@unerr-ai/unerr 0.1.5 → 0.1.7
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/README.md +70 -194
- package/dist/cli.js +39151 -36992
- package/package.json +9 -2
- package/dist/__tests__/architecture-guard.test.js +0 -122
- package/dist/__tests__/arg-validator.test.js +0 -205
- package/dist/__tests__/ast-extractor.test.js +0 -203
- package/dist/__tests__/auto-bootstrap.test.js +0 -280
- package/dist/__tests__/background-indexer.test.js +0 -228
- package/dist/__tests__/blast-radius-engine.test.js +0 -200
- package/dist/__tests__/bridge-isolation.test.js +0 -37
- package/dist/__tests__/budget-enforcer.test.js +0 -53
- package/dist/__tests__/cfg-test-detection-perf.test.js +0 -82
- package/dist/__tests__/change-narrative.test.js +0 -190
- package/dist/__tests__/check-commit.test.js +0 -258
- package/dist/__tests__/checksum.test.js +0 -34
- package/dist/__tests__/commit-watcher.test.js +0 -154
- package/dist/__tests__/community-detection.test.js +0 -179
- package/dist/__tests__/community-tools.test.js +0 -299
- package/dist/__tests__/components.test.js +0 -449
- package/dist/__tests__/compression-log.test.js +0 -174
- package/dist/__tests__/compression-quality-monitor.test.js +0 -40
- package/dist/__tests__/config-healer.test.js +0 -165
- package/dist/__tests__/context-ledger.test.js +0 -58
- package/dist/__tests__/convention-detector.test.js +0 -99
- package/dist/__tests__/convention-learner.test.js +0 -86
- package/dist/__tests__/correction-detector.test.js +0 -330
- package/dist/__tests__/daemon-autostart-install.test.js +0 -283
- package/dist/__tests__/daemon-bridge.test.js +0 -222
- package/dist/__tests__/daemon-dashboard.test.js +0 -202
- package/dist/__tests__/daemon-registry.test.js +0 -240
- package/dist/__tests__/daemon-supervisor.test.js +0 -318
- package/dist/__tests__/daemon-version-check.test.js +0 -275
- package/dist/__tests__/decision-point-detector.test.js +0 -98
- package/dist/__tests__/deep-link.test.js +0 -143
- package/dist/__tests__/disallowed-tools.test.js +0 -115
- package/dist/__tests__/drift-tracker.test.js +0 -582
- package/dist/__tests__/durability-scorer.test.js +0 -152
- package/dist/__tests__/efficiency-tracker.test.js +0 -65
- package/dist/__tests__/enrich.test.js +0 -144
- package/dist/__tests__/entity-rewind.test.js +0 -248
- package/dist/__tests__/ephemeral.test.js +0 -111
- package/dist/__tests__/exploration-cost.test.js +0 -93
- package/dist/__tests__/fact-generator.test.js +0 -197
- package/dist/__tests__/file-l0-graph.test.js +0 -244
- package/dist/__tests__/file-logger.test.js +0 -82
- package/dist/__tests__/file-outline.test.js +0 -141
- package/dist/__tests__/file-read-protocol.test.js +0 -188
- package/dist/__tests__/format-encoder.test.js +0 -233
- package/dist/__tests__/git-attribution.test.js +0 -259
- package/dist/__tests__/graph-temporal-joiner.test.js +0 -219
- package/dist/__tests__/health-grade-enhanced.test.js +0 -138
- package/dist/__tests__/health-map-data.test.js +0 -173
- package/dist/__tests__/helpers/mcp-harness.js +0 -45
- package/dist/__tests__/helpers/mcp-harness.test.js +0 -68
- package/dist/__tests__/hook-dedup.test.js +0 -112
- package/dist/__tests__/hook-runner.test.js +0 -253
- package/dist/__tests__/indexer-cfg.test.js +0 -185
- package/dist/__tests__/indexer-cross-file.test.js +0 -172
- package/dist/__tests__/indexer-extraction.test.js +0 -245
- package/dist/__tests__/indexer-incremental.test.js +0 -232
- package/dist/__tests__/indexer-language-expansion.test.js +0 -165
- package/dist/__tests__/init-push.test.js +0 -131
- package/dist/__tests__/instruction-writer.test.js +0 -179
- package/dist/__tests__/intelligence-integration.test.js +0 -217
- package/dist/__tests__/intent-correlator.test.js +0 -175
- package/dist/__tests__/intent-detector.test.js +0 -235
- package/dist/__tests__/intent-encoder.test.js +0 -167
- package/dist/__tests__/java-build-tool-detection.test.js +0 -174
- package/dist/__tests__/layer3-sprint-q.test.js +0 -160
- package/dist/__tests__/layer3-sprint-r.test.js +0 -91
- package/dist/__tests__/layer3-sprint-s.test.js +0 -183
- package/dist/__tests__/layer3-sprint-t.test.js +0 -201
- package/dist/__tests__/layer3-sprint-u.test.js +0 -174
- package/dist/__tests__/layer4-sprint-ba2.test.js +0 -354
- package/dist/__tests__/layer4-sprint-ba4.test.js +0 -84
- package/dist/__tests__/layer4-sprint-vs.test.js +0 -105
- package/dist/__tests__/ledger-chains.test.js +0 -162
- package/dist/__tests__/lifecycle-machine.test.js +0 -226
- package/dist/__tests__/local-chat-provider.test.js +0 -170
- package/dist/__tests__/local-convention-detector.test.js +0 -308
- package/dist/__tests__/local-embeddings.test.js +0 -422
- package/dist/__tests__/local-graph.test.js +0 -540
- package/dist/__tests__/local-indexer.test.js +0 -228
- package/dist/__tests__/local-intelligence-l3.test.js +0 -332
- package/dist/__tests__/local-llm.test.js +0 -253
- package/dist/__tests__/local-mode-offline.test.js +0 -187
- package/dist/__tests__/local-mode-stats.test.js +0 -273
- package/dist/__tests__/local-mode-tui.test.js +0 -343
- package/dist/__tests__/local-parse.test.js +0 -199
- package/dist/__tests__/log-tailer.test.js +0 -208
- package/dist/__tests__/loop-breaker.test.js +0 -276
- package/dist/__tests__/loop-miner.test.js +0 -226
- package/dist/__tests__/mcp-config.test.js +0 -126
- package/dist/__tests__/mcp-content-json.test.js +0 -10
- package/dist/__tests__/mcp-envelope.test.js +0 -124
- package/dist/__tests__/metrics-store.test.js +0 -223
- package/dist/__tests__/native-watcher.test.js +0 -191
- package/dist/__tests__/navigation-hooks-agent-aware.test.js +0 -145
- package/dist/__tests__/negative-knowledge.test.js +0 -116
- package/dist/__tests__/network-boundary.test.js +0 -190
- package/dist/__tests__/network-firewall.test.js +0 -112
- package/dist/__tests__/nudge-invariants.test.js +0 -160
- package/dist/__tests__/nudge-v2.test.js +0 -225
- package/dist/__tests__/offline-rewind.test.js +0 -251
- package/dist/__tests__/open-threads.test.js +0 -89
- package/dist/__tests__/output-compressor.test.js +0 -93
- package/dist/__tests__/pending-violations.test.js +0 -112
- package/dist/__tests__/persistence-effectiveness.test.js +0 -143
- package/dist/__tests__/provider-factory.test.js +0 -42
- package/dist/__tests__/providers.test.js +0 -24
- package/dist/__tests__/proxy.test.js +0 -314
- package/dist/__tests__/query-router.test.js +0 -1018
- package/dist/__tests__/reasoning-quality-route.test.js +0 -138
- package/dist/__tests__/redactor.test.js +0 -120
- package/dist/__tests__/resource-monitor.test.js +0 -57
- package/dist/__tests__/response-envelope.test.js +0 -100
- package/dist/__tests__/risk-classifier.test.js +0 -101
- package/dist/__tests__/risk-signal-scope.test.js +0 -75
- package/dist/__tests__/rule-evaluator.test.js +0 -280
- package/dist/__tests__/scip-decoder.test.js +0 -49
- package/dist/__tests__/scip-downloader.test.js +0 -201
- package/dist/__tests__/scip-merger.test.js +0 -103
- package/dist/__tests__/search-index.test.js +0 -422
- package/dist/__tests__/semantic-enrichment.test.js +0 -360
- package/dist/__tests__/session-brief-builder.test.js +0 -187
- package/dist/__tests__/session-context.test.js +0 -221
- package/dist/__tests__/session-continuity.test.js +0 -144
- package/dist/__tests__/session-dedup.test.js +0 -74
- package/dist/__tests__/session-event-wiring.test.js +0 -206
- package/dist/__tests__/session-events.test.js +0 -149
- package/dist/__tests__/session-legend.test.js +0 -20
- package/dist/__tests__/session-persistence.test.js +0 -131
- package/dist/__tests__/session-resume-block.test.js +0 -107
- package/dist/__tests__/session-resume.test.js +0 -97
- package/dist/__tests__/session-summary-writer.test.js +0 -134
- package/dist/__tests__/shadow-ledger.test.js +0 -203
- package/dist/__tests__/shell-classifier.test.js +0 -151
- package/dist/__tests__/shell-compression-floor.test.js +0 -189
- package/dist/__tests__/shell-compression-v2.test.js +0 -339
- package/dist/__tests__/shell-compressor.test.js +0 -35
- package/dist/__tests__/shell-hooks.test.js +0 -128
- package/dist/__tests__/shell-strategies.test.js +0 -644
- package/dist/__tests__/shell-tee.test.js +0 -133
- package/dist/__tests__/signal-dedup.test.js +0 -158
- package/dist/__tests__/signal-reinforcer.test.js +0 -77
- package/dist/__tests__/signal-scorer.test.js +0 -251
- package/dist/__tests__/signal-show-store.test.js +0 -108
- package/dist/__tests__/smart-truncate.test.js +0 -215
- package/dist/__tests__/snapshot-v2.test.js +0 -113
- package/dist/__tests__/sprint-l1-local-mode.test.js +0 -130
- package/dist/__tests__/sprint-l10-boot.test.js +0 -220
- package/dist/__tests__/sprint-l9-offline-commands.test.js +0 -189
- package/dist/__tests__/sprint-q-persistent-context.test.js +0 -198
- package/dist/__tests__/sprint-s1-wiring.test.js +0 -215
- package/dist/__tests__/sprint-s2-wiring.test.js +0 -256
- package/dist/__tests__/sprint-s3-wiring.test.js +0 -195
- package/dist/__tests__/sprint-s4-wiring.test.js +0 -213
- package/dist/__tests__/sprint-s6-hooks.test.js +0 -222
- package/dist/__tests__/sprint-s7-persistent.test.js +0 -263
- package/dist/__tests__/sprint-s8-value.test.js +0 -167
- package/dist/__tests__/sprint-s9-behavioral.test.js +0 -179
- package/dist/__tests__/sprint3-intelligence.test.js +0 -297
- package/dist/__tests__/sprint5-mcp-server.test.js +0 -136
- package/dist/__tests__/startup-display.test.js +0 -302
- package/dist/__tests__/startup-log-file.test.js +0 -97
- package/dist/__tests__/stash-manager.test.js +0 -229
- package/dist/__tests__/state-detector.test.js +0 -92
- package/dist/__tests__/status-dashboard.test.js +0 -142
- package/dist/__tests__/temporal-facts.test.js +0 -292
- package/dist/__tests__/temporal-routes.test.js +0 -142
- package/dist/__tests__/test-detector.test.js +0 -174
- package/dist/__tests__/theme.test.js +0 -72
- package/dist/__tests__/timeline-agents.test.js +0 -122
- package/dist/__tests__/timeline-bootstrap.test.js +0 -176
- package/dist/__tests__/timeline-filters.test.js +0 -193
- package/dist/__tests__/timeline-markers.test.js +0 -151
- package/dist/__tests__/timeline-routes.test.js +0 -156
- package/dist/__tests__/timeline-store.test.js +0 -171
- package/dist/__tests__/token-counter.test.js +0 -86
- package/dist/__tests__/token-estimator.test.js +0 -96
- package/dist/__tests__/token-flow-api.test.js +0 -239
- package/dist/__tests__/token-flow-instrumentation.test.js +0 -437
- package/dist/__tests__/token-flow-persistence.test.js +0 -356
- package/dist/__tests__/token-flow-routes.test.js +0 -199
- package/dist/__tests__/token-flow.test.js +0 -695
- package/dist/__tests__/tool-clusters.test.js +0 -177
- package/dist/__tests__/transport-mux.test.js +0 -283
- package/dist/__tests__/turn-segmenter.test.js +0 -166
- package/dist/__tests__/uninstall.test.js +0 -141
- package/dist/__tests__/warm-start-policy.test.js +0 -271
- package/dist/__tests__/wire-cap-nudge.test.js +0 -77
- package/dist/__tests__/worker-pool.test.js +0 -101
- package/dist/ui/assets/index-7gl3mIuY.css +0 -1
- package/dist/ui/assets/index-BsMTQdhX.js +0 -10
- package/dist/ui/assets/rolldown-runtime-S-ySWqyJ.js +0 -1
- package/dist/ui/assets/vis-network-NIJHUFI3.js +0 -908
- package/dist/ui/fonts/jetbrains-mono-latin-400-normal.woff +0 -0
- package/dist/ui/icon-wordmark.png +0 -0
- package/dist/ui/icon-wordmark.svg +0 -30
- package/dist/ui/icon.png +0 -0
- package/dist/ui/icon.svg +0 -25
- package/dist/ui/index.html +0 -15
- package/dist/ui/prototype-sandbox/index.html +0 -257
- package/dist/ui/screenshots/activity.png +0 -0
- package/dist/ui/screenshots/code-base-intelligence.png +0 -0
- package/dist/ui/screenshots/dashboard.png +0 -0
- package/dist/ui/screenshots/project-memory.png +0 -0
- package/dist/ui/screenshots/reasoning-quality.png +0 -0
- package/dist/ui/screenshots/reasoning-session.png +0 -0
- package/dist/ui/screenshots/token-session.png +0 -0
- package/dist/ui/screenshots/token-trace-main.png +0 -0
- package/dist/ui/screenshots/token-turn.png +0 -0
- package/dist/ui/unerr-wordmark.png +0 -0
- package/dist/ui/unerr-wordmark.svg +0 -9
- package/dist/ui/unerr.png +0 -0
- package/dist/ui/unerr.svg +0 -25
- package/dist/ui/web-app-manifest-192x192.png +0 -0
- package/dist/ui/web-app-manifest-512x512.png +0 -0
|
@@ -1,1018 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Phase 10b TEST-07 + Sprint 3 TEST-05: Query router + drift overlay tests.
|
|
3
|
-
*/
|
|
4
|
-
import { describe, expect, it, vi } from "vitest";
|
|
5
|
-
import { QueryRouter, orderContextFields, } from "../intelligence/query-router.js";
|
|
6
|
-
/** Helper: find a signal by content substring in _context.signals */
|
|
7
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
8
|
-
function findSignal(result, contentSubstr) {
|
|
9
|
-
const signals = result._context?.signals;
|
|
10
|
-
if (!signals)
|
|
11
|
-
return undefined;
|
|
12
|
-
return signals.find((s) => s.content.includes(contentSubstr));
|
|
13
|
-
}
|
|
14
|
-
/** Helper: check if any signal contains the substring */
|
|
15
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16
|
-
function hasSignalContaining(result, contentSubstr) {
|
|
17
|
-
return findSignal(result, contentSubstr) !== undefined;
|
|
18
|
-
}
|
|
19
|
-
function createMockLocalGraph(opts = {}) {
|
|
20
|
-
const { hasRules = true, hasJustifications = false, driftEntities = [], } = opts;
|
|
21
|
-
const driftMap = new Map();
|
|
22
|
-
for (const d of driftEntities)
|
|
23
|
-
driftMap.set(d.key, d);
|
|
24
|
-
// Build a mock db for direct drift_overlay queries
|
|
25
|
-
const mockDb = {
|
|
26
|
-
run: vi.fn(async (query, params) => {
|
|
27
|
-
if (query.includes("drift_overlay") && params?.key) {
|
|
28
|
-
const d = driftMap.get(params.key);
|
|
29
|
-
if (d) {
|
|
30
|
-
return {
|
|
31
|
-
rows: [
|
|
32
|
-
[
|
|
33
|
-
d.key,
|
|
34
|
-
d.name,
|
|
35
|
-
d.kind,
|
|
36
|
-
d.signature,
|
|
37
|
-
d.body,
|
|
38
|
-
d.file_path,
|
|
39
|
-
d.line_start,
|
|
40
|
-
d.line_end,
|
|
41
|
-
d.content_hash,
|
|
42
|
-
d.drift_status,
|
|
43
|
-
d.intent_id,
|
|
44
|
-
d.modified_at,
|
|
45
|
-
d.origin ?? "human",
|
|
46
|
-
d.previous_body ?? "",
|
|
47
|
-
d.previous_signature ?? "",
|
|
48
|
-
],
|
|
49
|
-
],
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
return { rows: [] };
|
|
53
|
-
}
|
|
54
|
-
// Default: count query for drift summary
|
|
55
|
-
if (query.includes("drift_overlay") && query.includes("count")) {
|
|
56
|
-
return { rows: [] };
|
|
57
|
-
}
|
|
58
|
-
return { rows: [] };
|
|
59
|
-
}),
|
|
60
|
-
};
|
|
61
|
-
return {
|
|
62
|
-
db: mockDb,
|
|
63
|
-
getEntity: vi.fn().mockReturnValue({
|
|
64
|
-
key: "fn1",
|
|
65
|
-
kind: "function",
|
|
66
|
-
name: "doStuff",
|
|
67
|
-
file_path: "src/index.ts",
|
|
68
|
-
start_line: 10,
|
|
69
|
-
signature: "()",
|
|
70
|
-
body: "function doStuff() {}",
|
|
71
|
-
fan_in: 0,
|
|
72
|
-
fan_out: 0,
|
|
73
|
-
risk_level: "normal",
|
|
74
|
-
}),
|
|
75
|
-
getCallersOf: vi.fn().mockReturnValue([]),
|
|
76
|
-
getCalleesOf: vi.fn().mockReturnValue([]),
|
|
77
|
-
getEntitiesByFile: vi.fn().mockReturnValue([]),
|
|
78
|
-
searchEntities: vi.fn().mockReturnValue([]),
|
|
79
|
-
getImports: vi.fn().mockReturnValue([]),
|
|
80
|
-
healthCheck: vi.fn().mockReturnValue({ status: "up", latencyMs: 0 }),
|
|
81
|
-
isLoaded: vi.fn().mockReturnValue(true),
|
|
82
|
-
loadSnapshot: vi.fn(),
|
|
83
|
-
hasRules: vi.fn().mockReturnValue(hasRules),
|
|
84
|
-
getRules: vi.fn().mockReturnValue([
|
|
85
|
-
{
|
|
86
|
-
key: "r1",
|
|
87
|
-
name: "Test",
|
|
88
|
-
scope: "repo",
|
|
89
|
-
severity: "warn",
|
|
90
|
-
engine: "naming",
|
|
91
|
-
query: "^_",
|
|
92
|
-
message: "No underscore",
|
|
93
|
-
file_glob: "",
|
|
94
|
-
enabled: true,
|
|
95
|
-
repo_id: "repo-1",
|
|
96
|
-
},
|
|
97
|
-
]),
|
|
98
|
-
getPatterns: vi.fn().mockReturnValue([
|
|
99
|
-
{
|
|
100
|
-
key: "p1",
|
|
101
|
-
name: "Error handler",
|
|
102
|
-
kind: "error-handling",
|
|
103
|
-
frequency: 5,
|
|
104
|
-
confidence: 0.8,
|
|
105
|
-
exemplar_keys: [],
|
|
106
|
-
promoted_rule_key: "",
|
|
107
|
-
},
|
|
108
|
-
]),
|
|
109
|
-
loadRules: vi.fn(),
|
|
110
|
-
loadPatterns: vi.fn(),
|
|
111
|
-
hasJustifications: vi.fn().mockReturnValue(hasJustifications),
|
|
112
|
-
getBusinessContext: vi.fn().mockReturnValue(hasJustifications
|
|
113
|
-
? {
|
|
114
|
-
purpose: "Handles payments",
|
|
115
|
-
role: "logic",
|
|
116
|
-
feature_area: "billing",
|
|
117
|
-
confidence: 0.9,
|
|
118
|
-
entity: null,
|
|
119
|
-
}
|
|
120
|
-
: null),
|
|
121
|
-
getConventions: vi.fn().mockReturnValue([
|
|
122
|
-
{
|
|
123
|
-
name: "Error handler",
|
|
124
|
-
kind: "error-handling",
|
|
125
|
-
frequency: 5,
|
|
126
|
-
confidence: 0.8,
|
|
127
|
-
adherence_rate: 0.1,
|
|
128
|
-
},
|
|
129
|
-
]),
|
|
130
|
-
loadJustifications: vi.fn(),
|
|
131
|
-
getBlastRadius: vi.fn().mockReturnValue({
|
|
132
|
-
direct_callers: 3,
|
|
133
|
-
direct_callees: 2,
|
|
134
|
-
transitive_count: 8,
|
|
135
|
-
transitive_depth: 2,
|
|
136
|
-
is_chokepoint: false,
|
|
137
|
-
summary: "3 direct callers, 2 direct callees, 8 transitive dependents (depth 2)",
|
|
138
|
-
}),
|
|
139
|
-
getBlastRadiusEntities: vi.fn().mockReturnValue([]),
|
|
140
|
-
getConventionsForEntity: vi.fn().mockReturnValue([
|
|
141
|
-
{
|
|
142
|
-
id: "pattern:p1",
|
|
143
|
-
name: "Error handler",
|
|
144
|
-
adherence_pct: 10,
|
|
145
|
-
rule: "error-handling pattern (5 occurrences, 80% confidence)",
|
|
146
|
-
},
|
|
147
|
-
]),
|
|
148
|
-
getDriftEntitiesForFile: vi.fn().mockReturnValue([]),
|
|
149
|
-
upsertDriftEntity: vi.fn(),
|
|
150
|
-
removeDriftEntity: vi.fn(),
|
|
151
|
-
clearDriftOverlay: vi.fn(),
|
|
152
|
-
getDriftSummary: vi.fn().mockReturnValue({
|
|
153
|
-
added: driftEntities.filter((d) => d.drift_status === "added").length,
|
|
154
|
-
modified: driftEntities.filter((d) => d.drift_status === "modified")
|
|
155
|
-
.length,
|
|
156
|
-
deleted: driftEntities.filter((d) => d.drift_status === "deleted").length,
|
|
157
|
-
dependency_changed: driftEntities.filter((d) => d.drift_status === "dependency_changed").length,
|
|
158
|
-
total: driftEntities.length,
|
|
159
|
-
}),
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
// ── Routing Tests ──────────────────────────────────────────────
|
|
163
|
-
describe("QueryRouter", () => {
|
|
164
|
-
describe("isKnownTool", () => {
|
|
165
|
-
it("recognizes all local tools", () => {
|
|
166
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
167
|
-
expect(router.isKnownTool("get_function")).toBe(true);
|
|
168
|
-
expect(router.isKnownTool("get_class")).toBe(true);
|
|
169
|
-
expect(router.isKnownTool("get_file")).toBe(true);
|
|
170
|
-
expect(router.isKnownTool("get_callers")).toBe(true);
|
|
171
|
-
expect(router.isKnownTool("get_callees")).toBe(true);
|
|
172
|
-
expect(router.isKnownTool("get_imports")).toBe(true);
|
|
173
|
-
expect(router.isKnownTool("search_code")).toBe(true);
|
|
174
|
-
// Disabled: get_rules, check_rules, get_business_context — not wired/no data
|
|
175
|
-
// expect(router.isKnownTool("get_rules")).toBe(true);
|
|
176
|
-
// expect(router.isKnownTool("check_rules")).toBe(true);
|
|
177
|
-
// expect(router.isKnownTool("get_business_context")).toBe(true);
|
|
178
|
-
expect(router.isKnownTool("get_conventions")).toBe(true);
|
|
179
|
-
// Disabled: semantic_search, find_similar — embedding store never wired
|
|
180
|
-
// expect(router.isKnownTool("semantic_search")).toBe(true);
|
|
181
|
-
// expect(router.isKnownTool("find_similar")).toBe(true);
|
|
182
|
-
expect(router.isKnownTool("get_project_stats")).toBe(true);
|
|
183
|
-
});
|
|
184
|
-
it("returns false for unknown tools", () => {
|
|
185
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
186
|
-
expect(router.isKnownTool("unknown_tool")).toBe(false);
|
|
187
|
-
});
|
|
188
|
-
});
|
|
189
|
-
describe("execute", () => {
|
|
190
|
-
it("executes local tools with local source in meta", async () => {
|
|
191
|
-
const localGraph = createMockLocalGraph();
|
|
192
|
-
const router = new QueryRouter(localGraph);
|
|
193
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
194
|
-
expect(result._meta.source).toBe("local");
|
|
195
|
-
expect(localGraph.getEntity).toHaveBeenCalledWith("fn1");
|
|
196
|
-
});
|
|
197
|
-
it("returns error when local fails (no cloud fallback)", async () => {
|
|
198
|
-
const localGraph = createMockLocalGraph();
|
|
199
|
-
localGraph.getEntity.mockImplementation(() => {
|
|
200
|
-
throw new Error("Not found");
|
|
201
|
-
});
|
|
202
|
-
const router = new QueryRouter(localGraph);
|
|
203
|
-
const result = await router.execute("get_function", { key: "missing" });
|
|
204
|
-
expect(result._meta.source).toBe("local");
|
|
205
|
-
expect(result.content).toHaveProperty("error");
|
|
206
|
-
});
|
|
207
|
-
// Disabled: get_rules, check_rules — no rules detected/stored yet, always returns empty.
|
|
208
|
-
// it("executes get_rules locally", async () => { ... });
|
|
209
|
-
// it("executes check_rules locally with evaluator", async () => { ... });
|
|
210
|
-
// it("returns error for check_rules without evaluator", async () => { ... });
|
|
211
|
-
it("returns empty rules when no local rules", async () => {
|
|
212
|
-
const localGraph = createMockLocalGraph({ hasRules: false });
|
|
213
|
-
const router = new QueryRouter(localGraph);
|
|
214
|
-
const result = await router.execute("get_rules", {});
|
|
215
|
-
expect(result._meta.source).toBe("local");
|
|
216
|
-
});
|
|
217
|
-
});
|
|
218
|
-
// ── Sprint 3: Business Context / Conventions Tests ────────────
|
|
219
|
-
// Disabled: get_business_context — not properly wired, produces no useful data.
|
|
220
|
-
// describe("get_business_context", () => {
|
|
221
|
-
// it("resolves locally when justifications exist", async () => { ... });
|
|
222
|
-
// it("returns null content when no justifications", async () => { ... });
|
|
223
|
-
// });
|
|
224
|
-
describe("get_conventions", () => {
|
|
225
|
-
it("resolves locally and returns adherence rates", async () => {
|
|
226
|
-
const localGraph = createMockLocalGraph();
|
|
227
|
-
const router = new QueryRouter(localGraph);
|
|
228
|
-
const result = await router.execute("get_conventions", {});
|
|
229
|
-
expect(result._meta.source).toBe("local");
|
|
230
|
-
expect(localGraph.getConventions).toHaveBeenCalled();
|
|
231
|
-
// Conventions are emitted as `_fmt:multi` (sections by kind) — the
|
|
232
|
-
// format-encoder reuses the "columnar" meta flag for multi-section
|
|
233
|
-
// responses since the legend covers both shapes.
|
|
234
|
-
expect(result._meta.format).toBe("columnar");
|
|
235
|
-
// Response is the encoded `_fmt:multi` string; assert structural markers.
|
|
236
|
-
const text = result.content;
|
|
237
|
-
expect(typeof text).toBe("string");
|
|
238
|
-
expect(text.startsWith("_fmt:multi")).toBe(true);
|
|
239
|
-
expect(text).toContain("@meta");
|
|
240
|
-
expect(text).toMatch(/@(naming|import_direction|structure|guidance)\[/);
|
|
241
|
-
expect(text).toContain("summary=");
|
|
242
|
-
});
|
|
243
|
-
});
|
|
244
|
-
// ── Sprint 3: Drift Overlay Tests (P10-TEST-05) ───────────────
|
|
245
|
-
describe("drift overlay merge", () => {
|
|
246
|
-
it("base entity only (no overlay) — no _meta.drift", async () => {
|
|
247
|
-
const localGraph = createMockLocalGraph();
|
|
248
|
-
const router = new QueryRouter(localGraph);
|
|
249
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
250
|
-
expect(result._meta.source).toBe("local");
|
|
251
|
-
expect(result._meta.drift).toBeUndefined();
|
|
252
|
-
});
|
|
253
|
-
it("modified entity — overlay body replaces base body, _meta.drift present", async () => {
|
|
254
|
-
const driftEntities = [
|
|
255
|
-
{
|
|
256
|
-
key: "fn1",
|
|
257
|
-
name: "doStuff",
|
|
258
|
-
kind: "function",
|
|
259
|
-
signature: "()",
|
|
260
|
-
body: "function doStuff() { return 'modified' }",
|
|
261
|
-
file_path: "src/index.ts",
|
|
262
|
-
line_start: 10,
|
|
263
|
-
line_end: 12,
|
|
264
|
-
content_hash: "abc123",
|
|
265
|
-
drift_status: "modified",
|
|
266
|
-
intent_id: "intent_001",
|
|
267
|
-
modified_at: "2026-03-09T10:00:00Z",
|
|
268
|
-
origin: "human",
|
|
269
|
-
previous_body: "",
|
|
270
|
-
previous_signature: "",
|
|
271
|
-
},
|
|
272
|
-
];
|
|
273
|
-
const localGraph = createMockLocalGraph({ driftEntities });
|
|
274
|
-
const router = new QueryRouter(localGraph);
|
|
275
|
-
router.setBranchContext({
|
|
276
|
-
currentBranch: "feature/auth",
|
|
277
|
-
baseBranch: "main",
|
|
278
|
-
baseCommit: "abc",
|
|
279
|
-
commitsAhead: 3,
|
|
280
|
-
commitsBehind: 0,
|
|
281
|
-
headSha: "def",
|
|
282
|
-
computedAt: "2026-03-09",
|
|
283
|
-
});
|
|
284
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
285
|
-
expect(result._meta.source).toBe("local");
|
|
286
|
-
expect(result._meta.drift).toBeDefined();
|
|
287
|
-
expect(result._meta.drift?.entityStatus).toBe("modified");
|
|
288
|
-
expect(result._meta.drift?.branch).toBe("feature/auth");
|
|
289
|
-
expect(result._meta.drift?.commitsAhead).toBe(3);
|
|
290
|
-
expect(result._meta.drift?.lastModifiedBy).toBe("intent_001");
|
|
291
|
-
// Body should be replaced with overlay body
|
|
292
|
-
const content = result.content;
|
|
293
|
-
expect(content.body).toContain("modified");
|
|
294
|
-
});
|
|
295
|
-
it("added entity — included in results with drift status", async () => {
|
|
296
|
-
const driftEntities = [
|
|
297
|
-
{
|
|
298
|
-
key: "fn_new",
|
|
299
|
-
name: "newFeature",
|
|
300
|
-
kind: "function",
|
|
301
|
-
signature: "(x: number)",
|
|
302
|
-
body: "function newFeature(x: number) { return x }",
|
|
303
|
-
file_path: "src/new.ts",
|
|
304
|
-
line_start: 1,
|
|
305
|
-
line_end: 3,
|
|
306
|
-
content_hash: "xyz789",
|
|
307
|
-
drift_status: "added",
|
|
308
|
-
intent_id: "intent_002",
|
|
309
|
-
modified_at: "2026-03-09T11:00:00Z",
|
|
310
|
-
origin: "ai",
|
|
311
|
-
previous_body: "",
|
|
312
|
-
previous_signature: "",
|
|
313
|
-
},
|
|
314
|
-
];
|
|
315
|
-
const localGraph = createMockLocalGraph({ driftEntities });
|
|
316
|
-
// Mock getEntity to return null for the new entity (not in base)
|
|
317
|
-
localGraph.getEntity.mockReturnValue(null);
|
|
318
|
-
const router = new QueryRouter(localGraph);
|
|
319
|
-
router.setBranchContext({
|
|
320
|
-
currentBranch: "feature/x",
|
|
321
|
-
baseBranch: "main",
|
|
322
|
-
baseCommit: null,
|
|
323
|
-
commitsAhead: 1,
|
|
324
|
-
commitsBehind: null,
|
|
325
|
-
headSha: "abc",
|
|
326
|
-
computedAt: "2026-03-09",
|
|
327
|
-
});
|
|
328
|
-
const result = await router.execute("get_function", { key: "fn_new" });
|
|
329
|
-
expect(result._meta.source).toBe("local");
|
|
330
|
-
expect(result._meta.drift).toBeDefined();
|
|
331
|
-
expect(result._meta.drift?.entityStatus).toBe("added");
|
|
332
|
-
const content = result.content;
|
|
333
|
-
expect(content.name).toBe("newFeature");
|
|
334
|
-
expect(content.kind).toBe("function");
|
|
335
|
-
});
|
|
336
|
-
it("deleted entity — excluded from results, drift annotated", async () => {
|
|
337
|
-
const driftEntities = [
|
|
338
|
-
{
|
|
339
|
-
key: "fn1",
|
|
340
|
-
name: "doStuff",
|
|
341
|
-
kind: "function",
|
|
342
|
-
signature: "()",
|
|
343
|
-
body: "",
|
|
344
|
-
file_path: "src/index.ts",
|
|
345
|
-
line_start: 10,
|
|
346
|
-
line_end: 10,
|
|
347
|
-
content_hash: "",
|
|
348
|
-
drift_status: "deleted",
|
|
349
|
-
intent_id: "intent_003",
|
|
350
|
-
modified_at: "2026-03-09T12:00:00Z",
|
|
351
|
-
origin: "human",
|
|
352
|
-
previous_body: "",
|
|
353
|
-
previous_signature: "",
|
|
354
|
-
},
|
|
355
|
-
];
|
|
356
|
-
const localGraph = createMockLocalGraph({ driftEntities });
|
|
357
|
-
const router = new QueryRouter(localGraph);
|
|
358
|
-
router.setBranchContext({
|
|
359
|
-
currentBranch: "main",
|
|
360
|
-
baseBranch: "main",
|
|
361
|
-
baseCommit: null,
|
|
362
|
-
commitsAhead: 0,
|
|
363
|
-
commitsBehind: null,
|
|
364
|
-
headSha: "abc",
|
|
365
|
-
computedAt: "2026-03-09",
|
|
366
|
-
});
|
|
367
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
368
|
-
// Deleted entity returns null content
|
|
369
|
-
expect(result.content).toBeNull();
|
|
370
|
-
});
|
|
371
|
-
it("local failure returns error with local source", async () => {
|
|
372
|
-
const localGraph = createMockLocalGraph();
|
|
373
|
-
localGraph.getEntity.mockImplementation(() => {
|
|
374
|
-
throw new Error("CozoDB corrupted");
|
|
375
|
-
});
|
|
376
|
-
const router = new QueryRouter(localGraph);
|
|
377
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
378
|
-
expect(result._meta.source).toBe("local");
|
|
379
|
-
expect(result.content).toHaveProperty("error");
|
|
380
|
-
});
|
|
381
|
-
it("no drift overlay — pure CozoDB results (no performance degradation)", async () => {
|
|
382
|
-
const localGraph = createMockLocalGraph();
|
|
383
|
-
const router = new QueryRouter(localGraph);
|
|
384
|
-
const start = Date.now();
|
|
385
|
-
await router.execute("get_function", { key: "fn1" });
|
|
386
|
-
const elapsed = Date.now() - start;
|
|
387
|
-
// Should be well under 100ms for a mock
|
|
388
|
-
expect(elapsed).toBeLessThan(100);
|
|
389
|
-
});
|
|
390
|
-
});
|
|
391
|
-
// ── Task 8.6: Mode-Aware Response Tests ──────────────────────────
|
|
392
|
-
describe("mode-aware responses (8.6)", () => {
|
|
393
|
-
it("local mode includes mode in _meta", async () => {
|
|
394
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
395
|
-
router.setMode("local");
|
|
396
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
397
|
-
expect(result._meta.mode).toBe("local");
|
|
398
|
-
expect(result._meta.tools_degraded).toBeUndefined();
|
|
399
|
-
});
|
|
400
|
-
it("setup mode returns informational response (not an error)", async () => {
|
|
401
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
402
|
-
router.setMode("setup", "Repository not configured");
|
|
403
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
404
|
-
expect(result._meta.mode).toBe("setup");
|
|
405
|
-
expect(result._meta.mode_reason).toBe("Repository not configured");
|
|
406
|
-
expect(result._meta.tools_degraded).toBeDefined();
|
|
407
|
-
expect(result._meta.tools_degraded?.length).toBeGreaterThan(0);
|
|
408
|
-
const content = result.content;
|
|
409
|
-
expect(content.available).toBe(false);
|
|
410
|
-
expect(content.message).toContain("unerr is not yet configured");
|
|
411
|
-
});
|
|
412
|
-
it("setup mode returns informational for all tools", async () => {
|
|
413
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
414
|
-
router.setMode("setup");
|
|
415
|
-
const result = await router.execute("semantic_search", { query: "auth" });
|
|
416
|
-
expect(result._meta.mode).toBe("setup");
|
|
417
|
-
const content = result.content;
|
|
418
|
-
expect(content.tool).toBe("semantic_search");
|
|
419
|
-
expect(content.available).toBe(false);
|
|
420
|
-
});
|
|
421
|
-
it("local mode serves local tools normally", async () => {
|
|
422
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
423
|
-
router.setMode("local", "Cloud unavailable");
|
|
424
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
425
|
-
expect(result._meta.mode).toBe("local");
|
|
426
|
-
expect(result._meta.source).toBe("local");
|
|
427
|
-
expect(result._meta.mode_reason).toBe("Cloud unavailable");
|
|
428
|
-
// Content should be the actual entity, not an error
|
|
429
|
-
expect(result.content.key).toBe("fn1");
|
|
430
|
-
});
|
|
431
|
-
it("local mode has no degraded tools", async () => {
|
|
432
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
433
|
-
router.setMode("local", "Local only");
|
|
434
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
435
|
-
expect(result._meta.mode).toBe("local");
|
|
436
|
-
expect(result._meta.tools_degraded).toBeUndefined();
|
|
437
|
-
});
|
|
438
|
-
it("parse mode degrades get_conventions", async () => {
|
|
439
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
440
|
-
router.setMode("parse", "No repo configured");
|
|
441
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
442
|
-
expect(result._meta.mode).toBe("parse");
|
|
443
|
-
// check_rules and get_business_context removed — disabled tools
|
|
444
|
-
expect(result._meta.tools_degraded).toContain("get_conventions");
|
|
445
|
-
});
|
|
446
|
-
it("parse mode serves local tools", async () => {
|
|
447
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
448
|
-
router.setMode("parse");
|
|
449
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
450
|
-
expect(result._meta.source).toBe("local");
|
|
451
|
-
expect(result._meta.mode).toBe("parse");
|
|
452
|
-
});
|
|
453
|
-
it("local mode returns error on local failure (no cloud fallback)", async () => {
|
|
454
|
-
const localGraph = createMockLocalGraph();
|
|
455
|
-
localGraph.getEntity.mockImplementation(() => {
|
|
456
|
-
throw new Error("CozoDB error");
|
|
457
|
-
});
|
|
458
|
-
const router = new QueryRouter(localGraph);
|
|
459
|
-
router.setMode("local");
|
|
460
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
461
|
-
expect(result._meta.mode).toBe("local");
|
|
462
|
-
expect(result._meta.source).toBe("local");
|
|
463
|
-
expect(result.content).toHaveProperty("error");
|
|
464
|
-
});
|
|
465
|
-
it("getMode returns current mode", () => {
|
|
466
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
467
|
-
expect(router.getMode()).toBe("local");
|
|
468
|
-
router.setMode("parse");
|
|
469
|
-
expect(router.getMode()).toBe("parse");
|
|
470
|
-
});
|
|
471
|
-
it("getDegradedTools lists all tools for setup mode", async () => {
|
|
472
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
473
|
-
router.setMode("setup");
|
|
474
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
475
|
-
// All tools should be degraded in setup mode (17 after disabling get_rules, check_rules, get_business_context, semantic_search, find_similar, unerr_revert_entity, 8 blueprint tools)
|
|
476
|
-
expect(result._meta.tools_degraded?.length).toBe(17);
|
|
477
|
-
});
|
|
478
|
-
});
|
|
479
|
-
// ── Sprint 2: Response Enrichment Tests ──────────────────────────
|
|
480
|
-
describe("Sprint 2: Response Enrichment", () => {
|
|
481
|
-
// ── 2.1: Response Envelope ──────────────────────────────────────
|
|
482
|
-
describe("2.1: Response envelope", () => {
|
|
483
|
-
it("every response includes _meta with source and latency_ms", async () => {
|
|
484
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
485
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
486
|
-
expect(result._meta).toBeDefined();
|
|
487
|
-
expect(result._meta.source).toBeDefined();
|
|
488
|
-
expect(result._meta.latency_ms).toBeGreaterThanOrEqual(0);
|
|
489
|
-
});
|
|
490
|
-
it("_meta includes blast_radius for entity tools", async () => {
|
|
491
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
492
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
493
|
-
expect(result._meta.blast_radius).toBeDefined();
|
|
494
|
-
expect(result._meta.blast_radius?.direct_callers).toBe(3);
|
|
495
|
-
expect(result._meta.blast_radius?.direct_callees).toBe(2);
|
|
496
|
-
expect(result._meta.blast_radius?.transitive_depth2).toBe(8);
|
|
497
|
-
expect(result._meta.blast_radius?.is_chokepoint).toBe(false);
|
|
498
|
-
});
|
|
499
|
-
it("_meta includes conventions for entity tools", async () => {
|
|
500
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
501
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
502
|
-
expect(result._meta.conventions).toBeDefined();
|
|
503
|
-
expect(result._meta.conventions?.length).toBeGreaterThan(0);
|
|
504
|
-
expect(result._meta.conventions?.[0]?.name).toBe("Error handler");
|
|
505
|
-
expect(result._meta.conventions?.[0]?.adherence_pct).toBe(10);
|
|
506
|
-
});
|
|
507
|
-
});
|
|
508
|
-
// ── 2.2: Blast Radius Injection ────────────────────────────────
|
|
509
|
-
describe("2.2: Blast radius injection", () => {
|
|
510
|
-
it("injects blast_radius in _context for first entity query", async () => {
|
|
511
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
512
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
513
|
-
expect(result._context?.signals).toBeDefined();
|
|
514
|
-
expect(findSignal(result, "direct caller")).toBeDefined();
|
|
515
|
-
});
|
|
516
|
-
it("does not inject blast_radius for non-entity tools", async () => {
|
|
517
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
518
|
-
const result = await router.execute("search_code", {
|
|
519
|
-
query: "something",
|
|
520
|
-
});
|
|
521
|
-
expect(result._meta.blast_radius).toBeUndefined();
|
|
522
|
-
});
|
|
523
|
-
it("marks chokepoints when detected", async () => {
|
|
524
|
-
const localGraph = createMockLocalGraph();
|
|
525
|
-
localGraph.getBlastRadius.mockReturnValue({
|
|
526
|
-
direct_callers: 10,
|
|
527
|
-
direct_callees: 8,
|
|
528
|
-
transitive_count: 45,
|
|
529
|
-
transitive_depth: 2,
|
|
530
|
-
is_chokepoint: true,
|
|
531
|
-
summary: "10 direct callers, 8 direct callees, CHOKEPOINT",
|
|
532
|
-
});
|
|
533
|
-
// Also need entity with high fan_in/fan_out
|
|
534
|
-
localGraph.getEntity.mockReturnValue({
|
|
535
|
-
key: "fn1",
|
|
536
|
-
kind: "function",
|
|
537
|
-
name: "doStuff",
|
|
538
|
-
file_path: "src/index.ts",
|
|
539
|
-
start_line: 10,
|
|
540
|
-
signature: "()",
|
|
541
|
-
body: "function doStuff() {}",
|
|
542
|
-
fan_in: 10,
|
|
543
|
-
fan_out: 8,
|
|
544
|
-
risk_level: "high",
|
|
545
|
-
});
|
|
546
|
-
const router = new QueryRouter(localGraph);
|
|
547
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
548
|
-
expect(result._meta.blast_radius?.is_chokepoint).toBe(true);
|
|
549
|
-
expect(hasSignalContaining(result, "CHOKEPOINT")).toBe(true);
|
|
550
|
-
});
|
|
551
|
-
});
|
|
552
|
-
// ── 2.3: Convention Context Injection ──────────────────────────
|
|
553
|
-
describe("2.3: Convention context injection", () => {
|
|
554
|
-
it("injects conventions in _context with adherence rates", async () => {
|
|
555
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
556
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
557
|
-
expect(result._context?.signals).toBeDefined();
|
|
558
|
-
const conventionSignal = findSignal(result, "Error handler");
|
|
559
|
-
expect(conventionSignal).toBeDefined();
|
|
560
|
-
expect(conventionSignal?.type).toBe("guidance");
|
|
561
|
-
});
|
|
562
|
-
it("skips convention injection for non-entity tools", async () => {
|
|
563
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
564
|
-
const result = await router.execute("get_rules", {});
|
|
565
|
-
expect(hasSignalContaining(result, "Error handler")).toBe(false);
|
|
566
|
-
});
|
|
567
|
-
});
|
|
568
|
-
// ── 2.4: Session Deduplication ─────────────────────────────────
|
|
569
|
-
describe("2.4: Session deduplication", () => {
|
|
570
|
-
it("first query includes blast radius, second omits it", async () => {
|
|
571
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
572
|
-
const r1 = await router.execute("get_function", { key: "fn1" });
|
|
573
|
-
expect(findSignal(r1, "direct caller")).toBeDefined();
|
|
574
|
-
expect(r1._meta.blast_radius).toBeDefined();
|
|
575
|
-
const r2 = await router.execute("get_function", { key: "fn1" });
|
|
576
|
-
expect(r2._meta.blast_radius).toBeUndefined();
|
|
577
|
-
});
|
|
578
|
-
it("different entities each get their own blast radius", async () => {
|
|
579
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
580
|
-
const r1 = await router.execute("get_function", { key: "fn1" });
|
|
581
|
-
expect(findSignal(r1, "direct caller")).toBeDefined();
|
|
582
|
-
const r2 = await router.execute("get_function", { key: "fn2" });
|
|
583
|
-
expect(findSignal(r2, "direct caller")).toBeDefined();
|
|
584
|
-
});
|
|
585
|
-
it("conventions are deduped across entities", async () => {
|
|
586
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
587
|
-
const r1 = await router.execute("get_function", { key: "fn1" });
|
|
588
|
-
expect(findSignal(r1, "Error handler")).toBeDefined();
|
|
589
|
-
// Same conventions should be deduped on second entity
|
|
590
|
-
const r2 = await router.execute("get_function", { key: "fn2" });
|
|
591
|
-
expect(r2._meta.conventions).toBeUndefined();
|
|
592
|
-
});
|
|
593
|
-
});
|
|
594
|
-
// ── 2.5: Proactive Drift Alerts ────────────────────────────────
|
|
595
|
-
describe("2.5: Proactive drift alerts", () => {
|
|
596
|
-
it("injects drift_alert when entity is modified", async () => {
|
|
597
|
-
const driftEntities = [
|
|
598
|
-
{
|
|
599
|
-
key: "fn1",
|
|
600
|
-
name: "doStuff",
|
|
601
|
-
kind: "function",
|
|
602
|
-
signature: "()",
|
|
603
|
-
body: "function doStuff() { return 'modified' }",
|
|
604
|
-
file_path: "src/index.ts",
|
|
605
|
-
line_start: 10,
|
|
606
|
-
line_end: 12,
|
|
607
|
-
content_hash: "abc123",
|
|
608
|
-
drift_status: "modified",
|
|
609
|
-
intent_id: "intent_001",
|
|
610
|
-
modified_at: "2026-03-09T10:00:00Z",
|
|
611
|
-
origin: "human",
|
|
612
|
-
previous_body: "",
|
|
613
|
-
previous_signature: "",
|
|
614
|
-
},
|
|
615
|
-
];
|
|
616
|
-
const localGraph = createMockLocalGraph({ driftEntities });
|
|
617
|
-
const router = new QueryRouter(localGraph);
|
|
618
|
-
router.setBranchContext({
|
|
619
|
-
currentBranch: "feature/auth",
|
|
620
|
-
baseBranch: "main",
|
|
621
|
-
baseCommit: "abc",
|
|
622
|
-
commitsAhead: 1,
|
|
623
|
-
commitsBehind: 0,
|
|
624
|
-
headSha: "def",
|
|
625
|
-
computedAt: "2026-03-09",
|
|
626
|
-
});
|
|
627
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
628
|
-
expect(result._context?.signals).toBeDefined();
|
|
629
|
-
const driftSignal = findSignal(result, "modified");
|
|
630
|
-
expect(driftSignal).toBeDefined();
|
|
631
|
-
expect(driftSignal?.type).toBe("warning");
|
|
632
|
-
});
|
|
633
|
-
it("drift alert fires only once per entity per session", async () => {
|
|
634
|
-
const driftEntities = [
|
|
635
|
-
{
|
|
636
|
-
key: "fn1",
|
|
637
|
-
name: "doStuff",
|
|
638
|
-
kind: "function",
|
|
639
|
-
signature: "()",
|
|
640
|
-
body: "modified body",
|
|
641
|
-
file_path: "src/index.ts",
|
|
642
|
-
line_start: 10,
|
|
643
|
-
line_end: 12,
|
|
644
|
-
content_hash: "abc",
|
|
645
|
-
drift_status: "modified",
|
|
646
|
-
intent_id: "i1",
|
|
647
|
-
modified_at: "2026-03-09T10:00:00Z",
|
|
648
|
-
origin: "mixed",
|
|
649
|
-
previous_body: "",
|
|
650
|
-
previous_signature: "",
|
|
651
|
-
},
|
|
652
|
-
];
|
|
653
|
-
const localGraph = createMockLocalGraph({ driftEntities });
|
|
654
|
-
const router = new QueryRouter(localGraph);
|
|
655
|
-
router.setBranchContext({
|
|
656
|
-
currentBranch: "main",
|
|
657
|
-
baseBranch: "main",
|
|
658
|
-
baseCommit: null,
|
|
659
|
-
commitsAhead: 0,
|
|
660
|
-
commitsBehind: null,
|
|
661
|
-
headSha: "abc",
|
|
662
|
-
computedAt: "2026-03-09",
|
|
663
|
-
});
|
|
664
|
-
const r1 = await router.execute("get_function", { key: "fn1" });
|
|
665
|
-
expect(findSignal(r1, "modified")).toBeDefined();
|
|
666
|
-
const r2 = await router.execute("get_function", { key: "fn1" });
|
|
667
|
-
expect(findSignal(r2, "modified")).toBeUndefined();
|
|
668
|
-
});
|
|
669
|
-
it("no drift_alert when entity has no drift", async () => {
|
|
670
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
671
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
672
|
-
// No drift entities, so no drift warning signal
|
|
673
|
-
expect(findSignal(result, "WARNING")).toBeUndefined();
|
|
674
|
-
});
|
|
675
|
-
});
|
|
676
|
-
// ── 2.6: Session Greeting ──────────────────────────────────────
|
|
677
|
-
// DEPRECATED: `_context.session_greeting` was replaced by the structured
|
|
678
|
-
// `session_brief` (see src/intelligence/session-brief-builder.ts and its
|
|
679
|
-
// dedicated tests in session-brief-builder.test.ts). Keep these as `.skip`
|
|
680
|
-
// so the history is visible without blocking CI.
|
|
681
|
-
describe.skip("2.6: Session greeting (deprecated — see session-brief-builder.test.ts)", () => {
|
|
682
|
-
it("first MCP response includes session_greeting", async () => {
|
|
683
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
684
|
-
router.setHealthInfo("B", { entities: 500, edges: 1200, rules: 10 });
|
|
685
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
686
|
-
expect(result._context?.session_greeting).toBeDefined();
|
|
687
|
-
expect(result._context?.session_greeting).toContain("B");
|
|
688
|
-
});
|
|
689
|
-
it("greeting fires exactly once per session", async () => {
|
|
690
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
691
|
-
router.setHealthInfo("A", { entities: 100, edges: 300, rules: 5 });
|
|
692
|
-
const r1 = await router.execute("get_function", { key: "fn1" });
|
|
693
|
-
expect(r1._context?.session_greeting).toBeDefined();
|
|
694
|
-
const r2 = await router.execute("get_function", { key: "fn2" });
|
|
695
|
-
expect(r2._context?.session_greeting).toBeUndefined();
|
|
696
|
-
});
|
|
697
|
-
it("greeting varies by health grade — A+ is healthy", async () => {
|
|
698
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
699
|
-
router.setHealthInfo("A+", { entities: 200, edges: 400, rules: 8 });
|
|
700
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
701
|
-
expect(result._context?.session_greeting).toContain("healthy");
|
|
702
|
-
});
|
|
703
|
-
it("greeting varies by health grade — C shows concern", async () => {
|
|
704
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
705
|
-
router.setHealthInfo("C", { entities: 800, edges: 200, rules: 3 });
|
|
706
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
707
|
-
expect(result._context?.session_greeting).toContain("C");
|
|
708
|
-
expect(result._context?.session_greeting).toContain("structural issues");
|
|
709
|
-
});
|
|
710
|
-
it("greeting varies by health grade — D/F shows warning", async () => {
|
|
711
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
712
|
-
router.setHealthInfo("D", { entities: 1000, edges: 100, rules: 1 });
|
|
713
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
714
|
-
expect(result._context?.session_greeting).toContain("Warning");
|
|
715
|
-
});
|
|
716
|
-
it("PARSE mode gets lite greeting", async () => {
|
|
717
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
718
|
-
router.setMode("parse");
|
|
719
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
720
|
-
expect(result._context?.session_greeting).toContain("parse mode");
|
|
721
|
-
});
|
|
722
|
-
it("no health info still produces a default greeting", async () => {
|
|
723
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
724
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
725
|
-
expect(result._context?.session_greeting).toContain("proxy ready");
|
|
726
|
-
});
|
|
727
|
-
it("greeting on non-entity tools too", async () => {
|
|
728
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
729
|
-
router.setHealthInfo("B", { entities: 500, edges: 1000, rules: 5 });
|
|
730
|
-
const result = await router.execute("search_code", {
|
|
731
|
-
query: "auth",
|
|
732
|
-
});
|
|
733
|
-
expect(result._context?.session_greeting).toBeDefined();
|
|
734
|
-
});
|
|
735
|
-
});
|
|
736
|
-
// ── 2.7: Value Counter ─────────────────────────────────────────
|
|
737
|
-
describe("2.7: Value counter", () => {
|
|
738
|
-
it("injects value_counter every 3rd caught event after 10 tool calls", async () => {
|
|
739
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
740
|
-
const events = {
|
|
741
|
-
conventionViolationsCaught: 0,
|
|
742
|
-
chokepointWarningsIssued: 0,
|
|
743
|
-
circularDepsDetected: 0,
|
|
744
|
-
signaturePreservations: 0,
|
|
745
|
-
deadCodeReferences: 0,
|
|
746
|
-
aiEntitiesModified: 0,
|
|
747
|
-
humanEntitiesModified: 0,
|
|
748
|
-
mixedEntitiesModified: 0,
|
|
749
|
-
};
|
|
750
|
-
router.setSessionEvents(events);
|
|
751
|
-
// Make 11 tool calls (need >10 for counter to fire)
|
|
752
|
-
for (let i = 0; i < 11; i++) {
|
|
753
|
-
await router.execute("search_code", { query: "x" });
|
|
754
|
-
}
|
|
755
|
-
// Set caught events to 3 (divisible by 3)
|
|
756
|
-
events.conventionViolationsCaught = 3;
|
|
757
|
-
const result = await router.execute("search_code", { query: "y" });
|
|
758
|
-
expect(result._context?.value_counter).toBeDefined();
|
|
759
|
-
expect(result._context?.value_counter).toContain("3 issues");
|
|
760
|
-
});
|
|
761
|
-
it("does not inject value_counter when <=10 tool calls", async () => {
|
|
762
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
763
|
-
const events = {
|
|
764
|
-
conventionViolationsCaught: 3,
|
|
765
|
-
chokepointWarningsIssued: 0,
|
|
766
|
-
circularDepsDetected: 0,
|
|
767
|
-
signaturePreservations: 0,
|
|
768
|
-
deadCodeReferences: 0,
|
|
769
|
-
aiEntitiesModified: 0,
|
|
770
|
-
humanEntitiesModified: 0,
|
|
771
|
-
mixedEntitiesModified: 0,
|
|
772
|
-
};
|
|
773
|
-
router.setSessionEvents(events);
|
|
774
|
-
// Only 5 calls — not enough
|
|
775
|
-
for (let i = 0; i < 5; i++) {
|
|
776
|
-
await router.execute("search_code", { query: "x" });
|
|
777
|
-
}
|
|
778
|
-
const result = await router.execute("search_code", { query: "y" });
|
|
779
|
-
expect(result._context?.value_counter).toBeUndefined();
|
|
780
|
-
});
|
|
781
|
-
it("does not inject when caught events not divisible by 3", async () => {
|
|
782
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
783
|
-
const events = {
|
|
784
|
-
conventionViolationsCaught: 2,
|
|
785
|
-
chokepointWarningsIssued: 0,
|
|
786
|
-
circularDepsDetected: 0,
|
|
787
|
-
signaturePreservations: 0,
|
|
788
|
-
deadCodeReferences: 0,
|
|
789
|
-
aiEntitiesModified: 0,
|
|
790
|
-
humanEntitiesModified: 0,
|
|
791
|
-
mixedEntitiesModified: 0,
|
|
792
|
-
};
|
|
793
|
-
router.setSessionEvents(events);
|
|
794
|
-
for (let i = 0; i < 12; i++) {
|
|
795
|
-
await router.execute("search_code", { query: "x" });
|
|
796
|
-
}
|
|
797
|
-
const result = await router.execute("search_code", { query: "y" });
|
|
798
|
-
expect(result._context?.value_counter).toBeUndefined();
|
|
799
|
-
});
|
|
800
|
-
it("counter fires only once per threshold crossing", async () => {
|
|
801
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
802
|
-
const events = {
|
|
803
|
-
conventionViolationsCaught: 0,
|
|
804
|
-
chokepointWarningsIssued: 0,
|
|
805
|
-
circularDepsDetected: 0,
|
|
806
|
-
signaturePreservations: 0,
|
|
807
|
-
deadCodeReferences: 0,
|
|
808
|
-
aiEntitiesModified: 0,
|
|
809
|
-
humanEntitiesModified: 0,
|
|
810
|
-
mixedEntitiesModified: 0,
|
|
811
|
-
};
|
|
812
|
-
router.setSessionEvents(events);
|
|
813
|
-
// 11 calls
|
|
814
|
-
for (let i = 0; i < 11; i++) {
|
|
815
|
-
await router.execute("search_code", { query: "x" });
|
|
816
|
-
}
|
|
817
|
-
events.conventionViolationsCaught = 3;
|
|
818
|
-
const r1 = await router.execute("search_code", { query: "a" });
|
|
819
|
-
expect(r1._context?.value_counter).toBeDefined();
|
|
820
|
-
// Same count — should not fire again
|
|
821
|
-
const r2 = await router.execute("search_code", { query: "b" });
|
|
822
|
-
expect(r2._context?.value_counter).toBeUndefined();
|
|
823
|
-
// Advance to 6
|
|
824
|
-
events.conventionViolationsCaught = 6;
|
|
825
|
-
const r3 = await router.execute("search_code", { query: "c" });
|
|
826
|
-
expect(r3._context?.value_counter).toBeDefined();
|
|
827
|
-
expect(r3._context?.value_counter).toContain("6 issues");
|
|
828
|
-
});
|
|
829
|
-
});
|
|
830
|
-
// ── Task 7.8: Post-compaction context recovery ─────────────────
|
|
831
|
-
// DEPRECATED: `_context.reminder = "Previously queried: ..."` was removed
|
|
832
|
-
// (query-router.ts:1618 comment: "redundant noise — showed up twice as
|
|
833
|
-
// ur|ctx + ur|fct"). Re-query of seen entities is now signaled via
|
|
834
|
-
// `_meta.context_complete = true` + the `ur|ctx already delivered` prefix.
|
|
835
|
-
describe.skip("post-compaction reminder (deprecated — see _meta.context_complete)", () => {
|
|
836
|
-
it("injects _context reminder signal on re-query of previously-seen entity", async () => {
|
|
837
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
838
|
-
// First query — records history, no reminder
|
|
839
|
-
const r1 = await router.execute("get_function", { key: "fn1" });
|
|
840
|
-
expect(findSignal(r1, "Previously queried")).toBeUndefined();
|
|
841
|
-
// Second query — should inject reminder as a context signal
|
|
842
|
-
const r2 = await router.execute("get_function", { key: "fn1" });
|
|
843
|
-
const reminderSignal = findSignal(r2, "Previously queried");
|
|
844
|
-
expect(reminderSignal).toBeDefined();
|
|
845
|
-
expect(reminderSignal?.type).toBe("context");
|
|
846
|
-
});
|
|
847
|
-
it("reminder includes blast radius count from first query", async () => {
|
|
848
|
-
const localGraph = createMockLocalGraph();
|
|
849
|
-
localGraph.getBlastRadius.mockReturnValue({
|
|
850
|
-
direct_callers: 7,
|
|
851
|
-
direct_callees: 3,
|
|
852
|
-
transitive_count: 15,
|
|
853
|
-
is_chokepoint: false,
|
|
854
|
-
summary: "7 callers, 15 transitive dependents",
|
|
855
|
-
});
|
|
856
|
-
const router = new QueryRouter(localGraph);
|
|
857
|
-
// First query — records blast radius
|
|
858
|
-
await router.execute("get_function", { key: "fn1" });
|
|
859
|
-
// Second query — reminder reflects blast radius from first query
|
|
860
|
-
const r2 = await router.execute("get_function", { key: "fn1" });
|
|
861
|
-
expect(hasSignalContaining(r2, "7 callers")).toBe(true);
|
|
862
|
-
});
|
|
863
|
-
it("different entities get independent reminders", async () => {
|
|
864
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
865
|
-
// Query fn1 first
|
|
866
|
-
await router.execute("get_function", { key: "fn1" });
|
|
867
|
-
// Query fn2 first time — no reminder
|
|
868
|
-
const r2 = await router.execute("get_function", { key: "fn2" });
|
|
869
|
-
expect(findSignal(r2, "Previously queried")).toBeUndefined();
|
|
870
|
-
// Re-query fn1 — should get reminder
|
|
871
|
-
const r3 = await router.execute("get_function", { key: "fn1" });
|
|
872
|
-
expect(findSignal(r3, "Previously queried")).toBeDefined();
|
|
873
|
-
});
|
|
874
|
-
it("reminder is short (<50 tokens)", async () => {
|
|
875
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
876
|
-
await router.execute("get_function", { key: "fn1" });
|
|
877
|
-
const r2 = await router.execute("get_function", { key: "fn1" });
|
|
878
|
-
const reminderSignal = findSignal(r2, "Previously queried");
|
|
879
|
-
const reminder = reminderSignal?.content ?? "";
|
|
880
|
-
// Rough token estimate: words + punctuation < 50
|
|
881
|
-
const wordCount = reminder.split(/\s+/).length;
|
|
882
|
-
expect(wordCount).toBeLessThan(50);
|
|
883
|
-
});
|
|
884
|
-
});
|
|
885
|
-
// ── Task 7.3: Push-based pending violations ───────────────────
|
|
886
|
-
describe("pending violations injection", () => {
|
|
887
|
-
it("injects pending_violations from store into _context", async () => {
|
|
888
|
-
const { PendingViolationStore } = await import("../tracking/pending-violations.js");
|
|
889
|
-
const store = new PendingViolationStore();
|
|
890
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
891
|
-
router.setPendingViolations(store);
|
|
892
|
-
// Simulate file-watcher adding violations
|
|
893
|
-
store.addViolations("src/a.ts", [
|
|
894
|
-
{
|
|
895
|
-
ruleKey: "rule-1",
|
|
896
|
-
ruleName: "naming-convention",
|
|
897
|
-
severity: "warning",
|
|
898
|
-
message: "Function should use camelCase",
|
|
899
|
-
filePath: "src/a.ts",
|
|
900
|
-
line: 10,
|
|
901
|
-
},
|
|
902
|
-
]);
|
|
903
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
904
|
-
expect(result._context?.signals).toBeDefined();
|
|
905
|
-
const violationSignal = findSignal(result, "Function should use camelCase");
|
|
906
|
-
expect(violationSignal).toBeDefined();
|
|
907
|
-
expect(violationSignal?.type).toBe("warning");
|
|
908
|
-
});
|
|
909
|
-
it("clears violations after draining", async () => {
|
|
910
|
-
const { PendingViolationStore } = await import("../tracking/pending-violations.js");
|
|
911
|
-
const store = new PendingViolationStore();
|
|
912
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
913
|
-
router.setPendingViolations(store);
|
|
914
|
-
store.addViolations("src/a.ts", [
|
|
915
|
-
{
|
|
916
|
-
ruleKey: "rule-1",
|
|
917
|
-
ruleName: "naming",
|
|
918
|
-
severity: "warning",
|
|
919
|
-
message: "bad name",
|
|
920
|
-
filePath: "src/a.ts",
|
|
921
|
-
},
|
|
922
|
-
]);
|
|
923
|
-
// First call drains
|
|
924
|
-
const r1 = await router.execute("get_function", { key: "fn1" });
|
|
925
|
-
expect(findSignal(r1, "bad name")).toBeDefined();
|
|
926
|
-
// Second call — no violations pending
|
|
927
|
-
const r2 = await router.execute("get_function", { key: "fn2" });
|
|
928
|
-
expect(findSignal(r2, "Rule violation")).toBeUndefined();
|
|
929
|
-
});
|
|
930
|
-
it("does not inject when no violations pending", async () => {
|
|
931
|
-
const { PendingViolationStore } = await import("../tracking/pending-violations.js");
|
|
932
|
-
const store = new PendingViolationStore();
|
|
933
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
934
|
-
router.setPendingViolations(store);
|
|
935
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
936
|
-
expect(findSignal(result, "Rule violation")).toBeUndefined();
|
|
937
|
-
});
|
|
938
|
-
});
|
|
939
|
-
// ── Cross-cutting: mode degradation ────────────────────────────
|
|
940
|
-
describe("enrichment graceful degradation", () => {
|
|
941
|
-
it("setup mode still tracks tool calls but skips enrichment", async () => {
|
|
942
|
-
const router = new QueryRouter(createMockLocalGraph());
|
|
943
|
-
router.setMode("setup");
|
|
944
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
945
|
-
expect(result._context).toBeUndefined();
|
|
946
|
-
expect(router.sessionContext.getToolCallCount()).toBe(1);
|
|
947
|
-
});
|
|
948
|
-
it("enrichment does not break when localGraph methods throw", async () => {
|
|
949
|
-
const localGraph = createMockLocalGraph();
|
|
950
|
-
localGraph.getBlastRadius.mockImplementation(() => {
|
|
951
|
-
throw new Error("CozoDB error");
|
|
952
|
-
});
|
|
953
|
-
localGraph.getConventionsForEntity.mockImplementation(() => {
|
|
954
|
-
throw new Error("Convention error");
|
|
955
|
-
});
|
|
956
|
-
const router = new QueryRouter(localGraph);
|
|
957
|
-
// Should not throw — enrichment failures are caught
|
|
958
|
-
const result = await router.execute("get_function", { key: "fn1" });
|
|
959
|
-
expect(result._meta.source).toBe("local");
|
|
960
|
-
expect(result.content).toBeDefined();
|
|
961
|
-
});
|
|
962
|
-
});
|
|
963
|
-
});
|
|
964
|
-
// ── Task 6.8: Context Placement Strategy ─────────────────────────
|
|
965
|
-
describe("orderContextFields — Lost in the Middle priority", () => {
|
|
966
|
-
it("orders critical fields before informational fields", () => {
|
|
967
|
-
const input = {
|
|
968
|
-
conventions: ["naming: camelCase (92%)"],
|
|
969
|
-
blast_radius: "14 callers, 38 transitive dependents",
|
|
970
|
-
value_counter: "unerr caught 3 issues",
|
|
971
|
-
drift_alert: "WARNING: modified locally",
|
|
972
|
-
session_greeting: "Welcome to unerr",
|
|
973
|
-
reminder: "Previously queried: 5 callers, risk=high",
|
|
974
|
-
related_issues: ["Chokepoint detected"],
|
|
975
|
-
pending_violations: [
|
|
976
|
-
{ file: "a.ts", rule: "naming", message: "Bad name" },
|
|
977
|
-
],
|
|
978
|
-
};
|
|
979
|
-
const ordered = orderContextFields(input);
|
|
980
|
-
const keys = Object.keys(ordered);
|
|
981
|
-
// Critical fields come first
|
|
982
|
-
expect(keys[0]).toBe("blast_radius");
|
|
983
|
-
expect(keys[1]).toBe("pending_violations");
|
|
984
|
-
expect(keys[2]).toBe("drift_alert");
|
|
985
|
-
expect(keys[3]).toBe("reminder");
|
|
986
|
-
// Informational fields come after
|
|
987
|
-
expect(keys[4]).toBe("conventions");
|
|
988
|
-
expect(keys[5]).toBe("related_issues");
|
|
989
|
-
expect(keys[6]).toBe("session_greeting");
|
|
990
|
-
expect(keys[7]).toBe("value_counter");
|
|
991
|
-
});
|
|
992
|
-
it("preserves field values during reordering", () => {
|
|
993
|
-
const input = {
|
|
994
|
-
conventions: ["use snake_case"],
|
|
995
|
-
blast_radius: "3 callers",
|
|
996
|
-
drift_alert: "modified 2 min ago",
|
|
997
|
-
};
|
|
998
|
-
const ordered = orderContextFields(input);
|
|
999
|
-
expect(ordered.blast_radius).toBe("3 callers");
|
|
1000
|
-
expect(ordered.drift_alert).toBe("modified 2 min ago");
|
|
1001
|
-
expect(ordered.conventions).toEqual(["use snake_case"]);
|
|
1002
|
-
});
|
|
1003
|
-
it("omits undefined fields (sparse context)", () => {
|
|
1004
|
-
const ordered = orderContextFields({
|
|
1005
|
-
blast_radius: "5 callers",
|
|
1006
|
-
value_counter: "caught 2 issues",
|
|
1007
|
-
});
|
|
1008
|
-
const keys = Object.keys(ordered);
|
|
1009
|
-
expect(keys).toEqual(["blast_radius", "value_counter"]);
|
|
1010
|
-
expect(keys).toHaveLength(2);
|
|
1011
|
-
});
|
|
1012
|
-
it("handles empty context", () => {
|
|
1013
|
-
const ordered = orderContextFields({});
|
|
1014
|
-
expect(Object.keys(ordered)).toHaveLength(0);
|
|
1015
|
-
});
|
|
1016
|
-
});
|
|
1017
|
-
// L8.3: Deferred Embedding Status Tests — disabled (semantic_search/find_similar removed from LOCAL_TOOLS)
|
|
1018
|
-
});
|