Skip to content

fix: approved fork pull request runs fail restoring a source snapshot that was never captured - #232

Merged
paulcam206 merged 2 commits into
mainfrom
paulcam206-fix-fork-approval-source-snapshot
Oct 30, 2026
Merged

paulcam206 merged 2 commits into
mainfrom
paulcam206-fix-fork-approval-source-snapshot

Conversation

@paulcam206

@paulcam206 paulcam206 commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator

Related: #219

What Problem This Solves

Fixes: the Gateway MSIX GitHub Actions workflow fails with Artifact not found for name: openclaw-source-resolution on every fork pull request run that a maintainer approves, so those PRs can never get a green build. #219 is the motivating case: run 41113043368, job "Capture source and validate build route" (124260386771); run 40580386645 failed the same way earlier.

User Impact

User impact: approved fork pull requests build and test normally. Reruns of a run that already captured its OpenClaw source still replay that exact snapshot, and still fail closed when it is gone.

Why This Change Was Made

The workflow treated "attempt 1" as "the attempt that captured source". A fork run that waits for approval ends attempt 1 as action_required without running any job, so approval creates attempt 2, which tried to replay a snapshot nobody captured. Reruns and close/reopen could not recover it.

Source capture now decides from run state instead of the attempt number (scripts/Get-WorkflowSourceSnapshotMode.ps1):

  • reuse when the run lists the openclaw-source-resolution artifact (including an expired one), or when any earlier attempt's capture job succeeded, ran its upload step, or left that step in an unknown state; a missing artifact then fails at the existing restore diagnostic;
  • resolve on attempt 1, or when every earlier capture job is absent, skipped, ended before any step ran, or skipped its upload; the attempt that resolves uploads the snapshot.

The capture job gains actions: read to read its own run's jobs and artifacts. It refuses to decide if the current attempt does not list the job under the name the workflow passes, so a job rename cannot silently turn replay into re-resolution. Downstream build and signing jobs already download the run's artifact unconditionally and are unchanged. Get-WorkflowSource.ps1 takes only -ReuseSnapshot and does not read the attempt number. The remaining attempt-keyed uses are deliberately per attempt: the cache-proof keys write and read within one attempt, and Get-WorkflowPackageVersion.ps1 -RunAttempt gives each attempt a distinct package version.

Evidence

Head: 465e0d3d64fd0aea98903c9397a27644ec229678.

Hosted proof ran on b7a464e9 from this upstream branch via workflow_dispatch (unsigned). 465e0d3d changes only README text, so the workflow and script under test are the same. Each row quotes the capture job's log.

Scenario Run / attempt Result
Attempt with no capture, then retry (equivalent of the approval-gated attempt in #219) 41114478067 a1 cancelled before any capture step ran, with 0 artifacts. a2 ran Re-run all jobs a2 SNAPSHOT_MODE: resolve, Artifact openclaw-source-resolution has been successfully uploaded! ... Artifact ID is 13005376667. Build OpenClaw npm package downloaded that ID, and the whole attempt concluded success
Snapshot captured, then the capture job reran (genuine rerun) 41120930586 a1 captured artifact 13007702869. a3 reran the capture job a3 SNAPSHOT_MODE: reuse, openclaw-source-resolution (ID: 13007702869, ... sha256:f6096d2b...), Artifact download completed successfully. There was no new upload
Downstream rerun same run, a2 reran Build OpenClaw npm package Downloaded the same ID and digest (13007702869, sha256:f6096d2b...)
Snapshot captured, then the platform discarded it 41114478067 a3 ran Re-run all jobs after a2 captured. Afterward GET /actions/artifacts/13005376667 returned 404 It decided to reuse and failed closed: Artifact not found for name: openclaw-source-resolution, then The immutable source snapshot artifact 'openclaw-source-resolution' could not be restored for run 41114478067 (attempt 3).... It did not re-resolve

The last row reproduces #125: re-running all jobs drops the earlier attempt's artifacts. This PR keeps that path fail-closed and documents the partial-rerun alternative. It does not change #125.

PR CI on 465e0d3d: 41124625576 passed. In attempt 1, only Test MSIX upgrade (Store update · bundle) failed, because WinGet could not install the Store product on the runner (msstore agreements, exit -2147418110). Re-run failed jobs (attempt 2) passed without re-running capture.

No fork run that needed approval was available. A maintainer's fork does not require approval. Instead, the a1-cancelled row reproduces the same input state: an earlier attempt whose capture job never ran a step, with no artifact. The unit suite replays the exact #219 shape: attempt 1 has zero jobs.

Local, on b7a464e9 (re-run for docs on 465e0d3d):

  • .\scripts\Test-WorkflowSourceSnapshotMode.Tests.ps1 passed (20 checks): approval-gated, cancelled, skipped, and failed-before-upload attempts resolve; listed or expired artifacts, successful captures, and run, failed, cancelled, unfinished, or unrecognized upload steps reuse; a drifted job name and API failures throw.
  • .\scripts\Test-OpenClawSource.Tests.ps1 passed (75 tests).
  • .\scripts\Test-WorkflowSigningConfiguration.ps1, .\scripts\Test-SigningInputs.Tests.ps1, .\scripts\Test-PackagingRelevance.Tests.ps1, and .\scripts\Test-WorkflowJobResults.Tests.ps1 passed.
  • .\scripts\Test-DocReferences.ps1 reported 0 findings. .\scripts\Test-DocReferences.Tests.ps1 passed. git diff --check was clean.

Not run: the .NET quality, xUnit, NativeAOT, MSIX packaging, and upgrade lanes, because no source, package, or signing input changed. The signing-mode validate job was not exercised. It already downloads the run's artifact unconditionally and is unchanged.

…ver captured

A fork pull request run that waits for approval ends attempt 1 as
action_required without running any job, so the approved attempt 2 tried to
download an openclaw-source-resolution artifact that never existed (#219).

Source capture now decides from run state rather than the attempt number:
reuse when the artifact is listed or an earlier attempt ran (or may have run)
its upload, and resolve fresh only when no earlier attempt could have
uploaded one. The attempt that resolves uploads the snapshot.
@clawsweeper

clawsweeper Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

ClawSweeper review complete

ClawSweeper finished reviewing this revision. The review result is being finalized.

View the workflow run.

@clawsweeper clawsweeper Bot added clawsweeper:intake:bug Preliminary submission classification; full source review pending. clawsweeper:intake:needs-environment Preliminary submission classification; full source review pending. clawsweeper:intake:needs-repro Preliminary submission classification; full source review pending. P2 Normal priority bug or improvement with limited blast radius. proof: sufficient Contributor real behavior proof is sufficient. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed clawsweeper:intake:bug Preliminary submission classification; full source review pending. clawsweeper:intake:needs-repro Preliminary submission classification; full source review pending. clawsweeper:intake:needs-environment Preliminary submission classification; full source review pending. labels Oct 30, 2026
@clawsweeper

clawsweeper Bot commented Oct 30, 2026

Copy link
Copy Markdown

Codex review: needs maintainer review before merge.

What this changes

The workflow uses artifact and job history to decide whether to capture or reuse its immutable OpenClaw source snapshot.

Example: Run 41113043368 reaches attempt 2 after fork approval, while attempt 1 ran zero jobs.

  • Before: The workflow downloads a snapshot that was never uploaded and fails before source resolution.
  • After: The workflow captures and uploads its first snapshot, allowing downstream builds to proceed.

Review scores

Measure Result What it means
Overall readiness 🦞 diamond lobster (5/6) Focused repair with production-workflow proof, meaningful scenario coverage, unchanged snapshot format, and no introduced correctness finding.
Proof confidence 🦞 diamond lobster (5/6) Sufficient (live_output): Hosted workflow runs at b7a464e exercise the changed preflight owner: capture after an attempt with no capture steps, downstream consumption, successful replay without another upload, and missing-artifact rejection before re-resolution. GitHub job records corroborate the supplied output; reviewed head changes only README text. Actual fork approval was represented by the equivalent no-capture state, and raw-log retrieval was blocked by the review host.
Patch quality 🦞 diamond lobster (5/6) No actionable review findings were identified.

Product

Kind: Bug fix · Worth it: Yes · Fix scope: Complete
User problem: A contributor's approved fork PR cannot obtain a successful packaging build because approval advances the attempt number before any source snapshot exists.
Reason: The collaborator-authored direction addresses a confirmed workflow blocker while preserving the original immutable-source contract.

Merge readiness

✅ Ready for maintainer review

Keep open: this maintainer-authored PR fixes a confirmed contributor-workflow failure still present on main, with no actionable introduced defect found.

Priority: P2
Reviewed head: 465e0d3d64fd0aea98903c9397a27644ec229678

Before merge

None.

Findings

None.

Agent review details

How this fits together

Source preflight converts workflow context and upstream selection into a validated immutable artifact consumed by package builds and signing authorization.

flowchart LR
  A[Workflow attempt] --> B[Inspect artifacts and job history]
  B --> C[Resolve or reuse snapshot]
  C --> D[Validate source and workflow context]
  D --> E[Immutable source artifact]
  E --> F[Package builds]
  E --> G[Signing authorization]
Loading

Technical review

Best possible solution:

Use run-state evidence to permit first capture while preserving immutable replay whenever an earlier attempt could have uploaded a snapshot.

Do we have a high-confidence way to reproduce the issue?

Yes: GitHub confirms the zero-job first attempt and failed approved retry, and current main retains the unconditional later-attempt restoration path.

Is this the best way to solve the issue?

The focused selector fixes the incorrect attempt-number assumption without duplicating source resolution or weakening immutable replay.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning medium; reviewed against f6dcf00eaf45.

Provenance checked

  • Source capture and immutable retry selection changes intended behavior with a stated reason (9f18180: The original release-selection change records one validated source choice per run and reuses it without querying a moving channel again.)
  • Central preflight ownership and workflow binding keeps the original intent (4a55f98: Centralized capture binds source selection to workflow context and separates trusted cache writers from read-only builds.)
  • Packaging relevance classification keeps the original intent (a2f0d42: The shared classifier retains broader packaging and upgrade validation for source-selection and workflow changes.)

Testing

Proof path: shipped entry point.

Security

None.

Evidence

What I checked:

Likely related people:

  • Paul Campbell: Raw commit a3b62dd adds .github/workflows/gateway-msix.yml:383 relative to its recorded parents. This identifies author metadata, not feature responsibility or a PR merger. (role: source-line author; confidence: high; commits: a3b62dd70e05; files: .github/workflows/gateway-msix.yml)
  • Linus Huang: Raw commit 9f18180 adds .github/workflows/gateway-msix.yml:268 relative to its recorded parents. This identifies author metadata, not feature responsibility or a PR merger. (role: source-line author; confidence: high; commits: 9f18180d27ba; files: .github/workflows/gateway-msix.yml)
  • Dallin Romney: Raw commit a2f0d42 adds scripts/Get-PackagingRelevance.ps1:39 relative to its recorded parents. This identifies author metadata, not feature responsibility or a PR merger. (role: source-line author; confidence: high; commits: a2f0d42f0cca; files: scripts/Get-PackagingRelevance.ps1)

Review metrics

Metric Value Why it matters
Change distribution Production/workflow +105/-4; tests +132/-0; documentation +11/-3. The growth adds one run-state classifier and scenario fixtures while retaining the existing source resolver and validators.

Labels

Label changes:

  • add P2: Approved fork contributions cannot complete packaging CI, but installed OpenClaw runtime behavior is unaffected.
  • add proof: sufficient: Contributor real behavior proof is sufficient.
  • add rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR.

Label justifications:

  • P2: Approved fork contributions cannot complete packaging CI, but installed OpenClaw runtime behavior is unaffected.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR.
  • proof: sufficient: Contributor real behavior proof is sufficient.

Rating scale

6/6 🦀 challenger crab · 5/6 🦞 diamond lobster · 4/6 🐚 platinum hermit · 3/6 🦐 gold shrimp · 2/6 🦪 silver shellfish · 1/6 🧂 unranked krab. Overall follows the weaker of proof and patch quality; ✨ marks media proof (a screenshot, video, or linked artifact) that directly shows the changed behavior.

Workflow

ClawSweeper edits this one comment on every review. Comment @clawsweeper re-review for a fresh review only. Repair and merge execution lanes are retired.

Reviewed October 30, 2026, 4:52 PM ET / 20:52 UTC.

@paulcam206
paulcam206 marked this pull request as ready for review October 30, 2026 21:19
@paulcam206
paulcam206 merged commit 62c79e2 into main Oct 30, 2026
68 of 70 checks passed
@paulcam206
paulcam206 deleted the paulcam206-fix-fork-approval-source-snapshot branch October 30, 2026 21:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P2 Normal priority bug or improvement with limited blast radius. proof: sufficient Contributor real behavior proof is sufficient. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant