Skip to content

feat(OMN-15156): thread optional backend_id pin through LocalDelegationDispatchPort.dispatch() - #1897

Merged
jonahgabriel merged 1 commit into
devfrom
jonah/omn-15156-p0omnimarket-thread-optional-backend_id-pin-through
Jul 26, 2026
Merged

jonahgabriel merged 1 commit into
devfrom
jonah/omn-15156-p0omnimarket-thread-optional-backend_id-pin-through

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Jul 26, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Threads an optional caller-supplied backend_id pin through
LocalDelegationDispatchPort.dispatch() -> _resolve_initial_backend ->
resolve_delegation_backend's pre-existing backend_id kwarg. backend_id
defaults to None, which preserves the exact pre-existing cheapest-first
task_type + tier_order resolution — a regression test proves this
byte-for-byte.

Ticket: OMN-15156 (P0, epic OMN-15154). Governing plan:
docs/plans/2026-07-26-steel-node-dispatch-integration-plan.md (P0, hostile
finding #4 — dispatch() had no caller-supplied backend pin; this ticket adds
it).

Signature diffs

LocalDelegationDispatchPort (src/omnimarket/nodes/node_delegate_skill_orchestrator/ports/port_local_delegation_dispatch.py):

async def dispatch(
    self,
    *,
    prompt: str,
    task_type: str,
    correlation_id: UUID,
    max_tokens: int | None,
    source_file_path: str | None,
    source_session_id: str | None,
    wait: bool,
    quality_contract_mode: str,
    acceptance_criteria: tuple[str, ...],
    tenant_id: str | None,
    backend_id: str | None = None,   # NEW, OMN-15156
) -> dict[str, object]: ...

def _resolve_initial_backend(
    self,
    task_type: str,
    *,
    roi_overlay: ModelRoutingRoiOverlay | None = None,
    backend_id: str | None = None,   # NEW, OMN-15156
) -> ModelResolvedDelegationBackend:
    if backend_id is not None:
        return resolve_delegation_backend(task_type, backend_id=backend_id)
    # ... unchanged tier_order path ...

No other call sites were touched — HandlerDelegateSkill.handle() /
ProtocolDelegationDispatchPort do not pass backend_id in this ticket
(narrowly scoped to the port-level chain per the ticket description); a
non-None pin is reachable today only via a direct dispatch(..., backend_id=...) call (e.g. steel's future LlmBusDelegationClient, or a
future CLI flag — out of scope here).

RuntimeDelegationDispatchPort was read but NOT mirrored. Its dispatch()
shares the outer call signature (same kwargs, same ProtocolDelegationDispatchPort
duck-typed surface in handler_delegate_skill.py), but it does not call
_resolve_initial_backend or resolve_delegation_backend at all — it builds a
ModelDelegationRequest (frozen, extra="forbid", no backend_id field) and
publishes it to the bus; backend resolution happens downstream, off-repo-file,
in whatever consumes that command topic. Adding a backend_id kwarg to that
port's dispatch() today would be an unhonored parameter — a silent no-op that
looks wired but isn't. Threading a pin onto the bus path is a separate, larger
change (new ModelDelegationRequest field + downstream consumer support) and
is out of this ticket's scope.

Escalation-interaction note (verbatim from the code, P0 readback requirement)

Escalation-interaction note (OMN-15156, P0 readback requirement): this pin
affects ONLY the initial attempt. If the pinned backend's transport call
fails, the existing escalation loop in dispatch() still excludes the
pinned backend's WHOLE TIER (via tier_for_backend(backend.backend_id))
and re-resolves the next hop through the normal closed-set tier_order
— NOT back to the pin, and NOT to a different backend within the same
tier. This ticket does not redesign escalation; a single-backend (rather
than whole-tier) exclusion semantics is out of scope here.

This was verified by reading the escalation branch in dispatch() (unchanged
by this PR): on transport failure it computes
current_tier = tier_for_backend(backend.backend_id) or backend.tier,
excluded_tiers.add(current_tier), then calls _resolve_next_backend(...),
which re-resolves via next_eligible_tier + backend_id_for_tier — the
tier-order ladder, never back to the original pin. If the pinned backend's
tier cannot be classified by tier_for_backend (an off-ladder backend_id),
backend.tier (the resolved backend's own declared tier, e.g. local for
local-coder-mlx) is used instead, so the exclusion is still tier-scoped, not
un-scoped.

Tests

tests/unit/nodes/node_delegate_skill_orchestrator/test_local_dispatch_backend_id_pin_omn15156.py
(3 new tests, all passing locally):

  • test_pinned_backend_id_selects_exactly_that_backend_and_bypasses_tier_order
    — pin resolves the exact backend; first_eligible_tier is monkeypatched to
    raise if invoked at all, proving the pin bypasses tier_order selection
    entirely rather than merely agreeing with it.
  • test_backend_id_none_preserves_existing_tier_based_resolution — regression:
    both an explicit backend_id=None and a caller that omits the (new,
    optional) kwarg entirely still drive the pre-existing
    first_eligible_tier -> backend_id_for_tier -> resolve_delegation_backend
    chain, byte-identical to pre-OMN-15156 behavior.
  • test_unknown_backend_id_pin_fails_loudly_not_silently — uses the REAL
    resolve_delegation_backend (only load_bifrost_backends is patched to a
    small in-memory list) against an unresolvable pin: RuntimeError propagates
    out of dispatch() verbatim, and the effect handler is never invoked (proves
    fail-closed, not a silent fallback to a different backend).

Verification

  • uv run ruff check / uv run ruff format --check — clean.
  • uv run mypy src/omnimarket/nodes/node_delegate_skill_orchestrator/ports/port_local_delegation_dispatch.py --strict — clean (also re-run via the pre-push hook's full strict pass — clean).
  • Targeted pytest (tests/unit/nodes/node_delegate_skill_orchestrator/,
    tests/unit/delegation/, tests/integration/node_delegate_skill_orchestrator/):
    728 passed, 2 skipped, 1 pre-existing unrelated failure
    (test_local_dispatch_fork_safety_omn13842.py::test_dispatch_returns_typed_receipt_through_process_boundary
    — reproduced identically on unmodified dev via git stash; a flaky
    unreachable.invalid DNS/timeout test, not touched by this diff).
  • Full local pre-commit (uv run pre-commit run --files ...): all 33
    applicable hooks passed; topic-naming-lint initially reported "Failed"
    only because OMNIBASE_INFRA_PATH wasn't set in this shell (an env-path
    resolution gap on this Mac, pass_filenames: false unrelated to the diff
    content) — re-ran with the var set and it passed clean; confirmed via
    git commit's own pre-commit run (which correctly resolved the sibling
    path) that this hook is green on the real commit.
  • git push's pre-push hook auto-escalated to the governed impacted-test
    selector's full local suite (tests/nodes/ tests/unit/ --ignore=tests/integration -m 'not kafka', 5943 collected) because port_local_delegation_dispatch.py
    is a widely-imported shared module — narrowing wasn't provably safe. Result:
    5933 passed, 9 skipped, 1 xfailed, 0 failed (312.53s); push allowed.
  • Small-diff exception claimed per dispatch instructions: diffs are
    port-signature-scoped (one new optional kwarg threaded through two methods)
    • a new test file; ran on this Mac rather than .200 because the pre-push
      hook itself already ran the full local suite as part of the push (see
      above) — that superseded the need for a second .200 full-suite run for
      this small a diff.

Receipt / CI gates

  • PR title/body cite OMN-15156 and the governing plan (this section).
  • Do not merge — merges belong to the Codex lane.

Summary by CodeRabbit

  • New Features

    • Added support for selecting a specific delegation backend when dispatching a task.
    • Pinned requests bypass automatic tier-based backend selection.
  • Bug Fixes

    • Invalid backend selections now fail clearly instead of silently falling back.
    • Existing automatic backend selection remains unchanged when no backend is specified.
  • Tests

    • Added coverage for pinned backend selection, default resolution behavior, and failure handling.

Evidence-Source: OCC#4918
Evidence-Ticket: OMN-15156
Evidence-Commit: d79b5a97be56334cfb56b645af7eb9e62ccd6e98

…onDispatchPort.dispatch()

dispatch() previously resolved the initial backend purely from task_type +
tier_order via _resolve_initial_backend, with no caller-supplied pin. Add an
optional backend_id kwarg (default None = byte-identical prior behavior)
threaded dispatch() -> _resolve_initial_backend -> resolve_delegation_backend's
existing backend_id kwarg (the same targeted-resolution path the LLM-judge
already uses, OMN-13470).

When a pin is supplied, tier_order/first_eligible_tier is bypassed entirely for
the initial attempt; an unresolvable pin fails loudly via
resolve_delegation_backend's existing RuntimeError (never a silent fallback).
Escalation is unchanged: a transport failure on the pinned backend still
excludes its whole tier via the existing tier_for_backend/next_eligible_tier
loop, not just that backend -- documented in the PR body per the plan's P0
readback requirement, not redesigned here.

RuntimeDelegationDispatchPort was read but not mirrored: its dispatch() does
not call _resolve_initial_backend/resolve_delegation_backend at all (backend
resolution happens downstream, off a ModelDelegationRequest with no backend_id
field) -- adding an unhonored parameter there would be a silent no-op.

Plan: docs/plans/2026-07-26-steel-node-dispatch-integration-plan.md (P0,
hostile finding #4). Epic OMN-15154.
@coderabbitai

coderabbitai Bot commented Jul 26, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Local delegation dispatch now accepts an optional backend_id for the initial attempt. Pinned backends bypass tier ordering and propagate resolution failures, while calls without a pin retain existing tier-based behavior. New tests cover both paths and fail-closed handling.

Changes

Local delegation backend pinning

Layer / File(s) Summary
Dispatch backend resolution
src/omnimarket/nodes/node_delegate_skill_orchestrator/ports/port_local_delegation_dispatch.py
dispatch forwards an optional backend pin; _resolve_initial_backend resolves that backend directly or retains the existing tier-based flow when no pin is provided.
Backend pin behavior tests
tests/unit/nodes/node_delegate_skill_orchestrator/test_local_dispatch_backend_id_pin_omn15156.py
Tests verify exact pinned selection, preserved tier resolution for None or omitted pins, and propagation of unresolved backend errors without invoking the effect handler.

Estimated code review effort: 3 (Moderate) | ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the main change: adding an optional backend_id pin to LocalDelegationDispatchPort.dispatch().
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jonah/omn-15156-p0omnimarket-thread-optional-backend_id-pin-through

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

@github-actions

Copy link
Copy Markdown

⚠️ Architectural Review — WARNINGS

Errors: 0
Warnings: 1

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

ARCH-DI-002: Direct Handler instantiation (warning)\n\n```\nsrc/omnimarket/nodes/node_delegate_skill_orchestrator/ports/port_local_delegation_dispatch.py:372: self._effect_handler = effect_handler or HandlerLlmDelegationCall()

src/omnimarket/nodes/node_delegate_skill_orchestrator/ports/port_local_delegation_dispatch.py:373: self._projection_handler = projection_handler or HandlerProjectionDelegation()
src/omnimarket/nodes/node_delegate_skill_orchestrator/ports/port_local_delegation_dispatch.py:393: self._judge = judge if judge is not None else HandlerJudgeAdequacy()\n```\n\nHandler classes should be wired only in workflow_runner.py or adapter modules. Direct instantiation elsewhere bypasses the contract system.\n\n

Static architectural lint — no model inference (OMN-14176).

@github-actions

Copy link
Copy Markdown

✅ Hostile Reviewer — PASSED

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


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)

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