@unerr-ai/unerr 0.1.6 → 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 +39149 -36991
- 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-CX4FCWGT.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,308 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sprint L6 Tests: Convention Pattern Detection & Rule Generation.
|
|
3
|
-
*/
|
|
4
|
-
import { describe, expect, it } from "vitest";
|
|
5
|
-
import { detectLocalConventions, } from "../intelligence/local-convention-detector.js";
|
|
6
|
-
import { generateLocalRules } from "../intelligence/local-rule-generator.js";
|
|
7
|
-
// ── Mock CozoDB ─────────────────────────────────────────────────
|
|
8
|
-
function createMockDB(entities, edges = [], communities = []) {
|
|
9
|
-
return {
|
|
10
|
-
async run(query) {
|
|
11
|
-
if (query.includes("*entities")) {
|
|
12
|
-
return Promise.resolve({ rows: entities });
|
|
13
|
-
}
|
|
14
|
-
if (query.includes("*edges")) {
|
|
15
|
-
return Promise.resolve({ rows: edges });
|
|
16
|
-
}
|
|
17
|
-
if (query.includes("*communities")) {
|
|
18
|
-
return Promise.resolve({ rows: communities });
|
|
19
|
-
}
|
|
20
|
-
return Promise.resolve({ rows: [] });
|
|
21
|
-
},
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
// ── Convention Detector Tests ───────────────────────────────────
|
|
25
|
-
describe("detectLocalConventions", () => {
|
|
26
|
-
it("detects camelCase function naming convention", async () => {
|
|
27
|
-
const db = createMockDB([
|
|
28
|
-
["fn1", "function", "processPayment", "src/payments.ts"],
|
|
29
|
-
["fn2", "function", "handleRequest", "src/handler.ts"],
|
|
30
|
-
["fn3", "function", "validateInput", "src/validator.ts"],
|
|
31
|
-
["fn4", "function", "sendEmail", "src/mailer.ts"],
|
|
32
|
-
["fn5", "function", "parseConfig", "src/config.ts"],
|
|
33
|
-
]);
|
|
34
|
-
const result = await detectLocalConventions(db);
|
|
35
|
-
const camelCaseFn = result.conventions.find((c) => c.key === "naming-function-camelCase");
|
|
36
|
-
expect(camelCaseFn).toBeDefined();
|
|
37
|
-
expect(camelCaseFn?.confidence).toBe(1.0);
|
|
38
|
-
expect(camelCaseFn?.frequency).toBe(5);
|
|
39
|
-
expect(camelCaseFn?.kind).toBe("naming");
|
|
40
|
-
});
|
|
41
|
-
it("detects PascalCase class naming convention", async () => {
|
|
42
|
-
const db = createMockDB([
|
|
43
|
-
["c1", "class", "PaymentService", "src/services/payment.ts"],
|
|
44
|
-
["c2", "class", "UserRepository", "src/repos/user.ts"],
|
|
45
|
-
["c3", "class", "EmailSender", "src/services/email.ts"],
|
|
46
|
-
["c4", "class", "ConfigManager", "src/config/manager.ts"],
|
|
47
|
-
]);
|
|
48
|
-
const result = await detectLocalConventions(db);
|
|
49
|
-
const pascalClass = result.conventions.find((c) => c.key === "naming-class-PascalCase");
|
|
50
|
-
expect(pascalClass).toBeDefined();
|
|
51
|
-
expect(pascalClass?.confidence).toBe(1.0);
|
|
52
|
-
expect(pascalClass?.frequency).toBe(4);
|
|
53
|
-
});
|
|
54
|
-
it("detects PascalCase React component convention", async () => {
|
|
55
|
-
const db = createMockDB([
|
|
56
|
-
["cmp1", "function", "UserProfile", "src/components/UserProfile.tsx"],
|
|
57
|
-
["cmp2", "function", "NavBar", "src/components/NavBar.tsx"],
|
|
58
|
-
["cmp3", "function", "LoginForm", "src/components/LoginForm.tsx"],
|
|
59
|
-
// Non-component functions (camelCase, not in .tsx)
|
|
60
|
-
["fn1", "function", "handleClick", "src/utils/handlers.ts"],
|
|
61
|
-
]);
|
|
62
|
-
const result = await detectLocalConventions(db);
|
|
63
|
-
const componentConvention = result.conventions.find((c) => c.key === "naming-component-PascalCase");
|
|
64
|
-
expect(componentConvention).toBeDefined();
|
|
65
|
-
expect(componentConvention?.name).toBe("PascalCase React components");
|
|
66
|
-
expect(componentConvention?.frequency).toBe(3);
|
|
67
|
-
});
|
|
68
|
-
it("detects mixed adherence (below threshold skipped)", async () => {
|
|
69
|
-
const db = createMockDB([
|
|
70
|
-
["fn1", "function", "processPayment", "src/a.ts"],
|
|
71
|
-
["fn2", "function", "HandleRequest", "src/b.ts"], // PascalCase = wrong
|
|
72
|
-
["fn3", "function", "validate_input", "src/c.ts"], // snake_case = wrong
|
|
73
|
-
]);
|
|
74
|
-
const result = await detectLocalConventions(db);
|
|
75
|
-
// With 1/3 camelCase, shouldn't detect camelCase as convention
|
|
76
|
-
const camelCaseFn = result.conventions.find((c) => c.key === "naming-function-camelCase");
|
|
77
|
-
// 1/3 = 33% < 60% threshold
|
|
78
|
-
expect(camelCaseFn).toBeUndefined();
|
|
79
|
-
});
|
|
80
|
-
it("detects single-kind directory structure", async () => {
|
|
81
|
-
const db = createMockDB([
|
|
82
|
-
["fn1", "function", "add", "src/utils/math.ts"],
|
|
83
|
-
["fn2", "function", "subtract", "src/utils/strings.ts"],
|
|
84
|
-
["fn3", "function", "multiply", "src/utils/arrays.ts"],
|
|
85
|
-
]);
|
|
86
|
-
const result = await detectLocalConventions(db);
|
|
87
|
-
const singleKind = result.conventions.find((c) => c.key.startsWith("structure-single-kind-") &&
|
|
88
|
-
c.name.includes("src/utils"));
|
|
89
|
-
expect(singleKind).toBeDefined();
|
|
90
|
-
expect(singleKind?.kind).toBe("structure");
|
|
91
|
-
expect(singleKind?.confidence).toBe(1.0);
|
|
92
|
-
});
|
|
93
|
-
it("detects test file segregation pattern", async () => {
|
|
94
|
-
const db = createMockDB([
|
|
95
|
-
["fn1", "function", "add", "src/math.ts"],
|
|
96
|
-
["fn2", "function", "subtract", "src/strings.ts"],
|
|
97
|
-
["t1", "function", "testAdd", "src/__tests__/math.test.ts"],
|
|
98
|
-
["t2", "function", "testSubtract", "src/__tests__/strings.test.ts"],
|
|
99
|
-
["t3", "function", "testMultiply", "src/__tests__/arrays.test.ts"],
|
|
100
|
-
]);
|
|
101
|
-
const result = await detectLocalConventions(db);
|
|
102
|
-
const testPattern = result.conventions.find((c) => c.key === "structure-test-segregated");
|
|
103
|
-
expect(testPattern).toBeDefined();
|
|
104
|
-
expect(testPattern?.kind).toBe("structure");
|
|
105
|
-
});
|
|
106
|
-
it("detects import direction leaf modules", async () => {
|
|
107
|
-
const db = createMockDB([
|
|
108
|
-
["fn1", "function", "handler", "src/controllers/api.ts"],
|
|
109
|
-
["fn2", "function", "validate", "src/utils/validate.ts"],
|
|
110
|
-
["fn3", "function", "format", "src/utils/format.ts"],
|
|
111
|
-
], [
|
|
112
|
-
// controllers imports from utils, but utils never imports controllers
|
|
113
|
-
["fn1", "fn2", "imports"],
|
|
114
|
-
["fn1", "fn3", "imports"],
|
|
115
|
-
], [
|
|
116
|
-
[0, "controllers", 1],
|
|
117
|
-
[1, "utils", 2],
|
|
118
|
-
]);
|
|
119
|
-
const result = await detectLocalConventions(db);
|
|
120
|
-
const leafModule = result.conventions.find((c) => c.key.startsWith("import-direction-leaf-"));
|
|
121
|
-
expect(leafModule).toBeDefined();
|
|
122
|
-
expect(leafModule?.kind).toBe("import_direction");
|
|
123
|
-
});
|
|
124
|
-
it("returns empty results for empty graph", async () => {
|
|
125
|
-
const db = createMockDB([]);
|
|
126
|
-
const result = await detectLocalConventions(db);
|
|
127
|
-
expect(result.patterns).toHaveLength(0);
|
|
128
|
-
expect(result.conventions).toHaveLength(0);
|
|
129
|
-
expect(result.stats.totalEntities).toBe(0);
|
|
130
|
-
});
|
|
131
|
-
it("handles DB errors gracefully", async () => {
|
|
132
|
-
const db = {
|
|
133
|
-
async run() {
|
|
134
|
-
throw new Error("CozoDB failure");
|
|
135
|
-
},
|
|
136
|
-
};
|
|
137
|
-
const result = await detectLocalConventions(db);
|
|
138
|
-
expect(result.patterns).toHaveLength(0);
|
|
139
|
-
expect(result.conventions).toHaveLength(0);
|
|
140
|
-
});
|
|
141
|
-
it("produces CompactPattern[] compatible with loadPatterns", async () => {
|
|
142
|
-
const db = createMockDB([
|
|
143
|
-
["fn1", "function", "processPayment", "src/payments.ts"],
|
|
144
|
-
["fn2", "function", "handleRequest", "src/handler.ts"],
|
|
145
|
-
["fn3", "function", "validateInput", "src/validator.ts"],
|
|
146
|
-
]);
|
|
147
|
-
const result = await detectLocalConventions(db);
|
|
148
|
-
for (const pattern of result.patterns) {
|
|
149
|
-
expect(pattern).toHaveProperty("key");
|
|
150
|
-
expect(pattern).toHaveProperty("name");
|
|
151
|
-
expect(pattern).toHaveProperty("kind");
|
|
152
|
-
expect(pattern).toHaveProperty("frequency");
|
|
153
|
-
expect(pattern).toHaveProperty("confidence");
|
|
154
|
-
expect(pattern).toHaveProperty("exemplar_keys");
|
|
155
|
-
expect(pattern).toHaveProperty("promoted_rule_key");
|
|
156
|
-
expect(Array.isArray(pattern.exemplar_keys)).toBe(true);
|
|
157
|
-
expect(typeof pattern.key).toBe("string");
|
|
158
|
-
expect(typeof pattern.confidence).toBe("number");
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
it("completes in <500ms for large entity sets", async () => {
|
|
162
|
-
// Generate 10K entities
|
|
163
|
-
const entities = [];
|
|
164
|
-
for (let i = 0; i < 10000; i++) {
|
|
165
|
-
const kind = i % 3 === 0 ? "function" : i % 3 === 1 ? "class" : "interface";
|
|
166
|
-
const name = kind === "function"
|
|
167
|
-
? `func${i}`
|
|
168
|
-
: kind === "class"
|
|
169
|
-
? `Class${i}`
|
|
170
|
-
: `Interface${i}`;
|
|
171
|
-
entities.push([`e${i}`, kind, name, `src/dir${i % 50}/file${i}.ts`]);
|
|
172
|
-
}
|
|
173
|
-
const db = createMockDB(entities);
|
|
174
|
-
const start = Date.now();
|
|
175
|
-
const result = await detectLocalConventions(db);
|
|
176
|
-
const elapsed = Date.now() - start;
|
|
177
|
-
expect(elapsed).toBeLessThan(500);
|
|
178
|
-
expect(result.conventions.length).toBeGreaterThan(0);
|
|
179
|
-
expect(result.stats.totalEntities).toBe(10000);
|
|
180
|
-
});
|
|
181
|
-
});
|
|
182
|
-
// ── Rule Generator Tests ────────────────────────────────────────
|
|
183
|
-
describe("generateLocalRules", () => {
|
|
184
|
-
it("generates rules from naming conventions", async () => {
|
|
185
|
-
const db = createMockDB([
|
|
186
|
-
["fn1", "function", "processPayment", "src/payments.ts"],
|
|
187
|
-
["fn2", "function", "handleRequest", "src/handler.ts"],
|
|
188
|
-
["fn3", "function", "validateInput", "src/validator.ts"],
|
|
189
|
-
]);
|
|
190
|
-
const detection = await detectLocalConventions(db);
|
|
191
|
-
const generation = generateLocalRules(detection.conventions, "test-repo");
|
|
192
|
-
expect(generation.rules.length).toBeGreaterThan(0);
|
|
193
|
-
expect(generation.stats.total).toBeGreaterThan(0);
|
|
194
|
-
// Naming rules should have engine: "structural"
|
|
195
|
-
const namingRules = generation.rules.filter((r) => r.key.includes("naming"));
|
|
196
|
-
for (const rule of namingRules) {
|
|
197
|
-
expect(rule.engine).toBe("structural");
|
|
198
|
-
expect(rule.enabled).toBe(true);
|
|
199
|
-
expect(rule.repo_id).toBe("test-repo");
|
|
200
|
-
expect(rule.status).toBe("active");
|
|
201
|
-
}
|
|
202
|
-
});
|
|
203
|
-
it("generates CompactRule[] compatible with loadRules", async () => {
|
|
204
|
-
const db = createMockDB([
|
|
205
|
-
["fn1", "function", "processPayment", "src/a.ts"],
|
|
206
|
-
["fn2", "function", "handleRequest", "src/b.ts"],
|
|
207
|
-
["fn3", "function", "validateInput", "src/c.ts"],
|
|
208
|
-
["c1", "class", "PaymentService", "src/d.ts"],
|
|
209
|
-
["c2", "class", "UserRepo", "src/e.ts"],
|
|
210
|
-
["c3", "class", "EmailSender", "src/f.ts"],
|
|
211
|
-
]);
|
|
212
|
-
const detection = await detectLocalConventions(db);
|
|
213
|
-
const generation = generateLocalRules(detection.conventions, "test-repo");
|
|
214
|
-
for (const rule of generation.rules) {
|
|
215
|
-
expect(rule).toHaveProperty("key");
|
|
216
|
-
expect(rule).toHaveProperty("name");
|
|
217
|
-
expect(rule).toHaveProperty("scope");
|
|
218
|
-
expect(rule).toHaveProperty("severity");
|
|
219
|
-
expect(rule).toHaveProperty("engine");
|
|
220
|
-
expect(rule).toHaveProperty("query");
|
|
221
|
-
expect(rule).toHaveProperty("message");
|
|
222
|
-
expect(rule).toHaveProperty("file_glob");
|
|
223
|
-
expect(rule).toHaveProperty("enabled");
|
|
224
|
-
expect(rule).toHaveProperty("repo_id");
|
|
225
|
-
// Key format: "local-rule-{convention.key}"
|
|
226
|
-
expect(rule.key).toMatch(/^local-rule-/);
|
|
227
|
-
}
|
|
228
|
-
});
|
|
229
|
-
it("produces zero rules from empty conventions", () => {
|
|
230
|
-
const generation = generateLocalRules([], "test-repo");
|
|
231
|
-
expect(generation.rules).toHaveLength(0);
|
|
232
|
-
expect(generation.stats.total).toBe(0);
|
|
233
|
-
});
|
|
234
|
-
it("generates structure rules with info severity", async () => {
|
|
235
|
-
const db = createMockDB([
|
|
236
|
-
["fn1", "function", "add", "src/utils/math.ts"],
|
|
237
|
-
["fn2", "function", "subtract", "src/utils/strings.ts"],
|
|
238
|
-
["fn3", "function", "multiply", "src/utils/arrays.ts"],
|
|
239
|
-
]);
|
|
240
|
-
const detection = await detectLocalConventions(db);
|
|
241
|
-
const generation = generateLocalRules(detection.conventions, "test-repo");
|
|
242
|
-
const structureRules = generation.rules.filter((r) => r.key.includes("structure"));
|
|
243
|
-
for (const rule of structureRules) {
|
|
244
|
-
expect(rule.severity).toBe("info");
|
|
245
|
-
}
|
|
246
|
-
});
|
|
247
|
-
it("generates import direction rules with warn severity", async () => {
|
|
248
|
-
const db = createMockDB([
|
|
249
|
-
["fn1", "function", "handler", "src/controllers/api.ts"],
|
|
250
|
-
["fn2", "function", "validate", "src/utils/validate.ts"],
|
|
251
|
-
["fn3", "function", "format", "src/utils/format.ts"],
|
|
252
|
-
], [
|
|
253
|
-
["fn1", "fn2", "imports"],
|
|
254
|
-
["fn1", "fn3", "imports"],
|
|
255
|
-
], [
|
|
256
|
-
[0, "controllers", 1],
|
|
257
|
-
[1, "utils", 2],
|
|
258
|
-
]);
|
|
259
|
-
const detection = await detectLocalConventions(db);
|
|
260
|
-
const generation = generateLocalRules(detection.conventions, "test-repo");
|
|
261
|
-
const importRules = generation.rules.filter((r) => r.key.includes("import-direction"));
|
|
262
|
-
for (const rule of importRules) {
|
|
263
|
-
expect(rule.severity).toBe("warn");
|
|
264
|
-
}
|
|
265
|
-
});
|
|
266
|
-
});
|
|
267
|
-
// ── Integration: Convention → Pattern → Rule Pipeline ───────────
|
|
268
|
-
describe("L6 convention pipeline integration", () => {
|
|
269
|
-
it("full pipeline: entities → patterns → rules", async () => {
|
|
270
|
-
const db = createMockDB([
|
|
271
|
-
// Functions: camelCase
|
|
272
|
-
["fn1", "function", "processPayment", "src/services/payment.ts"],
|
|
273
|
-
["fn2", "function", "handleRequest", "src/controllers/api.ts"],
|
|
274
|
-
["fn3", "function", "validateInput", "src/utils/validate.ts"],
|
|
275
|
-
["fn4", "function", "sendEmail", "src/services/email.ts"],
|
|
276
|
-
// Classes: PascalCase
|
|
277
|
-
["c1", "class", "PaymentService", "src/services/payment.ts"],
|
|
278
|
-
["c2", "class", "ApiController", "src/controllers/api.ts"],
|
|
279
|
-
["c3", "class", "Validator", "src/utils/validate.ts"],
|
|
280
|
-
// Test entities
|
|
281
|
-
["t1", "function", "testPayment", "src/__tests__/payment.test.ts"],
|
|
282
|
-
["t2", "function", "testApi", "src/__tests__/api.test.ts"],
|
|
283
|
-
["t3", "function", "testValidate", "src/__tests__/validate.test.ts"],
|
|
284
|
-
], [
|
|
285
|
-
// controllers → services → utils (layered)
|
|
286
|
-
["fn2", "fn1", "imports"],
|
|
287
|
-
["fn1", "fn3", "imports"],
|
|
288
|
-
["fn4", "fn3", "imports"],
|
|
289
|
-
], [
|
|
290
|
-
[0, "services", 2],
|
|
291
|
-
[1, "controllers", 1],
|
|
292
|
-
[2, "utils", 1],
|
|
293
|
-
]);
|
|
294
|
-
// Step 1: Detect conventions
|
|
295
|
-
const detection = await detectLocalConventions(db);
|
|
296
|
-
expect(detection.patterns.length).toBeGreaterThan(0);
|
|
297
|
-
expect(detection.stats.naming).toBeGreaterThan(0);
|
|
298
|
-
// Step 2: Generate rules
|
|
299
|
-
const generation = generateLocalRules(detection.conventions, "test-repo");
|
|
300
|
-
expect(generation.rules.length).toBeGreaterThan(0);
|
|
301
|
-
// Step 3: Verify pattern-rule linkage
|
|
302
|
-
for (const pattern of detection.patterns) {
|
|
303
|
-
expect(pattern.promoted_rule_key).toMatch(/^local-rule-/);
|
|
304
|
-
const linkedRule = generation.rules.find((r) => r.key === pattern.promoted_rule_key);
|
|
305
|
-
expect(linkedRule).toBeDefined();
|
|
306
|
-
}
|
|
307
|
-
});
|
|
308
|
-
});
|