diff --git a/docs/webui-local-dev.md b/docs/webui-local-dev.md index 8b4e68d..7972b16 100644 --- a/docs/webui-local-dev.md +++ b/docs/webui-local-dev.md @@ -258,7 +258,7 @@ The view never edits policy and exposes no gate-weakening toggle. The console shell (`webui/layout.py`) renders a grouped navigation driven by a single nav-config module, `webui/nav.py`. Nav groups follow the epic #631 Phase 1 information architecture: **Health, Traffic, Runtime/Sessions, -Projects, Inventory, Timeline, Policy, and Insights** +Projects, Inventory, Timeline, Policy** (live via #646), and **Insights** (placeholder). Live views and Phase 1 placeholders (`stub`) are declared in one place so the layout and the route table cannot drift. @@ -268,10 +268,10 @@ a **mode: read-only** badge — plus a **Docs** link to this document. No privileged action controls are present in the Phase 1 shell. Not-yet-implemented surfaces (`/sessions`, `/inventory`, `/timeline`, -`/insights`) resolve to graceful read-only stub pages instead of -404s; their backing views land in later child issues of #631 (the inventory -surfaces are backed by #636). Mutating methods on stub routes still fail closed -with `read-only-mvp`. +`/insights`) resolve to graceful read-only stub pages instead of 404s; their +backing views land in later child issues of #631 (the inventory surfaces are +backed by #636). `/policy` is a live read-only surface (#646), not a stub. +Mutating methods on stub routes still fail closed with `read-only-mvp`. ## System-health dashboard (#639) diff --git a/tests/test_webui_policy_visibility.py b/tests/test_webui_policy_visibility.py index 9d3a055..d07c43d 100644 --- a/tests/test_webui_policy_visibility.py +++ b/tests/test_webui_policy_visibility.py @@ -214,11 +214,16 @@ class TestPolicyRoutes(unittest.TestCase): self.assertIn(response.status_code, (404, 405)) def test_nav_links_policy(self): - from webui.nav import STUB_PAGES + # Policy is graduated live: not in STUB_PAGES and not labeled ·stub in nav. + from webui.nav import STUB_PAGES, iter_nav_items + self.assertNotIn("/policy", STUB_PAGES) + policy_items = [i for i in iter_nav_items() if i.href == "/policy"] + self.assertEqual(len(policy_items), 1) + self.assertEqual(policy_items[0].status, "live") text = self.client.get("/").text self.assertIn('href="/policy">Policy', text) - self.assertNotIn('href="/policy">Policy (stub)', text) + self.assertNotIn('href="/policy" class="nav-stub"', text) class TestPolicyViewFailSoft(unittest.TestCase): diff --git a/webui/nav.py b/webui/nav.py index 3847bb5..4c65b53 100644 --- a/webui/nav.py +++ b/webui/nav.py @@ -5,7 +5,7 @@ the ``webui/app.py`` route table stay aligned with epic #631. Read-only: every destination is a GET view or a Phase 1 placeholder. No mutation links. Nav groups follow the #631 Phase 1 information architecture: Health, Traffic, -Runtime/Sessions, Projects, Inventory, Timeline, Policy (placeholder), and +Runtime/Sessions, Projects, Inventory, Timeline, Policy (live via #646), and Insights (placeholder). Later-phase surfaces are declared as ``stub`` items and backed by ``STUB_PAGES`` so their nav links resolve to a graceful placeholder instead of a 404.