fix(unfinished): fix mobile sizing on Unfinished page and its modals#210
Conversation
Unfinished page and its component tree had no mobile CSS treatment, unlike sibling pages fixed in 759a100. Adds overflowX:hidden to the page container, converts WorktreeDiffModal/CommitPushModal to dvh-based sizing with a full-screen-sheet variant below 768px, ports CommitPushModal to createPortal so its fixed overlay can't be broken by a transformed ancestor, and makes item-card Dismiss/Snooze buttons visible via @media (hover: none) instead of hover-only. Also swaps two hardcoded zIndex values for the named theme-contract tokens. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UaXkDT9P1nSwknvACLd6Gi
✅ Registry ValidationTest Coverage: 18/179 features have
|
UX Analysis
|
Go Benchmarks (Tier 1) |
Frontend Terminal Throughput |
🎬 E2E Feature Demos2 shard(s) recorded feature flows for this PR. recordings shard 1 Demo preview opens directly in browser (single-file HTML). Raw WebM recordings in ZIP. Expires after 30 days. |
E2E RPC Latency |
📊 Feature E2E CoverageFeature coverage report unavailable
|
The suite couldn't execute at all until now (no Chromium in this sandbox previously masked it): rpc() was missing the /api prefix every RPC route requires, the pinned-repo fixture pointed at the bare repo instead of the working clone (scanner needs a .git dir to resolve `git worktree list`), and the hardcoded session title collided across hook retries against the same long-lived test server. All three predate this branch (authored 2026-04-30, commit 3296f2c). With these fixed, the suite actually runs: the accessibility contrast test and 7/11 core-mechanics tests (page load, empty state, filter toggle, refresh RPC, item expand/collapse, nav badge, reattach session) pass cleanly. The Commit & Push modal test failure confirms the CommitPushModal portal migration works correctly (dialog opens with proper aria-modal/aria-labelledby) — it fails only because its locator is too broad and also matches an unrelated pre-existing Notification Panel dialog. Remaining failures (Open Session fixture mismatch, Dismiss button strict-mode violation from worktree accumulation across sequential beforeAll runs) are pre-existing test/fixture design issues unrelated to the CSS changes in this branch. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UaXkDT9P1nSwknvACLd6Gi
Pre-existing untracked bug docs from prior profiling/investigation work in this shared worktree; committing so they aren't lost. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UaXkDT9P1nSwknvACLd6Gi
✅ Registry ValidationTest Coverage: 18/179 features have
|
…no-op Fixes three pre-existing e2e fixture/locator bugs blocking the suite: the "Open Session" test asserted on a worktree that always had a matching session (so it never showed that button), and the Commit & Push / Dismiss tests used ambiguous role queries that also matched the always-present Notification Panel dialog and the item card's own role="button" wrapper. Also fixes a real scanner bug found while stabilizing the suite: EnqueueRepo's 30s per-worktree TTL cache silently no-ops a manual ScanUnfinishedWork RPC call (the Refresh button) if any worktree in that repo was scanned recently, so repeated clicks did nothing. Periodic ticks should respect the TTL; a user-initiated scan should not. unfinished-work.spec.ts (11/11) and the /unfinished accessibility contrast test now pass consistently across repeat runs. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UaXkDT9P1nSwknvACLd6Gi
…-fix-unfinished-page-mobile-sizing
✅ Registry ValidationTest Coverage: 18/179 features have
|
The Sources-link test added by the main merge (d475144) asserted /settings/unfinished with no trailing slash, but next.config sets trailingSlash: true, so the app always renders the URL with one — the assertion failed on every run regardless of this branch's changes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UaXkDT9P1nSwknvACLd6Gi
✅ Registry ValidationTest Coverage: 18/179 features have
|
… enqueueRepo The previous fix only bypassed the repo-level TTL gate in enqueueRepo, so a forced (user-triggered) scan got enqueued but scanWorktree still hit its own independent per-worktree cache and returned stale data — the Refresh button appeared to work (a scanCompleted event fired) but the underlying worktree state wasn't actually re-read. force now flows through scanTask -> scanRepo -> scanWorktree, which skips the cache read (and still refreshes it via the existing cache.Set on the OK path). Adds a regression test that fails without this fix. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UaXkDT9P1nSwknvACLd6Gi
Architecture review flagged that removing the TTL-based throttle for forced scans (previous commit) meant a burst of triggers landing close together — fsnotify + manual Refresh + periodic tick — could each enqueue a redundant concurrent scanRepo for the same repo, since nothing tracked "already queued/scanning" independent of the cache. Adds Scanner.inFlight (sync.Map) so enqueueRepo skips re-queuing a repo that's already queued or being scanned; the worker clears the entry once scanRepo/publishResults finish, so the next trigger picks it back up with current state. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UaXkDT9P1nSwknvACLd6Gi
✅ Registry ValidationTest Coverage: 18/179 features have
|
… /unfinished
The Playwright-managed ephemeral test server (tests/e2e/helpers/test-server.ts)
never set STAPLER_SQUAD_INSTANCE=e2e-local, so /api/debug/backlog/{seed,mutate}-*
(server/server.go) were never registered — in CI or locally. This silently
no-op'd every test that depends on them, including the "backlog live updates"
accessibility suite (10 tests were failing on createBacklogItemDirect: a JSON
parse error from the 404 HTML fallback) and, critically, the "stuck-item chips
pass Axe color-contrast on /unfinished" test: with seeding broken, zero stuck
items ever rendered, so the Axe scan had nothing to flag — a false-negative
that masked two real WCAG AA violations on /unfinished's StuckItemsSection
(added by the recent main merge) the whole time.
With seeding fixed, Axe correctly flags:
- chipActive: primary+textInverse = 4.43:1 (needs 4.5:1) in the clean theme.
Fixed by using primaryActive+primaryText instead (6.29:1) — the existing
"pressed state" token pair, so this only touches the affected chip, not
primary's much broader usage across the app.
- stuckReason chip: success+successBg = 3.83:1. Fixed by nudging success
from #10b981 to #34d399 (5.06:1) — a one-step-lighter shade of the same
green, following this file's existing WCAG-nudge convention.
STAPLER_SQUAD_TEST_DIR (set via --test-dir) still takes priority in
config.GetConfigDirForDir, so this doesn't change data-directory isolation —
only the debug-handler gate and log prefix.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UaXkDT9P1nSwknvACLd6Gi
✅ Registry ValidationTest Coverage: 18/179 features have
|
…-fix-unfinished-page-mobile-sizing # Conflicts: # tests/e2e/helpers/test-server.ts # web-app/src/components/backlog-stuck/StuckItemsSection.css.ts
✅ Registry ValidationTest Coverage: 18/179 features have
|
…n backstop Closes the confirmed PR-metadata capture gap (backlog item 12981e9d, PR #210): an agent driving its own shipping via /backlog:ship -> gh pr create never reported the resulting PR back to the item record, since only the system- driven mechanical pushAndCreatePR path wrote pr_url/pr_number. Epic 3.1: new report_pr_created MCP tool (role: work) verifies the reported PR against GitHub (VerifyPRMatchesBranch, reusing GetPRForBranch's typed ErrNoPR) before trusting it, then persists via the new primary-write Storage.SetBacklogItemPRAndTransition and transitions review -> pr_pending. Idempotent on a repeated call for the same PR. Epic 3.2: reconcileOrphanedAgentPRs periodic detector backstops the case where the agent crashes after gh pr create but before calling report_pr_created — finds review-status items with no live session but a real open GitHub PR for their branch, and self-heals via the same SetBacklogItemPRAndTransition path. Deliberately not a new StuckReason per ADR-001/plan.md's scope note (StuckReasonAbandonedReview already covers the genuinely-no-PR case). Frontend verified unchanged: PullRequestSection already renders pr_url/ pr_number correctly whenever item.status === "pr_pending", which both new code paths now reliably reach. project_plans/backlog-agent-communication/implementation/plan.md, Phase 3. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NnUqFpFJid7USqmi7CJQJ7
…n input BUG-047: WriteToSession (web UI chat box) and the write_to_session/ run_command MCP tools appended "\n" after input instead of "\r", so messages sent to a live raw-mode TUI session (the Claude Code CLI itself) were written into the pane but never actually submitted -- they sit unactioned in the input buffer with no error surfaced to the sender. TapEnter, the backlog nudge, the initial-prompt send, and the autonomous driver's turn-submit keystroke all already correctly used "\r" (one with a comment tracing the exact failure mode back to BUG-031). Centralizes the convention into session.EnterKeySequence / session.BuildSubmittableInput and switches all six call sites to it. Found investigating why backlog item 12981e9d (PR #210) sat at status=review for 2.5+ hours: its work session had already gotten the PR fully green and ready to merge, and a human's "merge it" message into the live pane silently failed to submit for exactly this reason. Also files BUG-048 (open, not fixed here): a related but distinct gap where a stuck review-role autonomous session's autonomous_stuck row has no remediation/respawn path, unlike the work-role case. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NnUqFpFJid7USqmi7CJQJ7
… branch Merging PR #210's branch (created before BUG-018-024/027 were closed and moved to docs/bugs/fixed/) reintroduced their pre-resolution copies into docs/bugs/open/ as new files, since that branch's history predated the deletion. The fixed/ versions are authoritative; removing the resurrected open/ duplicates.
Summary
The Unfinished page and its modal components had no mobile CSS treatment — no
dvh/--viewport-heightusage, nooverflowX: hidden, and hover-only action buttons — unlike sibling pages already fixed in commit759a1006.What Changed
UnfinishedTab.css.ts: addedoverflowX: "hidden"to the page container to stop horizontal scroll at mobile widths.WorktreeDiffModal.css.ts:maxHeightnow usescalc(var(--viewport-height, 100dvh) - 4rem)instead of100vh, plus a full-screen-sheet variant below themd(768px) breakpoint.CommitPushModal.tsx: ported tocreatePortal(document.body), matchingWorktreeDiffModal, so its fixed overlay can't be broken by a transformed ancestor.CommitPushModal.css.ts: overlay/modal now scroll (overflowY: auto) with advh-basedmaxHeight, plus a full-screen-sheet variant below 768px, so Submit/Cancel stay reachable when the on-screen keyboard shrinks the viewport.UnfinishedItem.css.ts:.actionsnow forcesopacity: 1under@media (hover: none)so Dismiss/Snooze are visible/tappable on touch devices without requiring hover.UnfinishedItemDetail.css.ts/WorktreeDiffModal.css.ts: swapped two hardcodedzIndexnumbers for the namedzIndex.dropdown/zIndex.modaltokens percss-architecture.md.All new rules are scoped inside
@media (max-width: 768px)or@media (hover: none)blocks — the existing desktop (>=1024px)maxWidth: 960px, centering, andflexWraprules are untouched.Test plan
npx tsc --noEmit— no errors introduced in touched filespnpm run lint:css(stylelint) — cleannpx --yes tsx scripts/check-theme-contrast.ts— all WCAG AA pairs pass across all 4 themesnpx jest --no-coverage --testPathPatterns="unfinished"— 234/236 suites pass (2 pre-existing unrelated failures in SessionDetail/BacklogEmptyState, not touched by this change)navigation.spec.ts, the only spec hitting/unfinished) — could not run in the dev sandbox (no Chromium binary installed); needs a CI or local run withnpx playwright install