Skip to content

test(OMN-16814): drive the projection capability seam through a real chain - #2953

Merged
github-actions[bot] merged 1 commit into
devfrom
jonah/omn-16814-projection-capability-chain-gate
Aug 28, 2026
Merged

github-actions[bot] merged 1 commit into
devfrom
jonah/omn-16814-projection-capability-chain-gate

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Aug 28, 2026 •

Copy link
Copy Markdown
Collaborator

OMN-16814 — drive the projection capability seam through a real chain

OMN-16690: node_hook_event_capture/contract.yaml declared access: write while its handler called db.query(). The runtime read seam refused, the projection arm swallowed the PermissionError and DLQ'd the event, callers kept seeing 202, and the quarantine sink reached HWM 8,878,932. It ran about a week behind green CI.

The platform testing inventory (§7.1) names why nothing caught it:

The golden-chain DB double carries no capability enforcement. […] So the golden chain test passed, on every PR, while the live chain DLQ'd every single event. This is not a gap in coverage — it is a gap in fidelity, and it makes a contract/handler capability mismatch invisible to all 194 golden-chain tests by construction.

That is equally true in this repo: tests/integration/runtime/test_projection_handler_db_injection_integration.py injects a FakeDb through _build_projection_db_adapter whose upsert/query do no access checking, so it is green for every declared access value.

omnimarket#2164 closed the statically-visible half. It cannot see a read reached through a helper, a base class, or an adapter — and nothing anywhere proved the runtime refusal is still wired, or that a mismatch turns a whole chain red.

Where the seam boundary is drawn

_assert_read_declared / _assert_write_declared both fire before the adapter touches a connection, so the whole capability decision is reachable with zero DB contact.

Real: _prepare_handler_wiring arm selection · _make_projection_dispatch_callback · _build_projection_db_adapter · ProjectionDatabaseOperations domain routing · ProjectionTableOperation assertions and SQL construction.
Substituted: the psycopg2 driver only, via sys.modules — the technique test_sync_psycopg2_adapter_preserves_text_array_lists already uses here. Substituting the adapter object is the fidelity gap being closed; please don't "simplify" this file back into that.

The matrix — both directions

declared access handler op outcome
read_write query terminal emitted, SQL executed
read_write upsert terminal emitted, SQL executed
write query REFUSED — the OMN-16690 shape
read upsert REFUSED — mirror image

Only access varies. Same handler, same wiring, same wire bytes, same table — so any divergence is attributable to the capability seam and nothing else. A one-sided fixture could pass by accident, which is why both directions are present (AC4).

Each refused row asserts three facts, because any one alone is weak:

  1. no terminal event — the chain does not report success (the half the live outage got wrong at the HTTP boundary);
  2. the event reaches the contract-declared DLQ carrying the PermissionError — bus-observable, not log-only; log-only detection is what let the live defect run a week;
  3. zero SQL constructed — the refusal precedes statement construction, so it is a gate, not a late check.

RED-first proof — and the assertion it corrected

Stubbing both production assertions to lambda self: None does not make the PermissionError disappear. The chain then fails a second, independent refusal:

PermissionError: Projection operation has no declared workload binding

because a write-declared table has no read binding to resolve either.

So an assertion of the form "PermissionError" in dlq_text stays GREEN with the capability seam switched off, and would gate nothing. Asserting the seam's own wording is what makes these rows non-vacuous. Measured, then recorded at the assertion site so nobody relaxes it later:

neutered  ->  2 failed, 3 passed   (both refused rows RED, on that line only)
restored  ->  9 passed             (whole tests/integration/chains/ suite)

AC3 also anchors by importing ProjectionTableOperation and asserting both refusal methods exist on the production class. omnimarket/.../test_projection_live_events.py:38 re-implements access not in {"read", "read_write"} and asserts its own copy — it was green throughout the outage, because a mirror of a rule cannot tell you the rule is still wired.

Two fixture facts that are load-bearing, both found by measurement

  1. The table is projection_watermarks, a real table from the shipped local topology. A fabricated name cannot reach the capability seam at all — _require_projection_binding_privileges rejects it three layers earlier, and the only sanctioned grant-synthesis helper refuses for already-shipped tables. A fabricated row would have proven nothing about access.
  2. The contract must set terminal_event and list it in publish_topics (handler_wiring.py:8486-8492) or the arm emits no terminal — which would make a positive row's observation identical to a refused row's, i.e. vacuous.

Both are recorded as comments at the point of use, and the harness carries explicit precondition assertions so a future core pin that parses db_io or access away fails loudly rather than banking a free green.

Enforcement, not detection (rule 5)

No workflow edit. The Event Chain Gate job already runs uv run pytest tests/integration/chains/ wholesale and is registered in scripts/ci/ci_summary_gate.py::STRICT_GATE_JOBS, so a skipped/absent conclusion fails CI Summary closed. CI Summary is dev's only required check.

Non-goals

No runtime behavior change. In particular this does not implement inventory §7.2 — that a PermissionError from the access seam is a contract defect and should fail the consumer loudly rather than DLQ every event forever. That finding is correct, but the quarantine router is owned by OMN-16798 (#2949, #2951, landed 2026-08-27). This suite pins the current behavior instead, so that change is a visible diff when someone makes it rather than a silent one.

Acceptance criteria

  • AC1 — real ProjectionTableOperation, chain terminalizes when access admits: MET
  • AC2 — negative control proven detectable, committed as a passing assertion: MET (RED proof above)
  • AC3 — anchored to the seam's own refusal, not a mirror: MET (and the RED proof shows why the weaker form fails)
  • AC4 — both directions covered: MET
  • AC5 — inside the already-required gate, no workflow edit: MET
  • AC6 — zero infrastructure: MET

Related: #2952 (OMN-16813) is the sibling chain surface from the same inventory — separate files, no overlap.

Evidence: uv run pytest tests/integration/chains/ -q → 9 passed

Evidence-Ticket: OMN-16814
Evidence-Source: OCC#7357

…chain

OMN-16690: node_hook_event_capture/contract.yaml declared access='write' while
its handler called db.query(). The runtime read seam refused, the projection arm
swallowed the PermissionError and DLQ'd the event, callers kept seeing 202, and
the quarantine sink reached HWM 8,878,932. It ran about a week behind green CI.

The platform testing inventory names why nothing caught it (section 7.1): the
golden-chain DB double carries NO capability enforcement, so a contract/handler
capability mismatch is invisible to all 194 golden chains BY CONSTRUCTION. That
is equally true in THIS repo --
tests/integration/runtime/test_projection_handler_db_injection_integration.py
injects a FakeDb through _build_projection_db_adapter whose upsert/query do no
access checking, so it is green for every declared access value.

omnimarket#2164 closed the statically-visible half (a handler that TEXTUALLY
calls db.query() must declare read_write). It cannot see a read reached through
a helper, a base class or an adapter, and nothing anywhere proved the RUNTIME
refusal is still wired or that a mismatch turns a whole CHAIN red.

Where the seam boundary is drawn
--------------------------------
_assert_read_declared / _assert_write_declared both fire BEFORE the adapter
touches a connection, so the whole capability decision is reachable with zero DB
contact. Real here: _prepare_handler_wiring arm selection,
_make_projection_dispatch_callback, _build_projection_db_adapter,
ProjectionDatabaseOperations domain routing, and ProjectionTableOperation's
assertions and SQL construction. Substituted: the psycopg2 DRIVER only, via
sys.modules -- the technique test_sync_psycopg2_adapter_preserves_text_array_lists
already uses here. Substituting the adapter OBJECT is the fidelity gap being
closed; do not "simplify" this file back into that.

The matrix, both directions (a one-sided fixture can pass by accident):

  read_write declared + query  -> terminal emitted, SQL executed
  read_write declared + upsert -> terminal emitted, SQL executed
  write declared + query       -> REFUSED (the OMN-16690 shape)
  read declared + upsert       -> REFUSED (mirror image)

Only `access` varies across the four rows. Same handler, same wiring, same wire
bytes, same table -- so any divergence is attributable to the capability seam and
to nothing else.

Each refused row asserts THREE separate facts, because any one alone is weak:
no terminal event (the chain does not report success -- the half the live outage
got wrong at the HTTP boundary); the event reaches the contract-declared DLQ
carrying the PermissionError (bus-observable, not log-only -- log-only detection
is what let the live defect run a week); and ZERO SQL was constructed (the
refusal precedes statement construction, so it is a gate and not a late check).

Two fixture facts that are load-bearing, both found by measurement
-----------------------------------------------------------------
1. The table is projection_watermarks, a REAL table from the shipped local
   topology. A fabricated name cannot reach the capability seam at all:
   _require_projection_binding_privileges rejects it three layers earlier, and
   the only sanctioned grant-synthesis helper refuses for already-shipped tables.
   A fabricated row would have proven nothing about access.
2. The contract must set terminal_event AND list it in publish_topics
   (handler_wiring.py:8486-8492) or the arm emits no terminal -- which would make
   a positive row's observation identical to a refused row's, i.e. vacuous.

RED-first proof, and what it corrected
--------------------------------------
Stubbing BOTH production assertions to `lambda self: None` does NOT make the
PermissionError disappear -- the chain then fails a SECOND, independent refusal
("Projection operation has no declared workload binding"), because a
write-declared table has no read binding to resolve either.

So an assertion of the form `"PermissionError" in dlq_text` STAYS GREEN with the
capability seam switched off and would gate nothing. Asserting the seam's OWN
WORDING is what makes these rows non-vacuous. Measured, then recorded at the
assertion:

  neutered  -> 2 failed, 3 passed  (both refused rows RED, on that line only)
  restored  -> 9 passed            (whole tests/integration/chains/ suite)

AC3 also anchors by importing ProjectionTableOperation and asserting both refusal
methods exist on the production class. omnimarket's
node_projection_live_events/tests/test_projection_live_events.py:38 re-implements
`access not in {"read","read_write"}` and asserts its own copy -- it was green
throughout the outage, because a mirror of a rule cannot tell you the rule is
still wired.

Enforcement, not detection (rule 5): no workflow edit. The Event Chain Gate job
already runs `uv run pytest tests/integration/chains/` wholesale and is
registered in ci_summary_gate.py::STRICT_GATE_JOBS, so a skipped/absent
conclusion fails CI Summary closed.

NO runtime behavior change. In particular this does NOT implement inventory
section 7.2 (a PermissionError from the access seam is a CONTRACT defect and
should fail the consumer loudly rather than DLQ every event forever). That
finding is correct; the quarantine router is owned by OMN-16798 (#2949, #2951,
landed 2026-08-27), so this suite PINS the current behavior instead, making that
change a visible diff when someone makes it rather than a silent one.

Evidence: uv run pytest tests/integration/chains/ -q -> 9 passed
Evidence-Ticket: OMN-16814
@coderabbitai

coderabbitai Bot commented Aug 28, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 21 minutes.

View limit details

Limit details: You’ve used the included review currently available. Your 131 included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7623babb-4663-49b2-93e4-8a3af53123da

📥 Commits

Reviewing files that changed from the base of the PR and between 4529c34 and 62c2264.

📒 Files selected for processing (1)
  • tests/integration/chains/test_projection_capability_chain_gate.py

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Hostile Reviewer — DEGRADED (informational)

Blocking findings (critical): 0
Total findings: 0
Models succeeded: none

Note: All reviewer models failed or were unavailable. Degraded results are informational during the pilot phase (OMN-8468/OMN-8524) and do not block merge. Error: all review endpoints [192.168.86.201:8000 192.168.86.201:8000 ] unreachable — preflight short-circuit (no models available)


Gate semantics (pilot phase)

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 — multi-model adversarial review (OMN-8468/OMN-8524)

jonahgabriel pushed a commit to OmniNode-ai/onex_change_control that referenced this pull request Aug 28, 2026
#7357)

* evidence: OCC companion pass 1 for OmniNode-ai/omnibase_infra#2953

* evidence: OCC companion self-bind for #7357

---------

Co-authored-by: node-occ-companion-effect <occ-companion-effect@omninode.ai>
@github-actions
github-actions Bot merged commit 6f694fb into dev Aug 28, 2026
163 of 174 checks passed
@github-actions
github-actions Bot deleted the jonah/omn-16814-projection-capability-chain-gate branch August 28, 2026 02:24
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