Repository navigation
mtcollins1 runner: dispatch the floor to the attempt's slot and read the run back (leg 3) - #13211
gunbai-bot[bot] wants to merge 47 commits into
Conversation
…inding (leg 2) One JIT mint over a slot sum (microVM cell | transient systemd unit on a gunbc.managed_host host); ensure-style deregistration with org-listing readback and typed refusal on every exit; teardown inventory generalized to a host-unit arm; census row for deregistration (pre-approved, ruling 2026-10-03); route legs registration/deregistration bound. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ttempt label as input; collect the run back (leg 3) Generalizes extdeps.github.workflows CreateDispatch from the heal-only expected_healed_sha key to the upstream's own inputs object, and dissolves create_dispatch_unconsumed_frontier_rows with a production caller. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ack's subject is the dispatched run Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
briansrls
left a comment
There was a problem hiding this comment.
Reviewed exact head 64232065e23d7719615a57f7be51e10b385b37c6. The generic inputs object and the version-pinned 200 dispatch response are the right upstream shape, and the collection correctly refuses an incomplete page rather than reading omission as absence. The route is not ready to bind its dispatch leg yet.
1. A possibly committed dispatch is reported as refused
dispatch_qualification_floor matches raw RestOutcome and maps every non-RestOk arm to QualificationDispatchRefused. CreateDispatch is a mutation. In this repository's own transport authority, a transport refusal, an undecodable mutation response, or a 5xx is RestExchangeCommitAmbiguous: the run may have been created even though the receipt did not arrive.
Use classify_rest_outcome(RestMutationExchange { ... }). A decided 4xx may be a typed refusal; transport/5xx/undecodable outcomes must be a distinct ambiguous standing retaining the target and attempt for reconciliation. They must not be safe to retry as though no run exists.
Required controls: 422 -> refused; no response after send / 5xx / undecodable 200 -> commit ambiguous; successful 200 -> dispatched.
2. The route has no sealed dispatch subject and no production consumer
dispatch_qualification_floor(target, attempt) accepts an open QualificationWorkflowTarget and a free attempt string. It does not consume the authorized host-unit registration or slot, and nothing proves that the selected workflow declares qualification_attempt_dispatch_input and uses it in the floor job's runs-on. The witness only compares the free string with what ephemeral_slot_labels would derive.
The PR also states that no mode or job exists and no live dispatch occurs. Therefore dispatch_qualification_floor is an unconsumed effect function, not yet the bound route leg, and deleting create_dispatch_unconsumed_frontier_rows / changing mtcollins1_dispatch_leg to LegBoundToAuthority is premature.
Construct one sealed dispatch subject from:
- the authorized JIT registration/slot;
- the exact generated workflow declaration and repository/ref;
- the input declaration that the workflow actually consumes in
runs-on.
The route orchestrator must invoke that subject. Until then, keep the leg awaiting and the consumption frontier open.
The same relation is missing on readback: collect_qualification_run takes a bare WorkflowDispatchReceipt, another target, and another attempt independently. It must consume the sealed successful dispatch result so none can be crossed.
3. The census says WIF while the effect uses GITHUB_TOKEN
The new census row uses convergence_principal() and declares RealizedFederatedGrant. In this corpus that pattern is the fleet cloud principal reached through GitHub OIDC -> STS. The actual service is authenticated by the job's repository-scoped GITHUB_TOKEN; these are different credentials and authorities.
No workflow job lands here, so no job currently establishes the actions: write permission required by CreateDispatch. The operator ruling answers whether a per-dispatch human approval is needed; it does not prove which credential executes or what permission it holds.
Model the actual Actions-job credential and bind it to a real job with actions: write, or perform the dispatch through a genuinely federated GitHub App authority. Do not mark the site RealizedFederatedGrant before that path exists. Also re-evaluate ReversibleByReapply: dispatching again creates another durable run; it does not undo the prior dispatch.
4. Labels do not establish which runner executed the floor
job_served_by_attempt checks only that the job's label list contains the attempt and that started_at exists. That establishes that a job with those selection labels started; it does not join the job to the JIT registration this route minted. GitHub's job resource publishes runner_id, runner_name, and runner-group identity separately, and the JIT mint already returns the runner id.
Carry the authorized registration into the collection and compare the job's actual runner identity to it. Also identify the floor/instrument-producing job, not merely any job in the workflow: a helper job on the attempt runner beside the actual floor on another runner must refuse.
Required controls:
- another runner with the same labels refuses;
- a helper job on the attempt runner while the floor job runs elsewhere refuses;
- the named floor job on the minted runner id succeeds.
5. The collection can silently switch to a rerun
WorkflowRun and WorkflowJobRun carry run_attempt, and this module's upstream authority explicitly says the attempt is load-bearing. collect_qualification_run ignores it and calls ListJobs with its default latest filter. A later rerun of the same run id can therefore replace both the jobs and the conclusion attributed to the original dispatch.
Bind the collection to the dispatched attempt. Use the attempt-scoped jobs endpoint and an attempt-specific run reading, or refuse whenever the run has advanced beyond the admitted attempt. Verify every collected job's run_id and run_attempt.
Required RED: dispatch attempt 1 followed by rerun attempt 2 cannot be collected as attempt 1 merely because attempt 2 carries the same labels.
6. The success carrier is forgeable and drops the workload identity the assessment needs
QualificationRunCollection is open, and conclude_qualification_run accepts caller-authored run/job values. Its collected arm then retains only attempt, run id, conclusion, jobs, and an unextracted list. It drops the dispatch target, workflow id, event, head_sha, ref, and run attempt.
The eventual throughput assessment is pinned to an exact revision and workflow subject; the extraction frontier cannot recover those facts from this value without rereading and creating another authority. Make the production success payload construction-confined and retain the sealed dispatch plus the complete load-bearing run identity (head_sha, workflow/workflow-id, event, run_attempt, target/ref) beside the job evidence.
This head is also stacked on #13206, whose construction and lifecycle blockers remain until that base is repaired and this branch is rebased. Exact-head required CI is currently queued; the findings above are semantic and independent of its result.
…e the carrier-returning helper (constructor proxy) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
briansrls
left a comment
There was a problem hiding this comment.
Reviewed current exact head 303651b9b27d1295c969a9aae396686482f99ee0 (requested f33d26589c7... plus the later constructor-proxy fix). The new construction work is sound:
DispatchedQualificationRunseals target + attempt + dispatch receipt, andcollect_qualification_runconsumes only that value, so the read phase is causally downstream of a successful dispatch and its three subject inputs can no longer be crossed.CollectedQualificationRunis construction-confined;conclude_qualification_runadmits only the production collector and Bool-returning claims; deleting the carrier-returning witness helper closes the constructor proxy.RunSubjectMismatchnow refuses a different run id, a non-workflow_dispatchevent, or jobs belonging to another run.
Those changes close the readback cross-wire and the forgeable-success half of the previous review. Five load-bearing issues remain.
1. Mutation ambiguity is still collapsed into refusal
dispatch_qualification_floor still maps every non-RestOk outcome to QualificationDispatchRefused. For CreateDispatch, transport refusal, 5xx, and an undecodable response are commit-ambiguous: GitHub may have created the run even though this caller received no usable receipt.
Use the repository's mutation classifier and retain three standings:
- decided 4xx -> refused;
- transport / 5xx / undecodable mutation answer -> commit ambiguous, retaining target and attempt for reconciliation and not safe to retry;
- 200 -> sealed dispatched run.
Required controls remain 422 / transport-or-5xx / success.
2. “Authority implemented, not wired” is not represented by this head
The intended status in the update is reasonable, but the current model still says the opposite:
dispatch_qualification_flooris an unrestricted privileged effect taking an openQualificationWorkflowTargetand a free attempt string;- it does not consume the authorized JIT slot/registration or prove that the target workflow declares this input and feeds it to the floor job's
runs-on; create_dispatch_unconsumed_frontier_rowsis deleted;mtcollins1_dispatch_legis stillLegBoundToAuthority.
RouteLegStanding currently has only bound vs awaiting, so there is no structural “implemented but unwired” state. When #13206's split lands, rebase this PR and put this leg in that explicit implemented/unwired arm until the route orchestrator consumes a sealed dispatch plan joining:
- the authorized host-unit JIT registration/slot;
- the exact workflow/repository/ref;
- the declared input actually consumed by that workflow's floor
runs-on.
Until that split exists here, keep the leg awaiting and keep the consumption frontier open. The new sealed dispatch result fixes collection; it does not seal the privileged dispatch subject.
3. The authorization row still describes a different credential
The effect uses the job's repository GITHUB_TOKEN, while the census row binds convergence_principal() and declares RealizedFederatedGrant; in this corpus that principal is the cloud WIF identity, not the Actions job token. No real workflow job in this PR establishes the required actions: write permission.
Model the actual Actions-job credential and permission on the job that will call this authority, or route the write through a genuinely federated GitHub App authority. The operator ruling removes per-dispatch human consent; it does not establish the executing credential. Also, ReversibleByReapply is not accurate for dispatch: reapply creates another durable run rather than reversing the first.
4. RunSubjectMismatch does not establish the runner or the floor job
The new checks establish the GitHub run and job-list subject. job_served_by_attempt still establishes execution only from an attempt label plus started_at.
Another runner can carry identical labels, and a helper job can run on the attempt runner while the actual floor/instrument-producing job runs elsewhere. Carry the JIT mint's runner_id into the dispatch subject, model the job resource's actual runner identity, and identify the exact floor job. Required controls:
- same labels on another runner -> refuse;
- helper on the minted runner, floor elsewhere -> refuse;
- named floor job on the minted runner id -> collect.
5. Reruns and assessment identity are still lost
collect_qualification_run still uses ListJobs with the default latest-attempt filter and checks neither WorkflowRun.run_attempt nor WorkflowJobRun.run_attempt. Attempt 2 therefore passes every new run-id/event/job-run-id check and can replace the execution created by the original dispatch.
Use the attempt-scoped jobs read (or explicitly bind/refuse on the expected attempt), and check every job's run attempt.
The sealed success payload also still drops the load-bearing identity needed by instrument extraction and throughput assessment: target/ref, workflow id, head_sha, event, and run attempt. Retain the sealed DispatchedQualificationRun plus the observed WorkflowRun identity in CollectedQualificationRun; otherwise the follow-up extractor must reread GitHub and create a second authority for what workload was measured.
The remote 6/6 receipt and the outside-construction resolve refusal are accepted for the walls they exercise. Exact-head required CI is currently queued. This PR also remains stacked on #13206, so its inherited construction/lifecycle blockers must be repaired and rebased before this head can be approved.
…pt, token check, workflow compare; split RouteLegStanding
(1) post-delete listing consumes the delete receipts (readback_after_deletes)
(2) JitRegistration sole_constructor, minted only by jit_registration_of
(3) refuse a token or authority for another App/installation
(4) JitDeregistrationReceipt sealed, built only from a GitHub listing
(OrganizationRunnerListRead sealed); pure classifier kept
(5) slots carry their workflow; mint refuses a group restricted to another
RouteLegStanding = LegWired | LegAuthorityImplemented | LegAwaitingAuthority;
route_is_executable requires LegWired; registration/deregistration are
LegAuthorityImplemented with the wiring they owe.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…mplemented with the fleet-converge wiring owed Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… derived runner image until the untangle 4a runner medium Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…sion/jolly-bat-898
…ambiguous standing, App-token credential, runner-id floor join, attempt-1 binding, ruling+interpretation+interlock - QualificationDispatchSubject (sole_constructor) minted only from the route's JIT registration and its delivered credential, the slot's workflow == the generated fleet-converge workflow, and a floor job whose runs-on is exactly the declared attempt input; REDs for other workflows and labels - dispatch classified through RestMutationExchange: 4xx refused, transport/5xx/undecodable ambiguous - CreateDispatch takes its bearer as an input; dispatch runs under the gunbai-ci installation token, credential checked against DispatchWorkflow; takes the host-generic UnitHoldProof (interlock) - collection: attempt-scoped jobs, run_attempt == 1, revision pinned, workflow path, and the floor job's runner_id == the minted runner id; collected payload keeps the sealed dispatch + WorkflowRun - WorkflowJobRun gains runner_id/runner_name (upstream job resource fields) - census: IrreversibleEffect, discharged by the 2026-10-03 ruling (verbatim) through a separate scope interpretation (eager-gull-22, 2026-10-04); interlock rostered; narrowed-interpretation RED Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…n_ref_in_list arity, no panic) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… the minted JitRegistration name); drop runner_id; fix witness braces Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Head
1. A dispatch that may have committed was reported as refused.
Controls: 422 → refused; transport failure, 503 and undecodable 200 → ambiguous; success → dispatched. 2. The dispatch subject was unsealed and had no consumer.
The production mint passes I did not restore 3. The census described a different credential.
4. Labels did not establish which runner executed the floor.
5. A rerun could replace the dispatched run. Jobs are read through the attempt-scoped endpoint for attempt 1 ( 6. The success result was forgeable and dropped the workload identity. The 25 transcribed census rows written before — sent from jolly-bat-898 |
…mplate expression (floor NonFoldResidueRosterDiverged) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… joined floor job; one join, not two collect_qualification_run now joins the floor job to the minted runner (job_ran_on), so leg 3b's designated_floor_job and QualificationExtractionSubject are deleted; the receipt carries the sealed CollectedQualificationRun and the registration's host-unit slot. Log and artifact reads are token-bound beside read_run_with in gunbc.github_effect_perform. ActionsArtifact keeps only the fields a consumer reads (review 75456: the unread size_in_bytes Int is removed, not wrapped). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…uery subject (side-chat RC on #13206) (1) JitMintDispatchAuthorized { dispatch: AuthorizedJitMintDispatch } sole_constructor, minted only by dispatch_jit_mint; dispatch_jit_mint, attempt_dispatch and the witness helper `dispatched` are admit_callers-sealed so no admitted caller returns it onward. (2) OrganizationRunnerListRead carries organization, name, App and installation; readback_subject_refusal runs before the answer is read; conclude_from_readback, its inner step and readback_after_deletes admit only ensure_jit_runner_deregistered. REDs: compile probe test.probe.jit_deregistration_forged_probe (victim-runner forgeries of all four sealed records + unadmitted conclusion) enrolled by test.claim.jit_deregistration_forged_probe_witness; pure readback-subject RED. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…sion/jolly-bat-898
… subject consumes the sealed authorized dispatch; witness claims mint in place, admitted by name Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…nt case (floor COMPLETED-OVER-COST-REQUIREMENT 604048 > 72300) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…pure scope checks, run expectation, hold), ONE real-path claim through the mint The scope checks and the run decision take values: qualification_slot_refusal, qualification_floor_admission, QualificationRunExpectation, hold_covers_slot_host. The subject mint composes them; collect derives the expectation from the sealed subject. Only the_real_mint_admits_the_attempt_and_refuses_todays_workflow runs dispatch_jit_mint and the subject mint (admit lists trimmed to it). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…rop the fleet_converge_workflow evaluation (~600k eval steps, a fact about generated data) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ts own claim in the long tier, with its measured cost declared (~600k eval steps building the generated model) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…_slot_controller resolved as the union) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ep leg-2's added imports) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…t_converge_workflow (a shape fix: the ~600k-step jobs were built and never read); its refusal claim returns to the module witness Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
briansrls
left a comment
There was a problem hiding this comment.
Reviewed exact head cf291596a5b95356f0df10a05cbeed3aae24188d.
The cost-shape repair is right. qualification_dispatch_subject now asks the standalone fleet_converge_dispatch_inputs declaration before constructing the ~600k-step workflow value, so today's SubjectAttemptInputUndeclared path no longer pays for jobs it cannot read. Returning that claim to the ordinary module witness and deleting the long-tier file follows from that structural fix.
The earlier review classes are also substantially closed: dispatch mutation ambiguity is distinct from refusal; dispatch is honestly LegAuthorityImplemented, not wired; the subject, dispatched run and collected run are sealed; collection uses attempt 1's endpoint and retains the complete observed run; the App installation token is checked for actions: write; and the UnitHold interlock plus irreversible-effect census shape are present.
Four identity joins still block approval.
1. A delivered JIT config is joined to the authorized dispatch only by slot
qualification_dispatch_subject_over derives JitRegistration from authorized dispatch A, then accepts JitCredentialBoundToAttempt from any mint whose delivered_slot == registration.slot.
That is not the complete mint subject. AuthorizedJitMintDispatch also owns App, installation, organization and request. JitCredentialDelivery carries only slot, config and runner id. Two authorized mints can therefore name the same host-unit slot under different App/installations or organizations; delivery B passes the same-slot check beside registration A, and the sealed qualification subject then claims A's registration even though the credential actually delivered came from B.
Retain the sealed authorized dispatch (or the exact sealed JitRegistration) on the successful delivery and require equality with the dispatch used to construct the subject. A same-slot/different-installation-or-organization RED should refuse before a dispatch subject exists.
2. The permission authority is not bound to the token that performs the request
dispatch_qualification_floor correctly requires the token's App/installation to equal the registration's. It then separately calls credential_authorizes(authority, control_plane, effect), but never proves that authority names that same App/installation.
Thus token A + registration A can be accompanied by an authority/control-plane observation for installation B that has actions: write; the check passes for B and the HTTP request is made with A. The deregistration authority already has the right pattern: project authority_installation and compare it with both the token and registration before asking whether the permission is held.
Required RED:
registration/token: App A installation A
authority/control plane: App B installation B with actions:write
→ refuse before network
An ActionsJobCredential likewise must not authorize an installation-token request merely because it has an equivalent permission axis.
3. Collection still identifies both the runner and the floor by non-unique names
The successful JIT delivery already carries GitHub's runner_id, but QualificationDispatchSubject drops it and collection joins only on WorkflowJobRun.runner_name == JitRegistration.name. This repository's own deregistration model treats one runner name as potentially resolving to a list of ids, so name equality is not the exact registration identity the route minted.
Carry the delivered runner_id through the sealed dispatch subject, model the job resource's runner_id, and compare them. runner_name can remain corroboration. Required RED: same runner name and labels, different runner id, refuses.
The floor side has the analogous problem. The subject locates the authored workflow job by YAML id, then drops that id and retains only its display name. GitHub's job readback is accepted when its name equals that display name. Two authored jobs may share a display name, so a helper with the floor's name on the minted runner while the actual floor runs elsewhere currently satisfies the collection.
Either prove at subject mint that the selected floor's display name is unique across the workflow, or introduce a stable provider-observable marker. Add the same-display-name helper RED; the current helper control uses a different name and does not discriminate this case.
4. The authorized revision is not the ref dispatched
The sealed subject carries both branch and pinned revision. qualification_dispatch_effect names the revision, but CreateDispatch receives subject.branch. If that branch advances after the subject is minted, GitHub runs another commit. RunRevisionNotPinned notices only after the irreversible dispatch and after the wrong workload may already have executed on the self-hosted runner.
The dispatch subject needs an immutable executable ref tied to the pinned revision—for example an admitted tag/ref whose target is that revision—or an equivalent construction that makes branch movement unable to change the dispatched code. A post-run SHA rejection is necessary evidence, but it is not a pre-write admission wall.
Required RED:
subject minted for revision A
branch resolves to B before dispatch
→ no CreateDispatch request
The separate ruling-scope interpretation is represented honestly and its narrowing control is useful; I am not blocking on that shape here. The present-refusal cost fix is also accepted. When the boot leg finally declares the input, however, the production mint will again cross into full workflow construction, so that wiring PR must demonstrate the admitted path stays within its applicable execution budget or split out the floor-job declaration as another consumed projection.
Exact-head required CI is currently queued. These four findings are semantic and independent of its result.
…h authority bound to the token's installation; runner_id join with name corroboration and a unique floor display name - JitCredentialBoundToAttempt gains dispatch: AuthorizedJitMintDispatch (set in receive_jit_mint; an edit to #13206's type made here per quiet-stag-623); the subject refuses a delivery from another dispatch (SubjectDeliveryForAnotherDispatch), RED with two authorized mints for one slot - dispatch_authority_refusal: the authority must project to the registration's App/installation; an ActionsJobCredential refuses (REDs for other App, other installation, job token) - WorkflowJobRun regains runner_id; the subject carries the delivered runner_id and collection joins on it, runner_name corroborating; the floor's display name must be unique at the subject mint Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
briansrls
left a comment
There was a problem hiding this comment.
APPROVE at the requested exact head 38e5456b16dc7f88356da20891272c39f573edda, against DESIGN.md §§3, 4d and 5. This reconfirms the approved leg-3 semantics with the subsequent ruling/discharge corrections. The branch advanced to b1646813556449a5462ad157c20b395fb5b74d58 during review; that later head is not covered.
The October 3 ruling is no longer rewritten to include dispatch. runner_lifecycle_operator_ruling.effect_subject states registration and deregistration, while runner_lifecycle_scope_ruling records the separate October 5 operator confirmation and its escalation reference. The record distinguishes the operator's quoted decision from the relayed description of its scope. I am relying on the operator confirmation supplied in this review request and its recorded attribution, not claiming to have independently opened the escalation service.
The revised relationship is correctly one-way: a site may consume this ruling's discharge only where covers names it; membership does not force consumption. ruling_discharge_for derives dispatch's discharge from that list. Registration, deregistration, branch creation/pinning and branch removal carry NoWitnessDischarge. Their existing EveryProvision/reversible/API/bindable/no-wide-mint/no-bill parameters independently select federation under authorization_pattern_selection.witness_required; removing the gratuitous discharge does not remove an obligation they otherwise owed. This does not make a new claim about the credential's least privilege or branch immutability.
The controls retain both useful directions: a discharge outside the scope is rejected by the census witness, each covered declaration must exist in the census, the five real census rows must select federation and conform, and removing dispatch from a supplied scope makes that same irreversible dispatch cease to select federation. The existing interlock-census witness remains.
The actual dispatch still checks the supplied UnitHoldProof against the slot's host before sending, then checks token and permission-authority App/installation identity. Collection still enters through plan_qualification_collection; both reads and the collected carrier are confined to its admitted arm. The JIT mint module is byte-identical to the previously approved 7ebc19e01aa6076c4d5acc87089a2c00570589a6 (blob dc3058a8f09fcb4bc91c1f6fd98b3b42bedd4410), preserving the receiver/generate-fold confinement. The first-step revision guard, attempt/job/runner joins and commit-ambiguous dispatch result remain in place.
This is a source/delta review, not execution of claims, mutants, dispatches or hardware actions. The exact-head PR-triggered witnesses run 37271534619 was queued when checked, so approval is not an all-green CI receipt. Retain required exact-head checks and the landing order: this base before its children. The previously declared workflow-file mutability and not-yet-wired route obligations are not discharged by this approval. The stale PR-body references to an agent interpretation and the earlier open delivery shape are not the implementation approved here.
briansrls
left a comment
There was a problem hiding this comment.
APPROVE at exact head b1646813556449a5462ad157c20b395fb5b74d58, against DESIGN.md §§3, 4d and 5. Reconfirmation of review 5410797131 at 38e5456b16dc7f88356da20891272c39f573edda.
The complete comparison from that approved head is one commit changing only annotations in gunbc.auth.privileged_effect_census and gunbc.runner.runner_qualification_ref_pin. No function, data row, signature, import or witness changes in this increment.
The clarification accurately separates authorization facts: the operator's scope covers the per-attempt branch creation/removal, not the dedicated group's selected-workflow update. ensure_qualification_ref_pin is named in covers for its branch-create effect; its group update relies on the existing independently selected federated standing. The row continues to carry NoWitnessDischarge, so this annotation neither broadens a ruling discharge nor removes an interlock. Dispatch remains the irreversible consumer of the scope-derived discharge and retains its host-hold requirement.
authorization_pattern_selection_witness_test.dag at this head has blob 3da3815d4438107d93d5f82ee66ef10d5399f190, identical to the previously reviewed 38e5456b16 file. Its merged import header, scope-discharge controls and other claims are therefore preserved byte-for-byte; this head update introduces no further merge-resolution change there. The previously accepted JIT confinement, collection planning, identity joins, revision guard and ambiguous-dispatch handling are unchanged.
Source/delta review only; no claims, mutations, dispatches or hardware actions were executed. The exact-head PR-triggered witnesses run 37273280868 was queued when checked. Land only after required exact-head checks pass, before dependent runner PRs. This approval does not clear #13288's independent create-request control gap or discharge the previously declared route-wiring and workflow-file-mutability obligations. Head reconfirmed immediately before submission.
…me field, no RestExchangePerformance) Conflicts: github_effect_perform.dag (imports; the generate fold takes main's RestResult and keeps this branch's admit_callers seal) and github_effect_perform_witness_test.dag (main's RestAnswered call, this branch's sealed BoundJitCredential pattern). Beyond the conflicts, the port touches logic: this branch's REST ops drop their outcome fields (CreateDispatch's body is now result: WorkflowDispatchReceipt), the qualification performers carry RestResult<T>, and the dispatch, run collection, ref pin and branch removal decisions match RestAnswered/RestRefused and classify only the refusal (classify_rest_refusal, read or mutation). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The three new operations drop their outcome field; read_job_log_with / list_run_artifacts_with / download_artifact_with carry RestResult beside the sealed read; job-log and claim-cost refusals carry RestExchangeRefusal from classify_rest_refusal (a download 410 stays ClaimCostArtifactExpired). Witnesses build supplied RestResult values through small helpers. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
briansrls
left a comment
There was a problem hiding this comment.
APPROVE at exact requested head 15eb7f6b1a16bf967cca27513522d3ae344cc536, against DESIGN.md §§3, 4b and 5. Reconfirmation of the leg-3 approval at b1646813556449a5462ad157c20b395fb5b74d58, which is this merge's first parent; the second parent is main c82e4971029b3b2ba1e58ece3e7ab0ed3a2357d9. The RestResult adaptation preserves the reviewed decisions without restoring the deleted outcome/body product.
REST boundary and dispatch
The four added/adapted operations describe decoded answer bodies only. CreateDispatch now has result: WorkflowDispatchReceipt, and dispatch_workflow_with projects answer.result only inside RestAnswered. The run, attempt-jobs and ref readers likewise project their declared body field only on an answer, carrying RestRefused unchanged. There is no fabricated payload beside a failed exchange.
qualification_dispatch_standing now carries the successful receipt in DispatchStandingSucceeded itself. Only that arm mints DispatchedQualificationRun. Refusals go through the existing classify_rest_refusal(RestMutationExchange): a decided status refusal remains DispatchStatusRefused, while transport failure, server error and undecodable mutation response remain commit-ambiguous with the sealed subject retained. No automatic retry or read-style classification was introduced. The supplied control still distinguishes 422, lost response, 503, undecodable 200 and the successful receipt.
The host hold, token-to-registration join, authority-to-installation join and permission admission still precede dispatch. This port does not change the previously reviewed authorization scope.
Collection
collect_qualification_run still matches the pure collection plan before either read and obtains run id/attempt from that plan. Its only success mint remains inside the checked entry; no unchecked _under path returns.
decide_qualification_run eliminates RestResult separately for the run and jobs. Their refusals are classified as reads and remain RunReadUnreadable / RunJobsUnreadable, never empty successful populations. The run-id/event/workflow, attempt-1, branch and revision comparisons, completion/conclusion checks, exact jobs population, and runner-id/name/floor-job joins remain in place. The collected payload still retains its sealed dispatch, observed run and designated job. The ported controls preserve the distinction between a failed floor that really ran on this runner and a run that cannot be attributed to it.
Ref pin and removal
The initial ref read still admits creation only on a classified 404. A present branch refuses; a lost/undecodable read is not absence. Create refusal classification remains mutation-specific, with the same preexisting/status/ambiguous decisions. Group-update refusals also use mutation classification, and successful update still requires the independent group restriction readback.
The SHA now comes from the answered GitRefWire inside qualification_ref_pin_of, rather than a separately supplied readback string. A refusal has no SHA to project. The exact-revision and group-readback controls are preserved.
Removal remains readback-driven. RestAnswered on the post-delete GET means BranchStillPresent, even after an answered delete; only a classified GET 404 establishes removal. The new delete_refusal: RestExchangeRefusal? retains a delete failure as explanatory evidence and does not decide absence. An already-absent initial read still returns removal without claiming a delete was issued. This is the same decision as the approved parent, expressed without a success member in RestExchangeRefusal or an invented readback body.
JIT merge resolution and evidence
jit_mint_performance_of_generate adopts main's RestResult while preserving its admit_callers restriction to the real performer and the consuming Bool claim. receive_jit_mint remains confined, and BoundJitCredential still holds the complete authorized dispatch, credential and runner id. The merged generate witness matches that sealed payload; the outside-generate probe now supplies RestAnswered and still targets the actual restricted callee. The port therefore does not reopen either rewrapping route.
Verified exact-head workflow 37304513141: floor, generated, emit-build and aggregate witnesses all succeeded. The reported remote Hermetic 158/0 across nine modules remains author-run evidence; I did not execute local tests, mutants, network mutations or hardware actions. GitHub initially reported non-mergeable during this review, then reported mergeable on the same unchanged SHA immediately before submission.
No remaining source blocker in this port. Preserve the declared route-wiring and workflow-file-mutability obligations. This review covers neither the forthcoming #13288/#13225 ports nor a live dispatch/boot execution; those landing heads need their own reconfirmation.
…dispatch fold The collection-relabel probe is a fixture; its closure reached gunbc.fleet_converge_workflow through the dispatch module's production wrapper, and from there extdeps.gunbc (WitnessBin.Run), which the fixture-closure union emit refuses for target rust. The wrapper moves to gunbc.runner.runner_qualification_production_subject, the only importer of fleet_converge_workflow; the fold's closure no longer reaches extdeps.gunbc. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…STAYS DELETED prose (review 77507) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
Addressed review 77507: the |
…llected (review 77511) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
Addressed review 77511: |
briansrls
left a comment
There was a problem hiding this comment.
APPROVE at exact head 048afa6f637ab0899be37c9f4a6ae23a163feec1, re-confirming the revision since approved 15eb7f6b1a16bf967cca27513522d3ae344cc536. No blocking finding. The module split is justified on its own merits, not merely as a way around FixtureClosureUnionEmitRefused.
Why the boundary is right independently of #13466
qualification_dispatch_subject_over decides whether a supplied Workflow, sealed JIT dispatch/delivery and ref pin describe an admissible qualification subject. Constructing the complete generated fleet workflow is a different responsibility. Only qualification_dispatch_subject chooses that concrete workflow and reads its separately declared dispatch inputs. Moving that binding into gunbc.runner.runner_qualification_production_subject removes an unnecessary dependency from the subject-admission/dispatch module, without weakening the obligation of the production binding to consume the actual generated workflow.
I would retain this separation even if every operation in the full fleet closure emitted successfully. The collection-relabel probe needs the collection and dispatch carriers; it does not need to construct unrelated fleet modes and their host realizations merely because they previously shared a file with those carriers. The semantic dependency is removed at its owner, not hidden from a closure walker. These three commits change no walker, fixture exclusion, gate enrollment, emit refusal, or target-specific fallback. There is no replacement fake workflow on the production route, no copied decision and no compatibility wrapper left behind. #13466's transport exclusion and this responsibility split address different boundaries.
Preservation checked
The comparison is three commits affecting four files. The production wrapper's signature and executable body move unchanged: the real fleet_converge_dispatch_inputs still supplies the early check; failure remains SubjectAttemptInputUndeclared; the other arm still passes the real fleet_converge_workflow to the same admission fold. The qualification subject remains sole_constructor. Its mint's admit_callers replaces the old wrapper identity with the new module-qualified identity and retains exactly the same two Bool-returning witness entries. Its actual delivery, registration, attempt, group, workflow and floor checks are unchanged. No token/hold, RestResult classification or collection read-plan decision changes in this revision.
The dispatch witness's import follows the wrapper, with its claim bodies and assertions unchanged. the_production_mint_over_todays_fleet_converge_workflow_refuses_at_the_attempt_input still calls the moved production function, through the real JIT mint, and requires the named missing-input refusal. The supplied-workflow positive still exercises the sealed subject mint and its downstream expectation. This preserves the existing pairing; it does not claim the not-yet-wired production acceptance arm has now run.
qualification_collection_relabel_probe is unchanged and still attempts to forge CollectedQualificationRun. Its executing consumer requires a blocking SoleConstructorViolation at that exact carrier; the names-only control is retained. The closure cut has not replaced the intended forgery discriminator with a generic compilation failure.
8c1f0cd2c1 changes only the runner-field annotation. 048afa6f63 removes the seven-line Bool projection qualification_run_collected, not the collection producer, sealed carrier or typed refusal. No witness body or collection decision is deleted with it.
Execution independently verified
Workflow 37597806570 explicitly names this head and completed successfully. All five jobs succeeded, including all-target lint, stage0 mirror checking, floor and emit-build.
I downloaded its required-floor-claim-cost artifact 11474690055 and verified the ZIP SHA256 against GitHub's published digest: 3bd8bad2e82d33d6af0ba5405582a9f88871324691f9fffa1b6a9176f01ad27e. The TSV records all 11 selected dispatch claims and all 5 delivery/collection forgery claims as pass, verdict reached, cost observed. In particular, the moved production-wrapper claim passed at 28ms CPU/28ms wall; the collection-relabel refusal passed at 33ms CPU/33ms wall. The real-mint positive and names-only control also executed and passed. These are selected-claim execution receipts, not a statement that the entire historical 21-claim dispatch roster was rerun by this floor selection.
Scope
The existing fleet-converge qualification-mode wiring remains owed: the current production wrapper still refuses rather than inventing that mode. This review does not certify a live dispatch/runner qualification or the downstream stacked PRs. I inspected the three commit patches, pinned source, head DESIGN and CI evidence, and locally hashed/parsed the artifact; I did not build the compiler, run a local mutant, perform hardware or GitHub workflow dispatch, or conduct a fresh whole-tree consumer/closure census.
No further changes, additional test lane, temporary rung drop or removal of this split after #13466 is required.
…s row and witness read InterlockedBy Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…' declarations Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Leg 3 of the mtcollins1 qualification route: dispatch the floor to the attempt's ephemeral runner, and read the run back. Builds on #13206 (leg 2), which has landed;
mainis merged in.Dispatch (
gunbc.runner.runner_qualification_dispatch)CreateDispatchis generalized, not forked.extdeps.github.workflowsCreateDispatchtakes the upstreaminputsobject instead of the heal-onlyexpected_healed_shakey.GITHUB_TOKENfrom the environment.create_dispatch_unconsumed_frontier_rowsis dissolved.The dispatch subject is sealed.
QualificationDispatchSubjectcan only be built from:AuthorizedJitMintDispatch(leg 2);runs-onmust be exactly that input, with a unique display name.The dispatch has three outcomes, from the mutation classifier. A 4xx is refused. A lost response, a 5xx or an undecodable 200 is commit-ambiguous; it keeps the subject for reconciliation and is not offered for retry. Only a 200 produces the sealed
DispatchedQualificationRun.Authority and token. The request runs under the gunbai-ci installation token. The authority whose
actions: writepermission is checked must name the same App and installation as the token and the registration; an Actions job credential refuses. The dispatch also requires the host-genericUnitHoldProoffor the slot's host.Collection (
collect_qualification_run).runner_id;runner_nameonly corroborates.qualification_instrument_extraction_frontier_rows, taken up by mtcollins1 runner: extract qualification instruments from the run (leg 3b) #13225.Ref pin (
gunbc.runner.runner_qualification_ref_pin)A runner group can select a dispatched workflow only at a branch: GitHub's docs say "Pin non-reusable workflows to a branch", cited in
extdeps.github.org_actions. So the pin is a branch:refs/heads/qualification/<attempt>at the revision, with a readback;runner-qualificationgroup pinned to it;New upstream operations:
git_databaseCreateRefandDeleteRef, andorg_actionsUpdateOrganizationRunnerGroupWorkflows. No generated workflow fires on the branch.Edits to #13206's code
JitCredentialBoundToAttemptgainsminted_for: JitMintIdentity. This is leg 2's type, changed here per quiet-stag-623 so mtcollins1 runner: JIT register/deregister over a managed-host unit binding (leg 2) #13206 didn't need another review round. The field is set inreceive_jit_mint. It is a plain value rather than the sealed dispatch because the delivery variant is not sealed: carrying the dispatch would hand that sealed value to any holder of a delivery.dispatch_jit_mint's admit list now also names this PR's two real-path claims.Authorization
gunbc.auth.privileged_effect_censushas rows for the dispatch, the pin ensure and the pin removal. The dispatch is recorded asIrreversibleEffect.Coverage comes from the operator's 2026-10-03 ruling, quoted verbatim, plus a separate cited scope interpretation by eager-gull-22 on 2026-10-04, reported to the operator. The interlock is the host-generic unit hold.
Route
The dispatch leg is
LegAuthorityImplemented, and itswiring_owednames the fleet-converge mode that lands with the boot leg.route_is_executablestays false.Evidence
Remote
--claim-runresults are reported per head in the PR comments, and CI runs the required floor. The REDs:🤖 Generated with Claude Code