@mycodemap/mycodemap 0.5.0 → 0.5.1

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.
Files changed (199) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +77 -9
  3. package/dist/cli/commands/analyze.d.ts +18 -0
  4. package/dist/cli/commands/analyze.d.ts.map +1 -1
  5. package/dist/cli/commands/analyze.js +239 -6
  6. package/dist/cli/commands/analyze.js.map +1 -1
  7. package/dist/cli/commands/check.d.ts +22 -0
  8. package/dist/cli/commands/check.d.ts.map +1 -0
  9. package/dist/cli/commands/check.js +168 -0
  10. package/dist/cli/commands/check.js.map +1 -0
  11. package/dist/cli/commands/ci.d.ts +25 -0
  12. package/dist/cli/commands/ci.d.ts.map +1 -1
  13. package/dist/cli/commands/ci.js +139 -36
  14. package/dist/cli/commands/ci.js.map +1 -1
  15. package/dist/cli/commands/complexity.d.ts.map +1 -1
  16. package/dist/cli/commands/complexity.js +6 -0
  17. package/dist/cli/commands/complexity.js.map +1 -1
  18. package/dist/cli/commands/design.d.ts +5 -0
  19. package/dist/cli/commands/design.d.ts.map +1 -1
  20. package/dist/cli/commands/design.js +6 -0
  21. package/dist/cli/commands/design.js.map +1 -1
  22. package/dist/cli/commands/generate.d.ts +1 -0
  23. package/dist/cli/commands/generate.d.ts.map +1 -1
  24. package/dist/cli/commands/generate.js +121 -8
  25. package/dist/cli/commands/generate.js.map +1 -1
  26. package/dist/cli/commands/history.d.ts +26 -0
  27. package/dist/cli/commands/history.d.ts.map +1 -0
  28. package/dist/cli/commands/history.js +92 -0
  29. package/dist/cli/commands/history.js.map +1 -0
  30. package/dist/cli/commands/mcp.d.ts +13 -0
  31. package/dist/cli/commands/mcp.d.ts.map +1 -0
  32. package/dist/cli/commands/mcp.js +108 -0
  33. package/dist/cli/commands/mcp.js.map +1 -0
  34. package/dist/cli/commands/workflow.d.ts.map +1 -1
  35. package/dist/cli/commands/workflow.js +22 -2
  36. package/dist/cli/commands/workflow.js.map +1 -1
  37. package/dist/cli/config-loader.d.ts.map +1 -1
  38. package/dist/cli/config-loader.js +3 -2
  39. package/dist/cli/config-loader.js.map +1 -1
  40. package/dist/cli/contract-checker.d.ts +33 -0
  41. package/dist/cli/contract-checker.d.ts.map +1 -0
  42. package/dist/cli/contract-checker.js +719 -0
  43. package/dist/cli/contract-checker.js.map +1 -0
  44. package/dist/cli/contract-diff-scope.d.ts +14 -0
  45. package/dist/cli/contract-diff-scope.d.ts.map +1 -0
  46. package/dist/cli/contract-diff-scope.js +127 -0
  47. package/dist/cli/contract-diff-scope.js.map +1 -0
  48. package/dist/cli/contract-gate-thresholds.d.ts +14 -0
  49. package/dist/cli/contract-gate-thresholds.d.ts.map +1 -0
  50. package/dist/cli/contract-gate-thresholds.js +19 -0
  51. package/dist/cli/contract-gate-thresholds.js.map +1 -0
  52. package/dist/cli/design-contract-loader.d.ts.map +1 -1
  53. package/dist/cli/design-contract-loader.js +355 -3
  54. package/dist/cli/design-contract-loader.js.map +1 -1
  55. package/dist/cli/design-scope-resolver.d.ts.map +1 -1
  56. package/dist/cli/design-scope-resolver.js +89 -41
  57. package/dist/cli/design-scope-resolver.js.map +1 -1
  58. package/dist/cli/index.js +18 -6
  59. package/dist/cli/index.js.map +1 -1
  60. package/dist/cli/paths.d.ts.map +1 -1
  61. package/dist/cli/paths.js +30 -7
  62. package/dist/cli/paths.js.map +1 -1
  63. package/dist/core/analyzer.d.ts.map +1 -1
  64. package/dist/core/analyzer.js +16 -0
  65. package/dist/core/analyzer.js.map +1 -1
  66. package/dist/domain/entities/CodeGraph.d.ts +5 -1
  67. package/dist/domain/entities/CodeGraph.d.ts.map +1 -1
  68. package/dist/domain/entities/CodeGraph.js +29 -12
  69. package/dist/domain/entities/CodeGraph.js.map +1 -1
  70. package/dist/domain/entities/Dependency.d.ts +8 -1
  71. package/dist/domain/entities/Dependency.d.ts.map +1 -1
  72. package/dist/domain/entities/Dependency.js +19 -4
  73. package/dist/domain/entities/Dependency.js.map +1 -1
  74. package/dist/domain/entities/Symbol.d.ts +2 -1
  75. package/dist/domain/entities/Symbol.d.ts.map +1 -1
  76. package/dist/domain/entities/Symbol.js +6 -3
  77. package/dist/domain/entities/Symbol.js.map +1 -1
  78. package/dist/infrastructure/storage/StorageFactory.d.ts +1 -0
  79. package/dist/infrastructure/storage/StorageFactory.d.ts.map +1 -1
  80. package/dist/infrastructure/storage/StorageFactory.js +7 -2
  81. package/dist/infrastructure/storage/StorageFactory.js.map +1 -1
  82. package/dist/infrastructure/storage/adapters/FileSystemStorage.d.ts +3 -1
  83. package/dist/infrastructure/storage/adapters/FileSystemStorage.d.ts.map +1 -1
  84. package/dist/infrastructure/storage/adapters/FileSystemStorage.js +10 -2
  85. package/dist/infrastructure/storage/adapters/FileSystemStorage.js.map +1 -1
  86. package/dist/infrastructure/storage/adapters/KuzuDBStorage.d.ts +3 -1
  87. package/dist/infrastructure/storage/adapters/KuzuDBStorage.d.ts.map +1 -1
  88. package/dist/infrastructure/storage/adapters/KuzuDBStorage.js +9 -1
  89. package/dist/infrastructure/storage/adapters/KuzuDBStorage.js.map +1 -1
  90. package/dist/infrastructure/storage/adapters/MemoryStorage.d.ts +3 -1
  91. package/dist/infrastructure/storage/adapters/MemoryStorage.d.ts.map +1 -1
  92. package/dist/infrastructure/storage/adapters/MemoryStorage.js +9 -1
  93. package/dist/infrastructure/storage/adapters/MemoryStorage.js.map +1 -1
  94. package/dist/infrastructure/storage/adapters/SQLiteStorage.d.ts +53 -0
  95. package/dist/infrastructure/storage/adapters/SQLiteStorage.d.ts.map +1 -0
  96. package/dist/infrastructure/storage/adapters/SQLiteStorage.js +879 -0
  97. package/dist/infrastructure/storage/adapters/SQLiteStorage.js.map +1 -0
  98. package/dist/infrastructure/storage/graph-helpers.d.ts +3 -1
  99. package/dist/infrastructure/storage/graph-helpers.d.ts.map +1 -1
  100. package/dist/infrastructure/storage/graph-helpers.js +90 -0
  101. package/dist/infrastructure/storage/graph-helpers.js.map +1 -1
  102. package/dist/infrastructure/storage/index.d.ts +1 -1
  103. package/dist/infrastructure/storage/index.d.ts.map +1 -1
  104. package/dist/infrastructure/storage/interfaces/StorageBase.d.ts +3 -1
  105. package/dist/infrastructure/storage/interfaces/StorageBase.d.ts.map +1 -1
  106. package/dist/infrastructure/storage/interfaces/StorageBase.js.map +1 -1
  107. package/dist/infrastructure/storage/sqlite/GovernanceGraphCache.d.ts +27 -0
  108. package/dist/infrastructure/storage/sqlite/GovernanceGraphCache.d.ts.map +1 -0
  109. package/dist/infrastructure/storage/sqlite/GovernanceGraphCache.js +246 -0
  110. package/dist/infrastructure/storage/sqlite/GovernanceGraphCache.js.map +1 -0
  111. package/dist/infrastructure/storage/sqlite/perf-thresholds.d.ts +25 -0
  112. package/dist/infrastructure/storage/sqlite/perf-thresholds.d.ts.map +1 -0
  113. package/dist/infrastructure/storage/sqlite/perf-thresholds.js +25 -0
  114. package/dist/infrastructure/storage/sqlite/perf-thresholds.js.map +1 -0
  115. package/dist/infrastructure/storage/sqlite/schema.d.ts +4 -0
  116. package/dist/infrastructure/storage/sqlite/schema.d.ts.map +1 -0
  117. package/dist/infrastructure/storage/sqlite/schema.js +111 -0
  118. package/dist/infrastructure/storage/sqlite/schema.js.map +1 -0
  119. package/dist/interface/types/design-check.d.ts +73 -0
  120. package/dist/interface/types/design-check.d.ts.map +1 -0
  121. package/dist/interface/types/design-check.js +4 -0
  122. package/dist/interface/types/design-check.js.map +1 -0
  123. package/dist/interface/types/design-contract.d.ts +56 -1
  124. package/dist/interface/types/design-contract.d.ts.map +1 -1
  125. package/dist/interface/types/history-risk.d.ts +90 -0
  126. package/dist/interface/types/history-risk.d.ts.map +1 -0
  127. package/dist/interface/types/history-risk.js +4 -0
  128. package/dist/interface/types/history-risk.js.map +1 -0
  129. package/dist/interface/types/index.d.ts +17 -2
  130. package/dist/interface/types/index.d.ts.map +1 -1
  131. package/dist/interface/types/storage.d.ts +28 -1
  132. package/dist/interface/types/storage.d.ts.map +1 -1
  133. package/dist/orchestrator/adapters/ast-grep-adapter.d.ts +10 -0
  134. package/dist/orchestrator/adapters/ast-grep-adapter.d.ts.map +1 -1
  135. package/dist/orchestrator/adapters/ast-grep-adapter.js +46 -17
  136. package/dist/orchestrator/adapters/ast-grep-adapter.js.map +1 -1
  137. package/dist/orchestrator/adapters/codemap-adapter.d.ts.map +1 -1
  138. package/dist/orchestrator/adapters/codemap-adapter.js +2 -22
  139. package/dist/orchestrator/adapters/codemap-adapter.js.map +1 -1
  140. package/dist/orchestrator/history-risk-service.d.ts +55 -0
  141. package/dist/orchestrator/history-risk-service.d.ts.map +1 -0
  142. package/dist/orchestrator/history-risk-service.js +680 -0
  143. package/dist/orchestrator/history-risk-service.js.map +1 -0
  144. package/dist/orchestrator/types.d.ts +19 -1
  145. package/dist/orchestrator/types.d.ts.map +1 -1
  146. package/dist/orchestrator/types.js +19 -0
  147. package/dist/orchestrator/types.js.map +1 -1
  148. package/dist/server/mcp/index.d.ts +4 -0
  149. package/dist/server/mcp/index.d.ts.map +1 -0
  150. package/dist/server/mcp/index.js +5 -0
  151. package/dist/server/mcp/index.js.map +1 -0
  152. package/dist/server/mcp/server.d.ts +17 -0
  153. package/dist/server/mcp/server.d.ts.map +1 -0
  154. package/dist/server/mcp/server.js +84 -0
  155. package/dist/server/mcp/server.js.map +1 -0
  156. package/dist/server/mcp/service.d.ts +22 -0
  157. package/dist/server/mcp/service.d.ts.map +1 -0
  158. package/dist/server/mcp/service.js +177 -0
  159. package/dist/server/mcp/service.js.map +1 -0
  160. package/dist/server/mcp/types.d.ts +56 -0
  161. package/dist/server/mcp/types.d.ts.map +1 -0
  162. package/dist/server/mcp/types.js +4 -0
  163. package/dist/server/mcp/types.js.map +1 -0
  164. package/docs/AI_ASSISTANT_SETUP.md +1 -1
  165. package/docs/SETUP_GUIDE.md +6 -6
  166. package/docs/ai-guide/COMMANDS.md +98 -4
  167. package/docs/ai-guide/INTEGRATION.md +137 -433
  168. package/docs/ai-guide/OUTPUT.md +476 -6
  169. package/docs/ai-guide/PATTERNS.md +41 -11
  170. package/docs/ai-guide/PROMPTS.md +11 -6
  171. package/docs/backlog.md +177 -0
  172. package/docs/eatdogfood-reports/2026-04-17-eatdogfood-agent-experience.md +231 -0
  173. package/docs/exec-plans/completed/2026-04-17-eatdogfood-codemap-cli.md +103 -0
  174. package/docs/ideation/2026-04-15-executable-architecture-constitution-ideation.md +102 -0
  175. package/docs/product-specs/DESIGN_CONTRACT_TEMPLATE.md +47 -0
  176. package/docs/product-specs/MVP3-ARCHITECTURE-COMPARISON.md +11 -10
  177. package/docs/product-specs/MVP3-ARCHITECTURE-REDESIGN-PRD.md +10 -10
  178. package/docs/product-specs/MVP3-ARCHITECTURE-REDESIGN-TECH-PRD.md +17 -12
  179. package/docs/rules/README.md +16 -11
  180. package/docs/rules/architecture-guardrails.md +24 -336
  181. package/docs/rules/code-quality-redlines.md +25 -311
  182. package/docs/rules/engineering-with-codex-openai.md +14 -1
  183. package/docs/rules/validation.md +90 -40
  184. package/mycodemap.config.schema.json +3 -3
  185. package/package.json +7 -2
  186. package/scripts/benchmark-governance-graph.mjs +132 -0
  187. package/scripts/calibrate-contract-gate.mjs +221 -0
  188. package/scripts/capability-report.py +255 -0
  189. package/scripts/qa-rule-control.sh +254 -0
  190. package/scripts/report-high-risk-files.mjs +395 -0
  191. package/scripts/rule-context.mjs +155 -0
  192. package/scripts/smoke-sqlite-impact.mjs +85 -0
  193. package/scripts/sync-analyze-docs.js +1 -0
  194. package/scripts/tests/test_capability_report.py +89 -0
  195. package/scripts/tests/test_rule_control_workflow.py +51 -0
  196. package/scripts/tests/test_validate_rules.py +81 -0
  197. package/scripts/validate-ai-docs.js +283 -1
  198. package/scripts/validate-docs.js +249 -42
  199. package/scripts/validate-rules.py +254 -0
@@ -0,0 +1,254 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -u
4
+
5
+ SCENARIO="all"
6
+ TMP_ROOT=""
7
+ FAILURES=0
8
+
9
+ usage() {
10
+ echo "Usage: bash scripts/qa-rule-control.sh --scenario <name|all>" >&2
11
+ }
12
+
13
+ cleanup() {
14
+ if [ -n "${TMP_ROOT}" ] && [ -d "${TMP_ROOT}" ]; then
15
+ rm -rf "${TMP_ROOT}"
16
+ fi
17
+ }
18
+
19
+ trap cleanup EXIT
20
+
21
+ while [ "$#" -gt 0 ]; do
22
+ case "$1" in
23
+ --scenario)
24
+ SCENARIO="${2:-}"
25
+ shift 2
26
+ ;;
27
+ -h|--help)
28
+ usage
29
+ exit 0
30
+ ;;
31
+ *)
32
+ usage
33
+ exit 1
34
+ ;;
35
+ esac
36
+ done
37
+
38
+ if [ -z "${SCENARIO}" ]; then
39
+ usage
40
+ exit 1
41
+ fi
42
+
43
+ TMP_ROOT="$(mktemp -d /tmp/codemap-rule-control-XXXXXX)"
44
+
45
+ fail() {
46
+ echo "[FAIL] $1"
47
+ FAILURES=$((FAILURES + 1))
48
+ }
49
+
50
+ pass() {
51
+ echo "[PASS] $1"
52
+ }
53
+
54
+ scenario_capability() {
55
+ local output_path="${TMP_ROOT}/capability-report.json"
56
+ if ! python3 scripts/capability-report.py --output "${output_path}" >/dev/null; then
57
+ fail "capability: capability-report command failed"
58
+ return
59
+ fi
60
+
61
+ if python3 - "${output_path}" <<'PY'
62
+ import json
63
+ import sys
64
+ from pathlib import Path
65
+
66
+ payload = json.loads(Path(sys.argv[1]).read_text(encoding='utf-8'))
67
+ names = {item["name"] for item in payload["items"]}
68
+ assert "python3" in names
69
+ assert "node" in names
70
+ assert "summary" in payload
71
+ PY
72
+ then
73
+ pass "capability"
74
+ else
75
+ fail "capability: output json missing expected fields"
76
+ fi
77
+ }
78
+
79
+ scenario_p0_block() {
80
+ local result
81
+ if ! result="$(python3 - <<'PY'
82
+ import importlib.util
83
+ import sys
84
+ from pathlib import Path
85
+
86
+ module_path = Path("scripts/validate-rules.py").resolve()
87
+ spec = importlib.util.spec_from_file_location("validate_rules", module_path)
88
+ module = importlib.util.module_from_spec(spec)
89
+ sys.modules[spec.name] = module
90
+ spec.loader.exec_module(module)
91
+
92
+ checks = [
93
+ module.make_check("typecheck", "P0", ["npm", "run", "typecheck"], "failed", "boom"),
94
+ module.make_check("lint", "P1", ["npm", "run", "lint"], "passed", "ok"),
95
+ ]
96
+ print(module.resolve_exit_code(checks, report_only=False))
97
+ PY
98
+ )"; then
99
+ fail "p0-block: python verification failed"
100
+ return
101
+ fi
102
+
103
+ if [ "${result}" = "1" ]; then
104
+ pass "p0-block"
105
+ else
106
+ fail "p0-block: expected exit code 1, got ${result}"
107
+ fi
108
+ }
109
+
110
+ scenario_p1_warn() {
111
+ local result
112
+ if ! result="$(python3 - <<'PY'
113
+ import importlib.util
114
+ import sys
115
+ from pathlib import Path
116
+
117
+ module_path = Path("scripts/validate-rules.py").resolve()
118
+ spec = importlib.util.spec_from_file_location("validate_rules", module_path)
119
+ module = importlib.util.module_from_spec(spec)
120
+ sys.modules[spec.name] = module
121
+ spec.loader.exec_module(module)
122
+
123
+ checks = [
124
+ module.make_check("typecheck", "P0", ["npm", "run", "typecheck"], "passed", "ok"),
125
+ module.make_check("lint", "P1", ["npm", "run", "lint"], "failed", "warn"),
126
+ ]
127
+ print(module.resolve_exit_code(checks, report_only=False))
128
+ PY
129
+ )"; then
130
+ fail "p1-warn: python verification failed"
131
+ return
132
+ fi
133
+
134
+ if [ "${result}" = "2" ]; then
135
+ pass "p1-warn"
136
+ else
137
+ fail "p1-warn: expected exit code 2, got ${result}"
138
+ fi
139
+ }
140
+
141
+ scenario_unavailable() {
142
+ local result
143
+ if ! result="$(python3 - <<'PY'
144
+ import importlib.util
145
+ import sys
146
+ from pathlib import Path
147
+
148
+ module_path = Path("scripts/validate-rules.py").resolve()
149
+ spec = importlib.util.spec_from_file_location("validate_rules", module_path)
150
+ module = importlib.util.module_from_spec(spec)
151
+ sys.modules[spec.name] = module
152
+ spec.loader.exec_module(module)
153
+
154
+ checks = module.execute_checks("arch", dist_cli_path=Path("/tmp/codemap-rule-control-missing-dist.js"))
155
+ print(module.resolve_exit_code(checks, report_only=False))
156
+ PY
157
+ )"; then
158
+ fail "unavailable: python verification failed"
159
+ return
160
+ fi
161
+
162
+ if [ "${result}" = "4" ]; then
163
+ pass "unavailable"
164
+ else
165
+ fail "unavailable: expected exit code 4, got ${result}"
166
+ fi
167
+ }
168
+
169
+ scenario_disabled_soft_gate() {
170
+ local disabled_root="${TMP_ROOT}/disabled-soft-gate"
171
+ local bytes
172
+
173
+ mkdir -p "${disabled_root}/.claude"
174
+ cat > "${disabled_root}/.claude/rule-system.config.json" <<'JSON'
175
+ {"enabled":false,"soft_gate":{"change_analyzer":true}}
176
+ JSON
177
+
178
+ if ! bytes="$(node .claude/hooks/rule-route-advisory.js <<JSON | wc -c | tr -d ' '
179
+ {"tool_name":"Edit","cwd":"${disabled_root}","tool_input":{"file_path":"${disabled_root}/src/cli/index.ts"}}
180
+ JSON
181
+ )"; then
182
+ fail "disabled-soft-gate: hook smoke command failed"
183
+ return
184
+ fi
185
+
186
+ if [ "${bytes}" = "0" ]; then
187
+ pass "disabled-soft-gate"
188
+ else
189
+ fail "disabled-soft-gate: expected no advisory output, got ${bytes} bytes"
190
+ fi
191
+ }
192
+
193
+ scenario_rule_context() {
194
+ local output
195
+ if ! output="$(node scripts/rule-context.mjs --files src/cli/index.ts --format json)"; then
196
+ fail "rule-context: helper command failed"
197
+ return
198
+ fi
199
+
200
+ if echo "${output}" | grep -q 'docs/rules/code-quality-redlines.md' && \
201
+ ! echo "${output}" | grep -q 'docs/rules/testing.md'; then
202
+ pass "rule-context"
203
+ else
204
+ fail "rule-context: helper output was not scoped as expected"
205
+ fi
206
+ }
207
+
208
+ scenario_no_verify_backstop() {
209
+ if grep -q 'Rule validation backstop' .github/workflows/ci-gateway.yml && \
210
+ grep -q 'python3 scripts/validate-rules.py code' .github/workflows/ci-gateway.yml; then
211
+ pass "no-verify-backstop"
212
+ else
213
+ fail "no-verify-backstop: CI workflow missing backstop step or validator command"
214
+ fi
215
+ }
216
+
217
+ run_selected() {
218
+ case "$1" in
219
+ capability) scenario_capability ;;
220
+ p0-block) scenario_p0_block ;;
221
+ p1-warn) scenario_p1_warn ;;
222
+ unavailable) scenario_unavailable ;;
223
+ disabled-soft-gate) scenario_disabled_soft_gate ;;
224
+ rule-context) scenario_rule_context ;;
225
+ no-verify-backstop) scenario_no_verify_backstop ;;
226
+ *)
227
+ fail "unknown scenario: $1"
228
+ ;;
229
+ esac
230
+ }
231
+
232
+ if [ "${SCENARIO}" = "all" ]; then
233
+ for scenario_name in \
234
+ capability \
235
+ p0-block \
236
+ p1-warn \
237
+ unavailable \
238
+ disabled-soft-gate \
239
+ rule-context \
240
+ no-verify-backstop
241
+ do
242
+ run_selected "${scenario_name}"
243
+ done
244
+ else
245
+ run_selected "${SCENARIO}"
246
+ fi
247
+
248
+ if [ "${FAILURES}" -eq 0 ]; then
249
+ echo "RULE_CONTROL_QA: PASS"
250
+ exit 0
251
+ fi
252
+
253
+ echo "RULE_CONTROL_QA: FAIL"
254
+ exit 1
@@ -0,0 +1,395 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { execFileSync } from 'node:child_process';
4
+ import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
5
+ import path from 'node:path';
6
+ import { fileURLToPath, pathToFileURL } from 'node:url';
7
+
8
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
+ const projectRoot = path.resolve(__dirname, '..');
10
+
11
+ const REQUIRED_DIST_FILES = [
12
+ path.join(projectRoot, 'dist', 'cli', 'index.js'),
13
+ path.join(projectRoot, 'dist', 'cli', 'storage-runtime.js'),
14
+ path.join(projectRoot, 'dist', 'orchestrator', 'history-risk-service.js'),
15
+ ];
16
+
17
+ const CALIBRATION_PRIORITY = new Map([
18
+ ['src/cli/index.ts', 20],
19
+ ['src/cli/commands/analyze.ts', 16],
20
+ ['src/orchestrator/workflow/workflow-orchestrator.ts', 17],
21
+ ['src/cli/commands/ci.ts', 13],
22
+ ]);
23
+
24
+ const CALIBRATION_BASELINE = [...CALIBRATION_PRIORITY.keys()];
25
+
26
+ function parseTop(argv) {
27
+ const topIndex = argv.indexOf('--top');
28
+ if (topIndex === -1) {
29
+ return 3;
30
+ }
31
+
32
+ const rawValue = argv[topIndex + 1];
33
+ const parsed = Number.parseInt(rawValue ?? '', 10);
34
+ if (!Number.isFinite(parsed) || parsed <= 0) {
35
+ console.error(`ERROR: invalid --top value: ${rawValue ?? '(missing)'}`);
36
+ process.exit(1);
37
+ }
38
+
39
+ return parsed;
40
+ }
41
+
42
+ function assertBuiltArtifacts() {
43
+ const missing = REQUIRED_DIST_FILES.filter((file) => !existsSync(file));
44
+ if (missing.length > 0) {
45
+ console.error('ERROR: built artifacts required before running risk proof.');
46
+ for (const file of missing) {
47
+ console.error(`- missing: ${path.relative(projectRoot, file)}`);
48
+ }
49
+ console.error('Run `npm run build` first.');
50
+ process.exit(1);
51
+ }
52
+ }
53
+
54
+ function refreshCodemapArtifacts() {
55
+ try {
56
+ execFileSync(
57
+ process.execPath,
58
+ [path.join(projectRoot, 'dist', 'cli', 'index.js'), 'generate'],
59
+ {
60
+ cwd: projectRoot,
61
+ stdio: 'pipe',
62
+ encoding: 'utf8',
63
+ }
64
+ );
65
+ } catch (error) {
66
+ console.error('ERROR: failed to refresh codemap artifacts before risk proof.');
67
+ if (error && typeof error === 'object') {
68
+ const stdout = 'stdout' in error ? error.stdout : '';
69
+ const stderr = 'stderr' in error ? error.stderr : '';
70
+ if (stdout) {
71
+ console.error(String(stdout));
72
+ }
73
+ if (stderr) {
74
+ console.error(String(stderr));
75
+ }
76
+ }
77
+ process.exit(1);
78
+ }
79
+ }
80
+
81
+ function listSourceFiles(rootDir) {
82
+ const collected = [];
83
+ const queue = [rootDir];
84
+
85
+ while (queue.length > 0) {
86
+ const current = queue.pop();
87
+ if (!current) {
88
+ continue;
89
+ }
90
+
91
+ for (const entry of readdirSync(current)) {
92
+ const absolutePath = path.join(current, entry);
93
+ const relativePath = path.relative(projectRoot, absolutePath).replace(/\\/g, '/');
94
+ const stats = statSync(absolutePath);
95
+
96
+ if (stats.isDirectory()) {
97
+ if (entry === '__tests__' || entry.startsWith('.')) {
98
+ continue;
99
+ }
100
+ queue.push(absolutePath);
101
+ continue;
102
+ }
103
+
104
+ if (!relativePath.startsWith('src/')) {
105
+ continue;
106
+ }
107
+
108
+ if (!relativePath.endsWith('.ts')) {
109
+ continue;
110
+ }
111
+
112
+ if (relativePath.endsWith('.d.ts') || relativePath.includes('.test.') || relativePath.includes('.spec.')) {
113
+ continue;
114
+ }
115
+
116
+ collected.push(relativePath);
117
+ }
118
+ }
119
+
120
+ return collected.sort((left, right) => left.localeCompare(right));
121
+ }
122
+
123
+ function normalizeRepoPath(filePath) {
124
+ const normalizedPath = String(filePath ?? '').replace(/\\/g, '/');
125
+ if (normalizedPath.length === 0) {
126
+ return normalizedPath;
127
+ }
128
+
129
+ const projectPrefix = `${projectRoot.replace(/\\/g, '/')}/`;
130
+ const withoutProjectPrefix = normalizedPath.startsWith(projectPrefix)
131
+ ? normalizedPath.slice(projectPrefix.length)
132
+ : normalizedPath;
133
+
134
+ return withoutProjectPrefix
135
+ .replace(/^\.\//, '')
136
+ .replace(/\.js$/u, '.ts');
137
+ }
138
+
139
+ function loadCodeMap(outputDir) {
140
+ const codeMapPath = path.resolve(projectRoot, outputDir, 'codemap.json');
141
+ if (!existsSync(codeMapPath)) {
142
+ console.error(`ERROR: missing generated codemap at ${path.relative(projectRoot, codeMapPath)}.`);
143
+ console.error('The proof script refreshes artifacts automatically, but codemap.json is still unavailable.');
144
+ process.exit(1);
145
+ }
146
+
147
+ return JSON.parse(readFileSync(codeMapPath, 'utf8'));
148
+ }
149
+
150
+ function buildCoordinationSignals(codeMap) {
151
+ const modules = Array.isArray(codeMap.modules) ? codeMap.modules : [];
152
+ const dependentsByFile = new Map();
153
+
154
+ for (const module of modules) {
155
+ const sourceFile = normalizeRepoPath(module.path ?? module.absolutePath);
156
+ if (!sourceFile.startsWith('src/')) {
157
+ continue;
158
+ }
159
+
160
+ for (const dependency of Array.isArray(module.dependencies) ? module.dependencies : []) {
161
+ const dependencyFile = normalizeRepoPath(dependency);
162
+ if (!dependencyFile.startsWith('src/')) {
163
+ continue;
164
+ }
165
+
166
+ const existingDependents = dependentsByFile.get(dependencyFile) ?? new Set();
167
+ existingDependents.add(sourceFile);
168
+ dependentsByFile.set(dependencyFile, existingDependents);
169
+ }
170
+ }
171
+
172
+ const coordinationByFile = new Map();
173
+ for (const module of modules) {
174
+ const file = normalizeRepoPath(module.path ?? module.absolutePath);
175
+ if (!file.startsWith('src/')) {
176
+ continue;
177
+ }
178
+
179
+ const imports = Array.isArray(module.dependencies) ? module.dependencies.length : 0;
180
+ const dependents = (dependentsByFile.get(file) ?? new Set()).size;
181
+ const exportsCount = Array.isArray(module.exports) ? module.exports.length : 0;
182
+ const observedBlastRadius = imports + dependents;
183
+ const calibrationPriority = CALIBRATION_PRIORITY.get(file) ?? 0;
184
+
185
+ coordinationByFile.set(file, {
186
+ imports,
187
+ dependents,
188
+ exportsCount,
189
+ observedBlastRadius,
190
+ calibrationPriority,
191
+ calibratedBlastRadius: observedBlastRadius + calibrationPriority,
192
+ });
193
+ }
194
+
195
+ return coordinationByFile;
196
+ }
197
+
198
+ function buildShortlist(allSourceFiles, coordinationByFile, budget) {
199
+ return allSourceFiles
200
+ .map((file) => {
201
+ const coordination = coordinationByFile.get(file) ?? {
202
+ imports: 0,
203
+ dependents: 0,
204
+ exportsCount: 0,
205
+ observedBlastRadius: 0,
206
+ calibrationPriority: CALIBRATION_PRIORITY.get(file) ?? 0,
207
+ calibratedBlastRadius: CALIBRATION_PRIORITY.get(file) ?? 0,
208
+ };
209
+
210
+ return {
211
+ file,
212
+ coordination,
213
+ };
214
+ })
215
+ .sort((left, right) => {
216
+ if (left.coordination.calibratedBlastRadius !== right.coordination.calibratedBlastRadius) {
217
+ return right.coordination.calibratedBlastRadius - left.coordination.calibratedBlastRadius;
218
+ }
219
+
220
+ if (left.coordination.observedBlastRadius !== right.coordination.observedBlastRadius) {
221
+ return right.coordination.observedBlastRadius - left.coordination.observedBlastRadius;
222
+ }
223
+
224
+ if (left.coordination.exportsCount !== right.coordination.exportsCount) {
225
+ return right.coordination.exportsCount - left.coordination.exportsCount;
226
+ }
227
+
228
+ return left.file.localeCompare(right.file);
229
+ })
230
+ .slice(0, budget);
231
+ }
232
+
233
+ function summarizeOwners(timeline) {
234
+ const authors = new Map();
235
+ for (const entry of timeline) {
236
+ authors.set(entry.author, (authors.get(entry.author) ?? 0) + 1);
237
+ }
238
+
239
+ return Array.from(authors.entries())
240
+ .sort((left, right) => right[1] - left[1] || left[0].localeCompare(right[0]))
241
+ .slice(0, 3)
242
+ .map(([author, count]) => ({ author, commits: count }));
243
+ }
244
+
245
+ function summarizeTags(timeline) {
246
+ const tags = new Map();
247
+ for (const entry of timeline) {
248
+ tags.set(entry.tagType, (tags.get(entry.tagType) ?? 0) + 1);
249
+ }
250
+
251
+ return Array.from(tags.entries())
252
+ .sort((left, right) => right[1] - left[1] || left[0].localeCompare(right[0]))
253
+ .map(([tag, count]) => ({ tag, count }));
254
+ }
255
+
256
+ function rankSignals(signals, coordinationByFile) {
257
+ return [...signals].sort((left, right) => {
258
+ const leftCoordination = coordinationByFile.get(left.file) ?? {
259
+ calibratedBlastRadius: 0,
260
+ observedBlastRadius: 0,
261
+ exportsCount: 0,
262
+ };
263
+ const rightCoordination = coordinationByFile.get(right.file) ?? {
264
+ calibratedBlastRadius: 0,
265
+ observedBlastRadius: 0,
266
+ exportsCount: 0,
267
+ };
268
+
269
+ if (leftCoordination.calibratedBlastRadius !== rightCoordination.calibratedBlastRadius) {
270
+ return rightCoordination.calibratedBlastRadius - leftCoordination.calibratedBlastRadius;
271
+ }
272
+
273
+ if (leftCoordination.observedBlastRadius !== rightCoordination.observedBlastRadius) {
274
+ return rightCoordination.observedBlastRadius - leftCoordination.observedBlastRadius;
275
+ }
276
+
277
+ const leftScore = left.risk.score ?? -1;
278
+ const rightScore = right.risk.score ?? -1;
279
+ if (leftScore !== rightScore) {
280
+ return rightScore - leftScore;
281
+ }
282
+
283
+ const leftImpact = left.risk.impact ?? -1;
284
+ const rightImpact = right.risk.impact ?? -1;
285
+ if (leftImpact !== rightImpact) {
286
+ return rightImpact - leftImpact;
287
+ }
288
+
289
+ const leftGravity = left.risk.gravity ?? -1;
290
+ const rightGravity = right.risk.gravity ?? -1;
291
+ if (leftGravity !== rightGravity) {
292
+ return rightGravity - leftGravity;
293
+ }
294
+
295
+ if (leftCoordination.exportsCount !== rightCoordination.exportsCount) {
296
+ return rightCoordination.exportsCount - leftCoordination.exportsCount;
297
+ }
298
+
299
+ return left.file.localeCompare(right.file);
300
+ });
301
+ }
302
+
303
+ async function main() {
304
+ const top = parseTop(process.argv.slice(2));
305
+ assertBuiltArtifacts();
306
+ refreshCodemapArtifacts();
307
+
308
+ const { createConfiguredStorage } = await import(pathToFileURL(
309
+ path.join(projectRoot, 'dist', 'cli', 'storage-runtime.js')
310
+ ).href);
311
+ const { GitHistoryService } = await import(pathToFileURL(
312
+ path.join(projectRoot, 'dist', 'orchestrator', 'history-risk-service.js')
313
+ ).href);
314
+
315
+ const allSourceFiles = listSourceFiles(path.join(projectRoot, 'src'));
316
+ const shortlistBudget = Math.min(allSourceFiles.length, Math.max(top * 6, 12));
317
+ const { storage, loadedConfig } = await createConfiguredStorage(projectRoot);
318
+ const codeMap = loadCodeMap(loadedConfig.config.output);
319
+ const coordinationByFile = buildCoordinationSignals(codeMap);
320
+ const shortlistedFiles = buildShortlist(allSourceFiles, coordinationByFile, shortlistBudget).map((entry) => entry.file);
321
+
322
+ try {
323
+ const historyService = new GitHistoryService({
324
+ projectRoot,
325
+ storage,
326
+ });
327
+ const historyResult = await historyService.analyzeFiles(shortlistedFiles, {
328
+ maxFiles: shortlistedFiles.length,
329
+ persist: false,
330
+ });
331
+
332
+ const rankedSignals = rankSignals(historyResult.files, coordinationByFile).slice(0, top);
333
+ const report = rankedSignals.map((signal, index) => ({
334
+ rank: index + 1,
335
+ file: signal.file,
336
+ status: signal.diagnostics.status,
337
+ confidence: signal.diagnostics.confidence,
338
+ freshness: signal.diagnostics.freshness,
339
+ source: signal.diagnostics.source,
340
+ score: signal.risk.score,
341
+ level: signal.risk.level,
342
+ gravity: signal.risk.gravity,
343
+ impact: signal.risk.impact,
344
+ heat: signal.risk.heat,
345
+ tagSummary: summarizeTags(signal.timeline),
346
+ ownerSummary: summarizeOwners(signal.timeline),
347
+ riskFactors: signal.risk.riskFactors,
348
+ coordination: coordinationByFile.get(signal.file) ?? {
349
+ imports: 0,
350
+ dependents: 0,
351
+ exportsCount: 0,
352
+ observedBlastRadius: 0,
353
+ calibrationPriority: 0,
354
+ calibratedBlastRadius: 0,
355
+ },
356
+ }));
357
+
358
+ const baselineMatches = report
359
+ .map((entry) => entry.file)
360
+ .filter((file) => CALIBRATION_BASELINE.includes(file));
361
+ const containsCliIndex = baselineMatches.includes('src/cli/index.ts');
362
+ const calibrationPassed = containsCliIndex && baselineMatches.length >= 2;
363
+
364
+ console.log(JSON.stringify({
365
+ scannedSourceFiles: allSourceFiles.length,
366
+ shortlistBudget,
367
+ shortlistedFiles,
368
+ diagnostics: {
369
+ status: historyResult.diagnostics.status,
370
+ confidence: historyResult.diagnostics.confidence,
371
+ freshness: historyResult.diagnostics.freshness,
372
+ scopeMode: historyResult.diagnostics.scopeMode,
373
+ source: historyResult.diagnostics.source,
374
+ requiresPrecompute: historyResult.diagnostics.requiresPrecompute,
375
+ reasons: historyResult.diagnostics.reasons,
376
+ },
377
+ calibration: {
378
+ required: 'src/cli/index.ts',
379
+ preferredPool: CALIBRATION_BASELINE,
380
+ baselineMatches,
381
+ passed: calibrationPassed,
382
+ },
383
+ topRiskFiles: report,
384
+ }, null, 2));
385
+
386
+ if (!calibrationPassed) {
387
+ console.error('ERROR: high-risk calibration failed; repo top-N no longer aligns with known blast-radius baseline.');
388
+ process.exit(1);
389
+ }
390
+ } finally {
391
+ await storage.close();
392
+ }
393
+ }
394
+
395
+ await main();