Skip to content

fix(OMN-13141): runtime executor skips event_model import for operation_match entries - #1982

Merged
jonahgabriel merged 2 commits into
devfrom
jonah/omn-13141-executor-event-model
Jun 14, 2026
Merged

jonahgabriel merged 2 commits into
devfrom
jonah/omn-13141-executor-event-model

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Jun 14, 2026 •

Copy link
Copy Markdown
Collaborator

OMN-13141 — runtime executor skips event_model import for operation_match entries

Executor companion to OMN-13137 (#1973, merged on dev), which fixed only the validator half. This PR fixes the disjoint executor half.

Problem

RuntimeLocal._run_event_driven (src/omnibase_infra/runtime/runtime_local.py) unconditionally called importlib.import_module(entry.event_model_module) + getattr(...) for every resolved routing entry. The except clause caught only (ImportError, AttributeError).

For operation_match routing entries (e.g. node_integration_sweep_orchestrator), handler entries carry no event_model, so _resolve_routing_entries yields event_model_module="". Then importlib.import_module("") raised ValueError: Empty module name at runtime_local.py:816 — not caught by the (ImportError, AttributeError) clause, swallowed by the outer except Exception in run_async → workflow result FAILED. The node never booted end-to-end.

OMN-13137 fixed only _validate_routing (the static validation half); its test only validated the routing block, never booted through run_async(), so this path was uncovered.

Fix

Gate the importlib.import_module / getattr block on a non-empty event_model_module:

  • operation_match entries route by the operation field and declare no payload model → skip the import, wire the adapter with input_model_cls=None, and forward the raw decoded payload dict.
  • payload_type_match entries still resolve their typed event model (unchanged).

LocalRuntimeBusAdapter now accepts input_model_cls: type[BaseModel] | None; on None it forwards the raw decoded dict to the handler. No silent broadening of the except — the skip is gated explicitly on the empty-module condition. _validate_routing is left untouched (OMN-13137 owns it).

CI boot gate

tests/unit/runtime/test_run_event_driven_operation_match.py boots an operation_match contract (empty event_model) through RuntimeLocal.run_async() and asserts:

  1. no ValueError: Empty module name / result != FAILED-from-import (the bug);
  2. importlib.import_module("") is never called during operation_match wiring;
  3. payload_type_match still imports its event model (regression guard — a bad event_model module still FAILS).

This test runs in the standard CI unit job (@pytest.mark.unit, no infra markers), so it is wired as a pre-merge gate.

Verification (local, in worktree)

  • uv run ruff format src/ tests/ && uv run ruff check --fix src/ tests/ — clean
  • uv run mypy src/omnibase_infra/runtime/runtime_local.py src/omnibase_infra/runtime/runtime_local_adapter.py --strict — Success, no issues
  • uv run pytest tests/unit/runtime/ -q — 4886 passed, 5 skipped (pre-existing)
  • New e2e test: 2 fail on origin/dev (bug reproduced at L816), 3 pass with the fix
  • pre-commit run on changed files — all hooks pass (incl. union budget gate)

dod_evidence

Per contracts/OMN-13141.yaml (this PR):

  • dod-boot-e2e: uv run pytest tests/unit/runtime/test_run_event_driven_operation_match.py -q
  • dod-runtime-suite: uv run pytest tests/unit/runtime/ -q
  • dod-deploy: internal runtime-executor correctness fix; no new topics/schema/container changes; runtime restart picks it up.

OCC pairing

Paired OCC receipt PR: OmniNode-ai/onex_change_control#2620 (contract contracts/OMN-13141.yaml + PASS receipts under drift/dod_receipts/OMN-13141/; verifier receipt-gate-local ≠ runner).

Receipt Gate / DoD Gate evidence for OMN-13141:

Evidence-Source: OCC#2620
Evidence-Ticket: OMN-13141

(OCC#2620 carries contracts/OMN-13141.yaml + PASS receipts under drift/dod_receipts/OMN-13141/; infra PR head is 6d9402bbe43dc3379f4a2e72de35a60c5f0d7262.)

Closes OMN-13141. Parent: OMN-13119 (delegation chain drift). Disjoint from #1973 / OMN-13137 (Done) — touches only _run_event_driven, never _validate_routing.

Receipt re-validated against OCC#2620 head 8fc03029e (contract_sha256 added).

…on_match entries

_run_event_driven unconditionally imported entry.event_model_module for every
resolved routing entry. operation_match entries declare no event_model, so
event_model_module is empty and importlib.import_module("") raised
ValueError: Empty module name — not caught by the (ImportError, AttributeError)
clause, swallowed by the outer except in run_async -> result FAILED. The node
never booted e2e (e.g. node_integration_sweep_orchestrator).

Gate the import block on a non-empty event_model_module: operation_match routes
by the operation field and forwards the raw decoded payload (input_model_cls=None);
only payload_type_match resolves a typed event model. Mirrors the strategy-aware
validator half (OMN-13137 / #1973), which is left untouched.

Adds tests/unit/runtime/test_run_event_driven_operation_match.py — a CI boot gate
that runs an operation_match contract through RuntimeLocal.run_async() and asserts
no empty-module ValueError, plus a payload_type_match regression guard.
@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@jonahgabriel, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 3 hours, 25 minutes, and 24 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ead61846-7f25-44d1-a6b5-2a8f0ee4c4fa

📥 Commits

Reviewing files that changed from the base of the PR and between c513071 and 6d9402b.

📒 Files selected for processing (4)
  • contracts/OMN-13141.yaml
  • src/omnibase_infra/runtime/runtime_local.py
  • src/omnibase_infra/runtime/runtime_local_adapter.py
  • tests/unit/runtime/test_run_event_driven_operation_match.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jonah/omn-13141-executor-event-model

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

@jonahgabriel
jonahgabriel added this pull request to the merge queue Jun 14, 2026
Merged via the queue into dev with commit b56a3ff Jun 14, 2026
97 of 102 checks passed
@jonahgabriel
jonahgabriel deleted the jonah/omn-13141-executor-event-model branch June 14, 2026 09:31
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