Repository navigation
Description
Summary
The macOS libkrun cache key hashes the build script but not the patches it applies, so changing a patch's contents does not invalidate the cache. CI then serves a dylib built from the previous patches, and the lane goes green having tested code the PR does not ship.
.github/actions/setup-libkrun-macos/action.yml:28:
script_hash="$(shasum -a 256 scripts/build-libkrun-macos.sh | cut -d' ' -f1)"
...
echo "prefix=$HOME/.cache/minimal-ci/libkrun/$commit-${script_hash:0:12}"The surrounding comment asserts "The prefix embeds BOTH build inputs (pinned commit + build-script hash)". That was true until gominimal/minimal#884 added a patch-application step, which introduces a third build input the key does not cover.
Observed, not hypothetical
All three commits on #884 share script hash 516adfacdef8:
| Commit | Patches carried | macOS build |
|---|---|---|
7258ee5d |
credit floor (later refuted) | cache miss — logged applying 0001-vsock-don-t-shrink-rx-packets-to-the-last-bytes-of-peer-credit.patch |
5aa0de54 |
credit floor | cache hit |
5dc8cf01 |
IRQ fix + fill-loop (what the PR ships) | cache hit — same stale dylib |
The unit job bakes that dylib into mac-testbed, which the self-hosted e2e job consumes. So the macOS unit and e2e lanes on the current head ran against a libkrun built from a patch the PR deliberately deleted.
Severity
Bounded, but it destroys the signal where it matters most. The poisoned entry is PR-branch-scoped; main's script hash differs, so post-merge main and release rebuild correctly. The shipped artifact is not wrong — but any macOS result on a PR that changes patch contents without touching the build script is meaningless, and reads as green.
This is the CI lane that exists specifically to exercise libkrun on HVF, and patches to libkrun are exactly what it now cannot see.
Note the paths filter is fine — vendor/libkrun/** does trigger ci-macos.yml. Only the cache key is wrong, so the lane runs and reports on stale inputs rather than skipping.
Suggested fix
Fold the patch contents into the key:
build_hash="$( { shasum -a 256 scripts/build-libkrun-macos.sh; \
find vendor/libkrun/patches -name '*.patch' -type f -print0 | sort -z | xargs -0 -r shasum -a 256; \
} | shasum -a 256 | cut -d' ' -f1)"This cannot be fixed from scripts/. On a cache hit the action never invokes the build script at all, so no script-side change can invalidate a stale entry — it has to be the key itself, inside CODEOWNER-gated .github/.
Immediate workaround for #884
Drop that branch's libkrun cache entry on the mini (or make any byte change to scripts/build-libkrun-macos.sh) and re-run the macOS lane, to get an honest signal before merging.
Activity
gominimal-aw-bot commentedon Jul 22, 2026
Routing triage — #902
Kind:
bug· Route:patch· Confidence: 0.92Target:
gominimal/minimal— the composite action named in the issue (.github/actions/setup-libkrun-macos/action.yml) is confirmed present in this repository; the defect is visible at thescript_hash=andecho prefix=lines.Evidence
.github/actions/setup-libkrun-macos/action.ymlexists ingominimal/minimal. TheResolve libkrun pinstep (action.yml:28) computesscript_hashonly fromscripts/build-libkrun-macos.shand embeds it as$commit-${script_hash:0:12}in both theprefixoutput and theactions/cache key:. Patch file contents are absent from the key.setup-libkrun-macosandlibkrun cache patchingominimal/minimalreturned no prior issue tracking this specific defect. No routing markers (inbox-route:ledger,Routing-Key: inbox-route/) for this bug found in minimal.ci(macos): consolidate libkrun on our own pinned source build) created the setup-libkrun-macos action and lives in theminimalDistillery project; PR ci: cache discipline, slim CI debug info, and a --locked sweep #703 (ci: cache discipline) confirms cache key work belongs there. No prior Distillery entry for this patch-omission defect.routing-outcomeentries (all authored byinbox-route-retro, all taggedrouting-outcome) were found. All route CI and build-plane bugs togominimal/minimal; none show a correction away from minimal for this class of issue. No reordering of preference is indicated.gominimal/minimalisroute: allow; keywords includebuild,cache,ci(via purpose);sdd: true;default_ref: main.echo "prefix=..."output line and theactions/cache key:line inaction.ymlmust foldvendor/libkrun/patches/*.patchcontent into the hash.max_patch_files: 5; 1 file needed. A fix inscripts/build-libkrun-macos.shis insufficient (the script is not invoked on a cache hit).[inbox-route:decision]
{"schema":"inbox-route/v1","issue":340,"issue_node_id":"I_kwDOSUhdos8AAAABJsl7Jw","dry_run":false,"kind":"bug","route":"patch","confidence":0.92,"targets":[{"repo":"gominimal/minimal","reason":"action.yml confirmed present in gominimal/minimal; bug visible at action.yml:28 where script_hash excludes patch file contents from the cache key"}],"labels":["kind:bug","priority:should-have"],"patch":{"target_ref":"main","brief":"The 'Resolve libkrun pin' step hashes only scripts/build-libkrun-macos.sh into script_hash (action.yml:28) and embeds it in both the prefix output and the actions/cache key:. Since PR #884 added a patch-application step, patch file contents are now a third build input that the key does not cover. Evidence: action.yml confirms commit + script_hash[:12] is the full key; the three-commit table in the issue shows identical script_hash across commits with different patch sets, yielding a cache hit against a deleted patch. The fix folds vendor/libkrun/patches/*.patch contents into a combined digest replacing script_hash in both the echo prefix= line and the actions/cache key: line. Only action.yml needs editing; the build script is not involved (it is not invoked on a cache hit).","files":[".github/actions/setup-libkrun-macos/action.yml"]},"work_issue":{"title":"bug: CI macOS libkrun cache key missing patch file contents","body":"## Summary\n\nThe setup-libkrun-macos composite action caches the built libkrun dylib under a key that hashes only the build script, not the patch files it applies. After PR #884 added a patch-application step, patch file contents became a third build input not covered by the key. CI restores a stale dylib when patches change without a corresponding build-script change, making the macOS lane result meaningless for those PRs.\n\n## Expected behavior\n\nChanging any file under `vendor/libkrun/patches/` invalidates the macOS libkrun cache and triggers a fresh build.\n\n## Actual behavior\n\nThe `Resolve libkrun pin` step (`action.yml:28`) computes `script_hash` from `scripts/build-libkrun-macos.sh` only and uses it as the sole non-commit component of both the `prefix` output and the `actions/cache key:`. A patch change without a build-script change yields an identical hash, so the cache hit restores the previous dylib. The `unit` job bakes that dylib into `mac-testbed`; `e2e` consumes it — both lanes report results against code the PR does not ship.\n\n## Reproduction\n\nObserved on gominimal/minimal#884: all three commits share script hash `516adfacdef8`. The third commit changed the active patch set without touching the build script and received a cache hit, so unit and e2e ran against a dylib built from a patch the PR deliberately deleted.\n\n## Scope notes\n\nFix is isolated to `.github/actions/setup-libkrun-macos/action.yml`. Both the `echo \"prefix=...\"` line and the `actions/cache key:` line must incorporate a hash of `vendor/libkrun/patches/*.patch` content (e.g., sorted `shasum` of all patch files folded into the combined digest). A fix inside `scripts/build-libkrun-macos.sh` is insufficient — the script is not invoked on a cache hit.\n\nLaunch: a maintainer comments `/spec` on the work issue to start the SDD pipeline.\n\n---\n<!-- SDD command vocabulary. Do not edit this footer. -->\n\nThis issue is the tracking issue for this work. A maintainer with write\naccess starts the SDD pipeline by commenting `/spec` on this issue or by\nflipping the `sdd:spec` label.\n\nSteer the pipeline with these comment commands. Each is gated to commenters\nwith write access to the repository.\n\n| Command | Where | Effect |\n|---|---|---|\n| `/spec` | this tracking issue | re-run `sdd-spec` to draft or revise the spec |\n| `/fastpath` | this tracking issue | confirm a single-session change; `sdd-spec` produces a stub spec PR and an execution plan comment in one run (ADR 0012) |\n| `/triage` | this tracking issue, after the spec PR is merged | start `sdd-triage` phase A (architecture) |\n| `/approve` | this tracking issue | full path: confirm the proposed plan so `sdd-triage` creates the Unit and task sub-issues. Fast path: dispatch the execution plan against `sdd-execute-{tier}` |\n| `/dispatch` | this tracking issue (full path only) | arm the cascade across the task tree |\n| `/revise <note>` | a spec, architecture, or implementation PR, or this tracking issue | re-run the owning agent with the note as an added instruction |\n| `/execute` | a task sub-issue | run `sdd-execute` for that task ahead of the schedule |\n\nMerging the spec PR advances to the architecture phase; merging the\narchitecture PR advances to a plan-comment phase, where `sdd-triage` posts\nthe proposed plan as one comment on this tracking issue. When an agent needs\na human decision it applies the `needs-human` label and posts one comment;\nclear the label once you have answered and the agent resumes.\n"},"related":[],"rationale":"The issue names .github/actions/setup-libkrun-macos/action.yml:28 as the defect site. Reading that file confirmed the bug: only scripts/build-libkrun-macos.sh is hashed into script_hash; the cache key is commit + script_hash[:12] — patch file contents are absent. Distillery shows PR #694 (ci(macos): consolidate libkrun on our own pinned source build) created this action in gominimal/minimal, and PR #703 (ci: cache discipline) confirms cache work lives there. No inbox duplicates: only gominimal/minimal#902 itself matched the libkrun-cache-key search. Precedent pass returned 8 eligible routing-outcome entries (all by inbox-route-retro); all route to gominimal/minimal; none show corrections away from minimal for CI-type issues. Confidence 0.92: direct evidence — exact file named in the issue exists in gominimal/minimal with the defect visible, fix touches one file within max_patch_files."}gominimal-aw-bot commentedon Jul 22, 2026
[inbox-route:ledger]
Routed from gominimal/inbox#340 by inbox-route (https://github.com/gominimal/inbox/actions/runs/29893278378)
Routing-Key: inbox-route/I_kwDOSUhdos8AAAABJsl7Jw
Route: patch
Patch-Dispatched: https://github.com/gominimal/inbox/actions/runs/29893278378
gominimal-aw-bot commentedon Jul 22, 2026
[inbox-patch:handoff]
inbox-patch did not produce a verified fix PR for this issue — the agent run finished without creating one (agent result: success).
Run: https://github.com/gominimal/inbox/actions/runs/29893740351
Manual retry: