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:
@@ -429,7 +429,10 @@ def test_a11y_landmarks_and_labels(
|
||||
f"skip link must move focus to #main ({path})"
|
||||
)
|
||||
|
||||
# Every button has an accessible name; every img has alt text.
|
||||
# Every button has an accessible name; every img carries an alt
|
||||
# ATTRIBUTE (the WCAG contract — an EMPTY alt is the legitimate
|
||||
# decorative marker, e.g. the phase-123 attach-preview
|
||||
# thumbnail, pinned in tests/unit/test_chat_image_questions.py).
|
||||
unnamed = page.evaluate(
|
||||
"""() => [...document.querySelectorAll("button")]
|
||||
.filter((b) => !(b.getAttribute("aria-label") || b.textContent.trim()))
|
||||
@@ -437,9 +440,10 @@ def test_a11y_landmarks_and_labels(
|
||||
)
|
||||
assert unnamed == 0, f"{unnamed} button(s) without an accessible name on {path}"
|
||||
bad_imgs = page.evaluate(
|
||||
"() => [...document.querySelectorAll('img')].filter((i) => !i.alt).length"
|
||||
"""() => [...document.querySelectorAll('img')]
|
||||
.filter((i) => !i.hasAttribute('alt')).length"""
|
||||
)
|
||||
assert bad_imgs == 0, f"{bad_imgs} <img> without alt on {path}"
|
||||
assert bad_imgs == 0, f"{bad_imgs} <img> without an alt attribute on {path}"
|
||||
|
||||
# A real keyboard Tab walk: every focused element shows a visible
|
||||
# :focus-visible outline (solid, >= 2px). Start from the top of the
|
||||
|
||||
Reference in New Issue
Block a user