phase: 159_edit_and_resend_message
Build and Push Containers / build-and-push-app (push) Successful in 1m39s
Build and Push Containers / build-and-push-db (push) Successful in 15s

All completion criteria verified. Final report:

**Phase 159 — Edit the last question and re-ask it: VERIFIED COMPLETE** (all 4 tasks already in `complete/`; this pass verified end-to-end)

**Verified (implementation landed + tests green):**
- `app.js`: `EDIT_ICON`, `lastUserWrap`, `appendEditButton`/`markLastEditable` (single-target discipline, in-flight guard), `openEditor` (labelled textarea, `maxlength=4000`, Escape/Ctrl+⌘+Enter, empty guard), save path: replace → splice tail → DOM removal → `lastBrainWrap=null` → `saveConversation`+`persistConversation` → `runTurn(text,{reask:true})` — matches README exactly
- `styles.css`: `.edit-btn`/`.edit-form`/`.edit-error`/`.is-editing` + mobile 44px; unit pins 40, E2E 7, integration `test_chats_api.py` extended

**Test/lint results (all green):**
- `uv run pytest` — 3,661 tests, exit 0
- `uv run pytest --cov=app --cov-report=term-missing` — TOTAL **99%** (>90%)
- `uv run ruff check . && uv run pyright` — all checks passed; 0 errors
- `uv run pytest tests/e2e/test_edit_and_resend.py -v --no-cov` (DB up) — **7/7 passed**
- Regressions in isolation: `test_retry_answer.py` 4/4, `test_failed_turn_retry.py` 4/4, `test_chat_persistence.py` 4/4

**Completion criteria:** all 7 ✓ — Edit on last bubble + prefill + Escape/Cancel restore (E2E #3); replace+truncate+re-ask with no duplicated question (E2E #1); refresh survival (E2E #4); failed/“question too long” turn editable + trim re-asks (E2E #5); earlier bubbles un-editable + byte-identical Retry/Stop/persistence (E2E #2 + regressions + unit pins); suite/coverage/lint ✓; E2E + regressions isolated ✓. Commit + phase-dir move: harness's job (no git ops by me, per protocol).

**Documentation:** README.md — full review; phase 159 section cross-checked against `app.js` source (cap, keys, truncate, image survival) — consistent, no changes needed; all 30 `.env.example` vars documented. AGENTS.md — full review; all rules/quick-ref commands valid — verified consistent, no changes needed.

**Notable:** none — no defects found in prior work; no live-infrastructure changes required.

**Next pending phase:** `160_tool_budget_telemetry`
This commit is contained in:
2026-10-05 19:07:33 -04:00
parent 4d7d0f6297
commit cb8767512a
36 changed files with 4009 additions and 22 deletions
+16 -4
View File
@@ -27,13 +27,25 @@ def test_leave_partial_index_is_a_module_turn_local() -> None:
"""`leavePartialIndex` is a module-scope turn local (like
persistedOnLeave): declared -1, reset at the top of runTurn, and
written ONLY by the pagehide handler (the one `= conversation.length
- 1` assignment). No other code may move the correlation."""
- 1` assignment) — plus the phase-159 (task 02) truncation reset
(the SANCTIONED third write: the edit's Save clears it to -1 WHEN
IT POINTED PAST editIdx — a partial saved from the dropped tail
must not be re-persisted into the new shape; the settle's identity
guard would otherwise fall back to an append; the next runTurn
also resets it turn-locally regardless). No other code may move
the correlation."""
js = _js()
assert "let leavePartialIndex = -1" in js, "module-scope declaration"
# The two -1 writes are the declaration and the runTurn reset.
assert js.count("leavePartialIndex = -1;") == 2, (
"only the declaration and the runTurn reset write -1"
# The -1 writes: the declaration, the runTurn reset, and the
# phase-159 truncation reset (the sanctioned third).
assert js.count("leavePartialIndex = -1;") == 3, (
"only the declaration, the runTurn reset, and the phase-159 "
"truncation reset write -1"
)
# The phase-159 (task 02) truncation reset is GATED: it fires only
# when the pointer pointed past the edited record (a partial on or
# before the edited record is untouched).
assert "if (leavePartialIndex > editIdx) leavePartialIndex = -1;" in js
# The one and only index write is the pagehide handler's.
assert js.count("leavePartialIndex = conversation.length - 1") == 1, (
"only the pagehide handler records the partial's index"