feat: build lanes in parallel, arm only where approval is required, flag owed audits - #769
Merged
Merged
Conversation
Ruling DR6 (the product thinker, 2026-09-29): "per-run agent limit: WORK IN PARALLEL - a run may build several pieces and run reviewers concurrently up to its limit (new build-loop work; then AC6 is testable)." The pacing spec (spc-2609202134341288) owns the ceiling and criterion 6 of itd-2609201925079472, which the one-agent-at-a-time loop can never reach. It gains piece 6, concurrent lanes and validators: the count (one slot per outstanding await, implementers and validators together), isolation (a worktree per lane in the machine store; validators read-only on a copy), how a slot is freed (a verified receipt, looked up across every lane), the order waiting work takes a freed slot (open lanes before new ones, lower step first, reviewers in round order), a `- needs:` step line (absent, a step needs every earlier one, so the in-order landing of itd-2609212103565953 holds for every spec written so far), state schema 7 (awaits as a list, a `waiting` queue, syncs), one landing at a time with a merge-not-rebase sync and a fresh round when a sibling landed first, and the pace and fix rounds per lane. Criteria C1 to C12 make criterion 6 testable, and the section names every place the loop assumes one lane at a time. Choices taken here, not in the record: `needs` defaults to every earlier step; a sync does not count against --fix-rounds (bounded by the lane count); after a hand-back siblings run on but no new lane opens; build next picks stay one run after another (cross-run is the register's). The intent gains decision 7 citing DR6; DECISIONS.md gains one line. Records only; nothing is built, shipped or closed. Assisted-by: Claude:claude-opus-5-5
…6c open The spec review of the DR6 amendment (piece 6 of spc-2609202134341288) asked for four amendments and raised two product questions. This clears the four and marks the two open where the answers drop in. - Needs across a remainder: `spec close --remainder` renumbers the carried steps from one, so a `- needs:` line copied verbatim names the wrong step. The copy rewrites it: a landed step leaves the list, a carried step is renamed to its remainder number, an emptied list is written `- needs: none`, and a step without the line keeps none. Chosen over dropping the line because it is a total function of the parse (a step is carried exactly when it has no `landed:`, and order is kept), while a drop would mean different things under each DR6b option. The steps spec's scope 4 names the exception to its verbatim copy. - After a hand-back no lane closes the spec. The auditor reads the run's own lanes' pull-request diffs (each lane's head against the default-branch sha it last merged in, or its base), never base..head, which after a sync holds outside work. - The "reviewers counted separately" evidence bullet is superseded: the issue's resolution ruled shared slots, which piece 6 holds. - Piece 9 of spc-2609202134338445 (the landing) is named a prerequisite of C8 to C10 and the landing rules. Schema 7 uses a new key `awaits` (the strict decode keeps one type per key) and refuses a version-6-or-older file carrying `awaits`, `waiting` or `syncs`, and a version-7 file carrying `awaiting`, in the shape of the existing refusals. The footprint names the status block's multi-row shape change and the site's status page. - C3 counts its 14 minutes from the call that first found the ceiling; C4 says "called until"; C6 and C12 gain the remainder and refusal cases. Open: DR6b (the needs default) and Open: DR6c (siblings after a hand-back) quote the review's options and are not decided here. Records only. Assisted-by: Claude:claude-opus-5-5
Assisted-by: Claude:claude-opus-5-5
The product thinker answered the two questions the DR6 spec review left open in spc-2609202134341288 (relayed 2026-09-30). DR6b, verbatim: "(a) ONE AFTER ANOTHER BY DEFAULT: a step runs alongside earlier ones only if its plan says so; nothing already planned changes; reviews run side by side; the 2026-09-21 wording stands." A step's default `needs` is every earlier step; running beside them is an opt-in per step. The alternatives are removed, and the remainder rewrite no longer hangs on the ruling. DR6c, verbatim: "(c) FINISH, BUT HOLD THEM: when one piece is handed back, pieces in flight finish but nothing merges until the person re-plans; the person then decides whether the held pieces land as they are." A new section specifies it: the siblings in flight run to completion, and each passing one takes the lane stage `held` (before its push, or before arming once pushed; an armed one is disarmed), recorded in `lanes[].hold` (since, cause, head, before) and shown by `implement status` with its way out. The person releases or discards each held lane with `implement step --release <lane>` or `--discard <lane>`; `implement release` is a claim verb and is not reused. A discard closes any pull request, removes the worktree and branch, and leaves the step unlanded; `discarded` is terminal. Schema 7 gains the hold and the two stages, with the version refusal. C6 and C11 drop their Open notes; C13 tests the hold, the release, the discard and the refusals through the step interface with fake agents and a fake forge. The single-lane list names the stage set and the landing's unconditional arm at 7f6eb55. The intent gains decision 8 citing both rulings; DECISIONS.md gains one line. Records only. Assisted-by: Claude:claude-opus-5-5
…nt shipped, flagged and carried by one issue Ruling DQ1c (the product thinker, 2026-09-30): "(a) STAYS SHIPPED, FLAGGED: the intent stays in shipped/, its changelog entry stands, and a 'check still owed' flag names the unmet/undecided criteria until it is fixed and re-checked." The note: "can it auto-capture an issue with the remaining check? Either fix it or check again etc.?" - intent audit ingest: a verdict judging any criterion NOT_MET or INCONCLUSIVE writes an audit-owed flag in its block (criteria, receipt, remedy, carrying issue); it never un-ships and never reads as a pass. - The ledger files that issue through capture.Capture via a seam capture registers from init (intent.SetAuditLedger), called with the intent lock released since the ledger lock comes first: judge under the lock, file or resolve, then write under the lock again. A ledger that cannot answer refuses the ingest with nothing written. - Severity/category: NOT_MET is a major bug (delivered behaviour misses its promise, already announced); undecided is a minor inconsistency (the record claims shipped with a check that could not confirm it). Both are in the drain's fixable set; the remedy is real, so the drain judges by fields. - A later failed or undecided audit of the same receipt links to the open issue (exact: related to the intent and naming the receipt), else files with the filing-time match. - A re-emit of a flagged receipt rewrites the request (check_owed); a passing re-run clears the flag with a dated line outside the block and resolves the issue (impact fix, resolved_by intent). - Brief chapters 05-intent and 35-drain, commands/intent.md (the owed drain no longer files NOT_MET by hand), DECISIONS.md entry. Refs: iss-2608290820473197, iss-2608290822140563 Assisted-by: Claude:claude-opus-5-5
…nd carried, never a pass Ruling DQ1c's flag-and-issue shape supersedes the record's OWED re-run state; the defect (an INCONCLUSIVE verdict indistinguishable from a pass, with no way to ensure the re-run) is fixed by b68b3d4. Resolves: iss-2608290820473197 Assisted-by: Claude:claude-opus-5-5
…ites Apply the re-review's corrections to spc-2609202134341288 before any code. Main already writes state schema 7 for the landing, so the amendment's state is version 8: a file of version 7 or lower migrates `awaiting` to a one-entry `awaits`, one that carries what only version 8 writes is refused in the shape of capped() and landed(), and a version-8 file carrying `awaiting` is refused; C12 is respelled 7 to 8. The land stage is on main (land.go), so the "piece 9 unbuilt" text and its build order go. The spec also names auditsHere as a single-lane site, commands/ in the footprint for the two new flags, and the disarm invocation `gh pr merge <n> --disable-auto`. Assisted-by: Claude:claude-opus-5-5
A spec step may carry `- needs: none` or `- needs: 1, 3`, naming the earlier steps it waits for (ruling DR6). A step without the line needs every step before it (ruling DR6b), so running beside earlier steps is an opt-in; Step.Requires reports either. The parser refuses a need naming the step itself, a later step, or a step the spec does not list, naming the line. `spec close --remainder` carries the unlanded steps through CarryUnlanded, which rewrites each needs line against the remainder's own numbering (a landed need leaves the list, an emptied list is written `none`), and the close names each line it rewrote, before and after. Assisted-by: Claude:claude-opus-5-5
An ingested verdict that left a check owed (ruling DQ1c) is reviewed but not done: bare `intent audit` lists it under its own heading with the issue carrying the check and the re-emit that rewrites its request for the re-run, and the JSON entry carries audit_owed, audit_owed_issue and re_emit, with an audit_owed total. It is not counted as owed, so the owed-review drain does not re-run it on its own; the captured issue carries the re-run. Assisted-by: Claude:claude-opus-5-5
The verdict a provider returns is ingested through the same path as a host's, so an undecided or failed answer flags the intent and captures its issue (ruling DQ1c). `intent audit <itd-N>` on a provider route now prints the owed criteria and the issue in its text render, and the review a `spec close` sends prints them on stderr beside its one-line outcome. Assisted-by: Claude:claude-opus-5-5
The implement loop's arm step armed auto-merge wherever the ruleset mirror named a merge queue, without reading whether a person's approval is required. Refs: iss-2609301858349258 Assisted-by: Claude:claude-opus-5-5
…ired Ruling AM1 (the product thinker, 2026-09-30): "(a) ONLY WHERE APPROVAL IS REQUIRED: abcd arms auto-merge (land.go:703) only when the project's hosting service requires a person's approval; in a project without that rule it leaves the change open for a person to merge. This project unchanged." mergeRule, the one reader of the ruleset mirror at the lane's base, also reports whether an active ruleset on the default branch requires approval: a pull_request rule with required_approving_review_count >= 1, or with require_code_owner_review set while a CODEOWNERS file at the base names an owner (this repository's own shape: count 0 beside .github/CODEOWNERS). A code-owner rule with no owner asks no person for anything, so it does not count. landArm arms only with a merge queue AND a required approval; otherwise the landing records "left open for a person to merge: the ruleset requires no approval" in its state, the run record and implement status, and landMerged never arms. A missing mirror requires nothing; a file that cannot be read or parsed stays a refusal, which arms nothing either. The test fixture's queueRuleset carries a one-approval pull_request rule, so the existing arming tests keep their meaning; unreviewedQueueRuleset is the queue alone. Refs: iss-2609301858349258 Assisted-by: Claude:claude-opus-5-5
…ired Resolves: iss-2609301858349258 Assisted-by: Claude:claude-opus-5-5
The surface chapter's prose states no verb shape above its generated appendix (TestSurfaceChapterProseStatesNoShape), so the left-open landing is described as what the run's status shows. Assisted-by: Claude:claude-opus-5-5
fileAuditOwed scanned the open ledger for a carrier of the receipt outside the ledger lock, so ingests of one failed audit racing each other each saw none and each filed: four goroutines filed four issues, none linked. The scan and the filing are now one step in one withLedgerLock hold. Capture takes the lock itself and the flock is not reentrant, so it gains a lock-parameterised seam (captureWith, with reservePathWith, commitCaptureWith and mutationPreambleWith); captureHeld runs every hold in the caller's. Several open carriers of one receipt, left by an earlier race or by an ingest whose intent write failed after its filing, collapse: a failed or undecided ingest links the oldest and declines the others as its duplicates through Wontfix with a duplicates link, the ledger's duplicate closure (wontfix --duplicates, iss-2609291118049254). A passing re-run resolves every open carrier, not only the flagged one. A transition conflict from a concurrent closer is tolerated. Refs: iss-2609301913458174, iss-2609291118049254 Assisted-by: Claude:claude-opus-5-5
Resolves: iss-2609301913458174 Assisted-by: Claude:claude-opus-5-5
…ests included The audit ingest surface row and the command page say what the ingest does with several open carriers of one receipt's check (the oldest linked, the others declined as its duplicates) and that a passing re-run resolves every open carrier. Assisted-by: Claude:claude-opus-5-5
A run hands work to several agents at once, up to its pace.sub_agents (ruling DR6, spc-2609202134341288 criterion 6). A slot is an outstanding await on any lane; the state's lanes carry `awaits`, and implementers and validators take the same slots. Each `implement step` performs a stage the binary owns on any lane first, then gives a free slot to the first waiting work: an open lane's validators or fix and sync implementers before a new lane, the lower spec step first, a round's validators in order. At the ceiling it hands out nothing, names every lane alive with its awaits, and records the held work under `waiting` with the time first held; the move that serves it records the minutes it waited. `implement receipt` looks its path up across every lane. A lane opens once the steps it needs have landed, by its `- needs:` line or, by default, every earlier step (DR6b). Landing is one lane at a time. A lane whose sibling landed since its base is synced first: the default branch is merged in with a merge commit, never a rebase, and a fresh round judges the head; a conflicting merge is aborted and goes to a fresh implementer with a sync brief. A sync counts no fix round. The closing lane reaches its landing with no step pending, no other lane open and none handed back, and its audit reads each lane's own diff. After a hand-back the siblings finish and are held before their push or arming, an armed one disarmed with `gh pr merge <n> --disable-auto`, until `implement step --release <lane>` or `--discard <lane>` (DR6c). A lane's refused landing step holds only that lane. The state goes to schema 8: a file of version 7 or lower migrates its `awaiting` to a one-entry `awaits`, and one carrying what only version 8 writes is refused, as is a version-8 file carrying `awaiting`. `implement status` names the slots in use and the held lanes, and the status block reports one row per lane alive. C1 to C13 are tests through the step interface with fake agents, the Options clock, a bare local remote and the stub forge. Assisted-by: Claude:claude-opus-5-5
Two of the DR6 criteria's tests did not tell the build from a broken one: a mutation on a scratch copy that ignored a step's needs, and one that dropped the one-landing-at-a-time gate, both left them green, because lane 1 always had a move of its own first. Each now steps once while lane 1's pull request is armed and not merged, with every slot free, and asserts that no lane opens for step 2 (C6) and that lane 2 does not begin its landing (C10). Assisted-by: Claude:claude-opus-5-5
spc-2609202134341288's progress names what landed: pieces 3 and 6, the ceiling that binds and a run that works in parallel up to it (ruling DR6, C1 to C13), on top of pieces 1 and 2. Pieces 4 and 5, the budget check and the rate-limit checkpoint (criteria 7 and 8), wait on a runner that reports its quota, so the spec closes with a remainder, spc-2609301921521360, whose summary states them. The intent stays planned; nothing ships, so this change declares no delivery. Assisted-by: Claude:claude-opus-5-5
…the ceiling The step follows the pacing spec's letter (spc-2609202134341288), on the orchestrator's ruling that the spec is the person's record and the code follows it. A landing waiting on the forge's merge (a contention refusal) is the only refusal that holds just its own lane: the call moves another lane, names the wait under `blocked` and in `next`, and the text form prints a `blocked:` line. Every other refusal of a stage the binary performs is the call's answer and no other lane moves, so an armed sibling whose disarm the forge refuses stops the step naming its pull request, as "The `held` state" says; a missing preflight receipt now stops the step too. A lane opens for a ready spec step whatever the ceiling (C4: a stage the binary performs itself is never held by the ceiling): its worktree and brief are made, and only its implementer waits for a slot. The slots-plus-reserved gate on opening, and the waiting entries keyed on a spec step, are gone. Assisted-by: Claude:claude-opus-5-5
…lf done Before it disarms an armed sibling after a hand-back, the hold asks the forge for the pull request's state: one the forge reports merged had landed before the hand-back and its landing runs on to record it. The local tracking ref is not fetched for the hold, so it may lag the merge; the forge is the answer, and the landing's own fetch then proves the ancestor. A discard removes the lane's worktree and branch first and closes its pull request last. A removal git refuses (a worktree with changes) leaves the pull request open, the lane held and the state unwritten; the retry passes over a worktree or branch already gone and closes the pull request once. Local-first was chosen over tolerating a closed pull request on retry because it leaves no half-state on the forge at all. Assisted-by: Claude:claude-opus-5-5
… opening and the discard order `implement step`'s help, the implement and build command pages, the generated CLI reference and the implement and build brief chapters state what the step does: only a landing waiting on the forge's merge holds just its own lane, named under `blocked`; any other refused stage is the step's answer; a lane opens for a ready spec step whatever the ceiling; a refused disarm refuses naming the pull request and a merged one is recorded as landed; a discard removes the worktree and branch before it closes the pull request. Assisted-by: Claude:claude-opus-5-5
The loop arms auto-merge only where the default branch's rules require a person's approval; elsewhere the lane is left open, loudly. Semantic conflict: main (1419266) unexported the loop's Advance; the branch's land_approval_test.go called Advance, so the merge calls advance. Assisted-by: Claude:claude-opus-5-5
A build run works in parallel up to its ceiling (ruling DR6, with DR6b's needs default and DR6c's hold on a hand-back); the spec closes at criterion 6 with a remainder for criteria 7 and 8. Conflicts, resolved by hunk: - land.go merged cleanly with amApproval: a held lane stops before its push or its arm (an armed one is disarmed, a left-open one keeps no merge), and a released lane runs landArm again, so it goes through the arm decision (requiresApproval, or left open). - state.go: main's runner record (itd-2609201916056194) and DR6 each claimed schema version 8. Main's is on the v0.12.0 cut, so the runner keeps 8 and the parallel state is version 9: schemaVersionSerial is 8, a version 7 or 8 file migrates its `awaiting` into `awaits`, and a version-9 file carrying `awaiting` is refused. The C12 test covers both serial versions and the brief (34-build.md) names the three versions. - loop.go: main unexported Advance and added Drive, the route stamp and the `handed` flag; DR6 moved the step's body into schedule.go. The step is DR6's move under main's name; laneResult sets handed when the call handed work out, so Drive starts each routed agent the call hands out; the route stamp reads the await the receipt names. - cli/build.go: `implement step` keeps --release/--discard, and its default path is main's Drive with the runner configuration; the render names the route, the fallback and the blocked landings; redactStep redacts the fallback's detail. - commands/build.md, commands/implement.md: both sides' text, the runner paragraph after the parallel one; status names slots, held lanes and fallbacks. Semantic: drive_test.go and DR6's tests moved from Advance/Awaiting to advance/Awaits. Assisted-by: Claude:claude-opus-5-5
…ugh the arm decision Where DR6c's hold meets AM1's arm decision: a lane left open for a person (no required approval) is held before its arm with no merge decision kept, and released it is left open again, the forge never asked to arm it; an armed lane is disarmed at the hold and armed again at its release where the ruleset requires approval. The parallel fixture takes its ruleset mirror as a parameter for the first case. Assisted-by: Claude:claude-opus-5-5
The runner's record took schema version 8 on the default branch before DR6's parallel state landed, so the parallel state is version 9; the merge of feat/loop-parallel-lanes made the renumbering, and this line records it where the closed spec still says 8. Assisted-by: Claude:claude-opus-5-5
A failed or undecided after-merge audit leaves the intent shipped, flagged "audit owed" and carried by one captured issue; a passing re-run clears the flag and resolves it (ruling DQ1c). Merges cleanly. Assisted-by: Claude:claude-opus-5-5
…he forge Refs: iss-2609302205483845 Assisted-by: Claude:claude-opus-5-5
…er review The arm decision counted any non-comment line of any of the three CODEOWNERS locations as naming an owner. It now reads the first file found in .github/, the root and docs/ only, and a line names an owner only when an owner token (@name, @org/team or an e-mail address) follows its pattern before any comment. A bare '@', a pattern-only line and a comment-only .github/CODEOWNERS shadowing a root one leave the pull request open. Refs: iss-2609302205483845 Assisted-by: Claude:claude-opus-5-5
…RS as the forge does Resolves: iss-2609302205483845 Assisted-by: Claude:claude-opus-5-5
…carrier open Refs: iss-2609302207449478 Assisted-by: Claude:claude-opus-5-5
…riers A passing ingest asked the ledger to resolve the owed check's carriers only when the intent carried the audit-owed flag, so a carrier an ingest filed before its intent write failed stayed open on an unflagged receipt. Every passing verdict now asks one sweep of the open carriers of its intent and receipt (one List of the open ledger), naming the flag's issue when there is one. Brief 05-intent.md's audit-ingest row says what the ingest does to the ledger. Refs: iss-2609302207449478 Assisted-by: Claude:claude-opus-5-5
…ipt's carriers Resolves: iss-2609302207449478 Assisted-by: Claude:claude-opus-5-5
Refs: iss-2609302210137965 Assisted-by: Claude:claude-opus-5-5
site.Build completes an older ui.json before it loads it, and a failure after that write returned an empty result, so the CLI never said which labels it had added. A failure after the write is now a *site.LabelsAddedError naming the file and the labels, unwrapping to the cause with its message unchanged, and `abcd site build` names each label on stderr before the error, as it does on success. Refs: iss-2609302210137965 Assisted-by: Claude:claude-opus-5-5
…abels it added Resolves: iss-2609302210137965 Assisted-by: Claude:claude-opus-5-5
Measured on a clean clone of c0908c662 with `reading assemble --dry-run`: widening 1,489,409 tokens (window 1,490,000 -> 1,510,000), entailment 427,804 (430,000 -> 440,000), detection 1,498,444 (1,500,000 -> 1,520,000); each is the smallest ten-thousand boundary with one per cent headroom. The batch grew internal/core/capture and internal/core/intent, which the positions read. Refs: iss-2609251455354719 Assisted-by: Claude:claude-opus-5-5
Assisted-by: Claude:claude-opus-5-5
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.
This pull request lands three reviewed changes together, plus three small follow-ups the reviews asked for. A build run now works on several steps at once, up to the limit its pace sets. The loop arms a pull request to merge itself only where a person must still approve it. And an after-merge audit that fails or cannot decide leaves the intent shipped with a visible "audit owed" flag, carried by one captured issue.
Arm auto-merge only where a person's approval is required (amApproval). This applies ruling AM1: the landing arms auto-merge only when a merge queue gates the default branch AND an active ruleset requires a person's approval, meaning an approving review count of one or more, or a code-owner review with a CODEOWNERS file that names an owner. Anywhere else the pull request is left open for a person to merge. The step's note, the run record and the run's status say so, and no later step arms it. A missing ruleset mirror requires nothing. A mirror that cannot be read is refused. This repository's own rules still arm.
A build run works in parallel up to its ceiling (dr6Build). This applies ruling DR6, with DR6b and DR6c. A slot is one outstanding agent, counted against
pace.sub_agents. Eachimplement stepfirst performs a stage the binary owns on any lane. Then it hands a free slot to an open lane's work before a new lane's, the lower spec step first. At the ceiling it hands out nothing and names every lane alive. A step may declare- needs:; without the line it needs every earlier step. Lanes land one at a time. A lane is synced with a merge commit, and judged afresh, when a sibling landed since its base. When one lane is handed back, its siblings finish and are held before they push or arm; an armed sibling is disarmed.implement step --release <lane>lands a held lane and--discard <lane>drops it. A released lane lands through the arm decision above, so it is armed only where approval is required. The spec closes at criterion 6, with a remainder (spc-2609301921521360) for criteria 7 and 8, so the intent stays planned and this change declares no delivery. The run's state file is schema version 9: the runner's record already took version 8 on the default branch. A version 7 or 8 file migrates on read, and DECISIONS.md records the renumbering.An owed audit check stays visible (dq1cFlag). This applies ruling DQ1c. When
intent audit ingestgets a verdict with any NOT_MET or INCONCLUSIVE criterion, it writes an "audit owed" flag into the intent's Audit Notes naming each such criterion, the receipt, the remedy and the issue that carries it. The intent never leaves shipped/. That one issue is filed through the ledger's one filer. A second failed audit of the same receipt links to it, even when ingests run concurrently, and extra carriers are closed as duplicates. A passing re-run clears the flag and resolves the issue. Bareintent auditlists a flagged receipt under its own heading.Follow-ups. The arm decision reads CODEOWNERS as the forge does: only the first file found in
.github/, the root anddocs/, and only a line whose pattern is followed by@name,@org/teamor an e-mail address. Every passing audit ingest also resolves any open issue still carrying that receipt's check, so an issue left behind by an interrupted ingest does not outlive a pass. A site build that fails after adding missing labels tosite-src/ui.jsonstill names each label it added, before the error. The reading windows are recalibrated at the tip.Reviews: amApproval SHIP; dr6Build SHIP, fix round re-verified SHIP; dq1cFlag SHIP, fix round re-verified SHIP.
Resolves: iss-2609301858349258
Resolves: iss-2608290820473197
Resolves: iss-2609301913458174
Refs: iss-2609291118049254
Refs: iss-2608290822140563
Resolves: iss-2609302205483845
Resolves: iss-2609302207449478
Resolves: iss-2609302210137965
Refs: iss-2609251455354719
Assisted-by: Claude:claude-opus-5-5