fix(table): typewriter flash, Run-row completed-skip, dispatch-scope running count#4687
Conversation
- Typewriter: reset the revealed text synchronously during render when the value changes (not in an effect), so a cell going from running→value no longer flashes the full text for one frame before animating. - Run row / manual incomplete runs now treat a `completed` group as done even if an output column is blank — only "Run all" re-runs completed cells. The auto cascade keeps re-filling blank outputs (completedAndFilled). Client optimistic stamp mirrors: incomplete skips `completed` cells.
bulkClearWorkflowGroupCells in incomplete mode wiped EVERY targeted group's output data + exec on any row that wasn't fully filled across all targeted groups. So Run-row on a row with one completed group and one cancelled group wiped the completed group's outputs + exec too, and the dispatcher re-ran it. Now incomplete-mode clears per-group: only error/cancelled groups get their output columns + exec cleared; completed and in-flight groups are left intact (never-run groups have nothing to clear and run via eligibility). Combined with the classifyEligibility guard, a completed workflow is never re-run by Run-row — only Run-all re-runs it.
The "X running" badge read countRunningCells (sidecar in-flight), but the dispatcher only stamps one ~20-cell window at a time. During a 1000-row Run-all the client optimistically showed ~1000 while a reload showed ~20 — the sidecar never holds more than a window. Derive the count from the active dispatches instead: rows in scope ahead of the cursor × |groupIds| (exact for Run-all, upper bound for incomplete/new). Both scope and cursor are persisted, so a reload computes the same number. - countActiveRunCells (dispatcher.ts): dispatch-scope total, sidecar fallback when no dispatch is active. byRowId stays sidecar-based (the client overlay renders queued rows ahead of the cursor). - Live: applyDispatch re-syncs the badge from the server on every dispatch event (one per window, after its cells finish + cursor advances), so the badge steps down per window and matches reload. applyCell no longer touches runningCellCount (still keeps runningByRowId live for the gutter). - Optimistic on click: useRunColumn seeds the full run scope (totalCount × groups) so the badge is right before the first window lands.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview Aligns manual Makes the "X running" badge derive from active dispatch scope instead of only sidecar in-flight rows: adds Reviewed by Cursor Bugbot for commit a7c6337. Bugbot is set up for automated code reviews on this repo. Configure here. |
Greptile SummaryThis PR fixes the "X running" badge inconsistency between live view and reload by deriving the cell count from the persisted dispatch scope (
Confidence Score: 4/5The core fix is well-reasoned — anchoring the badge in the persisted dispatch scope means live and reload always compute the same number, and the per-window COUNT queries in apps/sim/lib/table/dispatcher.ts and apps/sim/hooks/queries/tables.ts warrant a second look — the former for the serialized COUNT queries, the latter for the Important Files Changed
Sequence DiagramsequenceDiagram
participant U as User
participant C as Client (useRunColumn)
participant S as Server (dispatches route)
participant D as Dispatcher
U->>C: Click Run all
C->>C: onMutate bumpRunState(totalCount x groups)
Note over C: Badge = 1000 optimistic
C->>S: POST /run-column
S->>D: "insertDispatch(scope, cursor=-1)"
S-->>C: dispatchId
C->>C: onSuccess seed dispatch into overlay
loop per window 20 rows
D->>D: dispatcherStep batchEnqueueAndWait
D->>D: advanceCursor(lastPosition)
D->>C: SSE dispatch status dispatching cursor
C->>C: applyDispatch update overlay
C->>S: invalidateQueries GET /dispatches
S->>S: countActiveRunCells rows ahead x groups
S-->>C: runningCellCount N minus window_size
Note over C: Badge steps down per window
end
D->>C: SSE dispatch status complete
C->>C: applyDispatch remove dispatch from overlay
C->>S: invalidateQueries GET /dispatches
S-->>C: runningCellCount 0
Note over C: Badge = 0
Reviews (1): Last reviewed commit: "fix(table): X-running count from dispatc..." | Re-trigger Greptile |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 89cf52a. Configure here.
…Count - countActiveRunCells: run the per-dispatch COUNT queries + the sidecar count in parallel instead of serially (one round-trip per dispatch). - Optimistic Run-all estimate now reads the table definition's maintained, unfiltered rowCount (detail cache) instead of the rows query's filter-scoped totalCount — the dispatcher runs every row regardless of the active filter.

Three table run-execution fixes (was split across #4685 + #4687, now combined).
1. Typewriter flash
A cell going Running → value flashed the full text for one frame, then restarted the type-out animation. The reset to empty happened in a
useEffect(one frame late) while the render fell back torevealed ?? kind.text. Now the reset runs synchronously during render (the "adjust state when a prop changes" pattern), so the full-text frame never paints; animation still fires only on post-mount changes (SSE completions), not on first mount/scroll-in. Verified live via DOM instrumentation: 40 animations, 0 flashes (was 77/100).2. Run-row re-running a completed workflow
On a row with one
completedgroup and onecancelledgroup, "Run row" re-ran the completed one. Two causes, both fixed:bulkClearWorkflowGroupCells(incomplete mode) was row-level — it wiped every targeted group's data + exec on any row that wasn't fully filled, so a completed group got wiped because a sibling group on the row was incomplete. Now per-group: onlyerror/cancelledgroups are cleared;completedand in-flight groups are left intact.classifyEligibilitynow skipscompletedgroups for manualincompleteruns (only "Run all" re-runs completed). Client optimistic stamp mirrors it.3. "X running" count from dispatch scope (reload matches live)
The badge read the sidecar in-flight count, but the dispatcher only stamps a ~20-cell window at a time — so a 1000-row Run-all showed ~1000 live but ~20 on reload. Now derived from the active dispatches:
rows in scope ahead of cursor × |groupIds|(persistedscope+cursor, so reload computes the same number). Exact for Run-all; an upper bound for incomplete/new (counts cells the eligibility filter later skips).applyDispatchre-syncs the badge per window;applyCellkeepsrunningByRowIdlive for the gutter; the optimistic on-click seed usestotalCount × groups.Type of Change
Testing
tsc clean; vitest (lib/table + hooks/queries, 202 passing); lint clean. Typewriter verified live in-browser (0 flashes). Counter verified consistent live↔reload on a large Run-all.
Checklist