phase: 192_verbatim_inline_midturn
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:
@@ -1327,6 +1327,27 @@ The model never retypes quoted text, so a displayed quote cannot drift.
|
||||
each block is capped at `BOR_SHOW_TEXT_MAX_CHARS`, cut at a line boundary
|
||||
with a truncation marker. Image documents are refused with a pointer to
|
||||
`show_image` — the two display tools never convert into each other.
|
||||
- **The panel lands while the answer streams.** A successful `show_text`
|
||||
sends its block TWICE on purpose (phase 192): once as the additive
|
||||
`verbatim_block` SSE frame — the eighth event type,
|
||||
`{type, source, path, title, start_line, end_line, total_lines, text,
|
||||
truncated, locator}`, i.e. exactly one `done.answer_text` item — emitted
|
||||
AFTER that round's `tool` / `tool_result` frames and BEFORE the next
|
||||
model round, so the panel appears where the model introduced the bytes
|
||||
instead of after it finished talking; and once on the `done` frame below.
|
||||
A refused call sends nothing, and `BOR_ANSWER_TEXT=0` offers no tool at
|
||||
all, so such a turn's frame sequence is byte-identical to pre-phase
|
||||
(pinned on the wire). Client-side, `hydrateVerbatimNow` settles the pending
|
||||
fence that block names IN PLACE the moment the frame arrives and leaves every
|
||||
other placeholder pending; when the answer has not fenced it (yet), the panel
|
||||
lands at the `answer_image` position then — not at the end of the answer. If
|
||||
the model fences that same locator in a later round, hydration drops the
|
||||
appended twin, so **one canonical locator paints exactly one panel**, at the
|
||||
fence (two honest ranges of one file stay two panels: the scan is per
|
||||
locator, bounded by the message's `.msg` wrap — or by the root when there is
|
||||
no wrap, so a missing wrap narrows the scan instead of switching the dedupe
|
||||
off, and one answer never reaches into the next one's panels). There is no
|
||||
client-side flag check — the server's gate is the only one.
|
||||
- **The bytes ride the `done` frame.** A turn that displayed text ends
|
||||
with one extra, additive SSE key: `done.answer_text`, the list of blocks
|
||||
in **display order** — answer order first (one per ` ```bor ` fence, the
|
||||
@@ -1338,10 +1359,13 @@ The model never retypes quoted text, so a displayed quote cannot drift.
|
||||
1-based inclusive extent — the numbers a caption shows can never be the
|
||||
model's claim. `locator` is the canonical matching key
|
||||
(`source/path`, or `source/path#12-40` for a range). There is no new
|
||||
bytes route and no eighth SSE event type: the bytes travel inline, and a
|
||||
saved or shared chat renders its panels from its own record. The same
|
||||
array persists on the saved brain record (`bor.chat.v1` `answer_text`),
|
||||
so a reload and an anonymous shared page show the same blocks.
|
||||
bytes route: the bytes travel inline (the only extra frame is the
|
||||
phase-192 `verbatim_block` above, carrying that same item), and a saved
|
||||
or shared chat renders its panels from its own record — the `done`
|
||||
frame, the saved record and the restore path are UNCHANGED by phase 192.
|
||||
The same array persists on the saved brain record (`bor.chat.v1`
|
||||
`answer_text`), so a reload and an anonymous shared page show the same
|
||||
blocks.
|
||||
- **Deflected turns resolve nothing.** A ` ```bor ` fence written into a
|
||||
deflected answer leaks no KB text — the disclaimer turn resolves no
|
||||
block and its frame carries no `answer_text` key.
|
||||
@@ -1379,8 +1403,10 @@ The model never retypes quoted text, so a displayed quote cannot drift.
|
||||
|
||||
- **Hydration paints the panel, and the panel is the file.** The client half
|
||||
is one classic script, `frontend/assets/verbatim.js`, loaded after
|
||||
`markdown.js` on the chat page and the shared page. At `done` (and on every
|
||||
restore) it matches each placeholder's normalized `data-bor-locator`
|
||||
`markdown.js` on the chat page and the shared page. Mid-turn it settles the
|
||||
one block a `verbatim_block` frame carries (`hydrateVerbatimNow`); at `done`
|
||||
(and on every restore) it matches each placeholder's normalized
|
||||
`data-bor-locator`
|
||||
against the frame's `answer_text[].locator` with a plain string compare —
|
||||
`markdown.js::borLocator` stays the ONLY locator grammar in the client, so
|
||||
the two sides cannot drift — and paints:
|
||||
@@ -1426,8 +1452,14 @@ The model never retypes quoted text, so a displayed quote cannot drift.
|
||||
exists once (the owner-locked share strings are unchanged; phase 189 added
|
||||
the save-before-the-token upsert in front of the same success paths).
|
||||
- **Parity, and what stays untouched.** The live turn, a reload and an
|
||||
anonymous shared page call the same three globals in the same order, so one
|
||||
answer renders one way. Only the two answer renderers (plus the shared
|
||||
anonymous shared page call the same three **settle-path** globals in the same
|
||||
order — `hydrateVerbatim` → `appendUnlocatedVerbatim` →
|
||||
`enhanceAnswerCodeBlocks` — so one answer renders one way. The phase-192
|
||||
mid-turn pass (`hydrateVerbatimNow`) is the ONE chat-only addition: a shared
|
||||
page has no stream to land a panel mid-turn, so it hydrates from its record
|
||||
through the same trio (which is why a reload and a shared page show the same
|
||||
panel the live turn showed at the `show_text` call). Only the two answer
|
||||
renderers (plus the shared
|
||||
page's) opt in: a question, a thinking run and the document viewer stay
|
||||
one-argument calls, and `document.html` does not even load the panel client.
|
||||
|
||||
@@ -1886,7 +1918,7 @@ startup (the DB rows shadow the env, `.env` is never rewritten).
|
||||
|-----|---------|---------|
|
||||
| `BOR_AGENT_MAX_ROUNDS` | `10` | Hard cap on agent tool rounds per grounded turn (0 = no tools); every tool result carries the model's remaining count (phase 160) |
|
||||
| `BOR_READ_MAX_CHARS` | `128000` | Cap on a `read` tool result (chars); over-cap reads truncate + a notice that teaches the grep → `read(offset, limit)` workflow (phase 95, rewritten phase 131) |
|
||||
| `BOR_ANSWER_TEXT` | `1` | Verbatim file display (phase 182): the **master switch, ON by default** — an answer's code block is typed by the server from the indexed bytes, never retyped by the model. `0` = the escape hatch: the `show_text` tool is not offered, its `<tools>` teaching clause is absent, ` ```bor ` locator fences are not resolved, and the `done` frame carries no `answer_text` key (the server surface is exactly pre-phase; a stray fence on the client still settles to the honest unresolved sentence rather than the model's copy) |
|
||||
| `BOR_ANSWER_TEXT` | `1` | Verbatim file display (phase 182): the **master switch, ON by default** — an answer's code block is typed by the server from the indexed bytes, never retyped by the model. `0` = the escape hatch: the `show_text` tool is not offered, its `<tools>` teaching clause is absent, ` ```bor ` locator fences are not resolved, no `verbatim_block` frame is sent, and the `done` frame carries no `answer_text` key (the server surface — frame sequence included — is exactly pre-phase; a stray fence on the client still settles to the honest unresolved sentence rather than the model's copy) |
|
||||
| `BOR_SHOW_TEXT_MAX_CHARS` | `12000` | Per-block character budget for ONE displayed verbatim slice (phase 182): the slice is cut at a **line boundary**, the shared `[…truncated…]` marker is appended and the caption's line range shrinks to what is actually shown. `0` = inert (nothing displays); a negative value refuses startup naming the field |
|
||||
| `BOR_SHOW_TEXT_MAX_BLOCKS` | `5` | Per-answer cap on displayed verbatim blocks (phase 182), counted in answer order. `0` = inert (nothing displays); a negative value refuses startup naming the field |
|
||||
|
||||
|
||||
Reference in New Issue
Block a user