Skip to content

fix(OMN-19661): a Postgres claim store writes the contract-declared schema - #2923

Merged
jonahgabriel merged 2 commits into
devfrom
jonah/omn-19661-claim-store-contract-schema
Sep 26, 2026
Merged

jonahgabriel merged 2 commits into
devfrom
jonah/omn-19661-claim-store-contract-schema

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Summary

OMN-19661. A Postgres-backed delegate-skill claim store now writes the table the node contract declares, omninode_internal.delegate_skill_command_claims. It previously resolved the bare table name against public.

Why

The claim port passes the bare name delegate_skill_command_claims to PostgresSyncProjectionAdapter. That adapter refuses dotted names (postgres_sync_database.py _validate_identifier), and it opened every psycopg2 connection with no search_path. No role or database on the deployed lanes sets one (omnibase_infra docker/migrations/cloud/run-cloud-migrations.sh:44-51 says so). The bare name therefore resolved to public, where the table does not exist. Any lane that bound OMNIMARKET_PROJECTION_RUNTIME_BINDING_OVERLAY would have failed every bus delegation with UndefinedTable, which is why no lane binds it. Deployed claims today go to a per-pod SQLite file in an emptyDir, and that file is lost when the pod is replaced. The loss reopens the crash-redelivery double-bill that OMN-18887 AC4 covers.

Change

  • PostgresSyncProjectionAdapter(dsn, *, schema=None) accepts one optional schema. The schema is validated as an identifier (a list is refused, so no fallback relation can answer), and each connection the adapter opens then carries options=-c search_path=<schema>. A caller that passes no schema gets exactly the previous connect(dsn) call, and a test pins that.
  • evidence_db_resolution._adapter_for_dsn passes an optional postgres_schema through. SQLite ignores it.
  • port_delegation_claim.claims_schema() reads the schema from contract.yaml db_io.db_tables for the claims table. It refuses a missing entry or a duplicate. The binding branch of resolve_delegation_claim_store passes that schema.

Proof

  • New file tests/unit/nodes/node_delegate_skill_orchestrator/test_claim_store_contract_schema_omn19661.py. RED before the change: 7 failed, and the pin test failed on 'search_path=omninode_internal' in ''. GREEN after: 9 passed.
  • One of the 9 is a real-Postgres case, run against a throwaway local postgres:16-alpine container that has since been removed. It builds the node's own migration into a private schema. The negative control is the unpinned adapter, which raises UndefinedTable. The pinned port wins the first claim and loses the second, and exactly one row is left. The case skips without INTEGRATION_POSTGRES_*, as the sibling real-DB suites do.
  • The node test directory plus test_omn18159_sync_upsert_write_contract.py and test_omn19029_claims_migration_shape_and_grant.py: 310 passed, 9 skipped. ruff and mypy --strict pass on the changed source files. pre-commit passes on the changed files.

Runtime-affecting: yes

After merge, nothing changes on any lane until a lane binds the overlay: the no-binding branch is untouched. The binding comes in omninode_infra (OMN-19661, onex-lab overlay first). That binding is safe to apply only once a runtime image carrying this change is on the lane.

Merge order

This PR is stacked on omnimarket#2917 (OMN-19654, which touches the same resolver). Land #2917 first. Until then, this diff shows #2917's commit as well.

Body drafted with onex delegate, run b7334a18-024a-453a-b887-13a6a60c2cb6 (wire correlation 91dbe239-6013-42cc-9cee-db94a793b6ca), then edited by hand.

Evidence-Ticket: OMN-19661
Evidence-Source: OCC#11336

@jonahgabriel
jonahgabriel marked this pull request as ready for review September 25, 2026 19:44
@github-actions

Copy link
Copy Markdown

✅ Architectural Review — PASSED

Errors: 0
Warnings: 0

What this checks

Rule Description
ARCH-TOPIC-001 No hardcoded Kafka topic strings in handler code
ARCH-DI-001 No event_bus=None bypass
ARCH-DI-002 No direct Handler instantiation outside workflow_runner/adapters
ARCH-DI-003 No reinvented DI containers
ARCH-TOPIC-002 contract.yaml topics follow `onex.{cmd

No architectural violations found.

Static architectural lint — no model inference (OMN-14176).

onexbot-occ-writer Bot added a commit to OmniNode-ai/onex_change_control that referenced this pull request Sep 25, 2026
…nimarket#2923

The declared checks were executed for real in the OmniNode-ai/omnimarket checkout at the PR head by the product-repo OCC receipt runner, and the results written append-only into this companion. Producer-minted PENDING receipts are superseded by a net-new record; no existing receipt was edited.

Ticket: OMN-16859 (AC3b)
Onex-Workflow: OCC Receipt Runner
Onex-Run: https://github.com/OmniNode-ai/omnimarket/actions/runs/36181532604
@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

✅ Hostile Reviewer — PASSED

Blocking findings (critical/error): 0
Total findings: 11
Models succeeded: qwen3-review,qwen3-review-b


Gate semantics

Verdict Meaning Blocks merge?
passed >=2 models succeeded, no critical/error findings No
blocked CRITICAL or ERROR findings found Yes
degraded Fewer than 2 models succeeded (infra unavailable/timeout) Yes (OMN-15110)

Powered by omniintelligence.review_pairing.cli_review — node-based adversarial review via HandlerLlmCliSubprocess (OMN-8524)

conn = psycopg2.connect(dsn)
except Exception as exc: # pragma: no cover - environment dependent
pytest.skip(f"Postgres unreachable: {exc}")
conn.autocommit = True
@jonahgabriel
jonahgabriel enabled auto-merge (squash) September 25, 2026 19:57
…chema

The delegate-skill claim port passes the bare table name to
PostgresSyncProjectionAdapter, which refuses dotted names and opened every
connection with no search_path. No role or database on the deployed lanes
sets one, so a claim resolved to public, where the table does not exist,
and any lane binding the projection runtime overlay would fail every bus
delegation with UndefinedTable. That is why no lane binds it, and why
deployed claims live in a per-pod SQLite file lost on pod replacement.

The adapter takes an optional single schema, validated as an identifier,
and pins search_path on each connection it opens. The claim resolver reads
the schema from the node contract's db_io entry for the table and passes it
on the binding branch. Callers that pass no schema are unchanged.
@jonahgabriel
jonahgabriel force-pushed the jonah/omn-19661-claim-store-contract-schema branch from 0754d59 to 592357b Compare September 26, 2026 00:42
onexbot-occ-writer Bot added a commit to OmniNode-ai/onex_change_control that referenced this pull request Sep 26, 2026
…nimarket#2923

The declared checks were executed for real in the OmniNode-ai/omnimarket checkout at the PR head by the product-repo OCC receipt runner, and the results written append-only into this companion. Producer-minted PENDING receipts are superseded by a net-new record; no existing receipt was edited.

Ticket: OMN-16859 (AC3b)
Onex-Workflow: OCC Receipt Runner
Onex-Run: https://github.com/OmniNode-ai/omnimarket/actions/runs/36205804235
onexbot-occ-writer Bot pushed a commit to OmniNode-ai/onex_change_control that referenced this pull request Sep 26, 2026
…2923

OCC companion by node_pr_lifecycle_fix_effect (OMN-13317 F1 / OMN-13990 / OMN-14285). Product PR head 592357b371b0927e7b0c05ec4e5b00363d2190be.
…ne cannot reach the search_path option

The Hostile Reviewer blocked on the schema reaching psycopg2's libpq
options string. The schema was validated, but _IDENTIFIER_RE.match with a
$ anchor accepts a trailing newline, so 'name\n' passed the gate. The gate
now uses fullmatch, and the options value is built by one helper that
re-validates. New refusal cases: a space, an embedded -c, a trailing
newline and a quoted name.
onexbot-occ-writer Bot added a commit to OmniNode-ai/onex_change_control that referenced this pull request Sep 26, 2026
…nimarket#2923

The declared checks were executed for real in the OmniNode-ai/omnimarket checkout at the PR head by the product-repo OCC receipt runner, and the results written append-only into this companion. Producer-minted PENDING receipts are superseded by a net-new record; no existing receipt was edited.

Ticket: OMN-16859 (AC3b)
Onex-Workflow: OCC Receipt Runner
Onex-Run: https://github.com/OmniNode-ai/omnimarket/actions/runs/36206829403
jonahgabriel pushed a commit to OmniNode-ai/onex_change_control that referenced this pull request Sep 26, 2026
…imarket#2923 (#11336)

* evidence(OMN-19661): author OCC companion for OmniNode-ai/omnimarket#2923

OCC companion by node_pr_lifecycle_fix_effect (OMN-13317 F1 / OMN-13990 / OMN-14285). Product PR head 592357b371b0927e7b0c05ec4e5b00363d2190be.

* evidence(OMN-19661): self-bind OCC#11336 + rebind contract_sha256

* evidence(OMN-16859): executed test_passes receipts for OmniNode-ai/omnimarket#2923

The declared checks were executed for real in the OmniNode-ai/omnimarket checkout at the PR head by the product-repo OCC receipt runner, and the results written append-only into this companion. Producer-minted PENDING receipts are superseded by a net-new record; no existing receipt was edited.

Ticket: OMN-16859 (AC3b)
Onex-Workflow: OCC Receipt Runner
Onex-Run: https://github.com/OmniNode-ai/omnimarket/actions/runs/36206829403

---------

Co-authored-by: omnimarket-bot <bot@omninode.ai>
Co-authored-by: onexbot-occ-writer[bot] <307849072+onexbot-occ-writer[bot]@users.noreply.github.com>
@jonahgabriel
jonahgabriel merged commit a0f4654 into dev Sep 26, 2026
159 of 166 checks passed
@jonahgabriel
jonahgabriel deleted the jonah/omn-19661-claim-store-contract-schema branch September 26, 2026 01:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants