opencode-cache-engine 0.3.5 → 0.4.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.
@@ -0,0 +1,440 @@
1
+ // cache-policy-core.mjs
2
+ //
3
+ // Pure policy registry + resolver for CacheEngine (v0.4.0).
4
+ //
5
+ // This module is the structured policy-resolution layer described by
6
+ // docs/cache-policy-inventory.md. It separates four concerns that used to be
7
+ // entangled in a single model-name-to-behavior branch:
8
+ //
9
+ // 1. creator / family classification
10
+ // 2. baseline cache policy (documented facts)
11
+ // 3. model-specific overlays (CacheEngine code behaviors, NOT implied by family)
12
+ // 4. transport capabilities (e.g. OpenRouter affinity), kept separate from
13
+ // creator cache semantics
14
+ //
15
+ // It performs NO network calls and NO runtime documentation lookups. Every
16
+ // registry entry is traceable to docs/cache-policy-inventory.md via
17
+ // `inventoryRef`. Inheritance is always explicit (`inheritsFrom`); "newer means
18
+ // same behavior" is never an unconditional rule.
19
+ //
20
+ // This release does not wire the resolver into runtime hooks. detectPolicy()
21
+ // remains the compatibility classifier until wiring is approved.
22
+
23
+ // ---------------------------------------------------------------------------
24
+ // Model normalization (shared with the legacy classifier)
25
+ // ---------------------------------------------------------------------------
26
+
27
+ // Normalize a model-like object into a searchable haystack. Accepts both the
28
+ // full OpenCode Model ({providerID, id, api:{id,npm}, name}) and slim test
29
+ // objects ({providerID, modelID/apiID}).
30
+ export function modelSignals(model) {
31
+ const m = model && typeof model === "object" ? model : {}
32
+ const api = m.api && typeof m.api === "object" ? m.api : {}
33
+ const providerID = String(m.providerID ?? m.provider ?? "")
34
+ const apiID = String(m.modelID ?? api.id ?? m.id ?? m.apiID ?? "")
35
+ const modelID = String(m.id ?? "")
36
+ const npm = String(api.npm ?? m.npm ?? "")
37
+ const name = String(m.name ?? "")
38
+ const slug = `${apiID} ${modelID}`.trim()
39
+ return { providerID, apiID, modelID, npm, name, slug: slug.toLowerCase() }
40
+ }
41
+
42
+ // OpenAI-ish context is required before we apply GPT-5.6 options, so we never
43
+ // send GPT-5.6-only fields to a non-OpenAI endpoint merely because a model
44
+ // string contains "gpt-5.6". A slug that explicitly starts with openai/ or
45
+ // azure/ (typical for openrouter/azure/openai-compatible routes) also counts
46
+ // because the upstream IS OpenAI. A bare openai-compatible provider with no
47
+ // such slug does NOT count: we must not guess.
48
+ export function isOpenAIish(s) {
49
+ const { providerID, slug, npm } = s
50
+ const p = providerID.toLowerCase()
51
+ if (p === "openai" || p === "azure") return true
52
+ if (slug.startsWith("openai/") || slug.startsWith("azure/")) return true
53
+ if (/@ai-sdk\/openai|@ai-sdk\/azure/.test(npm)) return true
54
+ return false
55
+ }
56
+
57
+ // Candidate ids for exact/alias lookup. Includes the raw apiID/modelID, the
58
+ // lower-cased forms, and a single stripped transport/vendor prefix
59
+ // (e.g. "openai/gpt-5.6-luna" -> "gpt-5.6-luna", "xiaomi/mimo-v2.6-flash" ->
60
+ // "mimo-v2.6-flash"). Prefix stripping is a lookup convenience only and never
61
+ // implies cache semantics.
62
+ function candidateIds(s) {
63
+ const raw = [s.apiID, s.modelID].filter(Boolean).map((v) => String(v).toLowerCase())
64
+ const out = new Set()
65
+ for (const v of raw) {
66
+ out.add(v)
67
+ const stripped = v.replace(/^[a-z0-9._-]+\//, "")
68
+ if (stripped) out.add(stripped)
69
+ }
70
+ return [...out]
71
+ }
72
+
73
+ // ---------------------------------------------------------------------------
74
+ // Baseline policies (documented cache-policy facts, not code behavior)
75
+ // ---------------------------------------------------------------------------
76
+
77
+ export const BASELINES = {
78
+ "openai.gpt56.cache": {
79
+ id: "openai.gpt56.cache",
80
+ creator: "openai",
81
+ appliesTo: "GPT-5.6 and later (OpenAI-documented generation boundary)",
82
+ automatic: true,
83
+ defaultMode: "implicit",
84
+ supportsExplicitBreakpoints: true,
85
+ minCacheTokens: 1024,
86
+ ttl: "30m",
87
+ cacheKeyOptional: true,
88
+ cacheWriteBilled: true,
89
+ usageFields: [
90
+ "input_tokens_details.cached_tokens",
91
+ "input_tokens_details.cache_write_tokens",
92
+ ],
93
+ inventoryRef: "§1 OpenAI",
94
+ },
95
+ "deepseek.kv-cache": {
96
+ id: "deepseek.kv-cache",
97
+ creator: "deepseek",
98
+ appliesTo: "DeepSeek provider-wide (documented default for all users)",
99
+ automatic: true,
100
+ defaultMode: "implicit",
101
+ supportsExplicitBreakpoints: false,
102
+ minCacheTokens: null,
103
+ ttl: null,
104
+ cacheKeyOptional: false,
105
+ cacheWriteBilled: false,
106
+ usageFields: ["prompt_cache_hit_tokens", "prompt_cache_miss_tokens"],
107
+ inventoryRef: "§2 DeepSeek",
108
+ },
109
+ "zai.implicit-cache": {
110
+ id: "zai.implicit-cache",
111
+ creator: "z.ai",
112
+ appliesTo: "Z.AI service-wide implicit context caching",
113
+ automatic: true,
114
+ defaultMode: "implicit",
115
+ supportsExplicitBreakpoints: false,
116
+ minCacheTokens: null,
117
+ ttl: null,
118
+ cacheKeyOptional: false,
119
+ cacheWriteBilled: false,
120
+ usageFields: ["prompt_tokens_details.cached_tokens"],
121
+ inventoryRef: "§3 Z.AI GLM",
122
+ },
123
+ "xiaomi.implicit-cache": {
124
+ id: "xiaomi.implicit-cache",
125
+ creator: "xiaomi",
126
+ appliesTo: "Xiaomi MiMo provider-managed implicit caching",
127
+ automatic: true,
128
+ defaultMode: "implicit",
129
+ supportsExplicitBreakpoints: false,
130
+ minCacheTokens: null,
131
+ ttl: null,
132
+ cacheKeyOptional: false,
133
+ cacheWriteBilled: false,
134
+ usageFields: ["prompt_tokens_details.cached_tokens", "cache_read_input_tokens"],
135
+ inventoryRef: "§4 Xiaomi MiMo",
136
+ },
137
+ "neutral.none": {
138
+ id: "neutral.none",
139
+ creator: "unknown",
140
+ appliesTo: "No registered cache policy; no model-specific optimization implied",
141
+ automatic: false,
142
+ defaultMode: null,
143
+ supportsExplicitBreakpoints: false,
144
+ minCacheTokens: null,
145
+ ttl: null,
146
+ cacheKeyOptional: false,
147
+ cacheWriteBilled: false,
148
+ usageFields: [],
149
+ inventoryRef: "§6 Compatibility Matrix",
150
+ },
151
+ }
152
+
153
+ // ---------------------------------------------------------------------------
154
+ // Model-specific overlays (CacheEngine code behaviors)
155
+ //
156
+ // An overlay is a concrete CacheEngine mutation. It is attached to a family
157
+ // ONLY by explicit registration; being classified into a creator/family never
158
+ // implies an overlay. This is what keeps "is GLM" from automatically meaning
159
+ // "<env> relocation".
160
+ // ---------------------------------------------------------------------------
161
+
162
+ export const OVERLAYS = {
163
+ "gpt56.prompt-cache-options": {
164
+ id: "gpt56.prompt-cache-options",
165
+ family: "gpt-5.6",
166
+ hook: "chat.params",
167
+ behavior: "inject missing promptCacheKey + promptCacheOptions(implicit, 30m)",
168
+ inventoryRef: "§1 OpenAI",
169
+ },
170
+ "glm53.env-relocation": {
171
+ id: "glm53.env-relocation",
172
+ family: "glm-5.3",
173
+ hook: "experimental.chat.system.transform",
174
+ behavior: "relocate the identifiable <env> block to the system tail",
175
+ inventoryRef: "§3 Z.AI GLM",
176
+ },
177
+ "mimo26.env-relocation": {
178
+ id: "mimo26.env-relocation",
179
+ family: "mimo-v2.6",
180
+ hook: "experimental.chat.system.transform",
181
+ behavior: "relocate the identifiable <env> block to the system tail",
182
+ inventoryRef: "§4 Xiaomi MiMo",
183
+ },
184
+ }
185
+
186
+ // ---------------------------------------------------------------------------
187
+ // Transport capabilities (routing), deliberately independent of cache policy
188
+ // ---------------------------------------------------------------------------
189
+
190
+ export const TRANSPORTS = {
191
+ openrouter: {
192
+ id: "openrouter",
193
+ kind: "openrouter",
194
+ sessionAffinityHeader: "x-session-id",
195
+ stickyRouting: true,
196
+ inventoryRef: "§5 OpenRouter transport",
197
+ },
198
+ }
199
+
200
+ function resolveTransport(s) {
201
+ const p = String(s.providerID ?? "").toLowerCase()
202
+ if (p === "openrouter") return { ...TRANSPORTS.openrouter }
203
+ if (!p) {
204
+ return { id: "unknown", kind: "unknown", sessionAffinityHeader: null, stickyRouting: false, inventoryRef: "§5 OpenRouter transport" }
205
+ }
206
+ return { id: p, kind: "direct", sessionAffinityHeader: null, stickyRouting: false, inventoryRef: "§5 OpenRouter transport" }
207
+ }
208
+
209
+ // ---------------------------------------------------------------------------
210
+ // Registry
211
+ //
212
+ // Entries are evaluated in array order, which encodes detection priority and
213
+ // preserves the legacy classifier's precedence (gpt-5.6 > glm-5.3 > mimo-v2.6 >
214
+ // deepseek). `legacy: true` entries reproduce the pre-v0.4.0 detectPolicy()
215
+ // behavior exactly. `legacy: false` entries (gpt-6, Pro UltraSpeed) are
216
+ // available to the new resolver only, so runtime behavior is unchanged until
217
+ // wiring is approved.
218
+ // ---------------------------------------------------------------------------
219
+
220
+ export const POLICY_REGISTRY = [
221
+ {
222
+ id: "openai.gpt-5.6",
223
+ creator: "openai",
224
+ family: "gpt-5.6",
225
+ kind: "family",
226
+ pattern: /gpt-5\.6(?![\d.])/i,
227
+ requiresOpenAIish: true,
228
+ exactIds: ["gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna", "gpt-5.6-cyber"],
229
+ baseline: "openai.gpt56.cache",
230
+ overlays: ["gpt56.prompt-cache-options"],
231
+ legacy: true,
232
+ inventoryRef: "§1 OpenAI",
233
+ },
234
+ {
235
+ id: "openai.gpt-6",
236
+ creator: "openai",
237
+ family: "gpt-6",
238
+ kind: "family",
239
+ pattern: /gpt-6(?![\d.])/i,
240
+ requiresOpenAIish: true,
241
+ exactIds: ["gpt-6-astra", "gpt-6-sol", "gpt-6-luna"],
242
+ baseline: "openai.gpt56.cache",
243
+ inheritsFrom: "gpt-5.6",
244
+ overlays: [],
245
+ legacy: false,
246
+ note: "Documented inheritance of the GPT-5.6-and-later baseline. No CacheEngine overlay is registered for gpt-6 yet.",
247
+ inventoryRef: "§1 OpenAI",
248
+ },
249
+ {
250
+ id: "zai.glm-5.3",
251
+ creator: "z.ai",
252
+ family: "glm-5.3",
253
+ kind: "family",
254
+ pattern: /glm-5\.3(?![\d.])/i,
255
+ exactIds: ["glm-5.3", "glm-5.3-flash", "glm-5.3-flashx"],
256
+ baseline: "zai.implicit-cache",
257
+ overlays: ["glm53.env-relocation"],
258
+ legacy: true,
259
+ inventoryRef: "§3 Z.AI GLM",
260
+ },
261
+ {
262
+ id: "xiaomi.mimo-v2.6",
263
+ creator: "xiaomi",
264
+ family: "mimo-v2.6",
265
+ kind: "family",
266
+ pattern: /mimo-v2\.6-(flash|pro)(?![\w-])/i,
267
+ exactIds: ["mimo-v2.6-flash", "mimo-v2.6-pro"],
268
+ baseline: "xiaomi.implicit-cache",
269
+ overlays: ["mimo26.env-relocation"],
270
+ legacy: true,
271
+ inventoryRef: "§4 Xiaomi MiMo",
272
+ },
273
+ {
274
+ id: "xiaomi.mimo-v2.6-pro-ultraspeed",
275
+ creator: "xiaomi",
276
+ family: "mimo-v2.6",
277
+ kind: "exact",
278
+ exactIds: ["mimo-v2.6-pro-ultraspeed"],
279
+ baseline: "xiaomi.implicit-cache",
280
+ overlays: [],
281
+ legacy: false,
282
+ policyStatus: "documented-series-member-without-registered-overlay",
283
+ note: "Documented as a Pro mode in the same V2.6 series, but the inventory does not establish identical cache controls and CacheEngine registers no overlay for it.",
284
+ inventoryRef: "§4 Xiaomi MiMo",
285
+ },
286
+ {
287
+ id: "deepseek.baseline",
288
+ creator: "deepseek",
289
+ family: "deepseek",
290
+ kind: "creator",
291
+ pattern: /deepseek/i,
292
+ providerPattern: /deepseek/i,
293
+ baseline: "deepseek.kv-cache",
294
+ overlays: [],
295
+ legacy: true,
296
+ inventoryRef: "§2 DeepSeek",
297
+ },
298
+ ]
299
+
300
+ // ---------------------------------------------------------------------------
301
+ // Explicit aliases identified by the inventory
302
+ // ---------------------------------------------------------------------------
303
+
304
+ export const MODEL_ALIASES = {
305
+ "gpt-5.6": { canonicalId: "gpt-5.6-sol", family: "gpt-5.6", creator: "openai", inventoryRef: "§1 OpenAI" },
306
+ "gpt-daybreak-blue-latest": { canonicalId: "gpt-5.6-sol", family: "gpt-5.6", creator: "openai", inventoryRef: "§1 OpenAI" },
307
+ "gpt-daybreak-red-latest": { canonicalId: "gpt-5.6-cyber", family: "gpt-5.6", creator: "openai", inventoryRef: "§1 OpenAI" },
308
+ "deepseek-v4-flash": { canonicalId: "deepseek-flash", family: "deepseek", creator: "deepseek", status: "retired-legacy-id", inventoryRef: "§2 DeepSeek" },
309
+ "deepseek-chat": { canonicalId: null, family: "deepseek", creator: "deepseek", status: "retired", inventoryRef: "§2 DeepSeek" },
310
+ "deepseek-reasoner": { canonicalId: null, family: "deepseek", creator: "deepseek", status: "retired", inventoryRef: "§2 DeepSeek" },
311
+ }
312
+
313
+ // ---------------------------------------------------------------------------
314
+ // Resolution
315
+ // ---------------------------------------------------------------------------
316
+
317
+ function neutralResult(reason, transport) {
318
+ return {
319
+ creator: "unknown",
320
+ family: "neutral",
321
+ baseline: BASELINES["neutral.none"],
322
+ overlays: [],
323
+ transport,
324
+ matchType: "neutral",
325
+ matchReason: reason,
326
+ matchedId: null,
327
+ inventoryRef: null,
328
+ note: null,
329
+ }
330
+ }
331
+
332
+ function overlaysFor(ids) {
333
+ return (ids ?? []).map((id) => OVERLAYS[id]).filter(Boolean)
334
+ }
335
+
336
+ function resultFromEntry(entry, matchType, matchReason, matchedId, transport) {
337
+ return {
338
+ creator: entry.creator,
339
+ family: entry.family,
340
+ baseline: BASELINES[entry.baseline] ?? null,
341
+ overlays: overlaysFor(entry.overlays),
342
+ transport,
343
+ matchType,
344
+ matchReason,
345
+ matchedId: matchedId ?? null,
346
+ inventoryRef: entry.inventoryRef ?? null,
347
+ note: entry.note ?? null,
348
+ }
349
+ }
350
+
351
+ function resultFromFamily(family, creator, matchType, matchReason, matchedId, inventoryRef, note, transport) {
352
+ const entry = POLICY_REGISTRY.find((e) => e.family === family && e.kind !== "exact")
353
+ return {
354
+ creator,
355
+ family,
356
+ baseline: entry ? BASELINES[entry.baseline] ?? null : null,
357
+ overlays: entry ? overlaysFor(entry.overlays) : [],
358
+ transport,
359
+ matchType,
360
+ matchReason,
361
+ matchedId: matchedId ?? null,
362
+ inventoryRef: inventoryRef ?? null,
363
+ note: note ?? null,
364
+ }
365
+ }
366
+
367
+ // Structured resolver. Returns creator, family, baseline, overlays, transport,
368
+ // matchType, and matchReason. Unknown models resolve to a neutral result with
369
+ // an empty overlay list and no model-specific optimization.
370
+ export function resolvePolicy(model) {
371
+ if (!model || typeof model !== "object") {
372
+ return neutralResult("neutral:invalid-model", resolveTransport({}))
373
+ }
374
+ const s = modelSignals(model)
375
+ const transport = resolveTransport(s)
376
+ if (!s.slug) return neutralResult("neutral:no-model-identity", transport)
377
+
378
+ const ids = candidateIds(s)
379
+
380
+ // 1. Explicit aliases (inventory-identified). An alias inherits its target
381
+ // family's context gate, so e.g. an OpenAI alias on a non-OpenAI gateway does
382
+ // not gain a cache policy it would not otherwise have.
383
+ for (const id of ids) {
384
+ const alias = MODEL_ALIASES[id]
385
+ if (!alias) continue
386
+ const familyEntry = POLICY_REGISTRY.find((e) => e.family === alias.family && e.kind !== "exact")
387
+ if (familyEntry?.requiresOpenAIish && !isOpenAIish(s)) continue
388
+ const reason = `alias:${id}->${alias.canonicalId ?? alias.family}`
389
+ return resultFromFamily(alias.family, alias.creator, "exact", reason, id, alias.inventoryRef, alias.status ?? null, transport)
390
+ }
391
+
392
+ // 2. Exact model ids (documented models).
393
+ for (const entry of POLICY_REGISTRY) {
394
+ if (!entry.exactIds || entry.exactIds.length === 0) continue
395
+ const hit = ids.find((id) => entry.exactIds.includes(id))
396
+ if (hit) return resultFromEntry(entry, "exact", `exact-id:${hit}`, hit, transport)
397
+ }
398
+
399
+ // 3. Model family / range patterns.
400
+ for (const entry of POLICY_REGISTRY) {
401
+ if (entry.kind !== "family" || !entry.pattern) continue
402
+ if (!entry.pattern.test(s.slug)) continue
403
+ if (entry.requiresOpenAIish && !isOpenAIish(s)) continue
404
+ return resultFromEntry(entry, "family", `family-pattern:${entry.id}`, null, transport)
405
+ }
406
+
407
+ // 4. Creator baseline.
408
+ for (const entry of POLICY_REGISTRY) {
409
+ if (entry.kind !== "creator") continue
410
+ const slugHit = entry.pattern ? entry.pattern.test(s.slug) : false
411
+ const providerHit = entry.providerPattern ? entry.providerPattern.test(s.providerID) : false
412
+ if (slugHit || providerHit) return resultFromEntry(entry, "creator", `creator-baseline:${entry.id}`, null, transport)
413
+ }
414
+
415
+ return neutralResult("neutral:no-match", transport)
416
+ }
417
+
418
+ // Compatibility classification used by detectPolicy(). Reproduces the
419
+ // pre-v0.4.0 behavior exactly: it considers only `legacy` registry entries,
420
+ // excludes newer-generation/alias/exact-overlay additions, and returns a family
421
+ // string (or "neutral"). Callers map the family to a POLICY_* constant.
422
+ export function resolveLegacyFamily(model) {
423
+ if (!model || typeof model !== "object") return "neutral"
424
+ const s = modelSignals(model)
425
+ if (!s.slug) return "neutral"
426
+ for (const entry of POLICY_REGISTRY) {
427
+ if (!entry.legacy) continue
428
+ if (entry.kind === "family") {
429
+ if (!entry.pattern.test(s.slug)) continue
430
+ if (entry.requiresOpenAIish && !isOpenAIish(s)) continue
431
+ return entry.family
432
+ }
433
+ if (entry.kind === "creator") {
434
+ const slugHit = entry.pattern ? entry.pattern.test(s.slug) : false
435
+ const providerHit = entry.providerPattern ? entry.providerPattern.test(s.providerID) : false
436
+ if (slugHit || providerHit) return entry.family
437
+ }
438
+ }
439
+ return "neutral"
440
+ }
@@ -48,6 +48,14 @@ import {
48
48
  toolFingerprint,
49
49
  toolWireFingerprint,
50
50
  } from "../src/cache-engine-core.mjs"
51
+ import {
52
+ BASELINES,
53
+ MODEL_ALIASES,
54
+ OVERLAYS,
55
+ POLICY_REGISTRY,
56
+ resolveLegacyFamily,
57
+ resolvePolicy,
58
+ } from "../src/cache-policy-core.mjs"
51
59
 
52
60
  const asst = (id, read, write) => ({
53
61
  info: { id, role: "assistant", tokens: { cache: { read, write } } },
@@ -1316,3 +1324,230 @@ test("affinity telemetry preserves non-OpenRouter families and reports provider
1316
1324
  assert.equal(glmChange.to.providerID, "zai")
1317
1325
  assert.equal(glmChange.policy, POLICY_GLM53)
1318
1326
  })
1327
+
1328
+ // ===========================================================================
1329
+ // v0.4.0 policy registry + resolvePolicy() (research-backed, pure, unwired)
1330
+ //
1331
+ // The inventory (docs/cache-policy-inventory.md) is the authority. These tests
1332
+ // assert the structured resolution layer and that detectPolicy() remains
1333
+ // byte-compatible with its pre-v0.4.0 behavior.
1334
+ // ===========================================================================
1335
+
1336
+ const overlayIds = (r) => r.overlays.map((o) => o.id)
1337
+ const baseId = (r) => (r.baseline ? r.baseline.id : null)
1338
+
1339
+ test("resolvePolicy: GPT-5.6 exact + inventory aliases resolve to the gpt-5.6 family", () => {
1340
+ const exact = resolvePolicy(M("openai", "gpt-5.6-sol"))
1341
+ assert.equal(exact.creator, "openai")
1342
+ assert.equal(exact.family, "gpt-5.6")
1343
+ assert.equal(exact.matchType, "exact")
1344
+ assert.equal(baseId(exact), "openai.gpt56.cache")
1345
+ assert.deepEqual(overlayIds(exact), ["gpt56.prompt-cache-options"])
1346
+ assert.equal(exact.transport.kind, "direct")
1347
+
1348
+ // Inventory alias: gpt-5.6 -> gpt-5.6-sol
1349
+ const alias = resolvePolicy(M("openai", "gpt-5.6"))
1350
+ assert.equal(alias.family, "gpt-5.6")
1351
+ assert.equal(alias.matchType, "exact")
1352
+ assert.ok(alias.matchReason.startsWith("alias:gpt-5.6"))
1353
+ assert.deepEqual(overlayIds(alias), ["gpt56.prompt-cache-options"])
1354
+
1355
+ // OpenRouter-prefixed documented variant resolves by exact id (prefix stripped)
1356
+ const orVariant = resolvePolicy(M("openrouter", "openai/gpt-5.6-luna"))
1357
+ assert.equal(orVariant.family, "gpt-5.6")
1358
+ assert.equal(orVariant.matchType, "exact")
1359
+ })
1360
+
1361
+ test("resolvePolicy: GPT-6 resolves via explicit documented inheritance, with no overlay", () => {
1362
+ const r = resolvePolicy(M("openrouter", "openai/gpt-6-luna"))
1363
+ assert.equal(r.creator, "openai")
1364
+ assert.equal(r.family, "gpt-6")
1365
+ assert.equal(baseId(r), "openai.gpt56.cache")
1366
+ assert.deepEqual(overlayIds(r), [])
1367
+ assert.equal(resolvePolicy(M("openai", "gpt-6-astra")).family, "gpt-6")
1368
+
1369
+ // Inheritance is explicit, not "newer means same": the registry records it.
1370
+ const gpt6 = POLICY_REGISTRY.find((e) => e.family === "gpt-6")
1371
+ assert.equal(gpt6.inheritsFrom, "gpt-5.6")
1372
+ assert.ok(gpt6.inventoryRef)
1373
+ // And no overlay is implied by that inheritance.
1374
+ assert.deepEqual(gpt6.overlays, [])
1375
+ })
1376
+
1377
+ test("resolvePolicy: GPT-6 is not classified by the legacy detectPolicy wrapper", () => {
1378
+ // Intentional: the new layer knows gpt-6, the compatibility wrapper does not.
1379
+ assert.equal(detectPolicy(M("openai", "gpt-6-astra")), POLICY_NEUTRAL)
1380
+ assert.equal(resolvePolicy(M("openai", "gpt-6-astra")).family, "gpt-6")
1381
+ })
1382
+
1383
+ test("resolvePolicy: pre-5.6 GPT negative controls are neutral with no overlays", () => {
1384
+ for (const id of ["gpt-5.5", "gpt-5.4", "gpt-5.2", "gpt-5.1", "gpt-5", "gpt-4.1", "gpt-4o"]) {
1385
+ const r = resolvePolicy(M("openai", id))
1386
+ assert.equal(r.family, "neutral", `${id} must be neutral`)
1387
+ assert.deepEqual(overlayIds(r), [])
1388
+ assert.equal(r.matchType, "neutral")
1389
+ }
1390
+ })
1391
+
1392
+ test("resolvePolicy: DeepSeek V4 / V4.1 resolve to the creator baseline (passive, no overlay)", () => {
1393
+ const v4 = resolvePolicy(M("deepseek", "deepseek-v4-pro"))
1394
+ assert.equal(v4.creator, "deepseek")
1395
+ assert.equal(v4.family, "deepseek")
1396
+ assert.equal(v4.matchType, "creator")
1397
+ assert.equal(baseId(v4), "deepseek.kv-cache")
1398
+ assert.deepEqual(overlayIds(v4), [])
1399
+
1400
+ assert.equal(resolvePolicy(M("deepseek", "deepseek-flash")).family, "deepseek")
1401
+
1402
+ // Inventory alias: retired deepseek-v4-flash -> deepseek-flash
1403
+ const legacy = resolvePolicy(M("deepseek", "deepseek-v4-flash"))
1404
+ assert.equal(legacy.family, "deepseek")
1405
+ assert.ok(legacy.matchReason.startsWith("alias:deepseek-v4-flash"))
1406
+
1407
+ // pre-V4 negative control still resolves to the creator baseline
1408
+ assert.equal(resolvePolicy(M("deepseek", "deepseek-chat")).family, "deepseek")
1409
+ })
1410
+
1411
+ test("resolvePolicy: GLM-5.3 + documented 5.3 variants carry the overlay; 5.2 and earlier do not", () => {
1412
+ const r = resolvePolicy(M("zai", "glm-5.3"))
1413
+ assert.equal(r.creator, "z.ai")
1414
+ assert.equal(r.family, "glm-5.3")
1415
+ assert.equal(baseId(r), "zai.implicit-cache")
1416
+ assert.deepEqual(overlayIds(r), ["glm53.env-relocation"])
1417
+
1418
+ assert.equal(resolvePolicy(M("zai", "glm-5.3-flash")).family, "glm-5.3")
1419
+ assert.equal(resolvePolicy(M("z-ai", "glm-5.3-flashx")).family, "glm-5.3")
1420
+
1421
+ for (const id of ["glm-5.2", "glm-5.1", "glm-5", "glm-4.7", "glm-4.6", "glm-4.5"]) {
1422
+ const g = resolvePolicy(M("zai", id))
1423
+ assert.equal(g.family, "neutral", `${id} must be neutral`)
1424
+ assert.deepEqual(overlayIds(g), [])
1425
+ }
1426
+ })
1427
+
1428
+ test("resolvePolicy: MiMo V2.6 Flash/Pro carry the overlay; Pro UltraSpeed is an explicit no-overlay series member", () => {
1429
+ const flash = resolvePolicy(M("xiaomi", "mimo-v2.6-flash"))
1430
+ assert.equal(flash.creator, "xiaomi")
1431
+ assert.equal(flash.family, "mimo-v2.6")
1432
+ assert.equal(baseId(flash), "xiaomi.implicit-cache")
1433
+ assert.deepEqual(overlayIds(flash), ["mimo26.env-relocation"])
1434
+
1435
+ const pro = resolvePolicy(M("xiaomi", "mimo-v2.6-pro"))
1436
+ assert.equal(pro.family, "mimo-v2.6")
1437
+ assert.deepEqual(overlayIds(pro), ["mimo26.env-relocation"])
1438
+
1439
+ // Documented as the same V2.6 series but with NO registered overlay.
1440
+ const ultraspeed = resolvePolicy(M("xiaomi", "mimo-v2.6-pro-ultraspeed"))
1441
+ assert.equal(ultraspeed.family, "mimo-v2.6")
1442
+ assert.equal(ultraspeed.matchType, "exact")
1443
+ assert.deepEqual(overlayIds(ultraspeed), [])
1444
+ const uEntry = POLICY_REGISTRY.find((e) => e.id === "xiaomi.mimo-v2.6-pro-ultraspeed")
1445
+ assert.equal(uEntry.policyStatus, "documented-series-member-without-registered-overlay")
1446
+
1447
+ const v25 = resolvePolicy(M("xiaomi", "mimo-v2.5"))
1448
+ assert.equal(v25.family, "neutral")
1449
+ assert.deepEqual(overlayIds(v25), [])
1450
+ })
1451
+
1452
+ test("resolvePolicy: overlays are never implied by creator/family classification", () => {
1453
+ // Being GLM/MiMo/DeepSeek does not by itself grant a transformation overlay.
1454
+ assert.deepEqual(overlayIds(resolvePolicy(M("zai", "glm-4.6"))), [])
1455
+ assert.deepEqual(overlayIds(resolvePolicy(M("xiaomi", "mimo-v2.5"))), [])
1456
+ assert.deepEqual(overlayIds(resolvePolicy(M("deepseek", "deepseek-v4-pro"))), [])
1457
+ // A hypothetical future GLM does not silently inherit the 5.3 overlay.
1458
+ assert.deepEqual(overlayIds(resolvePolicy(M("zai", "glm-5.4"))), [])
1459
+ })
1460
+
1461
+ test("resolvePolicy: malformed and unknown model ids resolve safely", () => {
1462
+ for (const bad of [undefined, null, {}, 42, "gpt-5.6", [], true]) {
1463
+ const r = resolvePolicy(bad)
1464
+ assert.equal(r.family, "neutral")
1465
+ assert.equal(r.matchType, "neutral")
1466
+ assert.equal(baseId(r), "neutral.none")
1467
+ assert.deepEqual(r.overlays, [])
1468
+ }
1469
+ // A provider with no model identity gets no family.
1470
+ assert.equal(resolvePolicy({ providerID: "openai" }).family, "neutral")
1471
+ })
1472
+
1473
+ test("resolvePolicy: unknown providers/creators do not gain policy from transport identity", () => {
1474
+ const orUnknown = resolvePolicy(M("openrouter", "acme/mystery-model-9"))
1475
+ assert.equal(orUnknown.family, "neutral")
1476
+ assert.deepEqual(orUnknown.overlays, [])
1477
+ assert.equal(orUnknown.transport.kind, "openrouter")
1478
+ assert.equal(orUnknown.transport.sessionAffinityHeader, "x-session-id")
1479
+
1480
+ // gpt-5.6 on a non-OpenAI gateway stays neutral even though the id looks OpenAI
1481
+ assert.equal(resolvePolicy(M("some-gateway", "gpt-5.6")).family, "neutral")
1482
+ assert.equal(resolvePolicy(M("xiaomi", "not-a-mimo")).family, "neutral")
1483
+ })
1484
+
1485
+ test("resolvePolicy: transport is computed independently from cache policy", () => {
1486
+ const ds = resolvePolicy(M("deepseek", "deepseek-v4-pro"))
1487
+ assert.equal(ds.transport.kind, "direct")
1488
+ assert.equal(ds.transport.sessionAffinityHeader, null)
1489
+
1490
+ const or = resolvePolicy(M("openrouter", "openai/gpt-5.6-luna"))
1491
+ assert.equal(or.family, "gpt-5.6")
1492
+ assert.equal(or.transport.kind, "openrouter")
1493
+ assert.equal(or.transport.sessionAffinityHeader, "x-session-id")
1494
+
1495
+ const zai = resolvePolicy(M("zai", "glm-5.3"))
1496
+ assert.equal(zai.transport.kind, "direct")
1497
+ assert.equal(zai.transport.sessionAffinityHeader, null)
1498
+
1499
+ const noProvider = resolvePolicy({ modelID: "gpt-6-astra" })
1500
+ assert.equal(noProvider.transport.kind, "unknown")
1501
+ })
1502
+
1503
+ test("resolvePolicy is pure and does not mutate its input", () => {
1504
+ const model = Object.freeze({ providerID: "openai", modelID: "gpt-5.6-sol" })
1505
+ const r = resolvePolicy(model)
1506
+ assert.equal(r.family, "gpt-5.6")
1507
+ assert.equal(model.modelID, "gpt-5.6-sol")
1508
+ })
1509
+
1510
+ test("detectPolicy remains compatible with the legacy family resolution", () => {
1511
+ const legacyMap = {
1512
+ "gpt-5.6": POLICY_GPT56,
1513
+ "glm-5.3": POLICY_GLM53,
1514
+ "mimo-v2.6": POLICY_MIMO26,
1515
+ deepseek: POLICY_DEEPSEEK,
1516
+ }
1517
+ const samples = [
1518
+ M("openrouter", "openai/gpt-5.6-luna"),
1519
+ M("openai", "gpt-5.6"),
1520
+ M("openai-compatible", "gpt-5.6"),
1521
+ M("openai", "gpt-5.5"),
1522
+ M("zai", "glm-5.3-flash"),
1523
+ M("zai", "glm-4.6"),
1524
+ M("xiaomi", "mimo-v2.6-flash"),
1525
+ M("xiaomi", "mimo-v2.6-pro-ultraspeed"),
1526
+ M("xiaomi", "mimo-v2.5"),
1527
+ M("deepseek", "deepseek-chat"),
1528
+ M("openrouter", "x-ai/grok-4"),
1529
+ M("anthropic", "claude-sonnet-4-5"),
1530
+ {},
1531
+ null,
1532
+ undefined,
1533
+ 42,
1534
+ ]
1535
+ for (const m of samples) {
1536
+ const expected = legacyMap[resolveLegacyFamily(m)] ?? POLICY_NEUTRAL
1537
+ assert.equal(detectPolicy(m), expected)
1538
+ }
1539
+ })
1540
+
1541
+ test("registry is traceable and internally consistent", () => {
1542
+ for (const entry of POLICY_REGISTRY) {
1543
+ assert.ok(entry.inventoryRef, `${entry.id} must cite the inventory`)
1544
+ assert.ok(BASELINES[entry.baseline], `${entry.id} baseline must exist`)
1545
+ for (const overlayId of entry.overlays) {
1546
+ assert.ok(OVERLAYS[overlayId], `${entry.id} overlay ${overlayId} must exist`)
1547
+ }
1548
+ }
1549
+ for (const [id, alias] of Object.entries(MODEL_ALIASES)) {
1550
+ assert.ok(alias.inventoryRef, `alias ${id} must cite the inventory`)
1551
+ assert.ok(alias.family)
1552
+ }
1553
+ })