phase: 158_thinking_timeline
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:
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user