phase: 146_search_tool_scope
Build and Push Containers / build-and-push-app (push) Successful in 2m24s
Build and Push Containers / build-and-push-db (push) Successful in 13s

Phase 146 final verification pass complete — all green, tree untouched by me.

**Verified (final pass — both tasks already in `complete/`):**
- Scoped grep streams `{"type":"tool","name":"grep","argument":<pattern>,"path":<source/path>}`; bare grep/read/ls frames dump byte-identical (unit matrix in `test_sse_events.py` + builder pins in `test_chat_gate.py` L1364–1448)
- Tool line `🔎 Searching for <pattern> in <source/path>` (two `<code>` spans, `.grep-scope` sibling, no new emoji); bare line byte-identical (unit Node test + E2E)
- Status label "… is searching for X in Y" scoped-only; `path` persisted additively on the saved tool record and re-rendered on `/?chat=<id>` restore; pre-phase records restore byte-identically (E2E tests 2 & 3)

**Results (exact commands):**
- `uv run pytest --cov=app --cov-report=term-missing` → **3419 passed**, `app/` coverage **99%** (>90% ✓)
- `uv run pytest tests/e2e/test_search_tool_scope.py -v --no-cov` → **3 passed** in isolation ✓
- `uv run ruff check . && uv run pyright` → clean (0 errors) ✓

**Completion criteria:** all 6 ✓ (wire shape, UI line, status label, save/restore, gates, no completed-phase behavior change — full suite green includes all prior-phase pins).

**Documentation:** README.md (incl. its phase-146 section) and AGENTS.md reviewed in full against the codebase — verified consistent, no changes needed (`.env.example` ⊆ README config tables; no stale vars; phase-100 72rem rule in AGENTS.md §5 matches shipped CSS; no-CDN/smoke-DB/gpgsign claims all confirmed).

**Notable:** none — no defects found, no live-infrastructure touched, nothing committed per harness protocol.

**Next pending phase:** `147_sync_changed_only`.
This commit is contained in:
2026-10-01 12:48:04 -04:00
parent 32a3ec4f5e
commit ab3f5f685b
27 changed files with 2151 additions and 29 deletions
+24 -11
View File
@@ -113,12 +113,15 @@ 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."""
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)"
in _js()
), "the signature carries the additive offset/limit (default null)"
"function appendToolLine(wrap, name, argument, offset = null, limit = null, "
"scope = null)" in _js()
), "the signature carries the additive offset/limit/scope (default null)"
assert "readRangeSuffix(offset, limit)" in body, (
"the read arm renders the suffix through the SAME helper"
)
@@ -185,15 +188,21 @@ def test_live_tool_branch_reads_the_range_with_the_guard() -> None:
"limit joins the record ONLY when non-null"
)
assert "toolAcc.push(toolRecord)" in branch, "every tool frame is recorded"
# Both values pass to the SAME helper (the line + the status label).
assert "appendToolLine(wrap, name, argument, frameOffset, frameLimit)" in branch
# Phase 146 (task 02): the scope joins the SAME two pass-throughs.
assert (
"appendToolLine(wrap, name, argument, frameOffset, frameLimit, framePath)"
in branch
)
def test_live_read_status_carries_the_range_suffix() -> None:
"""ASSUMPTION A2: the read status label carries the SAME
requested-range suffix as the line (``readRangeSuffix`` — the single
source of truth); a non-range read renders byte-identical (the
helper returns ``""``). The grep / ls labels are untouched."""
helper returns ``""``). The ls labels are untouched; the grep label
gains the phase-146 additive scope (`` in <path>`` ONLY when the
frame carried one — a bare grep renders the exact pre-phase label).
"""
js = _js()
tool_idx = js.find('ev.type === "tool"')
delta_idx = js.find('ev.type === "delta"')
@@ -202,8 +211,12 @@ def test_live_read_status_carries_the_range_suffix() -> None:
"`${brand()} is reading ${argument}${readRangeSuffix(frameOffset, frameLimit)}`"
in branch
), "the read status carries the suffix (A2)"
# The other labels stay byte-identical (no suffix).
assert "`${brand()} is searching for ${argument}`" in branch
# The other labels: the grep scope extension (phase 146) + the
# ls labels untouched.
assert (
"`${brand()} is searching for ${argument}"
"${framePath ? ` in ${framePath}` : \"\"}`" in branch
)
assert "`${brand()} is listing documents in ${argument}`" in branch
assert "`${brand()} is listing documents`" in branch
@@ -230,8 +243,8 @@ 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)" in body, (
"the stored range rides the SAME helper"
assert "appendToolLine(wrap, t.name, arg, tOffset, tLimit, tPath)" in body, (
"the stored range + the phase-146 stored scope ride the SAME helper"
)