Repository navigation
chore(OMN-16626): prod-promotion grant PREP — onex-prod omniintelligence digest pin - #7213
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
992afde to
4df9a54
Compare
…nce digest pin Two entries under batch-92a794cd: the runtime same-digest authorization the k3s gate mechanically resolves for deploy_target=runtime-only, and the omniintelligence digest sha256:a66ff063 that is the actual content change. Prunes the two OMN-16205 entries that expired unused at 2026-08-26T19:47:00Z. Header restored verbatim from main: the durable schema / invariant / process block (lines 1-45) is byte-identical to onex_change_control@main. An earlier revision of this branch mangled the OMN-13424 invariant line (dropped the literal `entries: []`, concatenated the section separator onto it) and deleted main's four-step approval process including "The approver MUST differ from the PR author (enforced by CODEOWNERS gate)" and "never by automated agents or CI". The only main header text not carried forward is the OMN-16205 per-request comment paragraph, which documents the two entries this PR prunes. approved_by is disclosed as a PROPOSAL, not an approval. As staged the PR author and approved_by are both jonahgabriel, which is self-approval on main's own header rule; the file comment and PR body now say so instead of claiming "NOT self-approved". The CODEOWNERS approver must confirm or replace the value at merge time. Consumer-side anti-self-approval is satisfied only by dispatcher != approved_by (dispatcher must be daniyalabbas96 as staged). PREP ONLY — must be landed on main by a human operator (CODEOWNERS). Evidence-Ticket: OMN-16626
4df9a54 to
d1d736f
Compare
…t eligibility resolves occ-preflight / eligibility and verify / verify were both failing #7213 with {"eligible":false,"reason":"missing_contract","missing_contracts":["OMN-16626"]}. Root cause, read from the gate rather than guessed: call-occ-preflight.yml's "Resolve OCC evidence SHA" step branches on the repo name. For onex_change_control's OWN PRs (design invariant I3, "OCC's own PRs validate evidence from the PR diff (in-tree checkout)") it sets sha=$(git rev-parse HEAD) and contracts_dir=contracts / receipts_dir=drift/dod_receipts against the PR head checkout -- it never checks out OCC at the base branch. So the pinned OCC evidence for this PR IS this PR's own tree, and the contract had to land on the branch itself. Landing it on OCC dev would not have been read at all; this PR targets main. Adds, on the branch: contracts/OMN-16626.yaml drift/dod_receipts/OMN-16626/dod-prod-promotion-grant-values-omn16626/command.yaml drift/dod_receipts/OMN-16626/dod-prod-promotion-grant-validation-omn16626/command.yaml drift/dod_receipts/OMN-16626/occ-self-bind-pr-7213/command.yaml Same shape OCC#7084 used for the OMN-16205 grant PREP on this same base (contract + receipts in the grant PR itself). Departure from that precedent: the two substantive check_values are real falsifiable probes rather than `grep -q '^status: PASS$' <the receipt itself>`, which tests/test_evidence_admissibility.py explicitly lists as a REFUSED shape. - grant-values: three-clause grep for both grant_ids + the shared promotion_batch_id in grants/prod_promotion_grants.yaml. Exits 0 here, non-zero on onex_change_control@main, which carries neither grant_id. - grant-validation: uv run pytest tests/test_prod_promotion_grants.py -q (18 passed), which includes the OMN-13424 at-rest invariant test that fails on any expired entry -- the falsifying test for the prune. - self-bind: gh pr view of #7213 itself. Receipts carry contract_entry_sha256 (OMN-13888 per-entry binding) plus the whole-file contract_sha256; runner != verifier, so no self-attestation downgrade. No skip tokens. No gate edits. No change to grants/prod_promotion_grants.yaml. #7213 stays DRAFT -- the CODEOWNERS merge remains the approval act (OMN-13418). Verification: omnibase_core@main's validator_occ_merge_eligibility (the exact module the gate imports, run from a worktree at origin/main) against this tree returns {"eligible":true,"reason":"eligible"}; pre-commit green on all four files. Evidence-Ticket: OMN-16626
…in the migration inventory `Migration Inventory Sync` (a REQUIRED context on onex_change_control@main) went red on #7213 with: [ERROR] UNLISTED_FILE: omninode_cloud: omninode_infra/db/migrations/20260825_backfill_gateway_workflows_completed_at.sql exists on disk but not in inventory Not caused by this PR's diff. The gate clones each peer repo at its default branch and compares that working tree against OCC's own src/onex_change_control/boundaries/migration_inventory.yaml. The migration has been on omninode_infra dev AND main since 6bb696d1 (2026-08-25, OMN-15681 #994). OCC dev's inventory already lists it; OCC main's does not, because main is release-synced and lags dev. #7213 is a main-based hotfix branch, so it is the branch where that lag surfaces -- and it surfaces as a required-check failure that would block the CODEOWNERS approver. Fix is the canonical value, copied verbatim from onex_change_control@dev (line 561-562) rather than re-derived: - file: "20260825_backfill_gateway_workflows_completed_at.sql" tables: [gateway_workflows, migrations_log] Independently confirmed against the migration's own SQL on omninode_infra@main: it UPDATEs public.gateway_workflows and CREATE/INSERTs public.migrations_log -- no other tables. Falsifiable both directions, run locally with the gate's own entry point (uv run check-migration-inventory --repos-root <symlinked peer clones>): with the entry -> zero ERRORs entry stashed out -> reproduces the exact CI error string above Evidence-Ticket: OMN-16626
Operator approval record — this comment is the citation, the merge is the actThis PR's body says "PREP ONLY. THIS PR MUST NOT BE MERGED BY ANY AGENT." That constraint was authored by the staging lane. It has now been explicitly lifted by the operator, for this PR by number, in a durable ledger row. The lift is recorded here rather than left implicit, and the grant file itself has not been reworded, softened, or re-staged — the merge is the approval act, nothing else changed. Consent authority (verbatim)
Operator, verbatim:
Scope clause governing this PR, verbatim from that row:
Item (5) of the same row, verbatim, which this merge does not touch:
What this merge does and does not authorize
Disclosure 1 — the "CODEOWNERS-gated merge" anchor is advisory, not mechanically enforcedThe PR body describes the merge as "that CODEOWNERS-gated merge is the anti-self-issue anchor an agent structurally cannot complete." Verified against live settings, that is not mechanically true on this branch, and it should not be relied on as a defense:
So the anti-self-issue property is not supplied by this merge's review path. It is supplied by the ledger consent row above (a durable, operator-authored record an agent cannot forge) plus Disclosure 2. Disclosure 2 — the load-bearing anti-self-approval check is consumer-side, and it constrains who may dispatch
The remaining mechanical defense is consumer-side and verified live on approved_by = str(entry["approved_by"])
if approved_by == requested_by:
... # SELF_GRANTED — "self-approval is rejected"
The dispatcher MUST be This is not a caveat to work around — it is the intended and only mechanical gate left on this path, and it is preserved intact by merging Pre-merge state verified
Merged via |
Summary
PREP ONLY. THIS PR MUST NOT BE MERGED BY ANY AGENT. It becomes effective only when a human operator lands it on
onex_change_control@main— that CODEOWNERS-gated merge is the anti-self-issue anchor an agent structurally cannot complete (OMN-13418, CLAUDE.md §2a/§12).Staged by agent lane
omn16626-promotion-prepunder the operator consent recorded inomni_home/docs/tracking/ROLLING_WORK_LEDGER.mdrow2026-08-26T19:22:09Z(laneoperator-consents-1900): "OMN-16626 image promotion GRANTED … repo pin fixes + grant-file PR prepared by lanes, dispatch by operator/Daniyal per standing no-session-dispatch rule."Two entries under one
promotion_batch_id(batch-92a794cd-680a-4af6-8879-32969bf7eeb1):grant-3c885a33-…sha256:13c96028…grant-9c23ed5d-…sha256:a66ff063…d1d736fa3An earlier revision of this branch (
4df9a5438) carried two defects that an audit caught. Both are corrected; they are stated here rather than quietly overwritten.Correction 1 — the grants-file header was silently corrupted
The first revision mangled
main's durable header:entries: []and had the section separator concatenated onto it, producing…it must be pruned so at rest the file is # ------------.main's four-step approval process block, including step 4 — "The approver MUST differ from the PR author (enforced by CODEOWNERS gate)" — and the sentence "Entries are added only through the CODEOWNERS-gated approval process — never by automated agents or CI." Those are the exact clauses that govern this PR, removed without disclosure.Fixed. The durable schema / invariant / process header (lines 1–45) is now byte-identical to
main— verified bysha256on the extracted region:85d4e1d8eb27d59c…on bothmainand this branch's head, and again afterpre-commit/yamlfmt(which made zero changes, so no policy text was traded away for a formatter).The only
mainheader text not carried forward is the OMN-16205 / OMN-16207 per-request comment paragraph (mainlines 47–71), which documents the two entries this PR prunes. Verified mechanically: all 25 dropped comment lines fall inside that paragraph and no others.Correction 2 —
approved_byas staged IS self-approval, and the previous body claimed otherwiseThe previous body asserted the entries were "NOT self-approved". That claim was wrong and is withdrawn. The PR author is
jonahgabrieland both entries carryapproved_by: jonahgabriel, pre-populated by the agent lane. Undermain's own header rule (step 4, restored above) that is self-approval as staged.approved_byon both entries is therefore a PROPOSAL, not an approval — an operator-owned field the CODEOWNERS approver must confirm or replace at merge time. Each entry now carries an inline# PROPOSAL — the CODEOWNERS approver sets this at merge timemarker, and the file's header block states the same at length.Why it is a real login rather than a literal placeholder string. This repo's schema validator requires
approved_byto be a non-empty string, so the field cannot be omitted or blanked. More importantly, the consumer (omninode_infra/scripts/validate_prod_promotion_grant.py, OMN-14209) enforcesapproved_by != requested_byagainstgithub.actor— a synthetic placeholder would compare unequal to every dispatcher and would silently disable the only mechanical anti-self-approval check on this path. Keeping a real login is the safer staging value; it remains a proposal either way.What actually satisfies anti-self-approval here: only
dispatcher != approved_byon the consumer side. Nothing about this file's own review satisfies it. As staged, that means Daniyal (daniyalabbas96) must be the dispatcher. See the table below.jonahgabrielomninode_infra/scripts/validate_prod_promotion_grant.pystill enforcesapproved_by != requested_by, whererequested_byisgithub.actor— the account that clicks Run workflow. OMN-14814 removed that check from this repo's schema validator only; it is live and unchanged in the consumer.Re-verified after the correction, by running the consumer's own
resolve_grant_for_digestagainst this exact corrected file:With
approved_by: jonahgabrielas staged, Daniyal (daniyalabbas96) must be the dispatcher (verifiedadminonomninode_infra2026-08-25 per OCC#7084). If the approver setsapproved_byto a different login at merge time, re-derive the permitted dispatcher from the new value before dispatching.Note also that
main's header has not absorbed OMN-14814's sole-CODEOWNER self-approval carve-out (commitf2b49416f, dev-only). The stricter main-branch text is what governs this PR, and is what Correction 2 is measured against.65128a2edStated here rather than left for the approver to discover: from
d1d736fa3until65128a2ed, both requiredchecks on this PR —
occ-preflight / eligibilityandverify / verify— were failing, identically:{"eligible":false,"reason":"missing_contract","missing_contracts":["OMN-16626"], "occ_commit_sha":"d1d736fa3eb6d98e9968d12d44c8cdddb783756c","ticket_ids":["OMN-16626"]}A CODEOWNERS approver could not have merged this PR in that state regardless of intent. That is the correct
behaviour of the gate, not a flake.
Why it happened. OMN-16626 had no
contracts/OMN-16626.yamlin the OCC evidence this PR's gate pins.The non-obvious part is which evidence that is.
.github/workflows/call-occ-preflight.yml'sResolve OCC evidence SHA step branches on the repo name, and for
onex_change_control's own PRs takesthe in-tree path (design invariant I3, "OCC's own PRs validate evidence from the PR diff (in-tree
checkout)"):
The
Resolve Evidence-SourceandCheck out onex_change_controlsteps are both guarded bygithub.repository != 'OmniNode-ai/onex_change_control'and never fire here. So the pinned OCC evidence forthis PR is this PR's own tree at its head SHA — confirmed by the failure JSON itself, whose
occ_commit_shais this branch's head, not a base-branch commit.Consequence: landing the contract on OCC
dev(the usual occ-autobind/companion route) would not have beenread by this gate at all, and this PR targets
main. The contract had to land on the PR branch itself.The fix (
65128a2ed) — evidence only, nothing else touched.grants/prod_promotion_grants.yamlisbyte-for-byte unchanged by it; the header-restore verification in Correction 1 above still holds.
contracts/OMN-16626.yamldrift/dod_receipts/OMN-16626/dod-prod-promotion-grant-values-omn16626/command.yamlgrep -Ffor bothgrant_ids + the sharedpromotion_batch_idin the grant filedrift/dod_receipts/OMN-16626/dod-prod-promotion-grant-validation-omn16626/command.yamluv run pytest tests/test_prod_promotion_grants.py -q→ 18 passeddrift/dod_receipts/OMN-16626/occ-self-bind-pr-7213/command.yamlgh pr view 7213self-bindThis is the same shape OCC#7084 used for the OMN-16205 grant PREP on this same base — contract + receipts
carried in the grant PR itself. One deliberate departure: #7084's two substantive contract
check_values weregrep -q '^status: PASS$' <the receipt file itself>, a shapetests/test_evidence_admissibility.pyexplicitly names as REFUSED (a receipt asserting its own PASS is not evidence). The checks here are
falsifiable against the tree instead — the grant-value grep exits non-zero on
onex_change_control@main,which carries neither
grant_id, and the pytest target includes the OMN-13424 at-rest invariant test thatfails on any expired entry, which is the falsifying test for the prune described above.
Receipts carry
contract_entry_sha256(OMN-13888 per-entry binding) as well as the whole-filecontract_sha256, andrunner!=verifierso no self-attestation downgrade applies.No skip token was used and no gate was edited. This PR carries no bypass token of the
[skip-…]family in its body, its diff, or its commit messages (the literal prefixes are deliberately notspelled out here — the Receipt Gate scans the PR body itself and rejects the string on sight, which is
exactly what happened on the first attempt at this section). The gate was satisfied on its own terms.
Second red, unrelated to the grant:
Migration Inventory Sync— fixed inc8223dd58Disclosed for the same reason as the section above: it was red, and it is a required context on
onex_change_control@main, so it would have blocked the approver.Not caused by this PR's diff. That gate clones each peer repo at its default branch and compares the
working tree against OCC's own
src/onex_change_control/boundaries/migration_inventory.yaml. The migrationhas been on
omninode_infradevandmainsince6bb696d1(2026-08-25, OMN-15681 / omninode_infra#994).onex_change_control@dev's inventory already lists it;@main's does not, becausemainis release-syncedand lags
dev. This PR is amain-based hotfix branch, which is exactly where that lag surfaces.The added entry is copied verbatim from
onex_change_control@dev(lines 561–562) rather than re-derived,and independently cross-checked against the migration's own SQL on
omninode_infra@main(itUPDATEspublic.gateway_workflowsandCREATE/INSERTspublic.migrations_log; no other tables):Falsified both directions locally with the gate's own entry point
(
uv run check-migration-inventory --repos-root <symlinked peer clones>): with the entry → zeroERRORs;with the entry stashed out → reproduces the exact CI error string above.
Also seen once and NOT required:
Contract Sync Gate (Layer 3)recorded afailureat exactly10m0swith zero step records and an expired log blob — a job-level timeout during the org-wide runner saturation
window (60/60 org runners
online busy=truewhile this batch queued), not a content failure. It is notin
main'srequired_status_checks.contexts, so it does not gate the merge; it re-runs on this push.Why the runtime entry is required for an omniintelligence-only promotion
This is the non-obvious part, and it is the reason a naive "grant the omniintelligence digest" PR would have left the dispatch BLOCKED.
deploy-onex-prod.yml's grant gate step Enforce prod-promotion grant — runtime image (OMN-14209) carries noif:condition. It runs for everydeploy_target,runtime-onlyincluded, and it resolvesRUNTIME_IMAGE_REF— the digest pinned ink8s/onex-prod/runtime/kustomization.yaml, i.e.sha256:13c96028…. The omniintelligence digest is never passed to the gate at all.Meanwhile the Apply PROD manifests including runtime path step is likewise unconditional and runs
kubectl apply --server-side --force-conflicts -k k8s/onex-prod, which renders the whole tree — includingk8s/onex-prod/omniintelligence, listed ink8s/onex-prod/kustomization.yaml. Soruntime-onlyis the correctdeploy_target: it applies the omniintelligence overlay while skipping the onex-api Trivy scan and digest deploy thatallwould drag in.Net: the gate demands a grant for the runtime digest even though nothing about the runtime changes.
sha256:13c96028…is re-verified ACTIVE in ECR (tagpinned-onex-prod-live-13c96028) and is what onex-prod's runtime plane is already running, so this is a same-digest authorization — the pattern precedented by OCC#6599 (OMN-15181) and OCC#7084 (OMN-16205).Pruned: two expired OMN-16205 entries
grant-5f94d77d-…(runtime) andgrant-a1257e52-…(omniweb), added by OCC#7084, both carriedexpires_at: 2026-08-26T19:47:00Zand lapsed unused — nodeploy-onex-prod.ymlrun consumed them. The OMN-13424 invariant refuses to let any expired entry remain, so this file cannot pass CI with them present; they are removed rather than silently extended. Their per-request comment paragraph is removed with them (see Correction 1) because it documents entries that no longer exist.For the approver: if the OMN-16205 / OMN-16620 ingress cutover still needs a grant, it must be re-issued in its own PR. The runtime entry added here re-authorizes the same
sha256:13c96028…digest but only for the OMN-16626 scope in itsreason— it is not a substitute for the pruned ingress-swap authorization, whose explicit "this grant also authorizes the ingress-host swap itself" scope statement does not carry over.Approver-owned fields
approved_by: jonahgabrielis a PROPOSAL staged by an agent lane, not an approval — see Correction 2. Confirm or replace it with the approving login (which must differ from the PR author) before merging.expires_at: 2026-08-28T20:00:00Zis a proposal (~48h). Shorten freely at merge time.requested_byis deliberately not a YAML field (see file header schema). The requester is agent laneomn16626-promotion-prep, recorded here and in the ledger row cited above, not in the file.Companion repo change
omninode_infra#1016(basedev) pinsk8s/onex-prod/omniintelligence/kustomization.yaml(newTag: placeholder→digest: sha256:a66ff063…) anddeployment.yaml(:placeholder→@sha256:a66ff063…). It must be merged todevand promoted toomninode_infra@mainbefore dispatch —deploy-onex-prod.ymlhard-refuses any dispatch whoseGITHUB_REFis notrefs/heads/main.Test plan
main—sha256(lines 1–45)=85d4e1d8eb27d59c…on bothonex_change_control@mainand this branch head; re-confirmed on the pushed remote blobreasonstrings): local file byte-identical before/afterpre-commit(yamlfmt made zero changes); pushed remote blob byte-identical to local; entries semantically identical to the pre-correction revision; bothreasonstrings byte-identical (2620 / 2410 chars); all 25 droppedmaincomment lines confirmed to lie inside the OMN-16205 per-request paragraph.github/workflows/validate-prod-promotion-grants.ymlinline validator, extracted and run against the corrected file →PASS: grants/prod_promotion_grants.yaml — 2 grant(s) validated successfullyuv run pytest tests/test_prod_promotion_grants.py -q→ 18 passedpre-commit run --files grants/prod_promotion_grants.yaml→ green, no reformatomninode_infra/scripts/validate_prod_promotion_grant.py::resolve_grant_for_digestre-run against the corrected file — table aboveaws ecr describe-imagesre-verified both digests ACTIVE on 2026-08-26occ-preflight / eligibilityroot-caused to the in-tree (I3) evidence pin by reading the workflow'sResolve OCC evidence SHAstep, not by guessing; contract + 3 PASS receipts landed on the branch in65128a2edomnibase_core@main'svalidator_occ_merge_eligibility— the exact module the gate imports, run from a worktree atorigin/mainagainst this tree — returns{"eligible":true,"reason":"eligible","receipt_ids":[3 receipts]}pre-commit run --filesgreen on the contract + all three receipts (yamlfmt, ModelTicketContract schema validation, check_value fail-open lint, dod-evidence-required, Receipt Honesty Gate)approved_byNo raw SSH/kubectl retag/recreate path is used or implied. NO PROD MUTATION HAS OCCURRED OR IS AUTHORIZED BY THIS PR. It lands only the trust-anchor entries; the
workflow_dispatchis a separate, explicit, subsequent human action per the standing no-session-dispatch rule.hotfix-evidence: OCC-7211
backmerge: #7211
Evidence-Ticket: OMN-16626