Skip to content

feat(OMN-19968): the tenant credentials writer runs on the local SQLite store - #3210

Merged
Patel230 merged 6 commits into
devfrom
lakshman/OMN-19968-tenant-credentials-sqlite
Oct 2, 2026
Merged

Patel230 merged 6 commits into
devfrom
lakshman/OMN-19968-tenant-credentials-sqlite

Conversation

@Patel230

@Patel230 Patel230 commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Gives node_projection_tenant_credentials a SQLite path. It was the last writer named in OMN-19968 without one. This closes Jonah's 09-30 closeout hold on AC1 ("for each writer") by its first option, "land that writer under this ticket".

Before this change, the writer's three writes were asyncpg SQL with $n, ::TEXT and NOW(), and the local SQLite schema had neither of its tables.

What changed

  • New handlers/handler_tenant_credentials_store.py. apply_credential_registered and apply_credential_revoked write the catalog row and the routing overlay through the store-neutral upsert_returning, which both the SQLite adapter and the Postgres sync adapter implement. They keep every rule the runner's SQL encodes:
    • a register never touches created_at or revoked_at;
    • a route is minted only for a key that is not revoked;
    • a revoke keeps the earliest revoked_at, and leaves a tombstone for an unknown key;
    • a revoke blanks only the route that points at that key;
    • an undeclared provider is catalogued but left unrouted.
  • The deployed asyncpg runner is unchanged.
  • projection/sqlite_database.py. Adds tenant_inference_credentials and delegation_routing_tenant_overlay, derived from the node's migrations 0000/0001 and the overlay's 0001/0004.
  • contract.yaml. Both tables now declare access: read_write instead of write. The projection contract-access gate (OMN-16690) requires this, because the store path reads before a revoke, and the runner itself already reads both tables (the overlay's WHERE NOT EXISTS revoke guard and every RETURNING).
    • The checked-in relation inventory (OMN-15423) is regenerated: the overlay table gains this node as a reader.
    • The OMN-17372 contract-shape test now pins that the overlay write is declared (write or read_write).
  • Tests. tests/test_omn19968_writer_store_parity.py compares six scenarios between the SQLite store path and the real asyncpg runner on PostgreSQL: register, register twice, register then revoke, revoke before register, undeclared provider, and re-register with a new ref. It also checks the SQLite path for Postgres-only tokens, and checks the tombstone, revoke and secret-field rules on SQLite alone.

How it was verified

Lab first. tests/test_omn19968_writer_store_parity.py ran on the lakshman lab lane's PostgreSQL 16 on .201, in a throwaway container from the lane's runtime image, against the final tree 159f31fc5 (2026-10-01T20:38:25Z):

  • 21 passed, including all 6 SQLite-versus-real-runner cases and all 9 SQLite-only cases.
  • The 2 failures are the pre-existing delegation_events and llm_call_metrics cases (invalid input value for enum usage_source_type: "MISSING"). That is the defect omnimarket#3183 fixes; this branch is cut from dev without it.

Checks:

  • Check 1 (own tests RED, then GREEN). Before the change the new tests could not import the store path (ModuleNotFoundError). After it, they give 9 passed locally; the 6 runner cases skip here because no local database runs.
  • Check 2 (mutation). I disabled the revoked-key guard before minting a route; test_tenant_credentials_sqlite_tombstone_blocks_the_route went RED (a route was minted for a revoked key). Restored, it went GREEN.
  • Check 3 (related suites, dev vs branch). 48 related test files: dev 2211ff939 gives 606 passed, 31 skipped; the branch gives 615 passed, 37 skipped. The difference is the 9 new tests and 6 new skips.
  • mypy --strict on changed source, ruff check, ruff format --check, the runtime sweep import check, and the node metadata dependency check all pass.

Overlap-Reviewed: #3183 — both touch src/omnimarket/projection/sqlite_database.py and tests/test_omn19968_writer_store_parity.py; #3183 (mine, same ticket) changes the llm_call_metrics DDL default and adds usage-source vocabulary cases, this adds two new tables and the tenant-credentials cases. A trial three-way merge (git merge-tree) of both heads is clean; each is needed and they merge in either order.

Overlap-Reviewed: #3172 — both touch docs/evidence/OMN-15423-relation-inventory.json; #3172 (mine, OMN-19969) changes a different relation's entry, this adds this node as a reader of delegation_routing_tenant_overlay. A trial three-way merge of both heads is clean; whichever lands second re-runs the generator's --check in CI.

Failure paths

n/a: this change writes no verdict, receipt or report. It is a store path, two local schemas and tests.

Open defects

none

Local gates

  • No gate was bypassed — no --no-verify, no SKIP=, no --no-gpg-sign, no core.hooksPath override. Every pre-commit and pre-push hook ran.
  • Any hook that failed was fixed at the input, not worked around. The canonical-file-shape ratchet refused three # noqa: E402, so the imports moved to the top of the file. The contract-access gate refused access: write with reads, so the declaration now says read_write.

Not in this change

  • omnimarket#3183 (the llm-cost vocabulary fix) and its vendored migration, omnibase_infra#4420.
  • Wiring the local runtime to call the store path. That is OMN-19985's runtime work.
  • Any change to the deployed runner's SQL.
  • Moving these tables out of public (OMN-15359).

Evidence-Ticket: OMN-19968
Evidence-Source: OCC#12224

…te store

node_projection_tenant_credentials was the last writer the ticket names with
no SQLite path: its three writes were asyncpg SQL with $n, ::TEXT and NOW(),
and the local schema had neither of its tables.

- handlers/handler_tenant_credentials_store.py: apply_credential_registered and
  apply_credential_revoked write the catalog row and the routing overlay
  through the store-neutral upsert_returning, keeping every rule the runner's
  SQL encodes: register never touches created_at or revoked_at, the route is
  minted only for a key that is not revoked, a revoke keeps the earliest
  revoked_at and leaves a tombstone for an unknown key, a revoke blanks only
  the route that points at that key, and an undeclared provider is catalogued
  but unrouted. The deployed asyncpg runner is unchanged.
- projection/sqlite_database.py: tenant_inference_credentials and
  delegation_routing_tenant_overlay, declared from the node migrations
  0000/0001 and the overlay migrations 0001/0004.
- contract.yaml: both tables declare access read_write instead of write.
  The runner already reads them (the overlay's WHERE NOT EXISTS revoke guard
  and every RETURNING) and the local path reads before a revoke; the
  projection contract-access gate requires the declaration to say so. The
  checked-in relation inventory is regenerated (the overlay gains this node
  as a reader), and the OMN-17372 contract-shape test now pins that the
  overlay write is declared, as write or read_write.
- tests/test_omn19968_writer_store_parity.py: six scenarios compared between
  the SQLite store path and the REAL asyncpg runner on PostgreSQL, the SQLite
  path checked for Postgres-only tokens, and the tombstone, revoke and
  secret-field rules on SQLite alone.
@github-actions

github-actions Bot commented Oct 1, 2026

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).

@github-actions

github-actions Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

✅ Hostile Reviewer — PASSED

Blocking findings (critical/error): 0
Total findings: 15
Models succeeded: qwen3-review,gpt-oss-review


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)

onexbot-occ-writer Bot pushed a commit to OmniNode-ai/onex_change_control that referenced this pull request Oct 1, 2026
…omnimarket#3210

OCC companion by node_pr_lifecycle_fix_effect (OMN-13317 F1 / OMN-13990 / OMN-14285). Product PR head 159f31fc58fe81180060743542a4551da24abf38.
onexbot-occ-writer Bot added a commit to OmniNode-ai/onex_change_control that referenced this pull request Oct 1, 2026
…nimarket#3210

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/36931740454
jonahgabriel added a commit to OmniNode-ai/onex_change_control that referenced this pull request Oct 1, 2026
…market (#12224)

* evidence(OMN-19968, OMN-20001): author OCC companion for OmniNode-ai/omnimarket#3210

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

* evidence(OMN-19968, OMN-20001): self-bind OCC#12224 + rebind contract_sha256

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

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/36930151590

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

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/36931740454

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

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/36930788697

---------

Co-authored-by: omnimarket-bot <bot@omninode.ai>
Co-authored-by: onexbot-occ-writer[bot] <307849072+onexbot-occ-writer[bot]@users.noreply.github.com>
Co-authored-by: jonahgabriel <jonah.gabriel@gmail.com>
omnimarket#3208 gave ProtocolProjectionRowSource a `selection` on rows() and a
walk_origin(); #3212 landed SqliteTableRowSource four minutes later without
either. On dev every read_page call against the local store raised TypeError
(5 of 11 OMN-20329 tests fail) and mypy rejects handler_projection_read.py:99.

- rows() takes `selection`: "walk" windows from the first cursor ascending,
  "ranked" windows by the contract's order, "newest" is unchanged.
- walk_origin() answers one below the tenant's smallest integer cursor, None
  for any other cursor, and refuses a missing table or store by name.
The release identity gate refuses a packaged-source change on an already
published version. 0.4.277 is published; this PR changes packaged source.
dev's #3216 landed its own selection/walk_origin fix in sqlite_row_source.py;
take dev's version of that file. The walk-protocol tests from b944255 pass
against it.
@Patel230
Patel230 merged commit 6fb2b45 into dev Oct 2, 2026
149 checks passed
@Patel230
Patel230 deleted the lakshman/OMN-19968-tenant-credentials-sqlite branch October 2, 2026 16:52
@Patel230

Patel230 commented Oct 3, 2026

Copy link
Copy Markdown
Contributor Author

No reviews or inline comments were left here. The two bot notes passed (architecture lint with 0 errors; the hostile reviewer with 0 blocking findings), so nothing needed a change.

Merged as 6fb2b45 on 2026-10-02: the tenant credentials writer now has a SQLite store path, its two local tables and read-write access in the contract. Per the PR body, 21 parity tests passed against real PostgreSQL; the 2 failures it lists are the llm-cost enum defect that omnimarket#3183 fixes. By the 2026-10-02 ruling on OMN-19968, tenant-credentials parity now sits with OMN-19985 AC4.

Thank you!

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.

1 participant