@keel_flow/pack-kb-hygiene 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 jglasskatz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,15 @@
1
+ # @keel_flow/pack-kb-hygiene
2
+
3
+ Knowledge base integration principles for Keel projects: six principles enforcing citation requirements, retrieval-before-answer discipline, chunk-size hygiene, and embedding consistency — each with a `check` function for `keel verify`.
4
+
5
+ Part of the [Keel](https://github.com/jglasskatz/keel) framework.
6
+
7
+ ## Install
8
+
9
+ ```
10
+ npm install @keel_flow/pack-kb-hygiene
11
+ ```
12
+
13
+ ## License
14
+
15
+ MIT
@@ -0,0 +1,2 @@
1
+ export declare function searchKb(query: string, candidates: unknown[]): Promise<unknown[]>;
2
+ //# sourceMappingURL=retrieve-call-guarded.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retrieve-call-guarded.d.ts","sourceRoot":"","sources":["../../src/__fixtures__/retrieve-call-guarded.ts"],"names":[],"mappings":"AAIA,wBAAsB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAEvF"}
@@ -0,0 +1,6 @@
1
+ import { retrieve } from "./retrieve-definition-only.js";
2
+ const DEFAULT_THRESHOLD = 0.5;
3
+ export async function searchKb(query, candidates) {
4
+ return retrieve({ query, candidates, minScore: DEFAULT_THRESHOLD });
5
+ }
6
+ //# sourceMappingURL=retrieve-call-guarded.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retrieve-call-guarded.js","sourceRoot":"","sources":["../../src/__fixtures__/retrieve-call-guarded.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAEzD,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAE9B,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,KAAa,EAAE,UAAqB;IACjE,OAAO,QAAQ,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,iBAAiB,EAAE,CAAC,CAAC;AACtE,CAAC"}
@@ -0,0 +1,6 @@
1
+ export declare function searchKb(kb: {
2
+ retrieve: (q: string, k: number, opts?: {
3
+ minScore?: number;
4
+ }) => Promise<unknown[]>;
5
+ }): Promise<unknown[]>;
6
+ //# sourceMappingURL=retrieve-call-third-arg-guarded.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retrieve-call-third-arg-guarded.d.ts","sourceRoot":"","sources":["../../src/__fixtures__/retrieve-call-third-arg-guarded.ts"],"names":[],"mappings":"AAAA,wBAAsB,QAAQ,CAAC,EAAE,EAAE;IAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAE/I"}
@@ -0,0 +1,4 @@
1
+ export async function searchKb(kb) {
2
+ return kb.retrieve("some query", 5, { minScore: 0.5 });
3
+ }
4
+ //# sourceMappingURL=retrieve-call-third-arg-guarded.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retrieve-call-third-arg-guarded.js","sourceRoot":"","sources":["../../src/__fixtures__/retrieve-call-third-arg-guarded.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,EAA4F;IACzH,OAAO,EAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;AACzD,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function searchKb(query: string, candidates: unknown[]): Promise<unknown[]>;
2
+ //# sourceMappingURL=retrieve-call-unguarded.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retrieve-call-unguarded.d.ts","sourceRoot":"","sources":["../../src/__fixtures__/retrieve-call-unguarded.ts"],"names":[],"mappings":"AAEA,wBAAsB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAGvF"}
@@ -0,0 +1,6 @@
1
+ import { retrieve } from "./retrieve-definition-only.js";
2
+ export async function searchKb(query, candidates) {
3
+ // eslint-disable-next-line @keel_flow/retrieval-confidence-floor
4
+ return retrieve({ query, candidates });
5
+ }
6
+ //# sourceMappingURL=retrieve-call-unguarded.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retrieve-call-unguarded.js","sourceRoot":"","sources":["../../src/__fixtures__/retrieve-call-unguarded.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAEzD,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,KAAa,EAAE,UAAqB;IACjE,iEAAiE;IACjE,OAAO,QAAQ,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1,6 @@
1
+ export declare function retrieve(opts: {
2
+ query: string;
3
+ candidates: unknown[];
4
+ minScore?: number;
5
+ }): Promise<unknown[]>;
6
+ //# sourceMappingURL=retrieve-definition-only.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retrieve-definition-only.d.ts","sourceRoot":"","sources":["../../src/__fixtures__/retrieve-definition-only.ts"],"names":[],"mappings":"AAAA,wBAAsB,QAAQ,CAAC,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAEpH"}
@@ -0,0 +1,4 @@
1
+ export async function retrieve(opts) {
2
+ return opts.candidates;
3
+ }
4
+ //# sourceMappingURL=retrieve-definition-only.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retrieve-definition-only.js","sourceRoot":"","sources":["../../src/__fixtures__/retrieve-definition-only.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAiE;IAC9F,OAAO,IAAI,CAAC,UAAU,CAAC;AACzB,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { PrincipleWithCheck, PrinciplePack } from "@keel_flow/schema";
2
+ export declare const kbHygienePrinciples: PrincipleWithCheck[];
3
+ export declare const kbHygienePack: PrinciplePack;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAa,MAAM,mBAAmB,CAAC;AA6HtF,eAAO,MAAM,mBAAmB,EAAE,kBAAkB,EAsHnD,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,aAK3B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,247 @@
1
+ import { existsSync, readFileSync } from "fs";
2
+ import { join } from "path";
3
+ import { parse, AST_NODE_TYPES } from "@typescript-eslint/typescript-estree";
4
+ const THRESHOLD = /threshold|minScore|similarity|floor/i;
5
+ function isRetrieveCallee(callee) {
6
+ if (callee.type === AST_NODE_TYPES.Identifier)
7
+ return callee.name === "retrieve";
8
+ if (callee.type === AST_NODE_TYPES.MemberExpression &&
9
+ callee.property.type === AST_NODE_TYPES.Identifier) {
10
+ return callee.property.name === "retrieve";
11
+ }
12
+ return false;
13
+ }
14
+ function argHasThreshold(arg) {
15
+ if (!arg || arg.type !== AST_NODE_TYPES.ObjectExpression)
16
+ return false;
17
+ return arg.properties.some((p) => p.type === AST_NODE_TYPES.Property &&
18
+ p.key.type === AST_NODE_TYPES.Identifier &&
19
+ THRESHOLD.test(p.key.name));
20
+ }
21
+ function anyArgHasThreshold(args) {
22
+ return args.some(argHasThreshold);
23
+ }
24
+ function memberName(member) {
25
+ if (member.type === AST_NODE_TYPES.TSPropertySignature &&
26
+ member.key.type === AST_NODE_TYPES.Identifier) {
27
+ return member.key.name;
28
+ }
29
+ return null;
30
+ }
31
+ // True when the file defines a retrieval options *type* (the implementation
32
+ // surface that carries the floor) yet that type declares no threshold/minScore
33
+ // member. This catches the failure mode the principle names directly: a
34
+ // retriever whose options interface cannot even express a confidence floor, so
35
+ // no call site could ever pass one. It complements the call-site guard —
36
+ // call-site syntax can be satisfied while the underlying contract has no floor.
37
+ function definesFloorlessRetrieveOpts(ast) {
38
+ let floorless = false;
39
+ const visit = (node) => {
40
+ if (floorless)
41
+ return;
42
+ if (node.type === AST_NODE_TYPES.TSInterfaceDeclaration &&
43
+ /Retrieve.*Opts|RetrieveOpts/.test(node.id.name)) {
44
+ const hasFloor = node.body.body.some((m) => {
45
+ const name = memberName(m);
46
+ return name !== null && THRESHOLD.test(name);
47
+ });
48
+ if (!hasFloor) {
49
+ floorless = true;
50
+ return;
51
+ }
52
+ }
53
+ for (const key in node) {
54
+ if (key === "parent")
55
+ continue;
56
+ const value = node[key];
57
+ if (Array.isArray(value)) {
58
+ for (const child of value) {
59
+ if (child && typeof child === "object" && "type" in child)
60
+ visit(child);
61
+ }
62
+ }
63
+ else if (value && typeof value === "object" && "type" in value) {
64
+ visit(value);
65
+ }
66
+ }
67
+ };
68
+ visit(ast);
69
+ return floorless;
70
+ }
71
+ // Walks the parsed program for retrieve(...) call sites lacking a confidence
72
+ // guard. Mirrors the AST logic in @keel_flow/eslint-plugin's retrieval-confidence-floor
73
+ // rule so editor-time and verify-time enforcement stay identical. A function
74
+ // *declaration* named retrieve is not a CallExpression, so the definition site
75
+ // never trips this — only actual invocations do.
76
+ function hasUnguardedRetrieveCall(ast) {
77
+ let found = false;
78
+ const visit = (node) => {
79
+ if (found)
80
+ return;
81
+ if (node.type === AST_NODE_TYPES.CallExpression &&
82
+ isRetrieveCallee(node.callee) &&
83
+ !anyArgHasThreshold(node.arguments)) {
84
+ found = true;
85
+ return;
86
+ }
87
+ for (const key in node) {
88
+ if (key === "parent")
89
+ continue;
90
+ const value = node[key];
91
+ if (Array.isArray(value)) {
92
+ for (const child of value) {
93
+ if (child && typeof child === "object" && "type" in child)
94
+ visit(child);
95
+ }
96
+ }
97
+ else if (value && typeof value === "object" && "type" in value) {
98
+ visit(value);
99
+ }
100
+ }
101
+ };
102
+ visit(ast);
103
+ return found;
104
+ }
105
+ function parseProgram(src) {
106
+ try {
107
+ return parse(src, { jsx: false, loc: false, range: false });
108
+ }
109
+ catch {
110
+ return null;
111
+ }
112
+ }
113
+ // Honors `@keel-ignore-file: <principle-id>` directive anywhere in source.
114
+ function hasIgnoreFileDirective(src, principleId) {
115
+ const escaped = principleId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
116
+ return new RegExp(`@keel-ignore-file\\s*:\\s*${escaped}\\b`).test(src);
117
+ }
118
+ export const kbHygienePrinciples = [
119
+ {
120
+ id: "cite-or-decline",
121
+ description: "Every agent response derived from the KB must cite the source chunk; if no relevant chunk exists, decline rather than hallucinate",
122
+ rationale: "Uncited claims are indistinguishable from hallucinations; citations let users verify and build trust",
123
+ severity: "critical",
124
+ },
125
+ {
126
+ id: "retrieval-confidence-floor",
127
+ description: "The retrieval data path must enforce a configurable confidence floor: retrieve options carry a minScore/threshold and the retriever drops chunks scoring below it. This is a real implementation contract — proven by the retriever's unit tests — not just call-site syntax. The AST checks below remain the editor/verify guard for call sites and for options types that cannot express a floor.",
128
+ rationale: "Low-confidence retrieval degrades response quality and poisons reasoning with irrelevant context",
129
+ severity: "critical",
130
+ check({ diff, cwd }) {
131
+ // Honor the verify cwd so file reads resolve against the target project
132
+ // rather than the runner's working directory.
133
+ const root = cwd ?? process.cwd();
134
+ const violations = [];
135
+ for (const file of diff.files) {
136
+ if (!file.path.includes("kb") && !file.path.includes("retriev"))
137
+ continue;
138
+ if (file.status === "removed")
139
+ continue;
140
+ if (file.path.endsWith(".test.ts"))
141
+ continue;
142
+ if (file.path.includes("__fixtures__"))
143
+ continue;
144
+ const absPath = join(root, file.path);
145
+ if (!existsSync(absPath))
146
+ continue;
147
+ try {
148
+ const content = readFileSync(absPath, "utf-8");
149
+ if (hasIgnoreFileDirective(content, "retrieval-confidence-floor"))
150
+ continue;
151
+ const ast = parseProgram(content);
152
+ if (!ast)
153
+ continue;
154
+ if (definesFloorlessRetrieveOpts(ast)) {
155
+ violations.push({
156
+ principleId: "retrieval-confidence-floor",
157
+ file: file.path,
158
+ severity: "critical",
159
+ message: `Retrieval options type in "${file.path}" has no confidence floor field. Add a minScore/threshold member so the retriever can drop sub-floor chunks.`,
160
+ });
161
+ continue;
162
+ }
163
+ if (!hasUnguardedRetrieveCall(ast))
164
+ continue;
165
+ violations.push({
166
+ principleId: "retrieval-confidence-floor",
167
+ file: file.path,
168
+ severity: "critical",
169
+ message: `KB retrieval in "${file.path}" does not appear to enforce a confidence threshold. Add a minScore/threshold guard.`,
170
+ });
171
+ }
172
+ catch {
173
+ // File unreadable; skip
174
+ }
175
+ }
176
+ return violations;
177
+ },
178
+ },
179
+ {
180
+ id: "kb-freshness-tracking",
181
+ description: "Each KB document records when it was last ingested; agents can query staleness",
182
+ rationale: "Stale KB content produces confident but outdated answers; freshness metadata lets the system warn users",
183
+ severity: "warning",
184
+ },
185
+ {
186
+ id: "no-grounding-on-empty",
187
+ description: "An agent must not proceed with a KB-grounded task if the KB has no indexed content for the workspace",
188
+ rationale: "An empty KB silently degrades to hallucination mode; the agent must surface this as an error, not proceed",
189
+ severity: "critical",
190
+ },
191
+ {
192
+ id: "chunk-size-bounded",
193
+ description: "KB chunks must be bounded to a configured maximum token size; oversized chunks degrade retrieval precision",
194
+ rationale: "Embedding models represent semantics at paragraph granularity; chunks spanning multiple topics produce diluted embeddings that retrieve for too many queries",
195
+ severity: "warning",
196
+ check({ diff, cwd }) {
197
+ // Honor the verify cwd so file reads resolve against the target project
198
+ // rather than the runner's working directory.
199
+ const root = cwd ?? process.cwd();
200
+ const violations = [];
201
+ for (const file of diff.files) {
202
+ if (!file.path.includes("kb") && !file.path.includes("chunk") && !file.path.includes("ingest"))
203
+ continue;
204
+ if (file.status === "removed")
205
+ continue;
206
+ const absPath = join(root, file.path);
207
+ if (!existsSync(absPath))
208
+ continue;
209
+ try {
210
+ const content = readFileSync(absPath, "utf-8");
211
+ if (hasIgnoreFileDirective(content, "chunk-size-bounded"))
212
+ continue;
213
+ // Only fire on files that LOOK like chunking code, not files that
214
+ // merely reference chunks (e.g. a retriever returning KBChunk).
215
+ const looksLikeChunker = /function\s+chunk|export\s+(const|function)\s+chunk|\.slice\(|while\s*\(start/.test(content);
216
+ if (!looksLikeChunker)
217
+ continue;
218
+ if (!content.match(/maxChunkSize|chunkSize|maxTokens|tokenLimit/i)) {
219
+ violations.push({
220
+ principleId: "chunk-size-bounded",
221
+ file: file.path,
222
+ severity: "warning",
223
+ message: `KB chunking in "${file.path}" does not appear to enforce a size bound. Add a maxChunkSize or tokenLimit guard.`,
224
+ });
225
+ }
226
+ }
227
+ catch {
228
+ // File unreadable; skip
229
+ }
230
+ }
231
+ return violations;
232
+ },
233
+ },
234
+ {
235
+ id: "embedding-model-locked",
236
+ description: "The embedding model for a KB index must be recorded at index creation and must not change without a full re-index",
237
+ rationale: "Switching embedding models invalidates all stored vectors silently; queries against mismatched vectors produce semantically incorrect results",
238
+ severity: "critical",
239
+ },
240
+ ];
241
+ export const kbHygienePack = {
242
+ id: "@keel_flow/pack-kb-hygiene",
243
+ version: "0.1.0",
244
+ description: "Knowledge base integration principles for safe and reliable KB-grounded agents.",
245
+ principles: kbHygienePrinciples,
246
+ };
247
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@keel_flow/pack-kb-hygiene",
3
+ "version": "0.2.0",
4
+ "private": false,
5
+ "type": "module",
6
+ "description": "Knowledge base integration principles for Keel projects",
7
+ "keywords": [
8
+ "keel",
9
+ "principles",
10
+ "knowledge-base"
11
+ ],
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "README.md"
18
+ ],
19
+ "main": "./dist/index.js",
20
+ "types": "./dist/index.d.ts",
21
+ "exports": {
22
+ ".": {
23
+ "import": "./dist/index.js",
24
+ "types": "./dist/index.d.ts"
25
+ }
26
+ },
27
+ "dependencies": {
28
+ "@typescript-eslint/typescript-estree": "^8.0.0",
29
+ "@keel_flow/schema": "0.2.0"
30
+ },
31
+ "devDependencies": {
32
+ "@types/node": "^25.9.1",
33
+ "@typescript-eslint/eslint-plugin": "^8.0.0",
34
+ "@typescript-eslint/parser": "^8.0.0",
35
+ "eslint": "^9.0.0",
36
+ "typescript": "^5.5.0",
37
+ "vitest": "^2.0.0"
38
+ },
39
+ "scripts": {
40
+ "build": "tsc",
41
+ "typecheck": "tsc --noEmit",
42
+ "test": "vitest run",
43
+ "lint": "eslint src"
44
+ }
45
+ }