@dommaker/harness 1.2.3 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (550) hide show
  1. package/CHANGELOG.md +15 -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 +76 -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 +30 -215
  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 +33 -26
  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 +21 -15
  53. package/dist/cli/commands/knowledge.d.ts.map +1 -1
  54. package/dist/cli/commands/knowledge.js +237 -199
  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 +73 -77
  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 +31 -16
  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 +2 -1
  115. package/dist/cli/commands/update-user-model.d.ts.map +1 -1
  116. package/dist/cli/commands/update-user-model.js +31 -45
  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/completion-checkers/index.d.ts +3 -3
  127. package/dist/completion-checkers/index.js +3 -3
  128. package/dist/completion-checkers/phase-format.d.ts +1 -1
  129. package/dist/completion-checkers/phase-format.js +2 -2
  130. package/dist/completion-checkers/phase-format.js.map +1 -1
  131. package/dist/completion-checkers/tdd-chain.d.ts +1 -1
  132. package/dist/completion-checkers/tdd-chain.js +2 -2
  133. package/dist/completion-checkers/tdd-chain.js.map +1 -1
  134. package/dist/completion-checkers/types.d.ts +5 -5
  135. package/dist/completion-checkers/types.d.ts.map +1 -1
  136. package/dist/completion-checkers/types.js +2 -2
  137. package/dist/context/session-manager.d.ts.map +1 -1
  138. package/dist/context/session-manager.js +19 -32
  139. package/dist/context/session-manager.js.map +1 -1
  140. package/dist/core/constraints/agent-prompt-renderer.d.ts.map +1 -1
  141. package/dist/core/constraints/agent-prompt-renderer.js +1 -4
  142. package/dist/core/constraints/agent-prompt-renderer.js.map +1 -1
  143. package/dist/core/constraints/capabilities-parser.d.ts +24 -7
  144. package/dist/core/constraints/capabilities-parser.d.ts.map +1 -1
  145. package/dist/core/constraints/capabilities-parser.js +32 -28
  146. package/dist/core/constraints/capabilities-parser.js.map +1 -1
  147. package/dist/core/constraints/capabilities-reconcile.d.ts +67 -0
  148. package/dist/core/constraints/capabilities-reconcile.d.ts.map +1 -0
  149. package/dist/core/constraints/capabilities-reconcile.js +105 -0
  150. package/dist/core/constraints/capabilities-reconcile.js.map +1 -0
  151. package/dist/core/constraints/checker.d.ts +21 -43
  152. package/dist/core/constraints/checker.d.ts.map +1 -1
  153. package/dist/core/constraints/checker.js +64 -115
  154. package/dist/core/constraints/checker.js.map +1 -1
  155. package/dist/core/constraints/checkers/capability-sync.d.ts +4 -3
  156. package/dist/core/constraints/checkers/capability-sync.d.ts.map +1 -1
  157. package/dist/core/constraints/checkers/capability-sync.js +29 -69
  158. package/dist/core/constraints/checkers/capability-sync.js.map +1 -1
  159. package/dist/core/constraints/checkers/context-doc-sync.d.ts +4 -2
  160. package/dist/core/constraints/checkers/context-doc-sync.d.ts.map +1 -1
  161. package/dist/core/constraints/checkers/context-doc-sync.js +13 -22
  162. package/dist/core/constraints/checkers/context-doc-sync.js.map +1 -1
  163. package/dist/core/constraints/checkers/docs-freshness.d.ts.map +1 -1
  164. package/dist/core/constraints/checkers/docs-freshness.js +37 -63
  165. package/dist/core/constraints/checkers/docs-freshness.js.map +1 -1
  166. package/dist/core/constraints/checkers/governance-presence.d.ts +2 -2
  167. package/dist/core/constraints/checkers/governance-presence.d.ts.map +1 -1
  168. package/dist/core/constraints/checkers/governance-presence.js +7 -28
  169. package/dist/core/constraints/checkers/governance-presence.js.map +1 -1
  170. package/dist/core/constraints/checkers/no-test-simplification.d.ts.map +1 -1
  171. package/dist/core/constraints/checkers/no-test-simplification.js +4 -3
  172. package/dist/core/constraints/checkers/no-test-simplification.js.map +1 -1
  173. package/dist/core/constraints/checkers/types.d.ts +2 -2
  174. package/dist/core/constraints/context-builder.d.ts +15 -14
  175. package/dist/core/constraints/context-builder.d.ts.map +1 -1
  176. package/dist/core/constraints/context-builder.js +32 -96
  177. package/dist/core/constraints/context-builder.js.map +1 -1
  178. package/dist/core/constraints/doc-freshness/runner.d.ts.map +1 -1
  179. package/dist/core/constraints/doc-freshness/runner.js +2 -1
  180. package/dist/core/constraints/doc-freshness/runner.js.map +1 -1
  181. package/dist/core/constraints/git-evidence.d.ts +60 -0
  182. package/dist/core/constraints/git-evidence.d.ts.map +1 -0
  183. package/dist/core/constraints/git-evidence.js +88 -0
  184. package/dist/core/constraints/git-evidence.js.map +1 -0
  185. package/dist/core/constraints/injection-drift.d.ts +3 -20
  186. package/dist/core/constraints/injection-drift.d.ts.map +1 -1
  187. package/dist/core/constraints/injection-drift.js +10 -57
  188. package/dist/core/constraints/injection-drift.js.map +1 -1
  189. package/dist/core/constraints/injection-writer.d.ts +113 -0
  190. package/dist/core/constraints/injection-writer.d.ts.map +1 -0
  191. package/dist/core/constraints/injection-writer.js +228 -0
  192. package/dist/core/constraints/injection-writer.js.map +1 -0
  193. package/dist/core/constraints/usage-report.d.ts +22 -1
  194. package/dist/core/constraints/usage-report.d.ts.map +1 -1
  195. package/dist/core/constraints/usage-report.js +27 -20
  196. package/dist/core/constraints/usage-report.js.map +1 -1
  197. package/dist/core/index.d.ts +2 -2
  198. package/dist/core/index.d.ts.map +1 -1
  199. package/dist/core/index.js +4 -2
  200. package/dist/core/index.js.map +1 -1
  201. package/dist/core/project-config-loader.d.ts +32 -1
  202. package/dist/core/project-config-loader.d.ts.map +1 -1
  203. package/dist/core/project-config-loader.js +39 -9
  204. package/dist/core/project-config-loader.js.map +1 -1
  205. package/dist/core/validators/passes-gate.d.ts +15 -64
  206. package/dist/core/validators/passes-gate.d.ts.map +1 -1
  207. package/dist/core/validators/passes-gate.js +84 -222
  208. package/dist/core/validators/passes-gate.js.map +1 -1
  209. package/dist/core/validators/test-output.d.ts +58 -0
  210. package/dist/core/validators/test-output.d.ts.map +1 -0
  211. package/dist/core/validators/test-output.js +109 -0
  212. package/dist/core/validators/test-output.js.map +1 -0
  213. package/dist/failure/recorder.d.ts +7 -1
  214. package/dist/failure/recorder.d.ts.map +1 -1
  215. package/dist/failure/recorder.js +13 -9
  216. package/dist/failure/recorder.js.map +1 -1
  217. package/dist/gates/acceptance.d.ts +1 -48
  218. package/dist/gates/acceptance.d.ts.map +1 -1
  219. package/dist/gates/acceptance.js +6 -38
  220. package/dist/gates/acceptance.js.map +1 -1
  221. package/dist/gates/checker-gate.d.ts.map +1 -1
  222. package/dist/gates/checker-gate.js +6 -11
  223. package/dist/gates/checker-gate.js.map +1 -1
  224. package/dist/gates/command.d.ts.map +1 -1
  225. package/dist/gates/command.js +10 -22
  226. package/dist/gates/command.js.map +1 -1
  227. package/dist/gates/contract.d.ts.map +1 -1
  228. package/dist/gates/contract.js +22 -61
  229. package/dist/gates/contract.js.map +1 -1
  230. package/dist/gates/performance.d.ts.map +1 -1
  231. package/dist/gates/performance.js +13 -31
  232. package/dist/gates/performance.js.map +1 -1
  233. package/dist/gates/review.d.ts.map +1 -1
  234. package/dist/gates/review.js +21 -53
  235. package/dist/gates/review.js.map +1 -1
  236. package/dist/gates/security.d.ts.map +1 -1
  237. package/dist/gates/security.js +14 -32
  238. package/dist/gates/security.js.map +1 -1
  239. package/dist/gates/types.d.ts +28 -5
  240. package/dist/gates/types.d.ts.map +1 -1
  241. package/dist/gates/types.js +38 -1
  242. package/dist/gates/types.js.map +1 -1
  243. package/dist/hooks/bootstrap.d.ts +2 -0
  244. package/dist/hooks/bootstrap.d.ts.map +1 -1
  245. package/dist/hooks/bootstrap.js +5 -2
  246. package/dist/hooks/bootstrap.js.map +1 -1
  247. package/dist/index.d.ts +4 -3
  248. package/dist/index.d.ts.map +1 -1
  249. package/dist/index.js +13 -4
  250. package/dist/index.js.map +1 -1
  251. package/dist/knowledge/audit.d.ts +7 -2
  252. package/dist/knowledge/audit.d.ts.map +1 -1
  253. package/dist/knowledge/audit.js +59 -79
  254. package/dist/knowledge/audit.js.map +1 -1
  255. package/dist/knowledge/flywheel-metrics.d.ts +39 -0
  256. package/dist/knowledge/flywheel-metrics.d.ts.map +1 -0
  257. package/dist/knowledge/flywheel-metrics.js +47 -0
  258. package/dist/knowledge/flywheel-metrics.js.map +1 -0
  259. package/dist/knowledge/import.d.ts.map +1 -1
  260. package/dist/knowledge/import.js +4 -14
  261. package/dist/knowledge/import.js.map +1 -1
  262. package/dist/knowledge/index-generator.d.ts.map +1 -1
  263. package/dist/knowledge/index-generator.js +18 -15
  264. package/dist/knowledge/index-generator.js.map +1 -1
  265. package/dist/knowledge/ingest.d.ts.map +1 -1
  266. package/dist/knowledge/ingest.js +9 -4
  267. package/dist/knowledge/ingest.js.map +1 -1
  268. package/dist/knowledge/migration.d.ts.map +1 -1
  269. package/dist/knowledge/migration.js +11 -8
  270. package/dist/knowledge/migration.js.map +1 -1
  271. package/dist/knowledge/reference-tracker.d.ts.map +1 -1
  272. package/dist/knowledge/reference-tracker.js +12 -9
  273. package/dist/knowledge/reference-tracker.js.map +1 -1
  274. package/dist/knowledge/store.d.ts +15 -0
  275. package/dist/knowledge/store.d.ts.map +1 -1
  276. package/dist/knowledge/store.js +59 -10
  277. package/dist/knowledge/store.js.map +1 -1
  278. package/dist/monitoring/context-tracker.d.ts.map +1 -1
  279. package/dist/monitoring/context-tracker.js +11 -20
  280. package/dist/monitoring/context-tracker.js.map +1 -1
  281. package/dist/monitoring/index.d.ts +1 -1
  282. package/dist/monitoring/index.d.ts.map +1 -1
  283. package/dist/monitoring/index.js +1 -2
  284. package/dist/monitoring/index.js.map +1 -1
  285. package/dist/monitoring/trace-analyzer.d.ts +15 -0
  286. package/dist/monitoring/trace-analyzer.d.ts.map +1 -1
  287. package/dist/monitoring/trace-analyzer.js +19 -2
  288. package/dist/monitoring/trace-analyzer.js.map +1 -1
  289. package/dist/monitoring/traces.d.ts +21 -2
  290. package/dist/monitoring/traces.d.ts.map +1 -1
  291. package/dist/monitoring/traces.js +38 -29
  292. package/dist/monitoring/traces.js.map +1 -1
  293. package/dist/release/index.d.ts +3 -0
  294. package/dist/release/index.d.ts.map +1 -0
  295. package/dist/release/index.js +7 -0
  296. package/dist/release/index.js.map +1 -0
  297. package/dist/release/integrity.d.ts +65 -0
  298. package/dist/release/integrity.d.ts.map +1 -0
  299. package/dist/release/integrity.js +151 -0
  300. package/dist/release/integrity.js.map +1 -0
  301. package/dist/sdd/index-generator.js +10 -11
  302. package/dist/sdd/index-generator.js.map +1 -1
  303. package/dist/test-setup/project-fixture.d.ts +48 -0
  304. package/dist/test-setup/project-fixture.d.ts.map +1 -0
  305. package/dist/test-setup/project-fixture.js +106 -0
  306. package/dist/test-setup/project-fixture.js.map +1 -0
  307. package/dist/types/constraint.d.ts +0 -18
  308. package/dist/types/constraint.d.ts.map +1 -1
  309. package/dist/types/constraint.js.map +1 -1
  310. package/dist/types/failure.d.ts +7 -0
  311. package/dist/types/failure.d.ts.map +1 -1
  312. package/dist/types/failure.js +8 -1
  313. package/dist/types/failure.js.map +1 -1
  314. package/dist/types/passes-gate.d.ts +10 -25
  315. package/dist/types/passes-gate.d.ts.map +1 -1
  316. package/dist/types/project-config.d.ts +1 -1
  317. package/dist/types/session.d.ts +6 -5
  318. package/dist/types/session.d.ts.map +1 -1
  319. package/dist/utils/exec.d.ts +10 -0
  320. package/dist/utils/exec.d.ts.map +1 -1
  321. package/dist/utils/exec.js +12 -0
  322. package/dist/utils/exec.js.map +1 -1
  323. package/dist/utils/file-walk.d.ts +9 -1
  324. package/dist/utils/file-walk.d.ts.map +1 -1
  325. package/dist/utils/file-walk.js +10 -1
  326. package/dist/utils/file-walk.js.map +1 -1
  327. package/dist/utils/frontmatter.d.ts +73 -0
  328. package/dist/utils/frontmatter.d.ts.map +1 -0
  329. package/dist/utils/frontmatter.js +141 -0
  330. package/dist/utils/frontmatter.js.map +1 -0
  331. package/dist/utils/jsonl.d.ts +92 -0
  332. package/dist/utils/jsonl.d.ts.map +1 -0
  333. package/dist/utils/jsonl.js +166 -0
  334. package/dist/utils/jsonl.js.map +1 -0
  335. package/dist/utils/package-version.d.ts +16 -0
  336. package/dist/utils/package-version.d.ts.map +1 -0
  337. package/dist/utils/package-version.js +63 -0
  338. package/dist/utils/package-version.js.map +1 -0
  339. package/package.json +1 -1
  340. package/src/CONTEXT.md +7 -2
  341. package/src/__tests__/acceptance-gate.test.ts +3 -1
  342. package/src/__tests__/checker-extra.test.ts +7 -1218
  343. package/src/__tests__/context-files-resolution.test.ts +116 -0
  344. package/src/__tests__/effective-constraints.test.ts +10 -13
  345. package/src/__tests__/exec.test.ts +35 -1
  346. package/src/__tests__/failure-recorder.test.ts +9 -0
  347. package/src/__tests__/layering.test.ts +152 -0
  348. package/src/__tests__/passes-gate-extra.test.ts +0 -145
  349. package/src/__tests__/passes-gate.test.ts +142 -106
  350. package/src/__tests__/public-exports.test.ts +3 -0
  351. package/src/__tests__/skip-semantics.test.ts +5 -9
  352. package/src/cli/__tests__/command-contract.test.ts +170 -0
  353. package/src/cli/command-contract.ts +108 -0
  354. package/src/cli/commands/CONTEXT.md +22 -7
  355. package/src/cli/commands/__tests__/acceptance.test.ts +40 -33
  356. package/src/cli/commands/__tests__/analyze-sessions.test.ts +35 -29
  357. package/src/cli/commands/__tests__/bin-exit-mapping.test.ts +101 -0
  358. package/src/cli/commands/__tests__/check-drift.test.ts +27 -34
  359. package/src/cli/commands/__tests__/check-skip-output.test.ts +21 -24
  360. package/src/cli/commands/__tests__/check.test.ts +378 -382
  361. package/src/cli/commands/__tests__/command.test.ts +85 -70
  362. package/src/cli/commands/__tests__/constraints-report.test.ts +100 -71
  363. package/src/cli/commands/__tests__/constraints-retire.test.ts +152 -95
  364. package/src/cli/commands/__tests__/contract.test.ts +27 -34
  365. package/src/cli/commands/__tests__/failure.test.ts +31 -34
  366. package/src/cli/commands/__tests__/init-injection.test.ts +58 -28
  367. package/src/cli/commands/__tests__/init.test.ts +77 -48
  368. package/src/cli/commands/__tests__/knowledge-flywheel-consistency.test.ts +108 -0
  369. package/src/cli/commands/__tests__/knowledge.test.ts +96 -38
  370. package/src/cli/commands/__tests__/passes-gate.test.ts +43 -45
  371. package/src/cli/commands/__tests__/performance.test.ts +22 -23
  372. package/src/cli/commands/__tests__/posteval-plan.test.ts +39 -38
  373. package/src/cli/commands/__tests__/project-path-anchoring.test.ts +157 -0
  374. package/src/cli/commands/__tests__/project-path-convention.test.ts +169 -0
  375. package/src/cli/commands/__tests__/registry.test.ts +69 -35
  376. package/src/cli/commands/__tests__/release.test.ts +224 -74
  377. package/src/cli/commands/__tests__/report-extra.test.ts +16 -16
  378. package/src/cli/commands/__tests__/report.test.ts +25 -25
  379. package/src/cli/commands/__tests__/review.test.ts +33 -31
  380. package/src/cli/commands/__tests__/security.test.ts +23 -27
  381. package/src/cli/commands/__tests__/spec-baseline-check.test.ts +20 -20
  382. package/src/cli/commands/__tests__/spec.test.ts +41 -29
  383. package/src/cli/commands/__tests__/status-extra.test.ts +18 -18
  384. package/src/cli/commands/__tests__/status-skipped-lines.test.ts +72 -0
  385. package/src/cli/commands/__tests__/status.test.ts +34 -34
  386. package/src/cli/commands/__tests__/sync-docs-agents.test.ts +108 -86
  387. package/src/cli/commands/__tests__/sync-docs.test.ts +72 -74
  388. package/src/cli/commands/__tests__/update-user-model.test.ts +62 -33
  389. package/src/cli/commands/__tests__/validate.test.ts +27 -29
  390. package/src/cli/commands/acceptance.ts +35 -24
  391. package/src/cli/commands/analyze-sessions.ts +25 -24
  392. package/src/cli/commands/check.ts +88 -65
  393. package/src/cli/commands/command.ts +30 -17
  394. package/src/cli/commands/constraints-report.ts +37 -34
  395. package/src/cli/commands/constraints-retire.ts +58 -55
  396. package/src/cli/commands/constraints.ts +10 -27
  397. package/src/cli/commands/contract.ts +51 -42
  398. package/src/cli/commands/definitions.ts +37 -223
  399. package/src/cli/commands/failure.ts +35 -27
  400. package/src/cli/commands/init.ts +166 -220
  401. package/src/cli/commands/knowledge.ts +250 -203
  402. package/src/cli/commands/passes-gate.ts +58 -68
  403. package/src/cli/commands/performance.ts +23 -18
  404. package/src/cli/commands/posteval-plan.ts +29 -15
  405. package/src/cli/commands/release.ts +75 -78
  406. package/src/cli/commands/report.ts +9 -5
  407. package/src/cli/commands/review.ts +39 -29
  408. package/src/cli/commands/sdd.ts +7 -5
  409. package/src/cli/commands/security.ts +35 -26
  410. package/src/cli/commands/spec-baseline-check.ts +16 -11
  411. package/src/cli/commands/spec.ts +66 -53
  412. package/src/cli/commands/status.ts +59 -53
  413. package/src/cli/commands/sync-docs/agents-syncer.ts +31 -15
  414. package/src/cli/commands/sync-docs/context-syncer.ts +3 -2
  415. package/src/cli/commands/sync-docs/index.ts +73 -100
  416. package/src/cli/commands/sync-docs/project-reader.ts +17 -18
  417. package/src/cli/commands/update-user-model.ts +33 -45
  418. package/src/cli/commands/validate.ts +31 -25
  419. package/src/cli/session-mining/__tests__/transcript.test.ts +118 -0
  420. package/src/cli/session-mining/transcript.ts +26 -8
  421. package/src/completion-checkers/CONTEXT.md +1 -1
  422. package/src/completion-checkers/__tests__/contract-presence.test.ts +1 -1
  423. package/src/completion-checkers/__tests__/phase-format.test.ts +1 -1
  424. package/src/completion-checkers/__tests__/tdd-chain.test.ts +2 -2
  425. package/src/completion-checkers/index.ts +3 -3
  426. package/src/completion-checkers/phase-format.ts +2 -2
  427. package/src/completion-checkers/tdd-chain.ts +2 -2
  428. package/src/completion-checkers/types.ts +5 -5
  429. package/src/context/session-manager.ts +19 -33
  430. package/src/core/CONTEXT.md +9 -6
  431. package/src/core/constraints/__tests__/capabilities-reconcile.test.ts +200 -0
  432. package/src/core/constraints/__tests__/capability-counts.test.ts +94 -0
  433. package/src/core/constraints/__tests__/git-evidence.test.ts +208 -0
  434. package/src/core/constraints/__tests__/injection-drift.test.ts +3 -10
  435. package/src/core/constraints/__tests__/injection-writer.test.ts +231 -0
  436. package/src/core/constraints/__tests__/trace-injection.test.ts +71 -0
  437. package/src/core/constraints/__tests__/usage-report.test.ts +112 -0
  438. package/src/core/constraints/agent-prompt-renderer.ts +2 -6
  439. package/src/core/constraints/capabilities-parser.ts +53 -35
  440. package/src/core/constraints/capabilities-reconcile.ts +166 -0
  441. package/src/core/constraints/checker.ts +75 -130
  442. package/src/core/constraints/checkers/__tests__/capability-sync.test.ts +214 -0
  443. package/src/core/constraints/checkers/__tests__/context-doc-sync.test.ts +77 -0
  444. package/src/core/constraints/checkers/__tests__/docs-freshness.test.ts +117 -0
  445. package/src/{__tests__ → core/constraints/checkers/__tests__}/governance-presence.test.ts +83 -9
  446. package/src/core/constraints/checkers/__tests__/iron-flags.test.ts +50 -0
  447. package/src/core/constraints/checkers/__tests__/no-bypass-checkpoint.test.ts +76 -0
  448. package/src/{__tests__ → core/constraints/checkers/__tests__}/no-hardcoded-credentials.test.ts +4 -3
  449. package/src/core/constraints/checkers/__tests__/no-test-simplification.test.ts +58 -0
  450. package/src/core/constraints/checkers/__tests__/three-state-consistency.test.ts +145 -0
  451. package/src/core/constraints/checkers/capability-sync.ts +29 -88
  452. package/src/core/constraints/checkers/context-doc-sync.ts +15 -25
  453. package/src/core/constraints/checkers/docs-freshness.ts +40 -69
  454. package/src/core/constraints/checkers/governance-presence.ts +7 -25
  455. package/src/core/constraints/checkers/no-test-simplification.ts +4 -3
  456. package/src/core/constraints/checkers/types.ts +2 -2
  457. package/src/core/constraints/context-builder.ts +39 -91
  458. package/src/core/constraints/doc-freshness/runner.ts +2 -1
  459. package/src/core/constraints/git-evidence.ts +120 -0
  460. package/src/core/constraints/injection-drift.ts +13 -60
  461. package/src/core/constraints/injection-writer.ts +212 -0
  462. package/src/core/constraints/usage-report.ts +36 -17
  463. package/src/core/index.ts +4 -2
  464. package/src/core/project-config-loader.ts +49 -9
  465. package/src/core/validators/__tests__/passes-gate.test.ts +2 -56
  466. package/src/core/validators/__tests__/test-output.test.ts +372 -0
  467. package/src/core/validators/passes-gate.ts +86 -248
  468. package/src/core/validators/test-output.ts +128 -0
  469. package/src/failure/__tests__/recorder.test.ts +168 -0
  470. package/src/failure/recorder.ts +13 -11
  471. package/src/gates/CONTEXT.md +6 -3
  472. package/src/gates/__tests__/acceptance-types-single-source.test.ts +68 -0
  473. package/src/gates/__tests__/acceptance.test.ts +4 -86
  474. package/src/gates/__tests__/effective-gates.test.ts +3 -8
  475. package/src/gates/__tests__/test-verdict-consistency.test.ts +140 -0
  476. package/src/gates/acceptance.ts +19 -84
  477. package/src/gates/checker-gate.ts +8 -7
  478. package/src/gates/command.ts +10 -16
  479. package/src/gates/contract.ts +22 -61
  480. package/src/gates/performance.ts +10 -22
  481. package/src/gates/review.ts +21 -41
  482. package/src/gates/security.ts +10 -22
  483. package/src/gates/types.ts +70 -5
  484. package/src/hooks/CONTEXT.md +1 -1
  485. package/src/hooks/bootstrap.ts +5 -2
  486. package/src/index.ts +11 -6
  487. package/src/knowledge/CONTEXT.md +8 -3
  488. package/src/knowledge/__tests__/audit-labels.test.ts +44 -0
  489. package/src/knowledge/__tests__/flywheel-metrics.test.ts +135 -0
  490. package/src/knowledge/__tests__/import.test.ts +44 -0
  491. package/src/knowledge/__tests__/index-generator.test.ts +55 -2
  492. package/src/knowledge/__tests__/ingest.test.ts +85 -0
  493. package/src/knowledge/__tests__/migration.test.ts +47 -0
  494. package/src/knowledge/__tests__/reference-tracker.test.ts +16 -0
  495. package/src/knowledge/__tests__/store.test.ts +194 -0
  496. package/src/knowledge/audit.ts +67 -71
  497. package/src/knowledge/flywheel-metrics.ts +71 -0
  498. package/src/knowledge/import.ts +4 -18
  499. package/src/knowledge/index-generator.ts +20 -15
  500. package/src/knowledge/ingest.ts +9 -4
  501. package/src/knowledge/migration.ts +11 -8
  502. package/src/knowledge/reference-tracker.ts +12 -8
  503. package/src/knowledge/store.ts +64 -11
  504. package/src/monitoring/CONTEXT.md +8 -3
  505. package/src/monitoring/__tests__/skipped-lines-report.test.ts +178 -0
  506. package/src/monitoring/__tests__/traces.test.ts +57 -0
  507. package/src/monitoring/context-tracker.ts +11 -23
  508. package/src/monitoring/index.ts +1 -1
  509. package/src/monitoring/trace-analyzer.ts +21 -2
  510. package/src/monitoring/traces.ts +39 -36
  511. package/src/release/CONTEXT.md +24 -0
  512. package/src/release/__tests__/barrel.test.ts +60 -0
  513. package/src/release/__tests__/integrity.test.ts +157 -0
  514. package/src/release/index.ts +2 -0
  515. package/src/release/integrity.ts +141 -0
  516. package/src/sdd/__tests__/index-generator.test.ts +71 -0
  517. package/src/sdd/index-generator.ts +9 -9
  518. package/src/test-setup/__tests__/project-fixture.test.ts +178 -0
  519. package/src/test-setup/project-fixture.ts +87 -0
  520. package/src/tools/CONTEXT.md +6 -0
  521. package/src/tools/__tests__/registry.test.ts +221 -0
  522. package/src/types/__tests__/types.test.ts +4 -5
  523. package/src/types/constraint.ts +0 -25
  524. package/src/types/failure.ts +8 -0
  525. package/src/types/passes-gate.ts +10 -30
  526. package/src/types/project-config.ts +1 -1
  527. package/src/types/session.ts +5 -5
  528. package/src/utils/__tests__/frontmatter.test.ts +206 -0
  529. package/src/utils/__tests__/jsonl-skip-disposition.test.ts +175 -0
  530. package/src/utils/__tests__/jsonl.test.ts +187 -0
  531. package/src/utils/__tests__/package-version.test.ts +97 -0
  532. package/src/utils/exec.ts +15 -0
  533. package/src/utils/file-walk.ts +11 -2
  534. package/src/utils/frontmatter.ts +121 -0
  535. package/src/utils/jsonl.ts +167 -0
  536. package/src/utils/package-version.ts +27 -0
  537. package/dist/cli/commands/doc-freshness-check.d.ts +0 -53
  538. package/dist/cli/commands/doc-freshness-check.d.ts.map +0 -1
  539. package/dist/cli/commands/doc-freshness-check.js +0 -352
  540. package/dist/cli/commands/doc-freshness-check.js.map +0 -1
  541. package/dist/types/index.d.ts +0 -14
  542. package/dist/types/index.d.ts.map +0 -1
  543. package/dist/types/index.js +0 -39
  544. package/dist/types/index.js.map +0 -1
  545. package/src/__tests__/long-running.test.ts +0 -17
  546. package/src/__tests__/passes-gate-extension.test.ts +0 -151
  547. package/src/cli/commands/__tests__/doc-freshness-check.test.ts +0 -168
  548. package/src/cli/commands/doc-freshness-check.ts +0 -386
  549. package/src/spec/CONTEXT.md +0 -11
  550. package/src/types/index.ts +0 -47
@@ -5,26 +5,18 @@
5
5
  * 各持一份正则,收敛到此处。H2 起能力清单计数(checkCapabilityCounts /
6
6
  * updateCapabilityCounts)也从 sync-docs/capabilities-syncer 收敛到此,
7
7
  * 使本模块成为 CAPABILITIES.md 解析 + 计数唯一入口。
8
+ *
9
+ * 计数所需的命令/门禁定义由调用方注入(harness#88:core 不值导入上层定义表)。
8
10
  */
9
11
 
10
12
  import * as fs from 'fs';
11
13
  import { IRON_LAWS, GUIDELINES } from './definitions';
12
- import { COMMAND_DEFINITIONS } from '../../cli/commands/definitions';
13
- import { GATE_DEFINITIONS } from '../../gates/definitions';
14
14
  import { FreshnessRunner } from './doc-freshness/runner';
15
15
  import type { DocFreshnessCheck } from '../../types/project-config';
16
16
 
17
- /** CLI 命令数 = 非门禁命令定义 + 门禁命令定义(ADR-0002:定义表是命令形状单一来源) */
18
- function cliCommandCount(): number {
19
- return COMMAND_DEFINITIONS.length + GATE_DEFINITIONS.filter(g => g.cli).length;
20
- }
21
-
22
17
  /** 匹配表格单元格中的源码文件条目(如 `src/foo.ts`、`foo.tsx`) */
23
18
  const FILE_CELL_REGEX = /\|\s*([^|]+?\.(?:ts|tsx|js|jsx))\s*\|/g;
24
19
 
25
- /** 仅匹配表格第二列的文件条目(checker 的历史语义:第一列为模块名,第二列为文件) */
26
- const FILE_SECOND_COLUMN_REGEX = /^\|[^|]+\|\s*([^|]+?\.(?:ts|tsx|js|jsx))\s*\|/gm;
27
-
28
20
  /**
29
21
  * 匹配表格单元格中的目录条目(如 `agents/`)。
30
22
  *
@@ -35,26 +27,25 @@ const FILE_SECOND_COLUMN_REGEX = /^\|[^|]+\|\s*([^|]+?\.(?:ts|tsx|js|jsx))\s*\|/
35
27
  const DIR_CELL_REGEX = /\|\s*([\w][\w@./-]*\/)\s*\|/g;
36
28
 
37
29
  export interface CapabilitiesParseOptions {
38
- /** 是否同时收集目录条目(sync-docs 需要;checker 只做文件覆盖比对,不需要) */
30
+ /** 是否同时收集目录条目,默认 false */
39
31
  includeDirs?: boolean;
40
- /** 只取表格第二列的文件条目(checker 的历史严格语义),默认 false */
41
- secondColumnOnly?: boolean;
42
32
  }
43
33
 
44
34
  /**
45
35
  * 从 CAPABILITIES.md 内容中提取表格列出的条目
46
36
  *
37
+ * 解析口径(ADR-0009):表格所有单元格收集;「只看第二列」的历史读法废弃。
38
+ *
47
39
  * @param content markdown 内容
48
40
  * @returns 文件路径原样 + (可选)目录条目,按出现顺序去重
49
41
  */
50
42
  export function parseCapabilitiesEntries(content: string, options: CapabilitiesParseOptions = {}): string[] {
51
- const { includeDirs = false, secondColumnOnly = false } = options;
43
+ const { includeDirs = false } = options;
52
44
  const entries: string[] = [];
53
45
 
54
- const fileRegex = secondColumnOnly ? FILE_SECOND_COLUMN_REGEX : FILE_CELL_REGEX;
55
46
  let match: RegExpExecArray | null;
56
- fileRegex.lastIndex = 0;
57
- while ((match = fileRegex.exec(content)) !== null) {
47
+ FILE_CELL_REGEX.lastIndex = 0;
48
+ while ((match = FILE_CELL_REGEX.exec(content)) !== null) {
58
49
  const raw = match[1].trim();
59
50
  if (!entries.includes(raw)) entries.push(raw);
60
51
  }
@@ -111,6 +102,20 @@ export function aggregateToSourceSubdir(root: string, file: string): string {
111
102
 
112
103
  // ── 能力清单计数 ────────────────────────────────────────────
113
104
 
105
+ /**
106
+ * 调用方注入的定义源(harness#88)
107
+ *
108
+ * core 只消费计数所需的最小形状,不 require 命令表:
109
+ * - commands:非门禁 CLI 命令定义(仅取长度)
110
+ * - gates:门禁定义(仅取长度与「是否带 cli 元数据」)
111
+ *
112
+ * ADR-0002「定义表是命令形状单一来源」不变,只是表的引用方从 core 移到 cli。
113
+ */
114
+ export interface CapabilityDefinitionSource {
115
+ commands: readonly unknown[];
116
+ gates: readonly { cli?: unknown }[];
117
+ }
118
+
114
119
  /**
115
120
  * 能力清单统计规则单份定义(ADR-0008:check/write 两方向共用,
116
121
  * 此前 label+pattern 在 buildCapabilityChecks 与 updateCapabilityCounts 各写一遍)
@@ -119,31 +124,40 @@ export function aggregateToSourceSubdir(root: string, file: string): string {
119
124
  * write 的替换文本前缀,如 `Quality Gates (6)`)
120
125
  * - pattern:同时供 check(doc_regex_count 字符串 pattern,捕获组为文档计数)
121
126
  * 与 write(编译为替换 regex)
122
- * - actual:定义表实际计数(ADR-0002 单一来源)
127
+ * - actual:实际计数——命令/门禁来自注入源,约束来自 core 自身定义表
123
128
  */
124
129
  interface CapabilityCountRule {
125
130
  label: string;
126
131
  pattern: string;
127
- actual: () => number;
132
+ actual: number;
128
133
  }
129
134
 
130
- const CAPABILITY_COUNT_RULES: CapabilityCountRule[] = [
131
- { label: 'CLI Commands', pattern: 'CLI Commands\\s*\\((\\d+)\\)', actual: cliCommandCount },
132
- { label: 'Quality Gates', pattern: 'Quality Gates?\\s*\\((\\d+)\\)', actual: () => GATE_DEFINITIONS.length },
133
- { label: 'Iron Laws', pattern: 'Iron Laws?\\s*\\((\\d+)\\)', actual: () => Object.keys(IRON_LAWS).length },
134
- { label: 'Guidelines', pattern: 'Guidelines?\\s*\\((\\d+)\\)', actual: () => Object.keys(GUIDELINES).length },
135
- ];
135
+ /**
136
+ * 能力清单统计规则(CLI Commands 计数 = 非门禁命令数 + cli 元数据的门禁数)
137
+ */
138
+ function capabilityCountRules(source: CapabilityDefinitionSource): CapabilityCountRule[] {
139
+ return [
140
+ {
141
+ label: 'CLI Commands',
142
+ pattern: 'CLI Commands\\s*\\((\\d+)\\)',
143
+ actual: source.commands.length + source.gates.filter(g => g.cli).length,
144
+ },
145
+ { label: 'Quality Gates', pattern: 'Quality Gates?\\s*\\((\\d+)\\)', actual: source.gates.length },
146
+ { label: 'Iron Laws', pattern: 'Iron Laws?\\s*\\((\\d+)\\)', actual: Object.keys(IRON_LAWS).length },
147
+ { label: 'Guidelines', pattern: 'Guidelines?\\s*\\((\\d+)\\)', actual: Object.keys(GUIDELINES).length },
148
+ ];
149
+ }
136
150
 
137
151
  /**
138
152
  * 构建 CAPABILITIES.md 能力清单格式的检查配置
139
153
  */
140
- function buildCapabilityChecks(): DocFreshnessCheck[] {
141
- return CAPABILITY_COUNT_RULES.map(rule => ({
154
+ function buildCapabilityChecks(source: CapabilityDefinitionSource): DocFreshnessCheck[] {
155
+ return capabilityCountRules(source).map(rule => ({
142
156
  type: 'doc_regex_count' as const,
143
157
  doc: 'CAPABILITIES.md',
144
158
  label: rule.label,
145
159
  pattern: rule.pattern,
146
- actual: { kind: 'const_count' as const, value: rule.actual() },
160
+ actual: { kind: 'const_count' as const, value: rule.actual },
147
161
  }));
148
162
  }
149
163
 
@@ -151,10 +165,11 @@ function buildCapabilityChecks(): DocFreshnessCheck[] {
151
165
  * 使用 FreshnessRunner 检查能力清单计数是否与代码一致(--check 模式)
152
166
  */
153
167
  export function checkCapabilityCounts(
154
- projectPath: string
168
+ projectPath: string,
169
+ source: CapabilityDefinitionSource
155
170
  ): { match: boolean; mismatches: string[] } {
156
171
  const runner = new FreshnessRunner();
157
- const checks = buildCapabilityChecks();
172
+ const checks = buildCapabilityChecks(source);
158
173
  const results = runner.runAll({ checks }, projectPath);
159
174
 
160
175
  const mismatches: string[] = [];
@@ -170,14 +185,17 @@ export function checkCapabilityCounts(
170
185
  /**
171
186
  * 更新 CAPABILITIES.md 中的能力清单计数(write 模式)
172
187
  *
173
- * 命令/门禁计数取自定义表(ADR-0002 单一来源),regex 替换文档计数行;
174
- * 规则与 check 方向共用 CAPABILITY_COUNT_RULES(ADR-0008)。
188
+ * 命令/门禁计数取自注入的定义源(ADR-0002 单一来源在调用方),regex 替换文档计数行;
189
+ * 规则与 check 方向共用 capabilityCountRules(ADR-0008)。
175
190
  */
176
- export function updateCapabilityCounts(content: string, _projectPath: string): string {
177
- for (const rule of CAPABILITY_COUNT_RULES) {
191
+ export function updateCapabilityCounts(
192
+ content: string,
193
+ source: CapabilityDefinitionSource
194
+ ): string {
195
+ for (const rule of capabilityCountRules(source)) {
178
196
  const regex = new RegExp(rule.pattern);
179
197
  if (regex.test(content)) {
180
- content = content.replace(regex, `${rule.label} (${rule.actual()})`);
198
+ content = content.replace(regex, `${rule.label} (${rule.actual})`);
181
199
  }
182
200
  }
183
201
 
@@ -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
25
  import { getConstraintCheck, buildCheckEnv, 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;
51
+ /** trace 记录器(构造注入;缺省 no-op) */
52
+ private readonly traceRecorder: TraceRecorder;
58
53
 
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;
54
+ constructor(traceRecorder: TraceRecorder = NOOP_TRACE_RECORDER) {
55
+ this.traceRecorder = traceRecorder;
82
56
  }
83
57
 
84
58
  /**
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
- }
92
-
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
- );
100
- }
101
-
102
- /**
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,7 +112,7 @@ 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 = await this.checkPrecondition(constraint, context, evidence);
164
116
 
165
117
  if (outcome === 'skip') {
166
118
  return {
@@ -203,28 +155,15 @@ export class ConstraintChecker {
203
155
  }
204
156
  }
205
157
 
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
158
  /**
219
159
  * 记录约束检查的 trace
220
160
  */
221
161
  private recordTrace(
222
- collector: TraceRecorder,
223
162
  constraint: Constraint,
224
163
  checkResult: ConstraintResult,
225
164
  context: ConstraintContext
226
165
  ): void {
227
- collector.record({
166
+ this.traceRecorder.record({
228
167
  constraintId: constraint.id,
229
168
  level: constraint.level,
230
169
  timestamp: Date.now(),
@@ -241,10 +180,14 @@ export class ConstraintChecker {
241
180
  *
242
181
  * 注册表闭环(ADR-0001):kind='check' 未注册 checker 直接抛错,
243
182
  * 不再有"未注册默认通过"路径;kind='prompt' 在 check() 入口已短路。
183
+ *
184
+ * git 证据(stagedDiff/stagedDiffNames)单一来源 = GitEvidence adapter(#87):
185
+ * 一次 run 内调用方传同一实例即至多取证一次,run 外调用独占一份。
244
186
  */
245
187
  private async checkPrecondition(
246
188
  constraint: Constraint,
247
- context: ConstraintContext
189
+ context: ConstraintContext,
190
+ evidence?: GitEvidence
248
191
  ): Promise<CheckOutcome> {
249
192
  const impl = getConstraintCheck(constraint.id);
250
193
  if (!impl) {
@@ -255,9 +198,10 @@ export class ConstraintChecker {
255
198
  }
256
199
 
257
200
  const projectPath = context.projectPath || process.cwd();
201
+ const git = evidence ?? createGitEvidence(projectPath);
258
202
  const env = buildCheckEnv(context, {
259
- stagedDiff: () => this.getStagedDiff(projectPath),
260
- stagedDiffNames: () => this.getStagedDiffNames(projectPath),
203
+ stagedDiff: async () => git.stagedDiff(),
204
+ stagedDiffNames: async () => git.changedFileNames(true),
261
205
  srcScan: (root: string) =>
262
206
  this.cache.getSync(`src_scan_${root}`, projectPath, () =>
263
207
  findTsSourceFiles(join(projectPath, root), { skipIndex: true }).map((f) =>
@@ -287,12 +231,9 @@ export class ConstraintChecker {
287
231
  const constraints = this.getConstraints(customConfig);
288
232
 
289
233
  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
- });
234
+ return Object.values(constraintSet).filter(constraint =>
235
+ matchesTrigger(constraint, operations)
236
+ );
296
237
  };
297
238
 
298
239
  return {
@@ -310,57 +251,58 @@ export class ConstraintChecker {
310
251
  *
311
252
  * @param context 约束上下文
312
253
  * @param customConfig 可选,per-request 自定义配置(避免多请求间的单例状态污染)
254
+ * @param evidence 可选,本 run 的 git 证据 adapter(#87)。调用方(CLI check)与
255
+ * buildConstraintContext 传同一实例 → 一次 run 内 git 取证单一来源;
256
+ * 不传则本 run 自建一份,run 级 memo 照样生效(memo 在实例层,非隐式全局)。
313
257
  */
314
258
  async checkConstraints(
315
259
  context: ConstraintContext,
316
- customConfig?: MergedConstraintsConfig | null
260
+ customConfig?: MergedConstraintsConfig | null,
261
+ evidence?: GitEvidence
317
262
  ): Promise<ConstraintCheckResult> {
318
- // run 起始:重置 run 级缓存;run 结束(含铁律提前抛出)清空(工单 18)
263
+ // run 起始:重置 src 扫描缓存(S7);git 证据 = 本 run 独占的 adapter 实例(工单 18 → #87
319
264
  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
- };
265
+ const run = evidence ?? createGitEvidence(context.projectPath || process.cwd());
329
266
 
330
- const traceCollector = this.getRecorder();
331
- const constraints = this.getConstraints(customConfig);
267
+ const result: ConstraintCheckResult = {
268
+ ironLaws: [],
269
+ guidelines: [],
270
+ passed: true,
271
+ warningCount: 0,
272
+ };
273
+
274
+ const constraints = this.getConstraints(customConfig);
275
+ // context.operation 为主触发条件,extraTriggers 为次级推断(ADR-0001),任一命中即匹配
276
+ const operations = [context.operation, ...(context.extraTriggers ?? [])];
332
277
 
333
- // 1. Iron Laws: 必须全部通过
334
- for (const constraint of Object.values(constraints.ironLaws)) {
335
- if (!this.matchesTrigger(constraint, context)) continue;
278
+ // 1. Iron Laws: 必须全部通过
279
+ for (const constraint of Object.values(constraints.ironLaws)) {
280
+ if (!matchesTrigger(constraint, operations)) continue;
336
281
 
337
- const checkResult = await this.check(constraint, context);
338
- result.ironLaws.push(checkResult);
339
- this.recordTrace(traceCollector, constraint, checkResult, context);
282
+ const checkResult = await this.check(constraint, context, run);
283
+ result.ironLaws.push(checkResult);
284
+ this.recordTrace(constraint, checkResult, context);
340
285
 
341
- if (!checkResult.satisfied) {
342
- result.passed = false;
343
- throw new ConstraintViolationError(checkResult);
344
- }
286
+ if (!checkResult.satisfied) {
287
+ result.passed = false;
288
+ throw new ConstraintViolationError(checkResult);
345
289
  }
290
+ }
346
291
 
347
- // 2. Guidelines: 记录警告
348
- for (const constraint of Object.values(constraints.guidelines)) {
349
- if (!this.matchesTrigger(constraint, context)) continue;
292
+ // 2. Guidelines: 记录警告
293
+ for (const constraint of Object.values(constraints.guidelines)) {
294
+ if (!matchesTrigger(constraint, operations)) continue;
350
295
 
351
- const checkResult = await this.check(constraint, context);
352
- result.guidelines.push(checkResult);
353
- this.recordTrace(traceCollector, constraint, checkResult, context);
296
+ const checkResult = await this.check(constraint, context, run);
297
+ result.guidelines.push(checkResult);
298
+ this.recordTrace(constraint, checkResult, context);
354
299
 
355
- if (!checkResult.satisfied) {
356
- result.warningCount++;
357
- }
300
+ if (!checkResult.satisfied) {
301
+ result.warningCount++;
358
302
  }
359
-
360
- return result;
361
- } finally {
362
- this.runCache = null;
363
303
  }
304
+
305
+ return result;
364
306
  }
365
307
 
366
308
  /**
@@ -368,19 +310,22 @@ export class ConstraintChecker {
368
310
  *
369
311
  * @param context 约束上下文
370
312
  * @param customConfig 可选,per-request 自定义配置(避免多请求间的单例状态污染)
313
+ * @param evidence 可选,本次检查共用的 git 证据 adapter(#87,同 checkConstraints)
371
314
  * @throws ConstraintViolationError 如果有铁律违规
372
315
  */
373
316
  async beforeExecution(
374
317
  context: ConstraintContext,
375
- customConfig?: MergedConstraintsConfig | null
318
+ customConfig?: MergedConstraintsConfig | null,
319
+ evidence?: GitEvidence
376
320
  ): Promise<void> {
321
+ const run = evidence ?? createGitEvidence(context.projectPath || process.cwd());
377
322
  const constraints = this.getConstraints(customConfig);
378
323
  const operations = [context.operation, ...(context.extraTriggers ?? [])];
379
324
 
380
325
  for (const constraint of Object.values(constraints.ironLaws)) {
381
- if (!normalizeTriggers(constraint.trigger).some((t) => operations.includes(t))) continue;
326
+ if (!matchesTrigger(constraint, operations)) continue;
382
327
 
383
- const result = await this.check(constraint, context);
328
+ const result = await this.check(constraint, context, run);
384
329
  if (!result.satisfied) {
385
330
  throw new ConstraintViolationError(result);
386
331
  }
@@ -465,5 +410,5 @@ export async function checkBeforeExecution(
465
410
  return ConstraintChecker.getInstance().beforeExecution(context, customConfig);
466
411
  }
467
412
 
468
- // 导出单例
413
+ // 导出单例(未接线记录器:只评估约束,不写 trace;写 trace 由组合根自行 new)
469
414
  export const constraintChecker = ConstraintChecker.getInstance();