phase: 158_thinking_timeline
Build and Push Containers / build-and-push-app (push) Successful in 8m38s
Build and Push Containers / build-and-push-db (push) Successful in 32s

All verification complete. Every gate is green and the docs check out. Final report:

## Phase 158 final verification pass — COMPLETE

**Verified (all tasks pre-completed; this pass re-ran the full gate):**
- Unit + integration: `uv run pytest --cov=app --cov-report=term-missing` → **3618 passed, 99% coverage on `app/`** (>90% gate)
- Phase E2E in isolation: `uv run pytest tests/e2e/test_thinking_timeline.py -v --no-cov` → **6/6 passed** (order pin, fold-at-rest, live-open, restore+`segments` array, shared page, no-thinking single disclosure)
- Regression E2E, each in isolation: `test_thinking_display` 5✓, `test_tool_call_compact` 4✓, `test_turn_progress_loader` 3✓ (per-run pin updated), `test_big_read_progress` 4✓, `test_agent_document_tools` 4✓, `test_share_chat` 4✓, `test_chat_persistence` 4✓, `test_smoke` 3✓
- Lint/types: `uv run ruff check . && uv run pyright` → **clean (0 errors)**

**Completion criteria:** all 9 met — timeline E2E pins ✓, restore/shared `segments` ✓, no-thinking single-disclosure + the three UNCHANGED regression suites green ✓, pre-phase byte-identical round-trip (integration pin: key absent, never null; >50 / >32 000 / empty text / unknown kind all 422) ✓, full suite + coverage + E2E + lint ✓, `git diff --stat` footprint limited to `app/schemas.py`, `frontend/assets/{app,shared}.js`, `tests/`, README, phase files (a pre-existing owner `TODO.md` edit is out of scope, not staged by the phase commit) ✓, D15→per-run supersession recorded in the updated pin ✓. (Commit + phase move are the harness's job; task dirs already in `complete/`.)

**Documentation:** README.md — Thinking section correctly describes the phase-158 timeline; config reference matches `.env.example` exactly; page table matches registered routes; no stale single-block wording. AGENTS.md — rules and quick-reference commands all accurate. **Verified consistent — no changes needed.**

**Decisions/deviations:** none. `test_tool_call_compact.py` carries a one-line docstring-only update (referenced the removed `closeToolCalls`); its test logic is byte-identical to the phase-117 contract and green.

**Next pending phase:** none — `todo/` contains only 158.
This commit is contained in:
2026-10-05 02:52:55 -04:00
parent 3f752fb77f
commit 31bd903a93
49 changed files with 4280 additions and 482 deletions
+43 -25
View File
@@ -111,17 +111,21 @@ def test_read_range_suffix_shape_order() -> None:
def test_append_tool_line_signature_takes_optional_range() -> None:
"""appendToolLine gains the additive ``offset``/``limit`` params
(default ``null`` — a pre-phase 3-arg call renders byte-identical),
and the read arm renders the suffix through the SAME helper.
Phase 146 (task 02) extends the signature one more additive param
(``scope = null`` — the scoped grep's document) — the 5-arg
pre-phase-146 call shape renders byte-identically."""
"""appendToolLine takes the CONTAINER as its first param (phase
158, D1 — the caller passes the run's disclosure; the
single-container derivation is gone) + the additive
``offset``/``limit`` params (default ``null`` — a pre-phase
3-arg call renders byte-identical), and the read arm renders the
suffix through the SAME helper. Phase 146 (task 02) extends the
signature one more additive param (``scope = null`` — the scoped
grep's document) — the 5-arg pre-phase-146 call shape renders
byte-identically."""
body = _extract(_js(), "appendToolLine")
assert (
"function appendToolLine(wrap, name, argument, offset = null, limit = null, "
"scope = null)" in _js()
), "the signature carries the additive offset/limit/scope (default null)"
"function appendToolLine(container, name, argument, offset = null, "
"limit = null, scope = null)" in _js()
), ("the signature carries the container + the additive "
"offset/limit/scope (default null)")
assert "readRangeSuffix(offset, limit)" in body, (
"the read arm renders the suffix through the SAME helper"
)
@@ -190,8 +194,8 @@ def test_live_tool_branch_reads_the_range_with_the_guard() -> None:
assert "toolAcc.push(toolRecord)" in branch, "every tool frame is recorded"
# Phase 146 (task 02): the scope joins the SAME two pass-throughs.
assert (
"appendToolLine(wrap, name, argument, frameOffset, frameLimit, framePath)"
in branch
"const line = appendToolLine("
in branch and "armToolLineClock(wrap, line)" in branch
)
@@ -243,8 +247,9 @@ def test_restore_path_passes_the_stored_range_through() -> None:
assert "Number.isInteger(t.limit) && t.limit >= 1 ? t.limit : null" in body, (
"the stored limit reads through the house guard"
)
assert "appendToolLine(wrap, t.name, arg, tOffset, tLimit, tPath)" in body, (
"the stored range + the phase-146 stored scope ride the SAME helper"
assert "appendToolLine(restoreDisc, t.name, arg, tOffset, tLimit, tPath)" in body, (
"the stored range + the phase-146 stored scope ride the SAME helper "
"(the caller passes the run's disclosure — phase 158)"
)
@@ -371,6 +376,19 @@ function makeWrap() {
wrap.appendChild(body);
return wrap;
}
function makeDisclosure() {
const container = document.createElement("details");
container.className = "tool-calls-disclosure";
const summary = document.createElement("summary");
summary.className = "tool-calls-summary";
container.appendChild(summary);
const listEl = document.createElement("div");
listEl.className = "tool-calls";
container.appendChild(listEl);
const wrap = makeWrap();
wrap.querySelector(".msg-body").appendChild(container);
return { wrap, container };
}
function describe(el) {
return {
text: el.textContent,
@@ -427,12 +445,12 @@ def test_plain_line_byte_identical_and_range_line_carries_the_suffix() -> None:
+ "\n"
+ append
+ '\nconst ARG = "samedoc/twice.md";\n'
+ "const w1 = makeWrap();\n"
+ 'appendToolLine(w1, "read", ARG);\n'
+ 'const plain = describe(w1.querySelector(".tool-call"));\n'
+ "const w2 = makeWrap();\n"
+ 'appendToolLine(w2, "read", ARG, 10, 20);\n'
+ 'const range = describe(w2.querySelector(".tool-call"));\n'
+ "const a1 = makeDisclosure();\n"
+ 'appendToolLine(a1.container, "read", ARG);\n'
+ 'const plain = describe(a1.wrap.querySelector(".tool-call"));\n'
+ "const a2 = makeDisclosure();\n"
+ 'appendToolLine(a2.container, "read", ARG, 10, 20);\n'
+ 'const range = describe(a2.wrap.querySelector(".tool-call"));\n'
+ "console.log(JSON.stringify({ plain, range }));"
)
out = json.loads(_run_node(driver))
@@ -477,12 +495,12 @@ def test_shared_page_line_parity_under_node() -> None:
+ append
+ '\nconst ARG = "samedoc/twice.md";\n'
# app.js: a range read + a plain read
+ "const wa = makeWrap();\n"
+ 'appendToolLine(wa, "read", ARG, 10, 20);\n'
+ 'const appRange = describe(wa.querySelector(".tool-call"));\n'
+ "const wp = makeWrap();\n"
+ 'appendToolLine(wp, "read", ARG);\n'
+ 'const appPlain = describe(wp.querySelector(".tool-call"));\n'
+ "const wa = makeDisclosure();\n"
+ 'appendToolLine(wa.container, "read", ARG, 10, 20);\n'
+ 'const appRange = describe(wa.wrap.querySelector(".tool-call"));\n'
+ "const wp = makeDisclosure();\n"
+ 'appendToolLine(wp.container, "read", ARG);\n'
+ 'const appPlain = describe(wp.wrap.querySelector(".tool-call"));\n'
# shared.js: the SAME record (range + no-fields) through addToolLines
+ shared_suffix.replace("function readRangeSuffix", "function sharedSuffix")
+ "\n"