Repository navigation
fix(release): let detect resume correlate-audit from an attached successful attempt - #867
Merged
Merged
Conversation
…essful attempt correlate-audit attaches audit-attempt-<run>-<attempt>.json while the marker stays AUDIT_DISPATCHED, then verifyAuditSuccess canonicalizes it and advances to AUDIT_VERIFIED. Both steps are idempotent, but when the job stopped between them (v0.13.0: a transient release-asset-download byte mismatch) every later detect threw RELEASE_AUDIT_DISPATCH_EVIDENCE_PREMATURE and the release needed the attempt asset deleted by hand. validateAuditAssetPhase now accepts a current-dispatch attempt under AUDIT_DISPATCHED only when it is a successful result exactly correlated to the recorded dispatch: same workflowRunId, the run's latest attempt, the run completed with success, and the canonical filename. Candidate, manifest digest, and byte checks run before it as before. The planner then proposes complete-release-audit. Everything else stays fail-closed: a failure attempt under AUDIT_DISPATCHED, an in-progress, unsuccessful, or superseded run, identity or byte drift, audit-result.json without AUDIT_VERIFIED, and duplicate current attempts. Regenerates the observe.mjs content pin and the pin-file digest snapshot. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
blove
temporarily deployed
to
vercel-preview
September 29, 2026 19:02 — with
GitHub Actions
Inactive
This branch was previously deployed
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.
Problem
During the v0.13.0 release (2026-09-28/29),
correlate-audit'srecordAuditAttemptuploadedaudit-attempt-<run>-<attempt>.jsonwhile the marker stayedAUDIT_DISPATCHED. That's correct: a successful attempt doesn't move the marker. Then the job failed on a transient "GitHub release-asset-download bytes are not exact" beforeverifyAuditSuccesscould canonicalize the attempt and advance the marker toAUDIT_VERIFIED.Both writers are idempotent over that state, but
detectrefused it.validateAuditAssetPhase(scripts/release/observe.mjs) threwRELEASE_AUDIT_DISPATCH_EVIDENCE_PREMATUREfor any current-dispatch attempt underAUDIT_DISPATCHED. The release only finished after someone deleted the attempt asset by hand and dispatchedreconcile.Fix
Under
AUDIT_DISPATCHED, detect now accepts a current-dispatch attempt only when all of these hold:conclusion: "success"result.workflowRunIdequalsmarker.audit.workflowRunIdresult.runAttemptequals the audit run's latest attemptcompleted/successaudit-attempt-<workflowRunId>-<runAttempt>.jsonThe existing checks still run before this one: candidate version, commit, manifest digest, listed-digest bytes and canonical bytes. The observation reports
audit.status: "dispatched", and the planner proposescomplete-release-audit, socorrelate-auditreruns and finishes through the idempotent writers. The writer-side resume is already covered byaudit.test.mjs("audit writers resume runner loss after attempt, canonical, and marker mutations").Still fail-closed (each has a regression test)
AUDIT_DISPATCHEDRELEASE_AUDIT_DISPATCH_EVIDENCE_PREMATURERELEASE_AUDIT_DISPATCH_EVIDENCE_PREMATURERELEASE_AUDIT_DISPATCH_EVIDENCE_PREMATURERELEASE_AUDIT_DISPATCH_EVIDENCE_PREMATURERELEASE_AUDIT_RECEIPT_IDENTITY_MISMATCHRELEASE_AUDIT_ATTEMPT_IDENTITY_MISMATCHRELEASE_AUDIT_ASSET_DIGEST_MISMATCHRELEASE_AUDIT_ASSET_NONCANONICALaudit-result.jsonwithoutAUDIT_VERIFIEDRELEASE_AUDIT_CANONICAL_PREMATURERELEASE_AUDIT_CURRENT_ATTEMPT_AMBIGUOUSThe new resumable-state test fails against the pre-fix
observe.mjsand passes with the fix.Other paths checked, no change needed
AUDIT_DISPATCHED.analyzeTerminalAssetsonly binds the marker-named attempt,releaseEvidenceAssetIsAllowedpermits it, and the planner mapsAUDIT_DISPATCHEDtocomplete-release-audit.scripts/release/recovery/observe.mjs): it uses its ownrecovery-v2-audit-*bookkeeping. Uploads are idempotent (same name, same bytes returns the existing asset), andAUDIT_PENDINGalready tolerates a result without its escrow, so it doesn't have this assumption.Known remaining gap (deliberately out of scope)
verifyAuditSuccessuploadsaudit-result.jsonbefore the marker CAS. If a runner is lost between those two steps, you getaudit-result.json+AUDIT_DISPATCHED. The writers resume from that, but detect still blocks withRELEASE_AUDIT_CANONICAL_PREMATURE, as requested. The same kind of relaxation could cover it later: canonical bytes identical to the exact successful current attempt.Kept separate from the pending duplicate tag dispatch / zero-job escrow task.
Pins
The
scripts/release/observe.mjspin is regenerated inrelease-script-hashes.json, andSTARTING_SCRIPT_PIN_SHA256is updated inworkflow-contracts.test.mjs.Verification
pnpm test:release-integrity: 33/33 passnode --test scripts/release/test/workflow-contracts.test.mjs: 166/166 passpnpm test:release-controller: 3950/3952 pass. Both failures are the samerecovery-rehearsal.test.mjs"effect 9 after" case: "Recovery observation blocked: exact value read unavailable" after 23s in a 17-minute contended run. That suite loads onlyrecovery/observe.mjs, never the changed file. Rerun on its own,recovery-rehearsal.test.mjspassed 70/70.No changeset: the change touches only
scripts/release, no publishable package.🤖 Generated with Claude Code