@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
@@ -0,0 +1,178 @@
1
+ /**
2
+ * project-fixture 构造 API 测试(架构评审 2026-09-02 候选11 / harness#90)
3
+ *
4
+ * 钉死三条契约:
5
+ * 1) 缺省根 = os.tmpdir(),`config` 槽位逐字节落 `.harness/config.yml`(不做 YAML 往返——
6
+ * 被检代码大量用例是畸形/脏配置,原样落盘是硬需求);
7
+ * 2) 非缺省根必须经 parentDir **显式**声明(cwd 锚定用例的前置约束,不隐式继承默认根);
8
+ * 3) 建出的根由 mkdtemp 劫持登记 = 用例结束自动清理,且 name 形状可被超龄兜底清扫识别。
9
+ */
10
+
11
+ import { describe, it, expect } from '@jest/globals';
12
+ import * as fs from 'fs';
13
+ import * as os from 'os';
14
+ import * as path from 'path';
15
+ import { createProjectFixture, writeProjectConfig, writeProjectTraces } from '../project-fixture';
16
+ import { isRegisteredTmpDir } from '../mkdtemp-cleanup';
17
+ import { DEFAULT_TRACE_FILE } from '../../types/trace';
18
+
19
+ /** mkdtemp-cleanup.ts 的超龄清扫签名(name 不合规的夹具目录漏网后永不被扫) */
20
+ const SWEEP_SIGNATURE = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*-[A-Za-z0-9]{6}$/;
21
+
22
+ describe('createProjectFixture — 根与 config 槽位', () => {
23
+ it('缺省根在 os.tmpdir(),config 逐字节落 .harness/config.yml', () => {
24
+ const root = createProjectFixture({ name: 'pfx-default', config: 'preset: standard\n' });
25
+
26
+ expect(path.dirname(root)).toBe(os.tmpdir());
27
+ expect(fs.readFileSync(path.join(root, '.harness', 'config.yml'), 'utf-8')).toBe('preset: standard\n');
28
+ });
29
+
30
+ it('省略 config → 不写 .harness/config.yml(存在性探测类用例依赖此语义)', () => {
31
+ const root = createProjectFixture({ name: 'pfx-no-config' });
32
+
33
+ expect(fs.existsSync(path.join(root, '.harness', 'config.yml'))).toBe(false);
34
+ expect(fs.existsSync(path.join(root, '.harness'))).toBe(false);
35
+ });
36
+
37
+ it('config 为空字符串仍算声明(falsy 不得退化为“不写”)', () => {
38
+ const root = createProjectFixture({ name: 'pfx-empty-config', config: '' });
39
+
40
+ expect(fs.readFileSync(path.join(root, '.harness', 'config.yml'), 'utf-8')).toBe('');
41
+ });
42
+
43
+ it('files 按相对路径落盘,父目录自动创建', () => {
44
+ const root = createProjectFixture({
45
+ name: 'pfx-files',
46
+ files: {
47
+ 'src/core/foo.ts': 'export const x = 1;',
48
+ 'src/CONTEXT.md': '# src\n',
49
+ '.harness/custom-constraints.yml': 'custom_constraints: {}\n',
50
+ },
51
+ });
52
+
53
+ expect(fs.readFileSync(path.join(root, 'src/core/foo.ts'), 'utf-8')).toBe('export const x = 1;');
54
+ expect(fs.readFileSync(path.join(root, 'src/CONTEXT.md'), 'utf-8')).toBe('# src\n');
55
+ // 通用槽位不得踩 config 正本路径:两者共存时各写各的
56
+ expect(fs.readFileSync(path.join(root, '.harness/custom-constraints.yml'), 'utf-8')).toBe(
57
+ 'custom_constraints: {}\n'
58
+ );
59
+ expect(fs.existsSync(path.join(root, '.harness/config.yml'))).toBe(false);
60
+ });
61
+
62
+ it('config 与 files 同时声明 → 两侧都落盘', () => {
63
+ const root = createProjectFixture({
64
+ name: 'pfx-both',
65
+ config: 'preset: relaxed\n',
66
+ files: { 'CAPABILITIES.md': '# Capabilities\n' },
67
+ });
68
+
69
+ expect(fs.readFileSync(path.join(root, '.harness/config.yml'), 'utf-8')).toBe('preset: relaxed\n');
70
+ expect(fs.readFileSync(path.join(root, 'CAPABILITIES.md'), 'utf-8')).toBe('# Capabilities\n');
71
+ });
72
+ });
73
+
74
+ describe('createProjectFixture — 显式 opt-out 根', () => {
75
+ it('parentDir 声明的根落在该父目录下,而非缺省 tmpdir', () => {
76
+ const parent = createProjectFixture({ name: 'pfx-parent' });
77
+ const root = createProjectFixture({ name: 'pfx-child', parentDir: parent });
78
+
79
+ expect(path.dirname(root)).toBe(parent);
80
+ expect(root.startsWith(path.join(parent, 'pfx-child-'))).toBe(true);
81
+ });
82
+
83
+ it('parentDir: process.cwd() → 根落在仓库工作目录(cwd 锚定套件依赖的正是这条语义)', () => {
84
+ const root = createProjectFixture({ name: 'pfx-cwd-anchor', parentDir: process.cwd() });
85
+ try {
86
+ expect(path.dirname(root)).toBe(process.cwd());
87
+ expect(fs.existsSync(root)).toBe(true);
88
+ } finally {
89
+ fs.rmSync(root, { recursive: true, force: true });
90
+ }
91
+ });
92
+
93
+ it('opt-out 用例仍被 mkdtemp 劫持登记(自动清理不依赖调用方手动 rm)', () => {
94
+ const parent = createProjectFixture({ name: 'pfx-optout-parent' });
95
+ const root = createProjectFixture({ name: 'pfx-optout-child', parentDir: parent });
96
+
97
+ expect(isRegisteredTmpDir(root)).toBe(true);
98
+ });
99
+
100
+ it('缺省根同样登记,且目录名符合超龄清扫签名(漏网目录可被兜底扫掉)', () => {
101
+ const root = createProjectFixture({ name: 'pfx-sweepable' });
102
+
103
+ expect(isRegisteredTmpDir(root)).toBe(true);
104
+ expect(SWEEP_SIGNATURE.test(path.basename(root))).toBe(true);
105
+ });
106
+
107
+ it('name 形状不合规(大写/下划线/空)→ 抛错,不静默产出扫不掉的目录', () => {
108
+ expect(() => createProjectFixture({ name: 'Pfx-Bad' })).toThrow(/name/);
109
+ expect(() => createProjectFixture({ name: 'pfx_bad' })).toThrow(/name/);
110
+ expect(() => createProjectFixture({ name: '' })).toThrow(/name/);
111
+ });
112
+ });
113
+
114
+ describe('writeProjectConfig — config 落盘唯一正本', () => {
115
+ it('根下无 .harness 时自动建目录并写入', () => {
116
+ const root = createProjectFixture({ name: 'pfx-writer' });
117
+
118
+ writeProjectConfig(root, 'gates:\n order:\n - security\n');
119
+
120
+ expect(fs.readFileSync(path.join(root, '.harness', 'config.yml'), 'utf-8')).toBe(
121
+ 'gates:\n order:\n - security\n'
122
+ );
123
+ });
124
+
125
+ it('已有 config 时覆盖写(用例内后续改配置不叠加旧内容)', () => {
126
+ const root = createProjectFixture({ name: 'pfx-rewrite', config: 'preset: standard\n' });
127
+
128
+ writeProjectConfig(root, 'preset: relaxed\n');
129
+
130
+ expect(fs.readFileSync(path.join(root, '.harness', 'config.yml'), 'utf-8')).toBe('preset: relaxed\n');
131
+ });
132
+ });
133
+
134
+ describe('traces 槽位 / writeProjectTraces — trace 落盘正本(harness#108)', () => {
135
+ it('traces 槽位逐条落 DEFAULT_TRACE_FILE,缺省字段补齐(level/timestamp/result)', () => {
136
+ const root = createProjectFixture({
137
+ name: 'pfx-traces',
138
+ traces: [{ constraintId: 'c1', result: 'fail' }],
139
+ });
140
+
141
+ const lines = fs.readFileSync(path.join(root, DEFAULT_TRACE_FILE), 'utf-8').trim().split('\n');
142
+ expect(lines).toHaveLength(1);
143
+ expect(JSON.parse(lines[0])).toEqual({
144
+ level: 'guideline',
145
+ timestamp: 1700000000000,
146
+ result: 'fail',
147
+ constraintId: 'c1',
148
+ });
149
+ });
150
+
151
+ it('traces 槽位缺省 → 不写 trace 文件(traceFileExists=false 用例依赖此语义)', () => {
152
+ const root = createProjectFixture({ name: 'pfx-no-traces' });
153
+
154
+ expect(fs.existsSync(path.join(root, DEFAULT_TRACE_FILE))).toBe(false);
155
+ });
156
+
157
+ it('writeProjectTraces 空数组仍落空文件(traceFileExists=true、零记录语义)', () => {
158
+ const root = createProjectFixture({ name: 'pfx-empty-traces' });
159
+
160
+ writeProjectTraces(root, []);
161
+
162
+ expect(fs.existsSync(path.join(root, DEFAULT_TRACE_FILE))).toBe(true);
163
+ expect(fs.readFileSync(path.join(root, DEFAULT_TRACE_FILE), 'utf-8')).toBe('');
164
+ });
165
+
166
+ it('writeProjectTraces 覆盖写:用例内重写不叠加旧记录', () => {
167
+ const root = createProjectFixture({
168
+ name: 'pfx-rewrite-traces',
169
+ traces: [{ constraintId: 'old' }],
170
+ });
171
+
172
+ writeProjectTraces(root, [{ constraintId: 'new' }]);
173
+
174
+ const lines = fs.readFileSync(path.join(root, DEFAULT_TRACE_FILE), 'utf-8').trim().split('\n');
175
+ expect(lines).toHaveLength(1);
176
+ expect(JSON.parse(lines[0]).constraintId).toBe('new');
177
+ });
178
+ });
@@ -0,0 +1,87 @@
1
+ /**
2
+ * 测试项目夹具构造 API(架构评审 2026-09-02 候选11 / harness#90)
3
+ *
4
+ * 职责:建一个临时项目根并按声明落 fixture,替掉散在各测试套件的
5
+ * `mkdtempSync + mkdir('.harness') + writeFileSync('config.yml')` 手写组合。
6
+ *
7
+ * 设计口径(triage 裁决):
8
+ * - **语义声明**而非文件树声明:`config`/`traces` 是独立槽位(`.harness/config.yml`
9
+ * 与 `DEFAULT_TRACE_FILE` 的形状正本只有这里知道),其余文件走 `files` 相对路径。
10
+ * constraints/knowledge 槽位随后续票补。
11
+ * - `config` 只收字符串、原样落盘:被检代码大量用例是畸形/脏配置(`governance: [`、
12
+ * `required_dirs: [1, null]`、未知 preset 名),YAML 往返会把这些用例抹平。
13
+ * - 非缺省根必须经 `parentDir` **显式**声明:默认根统一为 tmpdir,
14
+ * 路径锚定生产代码的用例(cwd 锚定)靠 opt-out 保持原语义,不隐式继承。
15
+ * - 清理不在本模块做:根经 `fs.mkdtempSync` 创建,由 ./mkdtemp-cleanup 的劫持在
16
+ * afterAll 统一回收(setupFilesAfterEnv 已全局装载)。
17
+ */
18
+
19
+ import * as fs from 'fs';
20
+ import * as os from 'os';
21
+ import * as path from 'path';
22
+ import { DEFAULT_TRACE_FILE, type ExecutionTrace } from '../types/trace';
23
+ import { appendJsonl } from '../utils/jsonl';
24
+
25
+ /** config.yml 相对项目根的落点(全仓唯一处,测试与生产读取口径在此对齐) */
26
+ const CONFIG_REL = path.join('.harness', 'config.yml');
27
+
28
+ /** name 只允许小写字母数字与连字符——见 mkdtemp-cleanup 的超龄清扫签名,大写/下划线会让漏网目录永不被扫 */
29
+ const NAME_RE = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
30
+
31
+ export interface ProjectFixtureDecl {
32
+ /** 用例标签,进入 mkdtemp 前缀(残留目录可定位到用例);小写连字符 */
33
+ name: string;
34
+ /** `.harness/config.yml` 内容,原样落盘;省略 = 不写该文件(未采用约定语义) */
35
+ config?: string;
36
+ /**
37
+ * trace 槽位(harness#108):落 `DEFAULT_TRACE_FILE` 的 JSONL 记录;
38
+ * 省略 = 不写该文件(traceFileExists=false 语义)。缺省字段补齐见 writeProjectTraces
39
+ */
40
+ traces?: Partial<ExecutionTrace>[];
41
+ /** 其余文件:相对路径 → 内容,父目录自动创建 */
42
+ files?: Record<string, string>;
43
+ /** 显式 opt-out:临时根的父目录,缺省 `os.tmpdir()`;cwd 锚定用例传 `process.cwd()` */
44
+ parentDir?: string;
45
+ }
46
+
47
+ /** 写入(或覆盖)项目根的 `.harness/config.yml`——用例内后续改配置走这里,不再手拼路径 */
48
+ export function writeProjectConfig(projectRoot: string, content: string): void {
49
+ const target = path.join(projectRoot, CONFIG_REL);
50
+ fs.mkdirSync(path.dirname(target), { recursive: true });
51
+ fs.writeFileSync(target, content, 'utf-8');
52
+ }
53
+
54
+ /**
55
+ * 写入(或覆盖)项目根的 trace 文件——路径锚定生产正本 DEFAULT_TRACE_FILE,
56
+ * 序列化走生产写链 appendJsonl(harness#108:测试不再手拼路径与 JSONL 形状,
57
+ * 生产端改格式时测试随之失真可见而非静默脱节)。
58
+ *
59
+ * 缺省字段补齐 level/timestamp/result(与原各套件 writeTraces 的口径一致),
60
+ * 调用方按需覆盖。覆盖语义:先清空再逐条 append;空数组仍落空文件
61
+ * (traceFileExists=true、零记录)。
62
+ */
63
+ export function writeProjectTraces(projectRoot: string, traces: Partial<ExecutionTrace>[]): void {
64
+ const target = path.join(projectRoot, DEFAULT_TRACE_FILE);
65
+ fs.mkdirSync(path.dirname(target), { recursive: true });
66
+ fs.writeFileSync(target, '', 'utf-8');
67
+ for (const t of traces) {
68
+ appendJsonl(target, { level: 'guideline', timestamp: 1700000000000, result: 'pass', ...t });
69
+ }
70
+ }
71
+
72
+ /** 建临时项目根并落声明式 fixture,返回根路径 */
73
+ export function createProjectFixture(decl: ProjectFixtureDecl): string {
74
+ if (!NAME_RE.test(decl.name)) {
75
+ throw new Error(`project-fixture: name 必须是小写连字符标签(收到 "${decl.name}"),否则残留目录无法被超龄清扫识别`);
76
+ }
77
+ const parent = decl.parentDir ?? os.tmpdir();
78
+ const root = fs.mkdtempSync(path.join(parent, `${decl.name}-`));
79
+ if (decl.config !== undefined) writeProjectConfig(root, decl.config);
80
+ if (decl.traces !== undefined) writeProjectTraces(root, decl.traces);
81
+ for (const [rel, content] of Object.entries(decl.files ?? {})) {
82
+ const target = path.join(root, rel);
83
+ fs.mkdirSync(path.dirname(target), { recursive: true });
84
+ fs.writeFileSync(target, content, 'utf-8');
85
+ }
86
+ return root;
87
+ }
@@ -13,6 +13,12 @@
13
13
  ## 约定
14
14
  - 工具定义目录路径由 paths 模块解析
15
15
  - `definitions/` 为静态能力目录,构建时复制到 dist
16
+ - **yml 目录是正本、`registry.json` 是派生索引**(#91 裁决):二者一致性由 `__tests__/registry.test.ts`
17
+ 按 ADR-0009 的 reconcile 形状守(双向集合对照 + 条目 path 指向存在的 yml + `name` 与 yml 内 `name` 一致)。
18
+ 新增能力 = 先落 yml,再补 registry 条目,缺一即测试红。**不做 yml schema 校验**——那等于替 studio 定能力契约。
19
+ `rollback` 重名 ×2(std/deploy 与 std/governance)是既有事实,进豁免名单;重名是否合法另票裁决。
20
+ - `paths.ts` 单变方**不是**假 seam(#91 裁决):它是包根公开导出(`src/index.ts`,由 public-exports 测试钉住),
21
+ 实际消费方是 studio 外部仓,本仓内无第二调用方属预期形状,留任
16
22
 
17
23
  ## 注意事项
18
24
  - 旧工具注册表/核心工具/加载器/类型定义已随 H1(#40)删除,仅保留路径管理与能力目录
@@ -0,0 +1,221 @@
1
+ /**
2
+ * tools 能力目录 registry 完整性测试(架构评审 2026-09-02 候选12 / harness#91)
3
+ *
4
+ * `src/tools/definitions/` 是随包发布的数据(package.json files 含 src),studio 经包根
5
+ * 公开导出消费(`getToolsDir` / `getRegistryPath`)——此前代码半边有 public-exports 钉住导出面,
6
+ * 数据半边零测试:幽灵项 / 漏登项 / path 悬空 / name 漂移都没人守。
7
+ * 这是 ADR-0002「注册型能力一律定义即注册 + 构建期闭环」唯一没覆盖的一类注册表。
8
+ *
9
+ * 裁决(#91 triage):
10
+ * - **yml 目录是正本**,registry.json 是派生索引 → 对照方向 = 双向集合一致
11
+ * - **不做 yml schema 校验**(那等于替 studio 定能力契约,破坏面外溢到 studio)
12
+ * - `rollback` 重名 ×2(std/deploy 与 std/governance)是既有事实,进豁免名单;
13
+ * 重名本身是否合法另票裁决 → 名单外的任何新重名一律红
14
+ *
15
+ * 判定形状参照 ADR-0009 的 reconcile:读声明 → 对照文件系统 → 产出双向差异清单,
16
+ * 失败信息一次报全(不逐条断言到第一个错就停)。
17
+ */
18
+
19
+ import * as fs from 'fs';
20
+ import * as path from 'path';
21
+ import * as yaml from 'js-yaml';
22
+ import { getRegistryPath, getToolsDir } from '../paths';
23
+ import { walkFiles } from '../../utils/file-walk';
24
+ import { createProjectFixture } from '../../test-setup/project-fixture';
25
+
26
+ /** registry.json 条目(只取本测试关心的两字段,schema 校验是 out of scope) */
27
+ interface RegistryEntry {
28
+ name: string;
29
+ path: string;
30
+ }
31
+
32
+ /** 一个 tools 定义目录的读取结果:派生索引声明 + 正本文件清单 + 正本内 name */
33
+ interface DefinitionsSnapshot {
34
+ /** registry.json 声明的条目 */
35
+ entries: RegistryEntry[];
36
+ /** definitions/ 下实际存在的 yml(相对定义根,`/` 分隔) */
37
+ ymlPaths: string[];
38
+ /** yml 内 name(相对路径 → name;读不到/非字符串 → null) */
39
+ ymlNames: Record<string, string | null>;
40
+ }
41
+
42
+ /** 双向漂移清单(ADR-0009 形状:一次产出全部判定,消费方按需取用) */
43
+ interface RegistryDrift {
44
+ /** 幽灵项:registry 登记了磁盘上不存在的 yml(含 path 悬空) */
45
+ ghostPaths: string[];
46
+ /** 漏登项:磁盘上的 yml 未被 registry 任何条目引用 */
47
+ unregisteredPaths: string[];
48
+ /** name 漂移:registry.name 与 yml 内 name 不一致(含 yml 缺 name) */
49
+ nameMismatches: string[];
50
+ /** 重名:同 name 被多条条目使用(排序) */
51
+ duplicateNames: string[];
52
+ }
53
+
54
+ /** 既有事实豁免:#91 裁决保留的重名,名单外新增即红 */
55
+ const KNOWN_DUPLICATE_NAMES = ['rollback'];
56
+
57
+ const EMPTY_DRIFT: RegistryDrift = {
58
+ ghostPaths: [],
59
+ unregisteredPaths: [],
60
+ nameMismatches: [],
61
+ duplicateNames: [],
62
+ };
63
+
64
+ /** 读一个定义目录:registry.json 声明 + yml 正本清单与其中的 name(相对路径统一 `/` 分隔) */
65
+ function readDefinitions(definitionsDir: string): DefinitionsSnapshot {
66
+ const registry = JSON.parse(fs.readFileSync(path.join(definitionsDir, 'registry.json'), 'utf-8')) as {
67
+ tools: RegistryEntry[];
68
+ };
69
+ const ymlPaths = walkFiles(definitionsDir, { filter: name => name.endsWith('.yml') })
70
+ .map(full => path.relative(definitionsDir, full).split(path.sep).join('/'))
71
+ .sort();
72
+ const ymlNames: Record<string, string | null> = {};
73
+ for (const rel of ymlPaths) {
74
+ const doc = yaml.load(fs.readFileSync(path.join(definitionsDir, rel), 'utf-8')) as
75
+ | { name?: unknown }
76
+ | undefined;
77
+ ymlNames[rel] = typeof doc?.name === 'string' ? doc.name : null;
78
+ }
79
+ return { entries: registry.tools, ymlPaths, ymlNames };
80
+ }
81
+
82
+ /** 双向对照(纯判定,不做 IO——ADR-0009 同口径) */
83
+ function reconcileRegistry(snapshot: DefinitionsSnapshot): RegistryDrift {
84
+ const ymlSet = new Set(snapshot.ymlPaths);
85
+ const declaredPaths = new Set<string>();
86
+ const seenNames = new Set<string>();
87
+ const duplicateNames = new Set<string>();
88
+ const ghostPaths: string[] = [];
89
+ const nameMismatches: string[] = [];
90
+
91
+ for (const entry of snapshot.entries) {
92
+ declaredPaths.add(entry.path);
93
+ if (!ymlSet.has(entry.path)) {
94
+ ghostPaths.push(entry.path);
95
+ continue; // 正本不存在,name 无从对照(幽灵项已含该条)
96
+ }
97
+ const ymlName = snapshot.ymlNames[entry.path];
98
+ if (ymlName !== entry.name) {
99
+ nameMismatches.push(
100
+ `${entry.path}: registry="${entry.name}" ${ymlName === null ? 'yml=<缺失>' : `yml="${ymlName}"`}`
101
+ );
102
+ }
103
+ if (seenNames.has(entry.name)) duplicateNames.add(entry.name);
104
+ seenNames.add(entry.name);
105
+ }
106
+
107
+ return {
108
+ ghostPaths: ghostPaths.sort(),
109
+ unregisteredPaths: snapshot.ymlPaths.filter(p => !declaredPaths.has(p)).sort(),
110
+ nameMismatches: nameMismatches.sort(),
111
+ duplicateNames: [...duplicateNames].sort(),
112
+ };
113
+ }
114
+
115
+ /** 临时定义根夹具(经 project-fixture 建根,afterAll 由 mkdtemp-cleanup 回收) */
116
+ function makeDefinitionsFixture(
117
+ label: string,
118
+ tools: RegistryEntry[],
119
+ ymls: Record<string, string>
120
+ ): string {
121
+ const files: Record<string, string> = {
122
+ 'definitions/registry.json': JSON.stringify({ tools }, null, 2),
123
+ };
124
+ for (const [rel, content] of Object.entries(ymls)) files[`definitions/${rel}`] = content;
125
+ return path.join(createProjectFixture({ name: `tools-registry-${label}`, files }), 'definitions');
126
+ }
127
+
128
+ const CLEAN_TOOLS: RegistryEntry[] = [
129
+ { name: 'code/parse', path: 'core/code/parse.yml' },
130
+ { name: 'deploy/rollback', path: 'std/deploy/rollback.yml' },
131
+ ];
132
+ const CLEAN_YMLS = {
133
+ 'core/code/parse.yml': 'name: code/parse\ndescription: parse\n',
134
+ 'std/deploy/rollback.yml': 'name: deploy/rollback\ndescription: rollback\n',
135
+ };
136
+
137
+ describe('tools registry 完整性 — 判定形状(ADR-0009 reconcile)', () => {
138
+ it('干净夹具:双向零漂移(不误报)', () => {
139
+ const snapshot = readDefinitions(makeDefinitionsFixture('clean', CLEAN_TOOLS, CLEAN_YMLS));
140
+ expect(reconcileRegistry(snapshot)).toEqual(EMPTY_DRIFT);
141
+ });
142
+
143
+ it('幽灵项 / path 悬空:registry 登记磁盘不存在的 yml → 红(闭环失败方向 1)', () => {
144
+ const snapshot = readDefinitions(
145
+ makeDefinitionsFixture('ghost', [...CLEAN_TOOLS, { name: 'ghost/item', path: 'std/ghost/item.yml' }], CLEAN_YMLS)
146
+ );
147
+ expect(reconcileRegistry(snapshot).ghostPaths).toEqual(['std/ghost/item.yml']);
148
+ });
149
+
150
+ it('漏登项:yml 存在但 registry 未登记 → 红(闭环失败方向 2)', () => {
151
+ const snapshot = readDefinitions(
152
+ makeDefinitionsFixture(
153
+ 'missing',
154
+ CLEAN_TOOLS,
155
+ { ...CLEAN_YMLS, 'std/unlisted/new-tool.yml': 'name: unlisted/new-tool\n' }
156
+ )
157
+ );
158
+ expect(reconcileRegistry(snapshot).unregisteredPaths).toEqual(['std/unlisted/new-tool.yml']);
159
+ });
160
+
161
+ it('name 漂移:registry.name 与 yml 内 name 不一致 → 红', () => {
162
+ const snapshot = readDefinitions(
163
+ makeDefinitionsFixture('name-drift', CLEAN_TOOLS, {
164
+ ...CLEAN_YMLS,
165
+ 'core/code/parse.yml': 'name: code/renamed\ndescription: parse\n',
166
+ })
167
+ );
168
+ expect(reconcileRegistry(snapshot).nameMismatches).toEqual([
169
+ 'core/code/parse.yml: registry="code/parse" yml="code/renamed"',
170
+ ]);
171
+ });
172
+
173
+ it('yml 缺 name 字段 → 计入 name 漂移(不做 schema 校验,但 name 是对照锚点)', () => {
174
+ const snapshot = readDefinitions(
175
+ makeDefinitionsFixture('name-absent', CLEAN_TOOLS, {
176
+ ...CLEAN_YMLS,
177
+ 'core/code/parse.yml': 'description: parse\n',
178
+ })
179
+ );
180
+ expect(reconcileRegistry(snapshot).nameMismatches).toEqual([
181
+ 'core/code/parse.yml: registry="code/parse" yml=<缺失>',
182
+ ]);
183
+ });
184
+
185
+ it('豁免名单外的新重名 → 红(rollback 重名合法性另票裁决,#91)', () => {
186
+ const snapshot = readDefinitions(
187
+ makeDefinitionsFixture(
188
+ 'dup',
189
+ [...CLEAN_TOOLS, { name: 'deploy/rollback', path: 'std/governance/rollback.yml' }],
190
+ { ...CLEAN_YMLS, 'std/governance/rollback.yml': 'name: deploy/rollback\n' }
191
+ )
192
+ );
193
+ expect(reconcileRegistry(snapshot).duplicateNames).toEqual(['deploy/rollback']);
194
+ });
195
+ });
196
+
197
+ describe('tools registry 完整性 — 真实数据(definitions/ 随包发布)', () => {
198
+ const snapshot = readDefinitions(getToolsDir());
199
+
200
+ it('yml 正本与 registry 派生索引双向一致:无幽灵、无漏登、path 全部指向存在的 yml', () => {
201
+ const drift = reconcileRegistry(snapshot);
202
+ expect({ ...drift, duplicateNames: drift.duplicateNames.filter(n => !KNOWN_DUPLICATE_NAMES.includes(n)) })
203
+ .toEqual(EMPTY_DRIFT);
204
+ });
205
+
206
+ it('重名豁免名单钉死:当前唯一重名 = rollback ×2,名单变化即红', () => {
207
+ expect(reconcileRegistry(snapshot).duplicateNames).toEqual(KNOWN_DUPLICATE_NAMES);
208
+ });
209
+
210
+ it('src/tools/CONTEXT.md 声明的 yml 计数与实际一致', () => {
211
+ const contextSource = fs.readFileSync(path.join(getToolsDir(), '..', 'CONTEXT.md'), 'utf-8');
212
+ const declared = contextSource.match(/(\d+) 个 yml/);
213
+ expect(declared).not.toBeNull();
214
+ expect(Number(declared?.[1])).toBe(snapshot.ymlPaths.length);
215
+ });
216
+
217
+ it('包根公开导出的两个路径入口指向存在的 definitions/ 与 registry.json(studio 消费面)', () => {
218
+ expect(fs.existsSync(getToolsDir())).toBe(true);
219
+ expect(fs.existsSync(getRegistryPath())).toBe(true);
220
+ });
221
+ });
@@ -1,14 +1,13 @@
1
1
  /**
2
- * src/types 模块导出覆盖测试
2
+ * src/types 类型层行为测试
3
3
  */
4
4
 
5
5
  import { describe, it, expect } from '@jest/globals';
6
6
 
7
- // barrel index.ts 导入,覆盖 re-export 行
8
- import { ConstraintViolationError } from '..';
7
+ import { ConstraintViolationError } from '../constraint';
9
8
 
10
- describe('types barrel exports', () => {
11
- it('ConstraintViolationError 应该可从 index 导入', () => {
9
+ describe('ConstraintViolationError 导出', () => {
10
+ it('ConstraintViolationError 应该可导入', () => {
12
11
  expect(ConstraintViolationError).toBeDefined();
13
12
  expect(typeof ConstraintViolationError).toBe('function');
14
13
  });
@@ -177,39 +177,14 @@ export interface ConstraintContext {
177
177
  /** 是否已进行复用检查 */
178
178
  hasReuseCheck?: boolean;
179
179
 
180
- /** 复用检查结果 */
181
- reuseCheckResult?: {
182
- existingCapabilities: string[];
183
- canReuse: boolean;
184
- reuseRecommendation: string;
185
- };
186
-
187
180
  /** 是否只处理单个任务(用于 incremental_progress) */
188
181
  hasSingleTask?: boolean;
189
182
 
190
- /** 是否已验证外部能力(对应约束已降级为 prompt,字段保留兼容) */
191
- hasExternalCapabilityVerification?: boolean;
192
-
193
- /** 是否已对比需求验证(review 变体已并入主约束,字段保留兼容) */
194
- hasRequirementReview?: boolean;
195
-
196
183
  /** 是否有需求文档(用于 no_implementation_without_requirement) */
197
184
  hasRequirement?: boolean;
198
185
 
199
- /** 是否在 worktree 中执行(对应约束已移出内置,字段保留兼容) */
200
- hasWorktree?: boolean;
201
-
202
186
  /** worktree 路径(用于 worktree 相关检查) */
203
187
  worktreePath?: string;
204
-
205
- /** 完成声明文本(对应检查已并入 prompt 层,字段保留兼容) */
206
- completionClaimText?: string;
207
-
208
- /** 是否完成两阶段审查(对应约束已移出内置,字段保留兼容) */
209
- hasTwoStageReview?: boolean;
210
-
211
- /** 执行上下文 */
212
- executionContext?: any;
213
188
  }
214
189
 
215
190
  /**
@@ -5,6 +5,14 @@
5
5
  * 不包含业务逻辑,只定义数据结构
6
6
  */
7
7
 
8
+ /**
9
+ * 默认 failure 日志路径(相对项目根目录)
10
+ *
11
+ * 读写双方必须统一引用此常量(DEFAULT_TRACE_FILE 同款先例);
12
+ * 自定义路径时向 FailureRecorder 传入自定 logFile
13
+ */
14
+ export const DEFAULT_FAILURE_LOG_FILE = '.harness/logs/failures.log';
15
+
8
16
  /**
9
17
  * 错误类型枚举
10
18
  */
@@ -9,13 +9,20 @@ export interface PassesGateConfig {
9
9
  /** 是否启用 */
10
10
  enabled?: boolean;
11
11
 
12
- /** 测试命令 */
12
+ /**
13
+ * 测试命令。缺省时走 core/validators/passes-gate.ts 的 detectTestCommand 探测:
14
+ * test:ci → test(排除 echo 占位脚本)→ test:e2e → test:coverage → Python 标记 → go.mod;
15
+ * 探不到则 fail-closed(不再兜底 'npm test')
16
+ */
13
17
  testCommand?: string;
14
18
 
15
19
  /** 是否需要证据 */
16
20
  requireEvidence?: boolean;
17
21
 
18
- /** 是否允许部分通过 */
22
+ /**
23
+ * 是否允许部分通过:退出码为 0 时,输出里的失败信号不再否决判定。
24
+ * 不赦免非零退出码(判定依据收在 core/validators/test-output.ts 的 judgeTestRun,ADR-0014)
25
+ */
19
26
  allowPartialPass?: boolean;
20
27
 
21
28
  /** 最大重试次数 */
@@ -50,9 +57,6 @@ export interface TaskTestResult {
50
57
  /** 失败的测试列表 */
51
58
  failures?: string[];
52
59
 
53
- /** 覆盖率 */
54
- coverage?: number;
55
-
56
60
  /** 证据路径 */
57
61
  evidence?: string;
58
62
  }
@@ -94,30 +98,6 @@ export interface DynamicTask {
94
98
  testResult?: TaskTestResult;
95
99
  }
96
100
 
97
- /**
98
- * PassesGate 扩展接口
99
- *
100
- * 用于注册额外的测试类型(如 Puppeteer E2E)
101
- */
102
- export interface PassesGateExtension {
103
- /** 扩展名称 */
104
- name: string;
105
-
106
- /** 扩展描述 */
107
- description?: string;
108
-
109
- /** 运行测试 */
110
- run(workDir: string, task?: DynamicTask): Promise<TaskTestResult>;
111
- }
112
-
113
- /**
114
- * 扩展测试结果(包含类型标识)
115
- */
116
- export interface ExtensionTestResult extends TaskTestResult {
117
- /** 测试类型(扩展名称) */
118
- type?: string;
119
- }
120
-
121
101
  // ========================================
122
102
  // AS-006: 纯约束验证接口
123
103
  // ========================================
@@ -134,7 +114,7 @@ export interface TestResult {
134
114
  /** 测试命令(可选,用于记录) */
135
115
  command?: string;
136
116
 
137
- /** 覆盖率(可选) */
117
+ /** 覆盖率(调用方自备数据,check() 不读它、只随 testResult 原样回显;harness 不取数不执法,ADR-0015) */
138
118
  coverage?: number;
139
119
 
140
120
  /** 证据路径(可选) */
@@ -41,7 +41,7 @@ export interface CustomConstraintDefinition {
41
41
  enabled?: boolean;
42
42
 
43
43
  /**
44
- * 退役元数据(#82 D6 统一落点)
44
+ * 退役元数据(studio#82 D6 统一落点)
45
45
  *
46
46
  * 存在即视为已退役:不进生效集、不注入 CLAUDE.md。恢复 = 删除该段。
47
47
  * 落点在 custom-constraints.yml 条目内(一处真相,不拆 config.yml 第二处)。