phase: 170_edit_bubble_sizing
Build and Push Containers / build-and-push-app (push) Successful in 1m42s
Build and Push Containers / build-and-push-db (push) Successful in 13s

All verification complete. Final report:

**Phase 170 — final verification pass (all 3 tasks were in `complete/`):**

**Verified implemented:**
- Editor renders inside the bubble: `bubble.replaceChildren(form)`, `display:none` rule deleted, `form.style.minWidth` seeded with pre-edit width, `restoreBubble()` (markdown + image re-prepend) before `closeEditor()` on Cancel/Escape, `closeEditor()` reordered before submit re-render
- Label: `editSaveBtn.textContent = "Send"` (app.js L1241)

**Gates (all 100% green):**
- `uv run pytest` → 4066 passed
- `uv run pytest --cov=app --cov-report=term-missing` → 99% on `app/` (gate >90%)
- `uv run ruff check . && uv run pyright` → clean (0 errors, 0 warnings)
- `uv run pytest tests/e2e/test_edit_bubble_sizing.py -v --no-cov` (in isolation) → 6/6 passed
- Regression set in isolation: `test_edit_and_resend.py` 7✓, `test_retry_answer.py` 4✓, `test_failed_turn_retry.py` 4✓, `test_chat_persistence.py` 4✓

**Completion criteria:** in-bubble editor + width pin ✅ · "Send" label + cancel restore + trim re-ask + "Question too long" driver case ✅ · suite/coverage/lint ✅ · E2E + regression isolation ✅ · phase dir moved to `complete/` ✅ (atomic commit is the harness's to make — changes left in the working tree per protocol)

**Documentation:** README.md reviewed in full — edit section already aligned to phase 170 (in-bubble editor + "Send"), pages table matches actual routes, all 29 `.env.example` vars documented, setup commands accurate; AGENTS.md reviewed — all referenced files/commands exist. Both verified consistent — no changes needed.

**Notable decisions:** none — verification pass only, no code changes required.

**Next pending phase:** `171_admin_settings_layout`
This commit is contained in:
2026-10-10 03:25:40 -04:00
parent 1200437bf8
commit c4f098d0c0
27 changed files with 1607 additions and 120 deletions
+8 -5
View File
@@ -524,11 +524,13 @@ def test_bubble_selector_is_only_lookups_and_anchors() -> None:
def test_bubble_variable_is_only_touched_for_content() -> None:
"""FINDING: the `bubble` variable (whatever a lookup bound) is
only ever touched for CONTENT — textContent, innerHTML,
classList, querySelector, prepend, appendChild, setAttribute — in
BOTH app.js and shared.js. A geometry property on the handle
would read ZERO once the box is hidden, so the allowlist failing
here means some future code silently depends on the painted box —
exactly what this audit forbids."""
classList, querySelector, prepend, appendChild, setAttribute,
replaceChildren — in BOTH app.js and shared.js. A geometry
property on the handle would read ZERO once the box is hidden,
so the allowlist failing here means some future code silently
depends on the painted box — exactly what this audit forbids.
(replaceChildren joined phase 170: the editor form IS the
bubble's content — a content swap, not a geometry read.)"""
content_props = {
"textContent",
"innerHTML",
@@ -537,6 +539,7 @@ def test_bubble_variable_is_only_touched_for_content() -> None:
"prepend",
"appendChild",
"setAttribute",
"replaceChildren",
}
for path in (APP_JS, SHARED_JS):
code = _strip_comments(_text(path))