@konneal/engine 0.2.120 → 0.2.121

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,11 +1,11 @@
1
1
  import {
2
2
  handleAsk
3
- } from "./chunk-SORXE55V.js";
3
+ } from "./chunk-YMRBMZNT.js";
4
4
  import "./chunk-FKG5VGOL.js";
5
5
  import "./chunk-IIQWESHC.js";
6
6
  import "./chunk-TH5XGPD5.js";
7
7
  import "./chunk-DJ65EF5G.js";
8
- import "./chunk-A3QHHUN5.js";
8
+ import "./chunk-A4A26BCV.js";
9
9
  import "./chunk-4NXH5ZI6.js";
10
10
  import "./chunk-VT7DR6NQ.js";
11
11
  import "./chunk-JZFXSTYX.js";
@@ -0,0 +1,89 @@
1
+ import {
2
+ P
3
+ } from "./chunk-3FYJM7LH.js";
4
+
5
+ // workers/worker_public/src/refusal.ts
6
+ function refusalAnswer() {
7
+ return P().prompts.vars.refusal_sentence;
8
+ }
9
+ function refusalPatterns(publisher) {
10
+ return {
11
+ variant: new RegExp(`^\\s*I don[\u2019']?t have information on .{1,120}? in the indexed ${publisher}(?: \\w+){0,2} (?:publications|passages|documents|corpus)\\.?`, "i"),
12
+ drift: [
13
+ new RegExp(`\\b(can'?t|cannot|couldn'?t|unable)\\b[^.]{0,120}?\\b(indexed )?${publisher}(?: \\w+){0,2} (?:publications|passages|documents|corpus)\\b`, "i"),
14
+ new RegExp(`\\bno real answer to give\\b[^.]{0,120}?\\b${publisher}\\b`, "i"),
15
+ /\b(?:falls|well) outside\b[^.]{0,120}?\b(?:what I can answer|my scope|the scope of)\b/i,
16
+ /\boutside (?:of )?what (?:I|this service) can answer\b/i,
17
+ // "I can't answer that — weather forecasting is outside my scope":
18
+ // requires the refusal verb, so a scope DISCUSSION inside a real answer
19
+ // ("this exemption is outside the scope of R 60") never matches
20
+ /\bI can[’']?t answer\b[^.]{0,100}?\bscope\b/i,
21
+ new RegExp(`^\\s*I don[\u2019']?t have any indexed ${publisher} \\w+(?:s)? (?:covering|about|on)\b`, "im"),
22
+ // trivia refusals in the model's own words (the refuse-trivia
23
+ // flake): out-of-domain content named plainly — the refusal
24
+ // verb is the guard, a scope DISCUSSION inside a real answer
25
+ // ("this exemption is outside the scope of R 60") never matches
26
+ /\bI don[’']?t have (?:any )?information on [^.]{0,80}(?:that[’']?s|—)?\s*(?:general|common) knowledge\b/i,
27
+ /\b(?:that[’']?s|this is) (?:just )?(?:general|common) knowledge[^.]{0,80}(?:outside|beyond|not covered)\b/i
28
+ ],
29
+ // the misplaced-pin wall's subset: every pattern here carries a
30
+ // first-person refusal verb ("I don't have information", "I can't
31
+ // answer", "that's general knowledge") — a cited answer's scope
32
+ // DISCUSSION ("outside the scope of R 60's requirements") never
33
+ // matches, so the wall can never eat real content
34
+ wallSafe: [
35
+ new RegExp(`\\b(can'?t|cannot|couldn'?t|unable)\\b[^.]{0,120}?\\b(indexed )?${publisher}(?: \\w+){0,2} (?:publications|passages|documents|corpus)\\b`, "i"),
36
+ new RegExp(`\\bno real answer to give\\b[^.]{0,120}?\\b${publisher}\\b`, "i"),
37
+ /\bI don[’']?t have (?:any )?information on [^.]{0,80}(?:that[’']?s|—)?\s*(?:general|common) knowledge\b/i,
38
+ /\b(?:that[’']?s|this is) (?:just )?(?:general|common) knowledge[^.]{0,80}(?:outside|beyond|not covered)\b/i,
39
+ /\bI can[’']?t answer\b[^.]{0,100}?\bscope\b/i
40
+ ]
41
+ };
42
+ }
43
+ function sentenceStart(answer, i) {
44
+ let s = 0;
45
+ for (const sep of [". ", "! ", "? ", "\n"]) {
46
+ const j = answer.lastIndexOf(sep, i);
47
+ if (j >= 0) s = Math.max(s, j + sep.length);
48
+ }
49
+ return s;
50
+ }
51
+ function sentenceEnd(answer, i) {
52
+ const m = /[.!?\n]/.exec(answer.slice(i));
53
+ return m ? i + m.index + 1 : answer.length;
54
+ }
55
+ function canonicalRefusal(answer) {
56
+ const CANON = refusalAnswer();
57
+ if (answer.includes(CANON)) return answer;
58
+ const { variant: REFUSAL_VARIANT, drift: REFUSAL_DRIFT } = refusalPatterns(P().publisher.name);
59
+ const variant = answer.match(REFUSAL_VARIANT);
60
+ if (variant) return answer.replace(variant[0], CANON);
61
+ for (const drift of REFUSAL_DRIFT) {
62
+ const m = drift.exec(answer);
63
+ if (!m) continue;
64
+ return answer.slice(0, sentenceStart(answer, m.index)) + CANON + answer.slice(sentenceEnd(answer, m.index));
65
+ }
66
+ return answer;
67
+ }
68
+ function exciseMisplacedPin(answer, cites) {
69
+ if (!cites) return answer;
70
+ const CANON = refusalAnswer();
71
+ let out = answer;
72
+ if (out.includes(CANON)) {
73
+ const i = out.indexOf(CANON);
74
+ out = out.slice(0, sentenceStart(out, i)) + out.slice(sentenceEnd(out, i));
75
+ }
76
+ const { wallSafe } = refusalPatterns(P().publisher.name);
77
+ for (const drift of wallSafe) {
78
+ const m = drift.exec(out);
79
+ if (!m) continue;
80
+ out = out.slice(0, sentenceStart(out, m.index)) + out.slice(sentenceEnd(out, m.index));
81
+ }
82
+ return out.replace(/^[ \t\n]+/, "").replace(/\n{3,}/g, "\n\n").trim();
83
+ }
84
+
85
+ export {
86
+ refusalAnswer,
87
+ canonicalRefusal,
88
+ exciseMisplacedPin
89
+ };
@@ -79,8 +79,9 @@ import {
79
79
  } from "./chunk-DJ65EF5G.js";
80
80
  import {
81
81
  canonicalRefusal,
82
+ exciseMisplacedPin,
82
83
  refusalAnswer
83
- } from "./chunk-A3QHHUN5.js";
84
+ } from "./chunk-A4A26BCV.js";
84
85
  import {
85
86
  entitlementScope,
86
87
  requestSalt,
@@ -2565,7 +2566,7 @@ ${q.query}`.replace("\n\n\n\n", "\n\n") }];
2565
2566
  }
2566
2567
  }
2567
2568
  }
2568
- const canonical0 = canonicalRefusal(full);
2569
+ const canonical0 = usedHits.length > 0 ? exciseMisplacedPin(canonicalRefusal(full), true) : canonicalRefusal(full);
2569
2570
  const c2 = canonical0.includes(refusalAnswer()) ? { text: canonical0, blocks: [], dropped: [] } : await contractV2(env.DB, canonical0, usedHits);
2570
2571
  send({
2571
2572
  type: "done",
@@ -2650,6 +2651,7 @@ ${q.query}`.replace("\n\n\n\n", "\n\n") }];
2650
2651
  answer = await generateOnce(env, MODELS.fallback, flat, routeEffort(routed.route));
2651
2652
  }
2652
2653
  if (answer) answer = canonicalRefusal(answer);
2654
+ if (answer && usedHits.length > 0) answer = exciseMisplacedPin(answer, true);
2653
2655
  stageTiming.generate = Date.now() - tGen;
2654
2656
  let used = usedHits;
2655
2657
  if (answer && !answer.includes(refusalAnswer())) {
package/dist/refusal.d.ts CHANGED
@@ -7,3 +7,12 @@ export declare function refusalAnswer(): string;
7
7
  * included) for the pinned one — the redirect tail survives. An answer
8
8
  * outside the refusal family is returned byte-identical. */
9
9
  export declare function canonicalRefusal(answer: string): string;
10
+ /** The misplaced-pin wall (2026-10-10): an answer that actually cites
11
+ * passages is NOT a refusal — but the model sometimes drops the
12
+ * pinned sentence into an otherwise-correct, well-cited answer as a
13
+ * sub-topic disclaimer (measured: the refusal pin at char 435 of a
14
+ * load-cell answer citing R 60). Readers and graders read the pin as
15
+ * a TOTAL refusal. The wall is deterministic: when the answer cites,
16
+ * the pin sentence (and its refusal-shaped paraphrases) are excised —
17
+ * the surrounding content stands on its own. */
18
+ export declare function exciseMisplacedPin(answer: string, cites: boolean): string;
@@ -4,7 +4,7 @@ import {
4
4
  import "./chunk-IIQWESHC.js";
5
5
  import "./chunk-TH5XGPD5.js";
6
6
  import "./chunk-DJ65EF5G.js";
7
- import "./chunk-A3QHHUN5.js";
7
+ import "./chunk-A4A26BCV.js";
8
8
  import "./chunk-4NXH5ZI6.js";
9
9
  import "./chunk-VT7DR6NQ.js";
10
10
  import "./chunk-3FYJM7LH.js";
@@ -4,7 +4,7 @@ import {
4
4
  handleMemories,
5
5
  scoreFaithfulness,
6
6
  scoreJudge
7
- } from "../../chunk-SORXE55V.js";
7
+ } from "../../chunk-YMRBMZNT.js";
8
8
  import {
9
9
  TOOLS_REGISTRY,
10
10
  bindModelNode,
@@ -52,7 +52,7 @@ import {
52
52
  } from "../../chunk-DJ65EF5G.js";
53
53
  import {
54
54
  canonicalRefusal
55
- } from "../../chunk-A3QHHUN5.js";
55
+ } from "../../chunk-A4A26BCV.js";
56
56
  import {
57
57
  entitlementScope,
58
58
  standardKeysFrom
@@ -1049,7 +1049,7 @@ async function callToolOnce(env, ctx, _req, tier, key, name, args, t0) {
1049
1049
  const r = await runTool({ ...env, DB: env.DB }, { name, args }, "mcp");
1050
1050
  payload = r ? { tool: r.name, query: r.query, result: r.output } : { error: { message: `tool ${name} returned nothing for the given arguments` } };
1051
1051
  } else {
1052
- const res = name === "ask" ? await (await import("../../ask-3BJKTVLY.js")).handleAsk(env, ctx, inner, tier, key) : await (await import("../../search-JDSQPI3A.js")).handleSearch(env, ctx, inner, tier, key);
1052
+ const res = name === "ask" ? await (await import("../../ask-5RWMWNX5.js")).handleAsk(env, ctx, inner, tier, key) : await (await import("../../search-RMB4BL4P.js")).handleSearch(env, ctx, inner, tier, key);
1053
1053
  payload = await res.json().catch(() => ({ error: { message: "tool transport failed", status: res.status } }));
1054
1054
  }
1055
1055
  telemetry(env, ctx, tier, `mcp:${name}`, null, !payload?.error, JSON.stringify(payload).length, await sha256Hex(`${name}:${JSON.stringify(args ?? {})}`), void 0, void 0, { durationMs: Date.now() - t0 });
@@ -1,9 +1,11 @@
1
1
  import {
2
2
  canonicalRefusal,
3
+ exciseMisplacedPin,
3
4
  refusalAnswer
4
- } from "../../chunk-A3QHHUN5.js";
5
+ } from "../../chunk-A4A26BCV.js";
5
6
  import "../../chunk-3FYJM7LH.js";
6
7
  export {
7
8
  canonicalRefusal,
9
+ exciseMisplacedPin,
8
10
  refusalAnswer
9
11
  };
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.120",
30
+ "version": "0.2.121",
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",
@@ -17,7 +17,7 @@ import { reflect } from "./reflect";
17
17
  import { scoreFaithfulness } from "./faithfulness";
18
18
  import { entailmentVerdict } from "./entailment";
19
19
  import { checkQuoteAnchors, ANCHOR_CORRECTION_NOTE } from "./anchors";
20
- import { canonicalRefusal } from "./refusal";
20
+ import { canonicalRefusal, exciseMisplacedPin } from "./refusal";
21
21
  import { contractV2, tableRetyped } from "./refs";
22
22
  import { completeTables, completeFigures } from "./completion";
23
23
  import { NO_CONTEXT, appliedContext, contextNote, namedDocumentIn, parseContext, resolveDocScope, syntheticUnderstanding } from "./context";
@@ -1464,7 +1464,9 @@ let convEntities: Array<{ entity: string; kind: string }> = [];
1464
1464
  } catch { /* deliver what we have */ }
1465
1465
  }
1466
1466
  }
1467
- const canonical0 = canonicalRefusal(full);
1467
+ // the misplaced-pin wall rides the streamed path too: a
1468
+ // CITED stream is not a refusal
1469
+ const canonical0 = usedHits.length > 0 ? exciseMisplacedPin(canonicalRefusal(full), true) : canonicalRefusal(full);
1468
1470
  // answer contract v2: validate [[u:]] refs, resolve typed blocks
1469
1471
  const c2 = canonical0.includes(refusalAnswer())
1470
1472
  ? { text: canonical0, blocks: [], dropped: [] as string[] }
@@ -1569,6 +1571,11 @@ let convEntities: Array<{ entity: string; kind: string }> = [];
1569
1571
  answer = await generateOnce(env, MODELS.fallback, flat, routeEffort(routed.route));
1570
1572
  }
1571
1573
  if (answer) answer = canonicalRefusal(answer);
1574
+ // the misplaced-pin wall: a CITED answer is not a refusal — excise
1575
+ // the pinned sentence if the model dropped it in as a disclaimer
1576
+ // (measured on chip-scoped asks: correct cited answers carrying the
1577
+ // pin mid-text, read by users and graders as total refusals)
1578
+ if (answer && usedHits.length > 0) answer = exciseMisplacedPin(answer, true);
1572
1579
  stageTiming.generate = Date.now() - tGen;
1573
1580
 
1574
1581
  // ── Deterministic quote-anchor + table-retyping check ──
@@ -10,7 +10,7 @@ export function refusalAnswer(): string {
10
10
  // on how to make lasagna in the indexed..."); the API contract is the
11
11
  // exact canonical sentence — normalize variants, keep the redirect tail.
12
12
  // The patterns are built per call: the publisher token is profile data.
13
- function refusalPatterns(publisher: string): { variant: RegExp; drift: RegExp[] } {
13
+ function refusalPatterns(publisher: string): { variant: RegExp; drift: RegExp[]; wallSafe: RegExp[] } {
14
14
  return {
15
15
  variant: new RegExp(`^\\s*I don[’']?t have information on .{1,120}? in the indexed ${publisher}(?: \\w+){0,2} (?:publications|passages|documents|corpus)\\.?`, "i"),
16
16
  drift: [
@@ -23,6 +23,24 @@ function refusalPatterns(publisher: string): { variant: RegExp; drift: RegExp[]
23
23
  // ("this exemption is outside the scope of R 60") never matches
24
24
  /\bI can[’']?t answer\b[^.]{0,100}?\bscope\b/i,
25
25
  new RegExp(`^\\s*I don[’']?t have any indexed ${publisher} \\w+(?:s)? (?:covering|about|on)\b`, "im"),
26
+ // trivia refusals in the model's own words (the refuse-trivia
27
+ // flake): out-of-domain content named plainly — the refusal
28
+ // verb is the guard, a scope DISCUSSION inside a real answer
29
+ // ("this exemption is outside the scope of R 60") never matches
30
+ /\bI don[’']?t have (?:any )?information on [^.]{0,80}(?:that[’']?s|—)?\s*(?:general|common) knowledge\b/i,
31
+ /\b(?:that[’']?s|this is) (?:just )?(?:general|common) knowledge[^.]{0,80}(?:outside|beyond|not covered)\b/i,
32
+ ],
33
+ // the misplaced-pin wall's subset: every pattern here carries a
34
+ // first-person refusal verb ("I don't have information", "I can't
35
+ // answer", "that's general knowledge") — a cited answer's scope
36
+ // DISCUSSION ("outside the scope of R 60's requirements") never
37
+ // matches, so the wall can never eat real content
38
+ wallSafe: [
39
+ new RegExp(`\\b(can'?t|cannot|couldn'?t|unable)\\b[^.]{0,120}?\\b(indexed )?${publisher}(?: \\w+){0,2} (?:publications|passages|documents|corpus)\\b`, "i"),
40
+ new RegExp(`\\bno real answer to give\\b[^.]{0,120}?\\b${publisher}\\b`, "i"),
41
+ /\bI don[’']?t have (?:any )?information on [^.]{0,80}(?:that[’']?s|—)?\s*(?:general|common) knowledge\b/i,
42
+ /\b(?:that[’']?s|this is) (?:just )?(?:general|common) knowledge[^.]{0,80}(?:outside|beyond|not covered)\b/i,
43
+ /\bI can[’']?t answer\b[^.]{0,100}?\bscope\b/i,
26
44
  ],
27
45
  };
28
46
  }
@@ -61,3 +79,29 @@ export function canonicalRefusal(answer: string): string {
61
79
  }
62
80
  return answer;
63
81
  }
82
+
83
+
84
+ /** The misplaced-pin wall (2026-10-10): an answer that actually cites
85
+ * passages is NOT a refusal — but the model sometimes drops the
86
+ * pinned sentence into an otherwise-correct, well-cited answer as a
87
+ * sub-topic disclaimer (measured: the refusal pin at char 435 of a
88
+ * load-cell answer citing R 60). Readers and graders read the pin as
89
+ * a TOTAL refusal. The wall is deterministic: when the answer cites,
90
+ * the pin sentence (and its refusal-shaped paraphrases) are excised —
91
+ * the surrounding content stands on its own. */
92
+ export function exciseMisplacedPin(answer: string, cites: boolean): string {
93
+ if (!cites) return answer;
94
+ const CANON = refusalAnswer();
95
+ let out = answer;
96
+ if (out.includes(CANON)) {
97
+ const i = out.indexOf(CANON);
98
+ out = out.slice(0, sentenceStart(out, i)) + out.slice(sentenceEnd(out, i));
99
+ }
100
+ const { wallSafe } = refusalPatterns(P().publisher.name);
101
+ for (const drift of wallSafe) {
102
+ const m = drift.exec(out);
103
+ if (!m) continue;
104
+ out = out.slice(0, sentenceStart(out, m.index)) + out.slice(sentenceEnd(out, m.index));
105
+ }
106
+ return out.replace(/^[ \t\n]+/, "").replace(/\n{3,}/g, "\n\n").trim();
107
+ }
@@ -1,54 +0,0 @@
1
- import {
2
- P
3
- } from "./chunk-3FYJM7LH.js";
4
-
5
- // workers/worker_public/src/refusal.ts
6
- function refusalAnswer() {
7
- return P().prompts.vars.refusal_sentence;
8
- }
9
- function refusalPatterns(publisher) {
10
- return {
11
- variant: new RegExp(`^\\s*I don[\u2019']?t have information on .{1,120}? in the indexed ${publisher}(?: \\w+){0,2} (?:publications|passages|documents|corpus)\\.?`, "i"),
12
- drift: [
13
- new RegExp(`\\b(can'?t|cannot|couldn'?t|unable)\\b[^.]{0,120}?\\b(indexed )?${publisher}(?: \\w+){0,2} (?:publications|passages|documents|corpus)\\b`, "i"),
14
- new RegExp(`\\bno real answer to give\\b[^.]{0,120}?\\b${publisher}\\b`, "i"),
15
- /\b(?:falls|well) outside\b[^.]{0,120}?\b(?:what I can answer|my scope|the scope of)\b/i,
16
- /\boutside (?:of )?what (?:I|this service) can answer\b/i,
17
- // "I can't answer that — weather forecasting is outside my scope":
18
- // requires the refusal verb, so a scope DISCUSSION inside a real answer
19
- // ("this exemption is outside the scope of R 60") never matches
20
- /\bI can[’']?t answer\b[^.]{0,100}?\bscope\b/i,
21
- new RegExp(`^\\s*I don[\u2019']?t have any indexed ${publisher} \\w+(?:s)? (?:covering|about|on)\b`, "im")
22
- ]
23
- };
24
- }
25
- function sentenceStart(answer, i) {
26
- let s = 0;
27
- for (const sep of [". ", "! ", "? ", "\n"]) {
28
- const j = answer.lastIndexOf(sep, i);
29
- if (j >= 0) s = Math.max(s, j + sep.length);
30
- }
31
- return s;
32
- }
33
- function sentenceEnd(answer, i) {
34
- const m = /[.!?\n]/.exec(answer.slice(i));
35
- return m ? i + m.index + 1 : answer.length;
36
- }
37
- function canonicalRefusal(answer) {
38
- const CANON = refusalAnswer();
39
- if (answer.includes(CANON)) return answer;
40
- const { variant: REFUSAL_VARIANT, drift: REFUSAL_DRIFT } = refusalPatterns(P().publisher.name);
41
- const variant = answer.match(REFUSAL_VARIANT);
42
- if (variant) return answer.replace(variant[0], CANON);
43
- for (const drift of REFUSAL_DRIFT) {
44
- const m = drift.exec(answer);
45
- if (!m) continue;
46
- return answer.slice(0, sentenceStart(answer, m.index)) + CANON + answer.slice(sentenceEnd(answer, m.index));
47
- }
48
- return answer;
49
- }
50
-
51
- export {
52
- refusalAnswer,
53
- canonicalRefusal
54
- };