Repository navigation
fix(OMN-15336): compose migration runner honours the k8s operator fence (skip+record, never apply) - #2532
Conversation
…ce (skip+record, never apply)
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 34 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 (2)
Comment |
…ring (ai-slop md_separator)
|
| 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)
#5386) * evidence: OCC companion pass 1 for OmniNode-ai/omnibase_infra#2532 * evidence: OCC companion self-bind for #5386 --------- Co-authored-by: node-occ-companion-effect <occ-companion-effect@omninode.ai>
OMN-15336 — the compose migration runner had no operator fence
The fence gating the tenant-RLS node migrations lived only in
omninode_infra/k8s/migrations/omnibase-infra-migrate.yaml.scripts/run-forward-migrations.sh— the runner every compose lane executes (dev, stability-test, judge, prod all mount it;docker/catalog/services/forward-migration.yaml,docker/docker-compose.{infra,stability-test,judge,prod}.yml) — had no fence and no skip branch of any kind in its node loop. It applied everynodes/*/*.sqlit discovered. Two sanctioned runners, one shared id space, disagreeing about what is gated.This PR ports the fence. It changes no live database state anywhere — see "What this does NOT do".
Live readback (read-only,
.201, four compose lanes, dbomnidash_analytics, 2026-07-29 ~00:15Z)schema_migrationsrelforcerowsecurityomnibase-infra-postgresregistration:0002omnibase-infra-stability-test-postgresregistration:0002omnibase-infra-prod-postgresregistration:0000/0001onlyomnibase-infra-judge-postgresregistration:0000/0001onlyTwo facts the ticket did not have:
stability-test— the designated proof lane for synthetic integration evidence — is also over the fence, with the same six FORCE-RLS tables. The ticket named only the dev lane.delegation:0023-0026, so without this fence the next forward-migration run on either would apply the un-proven tenant-RLS design unattended. That is the concrete hazard this closes.The seam (stated explicitly, matched field-by-field)
Both runners walk the same vendored SQL tree (
docker/migrations/forward/nodes/<node>/*.sql, synced byscripts/sync-node-migrations.sh) and mint the same idnode:<node>:<filename>. The fence is a shared list over a shared id space.node:${node_name}:$(basename "$sql_file")node:${node_name}:${filename}FENCED_NODE_MIGRATION_IDS=( … )(6 ids)FENCED_NODE_MIGRATION_IDS="…"(same 6, same order)grep -Fxq(exact whole-line)node_skipped+++continueNODE_SKIPPED+++continueSource read at build time:
omninode_infra@dev=f436ca6(fix(OMN-15335): … fence the registration pair (#740)), re-read immediately before push — still six ids,registration:0002not yet fenced there.Two deliberate deviations, both stated rather than smuggled:
bash(arrays,set -euo pipefail); this runner is#!/bin/shunder busybox ash in the migration container, where arrays do not exist. The seam is the id list and the semantics, not the syntax. Asserted bytest_fence_predicate_is_posix_sh.psql -f"; it is placed BEFORE the already-applied probe instead — matching the k8s runner, and strictly safer: a fenced id then cannot be reached by any path through the loop, including a ledger probe that fails open. Asserted bytest_fence_is_checked_before_the_ledger_probe_and_the_apply."Skip + record" means record the SKIP — counted into
NODE_SKIPPED, named on stdout. The id is deliberately not inserted intoschema_migrations, matching the k8s runner: a ledger row would make the eventual un-fencing a silent no-op (the runner would read the row, call it already applied, and never run the migration). Asserted bytest_fenced_skip_never_records_a_ledger_rowand proven live.Cross-boundary regression test (drives the artifact that actually runs)
tests/scripts/test_node_migration_fence_parity.py— 10 tests, reusing the OMN-15291 scratch-Postgres harness.Live proofs execute the shipped
scripts/run-forward-migrations.shagainst a real Postgres with a vendored-shaped node tree in which every fenced id creates a distinctly-named marker table, so "was this applied?" is answered by the database, not by parsing the runner's own log:test_shipped_runner_skips_and_records_fenced_node_migrations(GREEN) — exit 0; each fenced id reportedSKIP (operator-gated …); no fenced marker table exists; no fenced id inschema_migrations; summary line reports6 node skipped. An unfenced control migration in the same node directory IS applied and IS recorded — without it, "no fenced marker exists" would pass vacuously on a runner that never reached the node loop.test_fence_free_runner_applies_the_fenced_migration(RED control) — the same harness against a copy of the runner with both fence blocks mechanically stripped (derived from the shipped file, so the control cannot drift from what it controls). Asserts the fence-free runner applies every gated migration and writes every ledger row — i.e. it reproduces the exact.201/stability-test breach. Without this, the GREEN result is unfalsifiable.Static assertions (no DB, so they gate every PR): fence present; exact ordered list vs the pinned
EXPECTED_FENCE, with the delegation half and the registration half asserted separately so a failure names which half moved; every fenced id resolves to a real vendored.sqlfile (a typo'd id fences nothing and fails open, silently); the list is not env-overridable; ordering vs probe vs apply; skip writes nothing to the DB; POSIX-sh only.RED-vs-base, proven not asserted
Against
origin/dev's runner (byte-swapped in, then restored — sha256 verified identical after restore): 9 of 10 fail. The one that passes istest_every_fenced_id_names_a_real_vendored_sql_file, which is about the vendored SQL tree, not the runner — correct that it is green on base.Cross-repo drift hazard — flagged, NOT unilaterally re-architected
This fix duplicates the list: the same ids are now hand-maintained in two repos. That is the same shape as the defect being fixed, just slower to bite.
EXPECTED_FENCEtuple (exact + ordered).test_fence_matches_omninode_infra_k8s_runnerdiffs against the live k8s manifest, resolved from that repo'sorigin/dev, underREQUIRE_CROSS_REPO_FENCE_PARITY=1.The opt-in-ness was measured, not assumed: an always-on version of that test went RED on the
.200build host purely because that host'somninode_infraclone sat two commits behind dev (working tree294850e,origin/devref6e09ec3, true tipf436ca6). Gating every PR on another repo's local checkout freshness manufactures false REDs; the failure message now names the resolved source commit so a stale clone is diagnosable instead of being mistaken for real drift.Follow-up filed: OMN-15349 — "Single-source the node-migration operator fence across omnibase_infra + omninode_infra". Marked ARCHITECTURE / needs operator approval, with three costed options (committed manifest consumed by both runners / generated block + drift gate / cross-repo CI diff only). Not started here: single-sourcing a value consumed by two runners in two repos is an architecture change, and those are operator-gated.
Standing obligation until that lands: any change to
FENCED_NODE_MIGRATION_IDSmust edit both runners in the same change, plus theEXPECTED_FENCEpin. Live example: if the OMN-15345 lane addsnode:node_projection_registration:0002_node_service_registry_tenant_rls.sqlto the k8s fence, this list and the pin must move with it.What this does NOT do (deliberate; operator-owned)
NO FORCE, noDISABLE, noDROP POLICY, anywhere.registration:0002,delegation:0027,inference_response:0003, flat081, which the ticket flags as carrying the same FORCE hazard while being ungated on both runners. Widening the fence beyond parity is a separate decision on OMN-15088; parity is this ticket.SELECT(table above).Behaviour change to expect: on prod and judge (which have not applied
delegation:0023-0026), these ids now reportSKIP (operator-gated …)on every run instead of being applied. That is the point. On dev and stability-test, where they are already applied, the fence short-circuits ahead of the already-applied probe, so the line changes fromalready appliedtooperator-gated— no state change.Gates
Run on
.200(stickybeatz-studio) per rule 11a, patch-transfer with sha256 verified in both directions before any remote gate ran (scripts/run-forward-migrations.sh058c11d7…, test file5bcb3327…):ruff format --check+ruff check tests/scripts/ scripts/— clean.pytest tests/scripts/test_node_migration_fence_parity.py tests/scripts/test_forward_migration_advisory_lock.py tests/unit/migrations/withREQUIRE_CROSS_REPO_FENCE_PARITY=1against a freshly-fetchedomninode_infra@f436ca6— 79 passed, 0 skipped (-rs). The live Postgres proofs executed there, not skipped.pre-commit run --all-files— two failures, both proven pre-existing onorigin/devand untouched by this PR: SPDX year2026intests/ci/test_runner_routing_audit.pyandtests/scripts/test_deploy_runtime_core_contracts_resolution.py(confirmed viagit show origin/dev:<file> | head -1), andcheck-required-env-varsreportingGITHUB_TOKENmissing from that host's~/.omnibase/.env(reproduces identically on the pristine canonical clone at dev — host env, not repo state).shellcheck -S warning -x scripts/run-forward-migrations.sh— clean, and clean on the base version too (the threeSC2012info findings are pre-existingls-in-forlines this PR did not touch; the repo's shellcheck hook is scoped todeploy-runtime.shand does not cover this file).psql/initdb): the same fence module, 10/10 including both live proofs, fail-closed underREQUIRE_MIGRATION_LOCK_DB=1.dod_evidence
scripts/run-forward-migrations.sh— fence block + in-loop skip branch, both marker-delimited.tests/scripts/test_node_migration_fence_parity.py— 10 tests: 8 static, 2 live-Postgres (GREEN + RED control).origin/dev's runner..201readback table above (read-only).Closes OMN-15336.
Evidence-Ticket: OMN-15336
Evidence-Source: OCC#5386