Skip to content

feat(OMN-19215): place a lane-added delegation backend in the tier ladder as an unavailability-only sibling - #2803

Merged
jonahgabriel merged 4 commits into
devfrom
jonah/omn-19215-tier-placement
Sep 25, 2026
Merged

jonahgabriel merged 4 commits into
devfrom
jonah/omn-19215-tier-placement

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Summary

OMN-19215, design (B), omnimarket half. A lane overlay can add a delegation backend, but routing only offers a backend the packaged routing_tiers.yaml names, so the second lab host serving the same Qwen3.8-27B as .201 (local-omnipc2-chat at .202) takes traffic only on a per-run pin.

  • Placement on the backend entry, not on the wire model. A bifrost backend entry may declare placement: {tier, fallback_for, max_context_tokens}. It is routing configuration read once at load, so it lives in non-wire models (omnimarket.models.delegation.model_delegation_backend_placement). The loader lifts it off each entry before ModelDelegationBackendConfig validates, so the wire model keeps the shape the released consumer accepts (the Wire Compatibility Gate refused the first revision, which put the field on the wire model), and load_bifrost_backend_placements reads it from the same resolved contract/overlay pair. No placement means unchanged behaviour.
  • Mirrored into the ladder at load. omnimarket.routing.backend_placement.apply_backend_placements appends one mirrored tier entry per named rung AFTER the tier's existing models (id = the placed backend's own served model name, use_for copied from the rung, context = the smaller of the two). The routing reducer's _get_config() applies it, so the reducer, the same-tier sibling probe and the local dispatch path read one placed ladder. Declaration-order selection means the placed backend is reached only when its rung is unroutable or already tried, never ahead of it.
  • Typed refusals. Unknown tier, a rung the tier does not declare, a backend with no served model name, or a backend the tier already carries each raise ProtocolConfigurationError naming the backend. The context-window check lives in the infra renderer, the only place that knows the window.
  • Replay provenance. _routing_tiers_hash() folds in a digest of the placements; with none it is the tiers file's sha256 exactly as before.
  • AC3 precondition. After a quality rejection, the local dispatch port no longer hops to a same-tier sibling serving the same model id (it would only re-draw the rejected model on another host). A transport failure still hops to it, which is what the placement is for. The bus path already re-drafts on the same backend and then escalates on a quality rejection.

Load-spreading across same-model rungs is not in this PR (AC4).

Sequencing

Lands before the omnibase_infra companion that passes placement through the renderer and places local-omnipc2-chat in the dev overlay: a rendered contract carrying the key is refused by any omnimarket without this change. Lab proof on the .201 dev lane (AC2) follows after the M4 streak window closes; nothing here is deployed until then.

Tests

  • tests/unit/routing/test_backend_placement_omn19215.py (13): mirror order and fields, no-placement identity, five invalid placements naming the backend, digest, the wire loader accepting a placed contract while the placement loader reads it, a malformed placement refused naming the backend, the real routing authority loading a placed fixture, the sibling probe offering the placed backend only after its rung is tried, and the replay hash with a positive control.
  • scripts/ci/check_wire_compatibility.py --base origin/dev locally: PASS against released v0.4.207.
  • tests/unit/nodes/node_delegate_skill_orchestrator/test_local_dispatch_same_model_sibling_omn19215.py (2): RED before the port change (['cloud-primary', 'cloud-mirror'] called after a quality rejection), green after; the transport-failure control passes both before and after.
  • Focused selection of every test module touching the routing reducer, the local dispatch port, the delegation workflow handler, the bifrost config model routing_tiers or the bifrost config loader: 2071 passed, 4 skipped. mypy --strict clean on the six changed modules.

Landing after M4

Held per the orchestrator's M4 fence: this PR stays draft and disarmed (autoMergeRequest read back null) until the board reports green. This section records what landing requires once that holds lifts.

Merge order (OMN-19215): 1) this PR (omnimarket#2803) merges to dev first. 2) release-on-merge.yml (OMN-18010) auto-cuts an omnimarket release publishing the version carrying apply_backend_placements / ModelDelegationBackendPlacement — no manual release-train step; config/release_train_policy.yaml has omnimarket in mode: report_only precisely because this automation already cuts it on every source-touching merge. 3) omnibase_infra#3999 merges, consuming that published omnimarket version in the dev-lane runtime image. 4) the AC2 lab pair (below) runs on the .201 dev lane.

Release cut required between this PR and omnibase_infra#3999: the omnimarket auto-release from step 2 above. omnibase_infra#3999 renders a placement key that this omnimarket version is the first to accept; an omnibase_infra dev-lane image still running the pre-#2803 omnimarket would refuse to load the lane's delegation config.

Lab proof needed on the .201 dev lane after M4 (not run today — .201 is fenced): AC2 from the Sequencing section above — a test-scoped run whose rendered contract binds local-coder to a closed port answered by .202, plus an unmodified control answered by .201, both exercised through the deployed dev-lane onex-api container (never a raw client or shortcut).

M4 probes to re-run after landing: C13, C14, C29 — this PR changes local-dispatch same-model-sibling behavior on the customer-local delegation path that those probes exercise.

Evidence-Ticket: OMN-19215
Evidence-Source: OCC#11059

…dder as an unavailability-only sibling

A bifrost backend may declare placement {tier, fallback_for, max_context_tokens}.
The routing authority mirrors it into that tier after the rungs it backs when it
loads the ladder, so the reducer, the same-tier sibling probe and the local
dispatch path read one placed ladder. Invalid placements raise
ProtocolConfigurationError naming the backend. The replay-provenance hash covers
the placement. A quality rejection on the local dispatch path no longer hops to a
sibling serving the same model id; a transport failure still does.

Onex-Lane: pc2-delegation-load
Onex-Session: 85986327e3c342f1afa982a2ad965fc8
@github-actions

github-actions Bot commented Sep 23, 2026 •

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:881: self._effect_handler = effect_handler or HandlerLlmDelegationCall()

src/omnimarket/nodes/node_delegate_skill_orchestrator/ports/port_local_delegation_dispatch.py:882: self._projection_handler = projection_handler or HandlerProjectionDelegation(
src/omnimarket/nodes/node_delegate_skill_orchestrator/ports/port_local_delegation_dispatch.py:904: self._judge = judge if judge is not None else HandlerJudgeAdequacy()
src/omnimarket/nodes/node_delegation_orchestrator/handlers/handler_delegation_workflow.py:1159: loop = HandlerComplianceLoop()
src/omnimarket/nodes/node_delegation_orchestrator/handlers/handler_delegation_workflow.py:1958: HandlerEscalationDecision()\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

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

✅ Hostile Reviewer — PASSED

Blocking findings (critical/error): 0
Total findings: 14
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)

…ead of widening the wire model

The released consumer's ModelDelegationBackendConfig refuses unknown keys, so
the Wire Compatibility Gate refused a placement field on it. A placement is
routing configuration read once at load, not a payload, so it now lives in
non-wire models (ModelDelegationBackendPlacement, ModelPlacedDelegationBackend),
the loader lifts it off each backend entry before the wire model validates, and
load_bifrost_backend_placements reads it from the same resolved contract pair.

Onex-Lane: pc2-delegation-load
Onex-Session: 85986327e3c342f1afa982a2ad965fc8
@jonahgabriel
jonahgabriel marked this pull request as ready for review September 23, 2026 20:50
@jonahgabriel
jonahgabriel marked this pull request as draft September 23, 2026 20:53
@jonahgabriel
jonahgabriel marked this pull request as ready for review September 24, 2026 11:06
onexbot-occ-writer Bot added a commit to OmniNode-ai/onex_change_control that referenced this pull request Sep 24, 2026
…nimarket#2803

The declared checks were executed for real in the OmniNode-ai/omnimarket checkout at the PR head by the product-repo OCC receipt runner, and the results written append-only into this companion. Producer-minted PENDING receipts are superseded by a net-new record; no existing receipt was edited.

Ticket: OMN-16859 (AC3b)
Onex-Workflow: OCC Receipt Runner
Onex-Run: https://github.com/OmniNode-ai/omnimarket/actions/runs/35991067861
jonahgabriel pushed a commit to OmniNode-ai/onex_change_control that referenced this pull request Sep 25, 2026
…imarket#2803 (#11059)

* evidence(OMN-19215): author OCC companion for OmniNode-ai/omnimarket#2803

OCC companion by node_pr_lifecycle_fix_effect (OMN-13317 F1 / OMN-13990 / OMN-14285). Product PR head 5294af7d08ec477f2ce54511abdf2328e43ecc47.

* evidence(OMN-19215): self-bind OCC#11059 + rebind contract_sha256

* evidence(OMN-16859): executed test_passes receipts for OmniNode-ai/omnimarket#2803

The declared checks were executed for real in the OmniNode-ai/omnimarket checkout at the PR head by the product-repo OCC receipt runner, and the results written append-only into this companion. Producer-minted PENDING receipts are superseded by a net-new record; no existing receipt was edited.

Ticket: OMN-16859 (AC3b)
Onex-Workflow: OCC Receipt Runner
Onex-Run: https://github.com/OmniNode-ai/omnimarket/actions/runs/35991067861

---------

Co-authored-by: omnimarket-bot <bot@omninode.ai>
Co-authored-by: onexbot-occ-writer[bot] <307849072+onexbot-occ-writer[bot]@users.noreply.github.com>
@jonahgabriel
jonahgabriel merged commit d722dd9 into dev Sep 25, 2026
181 of 191 checks passed
@jonahgabriel
jonahgabriel deleted the jonah/omn-19215-tier-placement branch September 25, 2026 10:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

hold:auto-merge Holds auto-merge (check_auto_merge_hold.py); remove to release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant