Repository navigation
fix(OMN-15379): lane-scope the node-migration fence release to the lab lane (operator ruling 15) - #2540
Conversation
…b lane Operator ruling 15 (2026-07-29): node_service_registry FORCE ROW LEVEL SECURITY extends to the LAB LANE ONLY. The lab (compose dev lane, project omnibase-infra) applies node_projection_registration 0000/0001/0002 in full as the FORCE proving ground; the omninode_infra k8s fence is UNCHANGED. 1. registration 0002 joins the compose fence, restoring exact parity with the k8s list at seven ids. It was in the k8s list from the start and missing here. Not cosmetic: with 0000 (the CREATE) fenced and 0002 (the dependent ALTER) not, every COLD compose lane ran 0002 against a table that had never been created and died at exit 3 (measured on .201 2026-07-29). 2. A lane-scoped release, fail-closed on three independent axes: unset or unknown ONEX_MIGRATION_LANE releases nothing; the release SET is committed in the runner and is only ever consulted for already-fenced ids; and the indicator lives in a dev-only overlay, never in the base compose that every lane overlay merges.
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 37 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
Comment |
Hand-authored because the machine mint is STRANDED, not bypassed: the occ-companion-effect publisher SUCCEEDED on #2540, but live readback of the .201 dev broker shows onex.cmd.omnimarket.occ-companion-effect-requested.v1 at HIGH-WATERMARK 25 with ZERO consumer groups. The consuming runtime is down, and it is down because of the cold-bring-up failure #2540 fixes. OMN-15247 class. Five dod_evidence items. Every check_value was round-tripped out of the YAML and EXECUTED before this commit; none is a shape-only declaration. fence carries registration 0002 (pinned head SHA): head 2 / origin-dev 0 -> RED proven against the pre-change artifact indicator absent from base compose: base 0 / dev-lane overlay 2 -> discriminates; it is not a file-presence check FORCE RLS live on the lab lane: exit 1 (table absent, cold lane) -> DECLARED acceptance, NOT satisfied. Admissibility proven both ways: the identical probe against stability-test, where node_service_registry IS forced, exits 0. So the RED is a state fact, not a broken command. non-dev lanes unchanged: exit 0 against the true baseline 060 -> asserts UNCHANGED, not zero. stability-test's six forced tables are the pre-existing OMN-15336 breach, deliberately not rolled back here; a zero-expectation probe would go RED for a condition this PR did not cause. A 000 expectation exits 1 (RED control). No Done flip. Net-new file only.
Hand-authored because the machine mint is STRANDED, not bypassed: the occ-companion-effect publisher SUCCEEDED on #2540, but live readback of the .201 dev broker shows onex.cmd.omnimarket.occ-companion-effect-requested.v1 at HIGH-WATERMARK 25 with ZERO consumer groups. The consuming runtime is down, and it is down because of the cold-bring-up failure #2540 fixes. OMN-15247 class. Five dod_evidence items. Every check_value was round-tripped out of the YAML and EXECUTED before this commit; none is a shape-only declaration. fence carries registration 0002 (pinned head SHA): head 2 / origin-dev 0 -> RED proven against the pre-change artifact indicator absent from base compose: base 0 / dev-lane overlay 2 -> discriminates; it is not a file-presence check FORCE RLS live on the lab lane: exit 1 (table absent, cold lane) -> DECLARED acceptance, NOT satisfied. Admissibility proven both ways: the identical probe against stability-test, where node_service_registry IS forced, exits 0. So the RED is a state fact, not a broken command. non-dev lanes unchanged: exit 0 against the true baseline 060 -> asserts UNCHANGED, not zero. stability-test's six forced tables are the pre-existing OMN-15336 breach, deliberately not rolled back here; a zero-expectation probe would go RED for a condition this PR did not cause. A 000 expectation exits 1 (RED control). No Done flip. Net-new file only.
Hand-authored because the machine mint is STRANDED, not bypassed: the occ-companion-effect publisher SUCCEEDED on #2540, but live readback of the .201 dev broker shows onex.cmd.omnimarket.occ-companion-effect-requested.v1 at HIGH-WATERMARK 25 with ZERO consumer groups. The consuming runtime is down, and it is down because of the cold-bring-up failure #2540 fixes. OMN-15247 class. Five dod_evidence items. Every check_value was round-tripped out of the YAML and EXECUTED before this commit; none is a shape-only declaration. fence carries registration 0002 (pinned head SHA): head 2 / origin-dev 0 -> RED proven against the pre-change artifact indicator absent from base compose: base 0 / dev-lane overlay 2 -> discriminates; it is not a file-presence check FORCE RLS live on the lab lane: exit 1 (table absent, cold lane) -> DECLARED acceptance, NOT satisfied. Admissibility proven both ways: the identical probe against stability-test, where node_service_registry IS forced, exits 0. So the RED is a state fact, not a broken command. non-dev lanes unchanged: exit 0 against the true baseline 060 -> asserts UNCHANGED, not zero. stability-test's six forced tables are the pre-existing OMN-15336 breach, deliberately not rolled back here; a zero-expectation probe would go RED for a condition this PR did not cause. A 000 expectation exits 1 (RED control). No Done flip. Net-new file only.
…ped fence release (ruling 15) (#5469) * evidence(OMN-15379): OCC companion for OmniNode-ai/omnibase_infra#2540 Hand-authored because the machine mint is STRANDED, not bypassed: the occ-companion-effect publisher SUCCEEDED on #2540, but live readback of the .201 dev broker shows onex.cmd.omnimarket.occ-companion-effect-requested.v1 at HIGH-WATERMARK 25 with ZERO consumer groups. The consuming runtime is down, and it is down because of the cold-bring-up failure #2540 fixes. OMN-15247 class. Five dod_evidence items. Every check_value was round-tripped out of the YAML and EXECUTED before this commit; none is a shape-only declaration. fence carries registration 0002 (pinned head SHA): head 2 / origin-dev 0 -> RED proven against the pre-change artifact indicator absent from base compose: base 0 / dev-lane overlay 2 -> discriminates; it is not a file-presence check FORCE RLS live on the lab lane: exit 1 (table absent, cold lane) -> DECLARED acceptance, NOT satisfied. Admissibility proven both ways: the identical probe against stability-test, where node_service_registry IS forced, exits 0. So the RED is a state fact, not a broken command. non-dev lanes unchanged: exit 0 against the true baseline 060 -> asserts UNCHANGED, not zero. stability-test's six forced tables are the pre-existing OMN-15336 breach, deliberately not rolled back here; a zero-expectation probe would go RED for a condition this PR did not cause. A 000 expectation exits 1 (RED control). No Done flip. Net-new file only. * evidence(OMN-15379): make every check_value hermetic and self-evidence-free Three gates fired and all three were right; this commit obeys them rather than working around them. OMN-14051 (hermeticity): two check_values invoked ssh. A CI runner has no ssh and no route to .201, so they could never pass there. Both removed. OMN-12791 (receipt honesty) + OMN-13060 (receipt hardening): the sanctioned substitute for a live probe is a committed receipt that the contract greps. I wrote one - and the gates correctly rejected it: SELF_ATTESTATION, because runner and verifier were the same single lane, and missing contract_entry_sha256 because receipts must be tool-generated. Inventing a second verifier identity or hand-forging the hash would be exactly the self-authored evidence those gates exist to stop, so the receipt is deleted, not patched. What remains are three items, all hermetic, all executed before commit, none reading anything this PR authors: - PR bind for omnibase_infra#2540 - fence carries registration 0002 at the pinned head SHA (head 2 / dev 0) - lane indicator absent from the base compose (base 0 / dev overlay 2) The two live measurements are now recorded as PROSE OBSERVATIONS in the contract summary, not as evidence claims: - blast radius 0/6/0 (prod/stability-test/judge), unchanged from baseline - the ruling-15 FORCE readback, NOT yet satisfied (lab lane is cold) Both land as append-only dod_evidence with tool-generated, independently verified receipts once the lab bring-up is done. * evidence(OMN-15379): add missing lane-fence receipts * evidence(OMN-15379): self-bind OCC companion PR 5469 * evidence(OMN-15379): bind OCC companion final head
|
| Verdict | Meaning | Blocks merge? |
|---|---|---|
passed |
No critical findings | No |
blocked |
CRITICAL findings found | Yes |
degraded |
All models unavailable (infra) | No (pilot) |
Powered by omniintelligence.review_pairing.cli_review — node-based adversarial review via HandlerLlmCliSubprocess (OMN-8468/OMN-8524)
Rule 24(a) says every runtime-affecting merge to dev produces an automatic lab pass. In practice the Runtime Rebuild Trigger fires only on omnibase_infra merges, so an omnimarket merge reached the lane only when some unrelated omnibase_infra merge happened to carry it. MEASURED 2026-09-14. The lane's effects container vendored omnimarket at 65c237cd (omnimarket#2538, merged 07:53:57Z), recorded in the image's own /app/build-provenance.json, while its org.opencontainers.image.revision label read 732fd29 (omnibase_infra). omnimarket#2537 (09:11:34Z) and #2540 (10:09:57Z) had merged since and were not on it. Nothing was red: the omnimarket revision was never CHOSEN. stage_workspace.sh resolves each sibling from origin/dev at staging time (DEPLOY_SIBLING_FALLBACK_REF, OMN-17135), so the lane runs whatever that pointed at when another repository's merge last fired a rebuild. omnimarket's own trigger had been dispatch-only since 2026-07-21, disabled for absent SASL/HMAC secrets; the SASL pair is now an org secret with ALL visibility and no HMAC secret is a precondition of this producer at all. WHAT LANDS A reusable workflow, runtime-rebuild-trigger-reusable.yml, called by a sibling repository's CI on merge. There is no second publisher and no second copy of the classifier: the caller supplies facts and holds no logic. The runtime-path decision stays the canonical omniclaude deploy-gate classifier, which already owns omnimarket's runtime paths, so a docs-only merge declines. resolve_publish_ref() separates two facts the single-publisher shape conflated. The deploy agent resets its BUILD-CONTEXT clone -- omnibase_infra -- with git reset --hard <git_ref>, and a sibling merge SHA names no commit there, so a sibling trigger publishes the omnibase_infra ref and carries its own SHA separately. Every ambiguous combination is refused rather than defaulted. check_lane_sibling_revision.py is the convergence guard. check_dev_lane_ staleness.py cannot answer here: the infra revision label does not move on a sibling-only rebuild, so it would report converged on its first poll having proven nothing. This reads per_repo_vcs_provenance.siblings.<repo>.vcs_ref out of the image's build-provenance manifest and asserts CONTAINMENT, not equality -- a build that starts after a later merge legitimately vendors a descendant. The compose-dev lab-pass receipt is keyed by the sibling sha, since that is the revision the lane was proven to carry, and is emitted under always() so a failed lab pass is as recorded as a passing one. STATED RATHER THAN IMPLIED. A called reusable workflow runs inside the caller's repository, so the receipt lands on the caller's run and is deliberately not visible to omnibase_infra's delivery lab-pass gate, which queries omnibase_infra artifacts for an omnibase_infra sha. Those are different claims about different commits and no artifact name collides. Rule 24(d) applies unchanged: this lane has no onex-api and no RLS, so no check claims a tenant-scoped path. Wired as CI in the same change: the reusable workflow is held to the repo's shared-CI-env invariant, its uploader is declared in ci_evidence_policy.yaml, and the new guard ships with a real incident replay driven over the manifest bytes read from the running container and GitHub's own compare response.
Rule 24(a) says every runtime-affecting merge to dev produces an automatic lab pass. In practice the Runtime Rebuild Trigger fires only on omnibase_infra merges, so an omnimarket merge reached the lane only when some unrelated omnibase_infra merge happened to carry it. MEASURED 2026-09-14. The lane's effects container vendored omnimarket at 65c237cd (omnimarket#2538, merged 07:53:57Z), recorded in the image's own /app/build-provenance.json, while its org.opencontainers.image.revision label read 732fd29 (omnibase_infra). omnimarket#2537 (09:11:34Z) and #2540 (10:09:57Z) had merged since and were not on it. Nothing was red: the omnimarket revision was never CHOSEN. stage_workspace.sh resolves each sibling from origin/dev at staging time (DEPLOY_SIBLING_FALLBACK_REF, OMN-17135), so the lane runs whatever that pointed at when another repository's merge last fired a rebuild. omnimarket's own trigger had been dispatch-only since 2026-07-21, disabled for absent SASL/HMAC secrets; the SASL pair is now an org secret with ALL visibility and no HMAC secret is a precondition of this producer at all. WHAT LANDS A reusable workflow, runtime-rebuild-trigger-reusable.yml, called by a sibling repository's CI on merge. There is no second publisher and no second copy of the classifier: the caller supplies facts and holds no logic. The runtime-path decision stays the canonical omniclaude deploy-gate classifier, which already owns omnimarket's runtime paths, so a docs-only merge declines. resolve_publish_ref() separates two facts the single-publisher shape conflated. The deploy agent resets its BUILD-CONTEXT clone -- omnibase_infra -- with git reset --hard <git_ref>, and a sibling merge SHA names no commit there, so a sibling trigger publishes the omnibase_infra ref and carries its own SHA separately. Every ambiguous combination is refused rather than defaulted. check_lane_sibling_revision.py is the convergence guard. check_dev_lane_ staleness.py cannot answer here: the infra revision label does not move on a sibling-only rebuild, so it would report converged on its first poll having proven nothing. This reads per_repo_vcs_provenance.siblings.<repo>.vcs_ref out of the image's build-provenance manifest and asserts CONTAINMENT, not equality -- a build that starts after a later merge legitimately vendors a descendant. The compose-dev lab-pass receipt is keyed by the sibling sha, since that is the revision the lane was proven to carry, and is emitted under always() so a failed lab pass is as recorded as a passing one. STATED RATHER THAN IMPLIED. A called reusable workflow runs inside the caller's repository, so the receipt lands on the caller's run and is deliberately not visible to omnibase_infra's delivery lab-pass gate, which queries omnibase_infra artifacts for an omnibase_infra sha. Those are different claims about different commits and no artifact name collides. Rule 24(d) applies unchanged: this lane has no onex-api and no RLS, so no check claims a tenant-scoped path. Wired as CI in the same change: the reusable workflow is held to the repo's shared-CI-env invariant, its uploader is declared in ci_evidence_policy.yaml, and the new guard ships with a real incident replay driven over the manifest bytes read from the running container and GitHub's own compare response.
Implements operator ruling 15 (2026-07-29) for OMN-15379:
node_service_registryFORCE ROW LEVEL SECURITY extends to the lab lane only. The lab (compose dev lane, projectomnibase-infra) appliesnode_projection_registration0000/0001/0002 in full — CREATE + heartbeat columns + ENABLE/FORCE RLS — as the FORCE proving ground. The staging k8s fence (omninode_infraFENCED_NODE_MIGRATION_IDS) is untouched by this PR.Ticket: OMN-15379. Related: OMN-15336 (the fence this extends), OMN-15343 / OMN-15335 / OMN-15088 (the FORCE hold), OMN-15332 (ruling trail).
Two changes
1.
registration 0002joins the compose fence — a parity fix, not a cosmetic one0002_node_service_registry_tenant_rls.sqlwas in the k8s list from the start and missing from the compose list shipped in #2532. With0000(the CREATE) fenced and0002(the dependent ALTER) unfenced, every cold compose lane ran0002against a table that had never been created:…taking the
forward-migrationone-shot to exit 3 and the whole lane with it. Measured live on.2012026-07-29 — that is what makes OMN-15379 a blocker rather than a corpus curiosity. A fence that gates a CREATE but not its dependent ALTER is worse than no fence. This also restores exact cross-repo parity at seven ids.Net effect for every non-dev lane (stability-test / prod / judge / CI / fresh volumes): strictly safer.
0002goes from applied unattended to fenced, and cold bring-up on those lanes stops dying at exit 3.2. A lane-scoped release, fail-closed on three independent axes
scripts/run-forward-migrations.shgains a committed, lane-keyed release policy consulted inside the fenced-id branch:ONEX_MIGRATION_LANEunset → release nothing. An unknown value → release nothing, and say so on stderr. There is no value that widens the fence relative to today.docker-compose.infra.yml. Every non-dev lane overlay merges that base — stability-test'sforward-migrationoverride is a lonecontainer_name:line, so it inherits the baseenvironment:block wholesale. A value there would be inherited by stability-test, prod, judge, and any lane added later: fail-OPEN, silently. It lives in the newdocker/docker-compose.dev-lane.yml, which only the dev/lab project loads.delegation 0023-0026are not releasable on any lane — ruling 15 is scoped tonode_service_registry; the delegation tenant-RLS hold is a separate, still-pending ruling. Asserted by test.SEAMS (declared, matched field-by-field)
Seam A — the fence list (cross-repo,
omnibase_infra↔omninode_infra). Unchanged in mechanism from OMN-15336, now at seven ids:node:${node_name}:$(basename "$sql_file")node:${node_name}:${filename}FENCED_NODE_MIGRATION_IDS=(...)bash array, 7 idsgrep -Fxq(exact whole-line)Live source of truth read at authoring time:
omninode_infra@dev966463a; the cross-repo diff leg was additionally run against a freshly-fetched662a366and passes.Seam B — the lane indicator (compose → runner, new).
ONEX_MIGRATION_LANEONEX_MIGRATION_LANEdevcaseover exactlydev/""/*docker/docker-compose.dev-lane.yml,services.forward-migration.environment${ONEX_MIGRATION_LANE:-}→""arm → release nothing*arm → release nothing + stderr warningresolve_compose_file_args()(deploy-runtime.sh) and_LANE_CONFIGS[DEV](deploy_agent/executor.py)Seam C — the release set.
LANE_RELEASED_NODE_MIGRATION_IDSfor lanedev== exactly the threenode_projection_registrationids, asserted to be a strict subset of the fence and asserted to contain no delegation id on any lane.Cross-boundary test — drives the actual runner, both ways
tests/scripts/test_node_migration_fence_parity.pygrows 20 tests (14 static, 3 live, plus the existing 2 live and the cross-repo leg). The live half executes the shippedscripts/run-forward-migrations.shagainst a real Postgres over the real vendored registration SQL (copied verbatim fromdocker/migrations/forward/nodes, not marker stubs — marker stubs cannot prove FORCE landed), with theapp_dashboardrole created by a flat migration so 0002's real precondition is exercised:test_dev_lane_applies_the_registration_trio_with_force_rls—ONEX_MIGRATION_LANE=dev→ all three applied + recorded;pg_class.relrowsecurity = trueandrelforcerowsecurity = true;last_heartbeat_at/uptime_seconds/tenant_idcolumns present;tenant_isolationpolicy present. Negative control in the same run: a fenced delegation id rides along and must still be skipped.test_default_lane_skips_the_trio_and_the_registry_table_is_absent— indicator genuinely unset (popped, so an ambient value on the test host cannot leak in through theos.environsplat) → all three reported operator-gated,node_service_registrydoes not exist, no ledger rows.test_unknown_lane_value_fails_closed_to_the_full_fence— valuestability-test(a real lane name, so loose prefix/glob matching betrays itself) → fenced, plus the stderr warning.The pair is the discriminator: a runner that ignored the indicator entirely fails one leg whichever way it defaulted, so neither leg can pass vacuously.
Static half additionally asserts the compose seam directly: the indicator is absent from
docker-compose.infra.ymland fromdocker/catalog/services/forward-migration.yaml(so a catalog regenerate cannot reintroduce it), absent from all three non-dev overlays, present as exactlydevin the dev overlay, and wired into both lane→compose-file mappings.RED-vs-
origin/dev(proven by execution, not asserted)Same tests against the pre-change artifacts (shipped files reverted to
origin/dev, tests kept): 10 fail / 18 pass.Also note:
test_fence_matches_omninode_infra_k8s_runner(opt-in cross-repo diff) was a latent RED onorigin/dev— compose had 6 ids, k8s had 7. This PR is what makes it green.Gates — all on
.200per rule 11a, sha256-verified patch-transfer both directionsAll six changed files verified byte-identical between this Mac and the
.200worktree before and after gating (797e2b98…runner,c87528f4…overlay,2877c0b4…parity test, …).ruff check+ruff format --checkonscripts/+tests/scripts/: clean.scripts/ci/detect_test_paths.py) resolved this diff totests/scripts/ tests/unit/scripts/→ 1346 passed, 5 skipped (skips all pre-existing/environmental: 4× GNUrealpath -mOMN-15134, 1× the opt-in cross-repo leg).REQUIRE_MIGRATION_LOCK_DB=1(so a missing DB fails rather than silently skips) andREQUIRE_CROSS_REPO_FENCE_PARITY=1: 34 passed, 0 skipped.tests/ci/test_node_migration_shape_reconciliation.py,tests/unit/migrations/,tests/integration/migrations/,test_judge_compose_profile.py): 214 passed, 1 failed —test_sync_check_reports_in_sync, proven pre-existing by running the identical test on a pristineorigin/devworktree on the same host (same failure). Cause is.200'somnimarketclone sitting at69a576c4(feat(OMN-12957): wire runtime-profile validator + core registry parity guard #1945) while infra's vendored tree was synced fromf4f27a98(fix(OMN-12989): workspace-mode image build must honor sibling lock pins #1947); no vendored SQL is touched by this diff.pre-commit run --all-files: 4 hooks fail —URL Authority Gate,Node Migration Vendor Sync Check,SPDX Header Requirement(2026 year in two files this diff does not touch),check-required-env-vars(GITHUB_TOKENabsent from that host's env). A pristineorigin/devworktree on the same host fails 5, a strict superset. Every failure is pre-existing; none is introduced here.--no-verify, no--no-gpg-sign, no skip token.Deliberately NOT done
omninode_infra. Ruling 15 is lab-only and the staging un-fence is waiting on the evidence this lab lane will now generate.0003/081/0027belong to OMN-15088.Honest limit, stated rather than papered over
A deliberate
-e ONEX_MIGRATION_LANE=devon another lane'sforward-migrationcontainer would release the trio there. That is an explicit operator act on the same footing as editing the fence list itself, and it is not defended against: the container has no un-forgeable lane fact to corroborate against — compose does not inject the project name, and a service cannot read its owncontainer_namefrom inside itself. What is defended against is the realistic failure — silent inheritance through the base compose file — and that is closed by construction plus test.Evidence-Source: OCC#5469
Evidence-Ticket: OMN-15379