Converts the 9 TODO items into an executable phase roadmap (Protocol B, appended after phase 39): - 40 tuning toggle anonymous flash (TODO L3) - 41 sync fail-fast + modal when a model is down (TODO L4) - 42 no reply autoscroll (TODO L5) - 43 thinking scroll back — user scroll + gated autoscroll (TODO L7) - 44 markdown tables (TODO L6) - 45 agent unlimited tool calls behind BOR_AGENT_MAX_ROUNDS (TODO L8) - 46 mobile hamburger nav (TODO L9) - 47 quadlet + jinja import formats, A9 revision (TODO L10–L11) Each phase carries a user story, a dedicated Playwright E2E suite plan, and owner-locked decisions (R1 A9 format extension, R2 phase-37 budget revision, A1–A5 scope decisions) confirmed 2026-08-27. Also records the completed phases 30–39 todo/ -> complete/ moves that were pending in the working tree. TODO.md is cleared (items now live in .agent/phases/todo/).
6.1 KiB
Phase 34 — One Navbar on Every Page
Source: TODO.md L3 — "I want the navbar to be consistent between every page. I don't want buttons to pop in and out of existance. Just keep all those buttons active across all tabs."
Story: .agent/user_stories/nav-consistency.md
Context: The shared header (phase 19, frontend/assets/header.js) + the Tuning nav link (phase 29) already standardize nav + auth on chat / sources / tuning — but document.html still uses the separate .doc-header variant (back + title + actions, no nav at all), login.html misses the Tuning link, and two functional controls remain page-scoped: the Tuning steering toggle + panel (chat only, logic in app.js) and the Sync sources button (Sources only, logic in sources.js). Owner confirmation (2026-08-26): the bar must be identical on all pages — nav, Tuning toggle, Sync, New chat, and the auth pair all present everywhere; the locked A10 UI revision stays (admin-only controls hidden for anonymous, active for the admin on every tab).
Objective
Make the header bar identical on all five pages (chat, sources, document viewer, tuning, login): one shared markup block, one owner of all functional control behavior (header.js), the viewer's back link + title preserved in a second titlebar row, and the phase-12/19 height contract (64px desktop / 58px ≤640px) applied to the standard row on every page.
Dependencies
19_shared_header(complete) — theheader.jsmodule, the nav/auth markup + ids, the cached-one-whoami contract, the ship-hidden/reveal-for-admin pattern.29_tuning_nav_link(complete) — the admin-only#nav-tuningreveal pattern this phase completes on the remaining pages.15_steering_notes+27_global_tuning(complete) — the steering toggle/panel logic being moved into the shared module; chat-page behavior must not change.32_admin_sync_button(complete) — the sync button state machine +GET/POST /api/syncbeing moved into the shared module; Sources-page behavior (result line + error banner) must not change.13_document_back_navigation(complete) — the#doc-backtarget-resolution behavior the viewer titlebar must preserve.16_admin_auth(complete) — the whoami gate, the soft-gate pages, the sign-out binding.
Tasks
01_steering_moves_to_module.md— the steering toggle + panel logic moves fromapp.jsintoheader.js(exportedrefreshSteering()); the chat per-bubble Tune form keeps working.02_sync_and_chat_moves_to_module.md— the sync state machine moves fromsources.jsintoheader.js(bor:sync-statusevent); one module-owned New chat binding; the sign-in?next=rewrite.03_full_header_all_pages.md— all five pages ship the identical header block;#steering-panelexists on every page; the viewer becomes standard row + titlebar row; login gains the full header.04_viewer_titlebar_styles.md— the two-row viewer header styles, the sync button's failed state on non-Sources pages, theme/contrast/focus preserved.05_e2e_and_contract_update.md— the story E2E suitetest_nav_consistency.py;test_header_consistency.py+test_shared_header.pyupdated to the new viewer contract; regression pass; commit.
Testing & Quality
- Unit/integration: frontend-only — no new
app/logic; the no-CDN integration test (tests/integration/test_api.py::test_index_html_served_locally) must still pass (all new markup is same-origin, no new tags). - Coverage: >90% on
app/— unchanged by this phase (no Python change). - E2E (mandatory, A16):
tests/e2e/test_nav_consistency.py— the story gate, run in isolation; plus the two contract suites updated in task 05 and the regression list below.
Completion Criteria
- The same visible header controls appear on all five pages in the same order — brand, nav [Chat, Sources, Tuning], Tuning toggle, Sync sources (admin), New chat, exactly one of Sign in / Sign out — verified in
test_nav_consistency.pyfor both the admin and the anonymous role. - The document viewer shows the standard bar (row 1) + back link and title (row 2);
#doc-backtarget resolution (phase 13) unchanged. - The login page carries the full header (nav incl. Tuning, Tuning toggle, Sync, New chat, auth pair).
- Chat page: the steering panel + per-bubble Tune + inline form behave exactly as before; Sources page: the sync button state machine +
#sync-resultline +#sync-error-bannerbehave exactly as before. uv run pytestgreen;uv run pytest --cov=app --cov-report=term-missingTOTAL unchanged (>90%).- Regressions green in isolation:
test_header_consistency.py,test_shared_header.py,test_document_back_navigation.py,test_document_viewer.py,test_steering.py,test_global_tuning.py,test_sync_button.py,test_tuning_nav_link.py,test_smoke.py,test_chat_rag.py,test_admin_auth.py. uv run ruff check . && uv run pyrightclean (no Python change, but run the gate).- UI Structure Check (AGENTS.md rule 5): landmarks / labels / contrast ≥4.5:1 / focus-visible preserved; no CDN (rule 6).
- One
--no-gpg-signcommit staging only this phase's files;.agent/phases/todo/34_consistent_navbar/moved to.agent/phases/complete/.
Locked decisions
- A10 UI revision preserved — admin-only controls (Sources / Tuning nav links, Sync button) ship hidden and are revealed only for the signed-in admin; anonymous visitors get the reduced bar, identically on every page (owner confirmation 2026-08-26 — "hidden for anon, visible for admin").
- A11 untouched — vanilla HTML/CSS/JS, no CDN, no new packages.
- Phase 19 module contract extended, not replaced —
header.jskeeps the cached one-whoami-per-page promise; it gains ownership of the controls' behavior, not a second whoami. - Viewer bar superseded — the phase-19 single-row viewer bar (PLAN.md §7.1 "the viewer bar = back + title + the same actions") is replaced by the two-row layout at the owner's request (this TODO).
PLAN.mdis not edited (Protocol B); this phase directory records the revision. - A16 / A17 honoured — one new story E2E suite + one atomic
--no-gpg-signcommit.