@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
@@ -1,16 +1,17 @@
1
1
  /**
2
- * no_hardcoded_credentials checker 测试(ADR-0001)
2
+ * no_hardcoded_credentials 检查器旁测(ADR-0001)
3
3
  *
4
4
  * 注意:测试夹具中的假凭证一律用字符串拼接构造,
5
5
  * 避免本文件自身被凭证扫描(含 harness 自身 staged diff)命中。
6
+ * 测试面 = evaluate(env)(架构评审候选4,自 src/__tests__/ 就近迁入)。
6
7
  */
7
8
 
8
9
  import { describe, it, expect } from '@jest/globals';
9
10
  import {
10
11
  noHardcodedCredentials,
11
12
  containsHardcodedCredential,
12
- } from '../core/constraints/checkers/no-hardcoded-credentials';
13
- import type { CheckEnv } from '../core/constraints/checkers';
13
+ } from '../no-hardcoded-credentials';
14
+ import type { CheckEnv } from '../types';
14
15
 
15
16
  function makeEnv(stagedDiff: string): CheckEnv {
16
17
  return {
@@ -0,0 +1,58 @@
1
+ /**
2
+ * no_test_simplification 检查器旁测(架构评审候选4,ADR-0009 同模式)
3
+ *
4
+ * 测试面 = ConstraintCheck.evaluate(env):判定只吃 stagedDiff 文本,
5
+ * 证据经 providers 注入(旧 facade 测用真实非 git 目录触发 IO 失败,
6
+ * 旁测直接让 provider 抛错表达同一语义)。自 checker-extra.test.ts 迁入。
7
+ */
8
+
9
+ import { describe, it, expect } from '@jest/globals';
10
+ import { noTestSimplification } from '../no-test-simplification';
11
+ import { buildCheckEnv } from '../types';
12
+ import type { ConstraintContext } from '../../../../types/constraint';
13
+
14
+ function evaluate(diff: string | (() => Promise<string>)) {
15
+ const context: ConstraintContext = { operation: 'test_creation', projectPath: '/nonexistent' };
16
+ const stagedDiff = typeof diff === 'function' ? diff : async () => diff;
17
+ return noTestSimplification.evaluate(
18
+ buildCheckEnv(context, {
19
+ stagedDiff,
20
+ stagedDiffNames: async () => '',
21
+ srcScan: () => [],
22
+ })
23
+ );
24
+ }
25
+
26
+ describe('no_test_simplification', () => {
27
+ it('删除 test/it/describe → fail', async () => {
28
+ expect(await evaluate('--- a/x.test.ts\n+++ b/x.test.ts\n@@\n- test("gone", () => {});\n')).toBe(false);
29
+ expect(await evaluate('- it("gone", () => {});')).toBe(false);
30
+ expect(await evaluate('-describe("suite", () => {});')).toBe(false);
31
+ });
32
+
33
+ it('删除 expect → fail', async () => {
34
+ expect(await evaluate('- expect(x).toBe(y);')).toBe(false);
35
+ });
36
+
37
+ it('删除注释掉的 test → fail', async () => {
38
+ expect(await evaluate('- // test pending case')).toBe(false);
39
+ });
40
+
41
+ it('仅新增/上下文行 → pass', async () => {
42
+ expect(
43
+ await evaluate('--- a/x.test.ts\n+++ b/x.test.ts\n@@\n+ test("added", () => {});\n expect(1).toBe(1);\n')
44
+ ).toBe(true);
45
+ });
46
+
47
+ it('空 diff → pass', async () => {
48
+ expect(await evaluate('')).toBe(true);
49
+ });
50
+
51
+ it('git diff 失败 → 默认通过(fail-open,自 facade 测迁入)', async () => {
52
+ expect(
53
+ await evaluate(async () => {
54
+ throw new Error('not a git repository');
55
+ })
56
+ ).toBe(true);
57
+ });
58
+ });
@@ -0,0 +1,145 @@
1
+ /**
2
+ * context_files 三态对照测试(工单 84)
3
+ *
4
+ * 同一组 fixture 同时跑 context_doc_sync 与 docs_freshness 两条约束,
5
+ * 钉死 triage 裁决口径:未配置 / enabled 但无目标 → 约束 checker 一律 skip
6
+ * (ADR-0001 存在性探测同构);enabled 且非空 → 两条约束按同一组 dirs
7
+ * 评估且判定一致。
8
+ *
9
+ * 附带 docs_freshness 评估段的行为变更钉子:enabled 但无目标 → skip,
10
+ * 不再静默放行(此前返回 true)。
11
+ * 项目根由 src/test-setup/project-fixture 声明式构造(回收仍走 mkdtemp-cleanup)。
12
+ */
13
+
14
+ import { describe, it, expect } from '@jest/globals';
15
+ import { contextDocSync } from '../context-doc-sync';
16
+ import { docsFreshness } from '../docs-freshness';
17
+ import { buildCheckEnv } from '../types';
18
+ import { collectSourceFiles } from '../../capabilities-reconcile';
19
+ import { createProjectFixture } from '../../../../test-setup/project-fixture';
20
+ import type { ConstraintContext } from '../../../../types/constraint';
21
+
22
+ const TABLE_HEAD = '| 模块 | 文件 | 说明 |\n|------|------|------|\n';
23
+
24
+ interface Fixture {
25
+ configYml?: string;
26
+ contextMdDirs?: string[];
27
+ files?: string[];
28
+ capabilitiesBody?: string;
29
+ }
30
+
31
+ function setupDir(name: string, fixture: Fixture = {}): string {
32
+ return createProjectFixture({
33
+ name: `three-state-${name}`,
34
+ config: fixture.configYml,
35
+ files: {
36
+ ...Object.fromEntries((fixture.files ?? []).map(f => [f, 'export const x = 1;'])),
37
+ ...Object.fromEntries((fixture.contextMdDirs ?? []).map(d => [`${d}/CONTEXT.md`, `# ${d}\n`])),
38
+ ...(fixture.capabilitiesBody === undefined
39
+ ? {}
40
+ : { 'CAPABILITIES.md': `# Capabilities\n\n${fixture.capabilitiesBody}` }),
41
+ },
42
+ });
43
+ }
44
+
45
+ const CTX_FILES = (enabled: boolean, dirs?: string[]) =>
46
+ `governance:\n context_files:\n enabled: ${enabled}\n` +
47
+ (dirs ? ` required_dirs: [${dirs.map(d => `'${d}'`).join(', ')}]\n` : '');
48
+
49
+ function evalContextDocSync(dir: string) {
50
+ const context: ConstraintContext = { operation: 'module_modification', projectPath: dir };
51
+ return contextDocSync.evaluate(buildCheckEnv(context, 'none'));
52
+ }
53
+
54
+ function evalDocsFreshness(dir: string) {
55
+ const context: ConstraintContext = { operation: 'file_modification', projectPath: dir };
56
+ return docsFreshness.evaluate(
57
+ buildCheckEnv(context, {
58
+ stagedDiff: async () => '',
59
+ stagedDiffNames: async () => '',
60
+ srcScan: (root: string) => collectSourceFiles(dir, [root]),
61
+ })
62
+ );
63
+ }
64
+
65
+ /** 同一 fixture 上两条约束的判定必须一致(对照断言) */
66
+ async function expectBoth(dir: string, verdict: true | false | 'skip'): Promise<void> {
67
+ expect(await evalContextDocSync(dir)).toBe(verdict);
68
+ expect(await evalDocsFreshness(dir)).toBe(verdict);
69
+ }
70
+
71
+ describe('context_files 三态对照 — context_doc_sync vs docs_freshness(工单 84)', () => {
72
+ it('未配置(无 config.yml)→ 双双 skip', async () => {
73
+ await expectBoth(setupDir('no-config'), 'skip');
74
+ });
75
+
76
+ it('governance.context_files 段缺失 → 双双 skip', async () => {
77
+ await expectBoth(setupDir('no-section', { configYml: 'preset: standard\n' }), 'skip');
78
+ });
79
+
80
+ it('enabled: false(约定未采用)→ 双双 skip', async () => {
81
+ await expectBoth(setupDir('disabled', { configYml: CTX_FILES(false, ['src']) }), 'skip');
82
+ });
83
+
84
+ it('enabled 但 required_dirs 缺失(约定已立但无目标)→ 双双 skip', async () => {
85
+ await expectBoth(setupDir('no-dirs', { configYml: CTX_FILES(true) }), 'skip');
86
+ });
87
+
88
+ it('enabled 但 required_dirs 为空数组 → 双双 skip', async () => {
89
+ await expectBoth(setupDir('empty-dirs', { configYml: CTX_FILES(true, []) }), 'skip');
90
+ });
91
+
92
+ it('enabled 但 required_dirs 含非字符串项(脏配置)→ 双双 skip 而非抛错', async () => {
93
+ await expectBoth(
94
+ setupDir('dirty-dirs', {
95
+ configYml: 'governance:\n context_files:\n enabled: true\n required_dirs: [1, null]\n',
96
+ }),
97
+ 'skip'
98
+ );
99
+ });
100
+
101
+ it('enabled 且非空 + CONTEXT.md 齐全 → 双双 pass(同一组 dirs 同一判定)', async () => {
102
+ await expectBoth(
103
+ setupDir('all-present', {
104
+ configYml: CTX_FILES(true, ['src', 'bin']),
105
+ contextMdDirs: ['src', 'bin'],
106
+ }),
107
+ true
108
+ );
109
+ });
110
+
111
+ it('enabled 且非空 + CONTEXT.md 缺失 → 双双 fail', async () => {
112
+ await expectBoth(
113
+ setupDir('missing-doc', { configYml: CTX_FILES(true, ['src', 'bin']) }),
114
+ false
115
+ );
116
+ });
117
+ });
118
+
119
+ describe('docs_freshness 评估段 skip 行为变更(工单 84:约定已立但无目标不再静默放行)', () => {
120
+ it('doc_freshness.checks 已配 + enabled 但 required_dirs 缺失 → skip(原为 true)', async () => {
121
+ const dir = setupDir('checks-plus-empty', {
122
+ configYml:
123
+ 'governance:\n doc_freshness:\n checks:\n - type: changelog_version\n context_files:\n enabled: true\n',
124
+ });
125
+ expect(await evalDocsFreshness(dir)).toBe('skip');
126
+ });
127
+
128
+ it('enabled 但空 + CAPABILITIES.md 健康 → skip(原为 true)', async () => {
129
+ const dir = setupDir('caps-healthy', {
130
+ configYml: CTX_FILES(true),
131
+ files: ['src/module.ts'],
132
+ capabilitiesBody: `${TABLE_HEAD}| module | src/module.ts | module |`,
133
+ });
134
+ expect(await evalDocsFreshness(dir)).toBe('skip');
135
+ });
136
+
137
+ it('enabled 但空 + CAPABILITIES.md 幽灵条目 → 仍 fail(Step 1 文件表判定不因 context_files 受影响)', async () => {
138
+ const dir = setupDir('caps-ghost', {
139
+ configYml: CTX_FILES(true),
140
+ files: ['src/old.ts'],
141
+ capabilitiesBody: `${TABLE_HEAD}| old | src/old.ts | 活 |\n| 遗魂 | src/gone/ | 已删 |`,
142
+ });
143
+ expect(await evalDocsFreshness(dir)).toBe(false);
144
+ });
145
+ });
@@ -5,11 +5,12 @@
5
5
  * 1. Git diff 增量 — 当前变更的非测试文件是否在文档中有记录
6
6
  * 2. 全量扫描 — 源码根下所有源文件是否都在 CAPABILITIES.md 中(T-058)
7
7
  *
8
- * 覆盖判定两步统一(isCoveredBy):目录条目(以 / 结尾)前缀匹配,
9
- * 文件条目精确匹配或路径边界后缀匹配。module 模式下目录条目参与覆盖,
10
- * 未覆盖文件按源码根下第一级子目录聚合。
8
+ * 覆盖/漏登判定不在本文件实现,统一走 capabilities-reconcile(ADR-0009):
9
+ * 目录条目(以 / 结尾)前缀匹配,文件条目精确匹配或路径边界后缀匹配;
10
+ * module 模式下目录条目参与覆盖,未覆盖文件按源码根下第一级子目录聚合。
11
11
  *
12
12
  * 清单格式(计数行,mode=listing 或嗅探命中)无文件表可核对,直接放行;
13
+ * 「有表格但零条目」不得放行,无表格的散文文档保持历史放行;
13
14
  * 检查异常时 fail-open 但输出 console.warn 保留可观测性。
14
15
  *
15
16
  * ADR-0001 存在性探测:项目根无 CAPABILITIES.md(未采用该约定)时返回 'skip',
@@ -18,33 +19,12 @@
18
19
 
19
20
  import { existsSync, readFileSync } from 'fs';
20
21
  import { join } from 'path';
21
- import {
22
- aggregateToSourceSubdir,
23
- isCapabilityListingFormat,
24
- parseCapabilitiesEntries,
25
- } from '../capabilities-parser';
22
+ import { isCapabilityListingFormat } from '../capabilities-parser';
26
23
  import { getCapabilitiesMode } from '../../project-config-loader';
27
24
  import { detectSourceRoots } from '../../../utils/detect-source-roots';
25
+ import { reconcileCapabilities, significantCodeChanges } from '../capabilities-reconcile';
28
26
  import type { ConstraintCheck } from './types';
29
27
 
30
- /** markdown 表格分隔行(|------|------|):区分「无表格的散文文档」与「有表格但零条目」 */
31
- const TABLE_SEPARATOR_REGEX = /^\s*\|[\s:|-]+\|\s*$/m;
32
-
33
- /**
34
- * 变更文件是否被条目覆盖
35
- *
36
- * 目录条目(以 / 结尾)前缀匹配;文件条目精确匹配或路径边界后缀匹配
37
- * (兼容 basename 条目,但拒绝 xfoo.ts 命中 foo.ts、docs/src/foo.tsx 命中 src/foo.ts
38
- * 这类 endsWith/includes 模糊匹配造成的碰撞)
39
- */
40
- function isCoveredBy(entries: string[], changed: string): boolean {
41
- return entries.some((listed) =>
42
- listed.endsWith('/')
43
- ? changed.startsWith(listed)
44
- : changed === listed || changed.endsWith('/' + listed)
45
- );
46
- }
47
-
48
28
  export const capabilitySync: ConstraintCheck = {
49
29
  id: 'capability_sync',
50
30
  async evaluate(env) {
@@ -55,15 +35,6 @@ export const capabilitySync: ConstraintCheck = {
55
35
  }
56
36
  try {
57
37
  const capabilitiesPath = join(projectPath, 'CAPABILITIES.md');
58
- if (!existsSync(capabilitiesPath)) {
59
- // 检查是否有代码变更,无变更则跳过
60
- const diff = await env.stagedDiffNames();
61
- const changedCodeFiles = diff.split('\n').filter(
62
- (f: string) => f.endsWith('.ts') || f.endsWith('.tsx') || f.endsWith('.js')
63
- );
64
- return changedCodeFiles.length === 0;
65
- }
66
-
67
38
  const content = readFileSync(capabilitiesPath, 'utf-8');
68
39
  const capabilitiesMode = getCapabilitiesMode(projectPath);
69
40
 
@@ -72,64 +43,34 @@ export const capabilitySync: ConstraintCheck = {
72
43
  return true;
73
44
  }
74
45
 
75
- const listedFiles = parseCapabilitiesEntries(content, { secondColumnOnly: true });
76
- // module 模式下目录条目同样构成覆盖依据,与 step 2 判定对齐
77
- const entries =
78
- capabilitiesMode === 'module'
79
- ? parseCapabilitiesEntries(content, { includeDirs: true })
80
- : listedFiles;
81
- // 有表格但零条目 = 文档什么都没登记,不得直接放行;无表格的散文文档保持历史放行
82
- const hasTable = TABLE_SEPARATOR_REGEX.test(content);
46
+ const sourceRoots = detectSourceRoots(projectPath);
47
+ const population: string[] = [];
48
+ for (const root of sourceRoots) {
49
+ if (existsSync(join(projectPath, root))) {
50
+ population.push(...env.srcScan(root));
51
+ }
52
+ }
83
53
 
84
- // ── Step 1: Git diff 增量检查 ──
85
- const diff = await env.stagedDiffNames();
86
- const changedCodeFiles = diff.split('\n').filter(
87
- (f: string) => f.endsWith('.ts') || f.endsWith('.tsx') || f.endsWith('.js')
88
- );
89
- const significantChanges = changedCodeFiles.filter(
90
- (f: string) => !f.includes('__tests__') && !f.includes('.test.') && !f.includes('.spec.')
91
- );
54
+ const diffNames = (await env.stagedDiffNames()).split('\n').filter(Boolean);
55
+ const verdict = reconcileCapabilities({
56
+ content,
57
+ populationFiles: population,
58
+ changedFiles: significantCodeChanges(diffNames),
59
+ sourceRoots,
60
+ });
92
61
 
93
- // 每个变更文件都必须被覆盖(every;some 会让一个命中掩盖其余漏网)
94
- if (
95
- significantChanges.length > 0 &&
96
- (entries.length > 0 || hasTable) &&
97
- !significantChanges.every((changed: string) => isCoveredBy(entries, changed))
98
- ) {
99
- return false;
100
- }
62
+ // 零条目门槛:有表格但什么都没登记时不得直接放行
63
+ const gateOpen = verdict.coverageEntries.length === 0 && !verdict.hasTable;
64
+ if (gateOpen) return true;
65
+
66
+ // ── Step 1: Git diff 增量检查(每个变更文件都必须被覆盖)──
67
+ if (verdict.uncoveredChanges.length > 0) return false;
101
68
 
102
69
  // ── Step 2: 全量源码根扫描(T-058 修复核心)──
103
70
  if (capabilitiesMode === 'module') {
104
- // module 模式:目录条目参与覆盖(isCoveredBy 统一判定);
105
- // 未覆盖文件按源码根下第一级子目录聚合,任一组非空即失败
106
- if (entries.length > 0 || hasTable) {
107
- const uncoveredDirs = new Set<string>();
108
- const sourceRoots = detectSourceRoots(projectPath);
109
- for (const root of sourceRoots) {
110
- const srcDir = join(projectPath, root);
111
- if (existsSync(srcDir)) {
112
- for (const file of env.srcScan(root)) {
113
- if (!isCoveredBy(entries, file)) {
114
- uncoveredDirs.add(aggregateToSourceSubdir(root, file));
115
- }
116
- }
117
- }
118
- }
119
- if (uncoveredDirs.size > 0) return false;
120
- }
121
- } else if (listedFiles.length > 0 || hasTable) {
122
- const sourceRoots = detectSourceRoots(projectPath);
123
- for (const root of sourceRoots) {
124
- const srcDir = join(projectPath, root);
125
- if (existsSync(srcDir)) {
126
- for (const file of env.srcScan(root)) {
127
- if (!isCoveredBy(listedFiles, file)) {
128
- return false;
129
- }
130
- }
131
- }
132
- }
71
+ if (verdict.uncoveredDirs.length > 0) return false;
72
+ } else if (verdict.uncoveredFiles.length > 0) {
73
+ return false;
133
74
  }
134
75
 
135
76
  return true;
@@ -1,43 +1,33 @@
1
1
  /**
2
2
  * context_doc_sync:关键目录必须有 CONTEXT.md(工单 21)
3
3
  *
4
- * ADR-0001 存在性探测:项目未配置 governance.context_files 约定
5
- * (未启用或无 required_dirs)时返回 'skip',不计 pass/fail。
4
+ * ADR-0001 存在性探测 + context_files 三态统一口径(工单 84):
5
+ * 未配置 / enabled 但无目标(required_dirs 缺失或空)→ 一律 'skip'
6
+ * 不计 pass/fail,与 docs_freshness 同构;判定只走 resolveContextFiles
7
+ * 访问器,不做 governance 手写钻取。
6
8
  */
7
9
 
8
10
  import { existsSync } from 'fs';
9
11
  import { join } from 'path';
10
- import { loadRawProjectConfig } from '../../project-config-loader';
12
+ import { resolveContextFiles } from '../../project-config-loader';
11
13
  import type { ConstraintCheck } from './types';
12
14
 
13
15
  export const contextDocSync: ConstraintCheck = {
14
16
  id: 'context_doc_sync',
15
17
  async evaluate(env) {
16
18
  const projectPath = env.projectPath;
17
- try {
18
- const config = loadRawProjectConfig(projectPath) ?? {};
19
- const governance = config.governance as Record<string, unknown> | undefined;
20
- const contextFiles = governance?.context_files as Record<string, unknown> | undefined;
21
-
22
- if (!contextFiles?.enabled || !Array.isArray(contextFiles.required_dirs)) {
23
- return 'skip'; // 未配置 context_files 约定,跳过评估
24
- }
25
-
26
- const requiredDirs = contextFiles.required_dirs as string[];
27
- if (requiredDirs.length === 0) {
28
- return 'skip'; // 无目标目录,约定未生效
29
- }
19
+ const resolution = resolveContextFiles(projectPath);
20
+ if (resolution.state !== 'enabled') {
21
+ return 'skip'; // 未配置或约定已立但无目标,跳过评估
22
+ }
30
23
 
31
- for (const dir of requiredDirs) {
32
- const contextPath = join(projectPath, dir, 'CONTEXT.md');
33
- if (!existsSync(contextPath)) {
34
- return false;
35
- }
24
+ for (const dir of resolution.dirs) {
25
+ const contextPath = join(projectPath, dir, 'CONTEXT.md');
26
+ if (!existsSync(contextPath)) {
27
+ return false;
36
28
  }
37
-
38
- return true;
39
- } catch {
40
- return 'skip'; // 配置不存在或解析失败 = 无法判定约定,跳过
41
29
  }
30
+
31
+ return true;
42
32
  },
43
33
  };
@@ -9,11 +9,12 @@
9
9
 
10
10
  import { existsSync, readFileSync } from 'fs';
11
11
  import { join } from 'path';
12
- import { loadRawProjectConfig } from '../../project-config-loader';
12
+ import { getGovernanceConfig, resolveContextFiles } from '../../project-config-loader';
13
13
  import { FreshnessRunner, type FreshnessCheckResult } from '../doc-freshness/runner';
14
14
  import { detectSourceRoots } from '../../../utils/detect-source-roots';
15
- import type { DocFreshnessConfig, DocFreshnessCheck } from '../../../types/project-config';
16
- import type { ConstraintCheck } from './types';
15
+ import { reconcileCapabilities } from '../capabilities-reconcile';
16
+ import type { DocFreshnessCheck } from '../../../types/project-config';
17
+ import type { ConstraintCheck, CheckEnv } from './types';
17
18
 
18
19
  /**
19
20
  * 内置默认文档新鲜度检查配置
@@ -30,45 +31,31 @@ function getBuiltInDocFreshnessConfig(): DocFreshnessCheck[] {
30
31
  }
31
32
 
32
33
  /**
33
- * CAPABILITIES.md 文件表新鲜度:列出的文件路径必须仍存在。
34
- * 多根查找:支持不同项目的源码根(harness=src/, studio=apps/api/src/ 等)。
35
- * 无表格行(能力清单格式)时跳过。
34
+ * CAPABILITIES.md 文件表新鲜度:登记的条目(文件与目录)必须仍存在(ADR-0009 口径从严)。
35
+ * 判定逻辑统一走 capabilities-reconcile;多根查找支持不同项目的源码根
36
+ * (harness=src/, studio=apps/api/src/ 等)。无表格(能力清单格式)时自然零幽灵。
36
37
  */
37
- function checkCapabilitiesFreshness(projectPath: string): boolean {
38
+ function findDeadCapabilityEntries(projectPath: string, env: CheckEnv): string[] {
38
39
  try {
39
40
  const capabilitiesPath = join(projectPath, 'CAPABILITIES.md');
40
- if (!existsSync(capabilitiesPath)) return true;
41
+ if (!existsSync(capabilitiesPath)) return [];
41
42
  const content = readFileSync(capabilitiesPath, 'utf-8');
42
43
 
43
- const listedFiles: string[] = [];
44
- const tableRowRegex = /^\|[^|]+\|\s*([^|]+?\.(?:ts|tsx|js|jsx))\s*\|/gm;
45
- let match;
46
- while ((match = tableRowRegex.exec(content)) !== null) {
47
- listedFiles.push(match[1].trim());
48
- }
49
-
50
- if (listedFiles.length === 0) return true;
51
-
52
44
  const sourceRoots = detectSourceRoots(projectPath);
53
- const fileExists = (file: string): boolean => {
54
- if (existsSync(join(projectPath, file))) return true;
55
- for (const root of sourceRoots) {
56
- if (existsSync(join(projectPath, root, file))) return true;
57
- }
58
- return false;
59
- };
60
-
61
- const missing = listedFiles.filter(f => !fileExists(f));
62
- if (missing.length > 0) {
63
- // 报出具体文件名:此前只返回 false,CLI 只能打印通用提示,
64
- // 幽灵条目 basename 碰撞时 sync-docs 也不剔除,用户无从定位(2026-08-08 studio CI 4 连红)
65
- console.error(`[docs_freshness] CAPABILITIES.md 列出的文件不存在: ${missing.join(', ')}`);
66
- return false;
45
+ const population: string[] = [];
46
+ for (const root of sourceRoots) {
47
+ if (existsSync(join(projectPath, root))) population.push(...env.srcScan(root));
67
48
  }
68
49
 
69
- return true;
50
+ const verdict = reconcileCapabilities({
51
+ content,
52
+ populationFiles: population,
53
+ sourceRoots,
54
+ fileExists: (rel) => existsSync(join(projectPath, rel)),
55
+ });
56
+ return verdict.deadEntries;
70
57
  } catch {
71
- return true;
58
+ return [];
72
59
  }
73
60
  }
74
61
 
@@ -77,7 +64,7 @@ function checkCapabilitiesFreshness(projectPath: string): boolean {
77
64
  *
78
65
  * 判定信号(任一命中即视为采用了文档新鲜度约定):
79
66
  * - 配置了 governance.doc_freshness.checks
80
- * - 配置了 governance.context_filesenabled + 非空 required_dirs)
67
+ * - 配置了 governance.context_files 且约定有效(enabled + 非空 required_dirs)
81
68
  * - 项目根存在 CAPABILITIES.md
82
69
  * - 项目根存在 CHANGELOG.md / CHANGELOG
83
70
  *
@@ -89,26 +76,12 @@ function hasFreshnessTargets(projectPath: string): boolean {
89
76
  return true;
90
77
  }
91
78
 
92
- try {
93
- const raw = loadRawProjectConfig(projectPath);
94
- const governance = raw?.governance as Record<string, unknown> | undefined;
95
-
96
- const freshnessConfig = governance?.doc_freshness as DocFreshnessConfig | undefined;
97
- if (freshnessConfig?.checks && freshnessConfig.checks.length > 0) return true;
98
-
99
- const contextFiles = governance?.context_files as Record<string, unknown> | undefined;
100
- if (
101
- contextFiles?.enabled &&
102
- Array.isArray(contextFiles.required_dirs) &&
103
- (contextFiles.required_dirs as string[]).length > 0
104
- ) {
105
- return true;
106
- }
107
- } catch {
108
- // 配置不可读视为无配置
79
+ const governance = getGovernanceConfig(projectPath);
80
+ if (governance?.doc_freshness?.checks && governance.doc_freshness.checks.length > 0) {
81
+ return true;
109
82
  }
110
83
 
111
- return false;
84
+ return resolveContextFiles(projectPath).state === 'enabled';
112
85
  }
113
86
 
114
87
  export const docsFreshness: ConstraintCheck = {
@@ -119,26 +92,24 @@ export const docsFreshness: ConstraintCheck = {
119
92
  // ADR-0001 存在性探测:项目无任何 freshness 配置/目标 → skip(不计 pass/fail)
120
93
  if (!hasFreshnessTargets(projectPath)) return 'skip';
121
94
 
122
- // Step 1: 文件表格式 — 检查列出的文件是否还存在
123
- if (!checkCapabilitiesFreshness(projectPath)) return false;
95
+ // Step 1: 文件表格式 — 登记的条目(文件+目录)是否仍存在(ADR-0009)
96
+ const deadEntries = findDeadCapabilityEntries(projectPath, env);
97
+ if (deadEntries.length > 0) {
98
+ // 报出具体条目:此前只返回 false,CLI 只能打印通用提示,
99
+ // 幽灵条目 basename 碰撞时 sync-docs 也不剔除,用户无从定位(2026-08-08 studio CI 4 连红)
100
+ console.error(`[docs_freshness] CAPABILITIES.md 登记的条目不存在: ${deadEntries.join(', ')}`);
101
+ return false;
102
+ }
124
103
 
125
104
  // Step 2: 能力清单格式 + CLAUDE.md + CHANGELOG — 通过 FreshnessRunner
126
105
  try {
127
- let freshnessConfig: DocFreshnessConfig | undefined;
128
- let requiredDirs: string[] | undefined;
129
-
130
- try {
131
- const raw = loadRawProjectConfig(projectPath);
132
- const governance = raw?.governance as Record<string, unknown> | undefined;
133
- freshnessConfig = governance?.doc_freshness as DocFreshnessConfig | undefined;
134
-
135
- const contextFiles = governance?.context_files as Record<string, unknown> | undefined;
136
- if (contextFiles?.enabled && Array.isArray(contextFiles.required_dirs)) {
137
- requiredDirs = contextFiles.required_dirs as string[];
138
- }
139
- } catch {
140
- // 配置解析失败,使用默认
141
- }
106
+ const freshnessConfig = getGovernanceConfig(projectPath)?.doc_freshness;
107
+
108
+ // context_files 三态统一口径(工单 84):约定已立但无目标(enabled 但
109
+ // required_dirs 缺失/空)→ skip,与 context_doc_sync 同构;不再静默放行
110
+ const contextFiles = resolveContextFiles(projectPath);
111
+ if (contextFiles.state === 'enabled-empty') return 'skip';
112
+ const requiredDirs = contextFiles.state === 'enabled' ? contextFiles.dirs : undefined;
142
113
 
143
114
  const runner = new FreshnessRunner();
144
115
  let results: FreshnessCheckResult[];
@@ -10,42 +10,24 @@
10
10
  * 不强制迁移;两处都没有才报违规。
11
11
  */
12
12
 
13
- import { readFileSync } from 'fs';
14
13
  import { join } from 'path';
15
14
  import { loadRawProjectConfig } from '../../project-config-loader';
15
+ import { hasGovernanceContract, hasPreserveBlock, readIfExists } from '../injection-writer';
16
16
  import type { ConstraintCheck } from './types';
17
17
 
18
18
  /** 治理契约 PRESERVE 段名(ADR 落点模型约定) */
19
19
  export const GOVERNANCE_PRESERVE_NAME = 'governance';
20
20
 
21
- const GOVERNANCE_BEGIN_RE = /^<!-- PRESERVE:governance -->\s*$/m;
22
-
23
- /** AGENTS.md 是否存在非空 PRESERVE:governance 块(标记须独占一行,与 preserve-block.ts 同语义) */
21
+ /** AGENTS.md 是否存在非空 PRESERVE:governance 块(切片判定收口 injection-writer.hasPreserveBlock,#83) */
24
22
  export function hasGovernancePreserveBlock(agentsMdPath: string): boolean {
25
- let content: string;
26
- try {
27
- content = readFileSync(agentsMdPath, 'utf-8');
28
- } catch {
29
- return false;
30
- }
31
- const beginMatch = GOVERNANCE_BEGIN_RE.exec(content);
32
- if (!beginMatch) return false;
33
- const rest = content.slice(beginMatch.index + beginMatch[0].length);
34
- const endIdx = rest.indexOf(`<!-- /PRESERVE:${GOVERNANCE_PRESERVE_NAME} -->`);
35
- if (endIdx === -1) return false;
36
- // 块体(首尾标记之间)去空白后非空才算「在场」
37
- return rest.slice(0, endIdx).trim().length > 0;
23
+ const content = readIfExists(agentsMdPath);
24
+ return content !== null && hasPreserveBlock(content, GOVERNANCE_PRESERVE_NAME);
38
25
  }
39
26
 
40
- /** CLAUDE.md 是否存在治理块(与 agents-syncer getGovernanceInfo 同判定,旧模型仓豁免) */
27
+ /** CLAUDE.md 是否有治理契约在场(判定收口 injection-writer.hasGovernanceContract,#83;旧模型仓豁免) */
41
28
  export function hasClaudeGovernance(claudeMdPath: string): boolean {
42
- let content: string;
43
- try {
44
- content = readFileSync(claudeMdPath, 'utf-8');
45
- } catch {
46
- return false;
47
- }
48
- return /^##\s+Governance Rules/m.test(content) || content.includes('HARNESS_CONSTRAINTS_START');
29
+ const content = readIfExists(claudeMdPath);
30
+ return content !== null && hasGovernanceContract(content);
49
31
  }
50
32
 
51
33
  export const governancePresence: ConstraintCheck = {