Repository navigation
feat(OMN-17057): a sibling merge delivers its own named revision to onex-dev staging - #3611
Merged
jonahgabriel merged 2 commits intoSep 16, 2026
Merged
Conversation
…taging An omnimarket merge could not cause a delivery at all. It rode along on whatever the next omnibase_infra push happened to build, and that candidate clones every sibling at branch dev at that instant -- so the sibling revision in the image was never CHOSEN, could not be predicted, and no sibling merge could prove delivery of its own sha. Measured on delivery run 35013603978: the candidate vendored omnimarket 3038d1da, simply where that branch pointed 18 minutes after an unrelated commit merged here. Twelve omnimarket commits had landed since by the time this was read. The primitive already existed and CI was not reaching it. deploy_source_ref.py has taken --ref plus --fallback-ref since OMN-17135, resolving the primary in whichever repository carries it and taking the fallback everywhere else. The candidate build passed the same branch name as both. Trigger. runtime-rebuild-trigger-reusable.yml gains a terminal job that needs the existing convergence job, so it fires only after the .201 dev lane was proven to vendor the merged sibling sha and its compose-dev lab-pass receipt was emitted. It sends one repository_dispatch carrying that repo and revision. Because it lives in the reusable, every repository the runtime image vendors -- omnimarket, omnibase_core, omnibase_compat -- acquires the path with no per-repo code. omniclaude is deliberately outside the family: it is not vendored into the image, so there is nothing for it to pin. Naming. build-workspace-candidate-runtime.yml gains pinned_repo and pinned_revision, both empty by default so the push path is unchanged. When set, DEPLOY_REF becomes the commit and DEPLOY_SIBLING_FALLBACK_REF the branch. The pinned commit is fetched by sha into its clone, and after staging the vendored sha in sibling-vcs-provenance.json is compared against the requested one -- the same file the image bakes and the staging deploy later reads out of a running pod (OMN-17926). The build manifest records pinned_sibling so a chosen revision is distinguishable from a branch that drifted to the same commit. Gating. lab-pass-gate keeps asserting a PASS receipt for this repo's sha, and when a pin is present additionally reads the sibling repository's own compose-dev receipt with a token scoped actions:read on that one repository. dispatch-to-staging already needs lab-pass-gate under default success(), so a missing, unreadable, malformed, name/payload-disagreeing or FAIL sibling receipt leaves the announcement unfired. Fail-closed throughout: a half-specified pin, a non-sha revision, a repository the build does not stage, a commit its source does not contain, a vendored sha that disagrees with the request, an absent sibling receipt and absent announcement credentials are each a refusal. No force input, no skip input and no if: override is added anywhere, and a test over the parsed inputs refuses one later. Concurrency. The delivery group gains a segment naming the pinned repo. github.ref on a repository_dispatch resolves to the default branch, so without it the next ordinary push would silently cancel a sibling's delivery. The announcement payload carries pinned_sibling to omninode_infra, which already resolves what each running image actually vendors; what it never had was the other half of that comparison -- which revision was intended. Tests parse the workflow graph and pin properties, not spellings. Positive control: 12 of the 16 fail against the pre-change workflows, and the 4 that pass are invariants that were already true.
jonahgabriel
enabled auto-merge (squash)
September 16, 2026 01:20
Contributor
|
| Surface | Meaning | Blocks merge? |
|---|---|---|
| Review threads | Per-finding, posted by the reviewer | No (informational) |
Hostile Review Thread Gate |
Deterministic: unresolved hostile-reviewer threads exist | Fails until resolved (not yet a required context) |
degraded verdict |
Fewer than 2 models succeeded (infra) | No |
Powered by omniintelligence.review_pairing.cli_review — multi-model adversarial review: qwen3-review, qwen3-review-b, glm-review (OMN-8468/OMN-8524/OMN-17492)
jonahgabriel
pushed a commit
to OmniNode-ai/onex_change_control
that referenced
this pull request
Sep 16, 2026
…ibase_infra#3611 (#9756) * evidence(OMN-17057): author OCC companion for OmniNode-ai/omnibase_infra#3611 OCC companion by node_pr_lifecycle_fix_effect (OMN-13317 F1 / OMN-13990 / OMN-14285). Product PR head c7b8461f48409e5116a07353182502c2c24b54b3. * evidence(OMN-17057): self-bind OCC#9756 + rebind contract_sha256 --------- Co-authored-by: omnimarket-bot <bot@omninode.ai>
…w delivery job
Three existing guards asserted properties of a two-job workflow and failed on
the third. Each is extended by deciding what the new job needs, never by
excluding it.
* the secrets guard now asserts the App pair alongside the SASL pair, and
asserts the REQUIREDNESS of each: SASL required, the App pair optional at
the interface so an existing caller keeps compiling, and refused at run
time by the announcement job itself. Marking them required would break
every caller in the commit that adds them; skipping on their absence would
report a delivery that did not happen.
* the self-checkout guard now maps the new job to None -- it runs gh and jq
and nothing from the tree, so a checkout would be ceremony that later reads
as a dependency. Listed rather than excluded, so adding a job still forces
the decision the test exists to force, and a None job is asserted to
reference no local action and no repository script.
* the CI-python-environment guard now scopes the setup-action requirement to
jobs that RUN Python. The pip-install prohibition stays universal. The
discriminating half is the else branch: a job with no setup step is
asserted to invoke no Python at all, so "forgot the setup action" cannot
pass as "does not need it". Verified against the live graph -- all six
pre-existing jobs across the three workflows classify as Python jobs with
setup present, and only the new job classifies as neither.
jonahgabriel
deleted the
jonah/omn-17057-named-revision-sibling-delivery
branch
September 16, 2026 02:01
Patel230
pushed a commit
that referenced
this pull request
Sep 16, 2026
…nex-dev staging (#3611) * feat(OMN-17057): a sibling merge delivers its own named revision to staging An omnimarket merge could not cause a delivery at all. It rode along on whatever the next omnibase_infra push happened to build, and that candidate clones every sibling at branch dev at that instant -- so the sibling revision in the image was never CHOSEN, could not be predicted, and no sibling merge could prove delivery of its own sha. Measured on delivery run 35013603978: the candidate vendored omnimarket 3038d1da, simply where that branch pointed 18 minutes after an unrelated commit merged here. Twelve omnimarket commits had landed since by the time this was read. The primitive already existed and CI was not reaching it. deploy_source_ref.py has taken --ref plus --fallback-ref since OMN-17135, resolving the primary in whichever repository carries it and taking the fallback everywhere else. The candidate build passed the same branch name as both. Trigger. runtime-rebuild-trigger-reusable.yml gains a terminal job that needs the existing convergence job, so it fires only after the .201 dev lane was proven to vendor the merged sibling sha and its compose-dev lab-pass receipt was emitted. It sends one repository_dispatch carrying that repo and revision. Because it lives in the reusable, every repository the runtime image vendors -- omnimarket, omnibase_core, omnibase_compat -- acquires the path with no per-repo code. omniclaude is deliberately outside the family: it is not vendored into the image, so there is nothing for it to pin. Naming. build-workspace-candidate-runtime.yml gains pinned_repo and pinned_revision, both empty by default so the push path is unchanged. When set, DEPLOY_REF becomes the commit and DEPLOY_SIBLING_FALLBACK_REF the branch. The pinned commit is fetched by sha into its clone, and after staging the vendored sha in sibling-vcs-provenance.json is compared against the requested one -- the same file the image bakes and the staging deploy later reads out of a running pod (OMN-17926). The build manifest records pinned_sibling so a chosen revision is distinguishable from a branch that drifted to the same commit. Gating. lab-pass-gate keeps asserting a PASS receipt for this repo's sha, and when a pin is present additionally reads the sibling repository's own compose-dev receipt with a token scoped actions:read on that one repository. dispatch-to-staging already needs lab-pass-gate under default success(), so a missing, unreadable, malformed, name/payload-disagreeing or FAIL sibling receipt leaves the announcement unfired. Fail-closed throughout: a half-specified pin, a non-sha revision, a repository the build does not stage, a commit its source does not contain, a vendored sha that disagrees with the request, an absent sibling receipt and absent announcement credentials are each a refusal. No force input, no skip input and no if: override is added anywhere, and a test over the parsed inputs refuses one later. Concurrency. The delivery group gains a segment naming the pinned repo. github.ref on a repository_dispatch resolves to the default branch, so without it the next ordinary push would silently cancel a sibling's delivery. The announcement payload carries pinned_sibling to omninode_infra, which already resolves what each running image actually vendors; what it never had was the other half of that comparison -- which revision was intended. Tests parse the workflow graph and pin properties, not spellings. Positive control: 12 of the 16 fail against the pre-change workflows, and the 4 that pass are invariants that were already true. * test(OMN-17057): bring the three reusable-workflow guards onto the new delivery job Three existing guards asserted properties of a two-job workflow and failed on the third. Each is extended by deciding what the new job needs, never by excluding it. * the secrets guard now asserts the App pair alongside the SASL pair, and asserts the REQUIREDNESS of each: SASL required, the App pair optional at the interface so an existing caller keeps compiling, and refused at run time by the announcement job itself. Marking them required would break every caller in the commit that adds them; skipping on their absence would report a delivery that did not happen. * the self-checkout guard now maps the new job to None -- it runs gh and jq and nothing from the tree, so a checkout would be ceremony that later reads as a dependency. Listed rather than excluded, so adding a job still forces the decision the test exists to force, and a None job is asserted to reference no local action and no repository script. * the CI-python-environment guard now scopes the setup-action requirement to jobs that RUN Python. The pip-install prohibition stays universal. The discriminating half is the else branch: a job with no setup step is asserted to invoke no Python at all, so "forgot the setup action" cannot pass as "does not need it". Verified against the live graph -- all six pre-existing jobs across the three workflows classify as Python jobs with setup present, and only the new job classifies as neither.
Patel230
pushed a commit
to OmniNode-ai/onex_change_control
that referenced
this pull request
Sep 16, 2026
…ibase_infra#3611 (#9756) * evidence(OMN-17057): author OCC companion for OmniNode-ai/omnibase_infra#3611 OCC companion by node_pr_lifecycle_fix_effect (OMN-13317 F1 / OMN-13990 / OMN-14285). Product PR head c7b8461f48409e5116a07353182502c2c24b54b3. * evidence(OMN-17057): self-bind OCC#9756 + rebind contract_sha256 --------- Co-authored-by: omnimarket-bot <bot@omninode.ai>
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.
Closes OMN-17057 (LD-02).
The gap, and a premise from the ticket that is now false
The ticket's evidence says omnimarket carries no workflow that can trigger a rebuild. That was true when it was written and is not true now: OMN-18268 gave omnimarket a
runtime-rebuild-trigger.ymlthat rebuilds the.201compose dev lane on merge and emits a compose-dev lab-pass receipt for the merged sha. What still has no implementation is the second half of the title, which is the half this PR is about.An omnimarket merge cannot cause a delivery to staging. It rides along on whatever the next
omnibase_infrapush happens to build, and that candidate clones every sibling at branchdevat that instant. So the sibling revision baked into the image is never chosen, cannot be predicted, and no sibling merge can prove delivery of its own sha.Measured on delivery run
35013603978(2026-09-15T19:26Z, success), reading its build manifest artifact:commit_sha(omnibase_infra)034b9a0a8d74fac8bc9ebb4fa9de9ce290fd58c3sibling_refdevper_sibling_vcs_provenance.omnimarket.vcs_ref3038d1dabadea4973707f0228862b4aef4e092423038d1damerged to omnimarketdevat 17:08Z. It reached a candidate at 19:26Z because an unrelated commit landed here, not because anything chose it. Twelve omnimarket commits had landed on top of it by the time this was read.The primitive already existed and CI was not reaching it.
scripts/runtime_build/deploy_source_ref.pyhas accepted--refplus--fallback-refsince OMN-17135 — it resolves the primary in whichever repository carries it, takes the fallback everywhere else, and recordsfallback_from.stage_workspace.shalready refuses an unpinned build (OMN-17291) and already asserts the vendored sha equals what RT-1 checked out. The candidate build passed the same branch name as both values, which threw all of that away. Nothing new is invented here; the existing pin is reached.What changed
Trigger.
runtime-rebuild-trigger-reusable.ymlgains a terminal job thatneeds:the existing convergence job, so it fires only after the.201dev lane was proven to vendor the merged sibling sha and the compose-dev receipt for it was emitted. It sends onerepository_dispatchcarrying the repository and the revision. It lives in the reusable rather than in any caller, soomnimarket,omnibase_coreandomnibase_compateach acquire the path with no per-repo code and no per-repo configuration — a copy per caller is how this org ended up with two divergenttrigger_rebuild_on_merge.py, as that file's own header records.omniclaudeis deliberately outside the family: it is not inSIBLING_REPOSand is not vendored into the image, so there is nothing for it to pin.Naming the revision.
build-workspace-candidate-runtime.ymlgainspinned_repoandpinned_revision, both empty by default. When set,DEPLOY_REFbecomes the commit andDEPLOY_SIBLING_FALLBACK_REFthe branch, which is exactly the pair OMN-17135 built.sibling_refis untouched and still governs the other three repositories, so the constraint its comments describe — one value cannot be a commit in four repositories — is preserved rather than worked around.Proving it. The pinned commit is fetched by sha into its own clone, failing there with the repository named rather than later inside RT-1 with an unresolvable ref. After staging, the vendored sha in
sibling-vcs-provenance.jsonis compared against the requested one. That file is the one the image bakes andomninode_infra's freshness gate later reads out of a running pod (per_repo_vcs_provenance.siblings.<repo>.vcs_ref, OMN-17926), so it is the artefact the ticket's own done-proof probe names. The build manifest recordspinned_sibling, so a chosen revision is distinguishable from a branch that happened to drift to the same commit.Gating.
lab-pass-gatekeeps asserting a PASS receipt for this repository's sha. When a pin is present it additionally reads the sibling repository's compose-dev receipt, using a short-lived installation token scopedactions: readon that one repository — the receipt is published by the reusable running as that repository's workflow, so this repository's own token cannot see it.dispatch-to-stagingalreadyneeds:lab-pass-gateunder defaultsuccess(), so a missing, unreadable, malformed, name/payload-disagreeing or FAIL sibling receipt leaves the announcement unfired.Concurrency.
github.refon arepository_dispatchresolves to the default branch, so without a second segment the next ordinary push would cancel a sibling's delivery silently — the exact class of invisible non-delivery this workflow exists to end. The group now names the pinned repository. Two pinned deliveries of the same sibling still collapse, which is wanted: the later revision contains the earlier one.The announcement carries
pinned_siblingtoomninode_infra. That side already resolves what each running image actually vendors; what it has never had is the other half of the comparison, which revision was intended.What fails closed
A half-specified pin, a revision that is not a 40-character sha, a repository the build does not stage, a commit its source does not contain, a vendored sha that disagrees with the request, an absent sibling receipt, and absent announcement credentials are each a refusal rather than a warning or a skip. No force input, no skip input and no
if:override is added anywhere on the path, and a test over the parsed inputs of all three workflows refuses one being added later.Rollback
Both new inputs default to empty and every new step is conditioned on a pin being present, so the push path is unchanged. Reverting the announcement job alone restores today's behaviour. Nothing is deleted, no existing input changes meaning.
Tests
tests/ci/test_named_revision_sibling_delivery_omn17057.pyparses the workflow graph and asserts properties rather than matching text, because every one of these would survive a rename: the delivery workflow accepts the sibling announcement and only that type; the pin is declared on both trigger blocks with empty defaults;sibling_refstill defaults todev; the pin reachesDEPLOY_REFwhile the fallback keeps the branch; the build verifies what it vendored; the manifest records the pin; the pin is passed from the announcement and nowhere else; the sibling receipt is read, conditioned on a pin, namingcompose-dev; the announcement stillneeds:the lab gate with noif:; the concurrency group separates the two delivery kinds; the announcementneeds:convergence; it refuses a non-sha; it refuses rather than skips without credentials; and no trigger input on any of the three workflows reads as an override.Positive control. With the three workflow files restored to their
origin/devcontent, 12 of the 16 fail. The 4 that pass are invariants that were already true — the push branches, thesibling_refdefault,dispatch-to-stagingneeding the lab gate, and the absence of override inputs. The zero is a measurement, not an empty sweep.Pushed through the governed pre-push hook; no local gate was bypassed.
Lab proof and what remains
This change alters which revision a candidate is built from, and its correctness is provable from the parsed workflow graph, which is what the tests do. The live proof is the ticket's own done-proof probe and needs the chain to run end to end: a runtime-path omnimarket merge, a PASS compose-dev receipt for that sha, a candidate whose build manifest names it, and a
deploy-onex-stagingrun id carrying it. That readback is recorded on the ticket, not asserted here — a merge is not on staging until a deploy run id carries the sha.Two things this PR deliberately does not do. It does not change what
omninode_infraasserts from the newpinned_siblingfield; that side already reads live provenance out of the pod, and widening its assertion is a separate change on the verification half (LD-03), which the ticket says not to duplicate here. And it does not make omnimarket pass the announcement credentials to the reusable: that is a one-line change in omnimarket that also advances its pin to this commit, and it has to land after this one or the reusable it calls does not yet declare the secrets.The stale-receipt defect found while verifying this path is fixed separately under its own ticket, because a sibling sha that cannot receipt PASS blocks this gate.
Evidence-Ticket: OMN-17057
Evidence-Source: OCC#9756