feat(pin-move-verify): build the SENDER -- dispatch a proposed tuple to alp-e2e when a PR touches a pin site - #823
Open
alpCaner wants to merge 5 commits into
Open
feat(pin-move-verify): build the SENDER -- dispatch a proposed tuple to alp-e2e when a PR touches a pin site#823alpCaner wants to merge 5 commits into
alpCaner wants to merge 5 commits into
Conversation
…n, payload construction, fail-closed verdict judge (tan-cli#820)
… touches a pin site, fail closed on anything short of success (tan-cli#820)
…ender's real detect+fail-closed path (revert next commit)
…r's detect+fail-closed path
…k-run race, mirrored-contract drift, check-run identity, fork PRs, injection, and the sweep/certifiability gaps Ten findings, addressed: 1. Stale Check Run race (finding 1): poll now captures dispatched_at before the POST and filters check-runs on (.completed_at // .started_at) >= dispatched_at, so a fast-follow push or a "Re-run failed jobs" on an unchanged head can no longer read a PREVIOUS dispatch's completed Check Run as this one's verdict. Demonstrated locally with the real jq filters against a synthetic check-runs fixture: the old filter matches a stale success, the new one correctly waits. 2. Pin-site sweep (finding 2): tests/parity/scaffold_byte_parity.py's _SDK_DOC_LINK_REF (ADR-0029 observation 7's own example, tan-cli#756/ #766) is now named explicitly in the module docstring. It is currently DEAD (frozen at the retired v0.15.0-rc1 literal, exercised only by self_check()'s own hardcoded string, no live DELIBERATE_EDITS entry uses it) and, like the vendored tree below, only ever changes atomically with PINNED_SDK_TAG -- so it stays out of PIN_SITES, documented rather than silently missing. 3. False exclusion rationale (finding 3): the "no literal ref" claim was false for python/tan/templates/vendored/**'s own MANIFEST.md (it carries explicit Ref:/Commit: lines). Replaced with the true, evidence-based reason -- every historical re-vendor of that tree landed in the SAME commit as a PINNED_SDK_TAG bump and was independently re-verified against the live emit, a self-checking mechanism with zero documented drift, unlike ci.yml's ref and the freshness gate's hashes, which have each drifted for real at least once (tan-cli#485, #639). Applied the same criterion to test_planner_relocation_freshness.py and reached the OPPOSITE, correct conclusion: it stays IN PIN_SITES because its pins move via an independent bot (planner_resync.py), not atomically with PINNED_SDK_TAG. 4. Self-disabling test (finding 4): test_pin_sites_docstring_names_ every_dict_entry now asserts every PIN_SITES path exists on disk AND is named verbatim in the module docstring -- a rename now goes red instead of the gate silently stopping matching forever. 5. Weaker-question gate (finding 5): judge_polled_check_run's PASS message now names the PUBLISHED tan_ref and states plainly this is not proof of this PR's own code, so a reader of the green $GITHUB_STEP_SUMMARY line sees the caveat, not just the docstring or workflow header. Every PIN_SITES entry now carries a CERTIFIABILITY note. 6. Mirrored contract drift (finding 6): added MAX_SOMS = 8, mirroring alpe2e.pinverify.MAX_SOMS, enforced in build_tuple. The whole mirrored block (four regexes + MAX_SOMS + check_name's format) is now pinned by MIRRORED_CONTRACT_HASH with a new freshness gate, test_pin_move_verify_contract_mirror.py, ALP_E2E_ROOT-gated the same way test_planner_relocation_freshness.py gates on ALP_SDK_ROOT. tan-cli#835 tracks the next re-audit. Observed to fail: patched a local alp-e2e checkout's MAX_SOMS, watched the gate go red, reverted. 7. Check Run identity (finding 7): judge_polled_check_run now takes expected_check_name/expected_source_sha and fails closed on a mismatch, so an unrelated same-named run (e.g. a hand-run workflow_dispatch with a different SoM set) can no longer be graded as this dispatch's own verdict. 8. Fork PRs (finding 8): the "refuse to proceed without the App" step now branches on head.repo.fork with its own message stating plainly that provisioning the secrets never fixes a fork PR (ADR-0029 clause 5 mandates no secret reaches one) -- corrected from the previous message, which implied provisioning was the universal fix. 9. Injection (finding 9): the tanref/sdkref steps now apply parity.yml's own whole-string `case` guard (not `grep -qE`, per tan-cli#435) before a workflow_dispatch override reaches $GITHUB_OUTPUT/::notice::. 10. Nits (finding 10): check_name is read through env: in the dispatch step; alplabai/tan-cli is no longer hardcoded in the poll step or pin_move_verify.py's SOURCE_REPO default (both now flow ${{ github.repository }} via a new --source-repo flag); changelog.d/820.added.md now states the tan_ref consequence, not just the fact. Full suite: 4246 passed, 27 failed, 329 skipped, 1 xfailed -- the 27 failures are byte-identical (diffed sorted test IDs) to an unmodified origin/dev run, all pre-existing Windows-environment failures (PATH/ installer/taskkill) unrelated to this change.
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.
Summary
Builds the SENDER half of ADR-0029's cross-repo pin-move-verify loop
(alp-sdk
docs/adr/0029-cross-repo-pins-are-typed-lock-entries-with-a-property-gate.md,alp-sdk#1474) in this repo. The RECEIVER already exists on
alplabai/alp-e2ePR #1 (
.github/workflows/pin-move-verify.yml+alpe2e/pinverify.py+journeys/build-tuple.sh), proven on two real tuples on E1M-V2N101(
v0.5.1 x v0.15.0FAILS as expected;v0.6.0-rc1 x v0.16.0-rc1PASSES).This PR does not touch alp-sdk or alp-e2e — the sender adapts to the
receiver's existing, already-proven contract.
python/scripts/pin_move_verify.py— the pure logic: pin-site detection,(tan_ref, sdk_ref, soms)payload construction/validation (mirrorsalpe2e.pinverify's own_REF/_SKU/_REPO/_SHApatterns andcheck_namebyte-for-byte, not a second schema), and the fail-closedverdict judge. See its own module docstring for the full pin-site sweep
and the reasoning behind what's in
PIN_SITESand what's deliberately not..github/workflows/pin-move-verify.yml— one job, no matrix, staticname: pin-move-verify · sender(the literal string branch protectionshould require once it's safe to — see "What remains unproven" below).
Detects a touch to a tracked pin site, resolves
tan_ref(latestpublished tan-cli release) and
sdk_ref(parity.yml's livePINNED_SDK_TAG), dispatches toalplabai/alp-e2e, polls for its CheckRun (bounded, 90 min), and fails closed on anything short of a literal
successconclusion.python/tests/scripts/test_pin_move_verify.py— 44 tests over the purelogic + the CLI subcommands (including two through a real throwaway git
repo, proving the
git diff-based detector end to end offline).changelog.d/820.added.md.Closes #820.
Pin sites found (the full sweep)
Searched for every literal alp-sdk ref (tag/branch/40-char SHA) this repo
pins against, starting from
test_planner_relocation_freshness.pyper thetask, then a repo-wide sweep for
PINNED_SDK_TAG/PINNED_SDK_COMMIT-shapedconstants and every literal 40-char hex string in
.py/.yml/.yaml(
grep -noE '[0-9a-f]{40}'across the repo, then hand-triaged each hit —several are
actions/foo@<sha>version pins or historical commit referencesin comments, not live alp-sdk-ref pins).
In
PIN_SITES(this workflow dispatches on a touch to any of these):python/tests/gates/test_planner_relocation_freshness.pyPINNED_SDK_COMMIT,HAND_PORT_PINNED_SDK_COMMIT,STRICT_LOADERS_PINNED_SDK_COMMIT.github/workflows/parity.ymlPINNED_SDK_TAG(workflow-levelenv:).github/workflows/ci.ymlsdk_parityjob'salp-sdkcheckoutref:(a literal SHA that file's own comment says MUST move in lockstep withPINNED_SDK_TAG)Found, but this workflow cannot sensibly cover them (see the module
docstring for the full reasoning, not just the one-liner below):
ZEPHYR_SDK_INSTALL_VERSION(python/tan/commands/doctor_cmd.py)toolchain_reffield exists in the dispatch contract, and the receiver's journey never reads this constant. Already guarded bytests/parity/toolchain_lock_parity.py(byte-diff vsmetadata/toolchains.json) — ADR-0029's "propagated constant" model, not "compatibility declaration".contract/fixtures/bootstrap/manifest.json,contract/fixtures/toolchains/toolchains.json,tests/fixtures/kconfig-contract/emit-kconfig.golden.json,python/tan/templates/vendored/**sdk_ref. Their staleness already tracksPINNED_SDK_TAG(seetests/parity/README.md); a build tuple proves "does it compile", not "are these bytes identical to the vendor's" — the existing*_parity.pybyte-diffs are the right tool for that claim.python/tan/version.py'sTAN_VERSIONI did not find a
SUPPORTED_CLI_VERSION-shaped pin in this repo — that onelives in
alp-sdk-vscode(out of scope for this repo's PR; ADR-0029'sSequencing step 4 names it as
check-cli-pin.mjs's own future work,consuming this contract's attestations from that repo, not this one).
The tuple this sender proposes, and its honest limits
tan_refis always the latest published tan-cli release — thereceiver's journey installs it through the documented
install.shone-liner, which cannot fetch an unreleased PR branch.
sdk_refis readlive from
.github/workflows/parity.yml'sPINNED_SDK_TAGat the PR's ownhead — the value the PR is actually proposing.
somsdefaults toE1M-V2N101,E1M-AEN801(the receiver's own worked cost example, ~10runner-minutes).
This means a PR that re-audits
tan/planner/'s fork against a new alp-sdkcommit (the freshness-gate pins) is verified only indirectly: the dispatch
proves "does the currently-shipping tan still build against the alp-sdk ref
this PR wants to pin the audit against", not "does the code this PR itself
changed build against it" —
install.sh-based verification cannot ask thesecond question. Stated in full in the module's own docstring rather than
glossed over.
Status check name (for branch protection)
pin-move-verify · sender— one job, no matrix, no${{ }}in thename:. Do not require it until "What remains unproven" below isresolved — see that section.
Gates observed failing (with run URLs)
pull_requesttrigger, not a synthetic unit test. I temporarily touched
.github/workflows/parity.yml'sPINNED_SDK_TAGcomment (a no-op,whitespace-only edit next to the pin — reverted in the very next commit)
to make
detectreporttouched=trueon a real PR push. The run:DETECT_TOUCHED: true, and the errorannotation names the exact site:
This run touches a pin site (.github/workflows/parity.yml)tan_ref = v0.5.1(the real latest published release) andsdk_ref = 88318e759958529fbbd8fe9d481373681c0fa78d(parity.yml's livePINNED_SDK_TAGat that commit) and built a valid payloadhave=false(this repo genuinelyhas no
ALP_CI_APP_ID/ALP_CI_APP_PRIVATE_KEY— confirmed viagh secret list --repo alplabai/tan-cli, which shows onlyCARGO_REGISTRY_TOKEN/NPM_TOKEN)citing ADR-0029 clause 2
(job
pin-move-verify · sender, 95216940107)The touch to
parity.ymlwas reverted in the next commit;git diff origin/dev...HEAD -- .github/workflows/parity.ymlis empty in the finaldiff.
pull_requestruns (this PR's real diff touches none ofPIN_SITES):DETECT_TOUCHED: false→relevant=false→ everydispatch/mint/poll/judge step correctly skips → the job exits 0 in ~7s.
Runs: https://github.com/alplabai/tan-cli/actions/runs/31968117116 (before
the throwaway touch) and
https://github.com/alplabai/tan-cli/actions/runs/31969865719 (after the
revert, on the final diff).
Both observed runs are on this PR's own Actions tab, job
pin-move-verify · sender— nothing here was simulated locally.Local gates (from
python/)py -3.14 -m pytest tests -q: 27 failed, 4233 passed, 328 skipped, 1xfailed (repo floor is
>=3.12; the barepythonon this box is a stale3.9/3.11 per the repo's own
reference_local_python_314note). Triagedmine-vs-base: re-ran the identical command against an unmodified
origin/devworktree (27 failed, 4189 passed — passed-count differsonly because my branch adds 44 new tests, 4189+44=4233) and diffed the
sorted failing-test-ID lists — byte-identical, 27 == 27, all in
tests/installers/test_installer_release_layout.py(PowerShell/registry/ACLtests that need a real Windows install context this sandboxed shell doesn't
have) and
tests/commands/test_execute*.py/tests/gates/test_planner_resync.py(west/Zephyr-workspace-environmenttests). None of these files are in this PR's diff. This repo's own CI
(
pythonjob + allpython -- pytest shard (*)legs, ubuntu/macos/windows,all with
ALP_SDK_ROOTbound where applicable) is green on this PR — seethe Checks tab.
zizmor --min-severity medium --no-online-audits .github/workflows/(therepo's own
workflow-securitygate, zizmor 1.29.0) — clean:No findings to report. Good job! (14 ignored, 54 suppressed). Required one fix mid-review:the App-token mint step needed
permission-contents: write(the exactgrant
repository_dispatchneeds, perdispatch-tan-parity.yml's ownheader) — without it, zizmor's
github-appaudit (High) correctly flags anunscoped token inheriting the App's full installation permissions.
What remains unproven, stated plainly
The live dispatch end to end. Neither
alplabai/tan-cli(this repo) noralplabai/alp-e2ehasALP_CI_APP_ID/ALP_CI_APP_PRIVATE_KEYprovisioned(
gh secret listchecked on both — confirmed absent on this repo; thereceiver's own workflow header says the same for alp-e2e), and alp-e2e#1 is
still an open, unmerged PR. So this sender has never actually reached the
"mint a token" / "dispatch" / "poll" / "judge success" steps for real — only
the "no secret → fail closed" branch has been observed (see above). To prove
the rest, in order:
ALP_CI_APP_ID/ALP_CI_APP_PRIVATE_KEYonalplabai/tan-cli(mint step) and merges/provisions them onalplabai/alp-e2e(Check-Run-write step, per that receiver's own header).workflow_dispatch,once this workflow file is on
dev— GitHub does not exposeworkflow_dispatchfor a workflow that only exists on a feature branch,confirmed:
gh workflow run404s until the file lands on the defaultbranch) should then show: a successful dispatch, a completed Check Run
named
pin-verify · <tan_ref> × <sdk_ref>appearing on the commit withinthe poll window, and this job's own
judgestep readingsuccess→PASS. Only after that observed, real green run should this job's name be
set required in branch protection.
I have not claimed any of #3 happened — it hasn't.