Skip to content

fix(OMN-20490): size local-omnipc2-chat max_tokens to its slot share of the .202 pool - #4542

Merged
jonahgabriel merged 3 commits into
devfrom
OMN-20490-202-rung-max-tokens
Oct 4, 2026
Merged

jonahgabriel merged 3 commits into
devfrom
OMN-20490-202-rung-max-tokens

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Oct 4, 2026 •

Copy link
Copy Markdown
Collaborator

Lab: host=h201 (lane 202-rung-max-tokens, head cb2fd13); values rendered from docker/lane-overlays/dev.bifrost.yaml (local-omnipc2-chat max_tokens=4096, pool 65536, 4 slots, headroom 12288) by the repo renderer against a synthetic base, then 4 CONCURRENT POST http://192.168.86.202:8000/v1/chat/completions with that max_tokens and prompts of 12063-12387 prompt tokens: 4 x HTTP 200 in both waves (wave 1 finish_reason stop x4; wave 2, outputs forced to the cap, finish_reason length x4 at 4096 tokens, largest total 16306 of the 16384 share). Negative control, same pool, same prompts, max_tokens=65536: 2 x HTTP 500, 1 x client timeout at 300 s, 1 x HTTP 200 (stop, 22439 total tokens).

OMN-20490

Summary

  • Updated docker/lane-overlays/dev.bifrost.yaml to set max_tokens for the local-omnipc2-chat backend from 16384 to 4096.
  • Added a typed field ModelBifrostLaneOverlay.endpoint_capacity: a tuple of ModelBifrostLaneEndpointCapacity (endpoint host:port, pool_tokens, parallel_slots, prompt_headroom_tokens), defined in src/omnibase_infra/models/delegation/model_bifrost_lane_endpoint_capacity.py. Unknown keys are still rejected, a duplicate endpoint is refused, and the renderer does not write the block into the rendered contract.
  • The dev overlay declares endpoint 192.168.86.202:8000 with pool_tokens 65536, parallel_slots 4, and prompt_headroom_tokens 12288.
  • Added a new contract test tests/ci/test_bifrost_endpoint_capacity.py to validate capacity constraints.

Why 4096

  • The .202 llama.cpp server runs --kv-unified --parallel 4 -c 65536, creating one 65536-token pool shared by four slots.
  • The per-slot fair share is 65536 / 4 = 16384 tokens for prompt plus output; every slot reports n_ctx 65536, which is the pool.
  • The previous max_tokens of 16384 equaled the whole per-slot share, leaving no room for any prompt.
  • The new max_tokens of 4096 is derived from the formula: 65536 / 4 - 12288 = 4096.
  • Measured basis (delegation_events, real rows, attempts answered HTTP 200 by local-omnipc2-chat, 2026-09-28 to 2026-10-04, n=1882): prompt tokens p50 = 12301; 54.6% of prompts are at most 4096 tokens, 68.6% at most 12288, 72.4% at most 16384. Output tokens p50 170, p90 861, p99 3142, max 8478; 3 of 1882 answers exceeded 4096 output tokens and none exceeded 12288.
  • Outputs are short and prompts are large, so the share is spent on the prompt: a 4096 headroom would leave 45.4% of routed prompts outside the share, 12288 leaves 31.4%, and the 4096 output cap it costs sits above the output p99 of 3142.
  • Production signal in the same table: 263 attempts on local-omnipc2-chat answered HTTP 500 "Context size has been exceeded" (2026-10-01 to 2026-10-03); their events have prompt tokens p50 25222.

Lab proof

Surfaces on the .202 llama.cpp server exercised: GET /props and GET /slots (read-back of total_slots, n_ctx and slot activity, before and after each wave), GET /health, POST /tokenize (prompt sizing) and POST /v1/chat/completions (the waves). The server unit, its flags and its configuration were not touched. The dev-202 overlay binds no backend, so no request used it.

Values sent came from the rendered overlay, not typed by hand: max_tokens 4096, per-slot share 16384, headroom 12288. In wave 1 the model stopped on its own; wave 2 forced every request to the cap.

Wave 1, rendered max_tokens 4096, 4 concurrent (start 2026-10-04T01:22:37.705+00:00, end 2026-10-04T01:24:01.843+00:00; all slots idle at start: True)

# HTTP finish_reason prompt completion total start (UTC) end (UTC) s request id
0 200 stop 12205 3963 16168 01:22:43.193 01:24:01.586 78.39 chatcmpl-T8Hte3zzVUmgiweJfcd2WNltiOdFdwbm
1 200 stop 12249 3961 16210 01:22:43.193 01:24:00.942 77.75 chatcmpl-W0m9lDzMFebIph4oEPIcxkEuK5ucLYS0
2 200 stop 12257 1945 14202 01:22:43.193 01:23:33.681 50.49 chatcmpl-YxgLN8dIDM1VFgDjoQVHBY3BQ92x8ngM
3 200 stop 12387 3963 16350 01:22:43.193 01:24:01.840 78.65 chatcmpl-RtLIHhKi3phqIFCUTKjpT4gZWuxTMQSL

Wave 2, same, outputs forced to the cap (start 2026-10-04T01:24:11.926+00:00, end 2026-10-04T01:26:15.420+00:00; all slots idle at start: True)

# HTTP finish_reason prompt completion total start (UTC) end (UTC) s request id
0 200 length 12192 4096 16288 01:24:14.535 01:26:15.095 120.56 chatcmpl-UdHRL1Bk8mjm4cB2a0TqO2XN8VD1u5e8
1 200 length 12210 4096 16306 01:24:14.535 01:25:50.128 95.59 chatcmpl-eYI64tfeS8x7CK7dJaLUXtswx2odnKfE
2 200 length 12147 4096 16243 01:24:14.535 01:26:12.037 117.5 chatcmpl-sn20f6hGCJs1YDTCIzpt9MTKQRwnuf4R
3 200 length 12063 4096 16159 01:24:14.535 01:26:15.417 120.88 chatcmpl-yBGWewZHuHBqP8Nzdhtx0x72uO5Vx2yn

Negative control, max_tokens 65536, 4 concurrent (start 2026-10-04T01:26:21.896+00:00, end 2026-10-04T01:31:24.803+00:00; all slots idle at start: True)

# HTTP finish_reason prompt completion total start (UTC) end (UTC) s request id
0 timeout - - - - 01:26:24.700 01:31:24.801 300.1 -
1 200 stop 12152 10287 22439 01:26:24.700 01:29:51.341 206.64 chatcmpl-uiicXxiUIERkySBEyV1wUNgZPZ6dOBdm
2 500 - - - - 01:26:24.700 01:28:22.356 117.66 -
3 500 - - - - 01:26:24.700 01:28:22.356 117.66 -
  • request 0: TimeoutError('timed out')
  • request 2: {"error":{"code":500,"message":"got exception: speculative batch index 8 is not inside the current sub-batch [0, 8)","type":"server_error"}}
  • request 3: {"error":{"code":500,"message":"got exception: speculative batch index 9 is not inside the current sub-batch [0, 8)","type":"server_error"}}

The control reproduced failure under the same pool: two requests were refused with HTTP 500 at 117.66 s, about when four requests of this prompt size had each generated about 4100 tokens and the pool would be full (inferred from timing; the server's own log was not readable from here). The error text is speculative batch index N is not inside the current sub-batch [0, 8), not the "Context size has been exceeded" text recorded in delegation_events, so the wave shows a 500 at pool exhaustion but not that exact message. Live dev-lane traffic can also reach this server, so each wave started after a poll found every slot idle; /health answered ok with every slot idle afterwards. The waves show the new ceiling fits the pool at four concurrent requests; they do not show that the new test is what prevented the failures.

Deployed per-host files, recorded and not edited: ~/.omninode/delegation/bifrost_overrides.pc2.yaml repoints local-coder at .202:8000 with max_tokens 16384, and bifrost_overrides.yaml carries local-omnipc2-chat at 16384. Both sit outside this repo.

Not changed, and a finding for a decision

  • context_window 65536 and placement max_context_tokens 65536 keep their values; comments now clarify they represent the whole pool, not one slot's share.
  • The dev-202 overlay still declares no backend.
  • Deployed ~/.omninode/delegation bifrost_overrides files are untouched; they carry max_tokens 16384 for local-coder and local-omnipc2-chat and are per-host files outside the repo.
  • Finding: the placement ceiling (65536) is far above the per-slot share (16384) minus the 4096 output cap.
  • A prompt larger than the 12288-token headroom is still routed to .202 and fits only while other slots leave the pool free.
  • 31.4% of the measured routed prompts are above the headroom.
  • Bringing the ceiling down to the headroom is a routing change; this PR does not make it.

Tests

  • New contract test tests/ci/test_bifrost_endpoint_capacity.py loads every committed docker/lane-overlays/*.bifrost.yaml.
  • The test takes declared capacities as the union over all overlays and refuses two different declarations of one endpoint.
  • It fails when max_tokens + prompt_headroom_tokens exceeds pool_tokens / parallel_slots for any binding whose host:port is a declared pool endpoint.
  • The test renders each overlay that binds a pool endpoint against a synthetic base contract and checks the rendered backends.
  • The dev-202 overlay is asserted explicitly to be locale cloud with zero backends.
  • Positive controls: a ceiling exactly filling the share passes, one token over fails, and a ceiling equal to the whole share fails.
  • No literal pool, slot, or ceiling numbers are present in the test or src logic.
  • Red state at the first commit: the test failed with "backend 'local-omnipc2-chat' on 192.168.86.202:8000 asks for max_tokens=16384, which with the 12288-token prompt headroom is 28672 tokens, over the per-slot share of 16384".
  • Two of nine tests failed in the red state (the committed-overlay check and the rendered check).
  • After the second commit, all nine tests pass.
  • Tests run locally in the worktree on host h201 at head cb2fd13:
    • tests/ci/test_bifrost_endpoint_capacity.py
    • tests/unit/runtime/models/test_model_bifrost_lane_endpoint_capacity.py
    • tests/ci/test_bifrost_lane_overlay.py
    • 37 passed.
  • Wider overlay, renderer, and placement test files (335 selected tests) passed earlier.
  • ruff format, ruff check, and mypy --strict pass on the changed source files.
  • CI is the merge gate.

Evidence-Ticket: OMN-20490
Evidence-Source: OCC#12711

Test Runner added 2 commits October 3, 2026 21:15
Adds tests/ci/test_bifrost_endpoint_capacity.py to refuse lane-overlay
backends on unified-KV-pool endpoints where max_tokens plus prompt
headroom exceeds pool_tokens / parallel_slots.
Introduces ModelBifrostLaneOverlay.endpoint_capacity as a tuple of
ModelBifrostLaneEndpointCapacity with extra=forbid; the renderer does
not write this block into the rendered contract.
Declares .202 llama.cpp endpoint capacity in docker/lane-overlays/dev.bifrost.yaml.
The test covers all committed docker/lane-overlays/*.bifrost.yaml files
and asserts the dev-202 overlay binds no backend.
This commit is intentionally failing: the dev overlay's local-omnipc2-chat
backend has max_tokens 16384, which with 12288 headroom is 28672
against a per-slot share of 16384, causing two test failures.
Reduce backend max_tokens from 16384 to 4096 in dev.bifrost.yaml.
The 65536-token KV pool is shared by 4 slots, making 16384 the per-slot
fair share. The previous value left no room for the prompt. 4096 is the
share minus the 12288-token prompt headroom declared in endpoint_capacity.
Measured data (n=1882) shows output p99 at 3142 and max at 8478, with
3 responses exceeding 4096. Prompt p50 is 12301. Context window and
placement ceiling comments are relabelled as the whole pool, unchanged.
This turns the contract test added in the previous commit green.
@jonahgabriel
jonahgabriel enabled auto-merge October 4, 2026 01:35
Adds tests/integration/runtime/test_dev_overlay_pool_share_omn20490.py.
Renders committed dev lane overlay via real renderer and checks max_tokens.
Validates local-omnipc2-chat rung against endpoint_capacity (max_tokens + headroom).
Negative control uses whole per-slot share; renderer carries it, check refuses.
@jonahgabriel

Copy link
Copy Markdown
Collaborator Author

Lab: head=0de2977104212724d3ae455062ca0199076f34b6 The first push (head cb2fd13) failed the Integration Test Coverage check because the PR adds feature code without a test under tests/integration. This head adds tests/integration/runtime/test_dev_overlay_pool_share_omn20490.py (126 lines, tests only; the overlay, schema and renderer files are unchanged since the lab waves in the PR body). Its two tests pass on host h201 (uv run pytest on that file: 2 passed): the rendered local-omnipc2-chat max_tokens fits the declared per-slot share, and a copy of the overlay with max_tokens equal to the whole share renders through and is refused by the same check. The lab waves in the PR body (4 x HTTP 200 at the rendered max_tokens 4096, twice) therefore still describe the shipped values. The deploy-gate check names the OCC contract for OMN-20490 as missing, which the companion mint resolves; it is not hand-written here.

jonahgabriel pushed a commit to OmniNode-ai/onex_change_control that referenced this pull request Oct 4, 2026
…12711)

* evidence(OMN-20490): author OCC companion for OmniNode-ai/omnibase_infra#4542

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

* evidence(OMN-20490): self-bind OCC#12711 + rebind contract_sha256

---------

Co-authored-by: omnimarket-bot <bot@omninode.ai>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hostile Reviewer — adversarial findings (OMN-17492)

Models succeeded: qwen3-review, gpt-oss-review
Models failed: none
New finding threads: 2
Deduped (already posted on this PR): 0
Below quorum (one model only, reported not threaded): 7
Nit-level findings suppressed: 2

The model is the FINDER, never the gate: merge is gated only by the
deterministic Hostile Review Thread Gate, which blocks while
hostile-reviewer threads are unresolved. Resolve each thread after
addressing (or rejecting, with a reply) its finding.

Below quorum: 7 finding(s) raised by one model only (OMN-18479)

These are reported and NOT dropped, but they get no thread and do not block: a single model's finding no other model reproduced is not evidence enough to stop a merge. Read them; act on them if they are right.

  • [MAJOR] src/omnibase_infra/models/delegation/model_bifrost_lane_endpoint_capacity.py (qwen3-review) — authority_of returns None for URLs with default ports, breaking capacity matching | The authority_of method returns None when the URL omits a port and the scheme has no entry in _DEFAULT_PORTS, or whe
  • [MAJOR] src/omnibase_infra/models/delegation/model_bifrost_lane_endpoint_capacity.py (qwen3-review) — max_output_tokens can be negative if prompt_headroom_tokens > per_slot_tokens | The model_validator checks that prompt_headroom_tokens < per_slot_tokens, so max_output_tokens should always be positive
  • [MAJOR] tests/ci/test_bifrost_endpoint_capacity.py (qwen3-review) — Test test_dev_202_overlay_declares_no_backend_by_design assumes a specific file name | The test hardcodes the file name 'dev-202.bifrost.yaml' and asserts that it exists in the committed overlays. If
  • [MAJOR] src/omnibase_infra/runtime/models/model_bifrost_lane_overlay.py (gpt-oss-review) — Endpoint capacity declarations are not cross‑validated against backend bindings | ModelBifrostLaneOverlay adds an endpoint_capacity field but only checks for duplicate endpoint entries. It does not
  • [MINOR] src/omnibase_infra/models/delegation/model_bifrost_lane_endpoint_capacity.py (qwen3-review) — No validation that endpoint host is a valid hostname or IP | The endpoint field is validated to have a numeric port, but the host portion is not validated to be a valid hostname or IP address. A value
  • [MINOR] src/omnibase_infra/models/delegation/model_bifrost_lane_endpoint_capacity.py (qwen3-review) — No test for authority_of with IPv6 addresses | The authority_of method uses urlsplit, which handles IPv6 addresses with brackets. However, the endpoint field validation uses rpartition(':'), which wou
  • [MINOR] src/omnibase_infra/runtime/models/model_bifrost_lane_overlay.py (gpt-oss-review) — Duplicate endpoint detection ignores default port normalization | The duplicate‑endpoint check compares raw endpoint strings. If one entry uses an explicit port (e.g., "example.com:80") and another

Findings demoted from threads (anchor rejected)

  • [MINOR] hostile-reviewer (qwen3-review)

    rpartition on endpoint string may misparse if host contains colon | The rpartition(':') on the endpoint string will split on the last colon. If the host part contains a colon (e.g., a malformed host), it would be misparsed. The validation checks that port is decimal, but does not check that host does not contain a colon. | Evidence: host, separator, port = self.endpoint.rpartition(":") | Fix: Add a check that the host portion does not contain a colon.

    Resolve this thread when addressed — the Hostile Review Thread Gate blocks while hostile-reviewer threads are unresolved (OMN-17492).

  • [MINOR] hostile-reviewer (gpt-oss-review)

    IPv6 endpoint parsing fails in authority_of | ModelBifrostLaneEndpointCapacity.authority_of uses urlsplit followed by rpartition(':') to split host and port. For IPv6 literals such as "[::1]:8000" the colon inside the brackets is treated as part of the host, causing the split to produce an empty host and incorrect port, leading to a ValueError in the validator even though the endpoint is syntactically valid. | Evidence: The _validate_capacity method calls self.endpoint.rpartition(":") without ha

    Resolve this thread when addressed — the Hostile Review Thread Gate blocks while hostile-reviewer threads are unresolved (OMN-17492).

@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

✅ Hostile Reviewer — REVIEWED

Critical findings: 0
Major findings: 4
Total findings: 11
Models succeeded: qwen3-review,gpt-oss-review
Models unavailable: none

Action required: findings were posted as review threads. Address or reject each one, then resolve its thread — the Hostile Review Thread Gate fails while hostile-reviewer threads are unresolved (OMN-17492).


Semantics (OMN-17492 — the model finds, thread resolution gates)

Surface Meaning Blocks merge?
Review threads Per-finding, posted by the reviewer No (informational)
Hostile Review Thread Gate Deterministic: unresolved hostile-reviewer threads exist Fails until resolved (not yet a required context)
degraded verdict Fewer than 2 models succeeded (infra) Fails this job with a named reason

Powered by omniintelligence.review_pairing.cli_review — multi-model adversarial review: qwen3-review (Qwen3.8-27B), gpt-oss-review (gpt-oss-120b) (OMN-8468/OMN-8524/OMN-17492)

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