phase: 192_verbatim_inline_midturn
Build and Push Containers / build-and-push-app (push) Successful in 1m56s
Build and Push Containers / build-and-push-db (push) Successful in 14s

Phase 192 — final verification pass complete.

- **Verified (all 4 tasks already complete):** additive `verbatim_block` SSE frame (`VerbatimBlockPiece` → `ChatVerbatimBlockEvent` → chat dispatch, after the round's `tool`/`tool_result`, before the next round); `hydrateVerbatimNow` matched-only mid-turn pass + app.js branch; `dropPlacedTwin` per-locator done/restore dedupe; the dedicated E2E suite.
- **Root cause of the rejected attempt:** my own concurrent background `pytest` run deadlocked the harness validation run on the shared Postgres (`psycopg.errors.DeadlockDetected`). No code defect — re-ran every gate **exclusively**.
- `uv run pytest -q --cov=app --cov-report=term-missing` → **exit 0**, `TOTAL 7181 16 99%` (>90%)
- `uv run pytest tests/e2e/test_verbatim_inline_midturn.py --no-cov` → **6 passed** (isolated)
- `uv run pytest tests/e2e/test_verbatim_show_text.py tests/e2e/test_chat_history.py --no-cov` → **18 passed** (`test_chat_history.py` byte-unedited; the phase-182 suite's "no eighth type" pin was tightened, not loosened, to seven + `verbatim_block` with frame-order asserts)
- `uv run ruff check .` → All checks passed (exit 0) · `uv run pyright` → **0 errors**
- **Completion criteria:** single frame per success + zero per refusal ✅ · `BOR_ANSWER_TEXT=0` wire byte-identical (integration spelled baseline + E2E App B) ✅ · fence hydrates in place / unfenced lands at the call moment, before `done` ✅ · append+fence → 1 panel, two ranges → 2 panels ✅ · restore 1 panel/locator, `done.answer_text` + record key + `verbatim_blocks=N` unchanged ✅ · suite green, coverage 99%, lint/types clean ✅ · no-show_text turn byte-identical ✅ · commit → left to the harness (no git index/history commands run).
- **Docs:** README reviewed line-by-line (2399 lines) + AGENTS.md in full; mechanically verified all 86 `BOR_*` settings, every `.env.example` var, table defaults, internal anchors (0 broken), ports 8123/8901, tree depth 1–8, pagination 25/1–100, 17 palette colors, `0029`/`0030` migrations, and every cited test file. Fixed 1 inconsistency: the verbatim "Parity" bullet claimed the live turn/reload/shared page share "the same three globals" — now names the settle-path trio and states that `hydrateVerbatimNow` is the ONE chat-only addition (a shared page has no stream).
- **Notable:** `run_agent`'s four repeated piece unions were collapsed into the ONE exported `AgentPiece` alias, so a future piece type is spelled in one place; `test_frontend_edit_message.py`'s `runTurn` byte-pin was regenerated, not weakened.
- **Next pending phase:** `193_sync_remaining_count`.
This commit is contained in:
2026-10-19 12:19:51 -04:00
parent 4f20c256d7
commit fb17d15fbe
49 changed files with 17313 additions and 102 deletions
+27 -6
View File
@@ -59,7 +59,13 @@
caption and a `user-select: none` line-number gutter, while the
plain `.code-block` wrapper carries a Copy button and no badge
(phase 182); those placeholders hydrate against the frame's
`answer_text` through the ONE panel client
`answer_text` — or, since phase 192, against the additive
`verbatim_block` SSE frame (the eighth event type: one
`done.answer_text` item plus `type`) that carries a successful
`show_text` block the MOMENT the call succeeds, AFTER that round's
`tool` / `tool_result` frames and BEFORE the next model round, so the
panel lands where the model introduced the bytes instead of popping in
after the answer — through the ONE panel client
(`frontend/assets/verbatim.js` — a classic script loaded AFTER
`markdown.js` on the chat AND shared pages, no second locator grammar,
a plain string compare against the server's canonical `locator`, the
@@ -68,10 +74,23 @@
knowledge base` with no badge, no body and none of the model's bytes,
no panel left at "Retrieving the exact text…" after a terminal frame
(the `error` frame, the 300 s guard, Stop and the failure funnel all
settle it), the Copy button's clipboard content equal to the server
string exactly, and the shared page's panel Copy button + plain
`/document.html` link the ONE owner-directed exception to that page's
zero-controls rule) — phase 182 task 07), and the sync's peak-memory
settle it), a MID-TURN pass (`hydrateVerbatimNow`) that settles ONLY the
pending placeholders its ONE block matches — every other fence STAYS
`.verbatim-pending`, because burning one is how a still-resolvable fence
paints the honest sentence — and ONE canonical locator painting ONE panel
(`dropPlacedTwin`: the fence wins over the mid-turn appended twin, the scan
is PER LOCATOR so two honest ranges of one file stay two panels, it is
bounded by the `.msg` wrap (or the root when there is no wrap — a missing
wrap narrows the scan, it never switches the dedupe off), and a
pending/unresolved node is never a placement), the Copy button's clipboard
content equal to the server string exactly, and the shared page's panel Copy
button + plain `/document.html` link the ONE owner-directed exception to that
page's zero-controls rule) — phase 182 task 07, phase 192 tasks 01–04, the
mid-turn landing (panel on screen BEFORE `done`, the fence winning the
same-locator race, two ranges staying two panels, the `answer_text=False`
wire byte-identical) pinned through the UI by
`tests/e2e/test_verbatim_inline_midturn.py`), and
the sync's peak-memory
clause is TRAILING TEXT on the result line that already exists
(` · peak <N> MB` on the RAG page's `#sync-progress` counts line
or "Sync cancelled", written by the ONE `fmtSyncPeakClause` off
@@ -105,7 +124,9 @@
10. **Amply log, visibly feed back:** server-side, log the required
per-turn line (PLAN §9 — phase 182 appends `verbatim_blocks=N` after
`scaffold_stripped=N`: the verbatim display blocks actually SENT on
the `done` frame, `0` on every turn without them, deflected included)
the `done` frame, `0` on every turn without them, deflected included —
never the phase-192 mid-turn `verbatim_block` frames, which are not
counted anywhere else)
**and** the per-response byte-budget line
(`app/core/response_budget.py` — one
`api method=… path=… status=… bytes=… enc=… duration_ms=…` line per