Skip to content

fix(workflows): remove background widget run cap and expire quit cards - #2134

Merged
flora131 merged 2 commits into
mainfrom
fix/widget-run-cap-and-quit-expiry
Aug 2, 2026
Merged

fix(workflows): remove background widget run cap and expire quit cards#2134
flora131 merged 2 commits into
mainfrom
fix/widget-run-cap-and-quit-expiry

Conversation

@flora131

@flora131 flora131 commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

Summary

Two linked fixes to the workflows BACKGROUND widget in packages/workflows/src/tui/widget.ts.

The panel truncated to four runs, and quit runs never expired. Those two facts compounded: a quit run has no endedAt, so isActive reported it as active forever, it never became recentlyEnded, and it never dropped off. Quit cards accumulated without bound and, under the four-run cap, crowded live runs off the panel. The cap made the leak visible; the leak made the cap bite.

Changes

Removed the display cap. MAX_VISIBLE_RUNS and its ordered.slice(0, MAX_VISIBLE_RUNS) in selectDisplayRuns are deleted rather than raised, so every qualifying top-level run renders. There was no overflow or "+N more" affordance to clean up.

Quit cards expire on the finished-run rule. Quit runs are resumable, so expiry must not make them look terminal — stamping endedAt would change isActive, the counts, and every other consumer of run state. Instead the run is expired from the display against the existing RECENT_ENDED_WINDOW_MS window:

  • isQuitRun moves above isActive, and isActive now excludes quit runs.
  • A new recentlyQuit measures the window from quitAt, a display-only timestamp added to RunSnapshot and set in recordRunPaused when a run first enters quit state. pausedAt was unsuitable: a run can be paused long before it is quit, which would expire the card early or immediately. quitAt is cleared on resume.
  • quitExpiryTimestamp falls back to pausedAt then startedAt so snapshots written before this change still expire rather than pinning forever.

Repaint scheduling. nextWidgetRefreshDelayMs previously scheduled expiry repaints only for runs with endedAt. It now schedules the quit expiry the same way, so a quit card leaves the screen on time instead of lingering until some unrelated event repaints the widget.

Badges match cards. countRuns ran over all top-level runs, so a N quit badge would keep counting quit runs whose cards had already expired. Counts and the N runs subtitle now derive from the display set.

Before / after, six runs of which two were quit

Before: the four newest runs rendered; the two oldest were silently dropped, and both quit cards stayed forever, so over time the quit pair permanently occupied half the panel while live runs went unseen. After: all six render; roughly 30 s after each quit, that card disappears on a scheduled repaint and the panel settles to the four live runs with a header reading 4 runs.

Discoverability

An expired quit card does not make the run unreachable. statusRuns and the workflow status action read snap.runs, which this change does not touch, and resumable is untouched — asserted directly in quit card expires from the widget after the recent window while status stays resumable.

Tests

Extended the existing suites; no parallel ones. Time-dependent assertions derive from the exported RECENT_ENDED_WINDOW_MS rather than hardcoding 30000.

test/unit/widget-rendering.test.ts

  • more than four concurrent runs all render without truncation
  • quit card expires from the widget after the recent window while status stays resumable
  • expired quit runs do not contribute counts after their cards disappear — covers the wide and collapsed forms across the 80-column breakpoint
  • quit runs schedule the expiry repaint from quitAt

test/unit/store.test.ts

  • records quit time separately from paused time and clears it on resume

Verification

npm run check and npm run test:unit both passed as pre-push hooks on this branch: 609 test files, 5686 passed, 2 skipped, zero failures.

Known non-blocking observations

Recorded by review as P3 observations, not defects, and left unfixed to keep the change scoped:

  1. Panel height is now unbounded above the 80-column breakpoint. This is the requested behavior — the cap was to be deleted, not raised — but it is a real consequence: a probe with 40 concurrent runs produced a 121-line below-editor panel. The collapsed form below 80 columns stays a single line. Worth a look if run counts get large in practice.
  2. A retried quit does not restart the expiry window. publishLocalQuit can run twice without an intervening resume: once with resumable: false when the durable write is refused, then again on the retry that upgrades the record. The enteringQuit guard is false on that second call, so quitAt keeps the first quit's timestamp; if the retry lands more than one window later, the card does not reappear even though the run has just become resumable. The run stays discoverable through status throughout.

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

Greptile Summary

This change removes expired quit workflow runs from BACKGROUND widget cards, totals, and badges while preserving active workflow cards and their attention indicators.

The widget expiry boundary was exercised with an expired quit run alongside an active run awaiting input at wide and collapsed widths. The resulting widget showed one active card, BACKGROUND 1 run in wide mode, and 1 background · 1 ● in collapsed mode, with no stale quit card or quit count. The focused widget-rendering suite passed all 29 tests.

Confidence Score: 5/5

T-Rex T-Rex Logs

What T-Rex did

  • I ran a deterministic TypeScript boundary harness with one expired quit workflow run and one active workflow at 120-column and 60-column widths, then compared the harness output to verify the widget renders only the active workflow and shows the expected background badges.
  • I executed the Vitest unit test suite for widget rendering and all 29 focused tests passed.
  • I implemented code changes to exclude quit runs from display via selectDisplayRuns and to derive wide/collapsed totals and badges from the display set via buildThemedWidgetLines.
  • I verified that awaiting behavior is preserved: countRuns(display, snap.runs) continues to show the active run with its needs-attention badge while expired quit runs are omitted.
  • I uploaded artifact references documenting the changes and their verification for review.

View all artifacts

T-Rex Ran code and verified through T-Rex

Reviews (1): Last reviewed commit: "fix(workflows): align widget header coun..." | Re-trigger Greptile

@mintlify

mintlify Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
bastani 🟢 Ready View Preview Aug 2, 2026, 4:35 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@flora131
flora131 merged commit 80c6727 into main Aug 2, 2026
18 checks passed
@flora131
flora131 deleted the fix/widget-run-cap-and-quit-expiry branch August 14, 2026 01:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant