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
+40
View File
@@ -347,6 +347,46 @@ class ChatToolResultEvent(BaseModel):
chars_total: int = Field(ge=0) # the document's true length
class ChatVerbatimBlockEvent(BaseModel):
"""SSE frame for one verbatim block a ``show_text`` call JUST displayed
(phase 192, task 01, A1).
The MID-TURN twin of one :class:`VerbatimBlockRef` item of the ``done``
frame's ``answer_text`` list — the same field set with the same caps,
sent the moment the block exists instead of at the end of the answer
(``TODO.md`` L5: "the verbatim tag appear[s] at the end and only when
the llm is done answering which makes the chat read strangely"). The
frame is strictly ADDITIVE (the phase-95 ``tool_result`` precedent):
it lands AFTER the round's ``tool`` / ``tool_result`` frames and
BEFORE the next model round, clients that do not know the type ignore
it, a REFUSED ``show_text`` streams NO frame (the holder append is the
single success gate), and a ``BOR_ANSWER_TEXT=0`` turn offers no tool
at all — its frame sequence is byte-identical to pre-phase. The
``done`` frame's ``answer_text`` list, the saved record and the
restore path keep the exact phase-182 contract (the client's
idempotence keeps the same block from painting twice).
``isVerbatimBlock`` (``frontend/assets/verbatim.js``) accepts the
event as-is: the key set is the done-frame item's key set, so the one
panel client hydrates a mid-turn frame with no new shape. The field
caps are :class:`VerbatimBlockRef`'s verbatim — a unit pin fails the
day the two drift.
"""
type: Literal["verbatim_block"] = "verbatim_block"
source: str = Field(max_length=120)
path: str = Field(max_length=1000)
title: str = Field(max_length=500)
start_line: int = Field(ge=0)
end_line: int = Field(ge=0)
total_lines: int = Field(ge=0)
#: The verbatim bytes themselves — SERVER-supplied, never model output
#: (the :attr:`VerbatimBlockRef.text` contract, same cap).
text: str = Field(max_length=600_000)
truncated: bool = False
locator: str = Field(max_length=2100)
class ChatDoneEvent(BaseModel):
"""Final SSE event of a chat turn: metadata for the finished answer.