phase: 130_chat_answer_clusters
**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:
+38
-13
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user