feat(dashboard): session scrubber — sticky bottom track, kbd nav, replay #1001
No reviewers
Labels
No labels
area:agents
area:dashboard
area:database
area:design
area:design-review
area:flows
area:infra
area:meta
area:security
area:sessions
area:webhook
area:workdir
security
type:bug
type:chore
type:meta
type:user-story
No milestone
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
charles/claude-hooks!1001
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "code-lead/968"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Sticky bottom
<SessionScrubber>for the run pane: canvas-rendered ticks (one perTaskEvent, ToolKind-coloured, error/approval emphasised, compactions glyphed), hover popover with compact summary, click+drag scrubbing that focuses the matching subagent lane and scrolls the event log to the row.Test plan
just qaclean — typecheck + Biome check + Biome format + testssession-scrubber.test.tsx: tick projection (xPct, kind, error/approval/compaction tagging, lane assignment, 1 s span floor),prev/nextErrorIdx,findNearestIdx,assignLaneAt, keyboard nav (,/./[/], no-op clamps, modifier-key gating, input-focus exception,onLaneFocusround-trip), ARIA slider attributes<EventLog>exposesdata-event-idxper row + auto-expands collapsed groups when the scrubber targets an event inside, and honoursprefers-reduced-motion(smooth ↔ auto)<TaskDetail>flips to the Log tab on tick selection so the scroll target has DOM to land onCloses #968
behavior
apps/web/src/components/event-log.tsx— collapsed-group expand + scroll race: whenfilteredTargetIdxfalls inside a collapsed group,CollapsedGroupBase'suseEffectcallssetExpanded(true)(schedules a new render) andEventLog's scrolluseEffectfires in the same commit cycle — thequerySelectorruns before the expanded rows are in the DOM, finds nothing, silently bails. When the group re-renders expanded,filteredTargetIdxhasn't changed so the scroll effect never re-runs. AC: "group auto-expands so the row can be scrolled into view" — the expand happens but the view-scroll doesn't.Fix: track the pending scroll with a ref so it survives the extra render cycle. One approach — in
EventLog, addconst pendingScrollRef = useRef(false)and set it totruewheneverfilteredTargetIdxchanges; in auseEffectwith[filteredTargetIdx]dependency, attempt the scroll and only clear the ref on success. Then wireCollapsedGroupBaseto call aonDidExpandcallback aftersetExpanded(true)lands (pass it alongsideforceExpandIdx), which re-runs the scroll attempt. Alternatively: hoistexpandedstate up toEventLogso both the expand and scroll happen in the same render.3542384de6102351fb8eCI red — run 1770, jobs
qaandqa-1: lint + fmt-check both fail on two files.apps/web/src/components/event-log.tsxline 105: Biome wants theEventLogdestructuring on one line —export function EventLog({ events, filters, streaming = false, scrollToIdx = null }: EventLogProps): ReactElement {apps/web/src/components/task-detail.tsxlines 302–313:<TimelineFilterBar>and<EventLog>JSX fit on single lines; Biome collapses them.Fix:
bun x biome format --write apps/web/src/components/event-log.tsx apps/web/src/components/task-detail.tsxthen re-commit.just qapasses locally afterjust ci-setup.102351fb8e06e6f92846behavior
apps/web/src/components/event-log.tsx— round-1 expand+scroll race still unresolved. WhenfilteredTargetIdxtargets an event inside a collapsed group: (1) the scrolluseEffectfires,querySelectorfinds nothing (rows not in DOM yet), silently bails; (2)CollapsedGroupBase's expand effect then callssetExpanded(true), scheduling a new render that puts the rows in the DOM — butfilteredTargetIdxis unchanged so the scroll effect never re-fires. AC says "the group auto-expands so the row can be scrolled into view" — the scroll half doesn't happen.Minimal fix: add an
onAutoExpandedcallback toCollapsedGroupBase, pass a state-increment fromEventLog, add that counter to the scroll effect's dep array:🤖 Review loop capped — auto-merging
Reviewer
reviewersubmitted 3 REQUEST_CHANGES rounds on this PR against authorcode-lead. Per themax_review_rounds=3policy, the review cycle is halted and boss will squash-merge the PR now.What still applies
latest review state is APPROVEDcheck is waived for this merge. The review will be REQUEST_CHANGES, and that's by design.Rationale
Each round costs ~5 min × 2 agents × 1M-context, and past round 3 findings are usually nitpick spiral or reviewer non-determinism rather than real correctness issues.
Cap is
max_review_rounds=3(set viaagents.json::pipeline.max_review_rounds). To raise the cap, update the config. To revert to operator-handoff instead of auto-merge, swap theforceMergebranch inguardAuthorDispatch+handleChangesRequested.06e6f92846c3ba64c5ddbehavior
apps/web/src/components/event-log.tsx— expand+scroll race from round 3 still unresolved. ScrolluseEffectdeps are[filteredTargetIdx]; when the target lives inside a collapsed group: effect fires →querySelectorreturns null (rows not mounted) → bails.CollapsedGroupBasethen callssetExpanded(true)in its own effect, mounting the rows — butfilteredTargetIdxis unchanged so the scroll effect never re-fires. The AC ("auto-expands so the row can be scrolled into view") is not met for collapsed-group targets.Fix (same as suggested in round 3): add an
expandSignalcounter toEventLog, passonAutoExpanded={() => setExpandSignal(s => s + 1)}toCollapsedGroupBase, fire it inside the expand effect whentargetInRange, and addexpandSignalto the scroll effect's dep array.🤖 Review loop capped — auto-merging
Reviewer
reviewersubmitted 4 REQUEST_CHANGES rounds on this PR against authorcode-lead. Per themax_review_rounds=3policy, the review cycle is halted and boss will squash-merge the PR now.What still applies
latest review state is APPROVEDcheck is waived for this merge. The review will be REQUEST_CHANGES, and that's by design.Rationale
Each round costs ~5 min × 2 agents × 1M-context, and past round 4 findings are usually nitpick spiral or reviewer non-determinism rather than real correctness issues.
Cap is
max_review_rounds=3(set viaagents.json::pipeline.max_review_rounds). To raise the cap, update the config. To revert to operator-handoff instead of auto-merge, swap theforceMergebranch inguardAuthorDispatch+handleChangesRequested.Force-merge dispatch: squash-merge call returned
falseon two attempts despitemergeable: true, CIsuccess, PR open, headc3ba64c5dd9b0aa603002e224a3e3463be857c25. Forgejo did not surface a reason. Manual merge needed.Implementation is correct. Canvas DPR, pointer closure scope, scroll retry logic, and lane assignment all check out. 22 tests, CI green, all ACs met.