Skip to content

chore(release)(OMN-12245): backmerge omnimarket v0.4.3 version bump to dev - #1070

Merged
jonahgabriel merged 3 commits into
devfrom
hotfix/omn-12245-release-omnimarket-v0.4.3
Jun 6, 2026
Merged

jonahgabriel merged 3 commits into
devfrom
hotfix/omn-12245-release-omnimarket-v0.4.3

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Jun 6, 2026 •

Copy link
Copy Markdown
Contributor

Evidence-Ticket: OMN-12245
Evidence-Source: OCC#2231

Backmerge companion for main release-version PR #1069 so dev retains the v0.4.3 release metadata after main release publication.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added trace CLI command for querying and monitoring ONEX event-bus logs with filtering, aggregation, and real-time watch capabilities.
    • Multiple new orchestrator nodes for handling adversarial pipelines, epic decomposition, decision store management, and contract validation.
    • Golden chain coverage enforcement gate in CI and pre-commit workflows.
    • Contract drift detection for identifying topic declaration mismatches.
    • Delegation workflow enhancements with automatic tier escalation on quality gate failures.
    • Checkpoint persistence compute node for managing state snapshots.
  • Improvements

    • Fixed projection API UUID serialization error.
    • Enhanced quality gate validation with improved code block parsing and artifact-only checks.
    • Better LLM context window resolution from centralized registry.
    • Expanded LLM backend support (Gemini, OpenRouter, local models).
  • Configuration

    • Updated delegation routing tiers and model registry.

@github-advanced-security github-advanced-security AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CodeQL found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

@coderabbitai

coderabbitai Bot commented Jun 6, 2026 •

Copy link
Copy Markdown

Review Change Stack

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 1 minute and 5 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ 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: 9de4d8ca-b06d-49ad-9119-5e8f17b77116

📥 Commits

Reviewing files that changed from the base of the PR and between b560d9f and 4916272.

📒 Files selected for processing (7)
  • docs/evidence/dep-health-sweep/proof-of-life-001/projection_rows.json
  • pyproject.toml
  • src/omnimarket/nodes/node_context_experiment_compute/handlers/__init__.py
  • src/omnimarket/nodes/node_context_experiment_compute/handlers/handler_context_experiment.py
  • src/omnimarket/nodes/node_context_experiment_compute/models/__init__.py
  • src/omnimarket/nodes/node_context_experiment_compute/models/model_context_experiment_request.py
  • src/omnimarket/nodes/node_context_experiment_compute/models/model_context_experiment_result.py
📝 Walkthrough

Walkthrough

This PR updates CI and pre-commit enforcement, expands delegation and runtime contract handling, adds shared event and wire models, introduces multiple new node packages and CLI features, refreshes routing/model configuration, and records related work-tracking and evidence artifacts.

Changes

Runtime contracts and node expansion

Layer / File(s) Summary
CI validation and repository gates
.github/workflows/*, .pre-commit-config.yaml, scripts/ci/*, scripts/validate_node_drift.py, scripts/validation/unimported_handler_baseline.txt
CI adds golden-chain coverage, orphan-node enforcement, runtime import checks, SEA end-to-end chains, and a PR target guard, with matching pre-commit and validation script updates.
Delegation and runtime dispatch contracts
src/omnimarket/adapters/codex/*, src/omnimarket/models/delegation/wire/*, src/omnimarket/nodes/node_delegate_skill_orchestrator/*, src/omnimarket/nodes/node_delegation_orchestrator/*, src/omnimarket/nodes/node_delegation_quality_gate_reducer/*, src/omnimarket/nodes/node_delegation_routing_feedback_reducer/*
Runtime routing now resolves contract-defined topics and payload models, delegation wire DTOs move to canonical shared imports, quality-gate handling changes, escalation is added to the delegation FSM, and routing feedback reduction is introduced.
Shared models, new nodes, and app features
src/omnimarket/events/*, src/omnimarket/nodes/evidence_pipeline_native.py, src/omnimarket/nodes/node_*, src/omnimarket/cli/commands/trace.py, src/omnimarket/cli/market.py, scripts/audit/market_node_runtime_dogfood.py
The repo adds shared event contracts, a native evidence pipeline, multiple new node packages and handlers, a trace CLI command group, and a runtime dogfood audit script.
Configuration, manifests, and registry updates
pyproject.toml, src/omnimarket/configs/*, src/omnimarket/data/model_registry/model_registry_v1.yaml, src/omnimarket/inference/*, src/dep_health_allowlist.yaml
Package metadata, node entry points, delegation backends, routing tiers, task contracts, model registry data, context-window lookup, and topic allowlists are updated together.
Docs, skills, tests, and evidence artifacts
docs/work-tracking/contracts/*, plugins/onex/skills/*, src/omnimarket/adapters/codex/skills/*, docs/evidence/dep-health-sweep/..., .onex_state/dep_health_baseline.json, merge-sweep/*, tests/...
The PR adds work-tracking contracts, skill documentation, expanded golden-chain and unit tests, refreshed dependency-health evidence, updated baseline findings, and merge-sweep result artifacts.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • OmniNode-ai/omnimarket#1044: Overlaps on scripts/validate_node_drift.py, scripts/ci/run_runtime_sweep.py, scripts/ci/check_unimported_handlers.py, and matching workflow/pre-commit wiring.
  • OmniNode-ai/omnimarket#1041: Also changes node_delegate_skill_orchestrator contract-driven runtime delegation dispatch configuration and loader usage.
  • OmniNode-ai/omnimarket#1032: Shares the delegation DTO migration from local omnimarket imports to omnibase_core.models.delegation.wire.

Poem

🐇 I thumped through gates of gold,
And wired new trails for tales untold.
With topics hopped and contracts neat,
New nodes now twitch on busy feet.
I stash bright proofs in burrows deep—
Then curl up proud, and dream of sweep.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch hotfix/omn-12245-release-omnimarket-v0.4.3

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Note

Due to the large number of review comments, Critical severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
src/omnimarket/nodes/node_delegation_quality_gate_reducer/handlers/handler_quality_gate.py (1)

137-154: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Non-Python fenced blocks can cause false deterministic failures.

Lines 202–207 parse every fenced block as Python regardless of fence language. Mixed outputs containing ```json or ```bash can fail compiles_without_errors even when Python artifact blocks are valid.

♻️ Suggested parser narrowing
-_MARKDOWN_FENCE_RE = re.compile(r"```(?:\w+)?\n(.*?)```", re.DOTALL)
+_MARKDOWN_FENCE_RE = re.compile(r"```(?P<lang>\w+)?\n(?P<body>.*?)```", re.DOTALL)

-def _extract_fenced_code_blocks(content: str) -> list[str]:
-    """Return all fenced code block bodies from mixed content."""
-    return _MARKDOWN_FENCE_RE.findall(content)
+def _extract_fenced_code_blocks(content: str) -> list[tuple[str, str]]:
+    """Return (lang, body) tuples for fenced code blocks."""
+    out: list[tuple[str, str]] = []
+    for m in _MARKDOWN_FENCE_RE.finditer(content):
+        out.append(((m.group("lang") or "").lower(), m.group("body")))
+    return out
@@
-    blocks = _extract_fenced_code_blocks(content)
-    candidates = blocks if blocks else [_strip_markdown_code_fence(content)]
+    blocks = _extract_fenced_code_blocks(content)
+    py_blocks = [body for lang, body in blocks if lang in ("", "py", "python")]
+    candidates = py_blocks if py_blocks else [_strip_markdown_code_fence(content)]

Also applies to: 195-209

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/omnimarket/nodes/node_delegation_quality_gate_reducer/handlers/handler_quality_gate.py`
around lines 137 - 154, The current regex and extractor treat all fenced blocks
as Python which causes non-Python blocks (e.g., ```json```, ```bash```) to be
tested; update _MARKDOWN_FENCE_RE to capture a named lang group and body (e.g.,
r"```(?P<lang>\w+)?\n(?P<body>.*?)```", re.DOTALL), change
_extract_fenced_code_blocks to return list[tuple[str,str]] of (lang, body) using
finditer and .group("lang")/.group("body"), and then when building candidates
filter blocks to only Python-friendly fences (lang in ("", "py", "python"))
producing py_blocks and falling back to _strip_markdown_code_fence(content) if
none.
src/omnimarket/adapters/claude_code/delegate.py (1)

136-152: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Align max_tokens defaults across all public entry points.

Line 136 now uses DELEGATION_DEFAULT_MAX_TOKENS, but Line 252 and Line 290 still hardcode 2048. Programmatic callers of compile_request()/dispatch_sync() can now diverge from CLI and wire defaults.

Suggested patch
@@
-        max_tokens: int = 2048,
+        max_tokens: int = DELEGATION_DEFAULT_MAX_TOKENS,
@@
-        max_tokens: int = 2048,
+        max_tokens: int = DELEGATION_DEFAULT_MAX_TOKENS,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnimarket/adapters/claude_code/delegate.py` around lines 136 - 152,
Defaults for max_tokens are inconsistent: replace the hardcoded 2048 values used
in compile_request and dispatch_sync with the declared
DELEGATION_DEFAULT_MAX_TOKENS constant so all public entry points share the same
default; update the parameters/signatures in compile_request and dispatch_sync
to use DELEGATION_DEFAULT_MAX_TOKENS (and remove any literal 2048 in their
bodies), ensure the constant is imported/available in delegate.py, and run tests
to verify behavior remains unchanged.
src/omnimarket/nodes/node_delegation_orchestrator/plugin.py (1)

202-239: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Remove the service_registry hard gate from deferred dispatcher wiring.

With dispatcher wiring now deferred, this method still returns skipped when service_registry is absent, which leaves _dispatcher_wiring_succeeded false and prevents start_consumers() from running in no-registry environments even though that path already has fallback logic.

💡 Proposed fix
     async def wire_dispatchers(
         self,
         config: ModelDomainPluginConfig,
     ) -> ModelDomainPluginResult:
         """Defer dispatcher route registration to contract auto-wiring."""
         start_time = time.time()

-        if config.container.service_registry is None:
-            logger.warning(
-                "DEGRADED_MODE: ServiceRegistry not available, skipping "
-                "delegation dispatcher wiring (correlation_id=%s)",
-                config.correlation_id,
-            )
-            return ModelDomainPluginResult.skipped(
-                plugin_id=self.plugin_id,
-                reason="ServiceRegistry not available",
-            )
-
         if config.dispatch_engine is None:
             logger.warning(
                 "DEGRADED_MODE: dispatch_engine not available, skipping "
                 "delegation dispatcher wiring (correlation_id=%s)",
                 config.correlation_id,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnimarket/nodes/node_delegation_orchestrator/plugin.py` around lines 202
- 239, Remove the hard gate that returns skipped when
config.container.service_registry is None so deferred dispatcher wiring does not
block start_consumers(); specifically, delete or bypass the block that checks
config.container.service_registry and returns ModelDomainPluginResult.skipped,
but keep the existing dispatch_engine check; if service_registry is None, emit a
warning log about degraded mode (as currently done) yet continue to set
self._dispatcher_wiring_succeeded = True, compute duration, log the
deferred-wiring info, and return a successful ModelDomainPluginResult (same
shape as the existing success return) so start_consumers() can run in
no-registry environments.
src/omnimarket/nodes/node_contract_registry/handlers/handler_contract_registry.py (1)

90-97: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Validate top-level handler.module against the allowlist before adapter derivation.

The allowlist check currently inspects only handler_routing.handlers[].handler.module, but adapter derivation prioritizes top-level handler.module. A contract can bypass allowlist enforcement and still publish an adapted handler class.

🔧 Suggested fix
-        handler_routing = parsed.get("handler_routing", {})
-        handlers = handler_routing.get("handlers", [])
-        for entry in handlers:
-            handler = entry.get("handler", {}) if isinstance(entry, dict) else {}
-            module = handler.get("module", "") or entry.get("handler_module", "")
-            if module and not any(
-                module.startswith(p) for p in ALLOWED_HANDLER_PREFIXES
-            ):
-                return self._reject(
-                    request, EnumMaterializationRejection.HANDLER_ALLOWLIST
-                )
+        modules_to_check: list[str] = []
+        top_handler = parsed.get("handler")
+        if isinstance(top_handler, dict):
+            top_module = top_handler.get("module")
+            if isinstance(top_module, str) and top_module:
+                modules_to_check.append(top_module)
+
+        handler_routing = parsed.get("handler_routing", {})
+        handlers = handler_routing.get("handlers", [])
+        for entry in handlers:
+            if not isinstance(entry, dict):
+                continue
+            handler = entry.get("handler", {})
+            if isinstance(handler, dict):
+                module = handler.get("module", "")
+                if isinstance(module, str) and module:
+                    modules_to_check.append(module)
+            module_fallback = entry.get("handler_module", "")
+            if isinstance(module_fallback, str) and module_fallback:
+                modules_to_check.append(module_fallback)
+
+        for module in modules_to_check:
+            if not any(module.startswith(p) for p in ALLOWED_HANDLER_PREFIXES):
+                return self._reject(
+                    request, EnumMaterializationRejection.HANDLER_ALLOWLIST
+                )

Also applies to: 141-143

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/omnimarket/nodes/node_contract_registry/handlers/handler_contract_registry.py`
around lines 90 - 97, The code currently only checks
handler_routing.handlers[].handler.module against ALLOWED_HANDLER_PREFIXES but
later derives/adapts using the top-level handler.module, allowing bypass; update
the validation so that before any adapter derivation you normalize and check the
top-level module value (the computed variable module derived from parsed ->
handler_routing -> handlers -> entry -> handler) against
ALLOWED_HANDLER_PREFIXES and reject/raise/log when it’s not allowed; apply the
same fix to the other derivation path mentioned (the code around the second
adapter derivation referenced in the comment) so both places use the normalized
top-level module variable and the same allowlist check before proceeding with
adapter/class import.
src/omnimarket/nodes/node_delegate_skill_orchestrator/contract.yaml (1)

80-127: ⚠️ Potential issue | 🟠 Major

Fix duplicated top-level inputs in contract YAML
src/omnimarket/nodes/node_delegate_skill_orchestrator/contract.yaml defines inputs twice (at lines 22 and 80). Most YAML loaders keep only one value for duplicate keys (commonly the last), which can silently drop part of the contract schema. Remove one block and merge all fields into a single inputs mapping.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnimarket/nodes/node_delegate_skill_orchestrator/contract.yaml` around
lines 80 - 127, The contract YAML currently defines the top-level mapping
"inputs" twice which causes one block to override the other; open the contract
and merge the two "inputs" blocks into a single "inputs" mapping containing all
fields (prompt, task_type, source, cwd, source_file_path, working_directory,
session_id, recipient, codex_sandbox_mode, wait, max_tokens) and remove the
duplicate "inputs" key so no fields are silently dropped by YAML loaders.
🟡 Minor comments (18)
src/omnimarket/nodes/node_delegation_orchestrator/dispatchers/topic_utils.py-16-18 (1)

16-18: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Tighten canonical-topic validation before rewriting event_type.

Current parsing rewrites any onex.* topic with 5+ segments, including non-canonical formats, which contradicts the function contract and can mislabel envelope event types.

💡 Proposed fix
 def derive_event_type_from_topic(topic: str) -> str:
@@
     parts = topic.split(".")
-    if len(parts) >= 5 and parts[0] == "onex":
+    if (
+        len(parts) == 5
+        and parts[0] == "onex"
+        and parts[1] in {"cmd", "evt", "dlq"}
+        and parts[4].startswith("v")
+        and parts[4][1:].isdigit()
+        and parts[2]
+        and parts[3]
+    ):
         return f"{parts[2]}.{parts[3]}"
     return topic
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnimarket/nodes/node_delegation_orchestrator/dispatchers/topic_utils.py`
around lines 16 - 18, The current rewrite rewrites any topic with
parts[0]=="onex" and len(parts)>=5; tighten this by only rewriting when the
topic exactly matches the expected canonical ONEX pattern: require len(parts) ==
5, parts[0] == "onex", and validate that the other segments (parts[1], parts[2],
parts[3], parts[4]) are non-empty and only contain allowed characters (e.g.
alphanumeric, hyphen, underscore, dot) before returning
f"{parts[2]}.{parts[3]}"; otherwise return the original topic unchanged (use the
existing variables parts and topic to locate the logic).
docs/work-tracking/contracts/OMN-12570.yaml-68-77 (1)

68-77: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Make the DoD check prove the MERGING -> POST_MERGE_TAIL edge.

The description promises that exact transition, but the command only checks for post_merge_tail, transitions_recorded: true, and POST_MERGE_TAIL. A contract missing the actual MERGING -> POST_MERGE_TAIL transition would still pass this evidence step.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/work-tracking/contracts/OMN-12570.yaml` around lines 68 - 77, The DoD
check "dod-contract-phase-declaration" currently verifies only presence of
post_merge_tail, transitions_recorded: true, and POST_MERGE_TAIL but does not
assert the actual MERGING -> POST_MERGE_TAIL transition; update the check_value
for that check (in the checks array under id "dod-contract-phase-declaration")
to include a grep (or equivalent) that looks for the exact edge string
representing the transition from MERGING to POST_MERGE_TAIL (e.g., a pattern
matching "MERGING.*POST_MERGE_TAIL" or the exact "MERGING -> POST_MERGE_TAIL"
text) so the contract must contain the explicit MERGING -> POST_MERGE_TAIL
transition to pass.
src/omnimarket/configs/bifrost_delegation.yaml-99-105 (1)

99-105: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use the existing documentation capability name.

cloud-gemini-flash is the only backend here using document while the rest of the config and routing rules use documentation. Any capability matcher keyed on documentation will never consider this backend.

💡 Proposed fix
-      - document
+      - documentation
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnimarket/configs/bifrost_delegation.yaml` around lines 99 - 105,
Replace the incorrect capability key "document" with the existing
"documentation" in the capabilities list for the cloud-gemini-flash backend so
it matches the rest of the routing and capability matchers; update the
capabilities entry under the backend where you see capabilities: [..., document,
...] to use "documentation" instead so matchers keyed on documentation will
include this backend.
src/omnimarket/adapters/codex/local_runtime_dispatch.py-405-410 (1)

405-410: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Validate terminal_events shape before dict access.

Line 405-Line 410 uses cast(...) without runtime validation. If terminal_events is not a mapping, .get(...) on Line 426/Line 443 raises an AttributeError instead of surfacing a clear contract-validation error.

💡 Proposed fix
-    terminals = cast(
-        dict[str, Any],
-        runtime_dispatch.get("terminal_events")
-        or contract.get("terminal_events")
-        or {},
-    )
+    terminals_raw = (
+        runtime_dispatch.get("terminal_events")
+        or contract.get("terminal_events")
+        or {}
+    )
+    if not isinstance(terminals_raw, dict):
+        raise ValueError("Contract terminal_events must be a mapping")
+    terminals = cast(dict[str, Any], terminals_raw)

Also applies to: 426-427, 443-443

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnimarket/adapters/codex/local_runtime_dispatch.py` around lines 405 -
410, The code assigns terminals via cast(...) from
runtime_dispatch.get("terminal_events") or contract.get("terminal_events")
without runtime validation; add an explicit type/shape check after computing the
raw value (e.g., terminals_raw = runtime_dispatch.get("terminal_events") or
contract.get("terminal_events") or {}) and ensure it is a mapping/dict (has
items()/get attribute or isinstance(..., dict)); if it is not, raise a clear
ContractValidationError (or ValueError) mentioning "terminal_events" and include
the offending value; then set terminals = cast(dict[str, Any], terminals_raw)
and proceed, and apply the same validation pattern where terminal_events is
accessed later (the sites referenced around get calls in
local_runtime_dispatch.py that use terminals.get(...)).
src/omnimarket/configs/routing_tiers.yaml-102-107 (1)

102-107: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update tier-order comments to reflect cheap_frontier.

This file now includes a cheap_frontier tier, but the header docs still describe order as local → cheap_cloud → claude. Please align the comment to avoid operator confusion during tuning.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnimarket/configs/routing_tiers.yaml` around lines 102 - 107, The header
documentation above the tier definitions still documents the tier order as
"local → cheap_cloud → claude" but the new tier cheap_frontier has been added;
update the header comment to include cheap_frontier in the correct ordering
(e.g., "local → cheap_cloud → cheap_frontier → claude" or whatever intended
precedence) so operators see the true routing precedence when tuning, and ensure
any descriptive text that mentions the free-tier/OPENROUTER_API_KEY behavior
references cheap_frontier by name.
src/omnimarket/adapters/llm/adapter_llm_caller_delegation.py-97-100 (1)

97-100: ⚠️ Potential issue | 🟡 Minor

Propagate auth (api_key_ref/extra_headers) in LlmCallerDelegation, or ensure it’s never used in the live runtime path

src/omnimarket/adapters/llm/adapter_llm_caller_delegation.py constructs the provider like this (auth is never forwarded—only provider_type flips):

            api_key=None,
            provider_name=f"delegation-{intent.model}",
            provider_type="local" if intent.api_key_ref is None else "external_trusted",

In the live delegation runtime path, node_llm_delegation_call_effect/handlers/handler_inference_intent.py does resolve intent.api_key_ref into an Authorization: Bearer ... header and merges intent.extra_headers before the outbound HTTP call. So the “unauthenticated calls” risk is only relevant if LlmCallerDelegation is actually used in production wiring (e.g., via DelegationIntentBridge direct mode).

Either wire LlmCallerDelegation so it forwards the resolved auth/headers (or remove/adjust the misleading external_trusted flip), or add a clear guarantee/documentation that this adapter is never used where auth must be forwarded.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnimarket/adapters/llm/adapter_llm_caller_delegation.py` around lines 97
- 100, LlmCallerDelegation currently constructs the provider with api_key=None
and only flips provider_type, which drops intent.auth (api_key_ref) and
intent.extra_headers; update LlmCallerDelegation to propagate resolved auth by
setting the provider's api_key (or authorization header) and merging
extra_headers when building the provider (the code that sets api_key=None,
provider_name=f"delegation-{intent.model}", provider_type=...) so outbound calls
retain Authorization: Bearer ... and any intent.extra_headers, or if you cannot
forward auth, explicitly remove/rename the external_trusted behavior and add a
clear runtime guard/documentation in DelegationIntentBridge and
node_llm_delegation_call_effect/handlers/handler_inference_intent to ensure
LlmCallerDelegation is never used in flows requiring auth.
src/omnimarket/events/generation.py-39-39 (1)

39-39: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Validate SHA-256 format, not only length.

Line 39 currently accepts any 64-character string. Add a hex pattern check so malformed digests are rejected at model-parse time.

💡 Proposed patch
-    content_sha256: str = Field(min_length=64, max_length=64)
+    content_sha256: str = Field(
+        min_length=64,
+        max_length=64,
+        pattern=r"^[0-9a-fA-F]{64}$",
+    )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnimarket/events/generation.py` at line 39, The Field for content_sha256
currently only enforces length; update the Pydantic Field for content_sha256 to
validate hex characters by adding a regex/pattern that only allows 64
hexadecimal characters (0-9, a-f, A-F) so malformed digests are rejected during
model parsing; modify the declaration of content_sha256: str =
Field(min_length=64, max_length=64) in the events/generation.py model to include
the hex pattern (e.g., a pattern matching exactly 64 hex chars) and keep length
constraints consistent with the pattern.
src/omnimarket/events/design_to_plan.py-34-36 (1)

34-36: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Reject negative completion counters.

Line 34-Line 36 should enforce non-negative values; otherwise invalid terminal events can pass validation.

Proposed fix
-from pydantic import BaseModel, ConfigDict
+from pydantic import BaseModel, ConfigDict, Field
@@
-    created_count: int = 0
-    skipped_count: int = 0
-    failed_count: int = 0
+    created_count: int = Field(default=0, ge=0)
+    skipped_count: int = Field(default=0, ge=0)
+    failed_count: int = Field(default=0, ge=0)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnimarket/events/design_to_plan.py` around lines 34 - 36, The three
counter fields created_count, skipped_count, and failed_count must never be
negative; add validation where the event object is constructed (e.g., the event
class's __post_init__ or constructor in src/omnimarket/events/design_to_plan.py)
to check each of created_count, skipped_count and failed_count and raise a
ValueError (or otherwise reject the event) if any value < 0; alternatively
implement property setters or a validation helper that enforces non-negative
integers for these three symbols before the event is accepted.
src/omnimarket/models/swarm/model_swarm_subtask_result.py-18-18 (1)

18-18: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Constrain latency_ms to non-negative values.

Line 18 currently accepts negative latency, which is semantically invalid for execution telemetry.

Proposed fix
-from pydantic import BaseModel, ConfigDict
+from pydantic import BaseModel, ConfigDict, Field
@@
-    latency_ms: int = 0
+    latency_ms: int = Field(default=0, ge=0)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnimarket/models/swarm/model_swarm_subtask_result.py` at line 18, The
latency_ms field currently allows negative values; update the model to enforce
latency_ms >= 0 by adding validation: if this is a dataclass implement a
__post_init__ that raises ValueError when self.latency_ms < 0, or if the model
inherits from pydantic.BaseModel use Field(ge=0) or a `@validator` for
"latency_ms" to reject negatives; reference the latency_ms attribute and the
model's constructor/validation hook (e.g., __post_init__ or pydantic validator)
when making the change.
src/omnimarket/events/demo_pipeline.py-58-62 (1)

58-62: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add validation for cheapest_model_id/costs invariants.

Line 58-Line 62 allows inconsistent states that the description explicitly disallows, which can break downstream model selection logic.

Proposed fix
-from pydantic import BaseModel, ConfigDict, Field
+from pydantic import BaseModel, ConfigDict, Field, model_validator
@@
 class ModelDemoCostResult(BaseModel):
@@
     cheapest_model_id: str | None = Field(
         default=None,
         description="model_id with the lowest total_cost_usd; null when costs list is empty",
     )
+
+    `@model_validator`(mode="after")
+    def _validate_cheapest_model_id(self) -> "ModelDemoCostResult":
+        if not self.costs:
+            if self.cheapest_model_id is not None:
+                raise ValueError("cheapest_model_id must be null when costs is empty")
+            return self
+        valid_ids = {entry.model_id for entry in self.costs}
+        if self.cheapest_model_id is None or self.cheapest_model_id not in valid_ids:
+            raise ValueError("cheapest_model_id must reference one of the costs[].model_id values")
+        return self
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnimarket/events/demo_pipeline.py` around lines 58 - 62, Add a Pydantic
validation that enforces the invariant between costs: list[ModelDemoCostEntry]
and cheapest_model_id: ensure that when costs is empty cheapest_model_id is
None, and when costs is non-empty cheapest_model_id is non-None and equals the
model_id of the ModelDemoCostEntry with the lowest total_cost_usd (and that the
id exists in costs). Implement this as a validator/root_validator on the model
that references the costs field and cheapest_model_id to compute the min
total_cost_usd and either raise a ValidationError or set/normalize
cheapest_model_id accordingly; use the existing field names costs,
ModelDemoCostEntry, and cheapest_model_id to locate and modify the class.
src/omnimarket/events/demo.py-48-52 (1)

48-52: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Enforce cheapest_model_id consistency with costs.

Line 48-Line 52 documents an invariant but does not validate it, so invalid payloads can pass (e.g., unknown cheapest_model_id or non-null value with empty costs).

Proposed fix
-from pydantic import BaseModel, ConfigDict, Field
+from pydantic import BaseModel, ConfigDict, Field, model_validator
@@
 class ModelDemoCostResult(BaseModel):
@@
     cheapest_model_id: str | None = Field(
         default=None,
         description="model_id with the lowest total_cost_usd; null when costs list is empty",
     )
+
+    `@model_validator`(mode="after")
+    def _validate_cheapest_model_id(self) -> "ModelDemoCostResult":
+        if not self.costs:
+            if self.cheapest_model_id is not None:
+                raise ValueError("cheapest_model_id must be null when costs is empty")
+            return self
+        valid_ids = {entry.model_id for entry in self.costs}
+        if self.cheapest_model_id is None or self.cheapest_model_id not in valid_ids:
+            raise ValueError("cheapest_model_id must reference one of the costs[].model_id values")
+        return self
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnimarket/events/demo.py` around lines 48 - 52, Add a Pydantic validator
on the model that defines costs and cheapest_model_id to enforce the documented
invariant: if costs is empty then cheapest_model_id must be None, and if costs
is non-empty then cheapest_model_id must be non-null and equal to one of the
model_id values in the costs list. Implement this as a `@root_validator` (or a
validator for "cheapest_model_id" that accesses "costs") inside the same class
containing the costs: list[ModelDemoCostEntry] and cheapest_model_id: str | None
Field, and raise a ValueError with a clear message when the invariant is
violated.
src/omnimarket/nodes/node_decision_store_orchestrator/handlers/handler_decision_store_orchestrator.py-102-102 (1)

102-102: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Preserve valid falsy cursors in query responses.

Line 102 uses a truthy check, so a valid cursor like 0 is converted to None, breaking pagination continuity.

🔧 Proposed fix
-            next_cursor=str(next_cursor) if next_cursor else None,
+            next_cursor=str(next_cursor) if next_cursor is not None else None,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/omnimarket/nodes/node_decision_store_orchestrator/handlers/handler_decision_store_orchestrator.py`
at line 102, The response builder currently uses a truthy check on next_cursor
which converts valid falsy cursors (e.g., 0) to None; in the
handler_decision_store_orchestrator (handler_decision_store_orchestrator.py)
locate the expression that sets next_cursor to "str(next_cursor) if next_cursor
else None" and change it to use an explicit None check so that next_cursor is
converted to a string when it is not None (preserving values like 0) and set to
None only when it is actually None.
src/omnimarket/nodes/node_decision_store_orchestrator/__init__.py-1-1 (1)

1-1: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove stale “STUB: not yet implemented” wording from the module docstring.

This now conflicts with the contract state (node_not_implemented: false) and can cause operator confusion.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnimarket/nodes/node_decision_store_orchestrator/__init__.py` at line 1,
Update the module docstring in node_decision_store_orchestrator's __init__.py to
remove the stale phrase "STUB: not yet implemented" so it no longer contradicts
the module's implemented state; keep the descriptive portion ("conflict check,
LLM review, persist, notify for architectural decisions.") and adjust the
docstring to present the current functionality without implying it's
unimplemented.
src/omnimarket/nodes/node_data_flow_sweep/__main__.py-137-139 (1)

137-139: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

--collect --flows "[]" is currently rejected, but should be allowed.

This check treats any non-empty --flows string as conflicting, including "[]". That contradicts the non-empty-list exclusivity documented in this flow and contract behavior.

Suggested fix
-    if args.collect and args.flows:
-        _log.error("--collect and --flows are mutually exclusive")
-        sys.exit(1)
+    if args.collect and args.flows:
+        try:
+            maybe_flows = json.loads(args.flows)
+        except json.JSONDecodeError as exc:
+            _log.error("invalid --flows JSON: %s", exc)
+            sys.exit(1)
+        if maybe_flows:
+            _log.error("--collect and non-empty --flows are mutually exclusive")
+            sys.exit(1)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnimarket/nodes/node_data_flow_sweep/__main__.py` around lines 137 -
139, The mutual-exclusion check incorrectly rejects the string "[]" as a
non-empty flows value; update the check in __main__.py to allow an empty list
representation by treating args.flows == "[]" (or JSON-parsing it and checking
len == 0) as not conflicting with args.collect. Concretely, modify the if
condition that references args.collect and args.flows so it only errors when
args.collect is true AND args.flows represents a non-empty list (e.g.,
args.flows not None/empty and not equal to "[]" or json.loads(args.flows) yields
length > 0), keeping the error and sys.exit(1) behavior otherwise.
src/omnimarket/nodes/node_create_followup_tickets_effect/models/model_create_followup_tickets_state.py-40-43 (1)

40-43: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Validate line_number as positive when provided.

line_number currently accepts 0/negative values, which can generate invalid source locations in downstream ticket payloads.

🛠️ Proposed fix
     line_number: int | None = Field(
         default=None,
+        ge=1,
         description="Line number within the source file.",
     )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/omnimarket/nodes/node_create_followup_tickets_effect/models/model_create_followup_tickets_state.py`
around lines 40 - 43, The line_number Field in the model
(model_create_followup_tickets_state.py) must be validated as a positive integer
when provided; update the Field definition for line_number to include a minimum
constraint (e.g., Field(default=None, ge=1, description="Line number within the
source file.")) or add a pydantic validator on the model class to raise an error
when line_number is not None and is < 1 so downstream payloads never receive
0/negative values.
src/omnimarket/nodes/node_dashboard_sweep/handlers/handler_dashboard_sweep.py-324-333 (1)

324-333: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Normalize routes before building probe URLs.

If extra_routes contains values like "metrics" (no leading slash), Line 331 builds malformed URLs (<base_url>metrics) and silently downgrades recon quality.

🛠️ Proposed fix
         all_routes: list[str] = []
         seen: set[str] = set()
-        for route in list(discovered) + list(_KNOWN_ROUTES) + list(extra_routes):
+        def _normalize_route(route: str) -> str:
+            clean = (route or "").strip().split("?")[0].split("#")[0]
+            if not clean:
+                return "/"
+            return clean if clean.startswith("/") else f"/{clean}"
+
+        for route in (
+            _normalize_route(r)
+            for r in list(discovered) + list(_KNOWN_ROUTES) + list(extra_routes)
+        ):
             if route not in seen:
                 seen.add(route)
                 all_routes.append(route)
@@
-            url = base_url + route
+            url = urllib.parse.urljoin(base_url + "/", route.lstrip("/"))
             status_code, content_type, body_size, body_snippet = _fetch_page(url)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/omnimarket/nodes/node_dashboard_sweep/handlers/handler_dashboard_sweep.py`
around lines 324 - 333, The loop builds probe URLs using route values from
discovered, _KNOWN_ROUTES and extra_routes without normalizing leading slashes,
so entries like "metrics" produce malformed URLs when concatenated with
base_url; before adding to seen/all_routes (or immediately before forming url),
normalize each route by trimming whitespace, skipping empty strings, and
ensuring it starts with a single leading '/' (e.g., if not
route.startswith('/'): route = '/' + route) and optionally normalize base_url
trailing slash handling so you don't create double slashes; apply this
normalization where routes are collected (the loop handling
discovered/_KNOWN_ROUTES/extra_routes) so _fetch_page(base_url + route) always
receives a valid path and _ERROR_INDICATORS checks remain accurate.
src/omnimarket/nodes/node_delegation_ab_runner/handlers/handler_delegation_ab_runner.py-120-125 (1)

120-125: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix quality-pass default for failed delegated runs.

With quality_threshold > 0, a call error leaves quality_passed=True by default, which misreports failed delegated runs as passing quality.

Suggested patch
-    quality_score = 0.0
-    quality_passed = True
+    quality_score = 0.0
+    quality_passed = quality_threshold <= 0.0
     if not error and quality_threshold > 0.0:
         quality_score = _evaluate_quality(raw_output, quality_threshold)
         quality_passed = quality_score >= quality_threshold
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/omnimarket/nodes/node_delegation_ab_runner/handlers/handler_delegation_ab_runner.py`
around lines 120 - 125, The code sets quality_passed=True by default so when a
delegated run returns an error and quality_threshold>0 it incorrectly reports as
passing; change the logic so that when quality_threshold>0 and there is an error
(the variable error) quality_passed is set to False, otherwise compute
quality_score via _evaluate_quality(raw_output, quality_threshold) and set
quality_passed = quality_score >= quality_threshold; update the block around
quality_score, quality_passed, error, quality_threshold and _evaluate_quality to
reflect this conditional.
src/omnimarket/nodes/node_delegation_routing_feedback_reducer/models/model_delegation_feedback_event.py-37-37 (1)

37-37: ⚠️ Potential issue | 🟡 Minor

Disallow negative latency_ms at schema parse time

ModelDelegationFeedbackEvent.latency_ms is an unconstrained int (= 0), so negative values can still pass Pydantic parsing. HandlerDelegationRoutingFeedback currently only updates avg_latency_ms when event.latency_ms > 0, so negatives don’t affect the reducer average today—but constraining latency_ms >= 0 keeps the event invariant and prevents future downstream misuse.

Suggested patch
-from pydantic import BaseModel, ConfigDict
+from pydantic import BaseModel, ConfigDict, Field
@@
-    latency_ms: int = 0
+    latency_ms: int = Field(default=0, ge=0)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/omnimarket/nodes/node_delegation_routing_feedback_reducer/models/model_delegation_feedback_event.py`
at line 37, ModelDelegationFeedbackEvent currently allows negative latency_ms;
change its field to enforce non-negative values at parse time by replacing the
unconstrained int default with a Pydantic-constrained field (e.g., use
Field(..., ge=0) or conint(ge=0)) on the latency_ms attribute in the
ModelDelegationFeedbackEvent model so parsing rejects negatives; update imports
if necessary (from pydantic import Field or conint) and keep the
default/optional behavior consistent with the model (e.g., latency_ms: int =
Field(0, ge=0) or latency_ms: conint(ge=0) = 0).

Comment thread docs/evidence/dep-health-sweep/proof-of-life-001/projection_rows.json Outdated
Comment thread src/omnimarket/nodes/node_context_experiment_compute/contract.yaml
@jonahgabriel
jonahgabriel force-pushed the hotfix/omn-12245-release-omnimarket-v0.4.3 branch from b560d9f to ab086ca Compare June 6, 2026 20:47
@github-actions

github-actions Bot commented Jun 6, 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.

Powered by node_pr_review_bot

@github-actions

github-actions Bot commented Jun 6, 2026 •

Copy link
Copy Markdown

✅ PR Review Bot — CLEAN

Findings: 0
Run ID: ``

Required gate: This check blocks merge when verdict is blocking_issue.


Verdict semantics

Verdict Meaning
clean No blocking findings
risks_noted Findings noted; threads passed judge verification
blocking_issue MAJOR/CRITICAL findings not resolved — do not merge

Powered by node_pr_review_bot — Qwen3-Coder-30B reviewer + DeepSeek-R1 judge (OMN-7963)

@github-actions

github-actions Bot commented Jun 6, 2026 •

Copy link
Copy Markdown

⚠️ Hostile Reviewer — DEGRADED (informational)

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

Note: All reviewer models failed or were unavailable. Degraded results are informational during the pilot phase (OMN-8524) and do not block merge. Error: cli_review exited non-zero (all models failed or binary error)


Gate semantics (pilot phase)

Verdict Meaning Blocks merge?
passed No critical/error findings No
blocked CRITICAL or ERROR findings found Yes
degraded All models unavailable (infra) No (pilot)

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

@jonahgabriel
jonahgabriel added this pull request to the merge queue Jun 6, 2026
Merged via the queue into dev with commit 5ee01de Jun 6, 2026
87 checks passed
@jonahgabriel
jonahgabriel deleted the hotfix/omn-12245-release-omnimarket-v0.4.3 branch June 6, 2026 21:47
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