chore(agent): phase roadmap from TODO.md, 4 phases (190-193)

Convert the four open TODO items into executable phases (append mode,
starting at 190 after the completed 189):

  190_app_name_settings_fix  - the Settings-panel app name wins over the
      Theme tab; the three brand strings stripped from the Theme tab
      (colors-only); live brand re-apply on save, no reload
  191_source_name_labels_tags - source_labels table + admin API + Sources
      page editor; the separate bounded source_name_hit_bonus retrieval
      boost; label surfacing in the <document> blocks and KB overview
  192_verbatim_inline_midturn - an additive verbatim_block SSE frame at
      the show_text success moment; in-place mid-turn fence hydration;
      the done/restore per-locator dedupe; the done frame, record key,
      restore and shared page stay byte-identical
  193_sync_remaining_count - the running sync/upload label counts down:
      "N remaining" (N = total - done), hidden at the final file; the
      chunk/image/summaries/terminal parts untouched

TODO.md is cleared (its items now live in .agents/phases/todo/).

LLM-Generated: true
This commit is contained in:
2026-10-17 19:35:55 -04:00
parent 140a343b92
commit 47456a44df
22 changed files with 899 additions and 2 deletions
@@ -0,0 +1,36 @@
# Task 04 — The phase E2E suite, the full gates, the docs pass, the commit
**Phase:** `192_verbatim_inline_midturn` · **Source:** `TODO.md:6`
**Story:** n/a
## Objective
The dedicated Playwright suite proves the owner-visible contract — the panel is on screen WHILE the answer is still streaming, the fence lands in place, nothing doubles, the kill switch is a byte-identical wire — run in isolation per AGENTS rule 4; the full gates pass; the docs are consistent; one atomic commit.
## Work
1. `tests/e2e/test_verbatim_inline_midturn.py` (NEW — the module docstring names the TODO item and the A4 unchanged-contract clause) — the module-app fixture pattern (the phase-182 E2E convention — verify in `tests/e2e/conftest.py` / the sibling verbatim suites; the mock LLM from `tests/e2e/mock_llm.py` — verify the phase-182 mock's `show_text` arm; if the mock drives `show_text` via a fence-only turn, extend the mock with a direct `show_text` tool call arm in `tests/e2e/mock_llm.py` — the mock is a test fixture, the extension is additive and the phase-182 pins must stay green):
- the fixture: a small KB with one document whose content the mock's `show_text` call targets (the phase-182 fixture convention).
- **(a) the mid-turn arm (the TODO regression):** a mock turn: an intro delta ("…here is the exact text:") → the `show_text` call (the mock arm) → the continuation deltas → `done`. Assert: the panel (`.verbatim[data-bor-locator]` with the call's locator — caption + gutter + body) is in the DOM BEFORE the `done` frame is consumed (the Playwright shape: `page.wait_for_selector` on the panel resolves while the stream is still running — a sentinel delta after the call proves the stream is live; the panel's DOM position is BELOW the intro text and ABOVE the final sentinel delta — the inline position assertion, the `answer_image`-position contract of `appendUnlocatedVerbatim`); the `done` pass adds nothing (the final panel count == 1).
- **(b) the fence-in-place arm:** a mock turn: an intro delta → the `show_text` call for `source/path#12-20` → the final answer containing the ` ```bor ` fence for the SAME locator → `done`. Assert: the fence placeholder is hydrated IN PLACE (the panel is at the fence position — between the intro and the final sentinel delta, NOT at the answer tail) before `done` (the mid-turn `hydrateVerbatimNow` pass); after `done`, the total panel count for that locator == 1 (the dedupe — the task-03 arm).
- **(c) the two-ranges arm:** a mock turn with TWO `show_text` calls — range 1–10 and range 11–20 of the same document (the `shown_texts` per-locator dedupe admits both) — no fences. Assert: exactly TWO panels after `done`, both at the answer position in call order, both with their own captions (the per-locator-not-per-identity pin, owner-visible).
- **(d) the kill-switch wire arm:** the `BOR_ANSWER_TEXT=0` module app — the same mock turn (the mock's `show_text` attempt hits the phase-182 refusal) → the captured SSE frame sequence (types + payloads via the house SSE-capture pattern) equals the pre-phase baseline (documented in the test); NO `verbatim_block` frame, NO panel, NO placeholder in the DOM.
- **(e) the restore arm:** run arm (a) to completion (a saved conversation — the phase-158 auto-save), reload the page, restore → exactly ONE panel for the locator (the record's `answer_text` through the same dedupe functions — the A4 parity pin, owner-visible).
2. Regression, run in isolation: the phase-182 E2E suites (verify the exact names in `tests/e2e/` — the verbatim display suite, the fence suite), `tests/e2e/test_chat_history.py` (the restore contract) — green unedited.
3. The full gates, in order:
- `uv run pytest` (unit + integration) — 100% passing;
- `uv run pytest --cov=app --cov-report=term-missing` — **>90%** on `app/`;
- `uv run pytest tests/e2e/test_verbatim_inline_midturn.py -v --no-cov` — green in isolation;
- `uv run ruff check . && uv run pyright` — clean.
4. Documentation pass (the phase file's Documentation section): `README.md` + `AGENTS.md` reviewed in their entirety against the post-phase app; the verbatim section notes the mid-turn landing (a `show_text` panel appears the moment the call succeeds — in place when fenced, at the answer position when not; the `done`/restore/shared contract is unchanged, the kill switch byte-identical); `AGENTS.md` corrected only where it names the done-frame resolution as the ONLY landing point.
5. Commit: one atomic, professional commit (Conventional Commits, `--no-gpg-sign`), e.g.
`feat(verbatim): show_text panels land mid-turn, at the moment the call succeeds (phase 192)` — the body names the additive `verbatim_block` frame, the `hydrateVerbatimNow` matched-only pass, the per-locator dedupe, and the A4 unchanged contract. `.agents/phases/todo/192_verbatim_inline_midturn/` moves to `.agents/phases/complete/` in the SAME commit (AGENTS rule 8).
## Testing & Quality
- E2E: the suite above, isolated; the regression suites green.
- Coverage: **>90%** on `app/`.
- Lint/types: clean.
## Completion Criteria
- [ ] `tests/e2e/test_verbatim_inline_midturn.py` green in isolation — (a) the panel is on screen before `done`, at the inline position; (b) the same-locator fence hydrates in place mid-turn and never doubles; (c) two ranges of one file → two panels; (d) the `answer_text=False` wire is byte-identical with no panel/placeholder; (e) the restore shows one panel per locator.
- [ ] `uv run pytest` 100% passing; `uv run pytest --cov=app --cov-report=term-missing` >90%; `uv run ruff check . && uv run pyright` clean.
- [ ] `README.md` / `AGENTS.md` consistent (the mid-turn landing clause).
- [ ] the phase directory is in `.agents/phases/complete/`; one atomic commit with `--no-gpg-sign`.