@konneal/engine 0.2.112 → 0.2.113

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,8 +1,8 @@
1
1
  import {
2
2
  handleAsk
3
- } from "./chunk-25VMZ7WE.js";
3
+ } from "./chunk-PSI5SR2A.js";
4
4
  import "./chunk-32UDKBA2.js";
5
- import "./chunk-2R7OVYAO.js";
5
+ import "./chunk-NO4WHD3K.js";
6
6
  import "./chunk-TH5XGPD5.js";
7
7
  import "./chunk-DJ65EF5G.js";
8
8
  import "./chunk-A3QHHUN5.js";
@@ -24,181 +24,6 @@ import {
24
24
  P
25
25
  } from "./chunk-3FYJM7LH.js";
26
26
 
27
- // workers/worker_public/src/quality.ts
28
- var ORDER = { verified: 0, curated: 1, ocr: 2 };
29
- function hitQuality(m) {
30
- if (m.model_node || m.model_version || m.producer === "primmel") return "verified";
31
- if (m.tier === "curated") return "curated";
32
- return "ocr";
33
- }
34
- function answerQuality(qualities) {
35
- let worst = null;
36
- for (const q of qualities) {
37
- if (!q) continue;
38
- if (!worst || ORDER[q] > ORDER[worst]) worst = q;
39
- }
40
- return worst;
41
- }
42
- function qualityNote(q) {
43
- if (q === "verified") return "High confidence: this publication's requirements ride a machine-checkable data model.";
44
- if (q === "curated") return "Established sources: Metanorma-edited documents, chunked at clause boundaries.";
45
- return "WARNING: Partly grounded in experimental data source that was derived from OCR content. Please verify content against official publications.";
46
- }
47
- function experimentalSourceLabels(cites, cap = 6) {
48
- const labels = [];
49
- for (const c of cites) {
50
- if (c.quality !== "ocr") continue;
51
- const id = String(c.docidentifier || c.doc_id || "source");
52
- const anchor = String(c.clause_anchor ?? "");
53
- const garbage = /^[0-9a-f]{8}-[0-9a-f]{4}-/i.test(anchor) || anchor.startsWith("_") && anchor.length > 12;
54
- labels.push(garbage || !anchor || anchor === "overview" ? id : `${id} \xA7${anchor}`);
55
- if (labels.length >= cap) break;
56
- }
57
- return labels;
58
- }
59
-
60
- // workers/worker_public/src/lexical.ts
61
- var LEXICAL_K = 40;
62
- function ftsMatchQuery(query) {
63
- const terms = query.toLowerCase().replace(/[^\p{L}\p{N}\s_-]/gu, " ").split(/\s+/).map((t) => t.trim()).filter((t) => t.length >= 2 && t.length <= 40).filter((t) => !STOP.has(t));
64
- const uniq = [...new Set(terms)].slice(0, 12);
65
- if (!uniq.length) return null;
66
- return uniq.map((t) => `"${t.replace(/"/g, "")}"`).join(" OR ");
67
- }
68
- var STOP = /* @__PURE__ */ new Set([
69
- "the",
70
- "a",
71
- "an",
72
- "of",
73
- "and",
74
- "or",
75
- "to",
76
- "in",
77
- "for",
78
- "on",
79
- "is",
80
- "are",
81
- "was",
82
- "were",
83
- "be",
84
- "by",
85
- "with",
86
- "as",
87
- "at",
88
- "from",
89
- "that",
90
- "this",
91
- "what",
92
- "how",
93
- "when",
94
- "where",
95
- "which",
96
- "who",
97
- "does",
98
- "do",
99
- "did",
100
- "can",
101
- "could",
102
- "should",
103
- "would",
104
- "may",
105
- "might",
106
- "shall",
107
- "must",
108
- "about",
109
- "into",
110
- "than",
111
- "then",
112
- "its",
113
- "it",
114
- "their",
115
- "there"
116
- ]);
117
- function rowMeta(r) {
118
- return {
119
- doc_id: String(r.doc_id ?? ""),
120
- docidentifier: String(r.docidentifier ?? ""),
121
- doctype: String(r.doctype ?? ""),
122
- doc_number: String(r.doc_number ?? ""),
123
- edition: String(r.edition ?? ""),
124
- language: String(r.language ?? "en"),
125
- clause_anchor: String(r.clause_anchor ?? ""),
126
- clause_title: String(r.clause_title ?? ""),
127
- tier: String(r.tier ?? ""),
128
- corpus: String(r.corpus ?? ""),
129
- text_ref: "",
130
- status: String(r.status ?? "unknown"),
131
- superseded_by: String(r.superseded_by ?? ""),
132
- // contract v2 over the lexical lane: typed chunks arriving via BM25
133
- // keep their unit identity ([[u:…]] refs, typed pin, retyping check)
134
- unit_id: String(r.unit_id ?? "") || void 0,
135
- block: String(r.block ?? "") || void 0
136
- };
137
- }
138
- function rowsToHits(rows) {
139
- return rows.map((r) => {
140
- const bm25 = typeof r.rank === "number" ? r.rank : 0;
141
- return {
142
- id: String(r.id),
143
- score: 1 / (1 + Math.max(0, bm25)),
144
- metadata: rowMeta(r),
145
- text: String(r.text ?? "")
146
- };
147
- });
148
- }
149
- function rowsToMatches(rows) {
150
- return rows.map((r) => {
151
- const bm25 = typeof r.rank === "number" ? Math.max(0, r.rank) : 0;
152
- return {
153
- id: String(r.id),
154
- score: 1 / (1 + bm25),
155
- metadata: { ...rowMeta(r), chunk_text: String(r.text ?? "") }
156
- };
157
- });
158
- }
159
- async function lexicalWithin(env, query, docNumbers, k = 12) {
160
- const match2 = ftsMatchQuery(query);
161
- if (!match2 || !docNumbers.length) return [];
162
- try {
163
- const placeholders = docNumbers.map((_, i) => `?${i + 2}`).join(",");
164
- const res = await env.DB.prepare(
165
- `SELECT c.id, c.doc_id, c.docidentifier, c.doctype, c.doc_number, c.edition,
166
- c.language, c.clause_anchor, c.clause_title, c.status, c.superseded_by,
167
- c.corpus, c.tier, c.text, c.unit_id, c.block, bm25(chunks_fts) AS rank
168
- FROM chunks_fts
169
- JOIN chunks c ON c.rowid = chunks_fts.rowid
170
- WHERE chunks_fts MATCH ?1 AND c.doc_number IN (${placeholders})
171
- ORDER BY rank
172
- LIMIT ?${docNumbers.length + 2}`
173
- ).bind(match2, ...docNumbers, k).all();
174
- return rowsToMatches(res.results ?? []);
175
- } catch (e) {
176
- console.log("lexical-within failed:", String(e).slice(0, 200));
177
- return [];
178
- }
179
- }
180
- async function lexicalPrefilter(env, query, k = LEXICAL_K) {
181
- const match2 = ftsMatchQuery(query);
182
- if (!match2) return [];
183
- try {
184
- const res = await env.DB.prepare(
185
- `SELECT c.id, c.doc_id, c.docidentifier, c.doctype, c.doc_number, c.edition,
186
- c.language, c.clause_anchor, c.clause_title, c.status, c.superseded_by,
187
- c.corpus, c.tier, c.text, c.unit_id, c.block, bm25(chunks_fts) AS rank
188
- FROM chunks_fts
189
- JOIN chunks c ON c.rowid = chunks_fts.rowid
190
- WHERE chunks_fts MATCH ?1
191
- ORDER BY rank
192
- LIMIT ?2`
193
- ).bind(match2, k).all();
194
- const rows = res.results ?? [];
195
- return rowsToHits(rows);
196
- } catch (e) {
197
- console.log("lexical prefilter failed:", String(e).slice(0, 200));
198
- return [];
199
- }
200
- }
201
-
202
27
  // node_modules/@pubid/pubid/dist/grammar/engine.js
203
28
  var ParseFailed = class extends Error {
204
29
  pos;
@@ -22029,6 +21854,14 @@ function parseDocRef(doc, edition) {
22029
21854
  function namedDocumentIn(query) {
22030
21855
  return refCodec().scanQuestion(query);
22031
21856
  }
21857
+ function matchesDocScope(meta, scopeDocNumber) {
21858
+ if (meta.doc_number === scopeDocNumber) return true;
21859
+ if (!scopeDocNumber.includes("-")) return false;
21860
+ if (meta.doc_number !== scopeDocNumber.split("-")[0]) return false;
21861
+ const stem = (meta.docidentifier ?? "").replace(/\s*\([A-Z]\)\s*$/, "").replace(/:\d+$/, "").trim();
21862
+ const last = stem.split(/\s+/).pop()?.toLowerCase();
21863
+ return last === scopeDocNumber.toLowerCase();
21864
+ }
22032
21865
  async function resolveDocScope(env, ctx) {
22033
21866
  if (!ctx.doc) return null;
22034
21867
  const parsed = parseDocRef(ctx.doc, ctx.edition);
@@ -22104,6 +21937,181 @@ function syntheticUnderstanding(scope) {
22104
21937
  };
22105
21938
  }
22106
21939
 
21940
+ // workers/worker_public/src/quality.ts
21941
+ var ORDER = { verified: 0, curated: 1, ocr: 2 };
21942
+ function hitQuality(m) {
21943
+ if (m.model_node || m.model_version || m.producer === "primmel") return "verified";
21944
+ if (m.tier === "curated") return "curated";
21945
+ return "ocr";
21946
+ }
21947
+ function answerQuality(qualities) {
21948
+ let worst = null;
21949
+ for (const q of qualities) {
21950
+ if (!q) continue;
21951
+ if (!worst || ORDER[q] > ORDER[worst]) worst = q;
21952
+ }
21953
+ return worst;
21954
+ }
21955
+ function qualityNote(q) {
21956
+ if (q === "verified") return "High confidence: this publication's requirements ride a machine-checkable data model.";
21957
+ if (q === "curated") return "Established sources: Metanorma-edited documents, chunked at clause boundaries.";
21958
+ return "WARNING: Partly grounded in experimental data source that was derived from OCR content. Please verify content against official publications.";
21959
+ }
21960
+ function experimentalSourceLabels(cites, cap = 6) {
21961
+ const labels = [];
21962
+ for (const c of cites) {
21963
+ if (c.quality !== "ocr") continue;
21964
+ const id = String(c.docidentifier || c.doc_id || "source");
21965
+ const anchor = String(c.clause_anchor ?? "");
21966
+ const garbage = /^[0-9a-f]{8}-[0-9a-f]{4}-/i.test(anchor) || anchor.startsWith("_") && anchor.length > 12;
21967
+ labels.push(garbage || !anchor || anchor === "overview" ? id : `${id} \xA7${anchor}`);
21968
+ if (labels.length >= cap) break;
21969
+ }
21970
+ return labels;
21971
+ }
21972
+
21973
+ // workers/worker_public/src/lexical.ts
21974
+ var LEXICAL_K = 40;
21975
+ function ftsMatchQuery(query) {
21976
+ const terms = query.toLowerCase().replace(/[^\p{L}\p{N}\s_-]/gu, " ").split(/\s+/).map((t) => t.trim()).filter((t) => t.length >= 2 && t.length <= 40).filter((t) => !STOP.has(t));
21977
+ const uniq = [...new Set(terms)].slice(0, 12);
21978
+ if (!uniq.length) return null;
21979
+ return uniq.map((t) => `"${t.replace(/"/g, "")}"`).join(" OR ");
21980
+ }
21981
+ var STOP = /* @__PURE__ */ new Set([
21982
+ "the",
21983
+ "a",
21984
+ "an",
21985
+ "of",
21986
+ "and",
21987
+ "or",
21988
+ "to",
21989
+ "in",
21990
+ "for",
21991
+ "on",
21992
+ "is",
21993
+ "are",
21994
+ "was",
21995
+ "were",
21996
+ "be",
21997
+ "by",
21998
+ "with",
21999
+ "as",
22000
+ "at",
22001
+ "from",
22002
+ "that",
22003
+ "this",
22004
+ "what",
22005
+ "how",
22006
+ "when",
22007
+ "where",
22008
+ "which",
22009
+ "who",
22010
+ "does",
22011
+ "do",
22012
+ "did",
22013
+ "can",
22014
+ "could",
22015
+ "should",
22016
+ "would",
22017
+ "may",
22018
+ "might",
22019
+ "shall",
22020
+ "must",
22021
+ "about",
22022
+ "into",
22023
+ "than",
22024
+ "then",
22025
+ "its",
22026
+ "it",
22027
+ "their",
22028
+ "there"
22029
+ ]);
22030
+ function rowMeta(r) {
22031
+ return {
22032
+ doc_id: String(r.doc_id ?? ""),
22033
+ docidentifier: String(r.docidentifier ?? ""),
22034
+ doctype: String(r.doctype ?? ""),
22035
+ doc_number: String(r.doc_number ?? ""),
22036
+ edition: String(r.edition ?? ""),
22037
+ language: String(r.language ?? "en"),
22038
+ clause_anchor: String(r.clause_anchor ?? ""),
22039
+ clause_title: String(r.clause_title ?? ""),
22040
+ tier: String(r.tier ?? ""),
22041
+ corpus: String(r.corpus ?? ""),
22042
+ text_ref: "",
22043
+ status: String(r.status ?? "unknown"),
22044
+ superseded_by: String(r.superseded_by ?? ""),
22045
+ // contract v2 over the lexical lane: typed chunks arriving via BM25
22046
+ // keep their unit identity ([[u:…]] refs, typed pin, retyping check)
22047
+ unit_id: String(r.unit_id ?? "") || void 0,
22048
+ block: String(r.block ?? "") || void 0
22049
+ };
22050
+ }
22051
+ function rowsToHits(rows) {
22052
+ return rows.map((r) => {
22053
+ const bm25 = typeof r.rank === "number" ? r.rank : 0;
22054
+ return {
22055
+ id: String(r.id),
22056
+ score: 1 / (1 + Math.max(0, bm25)),
22057
+ metadata: rowMeta(r),
22058
+ text: String(r.text ?? "")
22059
+ };
22060
+ });
22061
+ }
22062
+ function rowsToMatches(rows) {
22063
+ return rows.map((r) => {
22064
+ const bm25 = typeof r.rank === "number" ? Math.max(0, r.rank) : 0;
22065
+ return {
22066
+ id: String(r.id),
22067
+ score: 1 / (1 + bm25),
22068
+ metadata: { ...rowMeta(r), chunk_text: String(r.text ?? "") }
22069
+ };
22070
+ });
22071
+ }
22072
+ async function lexicalWithin(env, query, docNumbers, k = 12) {
22073
+ const match2 = ftsMatchQuery(query);
22074
+ if (!match2 || !docNumbers.length) return [];
22075
+ try {
22076
+ const placeholders = docNumbers.map((_, i) => `?${i + 2}`).join(",");
22077
+ const res = await env.DB.prepare(
22078
+ `SELECT c.id, c.doc_id, c.docidentifier, c.doctype, c.doc_number, c.edition,
22079
+ c.language, c.clause_anchor, c.clause_title, c.status, c.superseded_by,
22080
+ c.corpus, c.tier, c.text, c.unit_id, c.block, bm25(chunks_fts) AS rank
22081
+ FROM chunks_fts
22082
+ JOIN chunks c ON c.rowid = chunks_fts.rowid
22083
+ WHERE chunks_fts MATCH ?1 AND c.doc_number IN (${placeholders})
22084
+ ORDER BY rank
22085
+ LIMIT ?${docNumbers.length + 2}`
22086
+ ).bind(match2, ...docNumbers, k).all();
22087
+ return rowsToMatches(res.results ?? []);
22088
+ } catch (e) {
22089
+ console.log("lexical-within failed:", String(e).slice(0, 200));
22090
+ return [];
22091
+ }
22092
+ }
22093
+ async function lexicalPrefilter(env, query, k = LEXICAL_K) {
22094
+ const match2 = ftsMatchQuery(query);
22095
+ if (!match2) return [];
22096
+ try {
22097
+ const res = await env.DB.prepare(
22098
+ `SELECT c.id, c.doc_id, c.docidentifier, c.doctype, c.doc_number, c.edition,
22099
+ c.language, c.clause_anchor, c.clause_title, c.status, c.superseded_by,
22100
+ c.corpus, c.tier, c.text, c.unit_id, c.block, bm25(chunks_fts) AS rank
22101
+ FROM chunks_fts
22102
+ JOIN chunks c ON c.rowid = chunks_fts.rowid
22103
+ WHERE chunks_fts MATCH ?1
22104
+ ORDER BY rank
22105
+ LIMIT ?2`
22106
+ ).bind(match2, k).all();
22107
+ const rows = res.results ?? [];
22108
+ return rowsToHits(rows);
22109
+ } catch (e) {
22110
+ console.log("lexical prefilter failed:", String(e).slice(0, 200));
22111
+ return [];
22112
+ }
22113
+ }
22114
+
22107
22115
  // workers/shared/chunk.ts
22108
22116
  function toHits(matches) {
22109
22117
  return matches.map((m) => ({
@@ -22693,7 +22701,7 @@ var seal = {
22693
22701
  const before = c.hits.length;
22694
22702
  const scope = c.opts.sealScope;
22695
22703
  if (scope) {
22696
- c.hits = c.hits.filter((h) => h.metadata.doc_number === scope.doc_number && (!scope.edition || h.metadata.edition === scope.edition));
22704
+ c.hits = c.hits.filter((h) => matchesDocScope(h.metadata, scope.doc_number) && (!scope.edition || h.metadata.edition === scope.edition));
22697
22705
  console.log("context seal:", before, "\u2192", c.hits.length, "candidates within", `doc#${scope.doc_number}${scope.edition ? "@" + scope.edition : ""}`);
22698
22706
  return;
22699
22707
  }
@@ -23471,7 +23479,7 @@ async function retrieve(env, query, opts = {}) {
23471
23479
  const lexicalP = lexicalPrefilter(env, opts.lexicalBoost ? `${rq} ${opts.lexicalBoost}` : rq).catch(() => []);
23472
23480
  const [vector, lexicalHits0] = await Promise.all([vectorP, lexicalP]);
23473
23481
  const lexicalHits = opts.sealScope || opts.standardKeys ? lexicalHits0.filter(
23474
- (h) => (!opts.sealScope || h.metadata.doc_number === opts.sealScope.doc_number && (!opts.sealScope.edition || h.metadata.edition === opts.sealScope.edition)) && standardKeyAllowed(h.metadata, opts.standardKeys)
23482
+ (h) => (!opts.sealScope || matchesDocScope(h.metadata, opts.sealScope.doc_number) && (!opts.sealScope.edition || h.metadata.edition === opts.sealScope.edition)) && standardKeyAllowed(h.metadata, opts.standardKeys)
23475
23483
  ) : lexicalHits0;
23476
23484
  if (lexicalHits.length) console.log("lexical prefilter:", lexicalHits.length, "hits");
23477
23485
  const ctx = {
@@ -24735,10 +24743,6 @@ async function editionNote(env, u) {
24735
24743
  }
24736
24744
 
24737
24745
  export {
24738
- answerQuality,
24739
- qualityNote,
24740
- experimentalSourceLabels,
24741
- ftsMatchQuery,
24742
24746
  refCodec,
24743
24747
  NO_CONTEXT,
24744
24748
  machineOffers,
@@ -24749,6 +24753,10 @@ export {
24749
24753
  parseAppliedContext,
24750
24754
  contextNote,
24751
24755
  syntheticUnderstanding,
24756
+ answerQuality,
24757
+ qualityNote,
24758
+ experimentalSourceLabels,
24759
+ ftsMatchQuery,
24752
24760
  STAGE_NAMES,
24753
24761
  promptVars,
24754
24762
  fill,
@@ -60,7 +60,7 @@ import {
60
60
  tokenBudget,
61
61
  understandQuery,
62
62
  usageTotal
63
- } from "./chunk-2R7OVYAO.js";
63
+ } from "./chunk-NO4WHD3K.js";
64
64
  import {
65
65
  embed,
66
66
  generateOnce,
@@ -6,7 +6,7 @@ import {
6
6
  sessionFrom,
7
7
  telemetry,
8
8
  understandQuery
9
- } from "./chunk-2R7OVYAO.js";
9
+ } from "./chunk-NO4WHD3K.js";
10
10
  import {
11
11
  portModelRunner
12
12
  } from "./chunk-TH5XGPD5.js";
package/dist/context.d.ts CHANGED
@@ -111,6 +111,18 @@ export declare function namedDocumentIn(query: string): DocScope | null;
111
111
  * scoped_to stays null). A registry READ failure proceeds with the
112
112
  * parsed scope — a scoped refusal is more honest than silently
113
113
  * widening to the whole corpus. */
114
+ /** The seal's grain fix (the 2026-10-09 gate): the corpus stores PART
115
+ * publications at family grain — R 60-1:2021's chunks carry
116
+ * doc_number "60" with the part identity only in the docidentifier —
117
+ * so a scope naming a part ("60-1") admits a family-grain chunk only
118
+ * when the chunk's OWN identifier stem names the same part (the
119
+ * stem's last token is the number, edition and language markers
120
+ * stripped). Exact grain agreement always matches; R 60-2 never
121
+ * passes an R 60-1 chip. */
122
+ export declare function matchesDocScope(meta: {
123
+ doc_number?: string;
124
+ docidentifier?: string;
125
+ }, scopeDocNumber: string): boolean;
114
126
  export declare function resolveDocScope(env: any, ctx: DeclaredContext): Promise<DocScope | null>;
115
127
  export declare function appliedContext(declared: DeclaredContext | null, scope: DocScope | null, note?: AppliedContext["note"], live?: LiveEcho): AppliedContext;
116
128
  /** Validate a context_applied object arriving from a client (the
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  handleSearch
3
- } from "./chunk-HAU5INEJ.js";
4
- import "./chunk-2R7OVYAO.js";
3
+ } from "./chunk-WUD4XR7Y.js";
4
+ import "./chunk-NO4WHD3K.js";
5
5
  import "./chunk-TH5XGPD5.js";
6
6
  import "./chunk-DJ65EF5G.js";
7
7
  import "./chunk-A3QHHUN5.js";
@@ -4,7 +4,7 @@ import {
4
4
  handleMemories,
5
5
  scoreFaithfulness,
6
6
  scoreJudge
7
- } from "../../chunk-25VMZ7WE.js";
7
+ } from "../../chunk-PSI5SR2A.js";
8
8
  import {
9
9
  TOOLS_REGISTRY,
10
10
  bindModelNode,
@@ -12,7 +12,7 @@ import {
12
12
  } from "../../chunk-32UDKBA2.js";
13
13
  import {
14
14
  handleSearch
15
- } from "../../chunk-HAU5INEJ.js";
15
+ } from "../../chunk-WUD4XR7Y.js";
16
16
  import {
17
17
  buildMessages,
18
18
  citations,
@@ -34,7 +34,7 @@ import {
34
34
  sessionFrom,
35
35
  telemetry,
36
36
  understandQuery
37
- } from "../../chunk-2R7OVYAO.js";
37
+ } from "../../chunk-NO4WHD3K.js";
38
38
  import {
39
39
  cfBlobs,
40
40
  embed,
@@ -1000,7 +1000,7 @@ async function callToolOnce(env, ctx, _req, tier, key, name, args, t0) {
1000
1000
  const r = await runTool({ ...env, DB: env.DB }, { name, args }, "mcp");
1001
1001
  payload = r ? { tool: r.name, query: r.query, result: r.output } : { error: { message: `tool ${name} returned nothing for the given arguments` } };
1002
1002
  } else {
1003
- const res = name === "ask" ? await (await import("../../ask-FFDCQXAA.js")).handleAsk(env, ctx, inner, tier, key) : await (await import("../../search-HKGN7F3O.js")).handleSearch(env, ctx, inner, tier, key);
1003
+ const res = name === "ask" ? await (await import("../../ask-645ZWTEQ.js")).handleAsk(env, ctx, inner, tier, key) : await (await import("../../search-6J5FUJOC.js")).handleSearch(env, ctx, inner, tier, key);
1004
1004
  payload = await res.json().catch(() => ({ error: { message: "tool transport failed", status: res.status } }));
1005
1005
  }
1006
1006
  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 });
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.112",
30
+ "version": "0.2.113",
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",
@@ -170,6 +170,26 @@ export function namedDocumentIn(query: string): DocScope | null {
170
170
  * scoped_to stays null). A registry READ failure proceeds with the
171
171
  * parsed scope — a scoped refusal is more honest than silently
172
172
  * widening to the whole corpus. */
173
+ /** The seal's grain fix (the 2026-10-09 gate): the corpus stores PART
174
+ * publications at family grain — R 60-1:2021's chunks carry
175
+ * doc_number "60" with the part identity only in the docidentifier —
176
+ * so a scope naming a part ("60-1") admits a family-grain chunk only
177
+ * when the chunk's OWN identifier stem names the same part (the
178
+ * stem's last token is the number, edition and language markers
179
+ * stripped). Exact grain agreement always matches; R 60-2 never
180
+ * passes an R 60-1 chip. */
181
+ export function matchesDocScope(
182
+ meta: { doc_number?: string; docidentifier?: string },
183
+ scopeDocNumber: string,
184
+ ): boolean {
185
+ if (meta.doc_number === scopeDocNumber) return true;
186
+ if (!scopeDocNumber.includes("-")) return false;
187
+ if (meta.doc_number !== scopeDocNumber.split("-")[0]) return false;
188
+ const stem = (meta.docidentifier ?? "").replace(/\s*\([A-Z]\)\s*$/, "").replace(/:\d+$/, "").trim();
189
+ const last = stem.split(/\s+/).pop()?.toLowerCase();
190
+ return last === scopeDocNumber.toLowerCase();
191
+ }
192
+
173
193
  export async function resolveDocScope(env: any, ctx: DeclaredContext): Promise<DocScope | null> {
174
194
  if (!ctx.doc) return null;
175
195
  const parsed = parseDocRef(ctx.doc, ctx.edition);
@@ -33,6 +33,7 @@ export function fill(template: string, vars: Record<string, string>): string {
33
33
  return template.replace(/\{\{(\w+)\}\}/g, (_m, k: string) => (k in vars ? vars[k] : ""));
34
34
  }
35
35
  import { QueryFilters, toVectorizeFilter, standardKeyAllowed } from "./selfquery";
36
+ import { matchesDocScope } from "./context";
36
37
  import { hitQuality } from "./quality";
37
38
  import { lexicalPrefilter } from "./lexical";
38
39
  import { positionOrder } from "./structural";
@@ -133,7 +134,7 @@ export async function retrieve(
133
134
  ? lexicalHits0.filter(
134
135
  (h) =>
135
136
  (!opts.sealScope ||
136
- (h.metadata.doc_number === opts.sealScope!.doc_number &&
137
+ (matchesDocScope(h.metadata, opts.sealScope!.doc_number) &&
137
138
  (!opts.sealScope!.edition || h.metadata.edition === opts.sealScope!.edition))) &&
138
139
  standardKeyAllowed(h.metadata, opts.standardKeys),
139
140
  )
@@ -2,6 +2,7 @@
2
2
  // after every lane has merged, before rerank + the top-N cut. Nothing
3
3
  // outside the declared family competes for the window; everything
4
4
  // inside it does.
5
+ import { matchesDocScope } from "../context.ts";
5
6
  import type { Stage } from "./types.ts";
6
7
 
7
8
  export const seal: Stage = {
@@ -11,7 +12,7 @@ export const seal: Stage = {
11
12
  const before = c.hits.length;
12
13
  const scope = c.opts.sealScope!;
13
14
  if (scope) {
14
- c.hits = c.hits.filter((h) => h.metadata.doc_number === scope.doc_number && (!scope.edition || h.metadata.edition === scope.edition));
15
+ c.hits = c.hits.filter((h) => matchesDocScope(h.metadata, scope.doc_number) && (!scope.edition || h.metadata.edition === scope.edition));
15
16
  console.log("context seal:", before, "→", c.hits.length, "candidates within", `doc#${scope.doc_number}${scope.edition ? "@" + scope.edition : ""}`);
16
17
  return;
17
18
  }