The 2026-08-08 audit found one defect thirty-four times: OrchestKit writes to CC contracts nobody verified against the binary. The fix — a script that derives the contract from the binary — was written, and is good. Grepping all 31 workflows for it returned zero hits. Nothing ever ran it.
derive-cc-output-keys.mjs ──reads──▶ the shipped binary
│
└──writes──▶ src/hooks/bin/cc-output-keys.generated.mjs
│
└──CI validates ork against this──▶ green
nothing re-runs step one. CI has been checking OrchestKit against a
snapshot no process refreshes — correct only for as long as it
happens to still be current.
derive-cc-output-keys.mjs:141 binaryEvents.filter(e => !allowed.has(e))
It fails only when the binary names an event the allow-list lacks. An older binary
names a subset, so the difference is empty and the gate prints OK. Every other CC
install in this repo is pinned to the support floor — correct for reproducible jobs, fatal here. A
floor-pinned host would not merely miss newer drift; it would report a pass it did not earn,
which is the exact failure the audit was about.
So this probe installs the newest published release and accepts that its version moves underneath it. That is the point, not a compromise.
| workflow | why not |
|---|---|
plugin-validation.yml | installs CC, but the job is continue-on-error: true — a drift exit would be swallowed. Also floor-pinned. |
claude-release-watch.yml | installs CC, but its header forbids automatic triggers, and it is structurally unschedulable: its text matches the LLM-in-CI guard's signature list. |
contract-parity.yml | semantically right, installs no binary, no schedule. |
hook-contract.yml | path filters can never match the derive script; no dispatch trigger either. |
cc-support-window-bump.yml | fires only after a human has already recorded the new version in-repo. |
Hence a new file, modeled on
labs-version-probe.yml — which exists for precisely this reason: that guard is
file-scoped and textual, so a scheduled job must live in a file that does not quote the
pattern. This one describes the policy strictly by reference.
exit 0 OK every event the binary names is in the allow-list exit 1 DRIFT fails the job — hooks are writing to a contract the binary contradicts exit 2 CANNOT-OBSERVE fails the job — the binary was not found, so the gate saw nothing
labs-version-probe.yml
deliberately never fails its nightly, because pin drift is informational. Both exits here are
actionable, and exit 2 especially: a contract gate that cannot observe must never look
green.
findBinary() searches only
~/.local/share/claude/versions/<x.y.z>. No workflow references that path, and whether
the npm install populates it on a GitHub runner was not determinable from the repo. If it does
not, this gate returns CANNOT-OBSERVE forever — a gate that never fires, shipped while
fixing gates that never fire.
So the layout step prints the directory listing unconditionally, before the check runs. A
CANNOT-OBSERVE result therefore names the actual layout instead of leaving the next
person to repeat the experiment.
1. Actions runs `run:` with bash -e, so a non-zero exit would kill the step BEFORE the summary was written — a red X with no explanation of which failure it was. Fixed with `|| rc=$?`, and the comment says why so the next editor does not "simplify" it back. 2. A `case` with duplicated patterns and `;&` fallthrough. Replaced with plain if/elif.
actionlint .github/workflows/cc-contract-probe.yml exit 0 (first pass flagged SC2129 — individual redirects; fixed to one block) bash tests/unit/test-no-llm-in-ci.sh PASS: all 7 LLM workflow(s) are manual-only (46 scanned) ← this file is scanned and NOT classified as an LLM workflow, so its schedule is legal
What remains unproven, deliberately. This PR cannot verify that the runner
populates the lookup path, because workflow_dispatch only becomes available once the
file is on the default branch. The honest sequence is merge, dispatch, read the layout summary, and
fix the install or the lookup if it reports CANNOT-OBSERVE — rather than asserting here
that it works. If the first scheduled run fails that way, that is the gate doing its job: it is
designed to be loud about not being able to see, which is the one thing the thirty-four defects had
in common.