@danielblomma/cortex-mcp 2.2.5 → 2.4.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.
@@ -0,0 +1,322 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import fs from "node:fs";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+ import { execFileSync } from "node:child_process";
7
+ import {
8
+ buildPatternReviewContext,
9
+ createLocalPatternRunner,
10
+ PATTERN_REVIEW_QUESTION,
11
+ } from "../dist/enterprise/reviews/pattern-context.js";
12
+ import {
13
+ buildContextReviewAuditInput,
14
+ registerEnterpriseTools,
15
+ } from "../dist/enterprise/tools/enterprise.js";
16
+
17
+ function evidence(overrides = {}) {
18
+ return {
19
+ query: "error handling",
20
+ query_source: "explicit",
21
+ local_pattern_found: false,
22
+ fallback_used: false,
23
+ evidence_order: ["same_file", "same_module", "same_feature_area", "repo_wide"],
24
+ tiers: [
25
+ { name: "same_file", evidence: [] },
26
+ { name: "same_module", evidence: [] },
27
+ { name: "same_feature_area", evidence: [] },
28
+ { name: "repo_wide", evidence: [] },
29
+ ],
30
+ ...overrides,
31
+ };
32
+ }
33
+
34
+ test("composes deterministic non-blocking pattern context without inventing pass or fail", async () => {
35
+ const runner = async ({ target }) => {
36
+ if (target === "missing.ts") {
37
+ throw new Error("Pattern target was not found in indexed context: /private/repo/missing.ts");
38
+ }
39
+ if (target === "error.ts") {
40
+ throw new Error("secret internal stack detail");
41
+ }
42
+ if (target === "a.ts") {
43
+ return evidence({
44
+ local_pattern_found: true,
45
+ tiers: [
46
+ {
47
+ name: "same_file",
48
+ evidence: [{ id: "chunk:a", path: "a.ts", start_line: 2, end_line: 8 }],
49
+ },
50
+ ],
51
+ });
52
+ }
53
+ if (target === "b.ts") {
54
+ return evidence({
55
+ fallback_used: true,
56
+ tiers: [
57
+ {
58
+ name: "repo_wide",
59
+ evidence: [{ id: "file:docs/review.md", path: "docs/review.md" }],
60
+ },
61
+ ],
62
+ });
63
+ }
64
+ return evidence();
65
+ };
66
+
67
+ const result = await buildPatternReviewContext({
68
+ files: ["z.ts", "a.ts", "b.ts", "a.ts", "../secret.ts", "c.ts", "missing.ts", "error.ts"],
69
+ enabled: true,
70
+ query: "error handling",
71
+ topK: 2,
72
+ limit: 10,
73
+ runner,
74
+ });
75
+
76
+ assert.equal(result.enabled, true);
77
+ assert.equal(result.non_blocking, true);
78
+ assert.equal(result.affects_policy_summary, false);
79
+ assert.equal(result.review_question, PATTERN_REVIEW_QUESTION);
80
+ assert.deepEqual(result.targets.map((target) => target.path), [
81
+ "a.ts",
82
+ "b.ts",
83
+ "c.ts",
84
+ "error.ts",
85
+ "missing.ts",
86
+ "z.ts",
87
+ ]);
88
+ assert.deepEqual(result.targets.map((target) => target.status), [
89
+ "local_evidence",
90
+ "repo_fallback",
91
+ "no_evidence",
92
+ "error",
93
+ "not_indexed",
94
+ "no_evidence",
95
+ ]);
96
+ assert.equal(result.targets[0].tiers[0].evidence[0].start_line, 2);
97
+ assert.equal(result.targets[3].message, "Pattern evidence could not be produced for this target.");
98
+ assert.equal(result.targets[3].local_pattern_found, false);
99
+ assert.equal(result.targets[3].fallback_used, false);
100
+ assert.equal(result.targets[3].tiers.length, 4);
101
+ assert.equal(result.targets[4].query, "error handling");
102
+ const targetKeys = Object.keys(result.targets[0]).sort();
103
+ for (const target of result.targets) {
104
+ assert.deepEqual(Object.keys(target).sort(), targetKeys);
105
+ }
106
+ assert.doesNotMatch(JSON.stringify(result), /secret internal stack detail|\/private\/repo/u);
107
+ assert.deepEqual(result.summary, {
108
+ requested: 8,
109
+ eligible: 6,
110
+ analyzed: 6,
111
+ local_evidence: 1,
112
+ repo_fallback: 1,
113
+ no_evidence: 2,
114
+ not_indexed: 1,
115
+ errors: 1,
116
+ omitted: 0,
117
+ invalid_paths: 1,
118
+ });
119
+ });
120
+
121
+ test("sanitizes runtime warnings and unsafe citation paths", async () => {
122
+ const result = await buildPatternReviewContext({
123
+ files: ["src/a.ts"],
124
+ enabled: true,
125
+ topK: 5,
126
+ limit: 1,
127
+ runner: async () => evidence({
128
+ warning: "model cache failed at /Users/alice/private/model and C:\\Users\\alice\\model",
129
+ tiers: [
130
+ {
131
+ name: "same_file",
132
+ evidence: [
133
+ { id: "chunk:src/a.ts:run", path: "src/a.ts", start_line: 1, end_line: 3 },
134
+ { id: "chunk:/Users/alice/private", path: "/Users/alice/private/a.ts" },
135
+ { id: "chunk:C:/Users/alice/private", path: "C:\\Users\\alice\\private\\a.ts" },
136
+ { id: "chunk:../secret", path: "../secret.ts" },
137
+ ],
138
+ },
139
+ ],
140
+ }),
141
+ });
142
+
143
+ assert.equal(result.targets[0].status, "local_evidence");
144
+ assert.equal(result.targets[0].tiers[0].evidence.length, 1);
145
+ assert.equal(result.targets[0].citations_dropped, 3);
146
+ assert.equal(result.targets[0].warning, "Pattern evidence completed with local runtime warnings.");
147
+ assert.doesNotMatch(JSON.stringify(result), /Users[\\/]alice|\.\.\/secret/u);
148
+ });
149
+
150
+ test("audit projection records query size but not query text", () => {
151
+ const input = buildContextReviewAuditInput({
152
+ scope: "changed",
153
+ include_passed: true,
154
+ include_pattern_evidence: true,
155
+ pattern_query: "SECRET_API_KEY=do-not-retain",
156
+ pattern_top_k: 2,
157
+ pattern_limit: 10,
158
+ });
159
+
160
+ assert.equal(input.pattern_query_present, true);
161
+ assert.equal(input.pattern_query_length, 28);
162
+ assert.equal("pattern_query" in input, false);
163
+ assert.doesNotMatch(JSON.stringify(input), /SECRET_API_KEY/u);
164
+ });
165
+
166
+ test("bounds review targets after normalized deterministic ordering", async () => {
167
+ const calls = [];
168
+ const result = await buildPatternReviewContext({
169
+ files: ["z.ts", "./b.ts", "a.ts", "b.ts"],
170
+ enabled: true,
171
+ topK: 1,
172
+ limit: 2,
173
+ runner: async ({ target }) => {
174
+ calls.push(target);
175
+ return evidence();
176
+ },
177
+ });
178
+
179
+ assert.deepEqual(calls, ["a.ts", "b.ts"]);
180
+ assert.equal(result.summary.requested, 4);
181
+ assert.equal(result.summary.eligible, 3);
182
+ assert.equal(result.summary.analyzed, 2);
183
+ assert.equal(result.summary.omitted, 1);
184
+ });
185
+
186
+ test("default local pattern runner loads context data once across targets", async () => {
187
+ const document = (id, filePath) => ({
188
+ id,
189
+ path: filePath,
190
+ kind: "CODE",
191
+ updated_at: "2026-07-12T00:00:00.000Z",
192
+ source_of_truth: false,
193
+ trust_level: 60,
194
+ status: "active",
195
+ excerpt: "export const value = 1;",
196
+ content: "export const value = 1;",
197
+ });
198
+ const data = {
199
+ documents: [document("file:src/a.ts", "src/a.ts"), document("file:src/b.ts", "src/b.ts")],
200
+ chunks: [],
201
+ rules: [],
202
+ adrs: [],
203
+ modules: [],
204
+ projects: [],
205
+ relations: [],
206
+ ranking: { semantic: 0.4, graph: 0.25, trust: 0.2, recency: 0.15 },
207
+ source: "cache",
208
+ };
209
+ let loads = 0;
210
+ const runner = createLocalPatternRunner(async () => {
211
+ loads += 1;
212
+ return data;
213
+ });
214
+
215
+ await runner({ target: "src/a.ts", top_k: 1 });
216
+ await runner({ target: "src/b.ts", top_k: 1 });
217
+
218
+ assert.equal(loads, 1);
219
+ });
220
+
221
+ test("disabled mode does not invoke pattern retrieval", async () => {
222
+ let called = false;
223
+ const result = await buildPatternReviewContext({
224
+ files: ["a.ts", "b.ts"],
225
+ enabled: false,
226
+ topK: 2,
227
+ limit: 10,
228
+ runner: async () => {
229
+ called = true;
230
+ return evidence();
231
+ },
232
+ });
233
+
234
+ assert.equal(called, false);
235
+ assert.equal(result.enabled, false);
236
+ assert.equal(result.affects_policy_summary, false);
237
+ assert.equal(result.summary.requested, 2);
238
+ assert.deepEqual(result.targets, []);
239
+ });
240
+
241
+ test("context.review includes pattern context without changing validator summary", async () => {
242
+ const projectRoot = fs.mkdtempSync(path.join(os.tmpdir(), "cortex-pattern-review-tool-"));
243
+ const contextDir = path.join(projectRoot, ".context");
244
+ const previousProjectRoot = process.env.CORTEX_PROJECT_ROOT;
245
+ fs.mkdirSync(path.join(projectRoot, "src"), { recursive: true });
246
+ fs.writeFileSync(path.join(projectRoot, ".gitignore"), ".context/\nignored.ts\n", "utf8");
247
+ execFileSync("git", ["init"], { cwd: projectRoot, stdio: "ignore" });
248
+ execFileSync("git", ["add", ".gitignore"], { cwd: projectRoot, stdio: "ignore" });
249
+ execFileSync("git", ["-c", "user.name=Cortex Test", "-c", "user.email=cortex@example.invalid", "commit", "-m", "fixture"], {
250
+ cwd: projectRoot,
251
+ stdio: "ignore",
252
+ });
253
+ fs.mkdirSync(contextDir, { recursive: true });
254
+ fs.writeFileSync(path.join(projectRoot, "src", "new-file.ts"), "export const value = 1;\n", "utf8");
255
+ fs.writeFileSync(path.join(projectRoot, "ignored.ts"), "ignored\n", "utf8");
256
+ process.env.CORTEX_PROJECT_ROOT = projectRoot;
257
+
258
+ try {
259
+ const tools = new Map();
260
+ const server = {
261
+ registerTool(name, definition, handler) {
262
+ tools.set(name, { definition, handler });
263
+ },
264
+ };
265
+ const config = {
266
+ enterprise: { endpoint: "", api_key: "", base_url: "" },
267
+ telemetry: { enabled: false, endpoint: "", api_key: "", interval_minutes: 10 },
268
+ audit: { enabled: false, retention_days: 90 },
269
+ policy: { enabled: false, endpoint: "", api_key: "", sync_interval_minutes: 240 },
270
+ rbac: { enabled: false, default_role: "developer" },
271
+ validators: {},
272
+ compliance: { frameworks: [], eu_addons: false },
273
+ govern: {
274
+ mode: "off",
275
+ sync_on_startup: false,
276
+ sync_interval_minutes: 60,
277
+ tier_claude: "prevent",
278
+ tier_codex: "prevent",
279
+ tier_copilot: "wrap",
280
+ detect_ungoverned: false,
281
+ govern_endpoint: "",
282
+ },
283
+ };
284
+ registerEnterpriseTools(
285
+ server,
286
+ {},
287
+ null,
288
+ config,
289
+ contextDir,
290
+ { getMergedPolicies: () => [] },
291
+ "2.3.0",
292
+ );
293
+
294
+ const reviewTool = tools.get("context.review");
295
+ assert.ok(reviewTool);
296
+ const result = await reviewTool.handler({
297
+ scope: "changed",
298
+ include_passed: true,
299
+ });
300
+ const output = result.structuredContent;
301
+
302
+ assert.equal(output.summary.total, 0);
303
+ assert.equal("pattern_analyzed" in output.summary, false);
304
+ assert.equal(output.pattern_review.enabled, true);
305
+ assert.equal(output.pattern_review.affects_policy_summary, false);
306
+ assert.equal(output.pattern_review.limit, 10);
307
+ assert.equal(output.pattern_review.top_k_per_tier, 2);
308
+ assert.equal(output.pattern_review.summary.analyzed, 1);
309
+ assert.equal(output.pattern_review.targets[0].path, "src/new-file.ts");
310
+ assert.equal(output.pattern_review.targets[0].status, "not_indexed");
311
+ assert.equal(output.pattern_review.targets[0].local_pattern_found, false);
312
+ assert.equal(output.pattern_review.targets[0].fallback_used, false);
313
+ assert.equal(output.pattern_review.targets[0].tiers.length, 4);
314
+ } finally {
315
+ if (previousProjectRoot === undefined) {
316
+ delete process.env.CORTEX_PROJECT_ROOT;
317
+ } else {
318
+ process.env.CORTEX_PROJECT_ROOT = previousProjectRoot;
319
+ }
320
+ fs.rmSync(projectRoot, { recursive: true, force: true });
321
+ }
322
+ });
@@ -4,13 +4,15 @@ import { mkdtempSync, mkdirSync, realpathSync, writeFileSync } from "node:fs";
4
4
  import { tmpdir } from "node:os";
5
5
  import path from "node:path";
6
6
  import { spawnSync } from "node:child_process";
7
- import { pathToFileURL } from "node:url";
7
+ import { fileURLToPath, pathToFileURL } from "node:url";
8
+
9
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
8
10
 
9
11
  test("paths resolve the project root from cwd without duplicating .context", () => {
10
12
  const projectRoot = mkdtempSync(path.join(tmpdir(), "cortex-paths-"));
11
13
  const contextDir = path.join(projectRoot, ".context");
12
14
  const mcpDir = path.join(contextDir, "mcp");
13
- const pathsModuleUrl = pathToFileURL(path.resolve("dist/paths.js")).href;
15
+ const pathsModuleUrl = pathToFileURL(path.resolve(__dirname, "..", "dist", "paths.js")).href;
14
16
 
15
17
  mkdirSync(mcpDir, { recursive: true });
16
18
  writeFileSync(path.join(contextDir, "config.yaml"), "source_paths:\n - src\n");
@@ -20,7 +22,7 @@ test("paths resolve the project root from cwd without duplicating .context", ()
20
22
  [
21
23
  "--input-type=module",
22
24
  "-e",
23
- `import { REPO_ROOT, CONTEXT_DIR, CACHE_DIR } from ${JSON.stringify(pathsModuleUrl)}; console.log(JSON.stringify({ REPO_ROOT, CONTEXT_DIR, CACHE_DIR }));`
25
+ `import { REPO_ROOT, CONTEXT_DIR, CACHE_DIR, DEFAULT_RANKING } from ${JSON.stringify(pathsModuleUrl)}; console.log(JSON.stringify({ REPO_ROOT, CONTEXT_DIR, CACHE_DIR, DEFAULT_RANKING }));`
24
26
  ],
25
27
  {
26
28
  cwd: mcpDir,
@@ -35,4 +37,10 @@ test("paths resolve the project root from cwd without duplicating .context", ()
35
37
  assert.equal(parsed.REPO_ROOT, resolvedProjectRoot);
36
38
  assert.equal(parsed.CONTEXT_DIR, path.join(resolvedProjectRoot, ".context"));
37
39
  assert.equal(parsed.CACHE_DIR, path.join(resolvedProjectRoot, ".context", "cache"));
40
+ assert.deepEqual(parsed.DEFAULT_RANKING, {
41
+ semantic: 0.4,
42
+ graph: 0.25,
43
+ trust: 0.2,
44
+ recency: 0.15
45
+ });
38
46
  });
@@ -0,0 +1,321 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import {
4
+ classifyPatternEvidence,
5
+ contextReferenceTimeMs,
6
+ runLocalPatternEvidence,
7
+ runPatternEvidence,
8
+ } from "../dist/patternEvidence.js";
9
+
10
+ function chunk(id, fileId, startLine, endLine) {
11
+ return {
12
+ id,
13
+ file_id: fileId,
14
+ name: id,
15
+ kind: "function",
16
+ signature: "",
17
+ body: "",
18
+ description: "",
19
+ start_line: startLine,
20
+ end_line: endLine,
21
+ language: "typescript",
22
+ exported: false,
23
+ updated_at: "2026-07-12T00:00:00.000Z",
24
+ source_of_truth: false,
25
+ trust_level: 60,
26
+ status: "active",
27
+ };
28
+ }
29
+
30
+ function document(id, filePath, kind, content = "") {
31
+ return {
32
+ id,
33
+ path: filePath,
34
+ kind,
35
+ updated_at: "2026-07-12T00:00:00.000Z",
36
+ source_of_truth: false,
37
+ trust_level: kind === "DOC" ? 80 : 60,
38
+ status: "active",
39
+ excerpt: content,
40
+ content,
41
+ };
42
+ }
43
+
44
+ function contextData({ documents, chunks = [] }) {
45
+ return {
46
+ documents,
47
+ chunks,
48
+ rules: [],
49
+ adrs: [],
50
+ modules: [],
51
+ projects: [],
52
+ relations: [],
53
+ ranking: { semantic: 0.4, graph: 0.25, trust: 0.2, recency: 0.15 },
54
+ source: "cache",
55
+ };
56
+ }
57
+
58
+ test("classifies helper, error, and config evidence in local-first order with line citations", () => {
59
+ const target = {
60
+ input: "src/features/auth/controller.ts",
61
+ entity_id: "file:src/features/auth/controller.ts",
62
+ entity_type: "File",
63
+ path: "src/features/auth/controller.ts",
64
+ };
65
+ const results = [
66
+ {
67
+ id: target.entity_id,
68
+ entity_type: "File",
69
+ kind: "CODE",
70
+ title: target.path,
71
+ path: target.path,
72
+ excerpt: "target must not cite itself",
73
+ score: 0.99,
74
+ },
75
+ {
76
+ id: "chunk:helper",
77
+ entity_type: "Chunk",
78
+ kind: "function",
79
+ title: "normalizeUser",
80
+ path: "src\\features\\auth\\controller.ts",
81
+ excerpt: "file-local helper shape",
82
+ score: 0.9,
83
+ matched_rules: ["rule.repo_local_pattern_review", "rule.repo_local_pattern_review"],
84
+ },
85
+ {
86
+ id: "chunk:error",
87
+ entity_type: "Chunk",
88
+ kind: "function",
89
+ title: "toAuthError",
90
+ path: "src/features/auth/errors.ts",
91
+ excerpt: "module-local error handling",
92
+ score: 0.8,
93
+ },
94
+ {
95
+ id: "chunk:config",
96
+ entity_type: "Chunk",
97
+ kind: "function",
98
+ title: "parseFeatureEnv",
99
+ path: "src/features/config/env.ts",
100
+ excerpt: "feature-local config parsing",
101
+ score: 0.7,
102
+ },
103
+ {
104
+ id: "file:docs/conventions.md",
105
+ entity_type: "File",
106
+ kind: "DOC",
107
+ title: "docs/conventions.md",
108
+ path: "docs/conventions.md",
109
+ excerpt: "repository fallback",
110
+ score: 0.6,
111
+ },
112
+ ];
113
+ const chunks = [
114
+ chunk("chunk:helper", "file:src/features/auth/controller.ts", 10, 18),
115
+ chunk("chunk:error", "file:src/features/auth/errors.ts", 4, 12),
116
+ chunk("chunk:config", "file:src/features/config/env.ts", 20, 31),
117
+ ];
118
+
119
+ const classified = classifyPatternEvidence({ target, results, chunks, topK: 3 });
120
+
121
+ assert.deepEqual(classified.tiers.map((tier) => tier.name), [
122
+ "same_file",
123
+ "same_module",
124
+ "same_feature_area",
125
+ "repo_wide",
126
+ ]);
127
+ assert.deepEqual(classified.tiers.map((tier) => tier.evidence.map((item) => item.id)), [
128
+ ["chunk:helper"],
129
+ ["chunk:error"],
130
+ ["chunk:config"],
131
+ ["file:docs/conventions.md"],
132
+ ]);
133
+ assert.equal(classified.tiers[0].evidence[0].path, "src/features/auth/controller.ts");
134
+ assert.equal(classified.tiers[0].evidence[0].start_line, 10);
135
+ assert.equal(classified.tiers[0].evidence[0].end_line, 18);
136
+ assert.deepEqual(classified.tiers[0].evidence[0].matched_rules, ["rule.repo_local_pattern_review"]);
137
+ assert.equal(classified.localPatternFound, true);
138
+ assert.equal(classified.fallbackUsed, false);
139
+ });
140
+
141
+ test("reports repository fallback without claiming a local pattern", () => {
142
+ const classified = classifyPatternEvidence({
143
+ target: {
144
+ input: "src/isolated.ts",
145
+ entity_id: "file:src/isolated.ts",
146
+ entity_type: "File",
147
+ path: "src/isolated.ts",
148
+ },
149
+ results: [
150
+ {
151
+ id: "file:docs/general-practices.md",
152
+ entity_type: "File",
153
+ kind: "DOC",
154
+ title: "docs/general-practices.md",
155
+ path: "docs/general-practices.md",
156
+ excerpt: "general fallback only",
157
+ },
158
+ ],
159
+ chunks: [],
160
+ topK: 3,
161
+ });
162
+
163
+ assert.equal(classified.localPatternFound, false);
164
+ assert.equal(classified.fallbackUsed, true);
165
+ assert.deepEqual(classified.tiers.slice(0, 3).flatMap((tier) => tier.evidence), []);
166
+ assert.equal(classified.tiers[3].evidence.length, 1);
167
+ });
168
+
169
+ test("filters chunk evidence when indexed line bounds are missing or invalid", () => {
170
+ const target = {
171
+ input: "src/a.ts",
172
+ entity_id: "file:src/a.ts",
173
+ entity_type: "File",
174
+ path: "src/a.ts",
175
+ };
176
+ const results = [
177
+ {
178
+ id: "chunk:missing",
179
+ entity_type: "Chunk",
180
+ kind: "function",
181
+ title: "missing",
182
+ path: "src/b.ts",
183
+ excerpt: "missing metadata",
184
+ },
185
+ {
186
+ id: "chunk:invalid",
187
+ entity_type: "Chunk",
188
+ kind: "function",
189
+ title: "invalid",
190
+ path: "src/c.ts",
191
+ excerpt: "invalid metadata",
192
+ },
193
+ ];
194
+
195
+ const classified = classifyPatternEvidence({
196
+ target,
197
+ results,
198
+ chunks: [chunk("chunk:invalid", "file:src/c.ts", 0, 0)],
199
+ topK: 3,
200
+ });
201
+
202
+ assert.deepEqual(classified.tiers.flatMap((tier) => tier.evidence), []);
203
+ assert.equal(classified.localPatternFound, false);
204
+ assert.equal(classified.fallbackUsed, false);
205
+ });
206
+
207
+ test("retrieves each locality tier before cutoff and stays deterministic", async () => {
208
+ const target = document("file:src/auth/handler.ts", "src/auth/handler.ts", "CODE");
209
+ const localFile = document("file:src/auth/config.ts", "src/auth/config.ts", "CODE");
210
+ const localChunk = {
211
+ ...chunk("chunk:local-config", localFile.id, 7, 14),
212
+ name: "parseLocalSetting",
213
+ body: "environment",
214
+ description: "module-local environment parsing",
215
+ };
216
+ const repoDocuments = Array.from({ length: 60 }, (_, index) =>
217
+ document(
218
+ `file:docs/pattern-${index}.md`,
219
+ `docs/pattern-${index}.md`,
220
+ "DOC",
221
+ "environment variable parsing configuration pattern",
222
+ ));
223
+ const data = contextData({ documents: [target, localFile, ...repoDocuments], chunks: [localChunk] });
224
+ const input = {
225
+ target: target.path,
226
+ query: "environment variable parsing configuration pattern",
227
+ top_k: 2,
228
+ include_deprecated: false,
229
+ };
230
+
231
+ const first = await runPatternEvidence(input, { data });
232
+ const second = await runPatternEvidence(input, { data });
233
+ const moduleTier = first.tiers.find((tier) => tier.name === "same_module");
234
+
235
+ assert.ok(moduleTier.evidence.some((evidence) => evidence.id === localChunk.id));
236
+ assert.equal(first.local_pattern_found, true);
237
+ assert.equal(first.ranking_reference_time, "2026-07-12T00:00:00.000Z");
238
+ assert.deepEqual(second, first);
239
+ });
240
+
241
+ test("runtime response exposes repository-only fallback and warning", async () => {
242
+ const target = document("file:src/isolated.ts", "src/isolated.ts", "CODE");
243
+ const fallback = document(
244
+ "file:docs/general-practices.md",
245
+ "docs/general-practices.md",
246
+ "DOC",
247
+ "general retry convention",
248
+ );
249
+ const result = await runPatternEvidence({
250
+ target: target.path,
251
+ query: "general retry convention",
252
+ top_k: 2,
253
+ include_deprecated: false,
254
+ }, {
255
+ data: contextData({ documents: [target, fallback] }),
256
+ });
257
+
258
+ assert.equal(result.local_pattern_found, false);
259
+ assert.equal(result.fallback_used, true);
260
+ assert.match(result.warning, /No applicable file-local, module-local, or feature-local pattern/);
261
+ assert.equal(result.tiers[3].evidence[0].id, fallback.id);
262
+ });
263
+
264
+ test("reference time calculation stays bounded for large indexes", () => {
265
+ const documents = Array.from({ length: 200_000 }, (_, index) => ({
266
+ updated_at: index === 199_999 ? "2026-07-13T00:00:00.000Z" : "2026-07-12T00:00:00.000Z",
267
+ }));
268
+ const data = contextData({ documents });
269
+
270
+ assert.equal(contextReferenceTimeMs(data), Date.parse("2026-07-13T00:00:00.000Z"));
271
+ });
272
+
273
+ test("equal-score evidence is stable across reversed source order", async () => {
274
+ const target = document("file:src/isolated.ts", "src/isolated.ts", "CODE");
275
+ const a = document("file:docs/a.md", "docs/a.md", "DOC", "shared convention");
276
+ const b = document("file:docs/b.md", "docs/b.md", "DOC", "shared convention");
277
+ const input = {
278
+ target: target.path,
279
+ query: "shared convention",
280
+ top_k: 1,
281
+ include_deprecated: false,
282
+ };
283
+
284
+ const forward = await runPatternEvidence(input, {
285
+ data: contextData({ documents: [target, a, b] }),
286
+ });
287
+ const reversed = await runPatternEvidence(input, {
288
+ data: contextData({ documents: [target, b, a] }),
289
+ });
290
+
291
+ assert.deepEqual(reversed, forward);
292
+ assert.equal(forward.tiers[3].evidence[0].id, a.id);
293
+ });
294
+
295
+ test("local-only pattern evidence uses lexical search without network fetch", async () => {
296
+ const target = document("file:src/a.ts", "src/a.ts", "CODE");
297
+ const fallback = document("file:docs/pattern.md", "docs/pattern.md", "DOC", "shared retry convention");
298
+ const originalFetch = globalThis.fetch;
299
+ let fetchCalls = 0;
300
+ globalThis.fetch = async () => {
301
+ fetchCalls += 1;
302
+ throw new Error("network access is forbidden in local review");
303
+ };
304
+
305
+ try {
306
+ const result = await runLocalPatternEvidence({
307
+ target: target.path,
308
+ query: "shared retry convention",
309
+ top_k: 1,
310
+ include_deprecated: false,
311
+ }, {
312
+ data: contextData({ documents: [target, fallback] }),
313
+ });
314
+
315
+ assert.equal(fetchCalls, 0);
316
+ assert.equal(result.semantic_engine, "lexical-only");
317
+ assert.equal(result.fallback_used, true);
318
+ } finally {
319
+ globalThis.fetch = originalFetch;
320
+ }
321
+ });