Repository navigation
feat(wakeups): workspace-wide switch to pause wakeup firing (CHE-1727) [squash] - #254
Merged
Merged
Conversation
added 4 commits
October 15, 2026 15:15
Tests only. Paused workspaces fire nothing for event, time, condition and system PR wakeups; dropped events are not replayed; other workspaces and manual human triggers are unaffected; the server stamps and audits the switch; create warns while paused; CLI prints the warning; UI switch and banner.
A workspace.settings.wakeups_paused switch stops dispatch for event, time, condition and system PR wakeups. Inputs that arrive meanwhile are consumed with outcome paused and never replayed; recurring schedules skip missed slots; overdue one-shots and conditions fire once on resume; manual human triggers still run. The server stamps who and when and writes one activity record per flip. Creating or enabling a wakeup while paused returns a workspace_wakeups_paused warning, which the CLI prints to stderr.
…l (CHE-1727) Admins get a master switch at the top of Settings, Wakeups. While paused the per-rule switch shows as overridden, and a banner names who paused and when in the settings tab and the issue wakeup panel. The switch saves through the existing workspace settings update; the server stamps who and when.
…ust not clear pause (CHE-1727 R1-R3) Tests only. Fail against 6864c76: resuming before a scheduler tick replays events that arrived while paused (R1) and fires recurring slots missed during the pause (R2); PATCH settings with a non-object body clears the pause with no resume audit (R3).
added 13 commits
October 15, 2026 16:43
…gs (CHE-1727 R1-R3) Resume now drops the inputs that arrived and skips the recurring slots that came due while paused, in the same transaction that lifts the switch, so a resume before the next dispatch tick cannot replay them. A settings body that is not an object is rejected, so it cannot clear the pause without a resume audit record.
…is on (CHE-1727 R3) An existing contract (wakeup definitions) tolerates a non-object settings blob, so the guard applies when the stored settings hold the pause, which is the case where the write would clear it with no resume record.
…der chip, cron (CHE-1727 review round 2) Tests only. Fail against 69e1e6b: a settings save that read before a pause flip clears the pause; a write whose stored-settings read fails succeeds and replaces paused settings; a pause or resume whose audit record fails reports success and commits; the issue header chip promises a due time while the workspace is paused. The two cron pause/resume tests are retrospective coverage and already pass.
…ause-aware chip (CHE-1727 review round 2) A settings write now reads, reconciles and writes under the workspace row lock, so a stale save cannot clear a concurrent pause. A read of the stored settings that fails fails the write. The pause and resume audit record commits with the flip, so a flip that cannot be audited does not happen. The issue header chip says wakeups are paused instead of promising a due time.
…ad must not drop later input (CHE-1727 review round 3) Tests only. Fail against cbd528c: a pause that commits between a dispatch's flag read and its enqueue transaction still gets a run enqueued, in regular and system dispatch; and a dispatch holding a stale paused read consumes an input that arrived after the resume. The interleavings are fixed by gating the dispatch's transaction start, not by sleeping.
…atch transaction (CHE-1727 review round 3) Regular and system dispatch now take the workspace row (FOR KEY SHARE) first, read the pause under it and settle a paused rule inside the same transaction that would enqueue. The pause and resume writers take FOR UPDATE on the same row, so a pause cannot commit between the read and the enqueue, and a resume cannot be followed by a stale paused read that drops a later input. Lock order is workspace, issue, wakeup.
Conflict: server/pkg/db/queries/wakeup.sql (ListReadyWakeups). main added the skip_ids and row_limit parameters and ListPendingWakeupInputGroups; the pause clause is kept before ORDER BY. server/pkg/db/generated/wakeup.sql.go is regenerated with sqlc.
Conflicts: packages/core/package.json (both sides added an exports entry; both kept) and server/internal/handler/workspace.go (main renamed validateCompactPromptConfig to validateCompactConfig for the settings body; the rename is taken, the pause-aware saveWorkspace path is kept).
…pproved rev-3 A (CHE-1727) Tests only. Fail against the merged head: no Saved or Resumed state, and the load error has no Retry.
… A copy (CHE-1727) Aligns the pause UI with the approved artifact design/wakeups-pause/rev-3/A.html @ 82c8a77. The admit sheet names the approved design and the new elements.
added 9 commits
October 17, 2026 07:45
…1727 pause branch No conflicts.
…one from approved rev-3 A (CHE-1727) Tests only. Fail against 586c20a: the banner and the Saved/Resumed line use neutral muted gray instead of the warning and success tokens.
…ved/Resumed (CHE-1727) Matches approved rev-3 A (design/wakeups-pause/rev-3/A.html @ 82c8a77). Surfaces use the semantic warning and success tokens at low alpha with a matching border; text stays on the foreground token and icons are aria-hidden, so contrast and the dark theme hold.
…7 review round 4) Tests only. Fail against 92c9832: a pull request event whose receipt commits after the resume sweep still fires (the workspace is never locked on that path), and the pause switch has no partial patch, so the client sends a cached full settings snapshot that can overwrite a concurrent change.
… server-side (CHE-1727 review round 4) TriggerPullRequestWakeup now takes the workspace row (FOR KEY SHARE) before the issue lock, in the order dispatch and the pause writers use, and holds it to the commit: a resume either waits for the receipt and sweeps it, or runs first and the event arrives after it. The pause switch is a partial patch (wakeups_paused); the server applies it to the settings it reads under the workspace lock, so a client's cached snapshot of the whole blob can no longer overwrite a concurrent change.
… receipt invariant) Tests only. Fail against db705eb: a sub-issue closing recorded while paused loses its hint, so the parent is never woken for state that still holds after the resume; and a receipt a lock-free producer (an issue update) inserted while paused but committed after the resume sweep still fires. The third test, an event after the resume that merges into a late paused receipt, passes today and guards the fix.
…era receipts (CHE-1727 receipt invariant) Condition hints (sub-issue and other state-check prompts) are no longer dropped by a pause or its resume sweep: they only prompt an evaluation, so the last sub-issue closing while paused still wakes the parent once on resume. The resume stamps its time from the database clock (server-owned, preserved across client settings saves); dispatch drops receipts whose event time is before it, which is how a producer that takes no workspace lock (issue, task, label, delete triggers) and commits after the resume sweep is kept from firing. A later event that merged into such a receipt is kept: the event time is the latest of the insert and the payload occurred_at. No new lock is taken on the producers, so lock order is unchanged.
…-1727 join/claim) Tests only. Fail against 3d1bb0d: JoinWaitingWakeups reserves pending receipts for a run being claimed with no pause gate, so a claim while paused, a claim after the resume of an input from before the pause, and a claim after the resume of a late paused-era receipt all get the wakeup instruction. Two controls pass today and guard the fix: a manual trigger still joins while paused, and an event after the resume joins.
…27 join/claim) JoinWaitingWakeups now takes the workspace row (FOR KEY SHARE) before the wakeup rows, reads the pause under it, and reserveForRun joins nothing but a person's manual trigger while paused (what the run reserved earlier goes back to pending for the sweep) and drops late paused-era receipts after a resume. Lock order is workspace, wakeup; the join takes no issue lock.
10 of 13 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Status: Independent verification complete. Cheese's merge is pending. Head
00556be28571da655d289d840623801fd5eb9e3d, base2b135399996d8072c5a99deb88ef55edb62f49b4. Exact-head CI is green. GitHub reports the PR clean. Design PR #255 is merged (82c8a7700d40c3aa007aac4cc9dc0b63f7442db9). Luna's signed full-pair PASS leaves no open P0/P1. Sol validated the exact-pair OCR receipt against the trusted schema. Coverage: 31 selected files and 10 manually reviewed test exclusions. Reviewer: x99-codex-luna, OpenAIgpt-6-luna, non-author against Sonnet/Anthropic. Signed verdict: CHE-1727 comment01a1497e-35c0-747b-8d83-abda9d1a9efe. P2/LOW findings remain disclosed and non-blocking. Author-local results below remain author-reported; neither Luna nor Sol reran local or database tests. The 12-capture UI pack is reused from3d1bb0d32dc62c60a6b5f5ee921fc40e65df0231, not recaptured. UI source is unchanged.Conditions:
design/wakeups-pause/rev-3/A.html. Exact-pair independent verification and OCR are complete. Readiness does not authorize an agent merge.Change:
A workspace switch
wakeups_pausedinworkspace.settingsstops wakeup firing. No new table.flowchart LR Settings[Admin settings] --> Lock[Workspace lock and pause state] Lock --> Dispatch[Dispatch and daemon claim] Dispatch --> Gate{Paused?} Gate -->|Yes| Hold[No new non-manual firing or join] Gate -->|No| Filter[Drop late paused-era receipts] Filter --> Run[Admit eligible wakeup inputs]paused. Recurring schedules skip missed slots. Overdue one-shots and conditions fire once after resume if they still hold. Manual human triggers still run. Other workspaces are unaffected.LockWorkspaceSettings). A save that read the settings before a pause flip can no longer overwrite it.FOR KEY SHARE) first, read the pause under it and settle a paused rule inside the transaction that would enqueue. The pause and resume writers takeFOR UPDATEon the same row. A pause can no longer commit between the read and the enqueue, and a resume can no longer be followed by a stale paused read that drops a later input. Lock order is workspace, issue, wakeup.wakeups_paused_byandwakeups_paused_at, theworkspace_wakeups_pausedwarning, the admin switch and banners, five locales.Evidence:
6a2221a301e64bce454cf6fe12da2d28364f63e2. Red CI: https://github.com/cheese-work/multica/actions/runs/38734898762.backend-testsfails onTestStaleSettingsSaveCannotClearAConcurrentPause,TestSettingsWriteFailsClosedWhenTheStoredSettingsCannotBeReadandTestPauseFlipRollsBackWhenItsAuditRecordFails. A views job fails on the header chip test. Each fails on the behavior, not on compilation.TestResumeBeforeNextTickSkipsMissedCronSlotsandTestPausedWorkspaceSkipsMissedCronSlotsalready passed on the tests-only commit.6e4e0316b8dda08c82401b8868d01e5781731c11. Headcbd528cc44a302a1f31fd669fce79ad01dea9423adds the chip test id and updates the admit sheet.cbd528cc44a302a1f31fd669fce79ad01dea9423: https://github.com/cheese-work/multica/actions/runs/38739121171. All 15 non-skipped checks pass.e554f9c23a0bbf14b96897fd7997256e5aced4a9addsTestPauseCommittingBeforeEnqueueCannotBeOutrunByDispatch,TestPauseCommittingBeforeEnqueueCannotBeOutrunBySystemDispatchandTestResumeBeforeAStalePausedReadDoesNotDropLaterInputs. They park the dispatch at its transaction start with a gate, not with a sleep. Red CI: https://github.com/cheese-work/multica/actions/runs/38758868312.backend-testsfails on exactly those three tests.3b9f1d36487569ccf20a5f7ea86bd945fdfbefb6. Green CI: https://github.com/cheese-work/multica/actions/runs/38760366702. All 15 non-skipped checks pass.maintwice with merge commits, never rebased. Conflicts:packages/core/package.json(both exports kept) andserver/internal/handler/workspace.go(mainrenamedvalidateCompactPromptConfigtovalidateCompactConfig; the rename is taken and the pause-awaresaveWorkspacepath is kept).9c56fe97d2e34a891df545b4d9769d27d36f2f40adds the Saved/Resumed and load-error Retry tests from the approved rev-3 A. Red CI: https://github.com/cheese-work/multica/actions/runs/38856321258.frontend-views-test (2/2)fails on exactly those two tests. The fix is commitfcc7eb374c43282de35f7152ccb1bed933c4ec25.backend-tests, which failed only on the migration prefix test thatmainalso failed. Fixed upstream by PR fix(migrations): renumber agent_task_queue_context to clear duplicate prefix 627 (CHE-1824) #290.48815262425ae7c569332278f26f32a179eb6a23addsTestPausedWorkspaceDoesNotJoinWakeupInputsIntoAClaimandTestResumeThenClaimDoesNotJoinALatePausedEraReceipt, plus two controls that pass before and after the fix:TestManualTriggerStillJoinsAClaimWhilePausedandTestEventAfterResumeStillJoinsAClaim. Red CI: https://github.com/cheese-work/multica/actions/runs/39019294055.backend-testsfails on exactly the first two. The fix is commit00556be28571da655d289d840623801fd5eb9e3d.JoinWaitingWakeupstakes the workspace row (FOR KEY SHARE) before the wakeup rows and reads the pause under it.reserveForRunjoins nothing but a person's manual trigger while paused, sends what the run reserved before the pause back to pending, and drops late paused-era receipts after a resume. Lock order is workspace, then wakeup. The join takes no issue lock.JoinWaitingWakeupsandreserveForRun(the daemon claim path,daemon.go): were a bypass; fixed above. Condition rules only join condition.met, timeout and manual receipts, and that filter is unchanged, so condition hints are not joined and still prompt re-evaluation in dispatch.dispatchanddispatchSystem, with theirtakenReceipts,deferForActiveRun, reserve, consume and timeout paths: run inside the workspace-locked, pause-gated transaction since round 3. Gated.rebaseBuiltinConfig: only settles firings of carrier runs that already started. Accepted.68dab99ad2703facf7744150747540825a7cb62faddsTestChildDoneHintRecordedWhilePausedEvaluatesOnResume,TestEventInsertedWhilePausedAndCommittedAfterResumeIsDroppedand the controlTestEventAfterResumeStillFiresWhenItMergesIntoALatePausedReceipt. Red CI: https://github.com/cheese-work/multica/actions/runs/39010584797.backend-testsfails on exactly the first two. The control passes before and after the fix. The fix is commit54199039a346179ffbc62cd4fa16161cd579b4ed. A later commit regenerates sqlc and the head is3d1bb0d32dc62c60a6b5f5ee921fc40e65df0231.issue_wakeup_receiptwas traced, including the effective SQL triggers (read from the live function and trigger definitions, not only the migrations). The SQL functioncapture_issue_wakeupis the one choke point of seven triggers.comment,comment_reaction,issue_reaction,attachmenton insert: the foreign key to the workspace already holdsKEY SHAREto the commit, so a resume waits for the producer and sweeps its receipt. I confirmed this by test: a held comment insert blocks the resume.issueupdate,issue_to_label,agent_task_queue, and update or delete on the tables above: no workspace lock. A receipt of these can commit after the resume swept. Disposition: dispatch drops receipts whose event time is before the resume time. The resume stamps that time from the database clock (wakeups_resumed_at), and it is server-owned.occurred_at, so a real event after the resume that merged into a late paused receipt is kept.KEY SHAREsince round 4. Registration snapshot receipts: workspaceKEY SHAREalready. Time-due, timeout and condition-met receipts: written inside dispatch under its locks. Manual triggers: exempt by design.children.changed) and the hints of any condition rule: no longer dropped by a pause or by the resume sweep. They only prompt an evaluation, so the last sub-issue closing while paused wakes the parent once after the resume if the state still holds. Their evaluation is state-based with the existing fingerprint dedup.ece9703c2d09b6cab8d2cf1b59f588cc9078341caddsTestPullRequestEventCommittingAfterResumeSweepDoesNotFire,TestPauseSwitchPatchKeepsUnrelatedSettings, and updates the pause-switch views tests to expect a partial patch. Red CI: https://github.com/cheese-work/multica/actions/runs/39005106626.backend-testsfails on exactly the two new Go tests, andfrontend-views-test (2/2)fails on the three pause-switch tests. The fix is commitdb705ebf115b4a13988ec7fbe3fe0db479f2760f.TriggerPullRequestWakeupnow takes the workspace row (FOR KEY SHARE) before the issue lock, in the order dispatch and the pause writers use, and holds it to the commit. A resume (FOR UPDATE) either waits for the receipt and sweeps it, or runs first and the event arrives after it. The test parks the event at its receipt insert with a transaction wrapper, then observes the resume either finish or wait on a lock, with no sleep.wakeups_paused. The server applies it to the settings it reads under the workspace lock, so a cached snapshot of the whole blob can no longer overwrite a concurrent change. The client sends only the switch.multica_multica_395, whichmake upcreated for this worktree. It is not the sharedmulticadatabase, and it lives on the shared PostgreSQL server of X99 next to 131 other databases. It is a dedicated database, not a separate server. No shared workspace or production database was used.61eff7bb4ab1544b94cd7c1bc2e97b1d01ae7ca6asserts the warning tone on the paused banner (settings tab and issue panel) and the success tone on Saved and Resumed. Red CI job: https://github.com/cheese-work/multica/actions/runs/38994864713/job/117285142833.frontend-views-test (2/2)fails on exactly those two tests, on the class assertions. GitHub marks the whole run cancelled because my next push superseded it, but that job had already failed. The fix is commit92c983278934bc7c6539617188cd72c50c94f321:bg-warning/10withborder-warning/30for the banner,bg-success/10withborder-success/30for Saved and Resumed. Text stays on the foreground token and icons arearia-hidden, so contrast and the dark theme hold. Green CI: https://github.com/cheese-work/multica/actions/runs/38995651393.mainat2b135399996d8072c5a99deb88ef55edb62f49b4with a merge commit, never a rebase, and no conflicts. No code changed in this round, so no new tests were needed. CI on the head: https://github.com/cheese-work/multica/actions/runs/38988181152. This clears thebackend-testsfailure of the previous round, which came from the duplicate migration prefix 627 onmain.golangci-lint(0 issues), the full views vitest run andpnpm typecheckpass.UI review pack — no UI file changed since head
3d1bb0d32dc62c60a6b5f5ee921fc40e65df0231. The pack below was captured on that head and still describes the UI of head00556be28571da655d289d840623801fd5eb9e3d.design/wakeups-pause/rev-3/A.html@82c8a7700d40c3aa007aac4cc9dc0b63f7442db9(approved by the merge of design PR design(wakeups-pause): rev-1 directions for the workspace wakeup pause #255)docs/ux/CHE-1727.ymlsettings-wakeups-running-1440-before.pngsettings-wakeups-paused-1440-after.png,settings-wakeups-resumed-1440-after.png, and the two-darkcapturessettings-wakeups-running-390-before.pngsettings-wakeups-paused-390-after.png,settings-wakeups-resumed-390-after.pngissue-panel-running-1440-before.pngissue-panel-paused-1440-after.pngissue-panel-running-390-before.pngissue-panel-paused-390-after.pngThe PNGs are attached to the CHE-1727 comment that carries this pack. The before captures run
mainat2b1353999. The after captures run head3d1bb0d32. The three gaps of the verdict are fixed. The resumed phone capture now shows Resumed (the earlier capture script reused a stale pause state). The paused phone capture now opens the Wakeups panel and shows the banner. The running before capture is no longer blank. Two extra captures,settings-wakeups-paused-1440-after-dark.pngandsettings-wakeups-resumed-1440-after-dark.pngshow the dark theme.Keep / Change / Remove check:
wakeups-child-done-switchpresent, yes.wakeups-child-done-instructionpresent, yes.wakeups-child-done-switchshows as overridden while paused, yes.wakeups-pause-statusshows Saved and Resumed, yes.wakeups-load-retryoffers Retry on a load error, yes.wakeups-header-chipreads Wakeups paused, yes.wakeups-pause-switchandwakeups-paused-bannerare new, yes.Writing-lint receipt: retained on CHE-1727 with the merge packet. Form warnings remain advisory. State-adjective and domain-terminology warnings are false positives; other warnings are true positives. Mermaid rendering is NOT-RUN.
Changelog: Admins can pause all wakeups in a workspace from Settings, Wakeups.
Closes CHE-1727