Repository navigation
test(OMN-16813): gate the in-process intent-execution arm — the leg a dead-chain report misread - #2952
Conversation
…MN-16755 read as dead
The OMN-16774 Event Chain Gate asserts exactly two things: a terminal event
lands, and nothing reaches the quarantine sink. Both are statements about
DispatchResultApplier's Phase 2 (output-event publish). Neither says anything
about Phase 1 -- intent execution -- or about the IntentExecutor behind it.
That hole has already cost a day. Re-probed live on the .201 dev lane
2026-08-27, the gateway link-health chain -- recorded as a DEAD CHAIN by a
High-priority ticket (OMN-16755), a status doc, and the platform testing
inventory (verdict row 7, "the canonical wired-but-never-fires shape") --
delivers its 17,717 upserts entirely in-process:
handler -> DispatchResultApplier -> IntentExecutor -> intent effect
never over the bus. The chain was alive; every observer was blind, and blind in
the same direction, because the only leg any of them watches is the one this
chain does not use.
Why this cannot be a row in CHAIN_CASES
---------------------------------------
handler_wiring._normalize_handler_result routes a bare BaseModel return to
output_EVENTS; only ModelHandlerOutput.intents (or a ModelIntent in .result)
reaches output_intents. Every existing gate row returns a bare typed model, so
no number of appended rows reaches this leg. It needs an assertion aimed at the
effect side of the seam, which is what this module adds.
Every hop is production: EventBusInmemory, raw JSON wire bytes,
EventBusSubcontractWiring's real consumer + deserializer, _prepare_handler_wiring
arm selection, MessageDispatchEngine, the handler, DispatchResultApplier.apply,
IntentExecutor.execute_all, and a real ProtocolIntentEffect. The single patched
seam is _import_handler_class, exactly as the OMN-16774 gate patches it. Zero
infrastructure: no broker, no database, no container, no lane.
Negative control, and what it measured
--------------------------------------
test_a_dead_intent_leg_is_invisible_on_every_topic_the_gate_watches runs the
identical chain twice, differing only in whether the executor carries a handler
for the intent_type. Measured, not assumed:
- terminal topic ............. EMPTY in both runs
- quarantine sink ............ EMPTY in both runs (the ONLY sink OMN-16774 watches)
- boundary DLQ ............... EMPTY in both runs
The refusal IS raised -- IntentExecutor names the unroutable intent_type -- but
EventBusInmemory exposes no _publish_raw_to_dlq and a RuntimeHostError is
classified retryable, not exhausted, on first delivery, so the exception is
logged as "Subscriber callback failed" and never reaches the publisher. The
initial draft of this suite asserted pytest.raises around bus.publish and was
WRONG for exactly that reason; the assertions were rewritten against what the
transport actually does rather than what it was assumed to do.
So on this leg, delivered work and bus-observable state are not the same
measurement, and the effect_calls assertion is the only one in this repo that
can go red when the intent arm breaks. That is what makes it non-vacuous.
RED-first proof (not a claim -- run and captured):
register_effect default flipped to False, positive test re-run ->
E AssertionError: the intent effect was called 0 time(s), expected exactly 1.
1 failed. Reverted; 4 passed.
Two further refusals are pinned so they cannot regress into silent commits: an
unregistered intent_type, and an applier built with no executor at all (which
must refuse in Phase 1 rather than fall through and publish a terminal event
advertising a write that never happened -- a dead leg that reports success).
AC3: IntentExecutor.execute answers a None payload with a WARNING and a bare
return, no raise. That branch is UNREACHABLE from validated data --
ModelIntent.payload is required and pydantic rejects None -- and that refusal is
now asserted rather than assumed, so the guarantee cannot be relaxed by a model
edit without going red. The branch stays as defence-in-depth.
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 or absent
conclusion fails CI Summary closed. This file is collected the moment it lands.
NO runtime behavior change. The DLQ/quarantine router is owned by OMN-16798
(#2949, #2951, both landed 2026-08-27) and the inventory's section 7.2
PermissionError-swallow finding; deliberately not touched here.
Evidence: uv run pytest tests/integration/chains/ -q -> 8 passed
Evidence-Ticket: OMN-16813
|
Warning Review limit reachedNext included review available in 58 minutes. View limit detailsLimit 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. Review configuration: ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
Comment |
|
| 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)
#7353) * evidence: OCC companion pass 1 for OmniNode-ai/omnibase_infra#2952 * evidence: OCC companion self-bind for #7353 * evidence(OMN-16813): behavior-proving check, and drop the incorrect OMN-16755 binding Two corrections to the autobind output on this companion. 1. DROPPED contracts/OMN-16755.yaml and its three receipts. The autobind bound OMN-16755 because that ticket id appears in omnibase_infra#2952's prose -- the PR cites it as the SOURCE of the finding, not as work it closes. OMN-16755's own ACs are about a gateway link-health bus hop, and its premise was falsified on 2026-08-27T20:21Z (the chain routes in-process and is alive). #2952 satisfies none of them. Left in place, that contract is a live false-autoclose hazard: the evidence-autoclose sweep would have read three passing surrogates against OMN-16755 and had grounds to flip a ticket whose real work is untouched. Removing the binding is the honest state; OMN-16755 keeps its own separate disposition. 2. ADDED a BEHAVIOR-PROVING evidence item to OMN-16813. The three autobind items are all surrogates and would leave behavior_proving_count = 0: - two BYTE-IDENTICAL file-content greps (static inspection, and they grep a class NAME rather than any assertion, so they pass on a file whose tests were all deleted), - one foreign suite (tests/test_evidence_admissibility.py, this repo's own), - one bare PR-state read. None executes the chain the ticket is about. The new item runs the actual suite -- the same command the required `Event Chain Gate` CI job runs. RECEIPT IS ADVERSARIAL, runner != verifier (OMN-12791). My first attempt set both to this lane and the receipt-honesty gate correctly rejected it as SELF_ATTESTATION. The independent verifier is GitHub Actions' own required `Event Chain Gate` job 98727318636 (run 33133247111, conclusion=success) on omnibase_infra#2952, whose log is reproduced verbatim in probe_stdout: test_intent_arm_reaches_the_real_effect_handler .................... PASSED test_a_dead_intent_leg_is_invisible_on_every_topic_the_gate_watches PASSED test_missing_intent_executor_refuses_rather_than_publishing_a_terminal PASSED test_validation_is_what_keeps_the_executors_silent_drop_unreachable PASSED 8 passed in 1.22s check_value carries a `repos/OmniNode-ai/omnibase_infra/tree/<sha>` reference because commit_sha is an omnibase_infra commit and COMMIT_SHA_EXISTS cannot resolve it in this repo -- also caught by the gate on the first attempt, not assumed. Existing receipts are unaffected: contract_entry_sha256 is per-entry (OMN-13888) and authoritative when present, so appending an item does not unbind them. Verified: check_receipt_hardening.py exit 0; pre-commit clean on both files. Evidence-Ticket: OMN-16813 * evidence(OMN-16813): name the receipt for its check_type so the eligibility gate resolves it The receipt id validator_occ_merge_eligibility looks for is <ticket>:<evidence_item_id>:<check_type>, and it resolves the file by check_type name -- command.yaml for check_type: command, test_passes.yaml for check_type: test_passes. The autobind only ever emits command receipts, so the new behavior-proving item (check_type: test_passes) was written to command.yaml by pattern-matching its siblings, and the gate correctly reported: missing_or_nonpass_receipts: ["OMN-16813:dod-behavior-intent-arm-chain-gate:test_passes"] Renamed, not re-typed. Downgrading the check to check_type: command to match the filename would have made the gate pass while turning the only behavior-proving leg back into a surrogate -- which is the whole defect this item exists to fix. Content unchanged; check_receipt_hardening.py still exits 0 (contract_entry_sha256 binds the entry, not the path). Evidence-Ticket: OMN-16813 --------- Co-authored-by: node-occ-companion-effect <occ-companion-effect@omninode.ai> Co-authored-by: jonahgabriel <jonah@omninode.ai>
…ibase_infra#2952 (#7363) * evidence(OMN-16813): author OCC companion for OmniNode-ai/omnibase_infra#2952 OCC companion by node_pr_lifecycle_fix_effect (OMN-13317 F1 / OMN-13990 / OMN-14285). Product PR head fe31f58a9d60f62432f65aa5373e45a1d88098b7. * evidence(OMN-16813): self-bind OCC#7363 + rebind contract_sha256 --------- Co-authored-by: omnimarket-bot <bot@omninode.ai>
OMN-16813 — gate the in-process intent-execution arm
The
Event Chain Gate(OMN-16774) asserts exactly two things: a terminal event lands, and nothing reaches the quarantine sink (test_event_chain_gate.py:562-595). Both are statements aboutDispatchResultApplier's Phase 2. Neither says anything about Phase 1 — intent execution — or about theIntentExecutorbehind it.That hole has already cost a day. Re-probed live on the
.201dev lane 2026-08-27, the gateway link-health chain — recorded as a dead chain by a High-priority ticket (see the note above), a status document, and the platform testing inventory (docs/tracking/2026-08-27-event-chain-testing-inventory.md, verdict row 7: "the canonical wired-but-never-fires shape") — delivers its 17,717 upserts entirely in-process:never over the bus. The chain was alive; every observer was blind, and blind in the same direction, because the only leg any of them watches is the one this chain does not use.
Why this cannot be a row in
CHAIN_CASEShandler_wiring._normalize_handler_resultroutes a bareBaseModelreturn to output events; onlyModelHandlerOutput.intents(or aModelIntentin.result) reachesoutput_intents. Every existing gate row returns a bare typed model, so no number of appended rows reaches this leg. It needs an assertion aimed at the effect side of the seam.What is real
EventBusInmemory, raw JSON wire bytes,EventBusSubcontractWiring's real consumer + deserializer,_prepare_handler_wiringarm selection,MessageDispatchEngine, the handler,DispatchResultApplier.apply,IntentExecutor.execute_all, and a realProtocolIntentEffect. The single patched seam is_import_handler_class, exactly as the OMN-16774 gate patches it. Zero infrastructure: no broker, no database, no container, no lane.Negative control — and what it actually measured
test_a_dead_intent_leg_is_invisible_on_every_topic_the_gate_watchesruns the identical chain twice, differing only in whether the executor carries a handler for theintent_type. Measured, not assumed:get_dlq_topic_for_original, resolved not hardcoded)The refusal is raised —
IntentExecutornames the unroutableintent_type— butEventBusInmemoryexposes no_publish_raw_to_dlqand aRuntimeHostErroris classified retryable, not exhausted, on first delivery, so the exception is logged asSubscriber callback failedand never reaches the publisher.Correction recorded rather than hidden: the first draft of this suite asserted
pytest.raisesaroundbus.publishand was wrong for exactly that reason. The assertions were rewritten against what the transport actually does. This is why the negative control exists — it caught my own bad assumption before review did.So on this leg, delivered work and bus-observable state are not the same measurement, and the
effect_callsassertion is the only one in this repo that can go red when the intent arm breaks.RED-first proof (run and captured, not claimed)
register_effectdefault flipped toFalse, positive test re-run:Reverted →
4 passed. The break is committed as an assertion, never as a broken chain row.Two further refusals pinned
intent_type, andAC3 — the one branch that does not refuse
IntentExecutor.executeanswers aNonepayload with a WARNING and a barereturn. That branch is unreachable from validated data (ModelIntent.payloadis required; pydantic rejectsNone), and that refusal is now asserted rather than assumed, so the guarantee cannot be relaxed by a model edit without going red.Enforcement, not detection (rule 5)
No workflow edit. The
Event Chain Gatejob already runsuv run pytest tests/integration/chains/wholesale and is registered inscripts/ci/ci_summary_gate.py::STRICT_GATE_JOBS, so askipped/absent conclusion failsCI Summaryclosed.CI Summaryisdev's only required check. This file is collected the moment it lands.Non-goals
No runtime behavior change. The DLQ/quarantine router is owned by OMN-16798 (#2949, #2951, both landed 2026-08-27) and the inventory's §7.2
PermissionError-swallow finding — deliberately not touched here to avoid colliding with a concurrent lane.Residual observed while pushing
The governed pre-push selector reported
deferred to CI (integration needs live services; this hook is unit-scoped): [tests/integration/chains/]. This suite needs no live service — the selector's directory heuristic treats all oftests/integration/as service-dependent. Not a blocker (the dedicated CI job runs it), but it is the same "the check exists but does not observe this" shape this PR is about. Recorded, not fixed here.Acceptance criteria
Evidence:
uv run pytest tests/integration/chains/ -q→ 8 passedEvidence-Ticket: OMN-16813
Evidence-Source: OCC#7363