omp-llm-role 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +202 -12
- package/agents/designer.md +4 -3
- package/docs/dev/README.md +44 -7
- package/docs/dev/agent-authoring.md +59 -1
- package/docs/dev/architecture.md +106 -28
- package/docs/dev/ci.md +163 -0
- package/docs/dev/current-state.md +364 -24
- package/docs/dev/data-sources.md +231 -38
- package/docs/dev/explorer.md +175 -46
- package/docs/dev/quirks.md +77 -4
- package/docs/dev/releasing.md +130 -17
- package/docs/dev/scoring.md +851 -27
- package/docs/dev/testing.md +253 -0
- package/docs/dev/writes-and-state.md +232 -28
- package/docs/llm-role-rankings.md +149 -148
- package/package.json +814 -80
- package/skills/omp-llm-role-create-agent/SKILL.md +7 -1
- package/src/agent-architect.ts +148 -19
- package/src/agent-create.ts +800 -40
- package/src/agent-file.ts +2 -5
- package/src/architect-provenance.ts +16 -0
- package/src/availability.ts +191 -15
- package/src/benchmark-author.ts +9 -4
- package/src/benchmark-sources.ts +283 -18
- package/src/cli/create-role.ts +29 -1
- package/src/cli/llm-role-rank.ts +40 -1
- package/src/config-edit.ts +207 -80
- package/src/engine.ts +519 -75
- package/src/error-report.ts +562 -0
- package/src/explorer/boot.ts +36 -24
- package/src/explorer/explain.ts +128 -13
- package/src/explorer/scopes.ts +110 -0
- package/src/explorer/server.ts +126 -33
- package/src/extension.ts +464 -48
- package/src/features.ts +105 -0
- package/src/project-registry.ts +65 -0
- package/src/project-setup.ts +382 -0
- package/src/prompts/agent-creation-architect.md +2 -0
- package/src/prompts/project-profile-architect.md +33 -0
- package/src/prompts/project-profile-user.md +8 -0
- package/src/provider-display.ts +67 -0
- package/src/role-archetypes.ts +12 -2
- package/src/role-settings.ts +22 -0
- package/src/settings.ts +211 -24
- package/src/state.ts +1 -1
- package/src/updater.ts +234 -37
- package/web/app.js +434 -12
- package/web/index.html +1 -0
- package/web/style.css +44 -1
- package/docs/dev/spec.md +0 -633
package/docs/dev/scoring.md
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
# Scoring
|
|
2
2
|
|
|
3
|
-
Maintainer reference for the ranking math
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
and the measured findings behind the shipped weights. All math is in
|
|
3
|
+
Maintainer reference for the ranking math: the exact transforms, the invariants
|
|
4
|
+
a weight change must preserve, and the measured findings behind the shipped
|
|
5
|
+
weights. All math is in
|
|
7
6
|
`src/engine.ts`; the shipped role defs are `DEFAULT_ROLES` in `src/settings.ts`;
|
|
8
7
|
the archetype sets are `src/role-archetypes.ts`.
|
|
9
8
|
|
|
@@ -16,9 +15,9 @@ rank compression (real magnitude gaps now count) and field-dependent scales.
|
|
|
16
15
|
|
|
17
16
|
| Class | Metrics | Transform | Anchors |
|
|
18
17
|
|---|---|---|---|
|
|
19
|
-
| index | `general`, `reasoning`, `math`, `code`, `agents`, `search`, `vision`, `tool_calling`, `long_context` | `(v+20)/80` | −20→0, +60→1; extrapolates outside (no clamp) |
|
|
18
|
+
| index | `general`, `reasoning`, `math`, `code`, `agents`, `search`, `vision`, `tool_calling`, `long_context`, `index_communication`, `index_finance`, `index_healthcare`, `index_legal` | `(v+20)/80` | −20→0, +60→1; extrapolates outside (no clamp) |
|
|
20
19
|
| benchmark, chance-anchored | `gpqa` | `(v−0.25)/0.75` | 4-way multiple choice, chance 0.25 |
|
|
21
|
-
| benchmark, raw | `mrcr`, `aime`, `swe_bench`, `arc_agi`, `terminal_bench`, `tau_bench` | identity | pass rate 0–1, chance ≈ 0 |
|
|
20
|
+
| benchmark, raw | `mrcr`, `aime`, `swe_bench`, `arc_agi`, `terminal_bench`, `tau_bench`, `simpleqa_score`, `hle_score`, `mmmu_score`, `mmmu_pro_score`, `mmmlu_score`, `browsecomp_score`, `swe_bench_pro_score`, `mcp_atlas_score`, `apex_agents_score`, `osworld_score`, `scicode_score`, `screenspot_pro_score`, `charxiv_r_score`, `frontiermath_score`, `toolathlon_score` | identity | pass rate 0–1, chance ≈ 0 |
|
|
22
21
|
| throughput | `throughput` | `ln(v/10)/ln(30)` | 10→0, 300→1; clamped to [0,1] |
|
|
23
22
|
| percentile / score | `website`, `writing` | identity | already 0–1 |
|
|
24
23
|
| external benchmark | `bench:<id>`, `<ns>:<local>` | identity | normalized to 0–1 at parse time (`score / scoreMax`), so no new transform class |
|
|
@@ -35,13 +34,14 @@ rank compression (real magnitude gaps now count) and field-dependent scales.
|
|
|
35
34
|
**Invariant — forward and inverse must agree.** The explorer's "what would it
|
|
36
35
|
take to move up" targets come from `inverseCardinal(metric, t)`
|
|
37
36
|
(`src/explorer/explain.ts`), which must invert `cardinalMetric` for every
|
|
38
|
-
weightable metric. It handles `index` (`t·80−20`)
|
|
39
|
-
null outside [0,1]) and
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
not 0.5. Before adding a metric to
|
|
43
|
-
`cardinalMetric` and `inverseCardinal` handle
|
|
44
|
-
metric needs a matching inverse (read
|
|
37
|
+
weightable metric. It handles `index` (`t·80−20`), `throughput` (`10·30^t`,
|
|
38
|
+
null outside [0,1]), and a chance-anchored metric (`t·(1−chance)+chance`, reading
|
|
39
|
+
`BENCHMARK_CHANCE` from the engine so the two can never drift); everything else
|
|
40
|
+
is identity. Forward and inverse therefore agree for every weightable metric —
|
|
41
|
+
`gpqa`'s `t = 0.5` maps to raw 0.625, not 0.5. Before adding a metric to
|
|
42
|
+
`KNOWN_METRICS`, check that both `cardinalMetric` and `inverseCardinal` handle
|
|
43
|
+
its transform; a chance-anchored metric needs a matching inverse (read
|
|
44
|
+
`BENCHMARK_CHANCE`).
|
|
45
45
|
|
|
46
46
|
## Quality composite `q`
|
|
47
47
|
|
|
@@ -78,7 +78,198 @@ value = q − λ · priceEff
|
|
|
78
78
|
model will actually run the role's level (see below); otherwise it is the bare
|
|
79
79
|
billed price.
|
|
80
80
|
- `value` is the sort key; ties break score desc → blended $/M asc → id asc
|
|
81
|
-
(determinism
|
|
81
|
+
(determinism).
|
|
82
|
+
|
|
83
|
+
### Cache-read pricing (cache-hit rate)
|
|
84
|
+
|
|
85
|
+
A role may declare an assumed **cache-hit rate** for its input tokens
|
|
86
|
+
(`roles.<role>.cacheHitRate`, 0–1; `0`/absent = off). Agent loops resend the
|
|
87
|
+
same system prompt every turn, so a cache-heavy role's invoice is dominated by
|
|
88
|
+
cache reads; the knob prices that, opt-in, without touching any shipped role.
|
|
89
|
+
|
|
90
|
+
- the route's billed price is `price = (3·input + output)/4` on the **listed**
|
|
91
|
+
input price; a hit rate `h` blends the endpoint's cache-read price into the
|
|
92
|
+
input term, `effInput = h·cacheRead + (1−h)·input`, giving
|
|
93
|
+
`billed = price + 3·(effInput − input)/4` (the output term is unchanged);
|
|
94
|
+
- `blendRoutePool(routes, cacheHitRate)` weights by **`1/listedInput²`** — the
|
|
95
|
+
router's sort key — so the hit rate changes the per-route billed price, not the
|
|
96
|
+
routing probability: a cheap cache on a lightly-weighted route does not
|
|
97
|
+
dominate (user story 9);
|
|
98
|
+
- a route with **no cache-read price** keeps its full input price
|
|
99
|
+
(`cacheReadPrice = null` → `effInput = input`), so missing data is not a silent
|
|
100
|
+
discount;
|
|
101
|
+
- `endpointFilteredModel(model, filters, cacheHitRate)` recomputes the blend when
|
|
102
|
+
the role declares endpoint filters **or** a non-zero hit rate; the hit rate
|
|
103
|
+
composes with the filters (filter the pool first, then cache-price it);
|
|
104
|
+
- `roleEffectivePrice`/`routeEffectivePrice` is the single per-route accessor the
|
|
105
|
+
blend, the pinned-route path and `roleMetricValue` share; a pinned role prices
|
|
106
|
+
its route's cache-adjusted billed price, and `maxPriceUsdPerM` caps the
|
|
107
|
+
thinking-adjusted `priceEff` (the same cap as the blend path);
|
|
108
|
+
- `explainModel` mirrors all of it, carries `role.cacheHitRate`, and reports the
|
|
109
|
+
cache-adjusted `cost.billedPrice`; the SPA cost line appends `· cache <rate>`
|
|
110
|
+
when the rate is set;
|
|
111
|
+
- with `cacheHitRate = 0` (absent) every path is **byte-identical** to the
|
|
112
|
+
uncached ranking. `resolveSettings` validates the rate to `[0, 1]` (a typo
|
|
113
|
+
cannot silently halve or double the price).
|
|
114
|
+
|
|
115
|
+
### Route-aware pricing (provider pin)
|
|
116
|
+
|
|
117
|
+
A role may pin its requests to one OpenRouter provider route
|
|
118
|
+
(`roles.<role>.providerPin`). When it does, the role is priced by that
|
|
119
|
+
route instead of the `1/price²` blend:
|
|
120
|
+
|
|
121
|
+
- `pinnedRoute(model, pin)` (`src/engine.ts`) resolves the model's route by
|
|
122
|
+
**exact, tiered-verbatim** `providerSlug` — `deepinfra` and `deepinfra/fp8`
|
|
123
|
+
are different routes, with no normalization — and returns `null` on no match.
|
|
124
|
+
- `priceEff` is the route's billed 3:1 price (cache-adjusted by the role's
|
|
125
|
+
`cacheHitRate` when set, see *Cache-read pricing*), scaled by the same
|
|
126
|
+
thinking factor and gated by the same `runsAtLevel` rule as an unpinned role:
|
|
127
|
+
the pin changes the base price, not the thinking math.
|
|
128
|
+
- the `throughput` weight reads the route's p50, falling back to the model's
|
|
129
|
+
blended throughput when the route carries no p50 — a sparse route must not
|
|
130
|
+
zero the metric (an absent p50 is unknown, not slow).
|
|
131
|
+
- `maxPriceUsdPerM` caps the pinned route price (the thinking-adjusted price the
|
|
132
|
+
role actually pays), like the blend cap.
|
|
133
|
+
- `roleMetricValue(model, metric, route, cacheHitRate)` is the accessor `rankRole`
|
|
134
|
+
and `explainModel` share: for a pinned role it returns the route's cache-adjusted
|
|
135
|
+
billed price (`routeEffectivePrice`) and `throughput`, and the model's own value
|
|
136
|
+
for every other metric.
|
|
137
|
+
- a model with **no matching route** is ineligible for that role
|
|
138
|
+
(`providerPinDrops` → `Decision.pinBlocked`, rendered `; pin-blocked: …`);
|
|
139
|
+
`explainModel` reports "no route matches the role's provider pin".
|
|
140
|
+
- an **unpinned** role ignores `routes` entirely — the blend path is unchanged —
|
|
141
|
+
**unless** it sets the soft `preferOwnProvider` policy (the `providerPinning`
|
|
142
|
+
capability), which prices it on its **best route** (the max-value-for-money
|
|
143
|
+
candidate route; see *Route ordering* and *Capability presets*).
|
|
144
|
+
|
|
145
|
+
The pin is a cost-and-throughput posture, not a quality edit: it moves the price
|
|
146
|
+
axis to the route's billed price and the throughput axis to the route's p50,
|
|
147
|
+
while every other weighted metric stays the model's own.
|
|
148
|
+
|
|
149
|
+
### Route ordering (the value-for-money score)
|
|
150
|
+
|
|
151
|
+
`rankedRoutes(model, def)` (`src/engine.ts`) is the one function that orders a
|
|
152
|
+
model's candidate routes; `bestRoute` is `rankedRoutes[0]`, and `roleRoute` (the
|
|
153
|
+
route `rankRole` prices the model on) and the updater's auto-pin both read it, so
|
|
154
|
+
the priced route, the written pin and the fallback chain move together.
|
|
155
|
+
|
|
156
|
+
- **Candidates.** A route is a candidate when it is non-degraded (`status === 0`),
|
|
157
|
+
passes `routePassesEndpointFilters(route, def.filters)`, carries a usable billed
|
|
158
|
+
price, and (when `filters.maxPriceUsdPerM > 0`) a thinking-adjusted price at or
|
|
159
|
+
below the cap. The allowed-providers whitelist is applied upstream by pruning
|
|
160
|
+
`m.routes` (see *Whitelist-aware route selection*).
|
|
161
|
+
- **The score.** Each candidate is scored
|
|
162
|
+
`vfm = wT·tNorm − wP·pNorm`, where `tNorm`/`pNorm` are the route's p50
|
|
163
|
+
throughput and cache-adjusted billed price **min/max-normalized over the
|
|
164
|
+
candidate set** (`tNorm = (tput − tMin)/(tMax − tMin)`, `pNorm = (priceEff −
|
|
165
|
+
pMin)/(pMax − pMin)`; a zero span normalizes to 0), and `wT =
|
|
166
|
+
wTput/(wPrice+wTput)`, `wP = wPrice/(wPrice+wTput)`. Sort desc; ties break by
|
|
167
|
+
`providerSlug` then `id`, so a re-run is deterministic. A route with no p50 uses
|
|
168
|
+
the model's blended throughput (an absent p50 is unknown, not slow).
|
|
169
|
+
- **The soft floor.** `filters.preferredMinThroughput` (tok/s; `0`/absent = off)
|
|
170
|
+
is a **preference, not a gate**: routes at or above the floor sort before
|
|
171
|
+
routes below it, and the score orders within each band. A below-floor route is
|
|
172
|
+
**never dropped** — it stays a last-resort candidate.
|
|
173
|
+
- **`routeValue` is deleted.** The old `q(route p50) − λ·route price` route sort
|
|
174
|
+
key is gone; the score above is the only route basis. (The model-level
|
|
175
|
+
`value = q − λ·priceEff` is unchanged — see *`λ` and `value`*.)
|
|
176
|
+
|
|
177
|
+
### Whitelist-aware route selection
|
|
178
|
+
|
|
179
|
+
The updater narrows every model's route pool to the account's
|
|
180
|
+
**allowed-providers privacy whitelist** before ranking (data-sources.md,
|
|
181
|
+
*OpenRouter — allowed-providers whitelist*; architecture.md, *Data flow*). The
|
|
182
|
+
prune is the single change point — `roleRoute`, `bestRoute`, `rankedRoutes` and
|
|
183
|
+
`endpointFilteredModel` all read `m.routes` — so every route consumer above is
|
|
184
|
+
whitelist-aware: a hard `providerPin` on a blocked provider matches no route and
|
|
185
|
+
drops the model (`providerPinDrops`), the soft `preferOwnProvider` basis prices
|
|
186
|
+
each model on its best **allowed** route, the endpoint-filtered blend is computed
|
|
187
|
+
over the allowed pool, and the fallback chains carry only allowed routes. A
|
|
188
|
+
`null` whitelist (no whitelist set, harvest failed) leaves every pool untouched,
|
|
189
|
+
so the ranking is byte-identical to today. The whitelist is a route-selection
|
|
190
|
+
filter, not a re-pricing: the role-independent `1/price²` blend (`m.price`/
|
|
191
|
+
`m.throughput`) is left as the account-agnostic expected value, and a model with
|
|
192
|
+
no allowed route keeps that blend (the soft basis never drops a model).
|
|
193
|
+
|
|
194
|
+
## Capability presets (feature flags)
|
|
195
|
+
|
|
196
|
+
One named flag per opt-in capability (`features.<id>` global,
|
|
197
|
+
`roles.<role>.features.<id>` per role) applies the plugin's recommended settings
|
|
198
|
+
to a role. The registry (`FEATURES` in `src/features.ts`) is the single source of
|
|
199
|
+
truth; `expandFeatures(authored, globalFlags)` is the single implementation of
|
|
200
|
+
the precedence rule, called by `resolveSettings` (per role) and by the explorer's
|
|
201
|
+
`/api/rank`/`/api/explain` on the posted def. The rule:
|
|
202
|
+
|
|
203
|
+
```
|
|
204
|
+
effective def = shipped default ⊕ preset(enabled flags) ⊕ explicit user keys
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
A flag is on when `roles.<role>.features.<id>` is present (it wins either way)
|
|
208
|
+
and otherwise when the global `features.<id>` is `true`; the preset fills only
|
|
209
|
+
knobs the authored def does not already set, and an explicit key is merged last,
|
|
210
|
+
so it always wins. Every flag ships **off** and no shipped role sets one, so with
|
|
211
|
+
no flags the resolved roles are byte-identical to `DEFAULT_ROLES`. The effective
|
|
212
|
+
def is what `rankRole`/`explainModel` see; the authored def (flags + explicit
|
|
213
|
+
keys) is what the explorer edits and exports.
|
|
214
|
+
|
|
215
|
+
What each recommendation does to the ranking math (grounded on the 2026-10-09
|
|
216
|
+
cache, `default` role, 146 eligible; the `providerPinning` bullet is re-measured
|
|
217
|
+
on the 2026-10-11 cache):
|
|
218
|
+
|
|
219
|
+
- **`endpointCeilings`** (`filters.tools: true`, `filters.minOutputTokens:
|
|
220
|
+
16384`) drops tool-incapable routes and routes whose output ceiling is below
|
|
221
|
+
16 384 tokens from the priced pool (see *Endpoint filters*): 146 → 135
|
|
222
|
+
eligible, leader unchanged (`deepseek-v4.1-flash`, 0.37 $/M). 16 384 is the
|
|
223
|
+
video's own threshold (19 endpoints cap output at or below it).
|
|
224
|
+
- **`cachePricing`** (`cacheHitRate: 0.5`) reprices the role on a cache-heavy
|
|
225
|
+
loop's invoice (see *Cache-read pricing*): 146 eligible, leader unchanged, its
|
|
226
|
+
`priceEff` 0.3732 → 0.3522 (−5.6 %). 0.5 is the low end of the measured
|
|
227
|
+
third-party range (51–69 %), so the preset never over-credits a cache.
|
|
228
|
+
- **`providerPinning`** (`{ preferOwnProvider: true, filters: {
|
|
229
|
+
preferredMinThroughput: 50 } }`) prices a model on its **best route** — the
|
|
230
|
+
max-value-for-money candidate route (see *Route ordering*: the `vfm` score
|
|
231
|
+
desc, with the soft 50 tok/s floor sorting below-floor routes last) among the
|
|
232
|
+
routes that pass the role's endpoint filters and the account's
|
|
233
|
+
allowed-providers whitelist (see *Whitelist-aware route selection*) — falling
|
|
234
|
+
back to
|
|
235
|
+
the default `1/price²` blend only when the model has no candidate route. It is
|
|
236
|
+
a **per-model policy, not a scalar** — the sensible pin differs per model, so
|
|
237
|
+
the bundle carries a policy field evaluated against the model's own routes at
|
|
238
|
+
rank time, not a slug baked into the lock file. `bestRoute` (`src/engine.ts`)
|
|
239
|
+
is `rankedRoutes(model, def)[0]` (see *Route ordering* for the candidate
|
|
240
|
+
criteria and the score). The basis is **soft**: a model with no
|
|
241
|
+
candidate route keeps the blend and is never dropped, so the capability
|
|
242
|
+
**never changes eligibility** (unlike the hard `providerPin`, which drops a
|
|
243
|
+
model with no matching route). The `maxPriceUsdPerM` gate is **basis-independent**:
|
|
244
|
+
with no hard pin it caps the model's own blend price, not the soft route's, so
|
|
245
|
+
the flag can neither add nor drop a model; the candidate-route cap filter only
|
|
246
|
+
keeps the written pin at or below the cap. Measured coverage on the 2026-10-11 cache: all
|
|
247
|
+
144 routed models have a candidate route (the old own-lab slug-prefix rule
|
|
248
|
+
matched only 51 of 149), so the capability covers the whole routed field. The
|
|
249
|
+
resolved route is the same basis a hard pin uses, so the preference moves the
|
|
250
|
+
**throughput** axis as well as the billed price — a role that routes to the
|
|
251
|
+
best endpoint gets that endpoint's p50 tok/s, not the blend's. Measured on the
|
|
252
|
+
2026-10-11 cache (`rankRole` over the full model set), the `default` leader is
|
|
253
|
+
`deepseek-v4.1-flash` either way: the blend prices it at `priceEff` 0.2317 /
|
|
254
|
+
`value` 0.8056 / `q` 0.8069, while the soft best-route basis prices it at
|
|
255
|
+
`priceEff` 0.1187 / `value` 0.8092 / `q` 0.8099 on its best route `decart/fp4`
|
|
256
|
+
($0.0639 billed, 72 tok/s). The soft route is cheaper than the blend, so
|
|
257
|
+
`priceEff` falls and `value` rises; `q` moves too because the route's p50
|
|
258
|
+
throughput replaces the blend's. That is deliberate (the pin path has always
|
|
259
|
+
priced and measured on the pinned route); a role that wants the blend's
|
|
260
|
+
throughput should leave the flag off.
|
|
261
|
+
- **`costCap`** (`filters.maxPriceUsdPerM: 10`) drops the priciest tail of the
|
|
262
|
+
eligible pool: 146 → 137 (the top ≈6 %), leader unchanged. The pool's p90 is
|
|
263
|
+
7.8 and p95 11.1 $/M, and every role leader sits at 0.20–3.71 $/M, so the
|
|
264
|
+
preset never excludes today's leader.
|
|
265
|
+
|
|
266
|
+
**Interaction with the switch hysteresis.** `switchMargin`/`priceSwitchFraction`
|
|
267
|
+
compare a challenger against the incumbent on `value` and `priceEff`. A flag that
|
|
268
|
+
reprices the **whole field** (`cachePricing`, `providerPinning`) moves **both
|
|
269
|
+
sides** of that comparison, so it can hold a switch that would otherwise happen
|
|
270
|
+
(or vice versa). Flip such a flag **between runs**, not mid-day: the day gate
|
|
271
|
+
stamps one run per UTC day, and a mid-day flag change would compare a
|
|
272
|
+
half-repriced field against a stale incumbent.
|
|
82
273
|
|
|
83
274
|
## Eligibility
|
|
84
275
|
|
|
@@ -88,12 +279,43 @@ A model ranks for a role only when:
|
|
|
88
279
|
**independent of weights** — the shipped defaults require `throughput`
|
|
89
280
|
without weighting it, so validation checks `required ⊆ KNOWN_METRICS`, not
|
|
90
281
|
`required ⊆ weights`);
|
|
91
|
-
- it has a billed price (`m.price != null
|
|
92
|
-
|
|
282
|
+
- it has a billed price (`m.price != null`; a pinned role uses its matching
|
|
283
|
+
route's price — see *Route-aware pricing*);
|
|
284
|
+
- `filters.image` (if set) is satisfied (`m.multimodal`);
|
|
285
|
+
- the role's **endpoint filters** (if any) are satisfied (below);
|
|
286
|
+
- for a **pinned** role, the model has a route matching `providerPin`
|
|
287
|
+
(`pinnedRoute != null`) — a route-less model is ineligible.
|
|
288
|
+
|
|
289
|
+
### Endpoint filters
|
|
290
|
+
|
|
291
|
+
`RoleDef.filters` carries four endpoint filters beyond `image`:
|
|
292
|
+
`tools` (boolean), `minContextTokens`, `minOutputTokens` and `maxPriceUsdPerM`
|
|
293
|
+
(numbers; `0`/`false` = off). They gate the **eligible standard-tier route pool**
|
|
294
|
+
— the same pool the `1/price²` blend uses — before the blend:
|
|
93
295
|
|
|
94
|
-
`
|
|
95
|
-
`
|
|
96
|
-
`
|
|
296
|
+
- `routePassesEndpointFilters` drops a route failing any declared filter; a
|
|
297
|
+
`null` capability field is **kept** (missing data is not a capability failure);
|
|
298
|
+
- `modelPassesEndpointFilters` requires at least one surviving route — a model
|
|
299
|
+
whose every standard-tier route fails (or that has no route data) is
|
|
300
|
+
ineligible, and the single-find-route fallback does not resurrect it;
|
|
301
|
+
- `minContextTokens` filters the **endpoint** `context_length`, not the
|
|
302
|
+
model-level `context`;
|
|
303
|
+
- `maxPriceUsdPerM` caps the thinking-adjusted `priceEff` (the price the role
|
|
304
|
+
actually pays), not the bare billed blend. For a **pinned** role that is the
|
|
305
|
+
pin route's price; for a soft `preferOwnProvider` role it is the model's own
|
|
306
|
+
blend price (basis-independent, so the flag cannot change eligibility), while
|
|
307
|
+
the candidate-route filter keeps the auto-pin at or below the cap;
|
|
308
|
+
- a role that declares `tools`/`minContextTokens`/`minOutputTokens` is **priced**
|
|
309
|
+
on the surviving pool: `endpointFilteredModel` recomputes `price`/`throughput`
|
|
310
|
+
as the `1/price²` blend over the routes that clear the filters
|
|
311
|
+
(`blendRoutePool`), so the role is priced on the routes the router would
|
|
312
|
+
actually choose from — not the model's full-route blend. No endpoint filter
|
|
313
|
+
leaves the model's own blend unchanged.
|
|
314
|
+
|
|
315
|
+
`endpointFilterDrops(def, models)` lists the ranking ids the gate removed (they
|
|
316
|
+
pass every other eligibility gate but have no capable route) for the decision
|
|
317
|
+
log. `resolveSettings` validates the four endpoint-filter keys plus the soft
|
|
318
|
+
`filters.preferredMinThroughput`; no shipped role sets an endpoint filter.
|
|
97
319
|
Filters apply before ranking eligibility so percentile norms stay on the
|
|
98
320
|
unfiltered pool.
|
|
99
321
|
|
|
@@ -134,6 +356,20 @@ instead of 0, so absence is not a coverage penalty. None of the three may be a
|
|
|
134
356
|
fill. Making it per-metric is a one-line change (`CAPABILITY_FILL`).
|
|
135
357
|
- The report marks a filled value `~` in the model column.
|
|
136
358
|
|
|
359
|
+
### The 0-fill posture
|
|
360
|
+
|
|
361
|
+
`code`, `agents`, `tool_calling`, `math` and `vision` are deliberately
|
|
362
|
+
**0-filled** — a missing value scores 0, not the capability fill. This is a
|
|
363
|
+
cost-conservative choice, not an oversight: capability-filling them at 0.195
|
|
364
|
+
promotes expensive models, because the fill lifts every uncovered model's `q`
|
|
365
|
+
and the expensive models are the ones the source tends to cover. Measured on the
|
|
366
|
+
2026-10-03 caches, filling these metrics flips `slow` #1 muse-spark-1.3 →
|
|
367
|
+
gpt-6-astra and `plan` #1 hy4-preview → gpt-5.6-sol. The 0-fill keeps the
|
|
368
|
+
ranking on the models the source actually measured; the cost is that a model
|
|
369
|
+
missing a weighted metric is penalized for a coverage gap (see rule 4), which is
|
|
370
|
+
why the defaults weight these metrics at reduced share and never add them to
|
|
371
|
+
`required`.
|
|
372
|
+
|
|
137
373
|
## Thinking price factor
|
|
138
374
|
|
|
139
375
|
Roles with a `thinking` level rank on the thinking-adjusted price.
|
|
@@ -195,6 +431,136 @@ Naming the archetype's own specialist set is a no-op (the focus share equals its
|
|
|
195
431
|
archetype share). A named metric already in the weights is reported as a
|
|
196
432
|
duplicate; a name outside the known-metric set is unknown.
|
|
197
433
|
|
|
434
|
+
**The nine-axis focus-metric gate.** A focus metric that is fill-0 and covers too
|
|
435
|
+
little of the field turns `q` into a coverage score (a missing weighted metric
|
|
436
|
+
contributes 0 while occupying its denominator share). `assessFocusMetric(models,
|
|
437
|
+
metric, declared, source?)` (`src/agent-create.ts`) is the one rule, returning a
|
|
438
|
+
`FocusMetricAssessment` with nine axes, each `{ …, status: "ok" | "below-bar" |
|
|
439
|
+
"unknown" }`:
|
|
440
|
+
|
|
441
|
+
- **coverage** (`FocusCoverageEntry`) — the share of the pool carrying the metric
|
|
442
|
+
(not the imputed fill). Safe when the source is capability-filled (`fill > 0`,
|
|
443
|
+
so absence is a known non-penalty) **or** the share clears
|
|
444
|
+
`FOCUS_COVERAGE_FLOOR` (0.35). This is `focusCoverageOk`, the coverage branch.
|
|
445
|
+
- **dispersion** — IQR/median of the cardinal-normalized covered values (the
|
|
446
|
+
engine's `cardinalMetric` first, so index and 0–1 metrics are comparable),
|
|
447
|
+
below-bar under `FOCUS_DISPERSION_FLOOR` (0.05). A saturated metric cannot
|
|
448
|
+
separate models. Fewer than two covered values, or a zero median, is `unknown`.
|
|
449
|
+
- **composition** — an org whose pool share is ≥ `FOCUS_ORG_MIN_SHARE` (0.1) but
|
|
450
|
+
which carries no covered model is flagged (`omittedOrgs`); a smaller provider's
|
|
451
|
+
absence is not a false positive.
|
|
452
|
+
- **freshness** — the newest covered model's `releaseDate` against the pool's
|
|
453
|
+
newest, below-bar beyond `FOCUS_STALENESS_MONTHS` (1). A missing date on either
|
|
454
|
+
side degrades to `unknown`.
|
|
455
|
+
- **trust** — the self-reported share of the payload's covered entries (the
|
|
456
|
+
per-entry `self_reported` flag, read by `parseBenchmarkPayloadMeta`), below-bar
|
|
457
|
+
above `FOCUS_SELF_REPORTED_MAX_SHARE` (0.5). A mostly vendor-submitted source
|
|
458
|
+
cannot be trusted to rank on. The `source` argument carries the cached trust
|
|
459
|
+
inputs (`cachedSourceInfo`: the source's scores cache for the payload meta, the
|
|
460
|
+
catalog cache for the row); a payload with no entry flags (a declared or
|
|
461
|
+
writing source) or no covered entries is `unknown` — never a silent `ok`.
|
|
462
|
+
`verified` is uniformly `false` upstream today, so it is carried but not gated.
|
|
463
|
+
The axis also carries the catalog row's `is_community` flag as `community` — a
|
|
464
|
+
community-submitted benchmark is visible even when the payload half is absent
|
|
465
|
+
(no per-entry flags); it is an annotation, never a gate (it never changes
|
|
466
|
+
`status` and `belowBarReason` has no community branch).
|
|
467
|
+
- **modality** — the catalog row's `modality` (e.g. `text`/`image`/`audio`/
|
|
468
|
+
`video`/`multimodal`) and the payload's per-entry `multimodal` share, read by
|
|
469
|
+
`parseBenchmarkPayloadMeta` and carried on `BenchmarkCatalogEntry`. This axis
|
|
470
|
+
is an **annotation, never a gate**: there is no role modality field, so it is
|
|
471
|
+
never `below-bar` and never a drop reason (`belowBarReason` has no modality
|
|
472
|
+
branch). It is `unknown` only when neither the catalog row nor the payload
|
|
473
|
+
carries a modality signal.
|
|
474
|
+
- **maintenance** — the catalog row's `updated_at` age in months against
|
|
475
|
+
`FOCUS_DATASET_STALENESS_MONTHS` (12), with `version_count`/`star_count`
|
|
476
|
+
carried as supporting detail. This is the **dataset-date** axis, distinct from
|
|
477
|
+
`freshness` (the **model-date** axis): freshness asks whether the benchmark
|
|
478
|
+
tracks the model field, maintenance asks whether the benchmark *project* is
|
|
479
|
+
alive. A benchmark whose dataset was last touched years ago but whose rows
|
|
480
|
+
happen to include one recent model passes freshness and is caught here. Like
|
|
481
|
+
modality it is an **annotation, never a gate**: `belowBarReason` has no
|
|
482
|
+
maintenance branch, so a stale dataset is warned but never drops a discovered
|
|
483
|
+
candidate. It is `unknown` when the catalog row is absent or its `updated_at`
|
|
484
|
+
is missing/unparseable.
|
|
485
|
+
- **provenance** — the benchmark's owner (the catalog row's `dataset_org_id`,
|
|
486
|
+
falling back to `dataset_slug`) and the source's own per-entry org mix (the
|
|
487
|
+
dominant lab and its share, read by `parseBenchmarkPayloadMeta` from each row's
|
|
488
|
+
`organization_id`, falling back to `provider_id`), below-bar above
|
|
489
|
+
`FOCUS_PROVENANCE_DOMINANT_SHARE` (0.5 — a **chosen, tunable heuristic**, not a
|
|
490
|
+
measured value). This is the **source's own claim** about who publishes the
|
|
491
|
+
benchmark and whose scores it carries: an independent cross-check on the
|
|
492
|
+
pool-derived `composition` axis, **not a replacement for it** (the composition
|
|
493
|
+
rule is unchanged). `compositionAgreement` records whether the two concur:
|
|
494
|
+
`"disagree"` when exactly one of the two flags `below-bar`, `"agree"` when both
|
|
495
|
+
or neither do, `"unknown"` when the payload carries no org mix. Like modality
|
|
496
|
+
and maintenance it is an **annotation, never a gate**: `belowBarReason` has no
|
|
497
|
+
provenance branch, so a vendor-populated source is warned but never drops a
|
|
498
|
+
discovered candidate. It is `unknown` when there is neither an owner nor a
|
|
499
|
+
payload org mix.
|
|
500
|
+
- **cross-source** — the zeroeval per-entry price/throughput/context
|
|
501
|
+
(`BenchmarkPayloadMeta.crossSource`, keyed by the entry's `model_id`) compared
|
|
502
|
+
against the plugin's own `price`/`throughput`/`context`. The join is **direct
|
|
503
|
+
on the bare id** (the generic llm-stats benchmark's `entries[].model_id` is the
|
|
504
|
+
llm-stats id, the same space as `Model.id`); only models present in the map AND
|
|
505
|
+
carrying the metric count toward `compared`. price compares zeroeval's 3:1
|
|
506
|
+
blend `(3·input + output)/4` against `m.price` ($/M), context compares
|
|
507
|
+
`row.context` against `m.context`, and the relative divergence is
|
|
508
|
+
`|a − b| / max(a, b, 1e-9)`; `priceDivergence`/`contextDivergence` are the
|
|
509
|
+
median over the models compared on that axis (`null` when none). An axis is
|
|
510
|
+
`unknown` when nothing was compared on it, else `ok` within
|
|
511
|
+
`PRICE_AGREEMENT_TOLERANCE` (0.5 — a **chosen, tunable heuristic**), else
|
|
512
|
+
`below-bar`. `speedAgreement` is **informational only** and excluded from
|
|
513
|
+
`status`: the units differ (zeroeval `speed_rps` is requests/s, the plugin's
|
|
514
|
+
`throughput` is output tok/s) and re-deriving throughput from `speed_rps` is
|
|
515
|
+
explicitly out of scope. `status` is `unknown` when `compared === 0`, else
|
|
516
|
+
`below-bar` when `priceAgreement` or `contextAgreement` is `below-bar`, else
|
|
517
|
+
`ok`. Like modality, maintenance and provenance it is an **annotation, never a
|
|
518
|
+
gate**: `belowBarReason` has no cross-source branch, and the axis never feeds
|
|
519
|
+
`price`/`weightPrice` or any ranking input — the `1/price²` blend is unchanged.
|
|
520
|
+
(A future option, recorded here only: use zeroeval's list price as a fallback
|
|
521
|
+
fill for a model with no OpenRouter route.)
|
|
522
|
+
|
|
523
|
+
An empty pool (unknown field size) or `covered === 0` (the metric's scores were
|
|
524
|
+
not loaded) reports **all nine axes `unknown`**, coverage included — never a
|
|
525
|
+
silent `ok`. `belowBarReason(assessment)` names the failed axis.
|
|
526
|
+
|
|
527
|
+
**Enforcement.** The pre-fetch catalog gate is count-only (`modelCount >= 3`); the
|
|
528
|
+
create-agent gate then probe-fetches each selected candidate's source
|
|
529
|
+
(`loadBenchmarkScores`), joins it onto the ranking universe, and assesses the
|
|
530
|
+
joined pool. A **discovered** candidate below-bar on any gating axis is dropped
|
|
531
|
+
non-fatally with a reason naming the axis; a **user-named** metric is never
|
|
532
|
+
dropped — it is annotated and warned. The report prints the nine signals and
|
|
533
|
+
warns per below-bar axis; the explorer's `/api/bootstrap` carries
|
|
534
|
+
`focusAssessments` and the SPA renders a `table.focus` (below-bar warned,
|
|
535
|
+
`unknown` muted, never green); the CLI report annotates a role's focus metrics
|
|
536
|
+
(`focusLine`). The genuine hazard is the six raw pass-rate metrics (`gpqa`,
|
|
537
|
+
`aime`, `swe_bench`, `arc_agi`, `terminal_bench`, `tau_bench`), which are fill-0
|
|
538
|
+
and reachable from discovery via the catalog→shipped mapping;
|
|
539
|
+
`writing`/`website`/`bench:<id>` are capability-filled at 0.195 and stay
|
|
540
|
+
weightable at any coverage.
|
|
541
|
+
|
|
542
|
+
**Focus cap.** The focus set is capped at `FOCUS_METRIC_CAP` (3) in priority
|
|
543
|
+
order (named/linked first, then discovery order), so one benchmark keeps a
|
|
544
|
+
decisive share instead of five sharing the budget; the metrics beyond the cap are
|
|
545
|
+
reported as dropped. The cap is applied before the share math, so the kept set
|
|
546
|
+
still receives `clamp(specialistShare, 0.25, 0.40)` split evenly and both
|
|
547
|
+
invariants hold exactly.
|
|
548
|
+
|
|
549
|
+
### Zeroeval catalog benchmarks — none added
|
|
550
|
+
|
|
551
|
+
No zeroeval catalog benchmark adds an independent axis at usable coverage, so
|
|
552
|
+
none is weighted in a shipped role. Measured over the 400-model ranking field
|
|
553
|
+
(2026-10-03): `mmlu-pro` is the only catalog benchmark that clears the 35%
|
|
554
|
+
`FOCUS_COVERAGE_FLOOR` (142/400 = 35.5%), but it correlates r 0.90–0.92 with
|
|
555
|
+
`general`/`reasoning`; `HLE` is the next best at 26% and does not clear the bar.
|
|
556
|
+
The role-relevant benchmarks are 17–30% coverage and collinear with an existing
|
|
557
|
+
index (`toolathlon` 0.89 with `tool_calling`, `swe-bench-pro` 0.91 with `code`,
|
|
558
|
+
`terminal-bench-2.1` 0.94 with `code`, `mcp-atlas` 0.80 with `agents`,
|
|
559
|
+
`browsecomp` 0.97 with `search`, `deepswe-1.1` 0.80 with `agents`, `lvbench`
|
|
560
|
+
0.95 with `vision`). The six shipped-but-unweighted raw benchmarks (`gpqa`,
|
|
561
|
+
`aime`, `swe_bench`, `arc_agi`, `terminal_bench`, `tau_bench`) are all redundant
|
|
562
|
+
with an index or 5–6% coverage — do not weight them.
|
|
563
|
+
|
|
198
564
|
## Weight design rules
|
|
199
565
|
|
|
200
566
|
The shipped weights (`DEFAULT_ROLES`) and the archetype sets
|
|
@@ -217,19 +583,48 @@ The shipped weights (`DEFAULT_ROLES`) and the archetype sets
|
|
|
217
583
|
100%-coverage backbone plus the partial-coverage trio at reduced share;
|
|
218
584
|
`mrcr`/`search` are unweighted and `long_context` is capped at 0.14.
|
|
219
585
|
`website`/`long_context`/`writing` are capability-filled rather than
|
|
220
|
-
0-filled.
|
|
586
|
+
0-filled. The nine-axis focus-metric gate (above) is the automated check for
|
|
587
|
+
this rule: it drops a discovered candidate that is below-bar on coverage,
|
|
588
|
+
dispersion, composition, freshness or trust (modality, maintenance,
|
|
589
|
+
provenance and cross-source are annotations, never a drop).
|
|
221
590
|
5. **Non-collinear differentiation.** The capability indices are one latent
|
|
222
|
-
factor (Pearson r over the pool: general↔reasoning 0.
|
|
591
|
+
factor (Pearson r over the pool: general↔reasoning 0.984, code↔agents 0.95,
|
|
223
592
|
general↔code 0.94), so re-weighting them barely separates roles.
|
|
224
593
|
Differentiate on the independent axes instead — throughput (r 0.13 with
|
|
225
|
-
general), price (r ≈ 0), and the specialist metrics.
|
|
594
|
+
general), price (r ≈ 0), and the specialist metrics. The `general`+`reasoning`
|
|
595
|
+
pair is the extreme case: at r 0.984 they are ~one latent factor, so
|
|
596
|
+
`default`/`slow`/`plan`/`advisor` merge them into a single `general` weight —
|
|
597
|
+
a pure relabel (the combined capability share is unchanged, so no share is
|
|
598
|
+
freed and none is reallocated; the ranking is ≈ unchanged, near-tie
|
|
599
|
+
reorderings only).
|
|
226
600
|
6. **λ from the intended posture.** `λ = (w_price/(1−w_price))/20` is the
|
|
227
601
|
quality-per-dollar exchange rate; a price weight whose leader-flip threshold
|
|
228
|
-
is 10–30× away is decoration. `
|
|
229
|
-
(λ 0.
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
602
|
+
is 10–30× away is decoration. `advisor` carries price 0.20 (λ 0.0125),
|
|
603
|
+
`plan` 0.25 (λ 0.01667); `tiny` stays at 0.40.
|
|
604
|
+
- **Measure the leader-flip threshold on the *reachable* pool** — the pool
|
|
605
|
+
the selector is actually chosen from (candidates the probe walk marks `ok`
|
|
606
|
+
or `unknown`). The full-pool threshold is a stability check only. Measured
|
|
607
|
+
2026-10-03 (issue #16): `plan`'s reachable threshold was w_price 0.2175
|
|
608
|
+
(Hy4 preview → DeepSeek-V4.1-Flash) against a full-pool 0.311 (Muse Spark
|
|
609
|
+
1.3 → Qwen3.8 Flash), so price 0.25 flips the actionable pick while the
|
|
610
|
+
full-pool #1 is unchanged.
|
|
611
|
+
- **Degenerate case.** When the value leader is also the quality leader the
|
|
612
|
+
formula `(q_QL − q_VL)/(p_QL − p_VL)` is 0/0 — *undefined*, not zero, and
|
|
613
|
+
it does **not** mean "no price weight dethrones the leader". The leader
|
|
614
|
+
still flips at `min` over the cheaper challengers X of
|
|
615
|
+
`(q_leader − q_X)/(pEff_leader − pEff_X)`.
|
|
616
|
+
- **Coverage caveat.** A reachable flip can land on a model whose weighted
|
|
617
|
+
metric is *imputed*, not measured. `long_context` covers 39% of the `plan`
|
|
618
|
+
pool (56/142), and DeepSeek-V4.1-Flash's `index_long_context` is null —
|
|
619
|
+
llm-stats reads that as insufficient evidence, not zero — so it scores the
|
|
620
|
+
0.195 capability fill against Hy4 preview's measured 18.9. Read the flip as
|
|
621
|
+
partly a data-coverage artefact.
|
|
622
|
+
7. **`website` vs `code` collinearity.** They correlate at r = 0.890 over the
|
|
623
|
+
covered pool, so `designer` weights `website` 0.18 with `code` trimmed to
|
|
624
|
+
0.06 (the old 0.10/0.18 pair double-counted one capability axis). The freed
|
|
625
|
+
0.04 goes to the independent axes (`price` +0.02, `throughput` +0.02) per
|
|
626
|
+
rule 5, giving `general` 0.26, `vision` 0.18, `throughput` 0.15, `price`
|
|
627
|
+
0.17, `website` 0.18, `code` 0.06.
|
|
233
628
|
|
|
234
629
|
## Value-review findings (2026-09-30)
|
|
235
630
|
|
|
@@ -250,6 +645,431 @@ one." Three findings, each measured on that day's caches:
|
|
|
250
645
|
GLM-5.3 → DeepSeek −0.004 q for 4.6× less money; `vision` −0.041 for 18×;
|
|
251
646
|
`designer` −0.010 for 26×; `task` +0.007 for 4.6×).
|
|
252
647
|
|
|
648
|
+
## Value-review findings (2026-10-03)
|
|
649
|
+
|
|
650
|
+
Three measured defects in the shipped weights, each fixed in issue #13 (all
|
|
651
|
+
numbers from the 2026-10-03 caches: 400 models, 151 throughput-matched, 150
|
|
652
|
+
priced):
|
|
653
|
+
|
|
654
|
+
- **`math` is collinear and sparse in `plan`/`slow`.** Over the eligible pool
|
|
655
|
+
`math` correlates with `reasoning` at r 0.919 and is missing for 18% of the
|
|
656
|
+
pool, so a model without `math` data loses up to 0.090 `q` for `plan` (share
|
|
657
|
+
0.156) and 0.049 for `slow` (share 0.084) — a coverage penalty, not a quality
|
|
658
|
+
signal. `advisor` had already dropped `math` for this reason (2026-09-30);
|
|
659
|
+
`plan`/`slow` were left behind. Fix: drop `math` from both and move its share
|
|
660
|
+
to the consolidated `general` axis (capability-preserving, 100% coverage) —
|
|
661
|
+
not `throughput`, which would contradict `slow`'s "speed as tiebreakers"
|
|
662
|
+
description and flip both leaders to a cheap/fast model. `plan`'s description
|
|
663
|
+
drops `math` in the same change.
|
|
664
|
+
- **`smol`/`commit` price weight does not bind.** Both are described as
|
|
665
|
+
"cheap", but the value leader is also the quality leader, so the price term is
|
|
666
|
+
not what picks #1. The leader-flip threshold is λ* 0.0367 (`smol`, w_price*
|
|
667
|
+
0.423) and 0.0402 (`commit`, w_price* 0.446) against the current λ 0.0214
|
|
668
|
+
(w_price 0.30) and 0.0286 (w_price 0.35). Fix: raise both `w_price` to 0.45
|
|
669
|
+
(the measured binding threshold), rescaling the non-price weights
|
|
670
|
+
proportionally — a posture change, not a capability change.
|
|
671
|
+
- **The capability weights are ~one latent factor.** `general`~`reasoning` r
|
|
672
|
+
0.984 over the eligible pool; `default`/`slow`/`plan`/`advisor` each spend
|
|
673
|
+
55–74% of their non-price budget on that pair. The split buys almost nothing —
|
|
674
|
+
merging leaves `default`'s top-3 identical and only swaps #4/#5. Fix: merge
|
|
675
|
+
`general`+`reasoning` into `general` in those four roles as a pure relabel (no
|
|
676
|
+
reallocation).
|
|
677
|
+
|
|
678
|
+
Measured effect: `slow` #1 glm-5.3 → muse-spark-1.3, `plan` #1 hy4-preview →
|
|
679
|
+
muse-spark-1.3, `smol`/`commit` #1 muse-spark-1.1 → deepseek-v4.1-flash;
|
|
680
|
+
`default`/`advisor` keep their #1 (near-tie reorderings only).
|
|
681
|
+
|
|
682
|
+
## Value-review findings (2026-10-03, issue #16 — `plan` cost posture)
|
|
683
|
+
|
|
684
|
+
`plan` did not honour the stated "cheapest model that can do the task" stance:
|
|
685
|
+
its price weight (0.12, λ 0.00682) was decoration on the pool the selector is
|
|
686
|
+
actually chosen from.
|
|
687
|
+
|
|
688
|
+
- **The reachable pool, not the full pool, is the decision pool.** The shipped
|
|
689
|
+
`plan` pick was Hy4 preview ($2.32/M); DeepSeek-V4.1-Flash ($0.43/M, 5.4×
|
|
690
|
+
cheaper) is reachable on this account and lost by 0.013 value. Hy4's whole
|
|
691
|
+
edge is `long_context` (measured 18.9 vs DeepSeek's null → capability fill
|
|
692
|
+
0.195); DeepSeek leads the measured axes (`general` 51.2 vs 50.4, 81 vs 36
|
|
693
|
+
tok/s). Fix: raise `plan`'s `price` 0.12 → 0.25 (λ 0.01667), rescaling the
|
|
694
|
+
non-price weights by 0.852273 — `general` 0.6, `long_context` 0.116676,
|
|
695
|
+
`throughput` 0.033324 (Σ(non-price) = 0.75 = 1 − price; `q` unchanged).
|
|
696
|
+
Measured reachable flip 0.2175, full-pool 0.311, so 0.25 flips the actionable
|
|
697
|
+
pick (Hy4 → DeepSeek-V4.1-Flash) and leaves the full-pool #1 (Muse Spark 1.3)
|
|
698
|
+
in place. `long_context` stays weighted — it is the only non-collinear
|
|
699
|
+
capability axis in `plan`; dropping it would collapse the role onto `general`.
|
|
700
|
+
- **The flip rides on imputed data.** 5 of the 7 reachable `plan` models are
|
|
701
|
+
`long_context`-imputed; the metric covers 39% of the pool. If the account's
|
|
702
|
+
provider whitelist changes, `qwen3.8-flash` (same $0.43/M, higher q) strictly
|
|
703
|
+
dominates DeepSeek and takes the reachable #1 with no weight edit.
|
|
704
|
+
|
|
705
|
+
## Domain-knowledge axis: measured, not landed (2026-10-05, issue #23)
|
|
706
|
+
|
|
707
|
+
The llm-stats `index_finance`/`index_legal`/`index_healthcare` scores were
|
|
708
|
+
evaluated as a domain-knowledge axis and **not landed** — no role weights them.
|
|
709
|
+
Measured over the 2026-10-05 400-model field (clean HEAD `a201a3b`, throwaway
|
|
710
|
+
worktree):
|
|
711
|
+
|
|
712
|
+
- **Coverage**: `index_finance` 228/400 (57.0%), `index_legal` 213/400 (53.3%),
|
|
713
|
+
`index_healthcare` 248/400 (62.0%), `general` 377/400 (94.3%).
|
|
714
|
+
- **Correlation with `general`** (full covered pool): finance 0.6981, legal
|
|
715
|
+
0.6632, healthcare 0.8449. Among the domains: finance↔legal 0.9529,
|
|
716
|
+
finance↔healthcare 0.9417, legal↔healthcare 0.9464 — one latent factor.
|
|
717
|
+
- **On the eligible covered pool** (domain + `general` + price + throughput):
|
|
718
|
+
finance 0.408, legal 0.388, healthcare 0.797.
|
|
719
|
+
- **0-fill leader flip** (`default`, share taken from `code`+`agents`): full pool
|
|
720
|
+
flips at 0.03–0.06 (DeepSeek-V4.1-Flash $0.24 → Muse Spark 1.3 $2.00 /
|
|
721
|
+
GPT-5.6 Sol $6.13); reachable pool (73 models) at 0.04–0.17; covered pool at
|
|
722
|
+
0.17–0.20.
|
|
723
|
+
- **Capability-fill measurement** (real fill branch): no leader flip on the full
|
|
724
|
+
pool at shares 0.05–0.20; on the reachable pool it flips at 0.05
|
|
725
|
+
(finance/legal) and 0.20 (healthcare), always to the **cheaper** model.
|
|
726
|
+
|
|
727
|
+
**Verdict: do not land.** r with `general` is 0.66–0.84, the 0-fill is a coverage
|
|
728
|
+
lottery (the cheap leader has no domain data), and the capability fill still
|
|
729
|
+
flips the leader on the reachable pool — neither posture is stable.
|
|
730
|
+
Counter-evidence for the record: on the eligible covered pool finance/legal
|
|
731
|
+
correlate only 0.39–0.41 with `general`, so the metric does carry independent
|
|
732
|
+
signal mid-ranking; it just does not move the leader at a plausible share.
|
|
733
|
+
|
|
734
|
+
## Truthfulness axis: measured, not landed (2026-10-06, issue #24)
|
|
735
|
+
|
|
736
|
+
The llm-stats `simpleqa_score` was evaluated as a truthfulness axis and **not
|
|
737
|
+
landed** — no role weights it. Measured over the 2026-10-06 400-model field:
|
|
738
|
+
|
|
739
|
+
- **Coverage**: `simpleqa_score` 47/400 (11.8%); default-eligible 18/142 (12.7%);
|
|
740
|
+
catalog-resolvable 16/137 (11.7%); allowed-keyed 7/65 (10.8%); probe-walk
|
|
741
|
+
reachable **0/3**.
|
|
742
|
+
- **Correlation with `general`**: full pool 0.68, eligible 0.75, catalog 0.70,
|
|
743
|
+
allowed 0.89. `hle_score` correlates 0.88 with `general` (collinear), and
|
|
744
|
+
`simpleqa_score` vs `hle_score` is 0.35 — the two truthfulness metrics are not
|
|
745
|
+
interchangeable.
|
|
746
|
+
- **0-fill leader flip** (`default`): the full pool flips at share 0.21 to
|
|
747
|
+
`gemini-3-flash-preview` ($1.125/M vs the leader's $0.598/M — 1.9× more
|
|
748
|
+
expensive); the capability fill flips to the pricier model too. The
|
|
749
|
+
allowed-pool top-10 **all** have `simpleqa_score = null`.
|
|
750
|
+
|
|
751
|
+
**Verdict: do not land.** The 0-fill is a pure coverage lottery for exactly the
|
|
752
|
+
models the selector chooses from (the reachable pool has no covered model at
|
|
753
|
+
all), and the capability fill reproduces the cost-promotion failure mode the
|
|
754
|
+
0-fill posture exists to avoid.
|
|
755
|
+
|
|
756
|
+
## Guardrail/alignment axis: measured, not landed (2026-10-06, issue #31)
|
|
757
|
+
|
|
758
|
+
The catalog's guardrail/alignment entries were evaluated as a "completes the
|
|
759
|
+
objective without tripping guardrails" axis and **not landed** — no role weights
|
|
760
|
+
one. Measured over the 2026-10-06 400-model field (clean HEAD `01fd7f2`,
|
|
761
|
+
throwaway worktree, `loadRankData({ roles: {} })` + `loadBenchmarkCatalog(false)`):
|
|
762
|
+
the catalog carries 745 entries; 57 match a guardrail/alignment keyword
|
|
763
|
+
(`guardrail`, `alignment`, `safety`, `attack`, `jailbreak`, `harm`, `refusal`,
|
|
764
|
+
`automationbench`, `agentdojo`, `siren`, `trust`, `toxicity`, `bias`) in
|
|
765
|
+
id/name/description/categories; 30 of those clear the pre-fetch count gate
|
|
766
|
+
(`modelCount >= 3`).
|
|
767
|
+
|
|
768
|
+
- **The semantically-relevant entries are at one model.** The pair the issue
|
|
769
|
+
names — `siren-agentdojo-attack-success` and `siren-agentdojo-utility` — and
|
|
770
|
+
`automationbench-aa` each carry `modelCount = 1`, below the count gate, so none
|
|
771
|
+
is even probe-fetchable. The rest of the `safety` category is the same:
|
|
772
|
+
`air-bench`, `wmdp`, `wmdp-bio`, `wmdp-chem`, `wmdp-cyber`, `cyberseceval-4`,
|
|
773
|
+
`cve-bench`, `cwe-bench`, `cathedralbench`, `gray-swan-ipi`, `mask`,
|
|
774
|
+
`miabench`, `biolp-bench`, `cloningscenarios`, `protocolqa`,
|
|
775
|
+
`protocolqa-open-ended`, `google-real-world-vulnerability-discovery`,
|
|
776
|
+
`ci-memories-coverage`, `ci-memories-violation` are all 1 model; `cybench`,
|
|
777
|
+
`mimo-cyber-bench`, `vct` are 2. Nothing in the catalog measures
|
|
778
|
+
guardrail-compliance at usable coverage.
|
|
779
|
+
- **Coverage**: the best-covered candidate is 20/400 = **5.0%**
|
|
780
|
+
(`automationbench`, `cybergym`, `winogrande`; the llm-stats per-benchmark
|
|
781
|
+
endpoint caps `entries` at 20, so `automationbench` 22 and `winogrande` 23 load
|
|
782
|
+
only 20). Every other candidate is 0.7–4.0%. The 35% `FOCUS_COVERAGE_FLOOR` is
|
|
783
|
+
7× away from the best candidate and ~50× from the median. `general` covers
|
|
784
|
+
377/400 (94.3%) for scale. (The generic `bench:<id>` source is
|
|
785
|
+
capability-filled at 0.195, so `assessFocusMetric`'s coverage axis reads `ok`
|
|
786
|
+
for all of them — the raw share is the binding number here.)
|
|
787
|
+
- **Correlation with `general`** (covered pool): the safety/security entries are
|
|
788
|
+
collinear — `capture-the-flag-challenges` 1.00, `figqa` 1.00, `exploitbench`
|
|
789
|
+
0.97, `sec-bench-pro` 0.97, `cybersecurity-ctfs` 0.97, `alignbench` 0.97,
|
|
790
|
+
`attaq` 0.93, `internal-research-debugging-evaluation` 0.92, `xstest` 0.91,
|
|
791
|
+
`exploitgym` 0.89. The only low-correlation candidate is `automationbench`
|
|
792
|
+
(r 0.24 with `general`, 0.30 with `agents`, 0.61 with `tool_calling`) — but it
|
|
793
|
+
is an agentic-automation benchmark (categories `reasoning|agents|tool_calling`),
|
|
794
|
+
not a guardrail axis, and it covers 5.0%.
|
|
795
|
+
- **0-fill leader flip** (`default`, share taken from the collinear `code`+`agents`
|
|
796
|
+
block = 0.2842; baseline leader `deepseek-v4.1-flash` $0.599/M): most of the
|
|
797
|
+
flips that happen go to **pricier** models — `capture-the-flag-challenges` 0.04 →
|
|
798
|
+
`gpt-5.6-sol` ($6.13/M, 10.2×), `exploitbench` 0.04 → `glm-5.3` ($2.47/M,
|
|
799
|
+
4.1×), `internal-research-debugging-evaluation` 0.06 → `gpt-5.6-sol` (10.2×),
|
|
800
|
+
`cybersecurity-ctfs` 0.21 → `gpt-5.3-codex` ($4.81/M, 8.0×), `exploitgym` 0.22
|
|
801
|
+
→ `gpt-5.6-sol` (10.2×), `cybergym` 0.30 → `mimo-v2.6-pro` ($0.543/M, cheaper),
|
|
802
|
+
`alignbench` 0.32 → `qwen3-14b` ($0.165/M, cheaper), `voicebench-avg` 0.14 →
|
|
803
|
+
`inkling-small` ($0.638/M, ≈same), `winogrande` 0.20 → `mimo-v2.5-pro`
|
|
804
|
+
($0.622/M, ≈same). The capability-fill posture (the real posture for
|
|
805
|
+
`bench:<id>`) moves the thresholds only slightly (`exploitgym` 0.16,
|
|
806
|
+
`cybersecurity-ctfs` 0.26, `alignbench` 0.37) and never changes the direction.
|
|
807
|
+
`automationbench`, `attaq`, `xstest`, `pope`, `figqa`, `sec-bench-pro`,
|
|
808
|
+
`crag`, `big-bench`, `vqav2` do not flip the leader at any share up to 0.40 —
|
|
809
|
+
they are the least-covered entries.
|
|
810
|
+
|
|
811
|
+
**Verdict: do not land.** No candidate clears the coverage bar (best 5.0% vs the
|
|
812
|
+
35% floor), the semantically-relevant guardrail entries are at one model, and the
|
|
813
|
+
safety/security entries that do carry data are collinear with `general`
|
|
814
|
+
(r 0.89–1.00). The one low-correlation candidate (`automationbench`, r 0.24) is
|
|
815
|
+
an agentic-automation benchmark, not a guardrail axis, and still covers only 5.0%.
|
|
816
|
+
The 0-fill is a cost-promotion lottery: most of the flips that happen land on
|
|
817
|
+
models 3–10× more expensive than the leader. No declarative source is authored —
|
|
818
|
+
the catalog is the only fetchable guardrail-adjacent data and it is too sparse.
|
|
819
|
+
|
|
820
|
+
### Candidate table (modelCount ≥ 3, 2026-10-06 field)
|
|
821
|
+
|
|
822
|
+
`flip0` = 0-fill leader-flip share; `flipCap` = capability-fill (0.195) share;
|
|
823
|
+
`none` = no flip up to 0.40. `rAgents` is `n/a` when fewer than 3 covered models
|
|
824
|
+
carry `agents`.
|
|
825
|
+
|
|
826
|
+
| catalog id | metric | modelCount | covered/400 | r(general) | r(agents) | dispersion | flip0 | flipCap |
|
|
827
|
+
|---|---|---|---|---|---|---|---|---|
|
|
828
|
+
| automationbench | bench:automationbench | 22 (20 loaded) | 20 (5.0%) | 0.24 | 0.30 | 0.62 | none | none |
|
|
829
|
+
| cybergym | bench:cybergym | 20 | 20 (5.0%) | 0.48 | 0.75 | 0.14 | 0.30 → mimo-v2.6-pro | 0.30 → mimo-v2.6-pro |
|
|
830
|
+
| winogrande | bench:winogrande | 23 (20 loaded) | 20 (5.0%) | 0.60 | n/a | 0.13 | 0.20 → mimo-v2.5-pro | 0.24 → mimo-v2.5-pro |
|
|
831
|
+
| global-mmlu-lite | bench:global-mmlu-lite | 16 | 16 (4.0%) | 0.88 | n/a | 0.33 | 0.15 → inkling-small | 0.18 → inkling-small |
|
|
832
|
+
| healthbench-professional | bench:healthbench-professional | 14 | 14 (3.5%) | 0.95 | 0.93 | 0.14 | 0.06 → gpt-5.6-sol | 0.09 → gpt-5.6-sol |
|
|
833
|
+
| healthbench | bench:healthbench | 13 | 13 (3.3%) | 0.70 | 0.84 | 0.08 | 0.07 → gpt-5.6-sol | 0.10 → gpt-5.6-sol |
|
|
834
|
+
| healthbench-hard | bench:healthbench-hard | 11 | 11 (2.8%) | 0.66 | 0.61 | 0.46 | 0.12 → gpt-5.6-sol | 0.30 → gpt-6.1-sol |
|
|
835
|
+
| exploitbench | bench:exploitbench | 8 | 8 (2.0%) | 0.97 | 0.95 | 0.57 | 0.04 → glm-5.3 | 0.06 → glm-5.3 |
|
|
836
|
+
| exploitgym | bench:exploitgym | 8 | 8 (2.0%) | 0.89 | 0.84 | 0.69 | 0.22 → gpt-5.6-sol | 0.16 → muse-spark-1.3 |
|
|
837
|
+
| sec-bench-pro | bench:sec-bench-pro | 7 | 7 (1.8%) | 0.97 | 0.96 | 0.25 | none | none |
|
|
838
|
+
| global-mmlu | bench:global-mmlu | 7 | 7 (1.8%) | 0.98 | 1.00 | 0.50 | 0.20 → mimo-v2.5-pro | 0.25 → mimo-v2.5-pro |
|
|
839
|
+
| alignbench | bench:alignbench | 5 | 5 (1.3%) | 0.97 | n/a | 0.10 | 0.32 → qwen3-14b | 0.37 → qwen3-14b |
|
|
840
|
+
| bfcl-v2 | bench:bfcl-v2 | 5 | 5 (1.3%) | 0.74 | n/a | 0.10 | 0.34 → llama-3.3-70b-instruct | 0.40 → llama-3.3-70b-instruct |
|
|
841
|
+
| healthbench-consensus | bench:healthbench-consensus | 5 | 5 (1.3%) | 0.79 | 0.55 | 0.004 | 0.04 → gpt-5.6-sol | 0.05 → gpt-5.6-sol |
|
|
842
|
+
| xstest | bench:xstest | 4 | 4 (1.0%) | 0.91 | n/a | 0.035 | none | none |
|
|
843
|
+
| tempcompass | bench:tempcompass | 4 | 4 (1.0%) | 1.00 | 0.74 | 0.13 | 0.28 → seed-2.0-mini | 0.34 → seed-2.0-mini |
|
|
844
|
+
| vlmsarebiased | bench:vlmsarebiased | 4 | 4 (1.0%) | 0.89 | 0.84 | 0.17 | 0.36 → seed-2.0-mini | none |
|
|
845
|
+
| attaq | bench:attaq | 3 | 3 (0.7%) | 0.93 | n/a | 0.014 | none | none |
|
|
846
|
+
| pope | bench:pope | 3 | 3 (0.7%) | 0.42 | n/a | 0.018 | none | none |
|
|
847
|
+
| capture-the-flag-challenges | bench:capture-the-flag-challenges | 3 | 3 (0.7%) | 1.00 | 1.00 | 0.06 | 0.04 → gpt-5.6-sol | 0.05 → gpt-5.6-sol |
|
|
848
|
+
| cybersecurity-ctfs | bench:cybersecurity-ctfs | 3 | 3 (0.7%) | 0.97 | n/a | 0.52 | 0.21 → gpt-5.3-codex | 0.26 → gpt-5.3-codex |
|
|
849
|
+
| figqa | bench:figqa | 3 | 3 (0.7%) | 1.00 | n/a | 0.35 | none | none |
|
|
850
|
+
| internal-research-debugging-evaluation | bench:internal-research-debugging-evaluation | 3 | 3 (0.7%) | 0.92 | 0.95 | 0.13 | 0.06 → gpt-5.6-sol | 0.08 → gpt-5.6-sol |
|
|
851
|
+
| voicebench-avg | bench:voicebench-avg | 3 | 3 (0.7%) | 1.00 | n/a | 0.10 | 0.14 → inkling-small | 0.18 → inkling-small |
|
|
852
|
+
| vqav2 | bench:vqav2 | 3 | 3 (0.7%) | 0.76 | n/a | 0.018 | none | none |
|
|
853
|
+
| big-bench | bench:big-bench | 3 | 3 (0.7%) | 0.39 | n/a | 0.045 | none | none |
|
|
854
|
+
| crag | bench:crag | 3 | 3 (0.7%) | 0.90 | n/a | 0.08 | none | none |
|
|
855
|
+
|
|
856
|
+
Not loadable (404 on the per-benchmark endpoint): `alpacaeval-2.0` (4),
|
|
857
|
+
`automationbench-1.0.6` (5), `vqav2-(val)` (3). Below the count gate (1–2 models):
|
|
858
|
+
the `siren-agentdojo-*` pair, `automationbench-aa`, and the rest of the `safety`
|
|
859
|
+
category listed above.
|
|
860
|
+
|
|
861
|
+
## Per-task cost composite: measured, not landed (2026-10-06, issue #32)
|
|
862
|
+
|
|
863
|
+
Issue #32 asked to rank on a per-task cost/throughput composite **when a per-task
|
|
864
|
+
token profile is available**, keeping the current $/M price as the fallback, and
|
|
865
|
+
to quantify the gap and defer when no profile source exists. **Verdict: defer.**
|
|
866
|
+
No per-task (or per-role) token profile exists, so the $/M price stays the price
|
|
867
|
+
axis. The closest available source — OpenRouter's per-model analytics, which the
|
|
868
|
+
plugin already downloads and ignores — is a *platform-wide, per-request* profile,
|
|
869
|
+
not the role's workload; using it would price OpenRouter's traffic mix, not the
|
|
870
|
+
plugin's.
|
|
871
|
+
|
|
872
|
+
### What the $/M proxy assumes
|
|
873
|
+
|
|
874
|
+
`priceEff` is the billed 3:1 blend `(3·p_in + p_out)/4` scaled by the role's
|
|
875
|
+
thinking factor. A per-task price is `tokens_per_task × priceEff`, so the proxy
|
|
876
|
+
makes two assumptions the composite would relax:
|
|
877
|
+
|
|
878
|
+
1. **A fixed 3:1 input:output token mix** (output = 25% of the mix). Measured on
|
|
879
|
+
6,813 real assistant turns in this repo's sessions: **5.74:1** (output =
|
|
880
|
+
14.8%). The blend over-weights the output price by ~1.7×. Per-model
|
|
881
|
+
`p_out/p_in` spans 0.8–800 (median 4.19) over the 448 OpenRouter models with
|
|
882
|
+
both prices, so the correction is a per-model price rescale of up to 1.72×.
|
|
883
|
+
2. **A model-independent token count per task.** If `tokens_per_task` is constant
|
|
884
|
+
across models, the per-task price is a constant × `priceEff` — a pure λ
|
|
885
|
+
rescale with no ranking change. The composite only bites when
|
|
886
|
+
`tokens_per_task` varies by model (a verbose/retrying model costs more per
|
|
887
|
+
task).
|
|
888
|
+
|
|
889
|
+
### Source 1 — a published per-task metric: none
|
|
890
|
+
|
|
891
|
+
- **llm-stats leaderboard** (`LlmStatsRow`, 56 fields in the 2026-10-06 cache):
|
|
892
|
+
`input_price`/`output_price` ($/M), `throughput` (output tok/s), `latency`
|
|
893
|
+
(TTFT), the index/benchmark scores, `params`, `training_tokens`. No
|
|
894
|
+
token-usage, cost-per-task or output-tokens-per-task field. `training_tokens`
|
|
895
|
+
is a pretraining count, not per-task usage.
|
|
896
|
+
- **Benchmark catalog** (`loadBenchmarkCatalog`, 745 entries): every entry is
|
|
897
|
+
`{id, name, description, categories, modelCount}`. No token/cost field; the
|
|
898
|
+
descriptions mention "token" only as context length.
|
|
899
|
+
|
|
900
|
+
### Source 2 — omp's recorded per-role usage: auxiliary-only
|
|
901
|
+
|
|
902
|
+
omp's session jsonl carries a dedicated `model_usage` event with a `role` tag
|
|
903
|
+
(`{type:"model_usage", purpose, role, api, provider, model, usage:{input, output,
|
|
904
|
+
cacheRead, cacheWrite, totalTokens, cost}}`). Across all 433 session files it
|
|
905
|
+
holds **2,833 records, 2 roles, 2 models** — `typesafe` (2,832; the judge role)
|
|
906
|
+
and `tiny` (1) — and every record is an *auxiliary* call: `judge_batch` 2,235,
|
|
907
|
+
`unexpected-stop` 255, `auto-thinking` 218, `find` 122, `judge` 3. The main
|
|
908
|
+
assistant turn's usage sits on the `message` record with `model` but **no role
|
|
909
|
+
tag** (6,813 turns, 7 models, 36.9M input / 6.4M output). So omp records per-role
|
|
910
|
+
usage only for harness-internal calls, never for the role's own work, and never
|
|
911
|
+
per task. The plugin's own `llm-role-history.jsonl` records per-role *decisions*
|
|
912
|
+
(`role, from, to, reason, score, bestScore, currentScore`) with no token fields.
|
|
913
|
+
|
|
914
|
+
### Source 3 — OpenRouter analytics: a per-model profile, but not per-task/per-role
|
|
915
|
+
|
|
916
|
+
The OpenRouter find payload the plugin already fetches
|
|
917
|
+
(`openrouter.ai/api/frontend/v1/models/find`, cached as
|
|
918
|
+
`openrouter-fetched-data.json`) carries `data.analytics`: per permaslug+variant,
|
|
919
|
+
`count` (requests), `total_prompt_tokens`, `total_completion_tokens`,
|
|
920
|
+
`total_native_tokens_reasoning`, `total_native_tokens_cached`, `total_usage` ($),
|
|
921
|
+
`total_tool_calls`, `date`. `src/` reads none of it (`grep analytics src/` → no
|
|
922
|
+
hits). It is a real per-model token+cost profile, but it does not satisfy the
|
|
923
|
+
issue's requirement:
|
|
924
|
+
|
|
925
|
+
- **Platform-wide, not the role's workload.** The plugin's own measured
|
|
926
|
+
input/req is **~10–14× lower** than the platform's prompt/req for the same
|
|
927
|
+
models (deepseek-v4.1-flash 4,451 vs 57,018; glm-5.3 4,533 vs 63,434;
|
|
928
|
+
mimo-v2.6-pro 7,556 vs 80,780; hy4-preview 9,302 vs 113,793). The platform's
|
|
929
|
+
prompt/req reflects long-context agentic traffic, not omp's turns. Output/req
|
|
930
|
+
is closer (deepseek 955 vs 926; glm-5.3-flash 906 vs 931), so the *verbosity*
|
|
931
|
+
signal is usable but the *workload* signal is not.
|
|
932
|
+
- **Per-request, not per-task.** `count` is API calls; an agent task spans many.
|
|
933
|
+
- **Single-day snapshot** (576/625 entries dated 2026-09-29), so it is
|
|
934
|
+
stale-prone.
|
|
935
|
+
- **152/400 coverage** (standard variant, `count > 0`); the other 248 models
|
|
936
|
+
would fall back to $/M, giving a mixed axis.
|
|
937
|
+
- **Not per-role.** The issue allows "per role, or per model × role"; this is
|
|
938
|
+
per-model only.
|
|
939
|
+
|
|
940
|
+
### Measured effect (if the analytics were used as the profile)
|
|
941
|
+
|
|
942
|
+
Re-ranking the 2026-10-06 field with `priceEff × (tokens_per_task / median)`,
|
|
943
|
+
uncovered models at the $/M fallback (t = 1):
|
|
944
|
+
|
|
945
|
+
| role | current #1 | composite #1 | change |
|
|
946
|
+
|---|---|---|---|
|
|
947
|
+
| `default` | deepseek-v4.1-flash | deepseek-v4.1-flash | same |
|
|
948
|
+
| `plan` | muse-spark-1.3 | qwen3.8-flash | changed |
|
|
949
|
+
| `slow` | muse-spark-1.3 | deepseek-v4.1-flash | changed |
|
|
950
|
+
| `smol` | muse-spark-1.1 | mercury-2 | changed |
|
|
951
|
+
|
|
952
|
+
The output-only variant (completion+reasoning per request, the model-controlled
|
|
953
|
+
part) changes the same three roles. So the composite is not inert — but the
|
|
954
|
+
change is driven by the platform's workload mix (tokens/req spans 437–114,810,
|
|
955
|
+
262×), not by the role's task. The token-mix correction alone (3:1 → 5.74:1) does
|
|
956
|
+
**not** change any leader (only a #5 swap in `default`).
|
|
957
|
+
|
|
958
|
+
### Verdict
|
|
959
|
+
|
|
960
|
+
**Do not land.** No per-task token profile exists: the published sources carry no
|
|
961
|
+
per-task metric, omp's per-role usage is auxiliary-only (2 roles, 2 models), and
|
|
962
|
+
the one per-model profile the plugin already has (OpenRouter analytics) is
|
|
963
|
+
platform-wide aggregate traffic whose prompt/req is ~10–14× the plugin's own
|
|
964
|
+
measured input/req. Landing it would price OpenRouter's workload mix, not the
|
|
965
|
+
role's, and would change 3 of 4 leaders on that basis. The $/M proxy remains the
|
|
966
|
+
price axis.
|
|
967
|
+
|
|
968
|
+
**What would change the verdict:** a per-role (or per-model × role) token count
|
|
969
|
+
from the plugin's own recorded usage. The plugin already sees the main-turn usage
|
|
970
|
+
per model (session jsonl) and the role→model mapping (config.yml); recording the
|
|
971
|
+
role alongside the turn's usage would give a per-role profile the composite could
|
|
972
|
+
use without the platform-workload confound. Until then this is a measurement, not
|
|
973
|
+
a weight change.
|
|
974
|
+
|
|
975
|
+
## Agentic multi-agent axes: measured, not landed (2026-10-06, issue #33)
|
|
976
|
+
|
|
977
|
+
The named multi-agent behaviours — delegation, small agent teams (SATs), agent
|
|
978
|
+
handoffs, agent swarms, failure recovery / self-healing, agent-to-agent
|
|
979
|
+
communication — were searched for in the llm-stats benchmark catalog and
|
|
980
|
+
**not landed** — no role weights an axis for them, because no source measures
|
|
981
|
+
them.
|
|
982
|
+
|
|
983
|
+
**Sweep.** The catalog (745 entries) was swept on `id`/`name`/`description`/
|
|
984
|
+
`categories` for `delegat`, `swarm`, `handoff`, `recover`, `self-heal`, `a2a`,
|
|
985
|
+
`agent-to-agent`, `negotiat`, `multi-agent`, `team`, `coordination`,
|
|
986
|
+
`orchestrat`, `collaborat`, `subagent`. **Zero hits** for delegat / swarm /
|
|
987
|
+
handoff / recover / self-heal / a2a / agent-to-agent / negotiat / subagent. The
|
|
988
|
+
17 hits that did match are:
|
|
989
|
+
|
|
990
|
+
| catalog id | models | matched | what it actually measures |
|
|
991
|
+
|---|---|---|---|
|
|
992
|
+
| `supergpqa` | 37 | collaborat | graduate QA; "Human-LLM **collaborative** filtering" is annotation methodology |
|
|
993
|
+
| `mcp-atlas` | 36 | coordinat | **single-agent** tool use ("coordinate and utilize multiple tools") |
|
|
994
|
+
| `tau2-telecom` | 36 | coordination | dual-control **human↔agent** conversation (Dec-POMDP) |
|
|
995
|
+
| `hmmt-2025` | 33 | team | math competition **team rounds** |
|
|
996
|
+
| `multichallenge` | 32 | collaborat | multi-turn conversation (instruction retention, self-coherence) |
|
|
997
|
+
| `hmmt25` | 28 | team | math competition team rounds |
|
|
998
|
+
| `tau2-airline` | 24 | coordination | dual-control human↔agent conversation |
|
|
999
|
+
| `automationbench` | 22 | orchestrat | **single-agent** tool orchestration |
|
|
1000
|
+
| `big-bench` | 3 | collaborat | "**collaborative** benchmark" = many contributors |
|
|
1001
|
+
| `phibench` | 3 | team | Microsoft internal math/coding benchmark |
|
|
1002
|
+
| `acebench` | 2 | multi-agent | the **only** multi-agent eval (an "Agent" sub-type); 2 models |
|
|
1003
|
+
| `mcp-universe` | 1 | orchestrat | single-agent MCP tool orchestration |
|
|
1004
|
+
| `cathedralbench` | 1 | team | red-team cyber |
|
|
1005
|
+
| `groundui-1k` | 2 | coordinat | UI grounding |
|
|
1006
|
+
| `swe-bench-verified-(agentic-coding)` | 2 | coordinat | single-agent coding |
|
|
1007
|
+
| `swe-bench-verified-(agentless)` | 2 | coordinat | single-agent coding |
|
|
1008
|
+
| `swe-bench-verified-(multiple-attempts)` | 1 | coordination | single-agent coding |
|
|
1009
|
+
|
|
1010
|
+
A broader sweep of the agentic vocabulary (`agent`, `tool`, `plan`, `memory`,
|
|
1011
|
+
`workflow`, `long-horizon`, `computer-use`, `mcp`, `environment`, `simulat`,
|
|
1012
|
+
`theory of mind`, `cooperat`, `adversar`, …) returns ~40 agentic benchmarks
|
|
1013
|
+
(`toolathlon` 42, `terminal-bench-2` 53, `agents-last-exam` 21, `t2-bench` 23,
|
|
1014
|
+
`nl2repo` 23, `osworld-2.0` 15, `claw-eval` 14, `tau3-banking` 12, `mcp-mark` 9,
|
|
1015
|
+
`coworkbench` 6, `vending-bench-2` 4, …). **Every one is single-agent**
|
|
1016
|
+
long-horizon / tool-use / computer-use; none scores delegation, teams, handoffs,
|
|
1017
|
+
swarms, recovery or a2a. The nearest thing to a multi-agent axis in the whole
|
|
1018
|
+
catalog is `acebench`'s "Agent (multi-agent interactions)" sub-type, at 2 models.
|
|
1019
|
+
|
|
1020
|
+
**Four-axis gate on the candidates with ≥ 3 models** (metric = `bench:<id>`,
|
|
1021
|
+
generic llm-stats source, joined direct on `model_id`):
|
|
1022
|
+
|
|
1023
|
+
| candidate | catalog | loaded | covered | dispersion | composition | freshness | r(general) | r(agents) | gate |
|
|
1024
|
+
|---|---|---|---|---|---|---|---|---|---|
|
|
1025
|
+
| `supergpqa` | 37 | 20 | 20/400 (5.0%) | 0.062 | below-bar (Google, OpenAI) | 3.2 mo | 0.867 | 0.765 | reject |
|
|
1026
|
+
| `mcp-atlas` | 36 | 20 | 20/400 (5.0%) | 0.092 | ok | 1.1 mo | 0.607 | 0.695 | reject |
|
|
1027
|
+
| `tau2-telecom` | 36 | 20 | 20/400 (5.0%) | 0.061 | below-bar (Qwen, Google) | 4.3 mo | 0.735 | 0.429 | reject |
|
|
1028
|
+
| `hmmt-2025` | 33 | 20 | 20/400 (5.0%) | 0.048 | below-bar (Google) | 3.4 mo | 0.615 | 0.199 | reject (dispersion) |
|
|
1029
|
+
| `multichallenge` | 32 | 20 | 20/400 (5.0%) | 0.194 | below-bar (Google) | 3.8 mo | 0.355 | 0.326 | reject |
|
|
1030
|
+
| `hmmt25` | 28 | 20 | 20/400 (5.0%) | 0.147 | below-bar (Google, OpenAI) | 1.1 mo | **0.909** | 0.712 | reject (collinear) |
|
|
1031
|
+
| `tau2-airline` | 24 | 20 | 20/400 (5.0%) | 0.149 | below-bar (Google) | 5.7 mo | 0.694 | 0.439 | reject |
|
|
1032
|
+
| `automationbench` | 22 | 20 | 20/400 (5.0%) | 0.622 | ok | 0.0 mo | 0.242 | 0.299 | **clears all axes** |
|
|
1033
|
+
| `big-bench` | 3 | 3 | 3/400 (0.8%) | 0.045 | below-bar | 27.1 mo | 0.389 | — | reject |
|
|
1034
|
+
| `phibench` | 3 | 3 | 3/400 (0.8%) | 0.128 | below-bar | 17.0 mo | 0.993 | — | reject |
|
|
1035
|
+
| `acebench` | 2 | 2 | 2/400 (0.5%) | 0.000 | below-bar | 12.8 mo | — | — | reject (below 3-model floor) |
|
|
1036
|
+
| `mcp-universe` | 1 | 1 | 1/400 (0.3%) | — | below-bar | 9.9 mo | — | — | reject (below 3-model floor) |
|
|
1037
|
+
|
|
1038
|
+
`automationbench` is the only candidate that clears the implemented nine-axis
|
|
1039
|
+
gate (dispersion 0.62, composition ok, freshness ok, r(general) 0.24,
|
|
1040
|
+
r(agents) 0.30) — but it measures **single-agent tool orchestration**, not
|
|
1041
|
+
delegation / teams / handoffs / swarms / recovery / a2a, and it covers 5% of the
|
|
1042
|
+
field. Landing it under an agentic-axis label would be mislabeling, and the
|
|
1043
|
+
issue forbids a stub or synthetic axis.
|
|
1044
|
+
|
|
1045
|
+
**Coverage ceiling (structural).** The per-benchmark endpoint caps `entries` at
|
|
1046
|
+
`BENCHMARK_ENTRY_CAP = 20` regardless of `limit`/`offset`/`page`/`per_page`, so
|
|
1047
|
+
a generic `bench:<id>` metric can never cover more than 20 of the 400 models —
|
|
1048
|
+
5.0%, against a `FOCUS_COVERAGE_FLOOR` of 0.35 (≥ 140 models). The best-covered
|
|
1049
|
+
agentic candidate in the catalog (`toolathlon`, 42) would still load ≤ 20. The
|
|
1050
|
+
top of the catalog by `model_count` is general-knowledge / coding (`gpqa` 250,
|
|
1051
|
+
`mmlu-pro` 142, `aime-2025` 122, `swe-bench-verified` 116, `humanity's-last-exam`
|
|
1052
|
+
104, `mmlu` 103); the highest-modelCount **agentic** entry is `toolathlon` at 42,
|
|
1053
|
+
and the field already carries `toolathlon_score` (42 covered) from the index
|
|
1054
|
+
payload.
|
|
1055
|
+
|
|
1056
|
+
**The general agentic axis is already covered; the multi-agent sub-axes are
|
|
1057
|
+
not.** The field already carries agentic proxies, all in `KNOWN_METRICS`:
|
|
1058
|
+
`agents` (index) 192/400 (48.0%, r(general) 0.918), `tool_calling` 202/400
|
|
1059
|
+
(50.5%, r(general) 0.799, r(agents) 0.879), `mcp_atlas_score` 36 (9.0%),
|
|
1060
|
+
`toolathlon_score` 42 (10.5%), `osworld_score` 21 (5.3%), `apex_agents_score` 10
|
|
1061
|
+
(2.5%). The agentic-adjacent candidates that do have data are collinear with
|
|
1062
|
+
them (`osworld` r(general) 0.927 / r(agents) 0.921; `browsecomp` 0.897 / 0.916;
|
|
1063
|
+
`toolathlon` 0.828 / 0.858; `mcp_atlas` 0.772 / 0.805), so even a landed
|
|
1064
|
+
tool-orchestration axis would add little independent signal.
|
|
1065
|
+
|
|
1066
|
+
**Verdict: do not land.** No catalog benchmark measures the named axes; the one
|
|
1067
|
+
multi-agent eval is below the 3-model floor; the endpoint cap makes the coverage
|
|
1068
|
+
bar unreachable for any generic benchmark; and the agentic-adjacent candidates
|
|
1069
|
+
are either collinear with the shipped `agents`/`tool_calling` indices or measure
|
|
1070
|
+
single-agent tool use. The honest outcome is the recorded evidence, mirroring
|
|
1071
|
+
the domain-knowledge (#23) and truthfulness (#24) verdicts.
|
|
1072
|
+
|
|
253
1073
|
## Changing a weight — checklist
|
|
254
1074
|
|
|
255
1075
|
1. Keep Σ = 1 and Σ(non-price) = 1 − w_price (rescale the others; do not touch
|
|
@@ -264,3 +1084,7 @@ one." Three findings, each measured on that day's caches:
|
|
|
264
1084
|
4. Re-run the report (`node src/cli/llm-role-rank.ts --top 5`) and check the stderr
|
|
265
1085
|
match/eligible counts; the explorer's `Δ` column measures against the role's
|
|
266
1086
|
effective def.
|
|
1087
|
+
5. A price-weight change is a posture change: measure the leader-flip threshold
|
|
1088
|
+
on the **reachable** pool (rule 6), not the full pool, and record both
|
|
1089
|
+
numbers (reachable and full-pool) in the review. A threshold measured on the
|
|
1090
|
+
wrong pool reads as decoration when it is binding, or vice versa.
|