phase: 159_edit_and_resend_message
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:
@@ -100,6 +100,20 @@ origin the browser rejects the clipboard, so the click instead offers the
|
||||
full path in an inline fallback field that selects itself on focus —
|
||||
click or Tab, then copy (phase 153).
|
||||
|
||||
**Edit** the newest question (phase 159): the latest user bubble carries
|
||||
an **Edit** button that swaps the bubble for an inline textarea
|
||||
prefilled with the question (the 4,000-character cap is enforced with
|
||||
`maxlength`; **Ctrl/⌘+Enter** submits, **Esc** / **Cancel** restore the
|
||||
original byte-identical, and a whitespace-only save is rejected inline).
|
||||
Saving rewrites the question in the chat and the saved chat in place,
|
||||
drops every turn that followed it, and re-asks the trimmed question —
|
||||
a fresh answer streams in the old answer's place (the question is
|
||||
never duplicated; an attachment on the question survives the edit and
|
||||
the re-ask stays text-only). A turn that failed with "Question too
|
||||
long — trim it and re-ask" (or a mistyped question) is fixed by
|
||||
trimming it in the editor instead of retyping it. Earlier bubbles
|
||||
never carry the button (last-question-only scope, owner-locked).
|
||||
|
||||
### RAG / Knowledge base (`/sources.html`)
|
||||
|
||||
The indexed document list. The *Path* column opens each document in the same
|
||||
|
||||
Reference in New Issue
Block a user