@konneal/engine 0.2.104 → 0.2.109

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.
Files changed (40) hide show
  1. package/dist/ablate.d.ts +31 -0
  2. package/dist/ask-EAKLN77G.js +15 -0
  3. package/dist/{chunk-25ECO5M7.js → chunk-2R7OVYAO.js} +377 -185
  4. package/dist/{chunk-U4ERFUOK.js → chunk-4NXH5ZI6.js} +1 -1
  5. package/dist/{chunk-DTW4UW2E.js → chunk-DJ65EF5G.js} +1 -1
  6. package/dist/{chunk-NCZHN6QW.js → chunk-G4KBK5XZ.js} +175 -22
  7. package/dist/{chunk-ANUHRJ4Z.js → chunk-G56TYXNN.js} +3 -3
  8. package/dist/{chunk-TFGJ6NYS.js → chunk-HAU5INEJ.js} +5 -5
  9. package/dist/{chunk-KNCRYAX3.js → chunk-TH5XGPD5.js} +1 -1
  10. package/dist/{chunk-BOAITSVV.js → chunk-VT7DR6NQ.js} +11 -1
  11. package/dist/config.d.ts +6 -0
  12. package/dist/openapi-types.d.ts +24 -0
  13. package/dist/prompts/doc-summary.md +1 -0
  14. package/dist/prompts/speculative-verify.md +9 -0
  15. package/dist/route.d.ts +29 -0
  16. package/dist/search-HKGN7F3O.js +13 -0
  17. package/dist/speculative.d.ts +9 -0
  18. package/dist/{tools-EXDADNWX.js → tools-WSWEGJVQ.js} +4 -4
  19. package/dist/worker_mcp/src/index.js +2 -2
  20. package/dist/worker_public/src/config.js +1 -1
  21. package/dist/worker_public/src/index.js +20 -16
  22. package/dist/worker_public/src/requestScope.js +2 -2
  23. package/docs/spec-pipeline.md +12 -1
  24. package/package.json +1 -1
  25. package/workers/worker_public/openapi.yaml +53 -0
  26. package/workers/worker_public/prompts/doc-summary.md +1 -0
  27. package/workers/worker_public/prompts/speculative-verify.md +9 -0
  28. package/workers/worker_public/src/ablate.ts +97 -0
  29. package/workers/worker_public/src/admin.ts +14 -6
  30. package/workers/worker_public/src/ask.ts +120 -16
  31. package/workers/worker_public/src/config.ts +10 -0
  32. package/workers/worker_public/src/pipeline.ts +5 -2
  33. package/workers/worker_public/src/route.ts +77 -0
  34. package/workers/worker_public/src/speculative.ts +39 -0
  35. package/workers/worker_public/src/stages/graphPpr.ts +189 -0
  36. package/workers/worker_public/src/stages/index.ts +19 -0
  37. package/workers/worker_public/src/stages/sectionDescent.ts +91 -7
  38. package/workers/worker_public/src/stages/types.ts +6 -0
  39. package/dist/ask-M3VRAIJB.js +0 -15
  40. package/dist/search-5SNP5CHL.js +0 -13
@@ -19,9 +19,10 @@ import {
19
19
  tableRetyped,
20
20
  toolNote,
21
21
  verdictNote
22
- } from "./chunk-ANUHRJ4Z.js";
22
+ } from "./chunk-G56TYXNN.js";
23
23
  import {
24
24
  NO_CONTEXT,
25
+ STAGE_NAMES,
25
26
  answerQuality,
26
27
  appliedContext,
27
28
  buildMessages,
@@ -33,6 +34,7 @@ import {
33
34
  editionNote,
34
35
  estimateTokens,
35
36
  experimentalSourceLabels,
37
+ fill,
36
38
  graphExpand,
37
39
  identityNote,
38
40
  listwiseRerank,
@@ -43,6 +45,7 @@ import {
43
45
  opCfg,
44
46
  opTokenMember,
45
47
  parseContext,
48
+ promptVars,
46
49
  qualityNote,
47
50
  rawSessionToken,
48
51
  refCodec,
@@ -57,20 +60,20 @@ import {
57
60
  tokenBudget,
58
61
  understandQuery,
59
62
  usageTotal
60
- } from "./chunk-25ECO5M7.js";
63
+ } from "./chunk-2R7OVYAO.js";
61
64
  import {
62
65
  embed,
63
66
  generateOnce,
64
67
  portModelRunner,
65
68
  portStore
66
- } from "./chunk-KNCRYAX3.js";
69
+ } from "./chunk-TH5XGPD5.js";
67
70
  import {
68
71
  corsHeaders,
69
72
  err,
70
73
  json,
71
74
  readJson,
72
75
  validateQuery
73
- } from "./chunk-DTW4UW2E.js";
76
+ } from "./chunk-DJ65EF5G.js";
74
77
  import {
75
78
  canonicalRefusal,
76
79
  refusalAnswer
@@ -80,7 +83,7 @@ import {
80
83
  requestSalt,
81
84
  resolveRequestScope,
82
85
  standardKeysFrom
83
- } from "./chunk-U4ERFUOK.js";
86
+ } from "./chunk-4NXH5ZI6.js";
84
87
  import {
85
88
  LIMITS,
86
89
  MODELS,
@@ -91,7 +94,7 @@ import {
91
94
  requestEffort,
92
95
  roleModel,
93
96
  sha256Hex
94
- } from "./chunk-BOAITSVV.js";
97
+ } from "./chunk-VT7DR6NQ.js";
95
98
  import {
96
99
  certificateLinks,
97
100
  registerNote,
@@ -1335,6 +1338,90 @@ function exactCacheKey(indexVersion, gen, ns, queryHash) {
1335
1338
  return `a:${indexVersion}:g${gen}:${ns}:${queryHash}`;
1336
1339
  }
1337
1340
 
1341
+ // workers/worker_public/src/ablate.ts
1342
+ function parseAblate(body, adminToken, presentedToken, knownStages) {
1343
+ const rawStages = body?.ablate_stages;
1344
+ const noVerdict = body?.ablate_no_verdict === true;
1345
+ const rawRoute = body?.ablate_route;
1346
+ const speculative = body?.ablate_speculative === true;
1347
+ const namesAblation = rawStages !== void 0 && rawStages !== null;
1348
+ const routeAblation = rawRoute !== void 0 && rawRoute !== null && rawRoute !== "adaptive";
1349
+ if (!namesAblation && !noVerdict && !routeAblation && !speculative) return { ok: true, config: null };
1350
+ if (!adminToken || presentedToken !== adminToken) {
1351
+ return {
1352
+ ok: false,
1353
+ status: 403,
1354
+ code: "ablation_forbidden",
1355
+ message: "ablation fields require the admin credential (x-admin-token)"
1356
+ };
1357
+ }
1358
+ let route = "adaptive";
1359
+ if (routeAblation) {
1360
+ if (rawRoute !== "fast" && rawRoute !== "deep") {
1361
+ return { ok: false, status: 400, code: "invalid_ablation", message: 'ablate_route must be "fast", "deep" or "adaptive"' };
1362
+ }
1363
+ route = rawRoute;
1364
+ }
1365
+ let stages = null;
1366
+ if (namesAblation) {
1367
+ if (!Array.isArray(rawStages) || rawStages.length === 0) {
1368
+ return { ok: false, status: 400, code: "invalid_ablation", message: "ablate_stages must be a non-empty array of stage names" };
1369
+ }
1370
+ if (rawStages.some((n) => typeof n !== "string")) {
1371
+ return { ok: false, status: 400, code: "invalid_ablation", message: "ablate_stages must contain only stage-name strings" };
1372
+ }
1373
+ const known = new Set(knownStages);
1374
+ const unknown = rawStages.filter((n) => !known.has(n));
1375
+ if (unknown.length) {
1376
+ return { ok: false, status: 400, code: "invalid_ablation", message: `unknown stage(s): ${unknown.join(", ")}` };
1377
+ }
1378
+ stages = [...new Set(rawStages)];
1379
+ }
1380
+ return { ok: true, config: { stages, noVerdict, route, speculative } };
1381
+ }
1382
+
1383
+ // workers/worker_public/src/route.ts
1384
+ var ROUTE_FAST_WORD_CAP = 10;
1385
+ var ROUTE_FAST_DROPS = ["hyde", "multi-query", "sub-query"];
1386
+ function routeFor(u, query) {
1387
+ const features = [];
1388
+ const words = query.trim().split(/\s+/).filter(Boolean).length;
1389
+ if (u?.complexity === "complex") features.push("complex");
1390
+ if ((u?.sub_queries ?? []).length > 0) features.push("sub-queries");
1391
+ if (u?.process_intent) features.push("process-intent");
1392
+ if (words > ROUTE_FAST_WORD_CAP) features.push("long-question");
1393
+ if (features.length) return { route: "deep", features };
1394
+ if (u?.doc_number) features.push("doc-scoped");
1395
+ if (u?.term) features.push("definitional");
1396
+ if ((u?.defined_terms ?? []).length > 0) features.push("terminology");
1397
+ features.push("short-question");
1398
+ return { route: "fast", features };
1399
+ }
1400
+ function fastRouteStages(registry) {
1401
+ return registry.filter((n) => !ROUTE_FAST_DROPS.includes(n));
1402
+ }
1403
+
1404
+ // workers/worker_public/src/speculative.ts
1405
+ var SPECULATIVE_SUBSETS = 3;
1406
+ function partitionSubsets(hits, k = SPECULATIVE_SUBSETS) {
1407
+ const groups = [];
1408
+ const byDoc = /* @__PURE__ */ new Map();
1409
+ for (const h of hits) {
1410
+ const key = h.metadata.docidentifier || h.metadata.doc_id || "";
1411
+ const arr = byDoc.get(key) ?? [];
1412
+ arr.push(h);
1413
+ if (arr.length === 1) groups.push(arr);
1414
+ byDoc.set(key, arr);
1415
+ }
1416
+ if (groups.length < 2) return null;
1417
+ const subsets = Array.from({ length: Math.min(k, groups.length) }, () => []);
1418
+ groups.forEach((g, i) => subsets[i % subsets.length].push(...g));
1419
+ return subsets;
1420
+ }
1421
+
1422
+ // workers/worker_public/prompts/speculative-verify.md
1423
+ var speculative_verify_default = "You answer questions about legal-metrology publications for {{PUBLISHER_NAME}}. Candidate draft answers were prepared in parallel, each from a PARTIAL view of the evidence (a subset of the passages); you see every candidate beside the FULL passages. Produce the final answer.\n\nRules:\n1. Compare the candidates against the full passages. Adopt the candidate best supported by the evidence as your starting point; correct every claim the full passages contradict or fail to support, and fold in anything the other candidates got right that the adopted one missed.\n2. Ground every factual claim in the numbered passages and cite them inline as [1], [2], \u2026 exactly as the passages are numbered below. Never cite a passage that is not there.\n3. Quote verbatim \u2014 with quotation marks \u2014 when a clause's exact wording matters (definitions, thresholds, requirements); a quotation must appear word-for-word in the passages.\n4. Numeric and table values come from the passages exactly; never retype a table as markdown \u2014 refer to the table and cite it.\n5. If the passages do not answer the question, say so plainly instead of guessing.\n6. Be complete but compact: answer the question, cite, stop.\n";
1424
+
1338
1425
  // workers/worker_public/src/operations.ts
1339
1426
  function isOperationIntent(query) {
1340
1427
  return /\b(operations?|endpoints?)\b/i.test(query);
@@ -1544,6 +1631,43 @@ function userImageDataUrl(body) {
1544
1631
  if (!m || !m[2]) return null;
1545
1632
  return img;
1546
1633
  }
1634
+ var DRAFT_TOKEN_BUDGET = 1600;
1635
+ function speculativeListing(hits) {
1636
+ return hits.map((h, i) => {
1637
+ const id = (h.metadata.docidentifier || h.metadata.doc_id || "source").replace(/\s*\(([A-Z])\)\s*$/, "").trim();
1638
+ const edition = h.metadata.edition && !id.includes(h.metadata.edition) ? ":" + h.metadata.edition : "";
1639
+ const anchor = h.metadata.clause_anchor ? ` \xA7${h.metadata.clause_anchor}` : "";
1640
+ return `[${i + 1}] ${id}${edition}${anchor} ${h.text.replace(/\s+/g, " ").slice(0, 700)}`;
1641
+ }).join("\n\n");
1642
+ }
1643
+ async function speculativeDraftVerify(env, opts) {
1644
+ const subsets = partitionSubsets(opts.hits);
1645
+ if (!subsets) return null;
1646
+ const draftSets = subsets.map(
1647
+ (subset) => buildMessages(opts.query, subset, opts.lang ?? void 0, [], void 0, void 0, DRAFT_TOKEN_BUDGET).messages
1648
+ );
1649
+ const drafts = await Promise.all(
1650
+ draftSets.map((m) => generateOnce(env, opts.draftModel, m, "low").catch(() => null))
1651
+ );
1652
+ const candidates = drafts.map((d) => (d ?? "").trim()).filter((d) => d.length > 0);
1653
+ if (!candidates.length) return null;
1654
+ const candidateText = candidates.map((d, i) => `<candidate ${i + 1} (prepared from a partial view)>
1655
+ ${d}
1656
+ </candidate ${i + 1}>`).join("\n\n");
1657
+ const system = fill(speculative_verify_default.trimEnd(), promptVars({}));
1658
+ const answer = await generateOnce(env, opts.verifierModel, [
1659
+ { role: "system", content: system },
1660
+ { role: "user", content: `Question: ${opts.query}
1661
+
1662
+ Candidate draft answers:
1663
+ ${candidateText}
1664
+
1665
+ Full context passages:
1666
+ ${speculativeListing(opts.hits)}` }
1667
+ ], "low").catch(() => null);
1668
+ if (!answer || !answer.trim()) return null;
1669
+ return { answer, chosen: candidates.length, nDrafts: drafts.length };
1670
+ }
1547
1671
  async function cacheGet(env, gen, ns, query, lang, salt) {
1548
1672
  const key = exactCacheKey(env.INDEX_VERSION, gen, ns, await sha256Hex(cacheKeyMaterial(query, lang, salt)));
1549
1673
  const hit = await env.CACHE.get(key, "json");
@@ -1706,6 +1830,9 @@ async function handleAsk(env, ctx, req, tier, key) {
1706
1830
  const body = await readJson(req);
1707
1831
  const q = validateQuery(body);
1708
1832
  if (!q) return err(400, "invalid_input", `query is required (1-${LIMITS.maxInputChars} chars)`);
1833
+ const ablated = parseAblate(body, env.ADMIN_TOKEN, req.headers.get("x-admin-token"), STAGE_NAMES);
1834
+ if (!ablated.ok) return err(ablated.status, ablated.code, ablated.message);
1835
+ const ablate = ablated.config;
1709
1836
  const declaredCtx = parseContext(body);
1710
1837
  const draftAct = P().publisher.features?.drafts ? detectDraftIntent(q.query) : null;
1711
1838
  const apiCallIntent = !draftAct && P().publisher.features?.api_call_drafts ? detectApiCallIntent(q.query, declaredCtx) : null;
@@ -1720,6 +1847,8 @@ async function handleAsk(env, ctx, req, tier, key) {
1720
1847
  scope: opMember.scope
1721
1848
  } : null);
1722
1849
  const effort = requestEffort(env, member, body?.effort);
1850
+ const declaredEffort = body?.effort;
1851
+ const routeEffort = (route) => route === "fast" && !declaredEffort ? "low" : effort;
1723
1852
  const limit = tier === "key" ? key.day_limit : tier === "member" || member ? num(env, "MEMBER_DAY_ASK", 300) : num(env, "ANON_DAY_ASK", 20);
1724
1853
  const bucketId = tier === "key" ? `key:${key.id}` : member ? `sub:${member.sub}` : clientIp(req);
1725
1854
  const quota = await checkQuota(env, "ask", bucketId, limit, effort === "low" ? 1 : 2);
@@ -1792,7 +1921,7 @@ async function handleAsk(env, ctx, req, tier, key) {
1792
1921
  const fresh = freshRequested(body);
1793
1922
  const gen = await corpusGen(env.CACHE);
1794
1923
  const withImage = effectiveImage || storedImage;
1795
- const cached = fresh || contextual || declaredCtx || draftAct || apiCallIntent || withImage ? null : await cacheGet(env, gen, ns, q.query, q.lang, salt);
1924
+ const cached = fresh || contextual || declaredCtx || draftAct || apiCallIntent || withImage || ablate ? null : await cacheGet(env, gen, ns, q.query, q.lang, salt);
1796
1925
  const wantsStream = body?.stream === true || tier === "anon" && body?.stream !== false;
1797
1926
  if (cached) {
1798
1927
  telemetry(env, ctx, tier, "ask", null, true, (cached.value.answer ?? "").length, cached.value.query_hash, q.lang, "exact", telemetryMeta());
@@ -2066,7 +2195,7 @@ ${summary}` }] : [],
2066
2195
  console.log("model plane: bound", boundModel.node_id, `[${boundModel.standard}]`, boundModel.clause?.urn ?? "no-clause", boundModel.gated ? "(gated: license)" : "");
2067
2196
  }
2068
2197
  const modelNote = boundModel && !boundModel.gated ? modelGroundingBlock(boundModel) : void 0;
2069
- const machineVerdict = boundModel && !boundModel.gated ? evaluate(boundModel.content, q.query) : null;
2198
+ const machineVerdict = boundModel && !boundModel.gated && !ablate?.noVerdict ? evaluate(boundModel.content, q.query) : null;
2070
2199
  const machineNote = machineVerdict && boundModel ? verdictNote(machineVerdict, boundModel) : void 0;
2071
2200
  const modelNodeRows = async (kind, docNum) => {
2072
2201
  const attempt = (num3) => {
@@ -2081,7 +2210,7 @@ ${summary}` }] : [],
2081
2210
  };
2082
2211
  let conditionVerdict = null;
2083
2212
  let conditionStandard = null;
2084
- if (!machineVerdict && !boundModel && P().publisher.features?.model_plane) {
2213
+ if (!machineVerdict && !boundModel && !ablate?.noVerdict && P().publisher.features?.model_plane) {
2085
2214
  const ql = q.query.toLowerCase();
2086
2215
  const severityWord = /\b(severity|test|valid|tolerance|condition|within)\b/.test(ql);
2087
2216
  const stated = quantitiesIn(q.query);
@@ -2195,6 +2324,10 @@ ${summary}` }] : [],
2195
2324
  boundaryNote = boundaryNoteText(match, citing);
2196
2325
  }
2197
2326
  }
2327
+ const routeMode = ablate?.route ?? "adaptive";
2328
+ const routed = routeMode === "adaptive" ? routeFor(understanding, q.query) : { route: routeMode, features: [`forced-${routeMode}`] };
2329
+ const routeSubset = ablate?.stages ?? (routed.route === "fast" ? fastRouteStages(STAGE_NAMES) : null);
2330
+ if (routeSubset) console.log("route:", routed.route, routed.features.join("+"), "\u2014", STAGE_NAMES.length - routeSubset.length, "lanes dropped");
2198
2331
  try {
2199
2332
  const tR = Date.now();
2200
2333
  if (declaredCtx?.kind === "account") {
@@ -2232,7 +2365,8 @@ Answer account questions from these records ONLY: name the record when you use i
2232
2365
  datasetScope: narrowed ? corpora : null,
2233
2366
  standardKeys,
2234
2367
  lexicalBoost,
2235
- licensedDocNumbers
2368
+ licensedDocNumbers,
2369
+ ...routeSubset ? { stageSubset: routeSubset } : {}
2236
2370
  });
2237
2371
  stageTiming["retrieve-core"] = Date.now() - tR;
2238
2372
  console.log("stage: retrieve", Date.now() - tR, "ms");
@@ -2256,7 +2390,7 @@ Answer account questions from these records ONLY: name the record when you use i
2256
2390
  if (grade === "weak" && understanding?.docidentifier) {
2257
2391
  const broaden = `${understanding.standalone_query || q.query} ${understanding.docidentifier}`.trim();
2258
2392
  const tc = Date.now();
2259
- const second = await retrieve(env, q.query, { prev, understanding, queryOverride: broaden, federate, datasetScope: narrowed ? corpora : null, standardKeys, sealScope: declaredScoped ? docScope : null, lexicalBoost });
2393
+ const second = await retrieve(env, q.query, { prev, understanding, queryOverride: broaden, federate, datasetScope: narrowed ? corpora : null, standardKeys, sealScope: declaredScoped ? docScope : null, lexicalBoost, ...routeSubset ? { stageSubset: routeSubset } : {} });
2260
2394
  const grade2 = await gradeRetrieval(env.AI, roleModel(env, "grader"), q.query, second.hits.map((h) => h.text));
2261
2395
  stageTiming.corrective = Date.now() - tc;
2262
2396
  if (grade2 === "good") retrieved = second;
@@ -2269,7 +2403,7 @@ Answer account questions from these records ONLY: name the record when you use i
2269
2403
  const { hits } = retrieved;
2270
2404
  if (hits.length === 0 && !liveRecords?.length && (!boundModel || boundModel.gated)) {
2271
2405
  const answer2 = licenseBoundaryRefusal(modelDocHint?.doc_number ?? understanding?.doc_number ?? null, standardKeys) ?? refusalAnswer();
2272
- const out2 = { answer: answer2, citations: [], model, query_hash: await sha256Hex(q.query), context_applied: ctxApplied };
2406
+ const out2 = { answer: answer2, citations: [], model, query_hash: await sha256Hex(q.query), context_applied: ctxApplied, ...ablate ? { ablate } : {}, route: { route: routed.route, features: routed.features } };
2273
2407
  telemetry(env, ctx, tier, "ask", model, true, answer2.length, out2.query_hash, q.lang, void 0, telemetryMeta());
2274
2408
  return json({ ...out2, quota });
2275
2409
  }
@@ -2359,7 +2493,7 @@ ${q.query}`.replace("\n\n\n\n", "\n\n") }];
2359
2493
  const queryHash = await sha256Hex(q.query);
2360
2494
  const cites = boundModel ? [modelCitation(boundModel), ...citations(usedHits)] : citations(usedHits);
2361
2495
  if (wantsStream) {
2362
- const stream = await generateStream(env, model, messages, effort);
2496
+ const stream = await generateStream(env, model, messages, routeEffort(routed.route));
2363
2497
  if (stream) {
2364
2498
  const encoder = new TextEncoder();
2365
2499
  const sse = new ReadableStream({
@@ -2401,7 +2535,7 @@ ${q.query}`.replace("\n\n\n\n", "\n\n") }];
2401
2535
  ...messages.slice(0, -1),
2402
2536
  { role: "user", content: "The photograph was attached and the register note lists actual matching certificate rows. Present those rows \u2014 number, holder, model, status, and every document link \u2014 as the answer. Do not claim that nothing was provided." },
2403
2537
  messages[messages.length - 1]
2404
- ], effort);
2538
+ ], routeEffort(routed.route));
2405
2539
  if (regen) {
2406
2540
  full = "";
2407
2541
  try {
@@ -2451,7 +2585,7 @@ ${q.query}`.replace("\n\n\n\n", "\n\n") }];
2451
2585
  if (streamed.violations.length > 0) {
2452
2586
  console.log("anchors:", streamed.violations.length, "of", streamed.total, "unverified \u2014 not caching");
2453
2587
  }
2454
- if (streamed.violations.length === 0 && canonical.length > 0 && !contextual && !declaredCtx && !canonical.includes(refusalAnswer())) {
2588
+ if (streamed.violations.length === 0 && canonical.length > 0 && !contextual && !declaredCtx && !canonical.includes(refusalAnswer()) && !ablate) {
2455
2589
  ctx.waitUntil(
2456
2590
  env.CACHE.put(exactCacheKey(env.INDEX_VERSION, gen, ns, await sha256Hex(cacheKeyMaterial(q.query, q.lang, salt))), JSON.stringify({ answer: canonical, citations: cites, model, query_hash: queryHash, ...sourceQuality ? { source_quality: sourceQuality, confidence_note: streamedNote || qualityNote(sourceQuality) } : {}, ...streamedEntailment ? { entailment: streamedEntailment } : {} }), { expirationTtl: LIMITS.cacheTtlSec })
2457
2591
  );
@@ -2470,14 +2604,32 @@ ${q.query}`.replace("\n\n\n\n", "\n\n") }];
2470
2604
  }
2471
2605
  }
2472
2606
  const tGen = Date.now();
2473
- let answer = await generateOnce(env, model, messages, effort);
2607
+ let answer = null;
2608
+ if (ablate?.speculative) {
2609
+ const spec = await speculativeDraftVerify(env, {
2610
+ query: q.query,
2611
+ hits: usedHits,
2612
+ lang: q.lang,
2613
+ draftModel: MODELS.member,
2614
+ verifierModel: roleModel(env, "verifier")
2615
+ }).catch((e) => {
2616
+ console.log("speculative: failed, falling through \u2014", String(e).slice(0, 120));
2617
+ return null;
2618
+ });
2619
+ if (spec) {
2620
+ answer = spec.answer;
2621
+ stageTiming.speculative = Date.now() - tGen;
2622
+ console.log("speculative:", spec.nDrafts, "drafts,", spec.chosen, "viable \u2014 verified");
2623
+ }
2624
+ }
2625
+ if (!answer) answer = await generateOnce(env, model, messages, routeEffort(routed.route));
2474
2626
  if (answer === null) {
2475
2627
  generateRetries += 1;
2476
2628
  const isFigureAttachMessage = (m) => Array.isArray(m.content) && m.content.some((part) => part?.type === "text" && /^The original image of figure unit /.test(part.text ?? ""));
2477
2629
  const flat = messages.filter((m) => !isFigureAttachMessage(m)).map(
2478
2630
  (m) => typeof m.content === "string" ? m : { ...m, content: m.content.filter((p) => p?.type === "text").map((p) => (p?.text ?? "").replace(/\n?\(The user attached an image with this question; interpret it directly when answering\.\)/, "")).join("\n") }
2479
2631
  );
2480
- answer = await generateOnce(env, MODELS.fallback, flat, effort);
2632
+ answer = await generateOnce(env, MODELS.fallback, flat, routeEffort(routed.route));
2481
2633
  }
2482
2634
  if (answer) answer = canonicalRefusal(answer);
2483
2635
  stageTiming.generate = Date.now() - tGen;
@@ -2501,7 +2653,7 @@ ${q.query}`.replace("\n\n\n\n", "\n\n") }];
2501
2653
  const tableUnitId = unreferenced ? used.find((h) => h.metadata.unit_id && h.metadata.block === "table")?.metadata.unit_id : void 0;
2502
2654
  const note = retyped || unreferenced ? `Correction notice: your draft reproduced a table as markdown or presented a served table's data without its reference. Rewrite the answer: describe the table in prose, cite the clause, and write the reference token [[u:${tableUnitId ?? "<unit id>"}]] exactly where the table belongs. Do not render any table as markdown.` : ANCHOR_CORRECTION_NOTE;
2503
2655
  generateRetries += 1;
2504
- const corrected = await generateOnce(env, model, [...messages, { role: "system", content: note }], effort);
2656
+ const corrected = await generateOnce(env, model, [...messages, { role: "system", content: note }], routeEffort(routed.route));
2505
2657
  if (corrected) {
2506
2658
  const correctedAnswer = canonicalRefusal(corrected);
2507
2659
  const retryAnchors = checkQuoteAnchors(correctedAnswer, used.map((h) => h.text));
@@ -2521,11 +2673,12 @@ ${q.query}`.replace("\n\n\n\n", "\n\n") }];
2521
2673
  understanding: { ...understanding, standalone_query: `${understanding?.standalone_query || q.query} ${reflection.missing_info}` },
2522
2674
  sealScope: declaredScoped ? docScope : null,
2523
2675
  datasetScope: narrowed ? corpora : null,
2524
- standardKeys
2676
+ standardKeys,
2677
+ ...routeSubset ? { stageSubset: routeSubset } : {}
2525
2678
  });
2526
2679
  if (retryRetrieve.hits.length > 0) {
2527
2680
  const { messages: retryMessages, usedHits: retryUsed } = buildMessages(q.query, retryRetrieve.hits, q.lang, keptHistory, void 0, summary, budget);
2528
- const retryAnswer = await generateOnce(env, model, retryMessages, effort);
2681
+ const retryAnswer = await generateOnce(env, model, retryMessages, routeEffort(routed.route));
2529
2682
  if (retryAnswer) {
2530
2683
  answer = canonicalRefusal(retryAnswer);
2531
2684
  used = retryUsed;
@@ -2578,8 +2731,8 @@ ${q.query}`.replace("\n\n\n\n", "\n\n") }];
2578
2731
  if (v.support !== "supported") console.log("entailment:", v.support, raced.score, raced.ungrounded_claims?.slice(0, 2));
2579
2732
  }
2580
2733
  }
2581
- const out = { answer, citations: finalCites, ...jsonQuality ? { source_quality: jsonQuality, confidence_note: entailmentNote || qualityNote(jsonQuality), ...entailment ? { entailment } : {}, ...jsonQuality === "ocr" ? { experimental_sources: experimentalSourceLabels(finalCites) } : {} } : {}, model: MODELS.member, query_hash: queryHash, follow_ups: understanding?.follow_ups ?? [], blocks: [...c2ns.blocks, ...verdictBlock ? [verdictBlock] : [], ...conditionBlock ? [conditionBlock] : [], ...aggregationBlock ? [aggregationBlock] : [], ...completionBlocks], context_applied: ctxApplied, ...liveRecords ? { records: liveRecords } : {} };
2582
- const cacheable = !contextual && !declaredCtx && !answer.includes(refusalAnswer()) && finalAnchors.violations.length === 0;
2734
+ const out = { answer, citations: finalCites, ...jsonQuality ? { source_quality: jsonQuality, confidence_note: entailmentNote || qualityNote(jsonQuality), ...entailment ? { entailment } : {}, ...jsonQuality === "ocr" ? { experimental_sources: experimentalSourceLabels(finalCites) } : {} } : {}, model: MODELS.member, query_hash: queryHash, follow_ups: understanding?.follow_ups ?? [], blocks: [...c2ns.blocks, ...verdictBlock ? [verdictBlock] : [], ...conditionBlock ? [conditionBlock] : [], ...aggregationBlock ? [aggregationBlock] : [], ...completionBlocks], context_applied: ctxApplied, ...liveRecords ? { records: liveRecords } : {}, ...ablate ? { ablate } : {}, route: { route: routed.route, features: routed.features } };
2735
+ const cacheable = !contextual && !declaredCtx && !ablate && !answer.includes(refusalAnswer()) && finalAnchors.violations.length === 0;
2583
2736
  if (cacheable) {
2584
2737
  const ck = exactCacheKey(env.INDEX_VERSION, gen, ns, await sha256Hex(cacheKeyMaterial(q.query, q.lang, salt)));
2585
2738
  ctx.waitUntil(env.CACHE.put(ck, JSON.stringify(out), { expirationTtl: LIMITS.cacheTtlSec }));
@@ -4,13 +4,13 @@ import {
4
4
  portIndex,
5
5
  portModelRunner,
6
6
  portStore
7
- } from "./chunk-KNCRYAX3.js";
7
+ } from "./chunk-TH5XGPD5.js";
8
8
  import {
9
9
  standardKeysFrom
10
- } from "./chunk-U4ERFUOK.js";
10
+ } from "./chunk-4NXH5ZI6.js";
11
11
  import {
12
12
  THRESHOLDS
13
- } from "./chunk-BOAITSVV.js";
13
+ } from "./chunk-VT7DR6NQ.js";
14
14
  import {
15
15
  P
16
16
  } from "./chunk-3FYJM7LH.js";
@@ -6,27 +6,27 @@ import {
6
6
  sessionFrom,
7
7
  telemetry,
8
8
  understandQuery
9
- } from "./chunk-25ECO5M7.js";
9
+ } from "./chunk-2R7OVYAO.js";
10
10
  import {
11
11
  portModelRunner
12
- } from "./chunk-KNCRYAX3.js";
12
+ } from "./chunk-TH5XGPD5.js";
13
13
  import {
14
14
  corsHeaders,
15
15
  err,
16
16
  json,
17
17
  readJson,
18
18
  validateQuery
19
- } from "./chunk-DTW4UW2E.js";
19
+ } from "./chunk-DJ65EF5G.js";
20
20
  import {
21
21
  entitlementScope,
22
22
  standardKeysFrom
23
- } from "./chunk-U4ERFUOK.js";
23
+ } from "./chunk-4NXH5ZI6.js";
24
24
  import {
25
25
  LIMITS,
26
26
  MODELS,
27
27
  num,
28
28
  sha256Hex
29
- } from "./chunk-BOAITSVV.js";
29
+ } from "./chunk-VT7DR6NQ.js";
30
30
 
31
31
  // workers/worker_public/src/search.ts
32
32
  async function handleSearch(env, ctx, req, tier, key) {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  answerEffort,
3
3
  effortBudget
4
- } from "./chunk-BOAITSVV.js";
4
+ } from "./chunk-VT7DR6NQ.js";
5
5
 
6
6
  // workers/worker_public/src/ai.ts
7
7
  var delay = (ms) => new Promise((r) => setTimeout(r, ms));
@@ -28,7 +28,12 @@ var MODELS = {
28
28
  // cross-encoder prunes, listwise orders jointly)
29
29
  listwise: "@cf/zai-org/glm-4.7-flash",
30
30
  // deep-research loop (G10): bounded agentic iterations, members-only
31
- research: "@cf/zai-org/glm-5.3-flash"
31
+ research: "@cf/zai-org/glm-5.3-flash",
32
+ // speculative draft-verify (TODO.sota/02 row 2): the strong verifier
33
+ // over the cheap drafts — the research-tier model verifies; the drafter
34
+ // is the standard answer model (MODELS.member). VERIFIER_MODEL swaps it
35
+ // live, same lever as every role.
36
+ verifier: "@cf/zai-org/glm-5.2"
32
37
  };
33
38
  var LIMITS = {
34
39
  /** Attachment quotas (TODO.new-era/8): per-member ceilings so a member's
@@ -65,6 +70,11 @@ var THRESHOLDS = {
65
70
  * pool below the primary dense lane; they must earn their window
66
71
  * slot under the cross-encoder, not by graph membership alone. */
67
72
  graphLaneDiscount: 0.75,
73
+ /** The PPR lane's merge discount (TODO.sota/06, catalog row 4): graph-
74
+ * propagated candidates arrive at the same half-discount the narrowed
75
+ * graph lane pays (rag#137's law — flooding dilutes the pool), and
76
+ * only the cross-encoder's preference survives the cut. */
77
+ pprDiscount: 0.375,
68
78
  licensedLaneScore: 0.5,
69
79
  /** The entailment gate (TODO.new-era/10): the faithfulness scorer
70
80
  * promoted from eval-only onto the serving path. The confidence line
package/dist/config.d.ts CHANGED
@@ -10,6 +10,7 @@ export declare const MODELS: {
10
10
  readonly enrich: "@cf/deepseek-ai/deepseek-v4-pro-0813";
11
11
  readonly listwise: "@cf/zai-org/glm-4.7-flash";
12
12
  readonly research: "@cf/zai-org/glm-5.3-flash";
13
+ readonly verifier: "@cf/zai-org/glm-5.2";
13
14
  };
14
15
  export declare const LIMITS: {
15
16
  /** Attachment quotas (TODO.new-era/8): per-member ceilings so a member's
@@ -37,6 +38,11 @@ export declare const THRESHOLDS: {
37
38
  * pool below the primary dense lane; they must earn their window
38
39
  * slot under the cross-encoder, not by graph membership alone. */
39
40
  readonly graphLaneDiscount: 0.75;
41
+ /** The PPR lane's merge discount (TODO.sota/06, catalog row 4): graph-
42
+ * propagated candidates arrive at the same half-discount the narrowed
43
+ * graph lane pays (rag#137's law — flooding dilutes the pool), and
44
+ * only the cross-encoder's preference survives the cut. */
45
+ readonly pprDiscount: 0.375;
40
46
  readonly licensedLaneScore: 0.5;
41
47
  /** The entailment gate (TODO.new-era/10): the faithfulness scorer
42
48
  * promoted from eval-only onto the serving path. The confidence line
@@ -871,6 +871,24 @@ export interface components {
871
871
  * @default false
872
872
  */
873
873
  fresh: boolean;
874
+ /** @description Research-only (TODO.sota/09): run the retrieval registry projected to these stage names (registry order preserved; unknown names are a 400). Requires the x-admin-token header — a request naming a configuration without it is a 403. Ablated answers bypass every answer cache read and write and echo the active configuration in the response's ablate field. */
875
+ ablate_stages?: string[];
876
+ /**
877
+ * @description Research-only: skip the verdict engine (machine verdicts and condition-set evaluation); the answer model narrates from passages alone. Same admin credential and cache law as ablate_stages.
878
+ * @default false
879
+ */
880
+ ablate_no_verdict: boolean;
881
+ /**
882
+ * @description Research-only (TODO.sota/02 row 2): arm speculative draft-verify — the cheap model drafts an answer per diversified subset of the window in parallel, one strong call verifies every candidate against the full passages and produces the final answer. Same admin credential and cache law as ablate_stages.
883
+ * @default false
884
+ */
885
+ ablate_speculative: boolean;
886
+ /**
887
+ * @description Research-only: force the route (TODO.sota/05). fast drops the candidate-expansion lanes (hyde, multi-query, sub-query) and floors generation effort at low; deep keeps the full registry. adaptive (the default) lets the router decide from understanding's features. Same admin credential and cache law as ablate_stages.
888
+ * @default adaptive
889
+ * @enum {string}
890
+ */
891
+ ablate_route: "fast" | "deep" | "adaptive";
874
892
  /** @description Forces the answer language, for example en or fr. */
875
893
  lang?: string;
876
894
  /** @description The previous question, for conversational context. */
@@ -913,6 +931,12 @@ export interface components {
913
931
  intent?: string;
914
932
  doc?: string | null;
915
933
  edition?: string | null;
934
+ };
935
+ /** @description The adaptive route the ask rode (TODO.sota/05): fast (the registry minus the candidate-expansion lanes, generation effort floored at low) or deep (the full registry), with the features that fired — the telemetry the routing-accuracy analysis reads. */
936
+ route?: {
937
+ /** @enum {string} */
938
+ route?: "fast" | "deep";
939
+ features?: string[];
916
940
  term?: string | null;
917
941
  terms?: string[];
918
942
  lang?: string | null;
@@ -0,0 +1 @@
1
+ You write the document-level summary for a legal-metrology publication in {{PUBLISHER_NAME}}'s retrieval index. The section summaries below cover the publication clause by clause. Write one compact abstract, three to five sentences: what the publication regulates or provides, its scope and applicability, and the structure a reader should know (parts, annexes, where the normative core sits). Use the publication's own terms exactly. No preamble, no headings.
@@ -0,0 +1,9 @@
1
+ You answer questions about legal-metrology publications for {{PUBLISHER_NAME}}. Candidate draft answers were prepared in parallel, each from a PARTIAL view of the evidence (a subset of the passages); you see every candidate beside the FULL passages. Produce the final answer.
2
+
3
+ Rules:
4
+ 1. Compare the candidates against the full passages. Adopt the candidate best supported by the evidence as your starting point; correct every claim the full passages contradict or fail to support, and fold in anything the other candidates got right that the adopted one missed.
5
+ 2. Ground every factual claim in the numbered passages and cite them inline as [1], [2], … exactly as the passages are numbered below. Never cite a passage that is not there.
6
+ 3. Quote verbatim — with quotation marks — when a clause's exact wording matters (definitions, thresholds, requirements); a quotation must appear word-for-word in the passages.
7
+ 4. Numeric and table values come from the passages exactly; never retype a table as markdown — refer to the table and cite it.
8
+ 5. If the passages do not answer the question, say so plainly instead of guessing.
9
+ 6. Be complete but compact: answer the question, cite, stop.
@@ -0,0 +1,29 @@
1
+ export type Route = "fast" | "deep";
2
+ /** Minimal structural shape of the understanding the router reads —
3
+ * the full contract lives in understandContract.ts; this subset keeps
4
+ * the module self-contained. */
5
+ export interface RouteFeatures {
6
+ complexity?: "simple" | "complex" | null;
7
+ doc_number?: string | null;
8
+ term?: string | null;
9
+ defined_terms?: string[];
10
+ sub_queries?: string[];
11
+ process_intent?: boolean;
12
+ }
13
+ /** THRESHOLDS-adjacent policy numbers (declared here until the grid
14
+ * measures them; every steering number lives in one place — this is
15
+ * the router's place). */
16
+ export declare const ROUTE_FAST_WORD_CAP = 10;
17
+ /** The candidate-expansion lanes the fast route drops (the stage
18
+ * names in the registry). */
19
+ export declare const ROUTE_FAST_DROPS: string[];
20
+ /** Route one question from its understanding features. Returns the
21
+ * route and the fired features — the response echoes both, which is
22
+ * the telemetry the routing-accuracy analysis reads (TODO.sota/05). */
23
+ export declare function routeFor(u: RouteFeatures | null, query: string): {
24
+ route: Route;
25
+ features: string[];
26
+ };
27
+ /** The fast route's stage list: the registry minus the expansion lanes.
28
+ * projectStages owns the ordering and validation semantics. */
29
+ export declare function fastRouteStages(registry: readonly string[]): string[];
@@ -0,0 +1,13 @@
1
+ import {
2
+ handleSearch
3
+ } from "./chunk-HAU5INEJ.js";
4
+ import "./chunk-2R7OVYAO.js";
5
+ import "./chunk-TH5XGPD5.js";
6
+ import "./chunk-DJ65EF5G.js";
7
+ import "./chunk-A3QHHUN5.js";
8
+ import "./chunk-4NXH5ZI6.js";
9
+ import "./chunk-VT7DR6NQ.js";
10
+ import "./chunk-3FYJM7LH.js";
11
+ export {
12
+ handleSearch
13
+ };
@@ -0,0 +1,9 @@
1
+ export declare const SPECULATIVE_SUBSETS = 3;
2
+ /** Minimal structural shape the partition reads. */
3
+ export interface Partitionable {
4
+ metadata: {
5
+ docidentifier?: string;
6
+ doc_id?: string;
7
+ };
8
+ }
9
+ export declare function partitionSubsets<T extends Partitionable>(hits: T[], k?: number): T[][] | null;
@@ -4,10 +4,10 @@ import {
4
4
  parseToolCall,
5
5
  runTool,
6
6
  toolNote
7
- } from "./chunk-ANUHRJ4Z.js";
8
- import "./chunk-KNCRYAX3.js";
9
- import "./chunk-U4ERFUOK.js";
10
- import "./chunk-BOAITSVV.js";
7
+ } from "./chunk-G56TYXNN.js";
8
+ import "./chunk-TH5XGPD5.js";
9
+ import "./chunk-4NXH5ZI6.js";
10
+ import "./chunk-VT7DR6NQ.js";
11
11
  import "./chunk-3FYJM7LH.js";
12
12
  export {
13
13
  TOOLS_REGISTRY,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  authenticate
3
- } from "../../chunk-DTW4UW2E.js";
4
- import "../../chunk-BOAITSVV.js";
3
+ } from "../../chunk-DJ65EF5G.js";
4
+ import "../../chunk-VT7DR6NQ.js";
5
5
  import {
6
6
  P,
7
7
  setProfile
@@ -16,7 +16,7 @@ import {
16
16
  roleModel,
17
17
  sha256Hex,
18
18
  today
19
- } from "../../chunk-BOAITSVV.js";
19
+ } from "../../chunk-VT7DR6NQ.js";
20
20
  import "../../chunk-3FYJM7LH.js";
21
21
  export {
22
22
  DATASETS,