Skip to content

feat(routes): per-element (per-target) context limits #710

Closed

Description

@dezren39

Support per-element (per-target) context limits in model routes

Today limit: { context } exists only at the route level (landed with the route context-limit feature). A pool whose members need different context ceilings must be expressed by nesting whole routes.

Motivating case (live config, 2026-10-27 redesign)

The small pool needs three elements with two different ceilings:

  • haiku-plan#high at ≤100k
  • luna-plan#xhigh at ≤100k
  • haiku-plan#high at ≤200k

Because per-target limits don't exist, this ships as a nested small-100k sub-route (100k cap) inside small (200k cap) — an extra route id, and the intent ("these elements, these ceilings") is split across two definitions.

Request

Allow limit on individual route targets, composing with the route-level limit:

{ "model": "opencode-route/haiku-plan#high", "limit": { "context": 100000 } }

Semantics to define:

  1. A target is eligible only when the request context fits BOTH the route limit (if any) and the target limit (if any).
  2. Over-limit targets are skipped like other ineligible targets (quota-demoted, disabled, window-closed), with the exclusion visible in the resolved-route dump with its reason.
  3. Nested-route references carrying their own limits keep working unchanged.

Done when

small can be written as one flat route with per-element limits, the dump shows per-element ceilings and skip reasons, and tests cover mixed-ceiling pools.

Acceptance criteria

  • small can be written as one flat route with per-element limit: { context } on individual targets — no nested small-100k sub-route needed (the body's "Done when", restated here as the criteria section).
  • A target is eligible only when the request context fits BOTH the route-level limit (if any) and the target limit (if any); over-limit targets are skipped like other ineligible targets.
  • The resolved-route dump shows per-element ceilings and the skip reason for each over-limit target.
  • Nested-route references carrying their own limits keep working unchanged, and tests cover mixed-ceiling pools.

Activity

  1. added
    kind/featureNew feature or capability request
    priority/normalOrdinary priority (the default)
    effort/mMedium: expected under 1 day of work
    source/humanFiled directly by a human
    meta/enrichedIntake review done: acceptance criteria, links, and normalized labels added
    on Oct 28, 2026
  2. dezren39 commented on Oct 28, 2026

    @dezren39
    Author

    Intake review

    • Related: the route context-limit feature already landed at route level (per the body); the motivating config is the 2026-10-27 routes redesign (small pool, nested small-100k sub-route workaround).
    • Still live: filed 2026-10-28T11:52Z with no labels; a merged-PR search for per-target context limits in this repo returned no resolving PR, and the issue is open and unheld.
    • Notes: the body is unusually complete — motivating case, syntax sketch, and three semantics to define are all pinned. The body carries a "Done when" section; an ## Acceptance criteria section restating it has been appended (original body preserved verbatim above it).
    • Risks: eligibility composition is the subtle part — per-target limits must compose with quota demotion, disabled targets, and window-closed exclusions without changing their precedence, and the dump must attribute the skip to the limit specifically or debugging mixed pools gets harder than the nested-route workaround it replaces.
    • Suggested approach: extend the route-target eligibility check with the target-limit predicate, thread the reason into the resolved-route dump, then convert the live small route to the flat form as the end-to-end proof.
    • Labels normalized by fleet monitor: kind/feature, priority/normal, effort/m, source/human (author dezren39), status/needs-triage, meta/enriched.
  3. added
    app/corePackage: core (pkgs/ or apps/ in this repo)
    queue/claimedA queue worker has claimed the task for this item
    work/assignedAn agent holds this item via the queue (claimed task)
    and removed
    queue/claimedA queue worker has claimed the task for this item
    work/assignedAn agent holds this item via the queue (claimed task)
    on Oct 28, 2026
  4. 46 remaining items

  5. dezren39 commented on Oct 29, 2026

    @dezren39
    Author

    Lane A resumed task 2913 at awaiting_ci on PR #811 head 2bfb0a6.

    CI classification: unit (linux), typecheck, affected, compliance and e2e all pass. basic unit (windows) failed on two tests outside this PR's diff (routes/schema/core only): upgrade command > is registered in root help (30s timeout) and subagent observer lifetime > notifies an idle parent exactly once (timing) — the standing windows timing-flake family. Failed jobs of run 40862768919 re-run.

    Codex gate: all 3 P2 findings dispositioned on their threads — each is already fixed in head 2bfb0a6 (model-resolver.ts:508 last-resort over-limit filter; model-routes.ts:451-462 duplicate-target ceiling merge; generated client types.ts:763 carries limit?: { context: number }).

    Task PARKED for the rerun: merge PR #811 (merge commit) once the windows rerun is green, then close out #710 and complete task 2913.

  6. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    and removed
    queue/claimedA queue worker has claimed the task for this item
    on Oct 29, 2026
  7. dezren39 commented on Oct 29, 2026

    @dezren39
    Author

    Triage verdict: CONFIRMED

    Verified against current main a9452a1546 (2026-10-28):

    • packages/schema/src/config/model-routes.ts:19-47 — TargetObject carries model, defaultVariant, variants, until, cache_format, window — no limit field, so the requested { "model": ..., "limit": { "context": 100000 } } target form cannot be expressed at all today.
    • Same file :259-268 — limit: { context } exists only on Route (route-level), described as capping "the context limit the route presents, below every target's own limit".
    • packages/core/src/config/plugin/model-routes.ts:24-35 — SourceModel carries no per-target limit; expand() propagates none; the presented context at :118-119 is only min(route.limit.context, min leaf context). A grep for context eligibility in model-route.ts / model-route-expansion.ts finds no per-target context check.

    So the nested small-100k sub-route workaround in the live config is currently the only way to express mixed ceilings — exactly as filed.

    Routing: scoped follow-up fix packet enqueued as task 2913 (kind small_fix, queue repo-health-opencode-pilot): add per-target limit to TargetObject, thread it through expand()/SourceModel, compose eligibility with the existing gate/quota/cooldown exclusions with the limit as the recorded skip reason, surface per-element ceilings + skip reasons in the resolved-route dump / route_stats, keep nested-route limits unchanged, and cover mixed-ceiling pools (incl. the flat small 100k/100k/200k case) with tests.

  8. dezren39 commented on Oct 29, 2026

    @dezren39
    Author

    🤖 Agent note · picked up, revalidated, CI rerun triggered — parked awaiting CI

  9. added
    queue/claimedA queue worker has claimed the task for this item
    and removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Oct 29, 2026
  10. removed
    queue/claimedA queue worker has claimed the task for this item
    work/assignedAn agent holds this item via the queue (claimed task)
    on Oct 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    app/corePackage: core (pkgs/ or apps/ in this repo)effort/mMedium: expected under 1 day of workkind/featureNew feature or capability requestmeta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedpriority/normalOrdinary priority (the default)source/humanFiled directly by a human

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions