Repository navigation
Conversation
…e (D16) Merge PR's job now records the design's seven steps (Fetch, Rebase, Push, Re-run checks, GitHub checks, Already-fixed check, Merge) with each step's state and start and end times, in its merge_jobs record. Preparation and the guarded merge report their steps through display-only callbacks. The review screen shows the list under the review strip with a Cancel merge button. Cancelling stops the job and its preparation without cancelling the task: the task keeps its status, its pull request stays open, and Merge PR may be clicked again. It is refused once GitHub has been asked to merge. A restart after a cancel settles the job cancelled. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Give the server test's fake preparation stopForMergeCancel; poll at once when a cancel is answered with a job that ended; rewrite only the elapsed times each second; name the pending Cancel 'Cancel requested'; test a cancel during the guarded merge's validation, during the job's first review load and before shutdown, and older poll records after a cancel; document where the list says a job stopped and when Cancel shows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Poll quickly again after a cancel, so its outcome shows within seconds of a backed-off poll; settle a restart after both cancels as a cancelled task; let screen readers read each step's word and time as text and move focus off a hidden Cancel; test a merge cancel during the push; document every case where no step reads where the job stopped, repeat cancels and clock skew. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Let a stop win over an inspection that answers after it, poll at once after an ended cancel answer unless a poll of this generation is in flight, escape a step's fallback word, and say that Cancel explains itself when the Merge step's write failed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Poll again within 2 s when a cancel is answered with an ended or newer job while a poll is on its way; move focus off Cancel whenever the bar or the button is hidden; write why a disabled Cancel cannot stop the merge beside it; give the restart row its cancelled case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Describe Cancel by its note only while the note is shown, test that focus moves off a hidden Cancel (to Refresh when the merge control hides too), and keep focus on the page when a failed load hides the merge controls. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Test that focus on Cancel moves to Refresh when a reload hides the merge control or fails, and stop the elapsed-time ticker when a failed load hides the step bar. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
Cancellation-response races and queue polling can leave stale outcomes or hide completed merge progress.
3 open issues
What changed in this PR
Adds D16 merge progress and merge-only cancellation to the existing background merge workflow, advancing build step 4.
Changes:
- Persists seven merge steps with states and timestamps.
- Adds cancellation that leaves the task and pull request open.
- Adds progress UI, lifecycle regressions, and documentation.
| File | Description |
|---|---|
| web/server.ts | Adds the cancel-merge endpoint. |
| web/public/style.css | Styles merge steps and cancellation controls. |
| web/public/index.html | Adds the step list and Cancel button. |
| web/public/app.js | Renders progress and handles cancellation responses. |
| test/runner-publishing.test.ts | Tests the cancellation endpoint. |
| test/pre-merge.test.ts | Tests progress callbacks and preparation cancellation. |
| test/merge-job.test.ts | Tests step persistence, cancellation, and recovery. |
| test/browser/review.spec.ts | Tests progress, polling, cancellation, and focus. |
| runner/store.ts | Persists steps and cancellation state. |
| runner/pre-merge.ts | Reports progress and supports merge-only stopping. |
| runner/merge.ts | Reports when guarded merge submission begins. |
| runner/merge-job.ts | Coordinates progress and merge-only cancellation. |
| docs/implementation/merge-handoff.md | Documents progress and cancellation behavior. |
| docs/designs/codeboost-plan-indexed-review.md | Updates D16 delivery status. |
| docs/architecture.md | Updates merge workflow capabilities. |
Review effort: Balanced
Keep the step list of a job that ended queued through the queue polls; ignore a cancel answer the poll already showed, follow a newer running job it carries and discard polls of older jobs; show a refusal only while the cancelled job is still shown running. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…194 review round 8) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…w round 9) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refuse a merge-only cancel while the task is being cancelled, keep the pending-cancel flag per job, update the Shutdown row and the #end comment for a cancelled merge, name Cancel merge in the architecture overview, note the approved D16 amendment beside D16, and test the refusal banner for an enabled Cancel. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… tests (#194 review round 12) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…onAsking (#194 review round 14) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add the step list's Waiting and Running marks to DESIGN.md (approved), an AGENTS.md rule for focus when a background update hides the focused control, cite #199 for the rest of D16 and DT7, save the waiting checks only when they change, and correct the onAsking comment. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…omment, and add Skipped to DESIGN.md (#194 review round 16) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s placement, and test focus when a reload shows the job ended (#194 review round 17) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd the list surviving the timer (#194 review round 18) Also log the step bar's placement in DESIGN.md and name the F6b queue test in the handoff doc's test list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hem, and test each way (#194 review round 19) Reads the focused control before hiding it, since hiding blurs it at once. Also drops the redundant first save of the waiting checks and widens DESIGN.md's step-bar log entry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…focus on it (#194 review round 20) Also test the fallback to Merge PR when a reload clears the last blocker, and word the test fixture's revision note as order only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…final state (#194 review round 21) Focus went to a still-disabled Merge PR (without a runner) and fell to the page. renderMerge now records the focused control, renders, then picks Merge PR only when shown and enabled, otherwise Refresh. The AGENTS.md rule now says the fallback must be shown and enabled and a control's visibility is decided once per update. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd test the disabled fallback (#194 review round 22) Also word the fallback as "not disabled (aria-disabled qualifies)" in the rule and the comment, drop the second write of Merge status's visibility, and document every focus move in merge-handoff.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lable, not disabled (#194 review round 23) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd keep Cancel pending until the poll answers (#194 review round 24) Also replace the last "disabled Cancel" and "until Refresh" wording. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…b as running (#194 review round 25) A poll already in flight could answer the job's older running record and clear the wait early. The in-flight test now checks Cancel after the held poll's answer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… not call onAsking, and note restart downtime in step times (#194 review round 26) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…own, Fetch failing for review, and a joined click (#194 review round 27) Also name the merge step bar in DESIGN.md's Frame. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…moved head stops it (#194 review round 28) Also list round 27's tests in the handoff doc. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

Part of closing build step 4 (#22 follow-up): the merge job's full step list and Cancel button (design D16, DT7 step list). Issues #174 and #176 were closed by separate PRs (#197 and #195).
What changes
merge_jobsJSON record. No schema version change; records saved before this have nostepsand show as before.PreMergeCoordinator.start) and the guarded merge (MergeCoordinator.merge,onAsking) report steps through display-only callbacks: a failed step write is logged and never stops the job.POST /api/action {action: "cancel-merge", jobId}) stops the job and its preparation without cancelling the task. The task keeps its status, its PR stays open, and Merge PR can be clicked again. Refused once the job's merge attempt exists (GitHub was asked), and while the task itself is being cancelled. A restart after a cancel settles the jobcancelled.aria-disabled, once the Merge step starts).merge-handoff.md"Step list and Cancel"; architecture, design and README status; build step 4 marked done, with the rest of D16 and DT7 in Build the rest of D16 and DT7: named merge failure banners, Queue-row step, and the blocker list with links #199.User decisions (2026-10-20): Cancel stops the merge only, not the task; use the design's 7 steps. (2026-10-21): Cancel shows only while the job runs, not "always" as D16 says; the rest of D16 and DT7 goes to follow-up #199; the step marks are added to DESIGN.md; the step list is a bar under the review strip, not a replacement for the header. Each is recorded beside D16 or in DESIGN.md's log.
Validation (head 546f6fc, intermediate checkpoint)
test/merge-job.test.ts: 106/106 at 561ed01 (13 new); 16 new tests in total after round 1, all passing (-t cancel15/15).test/pre-merge.test.tstests at 561ed01 (5): pass. Six in total after round 2. The rest of that file timed out locally under a machine load average of ~200 (48 timeouts at 15 s, 2 timing assertions); not yet compared with main under the same load. CI is the gate.-g D16): pass. The ended-answer and backed-off-poll tests were each checked to fail with their fix removed.test/merge-job.test.ts: 111/111 at a741b97. Browser-g D16: 9/9 at 546f6fc (the 2 new tests run alone: 2/2); the in-flight-poll and focus tests were each checked to fail without their own fix.testat 561ed01 failed only the route test fixed in round 1 (2476 other tests passed, including all of pre-merge).test/runner-publishing.test.ts: pass (failed at 561ed01: its fake lackedstopForMergeCancel).Review record
runner/merge.ts; removed an untested doc claim about pushes.stopForMergeCancel(409). Fixed in the fake. Declined the optional try/finally: the stop calls cannot throw.settleInterruptedMergeJobs; store test.aria-hidden. Fixed: the word and the time are text; only the mark is hidden; focus moves off a hidden Cancel.revision(harmless; the button is disabled while pending).title. Fixed: a visible note that also describes the button (a disabled Cancel ignores clicks, so no refusal banner would explain it).aria-describedbyis still read). Fixed: the description is set only while the note shows; test asserts the enabled description.Before Copilot request 1 (recorded at head 546f6fc, validated head for that request)
-g D169/9. Full suite and real-Docker: CI (pending at request time).testandreal-dockerpending; both later passed on 546f6fc. Mergeable: yes (blocked only by pending checks). Unresolved review threads: 0.docs/architecture.md,docs/designs/codeboost-plan-indexed-review.mdandrunner/production.ts(the first two are shared with this PR); GitHub reports no conflict. Not merged into the branch, so the reviewed base/head pair stands. (Corrected after round 10: this line first said they touched onlyagents/.)Copilot round 1 (head 546f6fc)
Copilot (copilot-pull-request-reviewer) on base aced300 / head 546f6fc: 3 medium findings, all in
web/public/app.js. Fixed in 1b4ded6; each thread was answered and resolved.queuedlost its step list once queue polling replaced thejob-refreshblocker. Fix:endedJobShownon the merge view, kept by queue polling. Regression: the queued-job browser test now has a step list and asserts it after GitHub merged (fails without the fix).withMergeJobObservation; a poll that read an older job is discarded. Regressions: the refusal arrives after the poll saw the job end, carrying the ended job, an older record and a newer job (each fails without its fix).After Copilot round 1
-g "D16|follows the merge queue a polled job ended in"13/13, typecheck. Findings, fixed in db6e7eb (docs only):-t "merge is cancelled|preparation step|command checks skipped|progress callback throws", which also matches 1 existing test: 7/7), route test 1/1, browser 13/13. Findings:settleInterruptedMergeJobsdoc comment did not mention the cancelled case. Fixed in 84e6b14 (comment only).cancel-mergeduring shutdown. The route reaches 503 through the server's sharedstoppingcheck andShuttingDownErrorhandler, which other routes' tests cover;cancelMerge'sShuttingDownErroris tested at the coordinator.#endcomment) did not cover a cancelled merge. Fixed.agents/. Corrected above.docs/architecture.mddid not name Cancel merge as a screen button. Fixed.-g "D16|follows the merge queue a polled job ended in"14/14; typecheck. CI (test,real-docker) passed on 9e49746.-g "D16|follows the merge queue a polled job ended in"14/14; typecheck. CI (test,real-docker) passed on 40d1563.-g "D16|follows the merge queue a polled job ended in"14/14; typecheck. CI (test,real-docker) passed on ac6dd8f.Base integration (2026-10-21)
main moved to e46cb68 (#190, #192, #195, #196, #197). Merged into the branch in 17db340 (no conflicts; shared files: docs/architecture.md, docs/designs/codeboost-plan-indexed-review.md, docs/implementation/merge-handoff.md, test/pre-merge.test.ts, test/runner-publishing.test.ts). Earlier reviews and validation are for the pre-merge pairs; the new pair needs a clean pass.
Self-review round 2 (author, base e46cb68 / head 891e6c3)
Full diff against main re-read, with the merge's shared files. Checked: the merged docs keep #195's and #197's text; status lines now true at merge; README status names the step list. No new issues found.
-g "D16|follows the merge queue a polled job ended in"14/14. CI (test,real-docker) passed on 891e6c3.Review-lesson audit (merge gate)
Each finding is covered by an existing rule, captured by the one new rule below, or a one-off with its reason.
New rule (this branch, AGENTS.md, Async review UI; CLAUDE.md has no mirror of that section): "When a background update (a poll, a reload, an answer) hides or removes the control that has keyboard focus, move focus to a named fallback that is still shown and not
disabled(anaria-disabledcontrol qualifies) once the update has set every control's final state, and test that focus lands there for each way the control can be hidden. Decide a focusable control's visibility once per update: hiding it and showing it again blurs it." (Amended after rounds 20, 21 and 22.) It captures rounds 4.2, 5.2, 5.3, 6.1 and 6.2. That class recurred, and no existing rule covered it: the existing focus rule covers only a control disabled during a request.Existing rules cited:
aria-disabled."By round (one-off reasons in brackets):
Self-review round 1: doc comment split, one-off [editorial]; untested push claim, [claim].
Round 1: 1 one-off [an internal fake cast to its type missed a new method; not an external tool; CI caught it]; 2 [current]; 3 [claim]; 4 [claim]; 5 one-off [screen-reader churn from a 1 s rebuild, and two controls with one name: accessibility details no rule names], with Cancel visibility a user decision, one-off [settled by the user, recorded beside D16]; 6 [evidence].
Round 2: 1 [backoff]; 2 [holders]; 3 [design]; 4 [claim]; 5 [claim].
Round 3: 1 [current]; 2 [current]; 3 [claim]; 4 one-off [defensive escaping of a server value]; 5 one-off [editorial; the declined part recorded with its reason].
Round 4: 1 [current]; 2 new rule; 3 [claim]; 4 one-off [a disabled control's reason lived only in
title, which keyboard and screen-reader users do not reliably get; no rule names it].Round 5: 1 one-off [a hidden element named by
aria-describedbyis still read: a browser detail no rule names]; 2 new rule; 3 new rule.Round 6: 1 new rule; 2 new rule; 3 [holders] (the ticker on the failed-load path).
Copilot round 1: 1 [current] and [one-part]; 2 [current]; 3 [current] and [one-part].
Round 7: clean; its two display-only notes were already documented, so nothing to classify.
Round 8: 1 one-off [editorial]; 2 [claim]; 3 [evidence].
Round 9: 1 one-off [settled by the user; recorded]; 2 [claim]; 3 [evidence]; 4 [evidence]; 5 one-off [declined: the route reaches 503 through shared, already-tested handling].
Round 10: 1 [claim]; 2 [holders]; 3 [evidence]; 4 [evidence]; 5 [claim]; 6 [claim]; 7 [current]; 8 one-off [the user decision recorded beside D16].
Round 11: 1 [one-part]; 2 [current]; 3 [claim] (an always-true assertion); 4 [claim]; 5 [evidence].
Round 12: 1 [one-part] and [current]; 2 [claim].
Round 13: 1 [claim]; 2 [claim] (the held refusal across a Refresh had no test), plus CLAUDE.md "A test's setup must leave the state the production path would" (the browser test's server stand-in lacked the running job a runner server's review carries); 3 [evidence].
Round 14: 1 [claim]; 2 [gate]; nit 1 one-off [the change list omitted README.md; record completeness]; nit 2 (
onAskingwording) [claim].Round 15: 1 one-off [settled by the user: follow-up Build the rest of D16 and DT7: named merge failure banners, Queue-row step, and the blocker list with links #199]; 2 new rule; 3 [gate]; 4 [gate]; 5 [gate]; 6 [evidence]; 7 one-off [settled by the user: marks added to DESIGN.md]; 8 [backoff]; 9 [claim].
Round 16: 1 [gate]; 2 [gate]; 3 [claim]; nit 1 [claim]; nit 2 one-off [the N/A mark worded "Skipped" for a step; within the approved step list, recorded in DESIGN.md's log].
Round 17: 1 one-off [settled by the user: marks added]; 2 one-off [the change list omitted three changes; record completeness]; 3 [gate]; 4 new rule; 5 one-off [settled by the user: placement]; 6 [claim].
Round 18: 1 [claim]; 2 [claim]; 3 [gate]; nit 1 [evidence]; nit 2 one-off [settled by the user; logged in DESIGN.md]; nit 3 [claim]; nit 4 [claim].
Round 19: 1 new rule (focus off Merge PR and its blockers button when a reload hides them); 2 [evidence]; nit 3 [claim]; nit 4 [claim]; nit 5 [gate].
Round 20: 1 new rule (Merge status hidden and shown again blurred it on each poll); 2 new rule (the Merge PR fallback had no test); 3 one-off [a test fixture's revision note, not an external tool; it now claims only the order]; nit [evidence].
Round 21: 1 new rule (as amended: the fallback must be enabled once the render is done); 2 [gate] (the rule did not yet say so; amended); nit [evidence].
Round 22: 1 [claim] and new rule (Cancel's check relied on a parent-hide timing the comment contradicted); 2 [claim] (the not-disabled clause had no test; added, defensive); nit 3 [gate] (rule wording); nit 4 new rule (a second write of one control's visibility).
Round 23: nits 1–3 [claim] (a split doc comment, "disables" where the button is only
aria-disabled, and the blockers button's two labels).Round 24: 1 [claim] (the display-only
onAskingguard had no test); 2 [claim] ("done after queued" had no test); nits 1–2 [claim] (wording); nit 3 [current] (a cancel answered as ended left Cancel offered until the poll answered).Round 25: 1 [claim] and [current] (the wait cleared on a stale running answer, so round 24's claim was false on the in-flight path).
Round 26: nit 1 [claim] (a retried assertion that passed on the later state); nit 2 [claim] (step times after a restart); nit 3 [claim] (an untested comment sentence).
Round 27: 1 [claim] and [current] (the older-record poll guard had no test); 2 [claim] (the shutdown half of "decides nothing"); 3 [claim] (Fetch Failed for review); nit 4 [claim] (the join half); nit 5 [claim] (DESIGN.md Frame).
Round 28: 1 [claim] (Fetch's running window on the real preparation path was untested); nit [claim] (the handoff doc's test list).
Independent review round 14 (fresh general-purpose agent, base e46cb68 / head 891e6c3): no high or medium issues and no code defects. Findings, fixed in 25e67d2 (docs, comment) and this body:
onAsking's comment says "when a store is configured".Independent review round 15 (fresh general-purpose agent, base e46cb68 / head 25e67d2): no code defects. Local at 25e67d2: merge-job 112/112, new pre-merge 7/7 (filter), route 1/1, browser 14/14. Findings, fixed in 8b9c9ad and this body:
onAsking's comment said "in the same turn as GitHub is asked". Now "the call that asks GitHub to merge", wrapped.Validation at 8b9c9ad (intermediate checkpoint): typecheck; merge-job 113/113. Round 16 ran browser
-g "D16|follows the merge queue a polled job ended in|merge-job poll"17/17 there.Independent review round 16 (fresh general-purpose agent, base e46cb68 / head 8b9c9ad): no code defects; the waiting-checks change checked against every consumer; the shared AGENTS.md/CLAUDE.md sections still identical. Findings, fixed in 03957d6 and this body:
Validation at 03957d6 (intermediate checkpoint, from round 17): typecheck; merge-job 113/113; new pre-merge 7/7 (filter); route 1/1; browser
-g "D16|follows the merge queue a polled job ended in|merge-job poll"17/17.Round 16 nit 2 classification stands; see round 17 for the remaining marks.
Independent review round 17 (fresh general-purpose agent, base e46cb68 / head 03957d6): no code defects, races or wrong route codes. Findings, fixed in the next commit and this body:
warningwithout a DESIGN.md entry. The user approved them; added to the warning row and the log. [one-off: settled by the user]Validation at 3d975e7 (intermediate checkpoint, from round 18): typecheck; merge-job 113/113; new pre-merge 7/7 (filter); route 1/1; browser 18/18.
Independent review round 18 (fresh general-purpose agent, base e46cb68 / head 3d975e7): no correctness, safety, race or route-code defects. Findings, fixed in dc6e6df and this body:
Validation at dc6e6df (intermediate checkpoint): typecheck; browser
-g "D16|follows the merge queue a polled job ended in|merge-job poll"19/19 (one earlier run of the same set at load average about 98 failed without naming the test; the rerun passed). merge-job unchanged since 8b9c9ad (113/113). CI: pending.Independent review round 19 (fresh general-purpose agent, base e46cb68 / head dc6e6df): no correctness, safety, data-integrity, race or route-code defects. Findings, fixed in 9883bec and 7e22563:
renderMergereads the focused control before hiding (hiding blurs it at once) and moves focus to Merge PR or Refresh; 4 browser tests (each control × a failed load and an unavailable reload); removing the move fails the unavailable cases.Base integration 2 (2026-10-21)
main moved to 79deeec (#193). Merged into the branch in 7e22563 with no conflicts and no shared files.
-g "D16|follows the merge queue a polled job ended in|merge-job poll"23/23. CI: pending.renderMergehid Merge status and then the running-job branch showed it again, so a focused Merge status lost focus on every poll of a running job with no blockers (to Merge PR since 9883bec, to the page before). Fixed: its visibility is decided once, counting a running job; browser test (fails without the fix).-g "D16|follows the merge queue a polled job ended in|merge-job poll"25/25. merge-job unchanged since 9883bec (113/113). CI:test(run 39570641945) andreal-docker(run 39570641957) passed.disabledstate was updated, so focus fell to the page when a reload cleared the last blocker. Fixed:renderMergerecords the focused control, renders the controls and the step list, then picks Merge PR only when shown and enabled, otherwise Refresh (the Cancel fallback uses the same choice). The "clears the last blocker" test now runs with and without a runner; the old order fails the without-runner case.-g "D16|F6b|merge"81/81. merge-job unchanged (113/113). CI: pending.document.activeElementafter hiding the step bar, working only because hiding a parent blurs at the next frame. Fixed:renderMergeStepstakes the control focused before the update; the comment states both blur timings.aria-disabledMerge PR. Rule and comment now say "notdisabled(anaria-disabledcontrol qualifies)".-g "D16|F6b|merge"82/82. merge-job unchanged (113/113). CI: pending.renderMergeStepshad two doc comments, the first saying "until Refresh". Merged; "until the review reloads".aria-disabledand keeps focus. Reworded.cancels a running merge job from the merge header1/1 (the round's filter had missed it). Code unchanged since ae68419 (browser 82/82, merge-job 113/113). CI: pending.onAskingthrows is ignored" had no test. Added a merge-job test with a throwing callback (GitHub is still asked; fails without the guard).queued" for the running step had no test. The queued merge-job test now asserts it (fails without it).aria-disabled).-g "D16|F6b|merge"82/82. CI: pending.mergeCancelAwaitingPolltraced; round 24's mutations re-checked. One Low, fixed in 1d9f910:-g "D16|F6b|merge"82/82. merge-job unchanged (114/114). CI: pending.onAsking" had no test. Added a replay test (fails ifonAskingruns before the replay). (The join half was tested in round 27.)review-requiredmaps to Stopped).onAskingsentence had no test. Added (a resend joining a click in progress; fails if a join calls it).-g "D16|F6b|merge"83/83. App and runner code unchanged since 1d9f910. CI: pending.test/pre-merge.test.tsnow asserts the progress events are exactlyfetch:running(fails if Fetch is marked done before the check).🤖 Generated with Claude Code