phase: 130_chat_answer_clusters
Build and Push Containers / build-and-push-app (push) Successful in 2m27s
Build and Push Containers / build-and-push-db (push) Successful in 12s

**Phase 130 — final verification pass: 100% green, complete.**

- **Verified:** chips-only row (no chip for image docs) → images-only row (`.msg-images`) → related row → `.msg-actions` last; `getActionsRow` used by all 3 buttons + stopped/failed notes; `markLastRetryable` save-re-append hack gone; in-place chip fallback on image-load failure; CSS right-align with per-button auto margins removed — implementation matches the design in every detail.
- **Completion criteria:** (1) mixed citation renders chips→images→actions-last, DOM-asserted ✅ (2) all 3 buttons in one right-aligned `.msg-actions`; non-admin sees Retry-only; restore path identical ✅ (3) 404-bytes figure → plain chip, unit-pinned ✅ (4) E2E isolated ✅ (5) no behavior change (modal affordances, related tier, ARIA names) ✅
- **Tests/lint/coverage:** `uv run pytest tests/e2e/test_chat_answer_clusters.py -v --no-cov` → 4 passed; `uv run pytest --cov=app --cov-report=term-missing` → 3061 passed, **99%** app coverage; the 4 E2E files this phase modified (test_answer_images, test_image_documents, test_pdf_support, test_responsive_polish) → 22 passed in isolation; `uv run ruff check .` clean, `uv run pyright` → 0 errors.
- **Docs:** README.md — verified consistent in full (page table vs routes, env-var coverage vs `.env.example`, phase-130 cluster wording already in tree); no changes needed. AGENTS.md — fixed one pre-existing inconsistency: rule 5 still cited the retired "centered 46rem chat column"; now states the 72rem container contract (phase 100).
- **Decisions:** PLAN.md §7.1 still says 46rem, but it's owner-managed (phase 100 records the supersession pending owner sign-off) and out of my editable scope — AGENTS.md now cross-references the supersession.
- **Next pending phase:** `131_read_line_ranges` (todo/).
This commit is contained in:
2026-09-28 07:49:37 -04:00
parent 2d0f608246
commit c88c65641a
46 changed files with 3266 additions and 351 deletions
+38 -13
View File
@@ -752,6 +752,29 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
gap: 0.35rem;
align-items: center;
}
/* Phase 130 (task 03, TODO L6): the ACTIONS cluster — the bubble's
LAST .msg-meta row (Tune / Retry / Save-as-doc + the Stopped/Failed
notes — phase 130 task 02's getActionsRow). The row's justify does
the TODO's "bottom right" (the bubble's bottom row, right edge);
the buttons are plain flex items of the row — the per-button auto
margins (the phase-49/59 .tune-btn/.retry-btn/.save-as-doc-btn
margin mechanisms) are gone, so chips and figures can never push
the cluster around. DOM order inside the row = insertion order
(Tune, Retry, Save-as-doc per their gates). */
.msg-meta.msg-actions {
justify-content: flex-end;
}
/* Phase 130 (task 03, TODO L6): the source-IMAGES cluster — the
second .msg-meta row appendSources builds (phase 130 task 01):
one .source-image figure per image ref, no chips (the figure IS
the citation for image docs). The explicit rule PINS the chip row's
rhythm — wrap + the base .msg-meta 0.35rem gap + center align — so
a future base-rule change cannot drift the two clusters apart. */
.msg-meta.msg-images {
flex-wrap: wrap;
gap: 0.35rem;
align-items: center;
}
.source-chip {
display: inline-flex;
align-items: center;
@@ -918,8 +941,10 @@ a.answer-image:hover { text-decoration: underline; } /* flat — the caption und
padding-inline: 0.25rem;
}
/* ---------- Steering notes (phase 15) ---------- */
/* "Tune" button in the meta row of every completed brain bubble: ghost
pill, ≥44px, right-aligned after the source chips. ink-soft on surface
/* "Tune" button in the completed brain bubble's actions row
(.msg-meta.msg-actions — phase 130: the ROW's right-align is the
cluster's "bottom right"; the button is a plain flex item, no
per-button auto margin). Ghost pill, ≥44px. ink-soft on surface
≈6.9:1; hover pair brand-ink/brand-soft ≈6.9:1. */
.tune-btn {
display: inline-flex;
@@ -927,7 +952,6 @@ a.answer-image:hover { text-decoration: underline; } /* flat — the caption und
justify-content: center;
gap: 0.35rem;
min-height: 44px;
margin-left: auto;
padding: 0.35rem 0.8rem;
border-radius: 999px;
border: 1px solid var(--line);
@@ -943,11 +967,13 @@ a.answer-image:hover { text-decoration: underline; } /* flat — the caption und
.tune-btn:hover { background: var(--brand-soft); color: var(--brand-ink); }
/* Phase 49 (owner-locked 2026-08-29, TODO.md L4): the "Retry" button —
the redo-in-place action in the meta row of the LAST brain bubble.
The exact visual family of .tune-btn (same pill size/spacing, the
global :focus-visible ring, >=44px via min-height) so the two meta
actions read as a pair — but neutral: ink-soft -> ink on hover (Tune
keeps the brand pair). The redo glyph rides currentColor. Contrast:
the redo-in-place action in the actions row (.msg-meta.msg-actions —
phase 130) of the LAST brain bubble. The exact visual family of
.tune-btn (same pill size/spacing, the global :focus-visible ring,
>=44px via min-height) so the meta actions read as a set — but
neutral: ink-soft -> ink on hover (Tune keeps the brand pair). The
redo glyph rides currentColor. No per-button auto margin (phase 130
— the row's justify right-aligns the cluster). Contrast:
ink-soft on --bg ~8.6:1, ink ~15:1, hover ink on --brand-soft
~15.7:1 — all AA. */
.retry-btn {
@@ -956,7 +982,6 @@ a.answer-image:hover { text-decoration: underline; } /* flat — the caption und
justify-content: center;
gap: 0.35rem;
min-height: 44px;
margin-left: auto;
padding: 0.35rem 0.8rem;
border-radius: 999px;
border: 1px solid var(--line);
@@ -978,9 +1003,10 @@ a.answer-image:hover { text-decoration: underline; } /* flat — the caption und
(same pill size/spacing, the global :focus-visible ring, >=44px via
min-height) so the meta actions read as one set — the brand hover
pair like Tune (a docs action), the file glyph rides currentColor.
margin-inline-start: auto pushes it to the row's RIGHT edge (the
TODO's "bottom right"; markLastRetryable keeps it rightmost when
the last bubble also carries the Retry button). Contrast:
No per-button auto margin (phase 130 — the row's .msg-actions
justify right-aligns the WHOLE cluster to the row's RIGHT edge, the
TODO's "bottom right"; the button appends LAST in the row's DOM
order per its gate, so it stays the rightmost action). Contrast:
ink-soft on --bg ~8.6:1, hover brand-ink on --brand-soft — AA,
same as the family. */
.save-as-doc-btn {
@@ -989,7 +1015,6 @@ a.answer-image:hover { text-decoration: underline; } /* flat — the caption und
justify-content: center;
gap: 0.35rem;
min-height: 44px;
margin-inline-start: auto;
padding: 0.35rem 0.8rem;
border-radius: 999px;
border: 1px solid var(--line);