Repository navigation
feat(OMN-20578): vendor the routing-feedback and alert-channel liveness projection migrations ahead of omnimarket#3416 and #3417 - #4573
Conversation
…ss projection migrations ahead of omnimarket#3416 and #3417 omnimarket adds node_projection_routing_feedback (a public platform table written by the tenant projection writer) and node_projection_alert_channel_liveness (an omninode_internal table written by the runtime principal). The node-migration vendor-parity gate refuses both PRs until these byte-identical copies are on dev, and a runtime that installs the nodes without the declared table grants exits at wiring, which the dev-202 lab runtime showed on 2026-10-05. Ledger rows, migration classes, interim bridge declarations with their expiry entries, the regenerated topology instances and catalogs, and a vendor test are included.
|
Lab: host=omni-202 (h202) lane=dev-202 (omninode-dev-202-runtime) head=1d31e2e9dfe44bcf1baafb4cdb0f58dd30bc8874 command=installed omnimarket#3416 and #3417 in the runtime, first with the existing topology instance, then with src/omnibase_infra/topology/instances/local.yaml from this PR observed=with the old instance the runtime exited at start with ModelOnexError "Auto-wiring failed for 2 contract(s): projection_routing_feedback ... principal 'tenant_projection_writer' lacks declared ...; projection_alert_channel_liveness ..." and restarted in a loop; with the instance from this PR the runtime auto-wired HandlerRoutingFeedbackWriter and AlertChannelLivenessProjectionWriter, subscribed both topics and wrote rows (three cumulative routing-feedback events gave one delegation_routing_feedback row with total_count 3; a LIVE and a DEAD checked event gave two alert_channel_liveness_verdicts rows). generate_application_database_table_grants.py --check --prove: 3 instances in sync, 90 PASS 0 FAIL on each of 9 profiles. The lane was restored and both tables dropped after the run (2026-10-05 09:06Z). |
…12885) * evidence(OMN-20578): author OCC companion for OmniNode-ai/omnibase_infra#4573 OCC companion by node_pr_lifecycle_fix_effect (OMN-13317 F1 / OMN-13990 / OMN-14285). Product PR head 1d31e2e9dfe44bcf1baafb4cdb0f58dd30bc8874. * evidence(OMN-20578): self-bind OCC#12885 + rebind contract_sha256 --------- Co-authored-by: omnimarket-bot <bot@omninode.ai>
There was a problem hiding this comment.
Hostile Reviewer — adversarial findings (OMN-17492)
Models succeeded: qwen3-review, gpt-oss-review
Models failed: none
New finding threads: 2
Deduped (already posted on this PR): 0
Below quorum (one model only, reported not threaded): 10
Nit-level findings suppressed: 0
The model is the FINDER, never the gate: merge is gated only by the
deterministic Hostile Review Thread Gate, which blocks while
hostile-reviewer threads are unresolved. Resolve each thread after
addressing (or rejecting, with a reply) its finding.
Below quorum: 10 finding(s) raised by one model only (OMN-18479)
These are reported and NOT dropped, but they get no thread and do not block: a single model's finding no other model reproduced is not evidence enough to stop a merge. Read them; act on them if they are right.
- [CRITICAL]
docker/migrations/forward/nodes/node_projection_alert_channel_liveness/0001_grant_omninode_runtime_alert_channel_liveness_verdicts.sql(qwen3-review) — Missing GRANT on BIGSERIAL sequence breaks all writes | The migration 0001_grant_omninode_runtime_alert_channel_liveness_verdicts.sql grants USAGE on the sequence 'omninode_internal.alert_channel_live - [MAJOR]
docker/migrations/forward/nodes/node_projection_alert_channel_liveness/0000_create_alert_channel_liveness_verdicts.sql(qwen3-review) — ALTER TABLE ADD COLUMN IF NOT EXISTS without NOT NULL on existing rows | The migration 0000_create_alert_channel_liveness_verdicts.sql uses 'CREATE TABLE IF NOT EXISTS' followed by a series of 'ALTER - [MAJOR]
docker/migrations/forward/nodes/node_projection_routing_feedback/0000_create_delegation_routing_feedback.sql(qwen3-review) — GRANT SELECT on public.delegation_routing_feedback to app_dashboard without RLS | The migration 0000_create_delegation_routing_feedback.sql creates the table in the 'public' schema and grants SELECT t - [MAJOR]
docker/catalog/database-topology/*yaml(gpt-oss-review) — Topology entries omit schema for omninode_internal table | The new table alert_channel_liveness_verdicts is created in the omninode_internal schema, but all topology YAML files list it under object_ty - [MAJOR]
docker/catalog/database-topology/*yaml(gpt-oss-review) — SHA256 hashes updated without verification | Multiple topology files have their source.sha256 values changed from a58dbd... to 8206b4... (or other values) but there is no evidence that the new hashes - [MINOR]
docker/migrations/forward/nodes/node_projection_routing_feedback/0000_create_delegation_routing_feedback.sql(qwen3-review) — Missing index on delegation_routing_feedback for common query patterns | The table 'delegation_routing_feedback' has a PRIMARY KEY on (model_id, task_type). The migration does not create any additiona - [MINOR]
tests/unit/migrations/test_vendor_routing_feedback_and_alert_liveness.py(qwen3-review) — Test does not verify the sequence grant for alert_channel_liveness_verdicts | The test 'test_alert_liveness_table_and_runtime_grant_are_present' in 'tests/unit/migrations/test_vendor_routing_feedback_ - [MINOR]
docker/migrations/forward/nodes/node_projection_routing_feedback/0000_create_delegation_routing_feedback.sql(qwen3-review) — Inconsistent schema placement: public vs omninode_internal | The migration creates 'delegation_routing_feedback' in the 'public' schema and 'alert_channel_liveness_verdicts' in the 'omninode_internal' - [MINOR]
docker/migrations/forward/nodes/node_projection_alert_channel_liveness/0000_create_alert_channel_liveness_verdicts.sql(gpt-oss-review) — Potential exposure of Slack error tokens | The column slack_error in alert_channel_liveness_verdicts stores raw Slack error strings. If these contain authentication tokens or sensitive identifiers, th - [MINOR]
docker/migrations/forward/nodes/node_projection_alert_channel_liveness/0001_grant_omninode_runtime_alert_channel_liveness_verdicts.sql(gpt-oss-review) — Division‑by‑zero pattern for grant assertions is brittle | The grant migration 0001_grant_omninode_runtime_alert_channel_liveness_verdicts.sql uses "SELECT 1 / count(*)" to assert grant existence. If
Findings demoted from threads (anchor rejected)
-
[MINOR] hostile-reviewer (qwen3-review)
BIGSERIAL on alert_channel_liveness_verdicts may cause sequence contention | The table 'alert_channel_liveness_verdicts' uses 'projection_cursor BIGSERIAL NOT NULL' as a monotonic boundary. BIGSERIAL creates a sequence that is incremented on every INSERT. If the table is written to by multiple concurrent processes, the sequence may become a contention point. However, PostgreSQL sequences are lock-free and use atomic increments, so contention is minimal. The real issue is that the sequence is not cached, whi
Resolve this thread when addressed — the
Hostile Review Thread Gateblocks while hostile-reviewer threads are unresolved (OMN-17492). -
[MINOR] hostile-reviewer (gpt-oss-review)
Redundant ALTER TABLE statements after CREATE TABLE | The migration 0000_create_alert_channel_liveness_verdicts.sql creates the full table schema, then immediately issues a series of ALTER TABLE ADD COLUMN IF NOT EXISTS for every column. These ALTER statements are unnecessary and add overhead during migration. | Evidence: Lines in 0000_create_alert_channel_liveness_verdicts.sql after the CREATE TABLE block, e.g., "ALTER TABLE omninode_internal.alert_channel_liveness_verdicts ADD COLUMN IF NOT EXISTS correla
Resolve this thread when addressed — the
Hostile Review Thread Gateblocks while hostile-reviewer threads are unresolved (OMN-17492).
✅ Hostile Reviewer — REVIEWEDCritical findings: 0
Semantics (OMN-17492 — the model finds, thread resolution gates)
Powered by omniintelligence.review_pairing.cli_review — multi-model adversarial review: qwen3-review (Qwen3.8-27B), gpt-oss-review (gpt-oss-120b) (OMN-8468/OMN-8524/OMN-17492) |
…ion block Re-vendors the SQL from the omnimarket source on branch jonah/omn-20578-routing-feedback-alert-liveness-prereqs (commit 58182a328bd1). The migration adds ALTER TABLE ADD COLUMN IF NOT EXISTS for all 11 columns, SET NOT NULL, and a guarded primary key. The sha256 pin moves to 43803f20610fb1ddeed49046f6c04656c5a27dfe976f0212ecfa5614f06e60f0 in the ledger and test files. This fixes test_node_migration_shape_reconciliation.py and test_whole_corpus_converges_from_drifted_shapes. sync-node-migrations.sh keeps the file frozen, so bytes were copied and the checksum re-pinned by hand.config/migration_classes.yaml now declares the file forward-only, as delegation_dispositions is.
…ack create The reconciliation block adds ALTER COLUMN and a guarded primary key, so config/migration_classes.yaml now declares it forward-only. test_migration_classes_match_the_classifier in tests/unit/migrations/test_vendor_routing_feedback_and_alert_liveness.py now expects forward-only for 0000_create_delegation_routing_feedback.sql.
The PR body trailers now name omnimarket#3420 at 58182a328bd1ad297dcb3f6675a89cedf91c2ffa, and pull_request CI reads the body from the synchronize event, so the previous head's run still paired with omnimarket#3416.
There was a problem hiding this comment.
Hostile Reviewer — adversarial findings (OMN-17492)
Models succeeded: qwen3-review, gpt-oss-review
Models failed: none
New finding threads: 7
Deduped (already posted on this PR): 0
Below quorum (one model only, reported not threaded): 5
Nit-level findings suppressed: 1
The model is the FINDER, never the gate: merge is gated only by the
deterministic Hostile Review Thread Gate, which blocks while
hostile-reviewer threads are unresolved. Resolve each thread after
addressing (or rejecting, with a reply) its finding.
Below quorum: 5 finding(s) raised by one model only (OMN-18479)
These are reported and NOT dropped, but they get no thread and do not block: a single model's finding no other model reproduced is not evidence enough to stop a merge. Read them; act on them if they are right.
- [MAJOR]
docker/migrations/forward/nodes/node_projection_routing_feedback/0000_create_delegation_routing_feedback.sql(qwen3-review) — delegation_routing_feedback in public schema lacks RLS and tenant isolation | The delegation_routing_feedback table is created in the public schema with a composite primary key of (model_id, task_type - [MINOR]
docker/migrations/forward/nodes/node_projection_alert_channel_liveness/0000_create_alert_channel_liveness_verdicts.sql(qwen3-review) — BIGSERIAL projection_cursor with UNIQUE INDEX creates a redundant constraint | The alert_channel_liveness_verdicts table defines projection_cursor as BIGSERIAL NOT NULL and then creates a UNIQUE INDEX - [MINOR]
tests/integration/migrations/test_omninode_internal_live_acl_gate_omn17886.py(qwen3-review) — Missing DELETE grant assertion for alert_channel_liveness in integration test | The integration test asserts that alert_channel_liveness_verdicts has exactly {SELECT, INSERT, UPDATE} for omninode_runt - [MINOR]
src/omnibase_infra/topology/table_grant_derivation.py(gpt-oss-review) — Legacy migration entries duplicate future contracts in table_grant_derivation | The diff adds twoContractTableDeclarationentries forlegacy_migration:delegation_routing_feedbackand `legacy_migr - [MINOR]
docker/migrations/forward/nodes/node_projection_alert_channel_liveness/0000_create_alert_channel_liveness_verdicts.sql(gpt-oss-review) — Potential exposure of Slack error tokens via SELECT privilege | Thealert_channel_liveness_verdictstable includes aslack_error TEXTcolumn that may contain sensitive Slack error tokens. The gran
Findings demoted from threads (anchor rejected)
-
[MAJOR] hostile-reviewer (qwen3-review)
Shape reconciliation ALTER COLUMN SET NOT NULL will fail on drifted tables with NULL rows | The migration 0000_create_delegation_routing_feedback.sql executes ALTER COLUMN ... SET NOT NULL on all columns after the guarded ADD COLUMN IF NOT EXISTS block. The comment in the sibling alert_channel_liveness migration explicitly acknowledges that 'NOT NULL is absent from ADDs without defaults because existing rows cannot satisfy it.' However, this migration unconditionally applies SET NOT NULL to all columns incl
Resolve this thread when addressed — the
Hostile Review Thread Gateblocks while hostile-reviewer threads are unresolved (OMN-17492). -
[MAJOR] hostile-reviewer (gpt-oss-review)
ALTER COLUMN SET NOT NULL may fail on pre‑existing rows | The migration
docker/migrations/forward/nodes/node_projection_routing_feedback/0000_create_delegation_routing_feedback.sqladds columns topublic.delegation_routing_feedbackwithIF NOT EXISTSand then immediately issuesALTER TABLE ... ALTER COLUMN ... SET NOT NULLwithout providing defaults or populating existing rows. If the table already contains data, theSET NOT NULLstatements will raise an error, causing the migration to abort. | EvResolve this thread when addressed — the
Hostile Review Thread Gateblocks while hostile-reviewer threads are unresolved (OMN-17492). -
[MAJOR] hostile-reviewer (gpt-oss-review)
Primary‑key addition may fail due to duplicate rows | The same migration (
0000_create_delegation_routing_feedback.sql) conditionally adds a primary‑key constraint on(model_id, task_type)via a DO block. If the table pre‑exists with duplicate(model_id, task_type)pairs, theALTER TABLE ... ADD CONSTRAINT ... PRIMARY KEYwill error, breaking the migration. | Evidence: DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_catalog.pg_constraint WHERE conrelid = 'public.delegation_routing_feedback'::regclass ANDResolve this thread when addressed — the
Hostile Review Thread Gateblocks while hostile-reviewer threads are unresolved (OMN-17492). -
[MINOR] hostile-reviewer (qwen3-review)
Index on (status, checked_at DESC) may be suboptimal for the stated query pattern | The comment states the index supports 'Recent measurements by status, including failures of the probe itself.' A composite index on (status, checked_at DESC) is appropriate for queries filtering by status and ordering by checked_at. However, if the common query pattern is 'latest N verdicts regardless of status,' this index is not useful. Additionally, the DESC ordering on checked_at within the composite index means the inde
Resolve this thread when addressed — the
Hostile Review Thread Gateblocks while hostile-reviewer threads are unresolved (OMN-17492). -
[MINOR] hostile-reviewer (qwen3-review)
Unit test does not verify the NOT NULL constraint behavior on drifted tables | The unit test test_vendor_routing_feedback_and_alert_liveness.py verifies byte-identity and manifest binding but does not test the migration's behavior on a pre-existing table with NULL values. Given the concern about ALTER COLUMN SET NOT NULL failing on drifted tables, an integration test that creates a table with NULL rows and then applies the migration would catch this issue. The current test suite only validates the static SQ
Resolve this thread when addressed — the
Hostile Review Thread Gateblocks while hostile-reviewer threads are unresolved (OMN-17492). -
[MINOR] hostile-reviewer (gpt-oss-review)
Index creation without CONCURRENTLY may block writes | The migration
0000_create_alert_channel_liveness_verdicts.sqlcreatesidx_alert_channel_liveness_status_timeand a unique index onprojection_cursorusing plainCREATE INDEX. On a live table with ongoing inserts, this can acquire exclusive locks, temporarily blocking writes. | Evidence:CREATE INDEX IF NOT EXISTS idx_alert_channel_liveness_status_time ON omninode_internal.alert_channel_liveness_verdicts (status, checked_at DESC);and `CREATE UResolve this thread when addressed — the
Hostile Review Thread Gateblocks while hostile-reviewer threads are unresolved (OMN-17492). -
[MINOR] hostile-reviewer (gpt-oss-review)
Missing integration test for tenant writer operations on routing‑feedback table | The added unit test verifies vendor byte‑parity and manifest bindings, but there is no integration test that exercises the
tenant_projection_writerrole inserting and updating rows inpublic.delegation_routing_feedback. Absence of such a test leaves the write path unvalidated. | Evidence: New filetests/unit/migrations/test_vendor_routing_feedback_and_alert_liveness.pycontains only parity checks; no integration test exeResolve this thread when addressed — the
Hostile Review Thread Gateblocks while hostile-reviewer threads are unresolved (OMN-17492).
Ticket: OMN-20578
Summary
omnimarket PRs omnimarket#3416 and omnimarket#3417 add projection nodes whose tables omnibase_infra neither vendors nor grants. This change vendors the four migration files byte-identically under docker/migrations/forward/nodes/node_projection_routing_feedback and docker/migrations/forward/nodes/node_projection_alert_channel_liveness. It adds application-migrations ledger rows and migration classes. It adds interim bridge declarations in LEGACY_MIGRATION_TABLE_DECLARATIONS for the two tables and their entries in the expiry test's _INTERIM_ENTRIES. It regenerates the topology instances and the nine rendered catalogs with scripts/generate_application_database_table_grants.py. It adds assertions to the live ACL gate test. It adds a new test file tests/unit/migrations/test_vendor_routing_feedback_and_alert_liveness.py.
Changes
Proof
Lab readback
On dev-202 on omni-202, h202, 2026-10-05: with omnimarket#3416 and #3417 installed in omninode-dev-202-runtime and the topology instance from before this change, the runtime exited at start with ModelOnexError "Auto-wiring failed for 2 contract(s): projection_routing_feedback ... Projection binding 'tenant_projection' principal 'tenant_projection_writer' lacks declared ...; projection_alert_channel_liveness ... Projection binding 'omninode_runtime_serv...' ..." and restarted in a loop. With src/omnibase_infra/topology/instances/local.yaml from this change copied into the container, the same runtime auto-wired both writers with DB injection, subscribed both topics, and wrote rows: three cumulative routing-feedback events gave one delegation_routing_feedback row with total_count 3; a LIVE and a DEAD checked event gave two alert_channel_liveness_verdicts rows. The lane was then restored (hot-patch removed, tables dropped).
Left
Re-pair to omnimarket#3420 (OMN-20578)
Node-Migration-Source-PR: omnimarket#3420
Node-Migration-Source-SHA: 58182a328bd1ad297dcb3f6675a89cedf91c2ffa
Evidence-Ticket: OMN-20578
Evidence-Source: OCC#12885