feat: phases 77–80 — navbar view refresh, static background, API tokens, history suggestion chips
Build and Push Containers / build-and-push-app (push) Successful in 1m45s
Build and Push Containers / build-and-push-db (push) Successful in 13s

Single consolidated commit for four completed, validated phases (77, 78,
79, 80). The pipeline run left all work uncommitted because the harness
commits only with PHASE_COMMIT=1 while child executors are forbidden from
committing; the phases themselves all passed validation and moved to
.agents/phases/complete/.

Phase 77 — navbar view refresh
- router.js dispatches bor:view-refresh on re-show / active re-click /
  popstate (gated on wasMounted; first show and boot exempt)
- History / RAG / Sources / Tuning re-fetch on refresh (admin branch);
  Chat deliberately excluded (stream survival)
- History "Refresh" button (admin-only, in-flight disable + status line)
- New story suite tests/e2e/test_navbar_refresh.py (7 tests)

Phase 78 — static background
- Removed the animated glow layers; static 44px grid over the flat --bg
  canvas; default and reduced-motion renders byte-identical
- Updated background/theme E2E suites; removed bg-glow test pins

Phase 79 — API tokens
- api_tokens model + migration 0012; hash-only token service
- Admin tokens API + Tokens admin view; POST /api/token-auth;
  live-revoking require_user on chat / suggestions / document content
- Frontend token gate with localStorage cache; anonymous E2E suites
  migrated to token login
- New story suite tests/e2e/test_api_tokens.py (9 tests)

Phase 80 — history suggestion chips
- last_questions() endpoint with SEED fallback; startNewChat() refetch
- Seed-semantics docs (config.py, .env.example, README)
- Integration state matrix + E2E suite rewritten to the 4 chip states

Also included: phase-76 report artifacts and the repo restore-test-db
skill (previously untracked), scripts/* ruff fixes from phase 77.

Final gate state (phase 80 final pass, covers everything above):
- uv run pytest --cov=app → 1637 passed, 0 failed, app/ coverage 99%
- uv run ruff check . && uv run pyright → clean, 0 errors
- Per-phase story E2E suites green in isolation
This commit is contained in:
2026-09-07 12:39:01 -04:00
parent 495d042a98
commit 7fce6572d0
215 changed files with 10142 additions and 1643 deletions
+19 -10
View File
@@ -24,8 +24,11 @@ This phase only surfaces the stored field: the content endpoint returns
``summary`` (task 01) and the shared ``renderDocument`` core draws the
labeled ``.doc-summary`` panel above the content on BOTH surfaces (task
02) — the full-page viewer and the chat/sources modal. The tests assert
exactly that contract, plus the phase-16 soft rule: the content
endpoint stays public (anonymous fetch → 200, no admin cookie needed).
exactly that contract. Phase 79 supersedes the phase-16 soft rule: the
content endpoint is ``require_user``-gated, so the viewer surfaces and
the API shape pin run under a signed-in session (the shape itself —
``summary`` for the yaml, ``null`` for the markdown control — is
unchanged).
"""
from __future__ import annotations
@@ -140,6 +143,7 @@ def test_full_page_shows_summary_and_original_together(
cannot contain, is rendered in the raw ``<pre>``."""
_reset_db_and_import(mock_llm)
page.set_default_timeout(30_000)
login(page, app_url, next="/") # phase 79: the viewer content is gated
digest_line, pointer_line = _summary_lines(SOURCE, YAML_PATH)
page.goto(f"{app_url}/document.html?source={SOURCE}&path={YAML_URL_PATH}")
@@ -279,6 +283,7 @@ def test_markdown_doc_has_no_summary_panel(
before (first child of the content container is the doc body)."""
_reset_db_and_import(mock_llm)
page.set_default_timeout(30_000)
login(page, app_url, next="/") # phase 79: the viewer content is gated
# Full page: no panel, markdown column untouched.
page.goto(f"{app_url}/document.html?source={SOURCE}&path={MD_URL_PATH}")
@@ -294,7 +299,8 @@ def test_markdown_doc_has_no_summary_panel(
assert order == ["doc-md"], f"markdown doc gained children: {order}"
# Modal: same story — no panel, .doc-md is the sole content child.
login(page, app_url)
# (the session is already signed in — the form login above)
page.goto(f"{app_url}/sources.html")
row = page.locator("#docs-tbody tr", has_text=MD_PATH)
expect(row).to_have_count(1)
row.locator("td:nth-child(2) a.doc-link").click()
@@ -312,18 +318,21 @@ def test_markdown_doc_has_no_summary_panel(
# ---------------------------------------------------------------------------
# 4. API shape (cheap, via the page context's request — still anonymous)
# 4. API shape (cheap, via the page context's request — signed in since
# phase 79 gated the endpoint)
# ---------------------------------------------------------------------------
def test_content_api_summary_shape_anonymous(
def test_content_api_summary_shape(
page: Page, app_url: str, mock_llm: int, db_ready: None
) -> None:
"""``GET /api/documents/content`` carries ``summary`` — the string
for the summarized yaml, ``null`` for the markdown control — and
stays PUBLIC: no admin cookie is set anywhere in this test, so both
200s prove the phase-16 soft rule (viewer public) is unchanged."""
for the summarized yaml, ``null`` for the markdown control. Phase 79
superseded the phase-16 soft rule: the endpoint is require_user, so
the pin runs under the form-login session (the shape itself is
unchanged)."""
_reset_db_and_import(mock_llm)
login(page, app_url, next="/")
digest_line, _ = _summary_lines(SOURCE, YAML_PATH)
expected_summary = f"{digest_line}\nSource: {SOURCE}/{YAML_PATH}"
@@ -331,7 +340,7 @@ def test_content_api_summary_shape_anonymous(
resp = page.context.request.get(
f"{app_url}/api/documents/content?source={SOURCE}&path={YAML_URL_PATH}"
)
assert resp.status == 200, "anonymous viewer access must stay public"
assert resp.status == 200
body = resp.json()
assert body["source"] == SOURCE
assert body["path"] == YAML_PATH
@@ -343,7 +352,7 @@ def test_content_api_summary_shape_anonymous(
resp_md = page.context.request.get(
f"{app_url}/api/documents/content?source={SOURCE}&path={MD_URL_PATH}"
)
assert resp_md.status == 200, "anonymous viewer access must stay public"
assert resp_md.status == 200
md_body = resp_md.json()
assert md_body["format"] == "md"
assert md_body["summary"] is None, "markdown docs never carry a summary"