Files
brain-of-reese/.agent/phases/complete/65_bottom_chat_actions/00_phase.md
T
ducoterra f04ddbe1f8
Build and Push Containers / build-and-push-app (push) Successful in 1m35s
Build and Push Containers / build-and-push-db (push) Successful in 10s
fix(web): history tab copy — every chat saves automatically, there is no Save button
meta description -> locked (A3) auto-save string (history.html L6).
page-sub -> locked (A3) string, the <strong>Save</strong> emphasis retired with the button (L106-109).
empty row -> locked (A3) string; colspan=6, hidden, and row id untouched (L163).
h1, the anonymous gate section, and history.js are byte-identical — state language verified accurate.
2026-09-02 01:29:42 -04:00

7.9 KiB
Raw Blame History

Phase 65 — Chat Action Cluster to the Pinned Bottom

Source: TODO.md L3 — "Move the new chat and share button to the tune/retry/save doc cluster area so it's always at the bottom of the screen and easily accessble. Make the button clusters look better, neater, more aligned" Story: n/a (TODO-derived — owner roadmap confirmation 2026-09-01) Context: Verified layout inventory (audited 2026-09-01, line numbers as of this writing):

  • frontend/index.html — the .chat-actions row (New chat + Share pills, ONE wrapper) sits at the TOP of the 46rem chat column: the comment block runs L126–148, the row div is L149, positioned between #steering-announcer (L129) and <section class="messages" id="messages"> (L193). The pinned composer form follows the messages at L225. In any real conversation the row scrolls off-screen the moment the reader is at the bottom — the exact defect this phase removes.
  • frontend/assets/styles.css — .chat-actions (L433: horizontal row, align-items: center, gap: 0.6rem, intrinsic pill widths); .new-chat-btn (L301) / .share-chat-btn (L335) — solid brand pill family, min-height: 44px, border-radius: 999px; .composer (L1226) — position: sticky; bottom: env(safe-area-inset-bottom, 0), no z-index (the phase-52 pin, owner-locked 2026-08-30); .messages — flex: 1 1 auto + min-height: 200px (the grow that rests the bottom at the screen on short chats); the per-answer meta cluster: .msg-meta (L641), .tune-btn (L694), .retry-btn (L723), .save-as-doc-btn (L756) — ghost pill family, min-height: 44px, 14px icons, margin(-inline-start): auto pushes Tune/Retry/Save-as-doc to the row's right edge ("Save as doc" is the bottom-right action of every completed brain bubble — the app's action corner). The ≤640px block (L3049) flips .chat-actions to a full-width vertical stack.
  • frontend/assets/header.js L336–339 — binds #new-chat-btn and dispatches the bor:new-chat window event; frontend/assets/app.js L1700 listens and resets the conversation (it owns the in-flight-turn guard); app.js L246/L2067 binds #share-chat-btn to shareCurrentChat (the empty-chat no-op writes Nothing to share yet. to #send-status). All bindings are id-based and position-independent — the move is pure HTML/CSS.
  • frontend/assets/app.js copyShareLinkWithFallback (L1424) appends the clipboard-fallback field to the composer (not the row) — unaffected by the move.
  • Existing suites that constrain the design: tests/e2e/test_pinned_composer.py (the #composer computed position must stay sticky; the composer box flush with the viewport bottom at EVERY scroll position inside the sticky range; settles back into flow above the footer at the document bottom; NO z-index on the composer; the empty chat must not be scrollable, sh <= ch + 1); tests/e2e/test_save_share_ux.py::test_action_row_layout (ONE .chat-actions, DOM order New chat → Share, horizontal row at 1280px with intrinsic pill widths, full-width stack at 390px, no horizontal overflow at 360px — all RELATIVE geometry, nothing pins the row's vertical position); tests/e2e/test_chat_persistence.py (#new-chat-btn ≥44px, click resets the conversation, New chat started in #send-status).
  • .agent/ is tracked and committed (AGENTS.md rule 8) — the phase commit stages .agent/ + frontend/ + tests/.

Objective

The New chat + Share pills live in the bottom cluster of the chat column — the same screen zone as the tune/retry/save-doc meta actions — and are always at the bottom of the screen (pinned with the composer, visible even while scrolled up reading a long conversation). The two button clusters read as neat, aligned sets: the bottom row hugs the column's right edge, mirroring the right-aligned "Save as doc" corner above it.

Dependencies

  • 64_sync_upload_progress (todo, preceding — no functional dependency; ordering by number)

Tasks

  1. 01_move_chat_actions_to_bottom.md — relocate the .chat-actions row (buttons + comments byte-identical) to the last child of .chat-shell, directly above the composer; in-flow at first.
  2. 02_pin_bottom_cluster.md — wrap row + composer in a sticky .chat-bottom unit (A1): the cluster is pinned at the viewport bottom at every scroll position and settles into flow above the footer at the document bottom.
  3. 03_align_button_clusters.md — right-align the bottom row to the column's right edge (A2); verify the five action pills share one geometry (44px targets, 999px radius, global focus-visible).
  4. 04_e2e_bottom_chat_actions.md — the dedicated Playwright suite tests/e2e/test_bottom_chat_actions.py (run in isolation): pinned at every scroll position, resting at the screen bottom, settled above the footer, geometry + DOM order, mobile stack, both buttons still work.
  5. 05_regressions_and_commit.md — regression E2E matrix, full validate.sh, one atomic commit.

Testing & Quality

  • E2E (mandatory, house rule — one file per phase, run in isolation): tests/e2e/test_bottom_chat_actions.py against the shared conftest server (DB up, mock LLM, seeded KB — the test_pinned_composer.py patterns for overflow conversations and scroll measurement).
  • Frontend-only phase: app/ is untouched, so the coverage gate stays satisfied at its current level — validate.sh (unit + integration >90% + ruff + pyright) must still pass end to end.
  • Regression E2E (each in isolation): test_pinned_composer.py, test_save_share_ux.py, test_chat_persistence.py, test_share_chat.py, test_chat_history.py, test_smoke.py.

Completion Criteria

  • The .chat-actions row is the bottom cluster of .chat-shell — above the composer, inside the sticky .chat-bottom — with DOM order New chat → Share preserved and all ids/aria-labels intact.
  • Over-viewport conversation, scrolled to the top: the row is fully visible, pinned at the viewport bottom above the composer, at every scroll position inside the sticky range; at the document bottom the cluster settles into flow above the footer (no overlap).
  • Empty chat at 1280×800: the row rests at the bottom of the screen, the document is not scrollable.
  • Desktop: the row's right edge aligns with the column's right edge (A2); ≤640px: full-width vertical stack; no horizontal overflow at 360px.
  • #new-chat-btn click resets the conversation (New chat started in #send-status); #share-chat-btn on an empty chat is a no-op (Nothing to share yet.) — the bindings survived the move.
  • uv run pytest green; coverage TOTAL >90%; uv run ruff check . && uv run pyright clean.
  • uv run pytest tests/e2e/test_bottom_chat_actions.py -v --no-cov green in isolation (DB up); the six regression E2E suites green in isolation.
  • One --no-gpg-sign commit; phase dir moved to .agent/phases/complete/.

Locked decisions

  • Owner-locked (2026-09-01, roadmap confirmation, A1): pinned bottom cluster — a .chat-bottom wrapper (position: sticky; bottom: env(safe-area-inset-bottom, 0), NO z-index) groups .chat-actions + #composer as one sticky unit, so the pills are literally always at the bottom of the screen — the rejected alternative (plain in-flow row) would scroll away while reading up a long conversation. The #composer's own sticky declaration STAYS (redundant inside the wrapper — it cannot shift within its containing block — but test_pinned_composer.py pins the computed style sticky).
  • Owner-locked (2026-09-01, roadmap confirmation, A2): right-aligned bottom row — the New chat + Share row hugs the column's RIGHT edge on desktop (so the bottom-right reads as one aligned action column with the right-aligned "Save as doc" buttons above); the ≤640px stack stays full-width (alignment is moot when stretched).

Commit

git add .agent/ frontend/ tests/ && git commit --no-gpg-sign -m "feat(web): move the chat action cluster to the pinned bottom and align the button sets"