phase: 161_reasoning_bubble
All gates verified. Final check — AGENTS.md rules against the project (commands, gates, protocols) — the quick-reference commands all exist and the rules (PLAN §2/§7/§9 references, phase protocol, No CDN, Debugpy, git gates) accurately describe the project; the reasoning bubble is a pure UI change with no new commands or env vars, so no AGENTS.md change is needed.
**Verification complete — full results:**
- **Verified** (implemented by prior task passes, all in working tree): `createReasoningWrap`/`ensureReasoningWrap` live container (D1), `settleReasoning` fold at the 3 settle sites + not at delta (D2), 320px `.reasoning-body` window + pinned-tail follow (D3), zero persistence change (D4), collapsed restore + shared-page parity with D6 step counts, `styles.css` family treatment + reduced-motion still, mock `REASONING_MIDROUND_TRIGGER` flow, 6-test story suite, phase-158 pin updates
- **Full suite:** `uv run pytest` → **3738 passed, 0 failed** · `uv run pytest --cov=app --cov-report=term-missing` → **TOTAL 99% (>90%)** · `uv run ruff check .` → all checks passed · `uv run pyright` → **0 errors, 0 warnings**
- **E2E in isolation** (DB up; port-8123 collision with an unrelated `undercooked` service → `E2E_APP_PORT=8125`/`E2E_MOCK_PORT=8902`, no live change made): `test_reasoning_bubble.py` **6/6** · `test_thinking_timeline.py` ✓ · `test_thinking_display.py` ✓ · `test_tool_call_compact.py` ✓ · `test_big_read_progress.py` ✓ · `test_turn_progress_loader.py` ✓ · `test_share_chat.py` ✓ · `test_chat_persistence.py` ✓ · `test_smoke.py` ✓ (all exit 0, zero failures)
- **Completion criteria:** all 9 checked against the code + test outcomes — container open/live/nested ✓, stays open past mid-round delta ✓, folds at done ✓, restore + shared collapsed with "3 steps" ✓, plain turn = no container ✓, regression suites green ✓, suite/coverage/lint green ✓, diff scope limited to `frontend/assets/{app.js,shared.js,styles.css}` + `tests/` + `README.md` + phase files (no `app/` — D4) ✓
- **Documentation:** README.md "Thinking" section names the Reasoning bubble accurately (320px window, open-until-settle incl. mid-round deltas, "N steps", byte-identical no-container, collapsed on restore/shared) — verified consistent, no changes needed; AGENTS.md — verified consistent, no changes needed; all `.env.example` vars documented
- **Decisions:** commit + phase-dir move left to the harness (per pass rules — no git index/history commands executed); `undercooked` dev server on port 8123 untouched, E2E used the env port overrides
- **Next pending phase:** none — `161_reasoning_bubble` is the last in `todo/`
This commit is contained in:
@@ -63,14 +63,17 @@ def _fn(src: str, name: str) -> str:
|
||||
|
||||
|
||||
def test_tool_run_builds_an_open_details_disclosure() -> None:
|
||||
"""Phase 158 (D1/D2/D5): ``ensureToolRun`` creates a native
|
||||
``details.tool-calls-disclosure`` via ``createToolDisclosure`` —
|
||||
a ``summary.tool-calls-summary`` (first child) + the existing
|
||||
``.tool-calls`` list (role=list + aria-label "Tool calls",
|
||||
second child) — inserted before the bubble in arrival order (D2).
|
||||
It starts OPEN while the run is live; every append re-renders the
|
||||
plain-text per-run "Tool call(s) (N)" count on the summary
|
||||
through textContent (no innerHTML anywhere)."""
|
||||
"""Phase 158 (D1/D5) + 161 (D1): ``ensureToolRun`` creates a
|
||||
native ``details.tool-calls-disclosure`` via
|
||||
``createToolDisclosure`` — a ``summary.tool-calls-summary``
|
||||
(first child) + the existing ``.tool-calls`` list (role=list +
|
||||
aria-label "Tool calls", second child) — appended into the
|
||||
phase-161 reasoning container's ``.reasoning-body`` in arrival
|
||||
order (D1 — the container sits above the bubble; the per-run
|
||||
bubble anchor is superseded). It starts OPEN while the run is
|
||||
live; every append re-renders the plain-text per-run "Tool
|
||||
call(s) (N)" count on the summary through textContent (no
|
||||
innerHTML anywhere)."""
|
||||
js = _js()
|
||||
disc = _fn(js, "createToolDisclosure")
|
||||
assert "document.createElement(\"details\")" in disc
|
||||
@@ -92,8 +95,15 @@ def test_tool_run_builds_an_open_details_disclosure() -> None:
|
||||
"calls and the phase-87 .tool-elapsed suffix stay visible during "
|
||||
"the turn"
|
||||
)
|
||||
assert 'insertBefore(disc, body.querySelector(".bubble"))' in run, (
|
||||
"D2: above the answer, in arrival order"
|
||||
assert 'insertBefore(disc, body.querySelector(".bubble"))' not in run, (
|
||||
"the per-run bubble anchor is GONE (phase 161 D1)"
|
||||
)
|
||||
assert (
|
||||
'ensureReasoningWrap(wrap).querySelector(".reasoning-body")'
|
||||
".appendChild(disc)" in run
|
||||
), (
|
||||
"phase 161 (D1): appended into the container's body — the "
|
||||
"container sits above the answer, arrival order preserved"
|
||||
)
|
||||
# D5: the count rides the summary — the template fragment itself
|
||||
# (singular for one call, plural otherwise), textContent-built.
|
||||
@@ -169,19 +179,28 @@ def test_restore_path_folds_the_disclosure() -> None:
|
||||
), "the fold sits AFTER the tool-line restore loop"
|
||||
|
||||
|
||||
def test_run_anchors_are_the_bubble_in_arrival_order() -> None:
|
||||
"""Phase 158 (D2): the anchor is the BUBBLE for both run kinds —
|
||||
the old ``.tool-calls-disclosure ?? .tool-calls ?? .bubble``
|
||||
anchor chain is GONE (with per-run disclosures, "above the
|
||||
tool lines" was the wrong order — arrival order is the
|
||||
contract), and the runs still open while active (D5)."""
|
||||
def test_run_anchors_are_the_container_in_arrival_order() -> None:
|
||||
"""Phase 158 (D2) + 161 (D1): the anchor moved to the REASONING
|
||||
CONTAINER for both run kinds (the phase-161 documented
|
||||
supersession — the container sits before the bubble; the runs
|
||||
append into its ``.reasoning-body``) — the old
|
||||
``.tool-calls-disclosure ?? .tool-calls ?? .bubble`` anchor chain
|
||||
is GONE (with per-run disclosures, "above the tool lines" was the
|
||||
wrong order — arrival order is the contract), and the runs still
|
||||
open while active (D5)."""
|
||||
js = _js()
|
||||
run = _fn(js, "ensureThinkingRun")
|
||||
assert 'querySelector(".bubble")' in run
|
||||
assert (
|
||||
'ensureReasoningWrap(wrap).querySelector(".reasoning-body")'
|
||||
".appendChild(block)" in run
|
||||
), "phase 161 (D1): the thinking run anchors on the container"
|
||||
assert "block.open = true" in run
|
||||
assert "??" not in run, "the old anchor chain is GONE"
|
||||
d = _fn(js, "ensureToolRun")
|
||||
assert 'querySelector(".bubble")' in d
|
||||
assert (
|
||||
'ensureReasoningWrap(wrap).querySelector(".reasoning-body")'
|
||||
".appendChild(disc)" in d
|
||||
), "phase 161 (D1): the tool run anchors on the container"
|
||||
assert "disc.open = true" in d
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user