@konneal/engine 0.2.27 → 0.2.29

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.
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  handleAsk
3
- } from "./chunk-JVN6SQAT.js";
4
- import "./chunk-4G5OGWXY.js";
3
+ } from "./chunk-ODHIVW3M.js";
4
+ import "./chunk-BHWG556Q.js";
5
5
  import "./chunk-2RKYO3OC.js";
6
6
  import "./chunk-A3QHHUN5.js";
7
7
  import "./chunk-JGKSUSF5.js";
@@ -22747,12 +22747,24 @@ var federate = {
22747
22747
  // workers/worker_public/src/stages/seal.ts
22748
22748
  var seal = {
22749
22749
  name: "seal",
22750
- when: (c) => !!c.opts.sealScope,
22750
+ when: (c) => !!c.opts.sealScope || !!c.opts.editionSteer,
22751
22751
  run: (c) => {
22752
22752
  const before = c.hits.length;
22753
22753
  const scope = c.opts.sealScope;
22754
- c.hits = c.hits.filter((h) => h.metadata.doc_number === scope.doc_number && (!scope.edition || h.metadata.edition === scope.edition));
22755
- console.log("context seal:", before, "\u2192", c.hits.length, "candidates within", `doc#${scope.doc_number}${scope.edition ? "@" + scope.edition : ""}`);
22754
+ if (scope) {
22755
+ c.hits = c.hits.filter((h) => h.metadata.doc_number === scope.doc_number && (!scope.edition || h.metadata.edition === scope.edition));
22756
+ console.log("context seal:", before, "\u2192", c.hits.length, "candidates within", `doc#${scope.doc_number}${scope.edition ? "@" + scope.edition : ""}`);
22757
+ return;
22758
+ }
22759
+ const steer = c.opts.editionSteer;
22760
+ const current = [];
22761
+ const superseded = [];
22762
+ for (const h of c.hits) {
22763
+ const same = h.metadata.doc_number === steer.doc_number;
22764
+ (same && h.metadata.edition !== steer.edition ? superseded : current).push(h);
22765
+ }
22766
+ c.hits = [...current, ...superseded];
22767
+ console.log("edition steer:", superseded.length, "superseded candidates demoted behind", current.length, "current-edition candidates of", `doc#${steer.doc_number}@${steer.edition}`);
22756
22768
  }
22757
22769
  };
22758
22770
 
@@ -28,7 +28,7 @@ import {
28
28
  syntheticUnderstanding,
29
29
  telemetry,
30
30
  understandQuery
31
- } from "./chunk-4G5OGWXY.js";
31
+ } from "./chunk-BHWG556Q.js";
32
32
  import {
33
33
  corsHeaders,
34
34
  err,
@@ -2188,7 +2188,7 @@ Answer account questions from these records ONLY: name the record when you use i
2188
2188
  // the evidence view's ground truth: the exact passages this
2189
2189
  // answer was built from, compact — cache hits carry none,
2190
2190
  // because the cache stores the answer and never the passages
2191
- passages: usedHits.slice(0, 8).map((h) => ({ d: h.metadata.docidentifier ?? "", a: h.metadata.clause_anchor ?? "", t: (h.text ?? "").slice(0, 600), ...h.metadata.table_selection ? { s: h.metadata.table_selection } : {} }))
2191
+ passages: usedHits.slice(0, 8).map((h) => ({ d: h.metadata.docidentifier ?? "", a: h.metadata.clause_anchor ?? "", t: (h.text ?? "").slice(0, h.metadata.block === "table" ? 1400 : 600), b: h.metadata.block === "table" || void 0, ...h.metadata.table_selection ? { s: h.metadata.table_selection } : {} }))
2192
2192
  });
2193
2193
  telemetry(env, ctx, tier, "ask", model, true, c2.text.length, queryHash, q.lang, void 0, telemetryMeta());
2194
2194
  const canonical = c2.text;
@@ -2367,6 +2367,8 @@ export {
2367
2367
  handleMemories,
2368
2368
  checkQuoteAnchors,
2369
2369
  standardForDocNumber,
2370
+ bindModelNode,
2371
+ modelGroundingBlock,
2370
2372
  scoreJudge,
2371
2373
  handleAsk
2372
2374
  };
@@ -7,7 +7,7 @@ import {
7
7
  sessionFrom,
8
8
  telemetry,
9
9
  understandQuery
10
- } from "./chunk-4G5OGWXY.js";
10
+ } from "./chunk-BHWG556Q.js";
11
11
  import {
12
12
  corsHeaders,
13
13
  err,
@@ -1 +1,4 @@
1
- export declare function buildJudgeContext(passages: string[], machine?: string[]): string;
1
+ export declare function buildJudgeContext(passages: (string | {
2
+ text: string;
3
+ table?: boolean;
4
+ })[], machine?: string[]): string;
@@ -3,4 +3,7 @@ export interface FaithfulnessResult {
3
3
  score: number;
4
4
  ungrounded_claims: string[];
5
5
  }
6
- export declare function scoreFaithfulness(ai: any, model: string, answer: string, passages: string[], machine?: string[]): Promise<FaithfulnessResult | null>;
6
+ export declare function scoreFaithfulness(ai: any, model: string, answer: string, passages: (string | {
7
+ text: string;
8
+ table?: boolean;
9
+ })[], machine?: string[]): Promise<FaithfulnessResult | null>;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  handleSearch
3
- } from "./chunk-5LCPKJ6V.js";
4
- import "./chunk-4G5OGWXY.js";
3
+ } from "./chunk-RI2SRLZY.js";
4
+ import "./chunk-BHWG556Q.js";
5
5
  import "./chunk-2RKYO3OC.js";
6
6
  import "./chunk-A3QHHUN5.js";
7
7
  import "./chunk-JGKSUSF5.js";
@@ -1,13 +1,15 @@
1
1
  import {
2
2
  handleSearch
3
- } from "../../chunk-5LCPKJ6V.js";
3
+ } from "../../chunk-RI2SRLZY.js";
4
4
  import {
5
+ bindModelNode,
5
6
  checkQuoteAnchors,
6
7
  handleAsk,
7
8
  handleMemories,
9
+ modelGroundingBlock,
8
10
  scoreJudge,
9
11
  standardForDocNumber
10
- } from "../../chunk-JVN6SQAT.js";
12
+ } from "../../chunk-ODHIVW3M.js";
11
13
  import {
12
14
  buildMessages,
13
15
  citations,
@@ -25,11 +27,12 @@ import {
25
27
  parseAppliedContext,
26
28
  portModelRunner,
27
29
  promptVars,
30
+ refCodec,
28
31
  retrieve,
29
32
  sessionFrom,
30
33
  telemetry,
31
34
  understandQuery
32
- } from "../../chunk-4G5OGWXY.js";
35
+ } from "../../chunk-BHWG556Q.js";
33
36
  import {
34
37
  authenticate,
35
38
  corsHeaders,
@@ -390,7 +393,11 @@ function parseVerdict(text) {
390
393
 
391
394
  // workers/worker_public/src/faithfulness-context.ts
392
395
  function buildJudgeContext(passages, machine = []) {
393
- const context = passages.slice(0, 8).map((p, i) => `[${i + 1}] ${p.replace(/\s+/g, " ").slice(0, 900)}`).join("\n");
396
+ const context = passages.slice(0, 8).map((p, i) => {
397
+ const text = typeof p === "string" ? p : p.text;
398
+ const limit = typeof p !== "string" && p.table ? 2400 : 1400;
399
+ return `[${i + 1}] ${text.replace(/\s+/g, " ").slice(0, limit)}`;
400
+ }).join("\n");
394
401
  const machineContext = machine.length ? "\n" + machine.slice(0, 6).map((m) => `[M] ${m.replace(/\s+/g, " ").slice(0, 400)}`).join("\n") : "";
395
402
  return context + machineContext;
396
403
  }
@@ -989,7 +996,7 @@ async function handleMcp(env, ctx, req, tier, key) {
989
996
  // stream:false forces the JSON lane (anon defaults to SSE)
990
997
  body: JSON.stringify({ ...args, stream: false })
991
998
  });
992
- const res = name === "ask" ? await (await import("../../ask-Y7L6MDAV.js")).handleAsk(env, ctx, inner, tier, key) : await (await import("../../search-4UK3RBEQ.js")).handleSearch(env, ctx, inner, tier, key);
999
+ const res = name === "ask" ? await (await import("../../ask-UAJHC6U7.js")).handleAsk(env, ctx, inner, tier, key) : await (await import("../../search-ICNVGXUY.js")).handleSearch(env, ctx, inner, tier, key);
993
1000
  return res.json().catch(() => ({ error: { message: "tool transport failed", status: res.status } }));
994
1001
  });
995
1002
  if (out.ok && "accepted" in out) return new Response(null, { status: 202 });
@@ -1448,7 +1455,22 @@ async function verifyRoute(c) {
1448
1455
  if (!answer || !query) return err(400, "invalid_input", "answer and query are required");
1449
1456
  try {
1450
1457
  const u = await understandQuery(env.AI, roleModel(env, "understand"), query, [], []);
1451
- const retrieved = await retrieve(env, query, { understanding: u, standardKeys: entitlementScope(standardKeysFrom(body)) });
1458
+ let lexicalBoost;
1459
+ let editionSteer = null;
1460
+ try {
1461
+ const fam = u?.doc_number ? refCodec().familyOf(u.doc_number) : null;
1462
+ if (fam) {
1463
+ const row = await env.DB.prepare("SELECT edition FROM documents WHERE family = ?1 AND active = 1 ORDER BY edition DESC LIMIT 1").bind(fam).first().catch(() => null);
1464
+ if (row?.edition) {
1465
+ lexicalBoost = String(row.edition);
1466
+ editionSteer = { doc_number: fam.split("-").pop() ?? "", edition: String(row.edition) };
1467
+ }
1468
+ }
1469
+ } catch {
1470
+ }
1471
+ const bound = await bindModelNode(env, { query, standardKeys: entitlementScope(standardKeysFrom(body)) });
1472
+ const modelGrounding = bound && !bound.gated ? modelGroundingBlock(bound) : null;
1473
+ const retrieved = await retrieve(env, query, { understanding: u, standardKeys: entitlementScope(standardKeysFrom(body)), lexicalBoost, editionSteer });
1452
1474
  const passages = retrieved.hits.map((h) => h.text);
1453
1475
  const anchors = checkQuoteAnchors(answer, passages);
1454
1476
  const refs = [...answer.matchAll(/\[\[u:([^\]]+)\]\]/g)].map((m) => m[1]);
@@ -1459,7 +1481,8 @@ async function verifyRoute(c) {
1459
1481
  { name: "citations_present", deterministic: true, pass: new RegExp(`\\[[^\\]]*(${P().publisher.name})[^\\]]*\\]`).test(answer), detail: "normative claims should carry a passage citation" }
1460
1482
  ];
1461
1483
  const machine = (Array.isArray(body?.blocks) ? body.blocks : []).filter((b) => b?.type === "verdict" && b?.payload).map((b) => [b.payload.check, b.payload.meaning, b.payload.definition, b.payload.violation_meaning].filter((x) => typeof x === "string" && x).join(" \u2014 ")).filter(Boolean);
1462
- const faith = await scoreFaithfulness(env.AI, roleModel(env, "grader"), answer, retrieved.hits.map((h) => h.text), machine);
1484
+ if (modelGrounding) machine.unshift(modelGrounding);
1485
+ const faith = await scoreFaithfulness(env.AI, roleModel(env, "grader"), answer, retrieved.hits.map((h) => ({ text: h.text, table: h.metadata.block === "table" || void 0 })), machine);
1463
1486
  return json({
1464
1487
  checks,
1465
1488
  judged: faith ? { name: "faithfulness", deterministic: false, score: faith.score, ungrounded_claims: faith.ungrounded_claims.slice(0, 5) } : null,
package/package.json CHANGED
@@ -27,7 +27,7 @@
27
27
  "playwright": "^1.62.1",
28
28
  "yaml": "^2.9.1"
29
29
  },
30
- "version": "0.2.27",
30
+ "version": "0.2.29",
31
31
  "description": "The Konneal engine: the publisher-agnostic build pipeline and API plane for standards intelligence (retrieval, answer contract, verdicts, evaluation).",
32
32
  "license": "BSD-3-Clause",
33
33
  "type": "module",
@@ -1098,7 +1098,7 @@ async function handleAsk(
1098
1098
  // the evidence view's ground truth: the exact passages this
1099
1099
  // answer was built from, compact — cache hits carry none,
1100
1100
  // because the cache stores the answer and never the passages
1101
- passages: usedHits.slice(0, 8).map((h: Hit) => ({ d: h.metadata.docidentifier ?? "", a: h.metadata.clause_anchor ?? "", t: (h.text ?? "").slice(0, 600), ...((h.metadata as any).table_selection ? { s: (h.metadata as any).table_selection } : {}) })) });
1101
+ passages: usedHits.slice(0, 8).map((h: Hit) => ({ d: h.metadata.docidentifier ?? "", a: h.metadata.clause_anchor ?? "", t: (h.text ?? "").slice(0, (h.metadata as any).block === "table" ? 1400 : 600), b: (h.metadata as any).block === "table" || undefined, ...((h.metadata as any).table_selection ? { s: (h.metadata as any).table_selection } : {}) })) });
1102
1102
  telemetry(env, ctx, tier, "ask", model, true, c2.text.length, queryHash, q.lang, undefined, telemetryMeta());
1103
1103
  const canonical = c2.text;
1104
1104
  // streamed answers can't be regenerated mid-flight; enforcement
@@ -4,10 +4,19 @@
4
4
  // service's own machine-computed model data: a machine-grounded answer
5
5
  // quotes it legitimately, so the judge must see it.
6
6
 
7
- export function buildJudgeContext(passages: string[], machine: string[] = []): string {
7
+ export function buildJudgeContext(
8
+ passages: (string | { text: string; table?: boolean })[],
9
+ machine: string[] = [],
10
+ ): string {
8
11
  const context = passages
9
12
  .slice(0, 8)
10
- .map((p, i) => `[${i + 1}] ${p.replace(/\s+/g, " ").slice(0, 900)}`)
13
+ .map((p, i) => {
14
+ const text = typeof p === "string" ? p : p.text;
15
+ // a table's evidence lives across its whole row set — a truncated
16
+ // table hides the very rows the answer computed from
17
+ const limit = typeof p !== "string" && p.table ? 2400 : 1400;
18
+ return `[${i + 1}] ${text.replace(/\s+/g, " ").slice(0, limit)}`;
19
+ })
11
20
  .join("\n");
12
21
  const machineContext = machine.length
13
22
  ? "\n" + machine.slice(0, 6).map((m) => `[M] ${m.replace(/\s+/g, " ").slice(0, 400)}`).join("\n")
@@ -19,7 +19,7 @@ export async function scoreFaithfulness(
19
19
  ai: any,
20
20
  model: string,
21
21
  answer: string,
22
- passages: string[],
22
+ passages: (string | { text: string; table?: boolean })[],
23
23
  machine: string[] = [],
24
24
  ): Promise<FaithfulnessResult | null> {
25
25
  if (!answer || !passages.length) return null;
@@ -13,7 +13,8 @@ import { ftsMatchQuery } from "./lexical";
13
13
  import { scoreFaithfulness } from "./faithfulness";
14
14
  import { checkQuoteAnchors } from "./anchors";
15
15
  import { namedDocumentIn } from "./context";
16
- import { standardForDocNumber } from "./modelplane";
16
+ import { standardForDocNumber, bindModelNode, modelGroundingBlock } from "./modelplane";
17
+ import { refCodec } from "./codecs";
17
18
  import { entitlementScope, standardKeysFrom } from "./requestScope";
18
19
  import type { Env } from "./env";
19
20
  export type { Env };
@@ -228,7 +229,28 @@ async function verifyRoute(c: RouteContext): Promise<Response> {
228
229
  if (!answer || !query) return err(400, "invalid_input", "answer and query are required");
229
230
  try {
230
231
  const u = await understandQuery(env.AI, roleModel(env, "understand"), query, [], []);
231
- const retrieved = await retrieve(env, query, { understanding: u, standardKeys: entitlementScope(standardKeysFrom(body)) });
232
+ // the grounding must MIRROR the ask path's: the edition boost (the
233
+ // publication's active edition, the codec's family) and the model
234
+ // grounding — a verify that grounds against different passages than
235
+ // the answer used judges a different answer
236
+ let lexicalBoost: string | undefined;
237
+ let editionSteer: { doc_number: string; edition: string } | null = null;
238
+ try {
239
+ const fam = u?.doc_number ? refCodec().familyOf(u.doc_number) : null;
240
+ if (fam) {
241
+ const row = await env.DB.prepare("SELECT edition FROM documents WHERE family = ?1 AND active = 1 ORDER BY edition DESC LIMIT 1")
242
+ .bind(fam).first().catch(() => null);
243
+ if (row?.edition) {
244
+ lexicalBoost = String(row.edition);
245
+ editionSteer = { doc_number: fam.split("-").pop() ?? "", edition: String(row.edition) };
246
+ }
247
+ }
248
+ } catch {
249
+ // degrade to unsteered retrieval
250
+ }
251
+ const bound = await bindModelNode(env, { query, standardKeys: entitlementScope(standardKeysFrom(body)) });
252
+ const modelGrounding = bound && !bound.gated ? modelGroundingBlock(bound) : null;
253
+ const retrieved = await retrieve(env, query, { understanding: u, standardKeys: entitlementScope(standardKeysFrom(body)), lexicalBoost, editionSteer });
232
254
  const passages = retrieved.hits.map((h: Hit) => h.text);
233
255
  const anchors = checkQuoteAnchors(answer, passages);
234
256
  const refs = [...answer.matchAll(/\[\[u:([^\]]+)\]\]/g)].map((m) => m[1]);
@@ -246,7 +268,8 @@ async function verifyRoute(c: RouteContext): Promise<Response> {
246
268
  .map((b: any) => [b.payload.check, b.payload.meaning, b.payload.definition, b.payload.violation_meaning]
247
269
  .filter((x: unknown) => typeof x === "string" && x).join(" — "))
248
270
  .filter(Boolean);
249
- const faith = await scoreFaithfulness(env.AI, roleModel(env, "grader"), answer, retrieved.hits.map((h: Hit) => h.text), machine);
271
+ if (modelGrounding) machine.unshift(modelGrounding);
272
+ const faith = await scoreFaithfulness(env.AI, roleModel(env, "grader"), answer, retrieved.hits.map((h: Hit) => ({ text: h.text, table: (h.metadata as any).block === "table" || undefined })), machine);
250
273
  return json({
251
274
  checks,
252
275
  judged: faith ? { name: "faithfulness", deterministic: false, score: faith.score, ungrounded_claims: faith.ungrounded_claims.slice(0, 5) } : null,
@@ -6,11 +6,23 @@ import type { Stage } from "./types.ts";
6
6
 
7
7
  export const seal: Stage = {
8
8
  name: "seal",
9
- when: (c) => !!c.opts.sealScope,
9
+ when: (c) => !!c.opts.sealScope || !!c.opts.editionSteer,
10
10
  run: (c) => {
11
11
  const before = c.hits.length;
12
12
  const scope = c.opts.sealScope!;
13
+ if (scope) {
13
14
  c.hits = c.hits.filter((h) => h.metadata.doc_number === scope.doc_number && (!scope.edition || h.metadata.edition === scope.edition));
14
- console.log("context seal:", before, "→", c.hits.length, "candidates within", `doc#${scope.doc_number}${scope.edition ? "@" + scope.edition : ""}`);
15
+ console.log("context seal:", before, "→", c.hits.length, "candidates within", `doc#${scope.doc_number}${scope.edition ? "@" + scope.edition : ""}`);
16
+ return;
17
+ }
18
+ const steer = c.opts.editionSteer!;
19
+ const current: typeof c.hits = [];
20
+ const superseded: typeof c.hits = [];
21
+ for (const h of c.hits) {
22
+ const same = h.metadata.doc_number === steer.doc_number;
23
+ (same && h.metadata.edition !== steer.edition ? superseded : current).push(h);
24
+ }
25
+ c.hits = [...current, ...superseded];
26
+ console.log("edition steer:", superseded.length, "superseded candidates demoted behind", current.length, "current-edition candidates of", `doc#${steer.doc_number}@${steer.edition}`);
15
27
  },
16
28
  };
@@ -29,6 +29,11 @@ export interface RetrieveOptions {
29
29
  * in-family passage out of the final hits, sealing the answer to
30
30
  * zero despite a healthy in-family pool. */
31
31
  sealScope?: { doc_number: string; edition?: string } | null;
32
+ /** Verify's grounding steer (demote-not-exclude): hits of the named
33
+ * document whose edition differs from the active one move to the END
34
+ * of the candidate pool — superseded passages stay servable but stop
35
+ * competing for the window against the current edition. */
36
+ editionSteer?: { doc_number: string; edition: string } | null;
32
37
  /** Option C: dense-lane results computed concurrently with
33
38
  * understanding (same folded-query vector, retrieve's exact query
34
39
  * parameters). With no filter they REPLACE the primary dense query;