@dommaker/harness 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (532) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +0 -2
  3. package/bin/harness.js +86 -32
  4. package/dist/cli/command-contract.d.ts +83 -0
  5. package/dist/cli/command-contract.d.ts.map +1 -0
  6. package/dist/cli/command-contract.js +66 -0
  7. package/dist/cli/command-contract.js.map +1 -0
  8. package/dist/cli/commands/acceptance.d.ts +3 -2
  9. package/dist/cli/commands/acceptance.d.ts.map +1 -1
  10. package/dist/cli/commands/acceptance.js +28 -24
  11. package/dist/cli/commands/acceptance.js.map +1 -1
  12. package/dist/cli/commands/analyze-sessions.d.ts +2 -1
  13. package/dist/cli/commands/analyze-sessions.d.ts.map +1 -1
  14. package/dist/cli/commands/analyze-sessions.js +25 -24
  15. package/dist/cli/commands/analyze-sessions.js.map +1 -1
  16. package/dist/cli/commands/check.d.ts +14 -2
  17. package/dist/cli/commands/check.d.ts.map +1 -1
  18. package/dist/cli/commands/check.js +104 -61
  19. package/dist/cli/commands/check.js.map +1 -1
  20. package/dist/cli/commands/command.d.ts +5 -1
  21. package/dist/cli/commands/command.d.ts.map +1 -1
  22. package/dist/cli/commands/command.js +26 -17
  23. package/dist/cli/commands/command.js.map +1 -1
  24. package/dist/cli/commands/constraints-report.d.ts +2 -1
  25. package/dist/cli/commands/constraints-report.d.ts.map +1 -1
  26. package/dist/cli/commands/constraints-report.js +37 -33
  27. package/dist/cli/commands/constraints-report.js.map +1 -1
  28. package/dist/cli/commands/constraints-retire.d.ts +6 -5
  29. package/dist/cli/commands/constraints-retire.d.ts.map +1 -1
  30. package/dist/cli/commands/constraints-retire.js +50 -52
  31. package/dist/cli/commands/constraints-retire.js.map +1 -1
  32. package/dist/cli/commands/constraints.d.ts +2 -1
  33. package/dist/cli/commands/constraints.d.ts.map +1 -1
  34. package/dist/cli/commands/constraints.js +10 -27
  35. package/dist/cli/commands/constraints.js.map +1 -1
  36. package/dist/cli/commands/contract.d.ts +3 -2
  37. package/dist/cli/commands/contract.d.ts.map +1 -1
  38. package/dist/cli/commands/contract.js +45 -42
  39. package/dist/cli/commands/contract.js.map +1 -1
  40. package/dist/cli/commands/definitions.d.ts +11 -11
  41. package/dist/cli/commands/definitions.d.ts.map +1 -1
  42. package/dist/cli/commands/definitions.js +27 -219
  43. package/dist/cli/commands/definitions.js.map +1 -1
  44. package/dist/cli/commands/failure.d.ts +5 -4
  45. package/dist/cli/commands/failure.d.ts.map +1 -1
  46. package/dist/cli/commands/failure.js +31 -25
  47. package/dist/cli/commands/failure.js.map +1 -1
  48. package/dist/cli/commands/init.d.ts +7 -5
  49. package/dist/cli/commands/init.d.ts.map +1 -1
  50. package/dist/cli/commands/init.js +147 -211
  51. package/dist/cli/commands/init.js.map +1 -1
  52. package/dist/cli/commands/knowledge.d.ts +17 -30
  53. package/dist/cli/commands/knowledge.d.ts.map +1 -1
  54. package/dist/cli/commands/knowledge.js +183 -273
  55. package/dist/cli/commands/knowledge.js.map +1 -1
  56. package/dist/cli/commands/passes-gate.d.ts +8 -2
  57. package/dist/cli/commands/passes-gate.d.ts.map +1 -1
  58. package/dist/cli/commands/passes-gate.js +44 -66
  59. package/dist/cli/commands/passes-gate.js.map +1 -1
  60. package/dist/cli/commands/performance.d.ts +2 -1
  61. package/dist/cli/commands/performance.d.ts.map +1 -1
  62. package/dist/cli/commands/performance.js +20 -18
  63. package/dist/cli/commands/performance.js.map +1 -1
  64. package/dist/cli/commands/posteval-plan.d.ts +5 -1
  65. package/dist/cli/commands/posteval-plan.d.ts.map +1 -1
  66. package/dist/cli/commands/posteval-plan.js +26 -15
  67. package/dist/cli/commands/posteval-plan.js.map +1 -1
  68. package/dist/cli/commands/release.d.ts +6 -1
  69. package/dist/cli/commands/release.d.ts.map +1 -1
  70. package/dist/cli/commands/release.js +69 -59
  71. package/dist/cli/commands/release.js.map +1 -1
  72. package/dist/cli/commands/report.d.ts +2 -1
  73. package/dist/cli/commands/report.d.ts.map +1 -1
  74. package/dist/cli/commands/report.js +9 -5
  75. package/dist/cli/commands/report.js.map +1 -1
  76. package/dist/cli/commands/review.d.ts +3 -2
  77. package/dist/cli/commands/review.d.ts.map +1 -1
  78. package/dist/cli/commands/review.js +33 -29
  79. package/dist/cli/commands/review.js.map +1 -1
  80. package/dist/cli/commands/sdd.d.ts +2 -1
  81. package/dist/cli/commands/sdd.d.ts.map +1 -1
  82. package/dist/cli/commands/sdd.js +7 -5
  83. package/dist/cli/commands/sdd.js.map +1 -1
  84. package/dist/cli/commands/security.d.ts +3 -2
  85. package/dist/cli/commands/security.d.ts.map +1 -1
  86. package/dist/cli/commands/security.js +29 -26
  87. package/dist/cli/commands/security.js.map +1 -1
  88. package/dist/cli/commands/spec-baseline-check.d.ts +2 -1
  89. package/dist/cli/commands/spec-baseline-check.d.ts.map +1 -1
  90. package/dist/cli/commands/spec-baseline-check.js +15 -11
  91. package/dist/cli/commands/spec-baseline-check.js.map +1 -1
  92. package/dist/cli/commands/spec.d.ts +7 -2
  93. package/dist/cli/commands/spec.d.ts.map +1 -1
  94. package/dist/cli/commands/spec.js +61 -51
  95. package/dist/cli/commands/spec.js.map +1 -1
  96. package/dist/cli/commands/status.d.ts +2 -1
  97. package/dist/cli/commands/status.d.ts.map +1 -1
  98. package/dist/cli/commands/status.js +57 -53
  99. package/dist/cli/commands/status.js.map +1 -1
  100. package/dist/cli/commands/sync-docs/agents-syncer.d.ts.map +1 -1
  101. package/dist/cli/commands/sync-docs/agents-syncer.js +5 -2
  102. package/dist/cli/commands/sync-docs/agents-syncer.js.map +1 -1
  103. package/dist/cli/commands/sync-docs/context-syncer.d.ts.map +1 -1
  104. package/dist/cli/commands/sync-docs/context-syncer.js +3 -2
  105. package/dist/cli/commands/sync-docs/context-syncer.js.map +1 -1
  106. package/dist/cli/commands/sync-docs/index.d.ts +2 -1
  107. package/dist/cli/commands/sync-docs/index.d.ts.map +1 -1
  108. package/dist/cli/commands/sync-docs/index.js +68 -88
  109. package/dist/cli/commands/sync-docs/index.js.map +1 -1
  110. package/dist/cli/commands/sync-docs/project-reader.d.ts +6 -1
  111. package/dist/cli/commands/sync-docs/project-reader.d.ts.map +1 -1
  112. package/dist/cli/commands/sync-docs/project-reader.js +14 -16
  113. package/dist/cli/commands/sync-docs/project-reader.js.map +1 -1
  114. package/dist/cli/commands/update-user-model.d.ts +9 -3
  115. package/dist/cli/commands/update-user-model.d.ts.map +1 -1
  116. package/dist/cli/commands/update-user-model.js +56 -61
  117. package/dist/cli/commands/update-user-model.js.map +1 -1
  118. package/dist/cli/commands/validate.d.ts +4 -3
  119. package/dist/cli/commands/validate.d.ts.map +1 -1
  120. package/dist/cli/commands/validate.js +28 -26
  121. package/dist/cli/commands/validate.js.map +1 -1
  122. package/dist/cli/session-mining/transcript.d.ts +7 -1
  123. package/dist/cli/session-mining/transcript.d.ts.map +1 -1
  124. package/dist/cli/session-mining/transcript.js +21 -14
  125. package/dist/cli/session-mining/transcript.js.map +1 -1
  126. package/dist/context/session-manager.d.ts.map +1 -1
  127. package/dist/context/session-manager.js +19 -32
  128. package/dist/context/session-manager.js.map +1 -1
  129. package/dist/core/constraints/agent-prompt-renderer.d.ts.map +1 -1
  130. package/dist/core/constraints/agent-prompt-renderer.js +1 -4
  131. package/dist/core/constraints/agent-prompt-renderer.js.map +1 -1
  132. package/dist/core/constraints/capabilities-parser.d.ts +24 -7
  133. package/dist/core/constraints/capabilities-parser.d.ts.map +1 -1
  134. package/dist/core/constraints/capabilities-parser.js +32 -28
  135. package/dist/core/constraints/capabilities-parser.js.map +1 -1
  136. package/dist/core/constraints/capabilities-reconcile.d.ts +67 -0
  137. package/dist/core/constraints/capabilities-reconcile.d.ts.map +1 -0
  138. package/dist/core/constraints/capabilities-reconcile.js +105 -0
  139. package/dist/core/constraints/capabilities-reconcile.js.map +1 -0
  140. package/dist/core/constraints/checker.d.ts +21 -43
  141. package/dist/core/constraints/checker.d.ts.map +1 -1
  142. package/dist/core/constraints/checker.js +68 -117
  143. package/dist/core/constraints/checker.js.map +1 -1
  144. package/dist/core/constraints/checkers/capability-sync.d.ts +20 -8
  145. package/dist/core/constraints/checkers/capability-sync.d.ts.map +1 -1
  146. package/dist/core/constraints/checkers/capability-sync.js +66 -77
  147. package/dist/core/constraints/checkers/capability-sync.js.map +1 -1
  148. package/dist/core/constraints/checkers/context-doc-sync.d.ts +4 -2
  149. package/dist/core/constraints/checkers/context-doc-sync.d.ts.map +1 -1
  150. package/dist/core/constraints/checkers/context-doc-sync.js +13 -22
  151. package/dist/core/constraints/checkers/context-doc-sync.js.map +1 -1
  152. package/dist/core/constraints/checkers/docs-freshness.d.ts.map +1 -1
  153. package/dist/core/constraints/checkers/docs-freshness.js +49 -66
  154. package/dist/core/constraints/checkers/docs-freshness.js.map +1 -1
  155. package/dist/core/constraints/checkers/governance-presence.d.ts +2 -2
  156. package/dist/core/constraints/checkers/governance-presence.d.ts.map +1 -1
  157. package/dist/core/constraints/checkers/governance-presence.js +7 -28
  158. package/dist/core/constraints/checkers/governance-presence.js.map +1 -1
  159. package/dist/core/constraints/checkers/index.d.ts +2 -2
  160. package/dist/core/constraints/checkers/index.d.ts.map +1 -1
  161. package/dist/core/constraints/checkers/index.js +2 -1
  162. package/dist/core/constraints/checkers/index.js.map +1 -1
  163. package/dist/core/constraints/checkers/no-test-simplification.d.ts.map +1 -1
  164. package/dist/core/constraints/checkers/no-test-simplification.js +4 -3
  165. package/dist/core/constraints/checkers/no-test-simplification.js.map +1 -1
  166. package/dist/core/constraints/checkers/types.d.ts +43 -4
  167. package/dist/core/constraints/checkers/types.d.ts.map +1 -1
  168. package/dist/core/constraints/checkers/types.js +33 -0
  169. package/dist/core/constraints/checkers/types.js.map +1 -1
  170. package/dist/core/constraints/context-builder.d.ts +15 -14
  171. package/dist/core/constraints/context-builder.d.ts.map +1 -1
  172. package/dist/core/constraints/context-builder.js +32 -96
  173. package/dist/core/constraints/context-builder.js.map +1 -1
  174. package/dist/core/constraints/doc-freshness/runner.d.ts.map +1 -1
  175. package/dist/core/constraints/doc-freshness/runner.js +2 -1
  176. package/dist/core/constraints/doc-freshness/runner.js.map +1 -1
  177. package/dist/core/constraints/git-evidence.d.ts +60 -0
  178. package/dist/core/constraints/git-evidence.d.ts.map +1 -0
  179. package/dist/core/constraints/git-evidence.js +88 -0
  180. package/dist/core/constraints/git-evidence.js.map +1 -0
  181. package/dist/core/constraints/injection-drift.d.ts +3 -20
  182. package/dist/core/constraints/injection-drift.d.ts.map +1 -1
  183. package/dist/core/constraints/injection-drift.js +10 -57
  184. package/dist/core/constraints/injection-drift.js.map +1 -1
  185. package/dist/core/constraints/injection-writer.d.ts +113 -0
  186. package/dist/core/constraints/injection-writer.d.ts.map +1 -0
  187. package/dist/core/constraints/injection-writer.js +228 -0
  188. package/dist/core/constraints/injection-writer.js.map +1 -0
  189. package/dist/core/constraints/usage-report.d.ts +22 -1
  190. package/dist/core/constraints/usage-report.d.ts.map +1 -1
  191. package/dist/core/constraints/usage-report.js +27 -20
  192. package/dist/core/constraints/usage-report.js.map +1 -1
  193. package/dist/core/index.d.ts +2 -2
  194. package/dist/core/index.d.ts.map +1 -1
  195. package/dist/core/index.js +4 -2
  196. package/dist/core/index.js.map +1 -1
  197. package/dist/core/project-config-loader.d.ts +32 -1
  198. package/dist/core/project-config-loader.d.ts.map +1 -1
  199. package/dist/core/project-config-loader.js +39 -9
  200. package/dist/core/project-config-loader.js.map +1 -1
  201. package/dist/core/validators/passes-gate.d.ts +15 -64
  202. package/dist/core/validators/passes-gate.d.ts.map +1 -1
  203. package/dist/core/validators/passes-gate.js +84 -222
  204. package/dist/core/validators/passes-gate.js.map +1 -1
  205. package/dist/core/validators/test-output.d.ts +58 -0
  206. package/dist/core/validators/test-output.d.ts.map +1 -0
  207. package/dist/core/validators/test-output.js +109 -0
  208. package/dist/core/validators/test-output.js.map +1 -0
  209. package/dist/failure/recorder.d.ts +6 -0
  210. package/dist/failure/recorder.d.ts.map +1 -1
  211. package/dist/failure/recorder.js +12 -8
  212. package/dist/failure/recorder.js.map +1 -1
  213. package/dist/gates/acceptance.d.ts +1 -48
  214. package/dist/gates/acceptance.d.ts.map +1 -1
  215. package/dist/gates/acceptance.js +6 -38
  216. package/dist/gates/acceptance.js.map +1 -1
  217. package/dist/gates/checker-gate.d.ts +2 -1
  218. package/dist/gates/checker-gate.d.ts.map +1 -1
  219. package/dist/gates/checker-gate.js +11 -13
  220. package/dist/gates/checker-gate.js.map +1 -1
  221. package/dist/gates/command.d.ts.map +1 -1
  222. package/dist/gates/command.js +10 -22
  223. package/dist/gates/command.js.map +1 -1
  224. package/dist/gates/contract.d.ts.map +1 -1
  225. package/dist/gates/contract.js +22 -61
  226. package/dist/gates/contract.js.map +1 -1
  227. package/dist/gates/performance.d.ts.map +1 -1
  228. package/dist/gates/performance.js +13 -31
  229. package/dist/gates/performance.js.map +1 -1
  230. package/dist/gates/review.d.ts.map +1 -1
  231. package/dist/gates/review.js +21 -53
  232. package/dist/gates/review.js.map +1 -1
  233. package/dist/gates/security.d.ts.map +1 -1
  234. package/dist/gates/security.js +14 -32
  235. package/dist/gates/security.js.map +1 -1
  236. package/dist/gates/types.d.ts +28 -5
  237. package/dist/gates/types.d.ts.map +1 -1
  238. package/dist/gates/types.js +38 -1
  239. package/dist/gates/types.js.map +1 -1
  240. package/dist/hooks/bootstrap.d.ts +2 -0
  241. package/dist/hooks/bootstrap.d.ts.map +1 -1
  242. package/dist/hooks/bootstrap.js +5 -2
  243. package/dist/hooks/bootstrap.js.map +1 -1
  244. package/dist/index.d.ts +1 -2
  245. package/dist/index.d.ts.map +1 -1
  246. package/dist/index.js.map +1 -1
  247. package/dist/knowledge/audit.d.ts +7 -2
  248. package/dist/knowledge/audit.d.ts.map +1 -1
  249. package/dist/knowledge/audit.js +59 -79
  250. package/dist/knowledge/audit.js.map +1 -1
  251. package/dist/knowledge/flywheel-metrics.d.ts +39 -0
  252. package/dist/knowledge/flywheel-metrics.d.ts.map +1 -0
  253. package/dist/knowledge/flywheel-metrics.js +47 -0
  254. package/dist/knowledge/flywheel-metrics.js.map +1 -0
  255. package/dist/knowledge/import.d.ts.map +1 -1
  256. package/dist/knowledge/import.js +4 -14
  257. package/dist/knowledge/import.js.map +1 -1
  258. package/dist/knowledge/index-generator.d.ts.map +1 -1
  259. package/dist/knowledge/index-generator.js +17 -14
  260. package/dist/knowledge/index-generator.js.map +1 -1
  261. package/dist/knowledge/ingest.d.ts.map +1 -1
  262. package/dist/knowledge/ingest.js +9 -4
  263. package/dist/knowledge/ingest.js.map +1 -1
  264. package/dist/knowledge/migration.d.ts.map +1 -1
  265. package/dist/knowledge/migration.js +11 -8
  266. package/dist/knowledge/migration.js.map +1 -1
  267. package/dist/knowledge/reference-tracker.d.ts.map +1 -1
  268. package/dist/knowledge/reference-tracker.js +12 -9
  269. package/dist/knowledge/reference-tracker.js.map +1 -1
  270. package/dist/knowledge/store.d.ts +15 -0
  271. package/dist/knowledge/store.d.ts.map +1 -1
  272. package/dist/knowledge/store.js +59 -10
  273. package/dist/knowledge/store.js.map +1 -1
  274. package/dist/monitoring/context-tracker.d.ts.map +1 -1
  275. package/dist/monitoring/context-tracker.js +11 -20
  276. package/dist/monitoring/context-tracker.js.map +1 -1
  277. package/dist/monitoring/index.d.ts +1 -1
  278. package/dist/monitoring/index.d.ts.map +1 -1
  279. package/dist/monitoring/index.js +1 -2
  280. package/dist/monitoring/index.js.map +1 -1
  281. package/dist/monitoring/trace-analyzer.d.ts +15 -0
  282. package/dist/monitoring/trace-analyzer.d.ts.map +1 -1
  283. package/dist/monitoring/trace-analyzer.js +19 -2
  284. package/dist/monitoring/trace-analyzer.js.map +1 -1
  285. package/dist/monitoring/traces.d.ts +21 -2
  286. package/dist/monitoring/traces.d.ts.map +1 -1
  287. package/dist/monitoring/traces.js +38 -29
  288. package/dist/monitoring/traces.js.map +1 -1
  289. package/dist/release/index.d.ts +2 -2
  290. package/dist/release/index.d.ts.map +1 -1
  291. package/dist/release/index.js +1 -5
  292. package/dist/release/index.js.map +1 -1
  293. package/dist/sdd/index-generator.js +10 -11
  294. package/dist/sdd/index-generator.js.map +1 -1
  295. package/dist/test-setup/project-fixture.d.ts +48 -0
  296. package/dist/test-setup/project-fixture.d.ts.map +1 -0
  297. package/dist/test-setup/project-fixture.js +106 -0
  298. package/dist/test-setup/project-fixture.js.map +1 -0
  299. package/dist/types/constraint.d.ts +8 -18
  300. package/dist/types/constraint.d.ts.map +1 -1
  301. package/dist/types/constraint.js +6 -1
  302. package/dist/types/constraint.js.map +1 -1
  303. package/dist/types/passes-gate.d.ts +10 -25
  304. package/dist/types/passes-gate.d.ts.map +1 -1
  305. package/dist/types/project-config.d.ts +1 -1
  306. package/dist/types/session.d.ts +6 -5
  307. package/dist/types/session.d.ts.map +1 -1
  308. package/dist/types/trace.d.ts +9 -0
  309. package/dist/types/trace.d.ts.map +1 -1
  310. package/dist/utils/exec.d.ts +10 -0
  311. package/dist/utils/exec.d.ts.map +1 -1
  312. package/dist/utils/exec.js +12 -0
  313. package/dist/utils/exec.js.map +1 -1
  314. package/dist/utils/file-walk.d.ts +9 -1
  315. package/dist/utils/file-walk.d.ts.map +1 -1
  316. package/dist/utils/file-walk.js +10 -1
  317. package/dist/utils/file-walk.js.map +1 -1
  318. package/dist/utils/frontmatter.d.ts +73 -0
  319. package/dist/utils/frontmatter.d.ts.map +1 -0
  320. package/dist/utils/frontmatter.js +141 -0
  321. package/dist/utils/frontmatter.js.map +1 -0
  322. package/dist/utils/jsonl.d.ts +92 -0
  323. package/dist/utils/jsonl.d.ts.map +1 -0
  324. package/dist/utils/jsonl.js +166 -0
  325. package/dist/utils/jsonl.js.map +1 -0
  326. package/dist/utils/package-version.d.ts +16 -0
  327. package/dist/utils/package-version.d.ts.map +1 -0
  328. package/dist/utils/package-version.js +63 -0
  329. package/dist/utils/package-version.js.map +1 -0
  330. package/package.json +1 -1
  331. package/src/CONTEXT.md +8 -2
  332. package/src/__tests__/acceptance-gate.test.ts +3 -1
  333. package/src/__tests__/checker-extra.test.ts +7 -1218
  334. package/src/__tests__/context-files-resolution.test.ts +116 -0
  335. package/src/__tests__/effective-constraints.test.ts +10 -13
  336. package/src/__tests__/exec.test.ts +35 -1
  337. package/src/__tests__/layering.test.ts +152 -0
  338. package/src/__tests__/passes-gate-extra.test.ts +0 -145
  339. package/src/__tests__/passes-gate.test.ts +130 -101
  340. package/src/__tests__/skip-semantics.test.ts +5 -9
  341. package/src/cli/__tests__/command-contract.test.ts +170 -0
  342. package/src/cli/command-contract.ts +108 -0
  343. package/src/cli/commands/CONTEXT.md +23 -8
  344. package/src/cli/commands/__tests__/acceptance.test.ts +40 -33
  345. package/src/cli/commands/__tests__/analyze-sessions.test.ts +35 -29
  346. package/src/cli/commands/__tests__/bin-exit-mapping.test.ts +107 -0
  347. package/src/cli/commands/__tests__/check-drift.test.ts +27 -34
  348. package/src/cli/commands/__tests__/check-skip-output.test.ts +21 -24
  349. package/src/cli/commands/__tests__/check.test.ts +448 -378
  350. package/src/cli/commands/__tests__/command.test.ts +85 -70
  351. package/src/cli/commands/__tests__/constraints-report.test.ts +100 -71
  352. package/src/cli/commands/__tests__/constraints-retire.test.ts +152 -95
  353. package/src/cli/commands/__tests__/contract.test.ts +27 -34
  354. package/src/cli/commands/__tests__/failure.test.ts +31 -34
  355. package/src/cli/commands/__tests__/init-injection.test.ts +58 -28
  356. package/src/cli/commands/__tests__/init.test.ts +77 -48
  357. package/src/cli/commands/__tests__/knowledge-flywheel-consistency.test.ts +108 -0
  358. package/src/cli/commands/__tests__/knowledge.test.ts +69 -43
  359. package/src/cli/commands/__tests__/passes-gate.test.ts +43 -45
  360. package/src/cli/commands/__tests__/performance.test.ts +22 -23
  361. package/src/cli/commands/__tests__/posteval-plan.test.ts +39 -38
  362. package/src/cli/commands/__tests__/project-path-anchoring.test.ts +157 -0
  363. package/src/cli/commands/__tests__/project-path-convention.test.ts +231 -0
  364. package/src/cli/commands/__tests__/registry.test.ts +75 -35
  365. package/src/cli/commands/__tests__/release.test.ts +209 -80
  366. package/src/cli/commands/__tests__/report-extra.test.ts +16 -16
  367. package/src/cli/commands/__tests__/report.test.ts +25 -25
  368. package/src/cli/commands/__tests__/review.test.ts +33 -31
  369. package/src/cli/commands/__tests__/security.test.ts +23 -27
  370. package/src/cli/commands/__tests__/spec-baseline-check.test.ts +20 -20
  371. package/src/cli/commands/__tests__/spec.test.ts +41 -29
  372. package/src/cli/commands/__tests__/status-extra.test.ts +18 -18
  373. package/src/cli/commands/__tests__/status-skipped-lines.test.ts +72 -0
  374. package/src/cli/commands/__tests__/status.test.ts +34 -34
  375. package/src/cli/commands/__tests__/sync-docs-agents.test.ts +77 -78
  376. package/src/cli/commands/__tests__/sync-docs.test.ts +72 -74
  377. package/src/cli/commands/__tests__/update-user-model.test.ts +97 -34
  378. package/src/cli/commands/__tests__/validate.test.ts +27 -29
  379. package/src/cli/commands/acceptance.ts +35 -24
  380. package/src/cli/commands/analyze-sessions.ts +25 -24
  381. package/src/cli/commands/check.ts +127 -66
  382. package/src/cli/commands/command.ts +30 -17
  383. package/src/cli/commands/constraints-report.ts +37 -34
  384. package/src/cli/commands/constraints-retire.ts +58 -55
  385. package/src/cli/commands/constraints.ts +10 -27
  386. package/src/cli/commands/contract.ts +51 -42
  387. package/src/cli/commands/definitions.ts +34 -227
  388. package/src/cli/commands/failure.ts +33 -26
  389. package/src/cli/commands/init.ts +166 -220
  390. package/src/cli/commands/knowledge.ts +192 -289
  391. package/src/cli/commands/passes-gate.ts +58 -68
  392. package/src/cli/commands/performance.ts +23 -18
  393. package/src/cli/commands/posteval-plan.ts +29 -15
  394. package/src/cli/commands/release.ts +70 -59
  395. package/src/cli/commands/report.ts +9 -5
  396. package/src/cli/commands/review.ts +39 -29
  397. package/src/cli/commands/sdd.ts +7 -5
  398. package/src/cli/commands/security.ts +35 -26
  399. package/src/cli/commands/spec-baseline-check.ts +16 -11
  400. package/src/cli/commands/spec.ts +66 -53
  401. package/src/cli/commands/status.ts +59 -53
  402. package/src/cli/commands/sync-docs/agents-syncer.ts +5 -2
  403. package/src/cli/commands/sync-docs/context-syncer.ts +3 -2
  404. package/src/cli/commands/sync-docs/index.ts +73 -100
  405. package/src/cli/commands/sync-docs/project-reader.ts +17 -18
  406. package/src/cli/commands/update-user-model.ts +64 -61
  407. package/src/cli/commands/validate.ts +31 -25
  408. package/src/cli/session-mining/__tests__/transcript.test.ts +118 -0
  409. package/src/cli/session-mining/transcript.ts +26 -8
  410. package/src/context/session-manager.ts +19 -33
  411. package/src/core/CONTEXT.md +10 -6
  412. package/src/core/constraints/__tests__/capabilities-reconcile.test.ts +200 -0
  413. package/src/core/constraints/__tests__/capability-counts.test.ts +94 -0
  414. package/src/core/constraints/__tests__/git-evidence.test.ts +208 -0
  415. package/src/core/constraints/__tests__/injection-drift.test.ts +3 -10
  416. package/src/core/constraints/__tests__/injection-writer.test.ts +231 -0
  417. package/src/core/constraints/__tests__/trace-injection.test.ts +71 -0
  418. package/src/core/constraints/__tests__/usage-report.test.ts +112 -0
  419. package/src/core/constraints/agent-prompt-renderer.ts +2 -6
  420. package/src/core/constraints/capabilities-parser.ts +53 -35
  421. package/src/core/constraints/capabilities-reconcile.ts +166 -0
  422. package/src/core/constraints/checker.ts +82 -133
  423. package/src/core/constraints/checkers/__tests__/capability-sync.test.ts +273 -0
  424. package/src/core/constraints/checkers/__tests__/check-outcome.test.ts +176 -0
  425. package/src/core/constraints/checkers/__tests__/context-doc-sync.test.ts +77 -0
  426. package/src/core/constraints/checkers/__tests__/docs-freshness.test.ts +126 -0
  427. package/src/{__tests__ → core/constraints/checkers/__tests__}/governance-presence.test.ts +83 -9
  428. package/src/core/constraints/checkers/__tests__/iron-flags.test.ts +50 -0
  429. package/src/core/constraints/checkers/__tests__/no-bypass-checkpoint.test.ts +76 -0
  430. package/src/{__tests__ → core/constraints/checkers/__tests__}/no-hardcoded-credentials.test.ts +4 -3
  431. package/src/core/constraints/checkers/__tests__/no-test-simplification.test.ts +58 -0
  432. package/src/core/constraints/checkers/__tests__/three-state-consistency.test.ts +153 -0
  433. package/src/core/constraints/checkers/capability-sync.ts +75 -96
  434. package/src/core/constraints/checkers/context-doc-sync.ts +15 -25
  435. package/src/core/constraints/checkers/docs-freshness.ts +54 -70
  436. package/src/core/constraints/checkers/governance-presence.ts +7 -25
  437. package/src/core/constraints/checkers/index.ts +9 -2
  438. package/src/core/constraints/checkers/no-test-simplification.ts +4 -3
  439. package/src/core/constraints/checkers/types.ts +60 -4
  440. package/src/core/constraints/context-builder.ts +39 -91
  441. package/src/core/constraints/doc-freshness/runner.ts +2 -1
  442. package/src/core/constraints/git-evidence.ts +120 -0
  443. package/src/core/constraints/injection-drift.ts +13 -60
  444. package/src/core/constraints/injection-writer.ts +212 -0
  445. package/src/core/constraints/usage-report.ts +36 -17
  446. package/src/core/index.ts +4 -2
  447. package/src/core/project-config-loader.ts +49 -9
  448. package/src/core/validators/__tests__/passes-gate.test.ts +2 -56
  449. package/src/core/validators/__tests__/test-output.test.ts +372 -0
  450. package/src/core/validators/passes-gate.ts +86 -248
  451. package/src/core/validators/test-output.ts +128 -0
  452. package/src/failure/__tests__/recorder.test.ts +168 -0
  453. package/src/failure/recorder.ts +12 -10
  454. package/src/gates/CONTEXT.md +7 -4
  455. package/src/gates/__tests__/acceptance-types-single-source.test.ts +68 -0
  456. package/src/gates/__tests__/acceptance.test.ts +4 -86
  457. package/src/gates/__tests__/checker-gate.test.ts +24 -0
  458. package/src/gates/__tests__/effective-gates.test.ts +3 -8
  459. package/src/gates/__tests__/test-verdict-consistency.test.ts +140 -0
  460. package/src/gates/acceptance.ts +19 -84
  461. package/src/gates/checker-gate.ts +12 -15
  462. package/src/gates/command.ts +10 -16
  463. package/src/gates/contract.ts +22 -61
  464. package/src/gates/performance.ts +10 -22
  465. package/src/gates/review.ts +21 -41
  466. package/src/gates/security.ts +10 -22
  467. package/src/gates/types.ts +70 -5
  468. package/src/hooks/CONTEXT.md +1 -1
  469. package/src/hooks/bootstrap.ts +5 -2
  470. package/src/index.ts +0 -4
  471. package/src/knowledge/CONTEXT.md +8 -3
  472. package/src/knowledge/__tests__/audit-labels.test.ts +44 -0
  473. package/src/knowledge/__tests__/flywheel-metrics.test.ts +135 -0
  474. package/src/knowledge/__tests__/import.test.ts +44 -0
  475. package/src/knowledge/__tests__/index-generator.test.ts +53 -0
  476. package/src/knowledge/__tests__/ingest.test.ts +85 -0
  477. package/src/knowledge/__tests__/migration.test.ts +47 -0
  478. package/src/knowledge/__tests__/reference-tracker.test.ts +16 -0
  479. package/src/knowledge/__tests__/store.test.ts +194 -0
  480. package/src/knowledge/audit.ts +67 -71
  481. package/src/knowledge/flywheel-metrics.ts +71 -0
  482. package/src/knowledge/import.ts +4 -18
  483. package/src/knowledge/index-generator.ts +19 -14
  484. package/src/knowledge/ingest.ts +9 -4
  485. package/src/knowledge/migration.ts +11 -8
  486. package/src/knowledge/reference-tracker.ts +12 -8
  487. package/src/knowledge/store.ts +64 -11
  488. package/src/monitoring/CONTEXT.md +8 -3
  489. package/src/monitoring/__tests__/skipped-lines-report.test.ts +178 -0
  490. package/src/monitoring/__tests__/traces.test.ts +57 -0
  491. package/src/monitoring/context-tracker.ts +11 -23
  492. package/src/monitoring/index.ts +1 -1
  493. package/src/monitoring/trace-analyzer.ts +21 -2
  494. package/src/monitoring/traces.ts +39 -36
  495. package/src/release/CONTEXT.md +1 -0
  496. package/src/release/__tests__/barrel.test.ts +60 -0
  497. package/src/release/index.ts +2 -13
  498. package/src/sdd/__tests__/index-generator.test.ts +71 -0
  499. package/src/sdd/index-generator.ts +9 -9
  500. package/src/test-setup/__tests__/project-fixture.test.ts +178 -0
  501. package/src/test-setup/project-fixture.ts +87 -0
  502. package/src/tools/CONTEXT.md +6 -0
  503. package/src/tools/__tests__/registry.test.ts +221 -0
  504. package/src/types/__tests__/types.test.ts +4 -5
  505. package/src/types/constraint.ts +16 -27
  506. package/src/types/passes-gate.ts +10 -30
  507. package/src/types/project-config.ts +1 -1
  508. package/src/types/session.ts +5 -5
  509. package/src/types/trace.ts +10 -0
  510. package/src/utils/__tests__/frontmatter.test.ts +206 -0
  511. package/src/utils/__tests__/jsonl-skip-disposition.test.ts +175 -0
  512. package/src/utils/__tests__/jsonl.test.ts +187 -0
  513. package/src/utils/__tests__/package-version.test.ts +97 -0
  514. package/src/utils/exec.ts +15 -0
  515. package/src/utils/file-walk.ts +11 -2
  516. package/src/utils/frontmatter.ts +121 -0
  517. package/src/utils/jsonl.ts +167 -0
  518. package/src/utils/package-version.ts +27 -0
  519. package/dist/cli/commands/doc-freshness-check.d.ts +0 -53
  520. package/dist/cli/commands/doc-freshness-check.d.ts.map +0 -1
  521. package/dist/cli/commands/doc-freshness-check.js +0 -352
  522. package/dist/cli/commands/doc-freshness-check.js.map +0 -1
  523. package/dist/types/index.d.ts +0 -14
  524. package/dist/types/index.d.ts.map +0 -1
  525. package/dist/types/index.js +0 -39
  526. package/dist/types/index.js.map +0 -1
  527. package/src/__tests__/long-running.test.ts +0 -17
  528. package/src/__tests__/passes-gate-extension.test.ts +0 -151
  529. package/src/cli/commands/__tests__/doc-freshness-check.test.ts +0 -168
  530. package/src/cli/commands/doc-freshness-check.ts +0 -386
  531. package/src/spec/CONTEXT.md +0 -11
  532. package/src/types/index.ts +0 -47
@@ -0,0 +1,166 @@
1
+ /**
2
+ * CAPABILITIES.md 声明与代码实况的对照判定(ADR-0009)
3
+ *
4
+ * 纯判定 module:吃「文档内容 + 实际文件清单(+ 增量清单)」,一次产出全部判定结果;
5
+ * 不做任何 fs/git IO(存在性可选注入)。此前同一套覆盖/幽灵规则在
6
+ * capability_sync / docs_freshness / sync-docs 三处独立实现,靠「同规则」注释人工同步,
7
+ * 同一 bug(basename 碰撞、后缀误配)在多处各修一遍——此处为唯一真相源。
8
+ *
9
+ * 方向:
10
+ * 代码→文档 uncoveredChanges / uncoveredFiles / uncoveredDirs(漏登记)
11
+ * 文档→代码 deadEntries(幽灵:文档登记的路径既不在代码实况中、文件系统中也不存在)
12
+ *
13
+ * 解析口径(ADR-0009):表格所有单元格收集,文件条目与目录条目都参与覆盖;
14
+ * 「只看第二列」的历史读法废弃。幽灵判定同样覆盖文件与目录条目(口径从严)。
15
+ * mode=module / file 的差异不在判定层,而是调用方取哪份输出形状:
16
+ * module 读 uncoveredDirs(目录聚合),file 读 uncoveredFiles(逐文件)。
17
+ */
18
+
19
+ import { join, relative } from 'path';
20
+ import {
21
+ aggregateToSourceSubdir,
22
+ isCapabilityListingFormat,
23
+ parseCapabilitiesEntries,
24
+ } from './capabilities-parser';
25
+ import { findTsSourceFiles } from '../../utils/file-walk';
26
+
27
+ /** markdown 表格分隔行(|------|------|):区分「无表格的散文文档」与「有表格但零条目」 */
28
+ const TABLE_SEPARATOR_REGEX = /^\s*\|[\s:|-]+\|\s*$/m;
29
+
30
+ export interface ReconcileInput {
31
+ /** CAPABILITIES.md 内容 */
32
+ content: string;
33
+ /** 代码实况全集:项目相对路径的源文件清单(由调用方收集,见 collectSourceFiles) */
34
+ populationFiles: string[];
35
+ /** 增量变更文件(项目相对路径);无 git 概念的消费方传空/不传 */
36
+ changedFiles?: string[];
37
+ /** 存在性 oracle(项目相对路径 → 是否存在);缺省退化为「代码实况兜底」 */
38
+ fileExists?: (relPath: string) => boolean;
39
+ /** 源码根(如 'src'、'apps/api/src'):未覆盖聚合与条目多根相对路径解析用 */
40
+ sourceRoots?: string[];
41
+ }
42
+
43
+ export interface CapabilityVerdict {
44
+ /** 文档中的文件条目(原样路径,可能为全路径或裸文件名) */
45
+ fileEntries: string[];
46
+ /** 文档中的目录条目(以 / 结尾) */
47
+ dirEntries: string[];
48
+ /** 参与覆盖判定的条目集 = 文件条目 + 目录条目 */
49
+ coverageEntries: string[];
50
+ /** 文档含 markdown 表格(区分「散文文档」与「有表格零条目」) */
51
+ hasTable: boolean;
52
+ /** 能力清单格式(计数行文档):无文件表可核对,调用方据此短路 */
53
+ listingFormat: boolean;
54
+ /** 增量文件中未被覆盖的(capability_sync Step1) */
55
+ uncoveredChanges: string[];
56
+ /** 代码实况中未被文档登记的 */
57
+ uncoveredFiles: string[];
58
+ /** 未覆盖文件按源码根下第一级子目录聚合(module 模式的 added 形状) */
59
+ uncoveredDirs: string[];
60
+ /** 幽灵条目(文件 + 目录):文档登记但代码实况与文件系统均不存在 */
61
+ deadEntries: string[];
62
+ }
63
+
64
+ /**
65
+ * 变更文件是否被条目覆盖(ADR-0009 唯一覆盖规则)
66
+ *
67
+ * 目录条目(以 / 结尾)前缀匹配;文件条目精确匹配或路径边界后缀匹配
68
+ * (兼容 basename 条目,但拒绝 xfoo.ts 命中 foo.ts、docs/src/foo.tsx 命中 src/foo.ts
69
+ * 这类 endsWith/includes 模糊匹配造成的碰撞)
70
+ */
71
+ function isCoveredBy(entries: string[], file: string): boolean {
72
+ return entries.some((listed) =>
73
+ listed.endsWith('/')
74
+ ? file.startsWith(listed)
75
+ : file === listed || file.endsWith('/' + listed)
76
+ );
77
+ }
78
+
79
+ /** 条目多根相对路径的存在性:项目根直查 + 各源码根前缀(docs_freshness/sync-docs 历史同语义) */
80
+ function entryExistsOnDisk(
81
+ entry: string,
82
+ fileExists: (rel: string) => boolean,
83
+ sourceRoots: string[]
84
+ ): boolean {
85
+ if (fileExists(entry)) return true;
86
+ return sourceRoots.some((root) => fileExists(`${root}/${entry}`));
87
+ }
88
+
89
+ export function reconcileCapabilities(input: ReconcileInput): CapabilityVerdict {
90
+ const {
91
+ content,
92
+ populationFiles,
93
+ changedFiles = [],
94
+ fileExists = () => false,
95
+ sourceRoots = [],
96
+ } = input;
97
+
98
+ const allEntries = parseCapabilitiesEntries(content, { includeDirs: true });
99
+ const fileEntries = allEntries.filter((e) => !e.endsWith('/'));
100
+ const dirEntries = allEntries.filter((e) => e.endsWith('/'));
101
+ const coverageEntries = [...fileEntries, ...dirEntries];
102
+
103
+ const uncoveredFiles = populationFiles.filter((f) => !isCoveredBy(coverageEntries, f));
104
+ const uncoveredDirs = [...new Set(
105
+ uncoveredFiles.map((file) => {
106
+ // 与 sync-docs 历史聚合同语义:归属第一个能前缀匹配的来源根,兜底首根
107
+ const root = sourceRoots.find((d) => file.startsWith(d + '/')) || sourceRoots[0] || '';
108
+ return aggregateToSourceSubdir(root, file);
109
+ })
110
+ )];
111
+
112
+ // 条目在代码实况中仍有对应文件即算活(裸文件名条目无法做存在性判定的兜底)
113
+ const aliveByPopulation = (entry: string): boolean =>
114
+ populationFiles.some((f) => isCoveredBy([entry], f));
115
+
116
+ const deadEntries = allEntries.filter((entry) => {
117
+ if (entryExistsOnDisk(entry, fileExists, sourceRoots)) return false;
118
+ return !aliveByPopulation(entry);
119
+ });
120
+
121
+ return {
122
+ fileEntries,
123
+ dirEntries,
124
+ coverageEntries,
125
+ hasTable: TABLE_SEPARATOR_REGEX.test(content),
126
+ listingFormat: isCapabilityListingFormat(content),
127
+ uncoveredChanges: changedFiles.filter((f) => !isCoveredBy(coverageEntries, f)),
128
+ uncoveredFiles,
129
+ uncoveredDirs,
130
+ deadEntries,
131
+ };
132
+ }
133
+
134
+ /**
135
+ * 变更清单中的「有意义的代码变更」:仅 .ts/.tsx/.js 且非测试文件
136
+ * (capability_sync Step1 的历史过滤规则,收口于此)
137
+ */
138
+ export function significantCodeChanges(diffNames: string[]): string[] {
139
+ return diffNames
140
+ .filter((f) => f.endsWith('.ts') || f.endsWith('.tsx') || f.endsWith('.js'))
141
+ .filter((f) => !f.includes('__tests__') && !f.includes('.test.') && !f.includes('.spec.'));
142
+ }
143
+
144
+ /**
145
+ * 收集源码根下的实际文件清单(项目相对路径)
146
+ *
147
+ * 对 utils/file-walk 的统一封装,替代各调用方自拼 join/relative。
148
+ * 扩展名口径保持各调用方现状(checker 不含 .tsx;sync-docs 的模块扫描需
149
+ * ModuleInfo 元数据,继续走 scanSourceModules)——统一扩展名口径属行为变更,
150
+ * 不在本次纯重构范围(ADR-0009 记录在案)。
151
+ */
152
+ export function collectSourceFiles(
153
+ projectPath: string,
154
+ roots: string[],
155
+ options: { includeTsx?: boolean } = {}
156
+ ): string[] {
157
+ const files: string[] = [];
158
+ for (const root of roots) {
159
+ const found = findTsSourceFiles(join(projectPath, root), {
160
+ skipIndex: true,
161
+ includeTsx: options.includeTsx,
162
+ });
163
+ files.push(...found.map((f) => relative(projectPath, f)));
164
+ }
165
+ return files;
166
+ }
@@ -12,32 +12,33 @@ import {
12
12
  ConstraintContext,
13
13
  ConstraintResult,
14
14
  ConstraintCheckResult,
15
- ConstraintTrigger,
16
15
  ConstraintLevel,
17
16
  ConstraintViolationError,
18
17
  } from '../../types/constraint';
19
18
  import type { ExecutionTrace } from '../../types/trace';
20
- import { getTraceCollector } from '../../monitoring/traces';
21
19
  import { IRON_LAWS, GUIDELINES, PROMPTS } from './definitions';
22
20
  import type { MergedConstraintsConfig } from '../../types/project-config';
23
- import { normalizeTriggers } from '../../utils/exec';
24
- import { runCommand } from '../../utils/exec';
21
+ import { matchesTrigger } from '../../utils/exec';
25
22
  import { join, relative } from 'path';
26
23
  import { CheckCache } from './check-cache';
27
24
  import { findTsSourceFiles } from '../../utils/file-walk';
28
- import { getConstraintCheck, buildCheckEnv, type CheckOutcome } from './checkers';
25
+ import { getConstraintCheck, buildCheckEnv, normalizeCheckOutcome, type CheckOutcome } from './checkers';
26
+ import { createGitEvidence, type GitEvidence } from './git-evidence';
29
27
 
30
28
  /**
31
- * trace 记录器最小接口(原工单 15 为消除 core→monitoring 循环;现 monitoring
32
- * 不反向依赖 core,方向单向、无环,checker 可直接值引用 getTraceCollector)
29
+ * trace 记录器最小接口(工单 15 decycle 收尾,harness#88)
33
30
  *
34
- * checker 不构造收集器;生产路径首次记录时惰性接线 getTraceCollector()
35
- * (幂等单点,ADR-0003),测试可经 setTraceRecorder 注入替身。
31
+ * core 不上行依赖 monitoring:记录器经**构造参数**注入,未注入 = no-op
32
+ * (默认无副作用)。真实收集器由组合根接线——CLI check/report 与 bootstrap
33
+ * 各自 `new ConstraintChecker(getTraceCollector())`。
36
34
  */
37
35
  export interface TraceRecorder {
38
36
  record(trace: ExecutionTrace): void;
39
37
  }
40
38
 
39
+ /** 未注入时的默认记录器:不记录 */
40
+ const NOOP_TRACE_RECORDER: TraceRecorder = { record: () => undefined };
41
+
41
42
  /**
42
43
  * 约束检查器
43
44
  */
@@ -47,60 +48,15 @@ export class ConstraintChecker {
47
48
  /** 检查结果缓存(S7:src 扫描等重复 I/O,TTL=1s 防跨测试污染) */
48
49
  private cache: CheckCache = new CheckCache({ ttlMs: 1000 });
49
50
 
50
- /**
51
- * run memo(工单 18):一次 checkConstraints 内
52
- * git diff 等命令只执行一次;run 外直接调用私有检查方法时不 memo(恒新鲜)。
53
- */
54
- private runCache: Map<string, Promise<string>> | null = null;
55
-
56
- /** trace 记录器(注入式;null = 未显式注入,首次记录时惰性接线全局收集器) */
57
- private traceRecorder: TraceRecorder | null = null;
58
-
59
- private constructor() {}
60
-
61
- /**
62
- * 取 trace 记录器:未显式注入时惰性接线全局收集器(幂等,ADR-0003 副作用收敛)
63
- */
64
- private getRecorder(): TraceRecorder {
65
- if (!this.traceRecorder) {
66
- this.traceRecorder = getTraceCollector();
67
- }
68
- return this.traceRecorder;
69
- }
70
-
71
- /**
72
- * run 内 memoize;无活动 run 时直接执行(工单 18)
73
- */
74
- private memoRun(key: string, fn: () => Promise<string>): Promise<string> {
75
- if (!this.runCache) return fn();
76
- let pending = this.runCache.get(key);
77
- if (!pending) {
78
- pending = fn();
79
- this.runCache.set(key, pending);
80
- }
81
- return pending;
82
- }
83
-
84
- /**
85
- * staged 全量 diff(同一次 run 内只执行一次 git 命令,工单 18)
86
- */
87
- private getStagedDiff(projectPath: string): Promise<string> {
88
- return this.memoRun(`git_diff_staged:${projectPath}`, () =>
89
- runCommand('git diff --cached', projectPath)
90
- );
91
- }
51
+ /** trace 记录器(构造注入;缺省 no-op) */
52
+ private readonly traceRecorder: TraceRecorder;
92
53
 
93
- /**
94
- * staged 变更文件名列表(同一次 run 内只执行一次 git 命令,工单 18)
95
- */
96
- private getStagedDiffNames(projectPath: string): Promise<string> {
97
- return this.memoRun(`git_diff_staged_names:${projectPath}`, () =>
98
- runCommand('git diff --cached --name-only', projectPath)
99
- );
54
+ constructor(traceRecorder: TraceRecorder = NOOP_TRACE_RECORDER) {
55
+ this.traceRecorder = traceRecorder;
100
56
  }
101
57
 
102
58
  /**
103
- * 获取单例实例
59
+ * 获取单例实例(未接线记录器的默认实例:不写 trace)
104
60
  */
105
61
  static getInstance(): ConstraintChecker {
106
62
  if (!ConstraintChecker.instance) {
@@ -109,13 +65,6 @@ export class ConstraintChecker {
109
65
  return ConstraintChecker.instance;
110
66
  }
111
67
 
112
- /**
113
- * 注入 trace 记录器(测试/定制场景;不调用则首次记录时惰性接线全局收集器)
114
- */
115
- setTraceRecorder(recorder: TraceRecorder): void {
116
- this.traceRecorder = recorder;
117
- }
118
-
119
68
  /**
120
69
  * 获取当前的约束集合(内置 + 自定义)
121
70
  *
@@ -143,10 +92,13 @@ export class ConstraintChecker {
143
92
 
144
93
  /**
145
94
  * 检查单个约束
95
+ *
96
+ * @param evidence 可选,本 run 的 git 证据实例(#87);不传 = 本次调用独占一份真 git 证据
146
97
  */
147
98
  async check(
148
99
  constraint: Constraint,
149
- context: ConstraintContext
100
+ context: ConstraintContext,
101
+ evidence?: GitEvidence
150
102
  ): Promise<ConstraintResult> {
151
103
  // prompt 类约束不参与 checker 执行(ADR-0001:仅参与注入)
152
104
  if (constraint.kind === 'prompt') {
@@ -160,9 +112,11 @@ export class ConstraintChecker {
160
112
  }
161
113
 
162
114
  // 检查前置条件('skip' = 约定未采用/证据未接线:satisfied 置 true 但不计 pass/fail)
163
- const outcome = await this.checkPrecondition(constraint, context);
115
+ const outcome = normalizeCheckOutcome(
116
+ await this.checkPrecondition(constraint, context, evidence)
117
+ );
164
118
 
165
- if (outcome === 'skip') {
119
+ if (outcome.skipped) {
166
120
  return {
167
121
  id: constraint.id,
168
122
  level: constraint.level,
@@ -174,7 +128,7 @@ export class ConstraintChecker {
174
128
  };
175
129
  }
176
130
 
177
- const satisfied = outcome;
131
+ const satisfied = outcome.satisfied;
178
132
 
179
133
  return {
180
134
  id: constraint.id,
@@ -182,6 +136,7 @@ export class ConstraintChecker {
182
136
  satisfied,
183
137
  constraint,
184
138
  message: satisfied ? undefined : constraint.message,
139
+ evidence: outcome.evidence.length > 0 ? outcome.evidence : undefined,
185
140
  requiredAction: satisfied ? undefined : constraint.enforcement,
186
141
  checkedAt: new Date(),
187
142
  };
@@ -203,28 +158,15 @@ export class ConstraintChecker {
203
158
  }
204
159
  }
205
160
 
206
- /**
207
- * 判断约束是否匹配当前触发条件
208
- *
209
- * context.operation 为主触发条件,context.extraTriggers 为次级推断
210
- * (ADR-0001:pre-commit 代码变更附加 code_implementation),任一命中即匹配。
211
- */
212
- private matchesTrigger(constraint: Constraint, context: ConstraintContext): boolean {
213
- const triggers = normalizeTriggers<ConstraintTrigger>(constraint.trigger);
214
- const operations = [context.operation, ...(context.extraTriggers ?? [])];
215
- return operations.some(op => triggers.includes(op));
216
- }
217
-
218
161
  /**
219
162
  * 记录约束检查的 trace
220
163
  */
221
164
  private recordTrace(
222
- collector: TraceRecorder,
223
165
  constraint: Constraint,
224
166
  checkResult: ConstraintResult,
225
167
  context: ConstraintContext
226
168
  ): void {
227
- collector.record({
169
+ this.traceRecorder.record({
228
170
  constraintId: constraint.id,
229
171
  level: constraint.level,
230
172
  timestamp: Date.now(),
@@ -233,6 +175,7 @@ export class ConstraintChecker {
233
175
  severity: this.getSeverity(constraint.level),
234
176
  projectPath: context.projectPath,
235
177
  sessionId: context.sessionId,
178
+ evidence: checkResult.evidence,
236
179
  });
237
180
  }
238
181
 
@@ -241,10 +184,14 @@ export class ConstraintChecker {
241
184
  *
242
185
  * 注册表闭环(ADR-0001):kind='check' 未注册 checker 直接抛错,
243
186
  * 不再有"未注册默认通过"路径;kind='prompt' 在 check() 入口已短路。
187
+ *
188
+ * git 证据(stagedDiff/stagedDiffNames)单一来源 = GitEvidence adapter(#87):
189
+ * 一次 run 内调用方传同一实例即至多取证一次,run 外调用独占一份。
244
190
  */
245
191
  private async checkPrecondition(
246
192
  constraint: Constraint,
247
- context: ConstraintContext
193
+ context: ConstraintContext,
194
+ evidence?: GitEvidence
248
195
  ): Promise<CheckOutcome> {
249
196
  const impl = getConstraintCheck(constraint.id);
250
197
  if (!impl) {
@@ -255,9 +202,10 @@ export class ConstraintChecker {
255
202
  }
256
203
 
257
204
  const projectPath = context.projectPath || process.cwd();
205
+ const git = evidence ?? createGitEvidence(projectPath);
258
206
  const env = buildCheckEnv(context, {
259
- stagedDiff: () => this.getStagedDiff(projectPath),
260
- stagedDiffNames: () => this.getStagedDiffNames(projectPath),
207
+ stagedDiff: async () => git.stagedDiff(),
208
+ stagedDiffNames: async () => git.changedFileNames(true),
261
209
  srcScan: (root: string) =>
262
210
  this.cache.getSync(`src_scan_${root}`, projectPath, () =>
263
211
  findTsSourceFiles(join(projectPath, root), { skipIndex: true }).map((f) =>
@@ -287,12 +235,9 @@ export class ConstraintChecker {
287
235
  const constraints = this.getConstraints(customConfig);
288
236
 
289
237
  const filterByTrigger = (constraintSet: Record<string, Constraint>): Constraint[] => {
290
- return Object.values(constraintSet).filter(constraint => {
291
- const triggers = Array.isArray(constraint.trigger)
292
- ? constraint.trigger
293
- : [constraint.trigger];
294
- return operations.some(op => triggers.includes(op));
295
- });
238
+ return Object.values(constraintSet).filter(constraint =>
239
+ matchesTrigger(constraint, operations)
240
+ );
296
241
  };
297
242
 
298
243
  return {
@@ -310,57 +255,58 @@ export class ConstraintChecker {
310
255
  *
311
256
  * @param context 约束上下文
312
257
  * @param customConfig 可选,per-request 自定义配置(避免多请求间的单例状态污染)
258
+ * @param evidence 可选,本 run 的 git 证据 adapter(#87)。调用方(CLI check)与
259
+ * buildConstraintContext 传同一实例 → 一次 run 内 git 取证单一来源;
260
+ * 不传则本 run 自建一份,run 级 memo 照样生效(memo 在实例层,非隐式全局)。
313
261
  */
314
262
  async checkConstraints(
315
263
  context: ConstraintContext,
316
- customConfig?: MergedConstraintsConfig | null
264
+ customConfig?: MergedConstraintsConfig | null,
265
+ evidence?: GitEvidence
317
266
  ): Promise<ConstraintCheckResult> {
318
- // run 起始:重置 run 级缓存;run 结束(含铁律提前抛出)清空(工单 18)
267
+ // run 起始:重置 src 扫描缓存(S7);git 证据 = 本 run 独占的 adapter 实例(工单 18 → #87
319
268
  this.cache.invalidate();
320
- this.runCache = new Map();
321
-
322
- try {
323
- const result: ConstraintCheckResult = {
324
- ironLaws: [],
325
- guidelines: [],
326
- passed: true,
327
- warningCount: 0,
328
- };
269
+ const run = evidence ?? createGitEvidence(context.projectPath || process.cwd());
329
270
 
330
- const traceCollector = this.getRecorder();
331
- const constraints = this.getConstraints(customConfig);
271
+ const result: ConstraintCheckResult = {
272
+ ironLaws: [],
273
+ guidelines: [],
274
+ passed: true,
275
+ warningCount: 0,
276
+ };
332
277
 
333
- // 1. Iron Laws: 必须全部通过
334
- for (const constraint of Object.values(constraints.ironLaws)) {
335
- if (!this.matchesTrigger(constraint, context)) continue;
278
+ const constraints = this.getConstraints(customConfig);
279
+ // context.operation 为主触发条件,extraTriggers 为次级推断(ADR-0001),任一命中即匹配
280
+ const operations = [context.operation, ...(context.extraTriggers ?? [])];
336
281
 
337
- const checkResult = await this.check(constraint, context);
338
- result.ironLaws.push(checkResult);
339
- this.recordTrace(traceCollector, constraint, checkResult, context);
282
+ // 1. Iron Laws: 必须全部通过
283
+ for (const constraint of Object.values(constraints.ironLaws)) {
284
+ if (!matchesTrigger(constraint, operations)) continue;
285
+
286
+ const checkResult = await this.check(constraint, context, run);
287
+ result.ironLaws.push(checkResult);
288
+ this.recordTrace(constraint, checkResult, context);
340
289
 
341
- if (!checkResult.satisfied) {
342
- result.passed = false;
343
- throw new ConstraintViolationError(checkResult);
344
- }
290
+ if (!checkResult.satisfied) {
291
+ result.passed = false;
292
+ throw new ConstraintViolationError(checkResult);
345
293
  }
294
+ }
346
295
 
347
- // 2. Guidelines: 记录警告
348
- for (const constraint of Object.values(constraints.guidelines)) {
349
- if (!this.matchesTrigger(constraint, context)) continue;
296
+ // 2. Guidelines: 记录警告
297
+ for (const constraint of Object.values(constraints.guidelines)) {
298
+ if (!matchesTrigger(constraint, operations)) continue;
350
299
 
351
- const checkResult = await this.check(constraint, context);
352
- result.guidelines.push(checkResult);
353
- this.recordTrace(traceCollector, constraint, checkResult, context);
300
+ const checkResult = await this.check(constraint, context, run);
301
+ result.guidelines.push(checkResult);
302
+ this.recordTrace(constraint, checkResult, context);
354
303
 
355
- if (!checkResult.satisfied) {
356
- result.warningCount++;
357
- }
304
+ if (!checkResult.satisfied) {
305
+ result.warningCount++;
358
306
  }
359
-
360
- return result;
361
- } finally {
362
- this.runCache = null;
363
307
  }
308
+
309
+ return result;
364
310
  }
365
311
 
366
312
  /**
@@ -368,19 +314,22 @@ export class ConstraintChecker {
368
314
  *
369
315
  * @param context 约束上下文
370
316
  * @param customConfig 可选,per-request 自定义配置(避免多请求间的单例状态污染)
317
+ * @param evidence 可选,本次检查共用的 git 证据 adapter(#87,同 checkConstraints)
371
318
  * @throws ConstraintViolationError 如果有铁律违规
372
319
  */
373
320
  async beforeExecution(
374
321
  context: ConstraintContext,
375
- customConfig?: MergedConstraintsConfig | null
322
+ customConfig?: MergedConstraintsConfig | null,
323
+ evidence?: GitEvidence
376
324
  ): Promise<void> {
325
+ const run = evidence ?? createGitEvidence(context.projectPath || process.cwd());
377
326
  const constraints = this.getConstraints(customConfig);
378
327
  const operations = [context.operation, ...(context.extraTriggers ?? [])];
379
328
 
380
329
  for (const constraint of Object.values(constraints.ironLaws)) {
381
- if (!normalizeTriggers(constraint.trigger).some((t) => operations.includes(t))) continue;
330
+ if (!matchesTrigger(constraint, operations)) continue;
382
331
 
383
- const result = await this.check(constraint, context);
332
+ const result = await this.check(constraint, context, run);
384
333
  if (!result.satisfied) {
385
334
  throw new ConstraintViolationError(result);
386
335
  }
@@ -465,5 +414,5 @@ export async function checkBeforeExecution(
465
414
  return ConstraintChecker.getInstance().beforeExecution(context, customConfig);
466
415
  }
467
416
 
468
- // 导出单例
417
+ // 导出单例(未接线记录器:只评估约束,不写 trace;写 trace 由组合根自行 new)
469
418
  export const constraintChecker = ConstraintChecker.getInstance();