Skip to content

feat: replace routing heuristics with measured evidence ledgers - #847

Merged
seonghobae merged 4 commits into
feat/model-group-cost-aware-discoveryfrom
feat/anti-heuristic-routing-evidence
Aug 25, 2026
Merged

feat: replace routing heuristics with measured evidence ledgers#847
seonghobae merged 4 commits into
feat/model-group-cost-aware-discoveryfrom
feat/anti-heuristic-routing-evidence

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Summary

Stacked on #834 (ADR 0026). Removes every task-keyword heuristic from the
routing path (ADR 0027):

  • Deletes DOMAIN_HINTS / COMPLEX_HINTS tables and the conduct-hint
    threshold from route selection.
  • Evidence ladder: eligibility contracts -> declaration order
    (-role_fit, -priority, has_affinity, -cosine, id) with cosine affinity
    computed over operator-declared metadata documents via the pool's own
    embedding member (LRU-cached per text hash) -> measured intra-group
    ordering (judged quality first, then stability x EWMA tokens/second).
  • Workflow triage is a strict structured call: exact
    {"workflow_required": bool} or fail closed to conducted orchestration;
    verdicts memoized by content hash.
  • Real-time fast-mlsirm judging on direct routes feeds a second
    Beta-Bernoulli quality ledger; rejects record failures and fail over
    within the retry budget. --no-realtime-judge keeps legacy shape.
  • General-chat capability gate retained in _select_agent as an
    endpoint-compatibility contract (not a heuristic).

Docs

  • ADR: docs/planning/adrs/0027-anti-heuristic-routing-evidence.md
  • APA 7 doctoring: docs/doctoring/measured-routing-evidence.md
    (Jacobson 1988; Gelman et al. 2013; Karpukhin et al. 2020; Ong et al.
    2024; Chen et al. 2023; Zheng et al. 2023; Jeon et al. 2021)
  • New gap baseline: docs/product-technical-gap-baseline.md
  • CHANGELOG updated under Unreleased.

Test plan

  • New tests/test_measured_routing_evidence.py: 29 tests — exact Jacobson
    TPS arithmetic, Laplace-prior stability products, deterministic mock
    embeddings + cosine guards, strict triage parser (7 malformed classes),
    verdict caching, judge accept/reject ledger updates, in-budget failover,
    dual-ledger admin state.
  • Cache-accounting tests pinned to single-step routing so provider-call
    counts stay exact measures of worker executions.
  • Full suite green locally: 1891 unit/contract + 12 fuzz tests.

Open in Devin Review

Remove DOMAIN_HINTS/COMPLEX_HINTS keyword tables; route via eligibility
contracts, declaration priority/capability fit/cosine affinity over
operator-declared metadata, and measured intra-group quality then EWMA
tokens-per-second. Add structured fail-closed triage gas with content-hash
verdict caching and real-time fast-mlsirm judging on direct routes that
feeds a Beta-Bernoulli quality ledger with in-budget failover.

ADR 0027 + doctoring APA 7 references (Jacobson 1988; Gelman et al. 2013;
Karpukhin et al. 2020; Ong et al. 2024; Chen et al. 2023; Zheng et al.
2023; Jeon et al. 2021). Gap baseline added at
docs/product-technical-gap-baseline.md.
@coderabbitai

coderabbitai Bot commented Aug 25, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a00ab7ec-f3f1-49d4-af47-d8bf824093c0

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

devin-ai-integration[bot]

This comment was marked as resolved.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Review remediation on exact head 2abc0d61e54f53d253e85791f208832e6c682fd9:

  • corrected affinity ordering so measured cosine evidence precedes missing evidence within a declaration tier;
  • restored the general-chat boundary in shared chat ranking while explicitly admitting non-chat models only through capability routing;
  • made every routing score use one comparable quantity, posterior stability / EWMA latency (expected successful responses per second); token throughput remains diagnostic evidence;
  • stopped unjudged transport successes from contaminating the quality ledger when real-time judging is disabled;
  • rebased the stack by merging current feat(routing): add operator-managed model groups #834 and reserved ADR 0034.

Evidence: 74 focused tests passed before base refresh; 68 integration/focused tests passed after merging current #834. The pre-refresh full suite completed 1923 passed with two free-model error-precedence regressions; both regressions were fixed and their focused tests passed. Hosted exact-head checks/review remain authoritative.

@seonghobae
seonghobae merged commit 93b8016 into feat/model-group-cost-aware-discovery Aug 25, 2026
1 of 2 checks passed
@seonghobae
seonghobae deleted the feat/anti-heuristic-routing-evidence branch August 25, 2026 11:53

@devin-ai-integration devin-ai-integration 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.

Devin Review found 4 new potential issues.

Open in Devin Review

Comment on lines 10715 to 10716
**self.policy.as_dict(),
"roles": list(self.ROLE_TAGS),

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.

🔍 Admin console load crashes on removed hints field

admin_state no longer emits complex_hints, but the console's load still reads state.policy.complex_hints.length. The field is now undefined, so reading .length throws and aborts load before agents, secondary views, and the simulator render, leaving the console blank.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +3275 to +3288
if not self.policy.realtime_judge:
return {
"accepted": True,
"reason": "single route path",
"verifier_output": answer,
"judge": "model",
}
fallback_report = {"verifier_output": answer}
base = self._model_judge_verification(
text, fallback_report, free_only=free_only
)
accepted = bool(base.get("accepted"))
_record(accepted)
return base

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.

🔍 Default real-time judge degrades routing without an installed judge

realtime_judge defaults on. When the fast-mlsirm judge cannot be resolved, _model_judge_verification returns accepted=False, so route_once rejects every direct answer, spends an extra failover call, returns the answer marked unaccepted, and records a quality-ledger failure for each member. Uniform failures then drive _measured_member_order, flattening intra-group ranking. Deployments without a judge must set --no-realtime-judge.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines 4109 to +4118
def _needs_workflow(self, text: str) -> bool:
lowered = text.lower()
hits = sum(1 for hint in self.COMPLEX_HINTS if hint in lowered)
return hits >= self.policy.conduct_hint_threshold or len(text) > self.policy.route_text_length_threshold
"""Route-vs-conduct decision from a strict structured triage verdict.

Keyword hint tables are intentionally absent: keyword matching cannot
handle negation, mixed language, or tasks that quote trigger words, and
hand-tuned thresholds are not evidence. The verdict comes from one
exact-schema model call (cached by content hash) and fails closed to
the orchestrated path on any uncertainty.
"""
return bool(self._triage_fn(text))

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.

📝 Info: Auto-mode triage now issues a blocking model call

_needs_workflow now delegates to a structured triage model call (content-hash cached), so would_route and _dispatch issue a synchronous provider request on cache miss where none existed before. Mock transports cannot emit the strict JSON, so they fail closed and route every auto-mode request to conduct unless _triage_fn is overridden.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +3211 to +3218
verification = self._realtime_route_judge(
text=text,
answer=answer,
served_id=served_id,
latency_seconds=latency_seconds,
usage=attempt_usage,
free_only=free_only,
)

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.

🔍 Judge and triage provider calls are not billed

The real-time route judge and triage each issue provider requests that never enter the run trace, so spend_analytics (which sums trace-row usage) under-reports the token cost of auto/route traffic while realtime_judge is on.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

seonghobae added a commit that referenced this pull request Aug 26, 2026
* feat(routing): add operator-managed model groups

* fix(api): enforce model group create semantics

* fix(routing): preserve eligibility and REST contracts

* docs(groups): remove ephemeral model example

* fix(groups): route advertised aliases end to end

* ci: hourly OpenCode maintenance agent routed through this gateway (#835)

* ci: add hourly OpenCode maintenance agent routed through this gateway

The scheduled job boots the contextual-orchestrator gateway with the five
org provider secrets seeded into the process-local KV registry (bootstrap
transport only), auto-discovers chat-capable models, assigns the ox-alpha
measured-routing group across OpenRouter + OpenCode Zen aliases, then runs
the pinned OpenCode CLI pointed at http://127.0.0.1:8000/v1 with model
'ox-alpha' so the agent's own traffic exercises group routing.

The agent works the PR queue (review -> fix -> recheck -> merge),
root-causes failing checks, and advances
docs/product-technical-gap-baseline.md when the PR queue is empty.
COPILOT_GITHUB_TOKEN is not used; the existing review-agent key scheme is
untouched.

* fix(ci): remove ephemeral model binding

* fix(ci): install gateway and grant branch writes

* fix(groups): preserve internal dispatch default

* fix: isolate model group routing evidence

* fix: preserve conduct semantics for model groups

* ci: minimize hourly loop permissions and installs

* fix: measure streamed group routing

* feat: route model groups across modalities (#837)

* feat: normalize and edit model groups (#838)

* fix: preserve capability routing contracts

* release: v0.2.0 — model groups, cost-aware discovery, changelog baseline

Bump 0.1.0 -> 0.2.0 and add the canonical Keep-a-Changelog file with the
0.1.0 baseline and the 0.2.0 additions (operator-managed model groups,
measured group routing, OpenCode Zen discovery + free-tier
classification, Strix B105 root-cause remediation).

* fix(discovery): tolerate null modality arrays

* docs: specify model group product and technical contracts

* release: align v0.2.0 changelog and lock metadata

* feat: stream orchestrated reasoning summaries

* fix: keep free reasoning streams fail closed

* fix: preserve free routing evidence and analytics

* fix: distinguish failed Responses streams in analytics

* fix: pin structured free judge to selected agent

* fix: lock container dependencies and virtual capabilities

* fix: keep free passthrough on zero-cost models

* fix: prune removed routing measurements

* refactor: remove unreachable responses passthrough branch

* fix: route virtual models across media capabilities

* fix: retain reset candidate routing rows

* fix: preserve Responses instructions in workflows

* test: align model-group missing-member code with canonical agent_not_found

#831 unified worker-agent not-found errors on agent_not_found; the
model-group CRUD contract now asserts that same canonical code.

* fix(api): model-group creation returns canonical agent_not_found for unknown members

* ci: route hourly OpenCode loop through auto

* fix: reject unsupported orchestrated structured output

* docs: correct Responses stream options error

* fix: retrieve URL-encoded model identifiers

* fix: measure free capability and failover routing

* fix: resolve model group review findings

* fix: close model group integration gaps

* fix: align provider inventory and session cache scope

* fix: harden compose secrets and repeated reasoning summaries

* fix: contain binary response disconnects

* fix: ground Zen free discovery in structured costs

* fix: keep group judge within allowed members

* fix: preserve free catalog evidence across reloads

* docs: assign unique model-group ADR number

* fix: preserve catalog capability evidence

* fix: preserve declared Bytez endpoint capabilities

* fix: validate batch model identity at ingress

* fix(api): normalize missing model group errors

* docs(prd): align product bets with model groups

* fix(discovery): filter chat-only Bytez transports

* docs(adr): reserve model-group decision identifier

* feat: replace routing heuristics with measured evidence ledgers (#847)

* feat: replace routing heuristics with measured evidence ledgers

Remove DOMAIN_HINTS/COMPLEX_HINTS keyword tables; route via eligibility
contracts, declaration priority/capability fit/cosine affinity over
operator-declared metadata, and measured intra-group quality then EWMA
tokens-per-second. Add structured fail-closed triage gas with content-hash
verdict caching and real-time fast-mlsirm judging on direct routes that
feeds a Beta-Bernoulli quality ledger with in-budget failover.

ADR 0027 + doctoring APA 7 references (Jacobson 1988; Gelman et al. 2013;
Karpukhin et al. 2020; Ong et al. 2024; Chen et al. 2023; Zheng et al.
2023; Jeon et al. 2021). Gap baseline added at
docs/product-technical-gap-baseline.md.

* fix: keep routing evidence units and capability boundaries honest

* fix(admin): tolerate unavailable model-group state

* docs(loop): require PRD and measured web capacity

* fix(admin): remove retired policy hint metric

* fix(routing): validate evidence before mutation

* fix(discovery): remove model-name free inference guidance

* fix: complete #834 model-group persistence on the normalized agent-pool schema

- model_group/model_group_member relations compose with main's normalized
  agent_pool (no JSON shadow); save() maintains membership, load_all()
  restores group_name via join.
- Legacy payload promotion reads agent_pool_legacy_payloads during the
  migration window and drops it after promoting group names.
- DB-naming gate now extracts SQL from AST string constants so prose in
  comments can no longer produce false identifier violations.
- Batch runner signature aligned (messages, mode, model) with the merged
  LocalBatchBackend; stream-route fake accepts the merged caller kwargs.

* test: case-sensitive DDL pattern so prose cannot fake identifiers

* docs: refresh protected-main gap evidence

* docs: record exact provider regression suite

* docs: correct exact provider head

* fix(admin): make guidance customer-actionable

* fix(admin): remove internal terms from customer copy

* docs(ui): record customer-copy screenshot audit

* test(ci): lock hourly orchestrator loop contract

* fix: replace synthetic admin status with truthful empty states

* docs: refresh exact-head remediation baseline

* fix(stream): cancel orchestration after Responses disconnect

* test: align boundary contracts with current routing

* docs: complete public boundary docstrings

* docs: refresh exact-head product gap queue

* test: enforce complete public docstrings

* ci: enforce protected exact-head merge loop
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