@dommaker/harness 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (532) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +0 -2
  3. package/bin/harness.js +86 -32
  4. package/dist/cli/command-contract.d.ts +83 -0
  5. package/dist/cli/command-contract.d.ts.map +1 -0
  6. package/dist/cli/command-contract.js +66 -0
  7. package/dist/cli/command-contract.js.map +1 -0
  8. package/dist/cli/commands/acceptance.d.ts +3 -2
  9. package/dist/cli/commands/acceptance.d.ts.map +1 -1
  10. package/dist/cli/commands/acceptance.js +28 -24
  11. package/dist/cli/commands/acceptance.js.map +1 -1
  12. package/dist/cli/commands/analyze-sessions.d.ts +2 -1
  13. package/dist/cli/commands/analyze-sessions.d.ts.map +1 -1
  14. package/dist/cli/commands/analyze-sessions.js +25 -24
  15. package/dist/cli/commands/analyze-sessions.js.map +1 -1
  16. package/dist/cli/commands/check.d.ts +14 -2
  17. package/dist/cli/commands/check.d.ts.map +1 -1
  18. package/dist/cli/commands/check.js +104 -61
  19. package/dist/cli/commands/check.js.map +1 -1
  20. package/dist/cli/commands/command.d.ts +5 -1
  21. package/dist/cli/commands/command.d.ts.map +1 -1
  22. package/dist/cli/commands/command.js +26 -17
  23. package/dist/cli/commands/command.js.map +1 -1
  24. package/dist/cli/commands/constraints-report.d.ts +2 -1
  25. package/dist/cli/commands/constraints-report.d.ts.map +1 -1
  26. package/dist/cli/commands/constraints-report.js +37 -33
  27. package/dist/cli/commands/constraints-report.js.map +1 -1
  28. package/dist/cli/commands/constraints-retire.d.ts +6 -5
  29. package/dist/cli/commands/constraints-retire.d.ts.map +1 -1
  30. package/dist/cli/commands/constraints-retire.js +50 -52
  31. package/dist/cli/commands/constraints-retire.js.map +1 -1
  32. package/dist/cli/commands/constraints.d.ts +2 -1
  33. package/dist/cli/commands/constraints.d.ts.map +1 -1
  34. package/dist/cli/commands/constraints.js +10 -27
  35. package/dist/cli/commands/constraints.js.map +1 -1
  36. package/dist/cli/commands/contract.d.ts +3 -2
  37. package/dist/cli/commands/contract.d.ts.map +1 -1
  38. package/dist/cli/commands/contract.js +45 -42
  39. package/dist/cli/commands/contract.js.map +1 -1
  40. package/dist/cli/commands/definitions.d.ts +11 -11
  41. package/dist/cli/commands/definitions.d.ts.map +1 -1
  42. package/dist/cli/commands/definitions.js +27 -219
  43. package/dist/cli/commands/definitions.js.map +1 -1
  44. package/dist/cli/commands/failure.d.ts +5 -4
  45. package/dist/cli/commands/failure.d.ts.map +1 -1
  46. package/dist/cli/commands/failure.js +31 -25
  47. package/dist/cli/commands/failure.js.map +1 -1
  48. package/dist/cli/commands/init.d.ts +7 -5
  49. package/dist/cli/commands/init.d.ts.map +1 -1
  50. package/dist/cli/commands/init.js +147 -211
  51. package/dist/cli/commands/init.js.map +1 -1
  52. package/dist/cli/commands/knowledge.d.ts +17 -30
  53. package/dist/cli/commands/knowledge.d.ts.map +1 -1
  54. package/dist/cli/commands/knowledge.js +183 -273
  55. package/dist/cli/commands/knowledge.js.map +1 -1
  56. package/dist/cli/commands/passes-gate.d.ts +8 -2
  57. package/dist/cli/commands/passes-gate.d.ts.map +1 -1
  58. package/dist/cli/commands/passes-gate.js +44 -66
  59. package/dist/cli/commands/passes-gate.js.map +1 -1
  60. package/dist/cli/commands/performance.d.ts +2 -1
  61. package/dist/cli/commands/performance.d.ts.map +1 -1
  62. package/dist/cli/commands/performance.js +20 -18
  63. package/dist/cli/commands/performance.js.map +1 -1
  64. package/dist/cli/commands/posteval-plan.d.ts +5 -1
  65. package/dist/cli/commands/posteval-plan.d.ts.map +1 -1
  66. package/dist/cli/commands/posteval-plan.js +26 -15
  67. package/dist/cli/commands/posteval-plan.js.map +1 -1
  68. package/dist/cli/commands/release.d.ts +6 -1
  69. package/dist/cli/commands/release.d.ts.map +1 -1
  70. package/dist/cli/commands/release.js +69 -59
  71. package/dist/cli/commands/release.js.map +1 -1
  72. package/dist/cli/commands/report.d.ts +2 -1
  73. package/dist/cli/commands/report.d.ts.map +1 -1
  74. package/dist/cli/commands/report.js +9 -5
  75. package/dist/cli/commands/report.js.map +1 -1
  76. package/dist/cli/commands/review.d.ts +3 -2
  77. package/dist/cli/commands/review.d.ts.map +1 -1
  78. package/dist/cli/commands/review.js +33 -29
  79. package/dist/cli/commands/review.js.map +1 -1
  80. package/dist/cli/commands/sdd.d.ts +2 -1
  81. package/dist/cli/commands/sdd.d.ts.map +1 -1
  82. package/dist/cli/commands/sdd.js +7 -5
  83. package/dist/cli/commands/sdd.js.map +1 -1
  84. package/dist/cli/commands/security.d.ts +3 -2
  85. package/dist/cli/commands/security.d.ts.map +1 -1
  86. package/dist/cli/commands/security.js +29 -26
  87. package/dist/cli/commands/security.js.map +1 -1
  88. package/dist/cli/commands/spec-baseline-check.d.ts +2 -1
  89. package/dist/cli/commands/spec-baseline-check.d.ts.map +1 -1
  90. package/dist/cli/commands/spec-baseline-check.js +15 -11
  91. package/dist/cli/commands/spec-baseline-check.js.map +1 -1
  92. package/dist/cli/commands/spec.d.ts +7 -2
  93. package/dist/cli/commands/spec.d.ts.map +1 -1
  94. package/dist/cli/commands/spec.js +61 -51
  95. package/dist/cli/commands/spec.js.map +1 -1
  96. package/dist/cli/commands/status.d.ts +2 -1
  97. package/dist/cli/commands/status.d.ts.map +1 -1
  98. package/dist/cli/commands/status.js +57 -53
  99. package/dist/cli/commands/status.js.map +1 -1
  100. package/dist/cli/commands/sync-docs/agents-syncer.d.ts.map +1 -1
  101. package/dist/cli/commands/sync-docs/agents-syncer.js +5 -2
  102. package/dist/cli/commands/sync-docs/agents-syncer.js.map +1 -1
  103. package/dist/cli/commands/sync-docs/context-syncer.d.ts.map +1 -1
  104. package/dist/cli/commands/sync-docs/context-syncer.js +3 -2
  105. package/dist/cli/commands/sync-docs/context-syncer.js.map +1 -1
  106. package/dist/cli/commands/sync-docs/index.d.ts +2 -1
  107. package/dist/cli/commands/sync-docs/index.d.ts.map +1 -1
  108. package/dist/cli/commands/sync-docs/index.js +68 -88
  109. package/dist/cli/commands/sync-docs/index.js.map +1 -1
  110. package/dist/cli/commands/sync-docs/project-reader.d.ts +6 -1
  111. package/dist/cli/commands/sync-docs/project-reader.d.ts.map +1 -1
  112. package/dist/cli/commands/sync-docs/project-reader.js +14 -16
  113. package/dist/cli/commands/sync-docs/project-reader.js.map +1 -1
  114. package/dist/cli/commands/update-user-model.d.ts +9 -3
  115. package/dist/cli/commands/update-user-model.d.ts.map +1 -1
  116. package/dist/cli/commands/update-user-model.js +56 -61
  117. package/dist/cli/commands/update-user-model.js.map +1 -1
  118. package/dist/cli/commands/validate.d.ts +4 -3
  119. package/dist/cli/commands/validate.d.ts.map +1 -1
  120. package/dist/cli/commands/validate.js +28 -26
  121. package/dist/cli/commands/validate.js.map +1 -1
  122. package/dist/cli/session-mining/transcript.d.ts +7 -1
  123. package/dist/cli/session-mining/transcript.d.ts.map +1 -1
  124. package/dist/cli/session-mining/transcript.js +21 -14
  125. package/dist/cli/session-mining/transcript.js.map +1 -1
  126. package/dist/context/session-manager.d.ts.map +1 -1
  127. package/dist/context/session-manager.js +19 -32
  128. package/dist/context/session-manager.js.map +1 -1
  129. package/dist/core/constraints/agent-prompt-renderer.d.ts.map +1 -1
  130. package/dist/core/constraints/agent-prompt-renderer.js +1 -4
  131. package/dist/core/constraints/agent-prompt-renderer.js.map +1 -1
  132. package/dist/core/constraints/capabilities-parser.d.ts +24 -7
  133. package/dist/core/constraints/capabilities-parser.d.ts.map +1 -1
  134. package/dist/core/constraints/capabilities-parser.js +32 -28
  135. package/dist/core/constraints/capabilities-parser.js.map +1 -1
  136. package/dist/core/constraints/capabilities-reconcile.d.ts +67 -0
  137. package/dist/core/constraints/capabilities-reconcile.d.ts.map +1 -0
  138. package/dist/core/constraints/capabilities-reconcile.js +105 -0
  139. package/dist/core/constraints/capabilities-reconcile.js.map +1 -0
  140. package/dist/core/constraints/checker.d.ts +21 -43
  141. package/dist/core/constraints/checker.d.ts.map +1 -1
  142. package/dist/core/constraints/checker.js +68 -117
  143. package/dist/core/constraints/checker.js.map +1 -1
  144. package/dist/core/constraints/checkers/capability-sync.d.ts +20 -8
  145. package/dist/core/constraints/checkers/capability-sync.d.ts.map +1 -1
  146. package/dist/core/constraints/checkers/capability-sync.js +66 -77
  147. package/dist/core/constraints/checkers/capability-sync.js.map +1 -1
  148. package/dist/core/constraints/checkers/context-doc-sync.d.ts +4 -2
  149. package/dist/core/constraints/checkers/context-doc-sync.d.ts.map +1 -1
  150. package/dist/core/constraints/checkers/context-doc-sync.js +13 -22
  151. package/dist/core/constraints/checkers/context-doc-sync.js.map +1 -1
  152. package/dist/core/constraints/checkers/docs-freshness.d.ts.map +1 -1
  153. package/dist/core/constraints/checkers/docs-freshness.js +49 -66
  154. package/dist/core/constraints/checkers/docs-freshness.js.map +1 -1
  155. package/dist/core/constraints/checkers/governance-presence.d.ts +2 -2
  156. package/dist/core/constraints/checkers/governance-presence.d.ts.map +1 -1
  157. package/dist/core/constraints/checkers/governance-presence.js +7 -28
  158. package/dist/core/constraints/checkers/governance-presence.js.map +1 -1
  159. package/dist/core/constraints/checkers/index.d.ts +2 -2
  160. package/dist/core/constraints/checkers/index.d.ts.map +1 -1
  161. package/dist/core/constraints/checkers/index.js +2 -1
  162. package/dist/core/constraints/checkers/index.js.map +1 -1
  163. package/dist/core/constraints/checkers/no-test-simplification.d.ts.map +1 -1
  164. package/dist/core/constraints/checkers/no-test-simplification.js +4 -3
  165. package/dist/core/constraints/checkers/no-test-simplification.js.map +1 -1
  166. package/dist/core/constraints/checkers/types.d.ts +43 -4
  167. package/dist/core/constraints/checkers/types.d.ts.map +1 -1
  168. package/dist/core/constraints/checkers/types.js +33 -0
  169. package/dist/core/constraints/checkers/types.js.map +1 -1
  170. package/dist/core/constraints/context-builder.d.ts +15 -14
  171. package/dist/core/constraints/context-builder.d.ts.map +1 -1
  172. package/dist/core/constraints/context-builder.js +32 -96
  173. package/dist/core/constraints/context-builder.js.map +1 -1
  174. package/dist/core/constraints/doc-freshness/runner.d.ts.map +1 -1
  175. package/dist/core/constraints/doc-freshness/runner.js +2 -1
  176. package/dist/core/constraints/doc-freshness/runner.js.map +1 -1
  177. package/dist/core/constraints/git-evidence.d.ts +60 -0
  178. package/dist/core/constraints/git-evidence.d.ts.map +1 -0
  179. package/dist/core/constraints/git-evidence.js +88 -0
  180. package/dist/core/constraints/git-evidence.js.map +1 -0
  181. package/dist/core/constraints/injection-drift.d.ts +3 -20
  182. package/dist/core/constraints/injection-drift.d.ts.map +1 -1
  183. package/dist/core/constraints/injection-drift.js +10 -57
  184. package/dist/core/constraints/injection-drift.js.map +1 -1
  185. package/dist/core/constraints/injection-writer.d.ts +113 -0
  186. package/dist/core/constraints/injection-writer.d.ts.map +1 -0
  187. package/dist/core/constraints/injection-writer.js +228 -0
  188. package/dist/core/constraints/injection-writer.js.map +1 -0
  189. package/dist/core/constraints/usage-report.d.ts +22 -1
  190. package/dist/core/constraints/usage-report.d.ts.map +1 -1
  191. package/dist/core/constraints/usage-report.js +27 -20
  192. package/dist/core/constraints/usage-report.js.map +1 -1
  193. package/dist/core/index.d.ts +2 -2
  194. package/dist/core/index.d.ts.map +1 -1
  195. package/dist/core/index.js +4 -2
  196. package/dist/core/index.js.map +1 -1
  197. package/dist/core/project-config-loader.d.ts +32 -1
  198. package/dist/core/project-config-loader.d.ts.map +1 -1
  199. package/dist/core/project-config-loader.js +39 -9
  200. package/dist/core/project-config-loader.js.map +1 -1
  201. package/dist/core/validators/passes-gate.d.ts +15 -64
  202. package/dist/core/validators/passes-gate.d.ts.map +1 -1
  203. package/dist/core/validators/passes-gate.js +84 -222
  204. package/dist/core/validators/passes-gate.js.map +1 -1
  205. package/dist/core/validators/test-output.d.ts +58 -0
  206. package/dist/core/validators/test-output.d.ts.map +1 -0
  207. package/dist/core/validators/test-output.js +109 -0
  208. package/dist/core/validators/test-output.js.map +1 -0
  209. package/dist/failure/recorder.d.ts +6 -0
  210. package/dist/failure/recorder.d.ts.map +1 -1
  211. package/dist/failure/recorder.js +12 -8
  212. package/dist/failure/recorder.js.map +1 -1
  213. package/dist/gates/acceptance.d.ts +1 -48
  214. package/dist/gates/acceptance.d.ts.map +1 -1
  215. package/dist/gates/acceptance.js +6 -38
  216. package/dist/gates/acceptance.js.map +1 -1
  217. package/dist/gates/checker-gate.d.ts +2 -1
  218. package/dist/gates/checker-gate.d.ts.map +1 -1
  219. package/dist/gates/checker-gate.js +11 -13
  220. package/dist/gates/checker-gate.js.map +1 -1
  221. package/dist/gates/command.d.ts.map +1 -1
  222. package/dist/gates/command.js +10 -22
  223. package/dist/gates/command.js.map +1 -1
  224. package/dist/gates/contract.d.ts.map +1 -1
  225. package/dist/gates/contract.js +22 -61
  226. package/dist/gates/contract.js.map +1 -1
  227. package/dist/gates/performance.d.ts.map +1 -1
  228. package/dist/gates/performance.js +13 -31
  229. package/dist/gates/performance.js.map +1 -1
  230. package/dist/gates/review.d.ts.map +1 -1
  231. package/dist/gates/review.js +21 -53
  232. package/dist/gates/review.js.map +1 -1
  233. package/dist/gates/security.d.ts.map +1 -1
  234. package/dist/gates/security.js +14 -32
  235. package/dist/gates/security.js.map +1 -1
  236. package/dist/gates/types.d.ts +28 -5
  237. package/dist/gates/types.d.ts.map +1 -1
  238. package/dist/gates/types.js +38 -1
  239. package/dist/gates/types.js.map +1 -1
  240. package/dist/hooks/bootstrap.d.ts +2 -0
  241. package/dist/hooks/bootstrap.d.ts.map +1 -1
  242. package/dist/hooks/bootstrap.js +5 -2
  243. package/dist/hooks/bootstrap.js.map +1 -1
  244. package/dist/index.d.ts +1 -2
  245. package/dist/index.d.ts.map +1 -1
  246. package/dist/index.js.map +1 -1
  247. package/dist/knowledge/audit.d.ts +7 -2
  248. package/dist/knowledge/audit.d.ts.map +1 -1
  249. package/dist/knowledge/audit.js +59 -79
  250. package/dist/knowledge/audit.js.map +1 -1
  251. package/dist/knowledge/flywheel-metrics.d.ts +39 -0
  252. package/dist/knowledge/flywheel-metrics.d.ts.map +1 -0
  253. package/dist/knowledge/flywheel-metrics.js +47 -0
  254. package/dist/knowledge/flywheel-metrics.js.map +1 -0
  255. package/dist/knowledge/import.d.ts.map +1 -1
  256. package/dist/knowledge/import.js +4 -14
  257. package/dist/knowledge/import.js.map +1 -1
  258. package/dist/knowledge/index-generator.d.ts.map +1 -1
  259. package/dist/knowledge/index-generator.js +17 -14
  260. package/dist/knowledge/index-generator.js.map +1 -1
  261. package/dist/knowledge/ingest.d.ts.map +1 -1
  262. package/dist/knowledge/ingest.js +9 -4
  263. package/dist/knowledge/ingest.js.map +1 -1
  264. package/dist/knowledge/migration.d.ts.map +1 -1
  265. package/dist/knowledge/migration.js +11 -8
  266. package/dist/knowledge/migration.js.map +1 -1
  267. package/dist/knowledge/reference-tracker.d.ts.map +1 -1
  268. package/dist/knowledge/reference-tracker.js +12 -9
  269. package/dist/knowledge/reference-tracker.js.map +1 -1
  270. package/dist/knowledge/store.d.ts +15 -0
  271. package/dist/knowledge/store.d.ts.map +1 -1
  272. package/dist/knowledge/store.js +59 -10
  273. package/dist/knowledge/store.js.map +1 -1
  274. package/dist/monitoring/context-tracker.d.ts.map +1 -1
  275. package/dist/monitoring/context-tracker.js +11 -20
  276. package/dist/monitoring/context-tracker.js.map +1 -1
  277. package/dist/monitoring/index.d.ts +1 -1
  278. package/dist/monitoring/index.d.ts.map +1 -1
  279. package/dist/monitoring/index.js +1 -2
  280. package/dist/monitoring/index.js.map +1 -1
  281. package/dist/monitoring/trace-analyzer.d.ts +15 -0
  282. package/dist/monitoring/trace-analyzer.d.ts.map +1 -1
  283. package/dist/monitoring/trace-analyzer.js +19 -2
  284. package/dist/monitoring/trace-analyzer.js.map +1 -1
  285. package/dist/monitoring/traces.d.ts +21 -2
  286. package/dist/monitoring/traces.d.ts.map +1 -1
  287. package/dist/monitoring/traces.js +38 -29
  288. package/dist/monitoring/traces.js.map +1 -1
  289. package/dist/release/index.d.ts +2 -2
  290. package/dist/release/index.d.ts.map +1 -1
  291. package/dist/release/index.js +1 -5
  292. package/dist/release/index.js.map +1 -1
  293. package/dist/sdd/index-generator.js +10 -11
  294. package/dist/sdd/index-generator.js.map +1 -1
  295. package/dist/test-setup/project-fixture.d.ts +48 -0
  296. package/dist/test-setup/project-fixture.d.ts.map +1 -0
  297. package/dist/test-setup/project-fixture.js +106 -0
  298. package/dist/test-setup/project-fixture.js.map +1 -0
  299. package/dist/types/constraint.d.ts +8 -18
  300. package/dist/types/constraint.d.ts.map +1 -1
  301. package/dist/types/constraint.js +6 -1
  302. package/dist/types/constraint.js.map +1 -1
  303. package/dist/types/passes-gate.d.ts +10 -25
  304. package/dist/types/passes-gate.d.ts.map +1 -1
  305. package/dist/types/project-config.d.ts +1 -1
  306. package/dist/types/session.d.ts +6 -5
  307. package/dist/types/session.d.ts.map +1 -1
  308. package/dist/types/trace.d.ts +9 -0
  309. package/dist/types/trace.d.ts.map +1 -1
  310. package/dist/utils/exec.d.ts +10 -0
  311. package/dist/utils/exec.d.ts.map +1 -1
  312. package/dist/utils/exec.js +12 -0
  313. package/dist/utils/exec.js.map +1 -1
  314. package/dist/utils/file-walk.d.ts +9 -1
  315. package/dist/utils/file-walk.d.ts.map +1 -1
  316. package/dist/utils/file-walk.js +10 -1
  317. package/dist/utils/file-walk.js.map +1 -1
  318. package/dist/utils/frontmatter.d.ts +73 -0
  319. package/dist/utils/frontmatter.d.ts.map +1 -0
  320. package/dist/utils/frontmatter.js +141 -0
  321. package/dist/utils/frontmatter.js.map +1 -0
  322. package/dist/utils/jsonl.d.ts +92 -0
  323. package/dist/utils/jsonl.d.ts.map +1 -0
  324. package/dist/utils/jsonl.js +166 -0
  325. package/dist/utils/jsonl.js.map +1 -0
  326. package/dist/utils/package-version.d.ts +16 -0
  327. package/dist/utils/package-version.d.ts.map +1 -0
  328. package/dist/utils/package-version.js +63 -0
  329. package/dist/utils/package-version.js.map +1 -0
  330. package/package.json +1 -1
  331. package/src/CONTEXT.md +8 -2
  332. package/src/__tests__/acceptance-gate.test.ts +3 -1
  333. package/src/__tests__/checker-extra.test.ts +7 -1218
  334. package/src/__tests__/context-files-resolution.test.ts +116 -0
  335. package/src/__tests__/effective-constraints.test.ts +10 -13
  336. package/src/__tests__/exec.test.ts +35 -1
  337. package/src/__tests__/layering.test.ts +152 -0
  338. package/src/__tests__/passes-gate-extra.test.ts +0 -145
  339. package/src/__tests__/passes-gate.test.ts +130 -101
  340. package/src/__tests__/skip-semantics.test.ts +5 -9
  341. package/src/cli/__tests__/command-contract.test.ts +170 -0
  342. package/src/cli/command-contract.ts +108 -0
  343. package/src/cli/commands/CONTEXT.md +23 -8
  344. package/src/cli/commands/__tests__/acceptance.test.ts +40 -33
  345. package/src/cli/commands/__tests__/analyze-sessions.test.ts +35 -29
  346. package/src/cli/commands/__tests__/bin-exit-mapping.test.ts +107 -0
  347. package/src/cli/commands/__tests__/check-drift.test.ts +27 -34
  348. package/src/cli/commands/__tests__/check-skip-output.test.ts +21 -24
  349. package/src/cli/commands/__tests__/check.test.ts +448 -378
  350. package/src/cli/commands/__tests__/command.test.ts +85 -70
  351. package/src/cli/commands/__tests__/constraints-report.test.ts +100 -71
  352. package/src/cli/commands/__tests__/constraints-retire.test.ts +152 -95
  353. package/src/cli/commands/__tests__/contract.test.ts +27 -34
  354. package/src/cli/commands/__tests__/failure.test.ts +31 -34
  355. package/src/cli/commands/__tests__/init-injection.test.ts +58 -28
  356. package/src/cli/commands/__tests__/init.test.ts +77 -48
  357. package/src/cli/commands/__tests__/knowledge-flywheel-consistency.test.ts +108 -0
  358. package/src/cli/commands/__tests__/knowledge.test.ts +69 -43
  359. package/src/cli/commands/__tests__/passes-gate.test.ts +43 -45
  360. package/src/cli/commands/__tests__/performance.test.ts +22 -23
  361. package/src/cli/commands/__tests__/posteval-plan.test.ts +39 -38
  362. package/src/cli/commands/__tests__/project-path-anchoring.test.ts +157 -0
  363. package/src/cli/commands/__tests__/project-path-convention.test.ts +231 -0
  364. package/src/cli/commands/__tests__/registry.test.ts +75 -35
  365. package/src/cli/commands/__tests__/release.test.ts +209 -80
  366. package/src/cli/commands/__tests__/report-extra.test.ts +16 -16
  367. package/src/cli/commands/__tests__/report.test.ts +25 -25
  368. package/src/cli/commands/__tests__/review.test.ts +33 -31
  369. package/src/cli/commands/__tests__/security.test.ts +23 -27
  370. package/src/cli/commands/__tests__/spec-baseline-check.test.ts +20 -20
  371. package/src/cli/commands/__tests__/spec.test.ts +41 -29
  372. package/src/cli/commands/__tests__/status-extra.test.ts +18 -18
  373. package/src/cli/commands/__tests__/status-skipped-lines.test.ts +72 -0
  374. package/src/cli/commands/__tests__/status.test.ts +34 -34
  375. package/src/cli/commands/__tests__/sync-docs-agents.test.ts +77 -78
  376. package/src/cli/commands/__tests__/sync-docs.test.ts +72 -74
  377. package/src/cli/commands/__tests__/update-user-model.test.ts +97 -34
  378. package/src/cli/commands/__tests__/validate.test.ts +27 -29
  379. package/src/cli/commands/acceptance.ts +35 -24
  380. package/src/cli/commands/analyze-sessions.ts +25 -24
  381. package/src/cli/commands/check.ts +127 -66
  382. package/src/cli/commands/command.ts +30 -17
  383. package/src/cli/commands/constraints-report.ts +37 -34
  384. package/src/cli/commands/constraints-retire.ts +58 -55
  385. package/src/cli/commands/constraints.ts +10 -27
  386. package/src/cli/commands/contract.ts +51 -42
  387. package/src/cli/commands/definitions.ts +34 -227
  388. package/src/cli/commands/failure.ts +33 -26
  389. package/src/cli/commands/init.ts +166 -220
  390. package/src/cli/commands/knowledge.ts +192 -289
  391. package/src/cli/commands/passes-gate.ts +58 -68
  392. package/src/cli/commands/performance.ts +23 -18
  393. package/src/cli/commands/posteval-plan.ts +29 -15
  394. package/src/cli/commands/release.ts +70 -59
  395. package/src/cli/commands/report.ts +9 -5
  396. package/src/cli/commands/review.ts +39 -29
  397. package/src/cli/commands/sdd.ts +7 -5
  398. package/src/cli/commands/security.ts +35 -26
  399. package/src/cli/commands/spec-baseline-check.ts +16 -11
  400. package/src/cli/commands/spec.ts +66 -53
  401. package/src/cli/commands/status.ts +59 -53
  402. package/src/cli/commands/sync-docs/agents-syncer.ts +5 -2
  403. package/src/cli/commands/sync-docs/context-syncer.ts +3 -2
  404. package/src/cli/commands/sync-docs/index.ts +73 -100
  405. package/src/cli/commands/sync-docs/project-reader.ts +17 -18
  406. package/src/cli/commands/update-user-model.ts +64 -61
  407. package/src/cli/commands/validate.ts +31 -25
  408. package/src/cli/session-mining/__tests__/transcript.test.ts +118 -0
  409. package/src/cli/session-mining/transcript.ts +26 -8
  410. package/src/context/session-manager.ts +19 -33
  411. package/src/core/CONTEXT.md +10 -6
  412. package/src/core/constraints/__tests__/capabilities-reconcile.test.ts +200 -0
  413. package/src/core/constraints/__tests__/capability-counts.test.ts +94 -0
  414. package/src/core/constraints/__tests__/git-evidence.test.ts +208 -0
  415. package/src/core/constraints/__tests__/injection-drift.test.ts +3 -10
  416. package/src/core/constraints/__tests__/injection-writer.test.ts +231 -0
  417. package/src/core/constraints/__tests__/trace-injection.test.ts +71 -0
  418. package/src/core/constraints/__tests__/usage-report.test.ts +112 -0
  419. package/src/core/constraints/agent-prompt-renderer.ts +2 -6
  420. package/src/core/constraints/capabilities-parser.ts +53 -35
  421. package/src/core/constraints/capabilities-reconcile.ts +166 -0
  422. package/src/core/constraints/checker.ts +82 -133
  423. package/src/core/constraints/checkers/__tests__/capability-sync.test.ts +273 -0
  424. package/src/core/constraints/checkers/__tests__/check-outcome.test.ts +176 -0
  425. package/src/core/constraints/checkers/__tests__/context-doc-sync.test.ts +77 -0
  426. package/src/core/constraints/checkers/__tests__/docs-freshness.test.ts +126 -0
  427. package/src/{__tests__ → core/constraints/checkers/__tests__}/governance-presence.test.ts +83 -9
  428. package/src/core/constraints/checkers/__tests__/iron-flags.test.ts +50 -0
  429. package/src/core/constraints/checkers/__tests__/no-bypass-checkpoint.test.ts +76 -0
  430. package/src/{__tests__ → core/constraints/checkers/__tests__}/no-hardcoded-credentials.test.ts +4 -3
  431. package/src/core/constraints/checkers/__tests__/no-test-simplification.test.ts +58 -0
  432. package/src/core/constraints/checkers/__tests__/three-state-consistency.test.ts +153 -0
  433. package/src/core/constraints/checkers/capability-sync.ts +75 -96
  434. package/src/core/constraints/checkers/context-doc-sync.ts +15 -25
  435. package/src/core/constraints/checkers/docs-freshness.ts +54 -70
  436. package/src/core/constraints/checkers/governance-presence.ts +7 -25
  437. package/src/core/constraints/checkers/index.ts +9 -2
  438. package/src/core/constraints/checkers/no-test-simplification.ts +4 -3
  439. package/src/core/constraints/checkers/types.ts +60 -4
  440. package/src/core/constraints/context-builder.ts +39 -91
  441. package/src/core/constraints/doc-freshness/runner.ts +2 -1
  442. package/src/core/constraints/git-evidence.ts +120 -0
  443. package/src/core/constraints/injection-drift.ts +13 -60
  444. package/src/core/constraints/injection-writer.ts +212 -0
  445. package/src/core/constraints/usage-report.ts +36 -17
  446. package/src/core/index.ts +4 -2
  447. package/src/core/project-config-loader.ts +49 -9
  448. package/src/core/validators/__tests__/passes-gate.test.ts +2 -56
  449. package/src/core/validators/__tests__/test-output.test.ts +372 -0
  450. package/src/core/validators/passes-gate.ts +86 -248
  451. package/src/core/validators/test-output.ts +128 -0
  452. package/src/failure/__tests__/recorder.test.ts +168 -0
  453. package/src/failure/recorder.ts +12 -10
  454. package/src/gates/CONTEXT.md +7 -4
  455. package/src/gates/__tests__/acceptance-types-single-source.test.ts +68 -0
  456. package/src/gates/__tests__/acceptance.test.ts +4 -86
  457. package/src/gates/__tests__/checker-gate.test.ts +24 -0
  458. package/src/gates/__tests__/effective-gates.test.ts +3 -8
  459. package/src/gates/__tests__/test-verdict-consistency.test.ts +140 -0
  460. package/src/gates/acceptance.ts +19 -84
  461. package/src/gates/checker-gate.ts +12 -15
  462. package/src/gates/command.ts +10 -16
  463. package/src/gates/contract.ts +22 -61
  464. package/src/gates/performance.ts +10 -22
  465. package/src/gates/review.ts +21 -41
  466. package/src/gates/security.ts +10 -22
  467. package/src/gates/types.ts +70 -5
  468. package/src/hooks/CONTEXT.md +1 -1
  469. package/src/hooks/bootstrap.ts +5 -2
  470. package/src/index.ts +0 -4
  471. package/src/knowledge/CONTEXT.md +8 -3
  472. package/src/knowledge/__tests__/audit-labels.test.ts +44 -0
  473. package/src/knowledge/__tests__/flywheel-metrics.test.ts +135 -0
  474. package/src/knowledge/__tests__/import.test.ts +44 -0
  475. package/src/knowledge/__tests__/index-generator.test.ts +53 -0
  476. package/src/knowledge/__tests__/ingest.test.ts +85 -0
  477. package/src/knowledge/__tests__/migration.test.ts +47 -0
  478. package/src/knowledge/__tests__/reference-tracker.test.ts +16 -0
  479. package/src/knowledge/__tests__/store.test.ts +194 -0
  480. package/src/knowledge/audit.ts +67 -71
  481. package/src/knowledge/flywheel-metrics.ts +71 -0
  482. package/src/knowledge/import.ts +4 -18
  483. package/src/knowledge/index-generator.ts +19 -14
  484. package/src/knowledge/ingest.ts +9 -4
  485. package/src/knowledge/migration.ts +11 -8
  486. package/src/knowledge/reference-tracker.ts +12 -8
  487. package/src/knowledge/store.ts +64 -11
  488. package/src/monitoring/CONTEXT.md +8 -3
  489. package/src/monitoring/__tests__/skipped-lines-report.test.ts +178 -0
  490. package/src/monitoring/__tests__/traces.test.ts +57 -0
  491. package/src/monitoring/context-tracker.ts +11 -23
  492. package/src/monitoring/index.ts +1 -1
  493. package/src/monitoring/trace-analyzer.ts +21 -2
  494. package/src/monitoring/traces.ts +39 -36
  495. package/src/release/CONTEXT.md +1 -0
  496. package/src/release/__tests__/barrel.test.ts +60 -0
  497. package/src/release/index.ts +2 -13
  498. package/src/sdd/__tests__/index-generator.test.ts +71 -0
  499. package/src/sdd/index-generator.ts +9 -9
  500. package/src/test-setup/__tests__/project-fixture.test.ts +178 -0
  501. package/src/test-setup/project-fixture.ts +87 -0
  502. package/src/tools/CONTEXT.md +6 -0
  503. package/src/tools/__tests__/registry.test.ts +221 -0
  504. package/src/types/__tests__/types.test.ts +4 -5
  505. package/src/types/constraint.ts +16 -27
  506. package/src/types/passes-gate.ts +10 -30
  507. package/src/types/project-config.ts +1 -1
  508. package/src/types/session.ts +5 -5
  509. package/src/types/trace.ts +10 -0
  510. package/src/utils/__tests__/frontmatter.test.ts +206 -0
  511. package/src/utils/__tests__/jsonl-skip-disposition.test.ts +175 -0
  512. package/src/utils/__tests__/jsonl.test.ts +187 -0
  513. package/src/utils/__tests__/package-version.test.ts +97 -0
  514. package/src/utils/exec.ts +15 -0
  515. package/src/utils/file-walk.ts +11 -2
  516. package/src/utils/frontmatter.ts +121 -0
  517. package/src/utils/jsonl.ts +167 -0
  518. package/src/utils/package-version.ts +27 -0
  519. package/dist/cli/commands/doc-freshness-check.d.ts +0 -53
  520. package/dist/cli/commands/doc-freshness-check.d.ts.map +0 -1
  521. package/dist/cli/commands/doc-freshness-check.js +0 -352
  522. package/dist/cli/commands/doc-freshness-check.js.map +0 -1
  523. package/dist/types/index.d.ts +0 -14
  524. package/dist/types/index.d.ts.map +0 -1
  525. package/dist/types/index.js +0 -39
  526. package/dist/types/index.js.map +0 -1
  527. package/src/__tests__/long-running.test.ts +0 -17
  528. package/src/__tests__/passes-gate-extension.test.ts +0 -151
  529. package/src/cli/commands/__tests__/doc-freshness-check.test.ts +0 -168
  530. package/src/cli/commands/doc-freshness-check.ts +0 -386
  531. package/src/spec/CONTEXT.md +0 -11
  532. package/src/types/index.ts +0 -47
@@ -13,6 +13,7 @@ import * as path from 'path';
13
13
  import type { Constraint } from '../../types/constraint';
14
14
  import type { ExecutionTrace } from '../../types/trace';
15
15
  import { DEFAULT_TRACE_FILE } from '../../types/trace';
16
+ import { readJsonl } from '../../utils/jsonl';
16
17
  import { getEffectiveConstraints, lintEffectiveConfig } from '../effective-constraints';
17
18
  import type { EffectiveConfigLint } from '../effective-constraints';
18
19
 
@@ -67,6 +68,14 @@ export interface RetireCandidate {
67
68
  reason: string;
68
69
  }
69
70
 
71
+ /** 候选种类的呈现名(constraints report / retire 共用) */
72
+ export const CANDIDATE_KIND_LABEL: Record<RetireCandidateKind, string> = {
73
+ zero_trigger: '零触发',
74
+ unevaluable: '不可评估',
75
+ high_noise: '高噪',
76
+ zero_intercept: '零拦截',
77
+ };
78
+
70
79
  /**
71
80
  * 候选诊断阈值(CLI 可覆盖)
72
81
  */
@@ -99,27 +108,36 @@ export interface ConstraintsUsageReport {
99
108
  lint: EffectiveConfigLint;
100
109
  /** trace 文件是否存在 */
101
110
  traceFileExists: boolean;
111
+ /**
112
+ * trace 文件被跳过的坏行数(harness#100,与 `traceFileExists` 同一降级维度)
113
+ *
114
+ * 恒有值,0 = 无损坏。文件级口径:坏行没有 timestamp,归不进任何统计窗口。
115
+ */
116
+ skippedLines: number;
102
117
  }
103
118
 
104
119
  /**
105
- * 读取项目 traces.log(只读,容错:坏行跳过)
120
+ * 读取项目 traces.log 并带出坏行计数(只读,harness#100 报告入口)
121
+ *
122
+ * 坏行策略:skip(原语义不变——report 只读,不因单行损坏失败);
123
+ * 计数去向:透传——`skippedLines` 随本方法返回,进 `ConstraintsUsageReport.skippedLines`,
124
+ * 消费面为 `constraints report` 的文本行 / `--json` 字段 / `--export` 摘要。
125
+ */
126
+ export function readProjectTracesReport(projectRoot: string): { traces: ExecutionTrace[]; skippedLines: number } {
127
+ const { records, skippedLines } = readJsonl<ExecutionTrace>(
128
+ path.join(projectRoot, DEFAULT_TRACE_FILE),
129
+ 'skip'
130
+ );
131
+ return { traces: records, skippedLines };
132
+ }
133
+
134
+ /**
135
+ * 读取项目 traces.log(只读)
136
+ *
137
+ * 兼容签名:只返回记录数组、丢坏行计数,需要计数的消费方走 `readProjectTracesReport()`。
106
138
  */
107
139
  export function readProjectTraces(projectRoot: string): ExecutionTrace[] {
108
- const tracePath = path.join(projectRoot, DEFAULT_TRACE_FILE);
109
- if (!fs.existsSync(tracePath)) return [];
110
-
111
- const content = fs.readFileSync(tracePath, 'utf-8');
112
- const traces: ExecutionTrace[] = [];
113
- for (const line of content.split('\n')) {
114
- const trimmed = line.trim();
115
- if (!trimmed) continue;
116
- try {
117
- traces.push(JSON.parse(trimmed) as ExecutionTrace);
118
- } catch {
119
- // 坏行跳过(report 只读,不因单行损坏失败)
120
- }
121
- }
122
- return traces;
140
+ return readProjectTracesReport(projectRoot).traces;
123
141
  }
124
142
 
125
143
  /**
@@ -234,7 +252,7 @@ export function buildConstraintsUsageReport(
234
252
  const activePromptIds = effective.filter(c => c.kind === 'prompt').map(c => c.id);
235
253
 
236
254
  const tracePath = path.join(projectRoot, DEFAULT_TRACE_FILE);
237
- const traces = readProjectTraces(projectRoot);
255
+ const { traces, skippedLines } = readProjectTracesReport(projectRoot);
238
256
  const usage = collectUsageByConstraint(traces);
239
257
 
240
258
  const stats = checkConstraints.map(c => toStats(c.id, c.level, usage.get(c.id)));
@@ -247,5 +265,6 @@ export function buildConstraintsUsageReport(
247
265
  activePromptIds,
248
266
  lint,
249
267
  traceFileExists: fs.existsSync(tracePath),
268
+ skippedLines,
250
269
  };
251
270
  }
package/src/core/index.ts CHANGED
@@ -84,13 +84,15 @@ export type {
84
84
  SpecType,
85
85
  } from '../types/spec';
86
86
 
87
- // 项目配置加载器
87
+ // 项目配置加载器(governance 段读取一律经访问器,禁止消费方手写钻取)
88
88
  export {
89
89
  ProjectConfigLoader,
90
90
  loadRawProjectConfig,
91
+ getGovernanceConfig,
92
+ resolveContextFiles,
91
93
  getCapabilitiesMode,
92
94
  } from './project-config-loader';
93
- export type { CapabilitiesMode } from './project-config-loader';
95
+ export type { CapabilitiesMode, ContextFilesResolution } from './project-config-loader';
94
96
 
95
97
  // 生效约束集(ADR-0001:唯一生效集来源)
96
98
  export {
@@ -14,6 +14,7 @@ import type {
14
14
  CustomConstraintDefinition,
15
15
  MergedConstraintsConfig,
16
16
  CapabilitiesConfig,
17
+ GovernanceConfig,
17
18
  } from '../types/project-config';
18
19
  import { IRON_LAWS, GUIDELINES, PROMPTS } from './constraints/definitions';
19
20
  import { PRESETS_BY_NAME, STANDARD_PRESET } from '../presets';
@@ -78,20 +79,59 @@ export function loadRawProjectConfig(projectPath: string): Record<string, unknow
78
79
  export type CapabilitiesMode = NonNullable<CapabilitiesConfig['mode']>;
79
80
 
80
81
  /**
81
- * 读取 governance.capabilities.mode(缺省 'file',向后兼容)
82
+ * 读取 governance 段(全仓唯一手写钻取点,工单 84)
82
83
  *
83
- * 配置缺失/解析失败/取值非法时一律回落 'file'。
84
+ * 基于 loadRawProjectConfig 的进程级 memoize,不引入第二次 yaml 解析。
85
+ * 配置缺失 / 解析失败 / 形状不符时返回 undefined,由调用方按未配置处理。
84
86
  */
85
- export function getCapabilitiesMode(projectPath: string): CapabilitiesMode {
87
+ export function getGovernanceConfig(projectPath: string): GovernanceConfig | undefined {
86
88
  try {
87
89
  const raw = loadRawProjectConfig(projectPath);
88
- const governance = raw?.governance as Record<string, unknown> | undefined;
89
- const capabilities = governance?.capabilities as Record<string, unknown> | undefined;
90
- const mode = capabilities?.mode;
91
- if (mode === 'file' || mode === 'module' || mode === 'listing') return mode;
90
+ const governance = raw?.governance;
91
+ if (governance === null || typeof governance !== 'object') return undefined;
92
+ return governance as GovernanceConfig;
92
93
  } catch {
93
- // 配置缺失或解析失败,按默认 file 处理
94
+ return undefined;
94
95
  }
96
+ }
97
+
98
+ /**
99
+ * governance.context_files 三态分辨率(工单 84 triage 裁决口径)
100
+ *
101
+ * - unconfigured:段缺失 / enabled 为假 / 解析失败——约定未采用
102
+ * - enabled-empty:enabled 但 required_dirs 缺失、非数组、含非字符串项或空——
103
+ * 约定已立但无可用目标
104
+ * - enabled:enabled 且 required_dirs 为非空字符串数组——约定有效
105
+ */
106
+ export type ContextFilesResolution =
107
+ | { state: 'unconfigured' }
108
+ | { state: 'enabled-empty' }
109
+ | { state: 'enabled'; dirs: string[] };
110
+
111
+ /**
112
+ * 分辨 governance.context_files 三态(语义见 ContextFilesResolution)
113
+ *
114
+ * 消费方约定:约束 checker 对前两态一律 skip(与 ADR-0001 存在性探测同构);
115
+ * init / 扫描类工具流的自动探测回落保留在调用方,不进本访问器。
116
+ * 元素类型在此收口:脏配置(如 required_dirs: [1])不得流入调用方 path.join。
117
+ */
118
+ export function resolveContextFiles(projectPath: string): ContextFilesResolution {
119
+ const contextFiles = getGovernanceConfig(projectPath)?.context_files;
120
+ if (!contextFiles?.enabled) return { state: 'unconfigured' };
121
+ const dirs = contextFiles.required_dirs;
122
+ if (!Array.isArray(dirs) || dirs.length === 0) return { state: 'enabled-empty' };
123
+ if (!dirs.every(dir => typeof dir === 'string')) return { state: 'enabled-empty' };
124
+ return { state: 'enabled', dirs };
125
+ }
126
+
127
+ /**
128
+ * 读取 governance.capabilities.mode(缺省 'file',向后兼容)
129
+ *
130
+ * 配置缺失/解析失败/取值非法时一律回落 'file'。
131
+ */
132
+ export function getCapabilitiesMode(projectPath: string): CapabilitiesMode {
133
+ const mode = getGovernanceConfig(projectPath)?.capabilities?.mode;
134
+ if (mode === 'file' || mode === 'module' || mode === 'listing') return mode;
95
135
  return 'file';
96
136
  }
97
137
 
@@ -228,7 +268,7 @@ export class ProjectConfigLoader {
228
268
 
229
269
  // 2. 添加自定义约束(config.yml 禁用的 id 不追加:step 1 已将其
230
270
  // 收集进 disabled,custom 在 step 1 时尚未入桶,须在此兜底跳过;
231
- // 条目带 retired 元数据的同样不追加——#82 D6 退役落点在条目自身)
271
+ // 条目带 retired 元数据的同样不追加——studio#82 D6 退役落点在条目自身)
232
272
  for (const [id, customDef] of Object.entries(this.customConstraints)) {
233
273
  if (result.disabled.includes(id) || customDef.retired) {
234
274
  continue;
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * Tests for passes-gate.ts
3
3
  *
4
- * Priority: test pure logic methods (check, extractCoverage, extractFailures, extension management)
4
+ * Priority: test pure logic methods (check)
5
5
  * Skip methods that do real file I/O / exec (setPasses, runTests, runTest, detectTestCommand, etc.)
6
+ * 测试产物解析判定不在此面:见 test-output.test.ts(ADR-0012)
6
7
  */
7
8
 
8
9
  import { PassesGate, createPassesGate } from '../passes-gate';
@@ -67,65 +68,10 @@ describe('PassesGate', () => {
67
68
  });
68
69
  });
69
70
 
70
- describe('extension management', () => {
71
- it('registerExtension adds an extension', () => {
72
- const gate = createPassesGate();
73
- const ext = { name: 'e2e', run: async () => ({ passed: true, command: 'e2e' }) };
74
- gate.registerExtension('e2e', ext);
75
- expect(gate.getExtensionNames()).toContain('e2e');
76
- });
77
-
78
- it('unregisterExtension removes an extension', () => {
79
- const gate = createPassesGate();
80
- const ext = { name: 'e2e', run: async () => ({ passed: true, command: 'e2e' }) };
81
- gate.registerExtension('e2e', ext);
82
- const removed = gate.unregisterExtension('e2e');
83
- expect(removed).toBe(true);
84
- expect(gate.getExtensionNames()).not.toContain('e2e');
85
- });
86
-
87
- it('unregisterExtension returns false for non-existent extension', () => {
88
- const gate = createPassesGate();
89
- const removed = gate.unregisterExtension('nonexistent');
90
- expect(removed).toBe(false);
91
- });
92
-
93
- it('getExtensionNames returns empty array when no extensions', () => {
94
- const gate = createPassesGate();
95
- expect(gate.getExtensionNames()).toEqual([]);
96
- });
97
-
98
- it('getExtensionNames returns multiple extension names', () => {
99
- const gate = createPassesGate();
100
- gate.registerExtension('a', { name: 'a', run: async () => ({ passed: true, command: 'a' }) });
101
- gate.registerExtension('b', { name: 'b', run: async () => ({ passed: true, command: 'b' }) });
102
- const names = gate.getExtensionNames();
103
- expect(names).toContain('a');
104
- expect(names).toContain('b');
105
- expect(names).toHaveLength(2);
106
- });
107
- });
108
-
109
71
  describe('getTestResult', () => {
110
72
  it('returns undefined for unknown task', () => {
111
73
  const gate = createPassesGate();
112
74
  expect(gate.getTestResult('unknown')).toBeUndefined();
113
75
  });
114
76
  });
115
-
116
- describe('extractCoverage (via extractCoverage private method behavior check)', () => {
117
- // extractCoverage is private but we can infer behavior through public API
118
- // runTest uses it internally — but that method is not easily testable without mocking exec
119
- it('PassesGate instance is properly constructed', () => {
120
- const gate = createPassesGate({ testCommand: 'npm test' });
121
- expect(gate).toBeInstanceOf(PassesGate);
122
- });
123
- });
124
-
125
- describe('extractFailures (via extractFailures private method behavior check)', () => {
126
- it('PassesGate handles config properly', () => {
127
- const gate = createPassesGate({ allowPartialPass: true, maxRetries: 0, retryDelay: 0 });
128
- expect(gate).toBeInstanceOf(PassesGate);
129
- });
130
- });
131
77
  });
@@ -0,0 +1,372 @@
1
+ /**
2
+ * test-output 表驱动旁测(架构评审候选1 / #80 → ADR-0012;判定口径 #93 → ADR-0014;
3
+ * 覆盖率取数路删除 #94)
4
+ *
5
+ * runner 输出解读口的唯一测试面:真实 stdout 样本进、判定值出。
6
+ * 迁移前 extractCoverage / extractFailures / parseTestOutput 是 PassesGate 与
7
+ * SpecAcceptanceGate 的 private 方法,分支覆盖率 0%——passes-gate.test.ts 里只剩
8
+ * toBeInstanceOf 占位断言,acceptance.test.ts 要写 6 份近重复 exec mock 才碰得到分支。
9
+ *
10
+ * extractFailures 的期望值钉的是**迁移前的既有行为**(ADR-0012 硬门槛:行为零变更),
11
+ * 标 ⚠ 的行是已知的粗糙解析,原样钉住不代表认可。
12
+ *
13
+ * judgeTestRun 是 #93 裁决后的**判定唯一入口**(退出码为主 + 文本交叉否决),取代
14
+ * 原 parseTestOutput(纯文本判定,可被测试名里的 FAIL 反转);两门禁消费同一函数的
15
+ * 一致性用例在 gates/__tests__/test-verdict-consistency.test.ts。
16
+ *
17
+ * extractCoverage 曾在此有 8 条表驱动用例,#94 裁决 B(harness 核心判定不管覆盖率)
18
+ * 连同函数一起删除,只剩下面那条导出面守卫钉住「不再导出」。
19
+ */
20
+
21
+ import { describe, it, expect } from '@jest/globals';
22
+ import { extractFailures, judgeTestRun } from '../test-output';
23
+
24
+ // ========================================
25
+ // 真实输出样本(各 runner 家族的原始 stdout)
26
+ // ========================================
27
+
28
+ /** jest --coverage:文本表 + 汇总行 */
29
+ const JEST_COV = `PASS src/app.test.ts
30
+ ----------------|---------|----------|---------|---------|-------------------
31
+ File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
32
+ ----------------|---------|----------|---------|---------|-------------------
33
+ All files | 80.50 | 70.21 | 83.33 | 79.59 |
34
+ app.ts | 80.50 | 70.21 | 83.33 | 79.59 | 12-13
35
+ ----------------|---------|----------|---------|---------|-------------------
36
+ Test Suites: 1 passed, 1 total
37
+ Tests: 5 passed, 5 total
38
+ `;
39
+
40
+ const MOCHA_PLAIN = ` 2 passing (11ms)
41
+ 1 failing
42
+ `;
43
+
44
+ /** jest verbose 失败清单 */
45
+ const JEST_FAILURES = `FAIL src/app.test.ts
46
+ App
47
+ ✕ renders title (23 ms)
48
+ ✓ renders subtitle (5 ms)
49
+ ✕ handles click (12 ms)
50
+
51
+ Test Suites: 1 failed, 1 total
52
+ Tests: 2 failed, 1 passed, 3 total
53
+ `;
54
+
55
+ /** jest 失败详情带堆栈行 */
56
+ const JEST_FAILURES_WITH_STACK = `FAIL src/app.test.ts
57
+ App
58
+ ✕ renders title (23 ms)
59
+
60
+ ● App › renders title
61
+
62
+ expect(received).toBe(expected)
63
+
64
+ at Object.<anonymous> (src/app.test.ts:12:15)
65
+
66
+ Test Suites: 1 failed, 1 total
67
+ `;
68
+
69
+ /**
70
+ * PR #117 实发样本(2026-09-08):全绿 jest 输出混 console 噪音——init/sync-docs 测试
71
+ * 直接打印的 ✅ 日志行(行尾 (v1.0.0))与失败路径测试的 stack trace(行尾 :213:23))。
72
+ * 行尾「数字+)」+ 下一行含 ":" 是旧 mocha 正则(\s+ 跨行)的诱饵:它在同形状的真实输出
73
+ * 上捕出 24 条假失败,governance 门禁因此对 exit 0 的绿色 npm test 误判失败。
74
+ */
75
+ const JEST_GREEN_WITH_CONSOLE_NOISE = `PASS src/cli/commands/__tests__/init-injection.test.ts
76
+ ✅ 已创建 AGENTS.md 并写入治理契约 PRESERVE:governance 段 (v1.0.0)
77
+ ✅ 已创建 AGENTS.md 并写入治理契约 PRESERVE:governance 段 (v1.0.0)
78
+ ✅ 已更新 CLAUDE.md 治理约束 (v1.0.0)
79
+ PASS src/__tests__/skip-semantics.test.ts
80
+ at Object.evaluate (src/core/constraints/checkers/docs-freshness.ts:100:15)
81
+ at ConstraintChecker.checkPrecondition (src/core/constraints/checker.ts:213:23)
82
+ at Object.<anonymous> (src/__tests__/skip-semantics.test.ts:152:36)
83
+ PASS src/failure/__tests__/recorder.test.ts
84
+
85
+ Test Suites: 156 passed, 156 total
86
+ Tests: 7 skipped, 2182 passed, 2189 total
87
+ `;
88
+
89
+ /** mocha 单行形状:编号 + 套件 + 标题同行,末尾带冒号(正则认的形状) */
90
+ const MOCHA_ONE_LINE = ` 1) Account "should open":
91
+ AssertionError: expected false to be true
92
+
93
+ 2) Account "should close":
94
+ Error: timeout of 2000ms exceeded
95
+ `;
96
+
97
+ /** mocha 10 spec reporter 实际形状:编号行与标题行分两行 */
98
+ const MOCHA_TWO_LINE = ` 1) Account
99
+ should open:
100
+ AssertionError: expected false to be true
101
+
102
+ 2) Account
103
+ should close:
104
+ Error: timeout of 2000ms exceeded
105
+ `;
106
+
107
+ const MOCHA_TWO_LINE_WITH_STACK = ` 1) Account
108
+ should open:
109
+ AssertionError: expected false to be true
110
+ at Context.<anonymous> (test/account.test.js:14:16)
111
+ at processImmediate (node:internal/timers:476:21)
112
+
113
+ 2) Account
114
+ should close:
115
+ Error: timeout of 2000ms exceeded
116
+ `;
117
+
118
+ const PYTEST_FAILURES = `FAILED tests/test_app.py::TestLogin::test_empty_password - AssertionError: 400 != 200
119
+ FAILED tests/test_app.py::test_logout - assert False
120
+ 2 failed, 5 passed in 0.88s
121
+ `;
122
+
123
+ const GO_FAILURES = `=== RUN TestLogin
124
+ --- FAIL: TestLogin (0.00s)
125
+ app_test.go:24: expected 200, got 401
126
+ === RUN TestLogout
127
+ --- FAIL: TestLogout (0.01s)
128
+ FAIL
129
+ exit status 1
130
+ FAIL example.com/app 0.014s
131
+ `;
132
+
133
+ const PW_PASS = `Running 3 tests using 1 worker
134
+
135
+ ✓ 1 example.spec.ts:5:5 › should have title (1.2s)
136
+ ✓ 2 example.spec.ts:8:5 › should navigate (0.6s)
137
+ ✓ 3 example.spec.ts:12:5 › should submit (0.3s)
138
+
139
+ 3 passed (2.1s)
140
+ `;
141
+
142
+ const PW_FAIL = `Running 3 tests using 1 worker
143
+
144
+ ✓ 1 example.spec.ts:5:5 › should have title (1.2s)
145
+ ✘ 2 example.spec.ts:10:5 › should fail (0.9s)
146
+ ✓ 3 example.spec.ts:12:5 › should submit (0.3s)
147
+
148
+
149
+ 1) example.spec.ts:10:5 › should fail ─────────────────────────────
150
+
151
+ Error: expect(received).toBe(expected)
152
+
153
+ 1 failed
154
+ example.spec.ts:10:5 › should fail
155
+ 2 passed (3.1s)
156
+ `;
157
+
158
+ const JEST_SUITES_PASS = `Test Suites: 5 passed, 5 total
159
+ Tests: 42 passed, 42 total
160
+ `;
161
+
162
+ const JEST_SUITES_FAIL = `Test Suites: 2 failed, 3 passed, 5 total
163
+ `;
164
+
165
+ /** 零套件通过时 jest 的汇总形状(只有 failed/total,无 "passed" 字样 → 走 Jest 分支) */
166
+ const JEST_ALL_FAILED = `Test Suites: 2 failed, 2 total
167
+ Tests: 3 failed, 3 total
168
+ `;
169
+
170
+ /** jest 汇总行零失败,但输出里没有 "passed" 字样(截断/过滤后的形状) */
171
+ const JEST_SUITES_NO_PASSED_WORD = `Test Suites: 0 failed, 2 total
172
+ `;
173
+
174
+ const GENERIC_PASS = `PASS src/a.test.js
175
+ PASS src/b.test.js
176
+ `;
177
+
178
+ const GENERIC_MIXED = `PASS src/a.test.js
179
+ FAIL src/b.test.js
180
+ `;
181
+
182
+ /** 全绿输出,但通过的测试标题里带大写 FAIL 字样 */
183
+ const GENERIC_FAIL_IN_TEST_NAME = `PASS src/a.test.js
184
+ ✓ does not FAIL here (3 ms)
185
+ `;
186
+
187
+ // ========================================
188
+ // 模块导出面(harness#94 裁决 B:extractCoverage 已删除)
189
+ // ========================================
190
+
191
+ describe('test-output 导出面', () => {
192
+ it('运行时只有 extractFailures 与 judgeTestRun,不含 extractCoverage', async () => {
193
+ const mod = await import('../test-output');
194
+ expect(Object.keys(mod).sort()).toEqual(['extractFailures', 'judgeTestRun']);
195
+ });
196
+ });
197
+
198
+ // ========================================
199
+ // extractFailures
200
+ // ========================================
201
+
202
+ type FailuresCase = { name: string; output: string; expected: string[] };
203
+
204
+ const FAILURES_CASES: FailuresCase[] = [
205
+ { name: 'jest ✕ 行 → 两个用例名', output: JEST_FAILURES, expected: ['renders title', 'handles click'] },
206
+ {
207
+ name: 'jest 带堆栈行 → 只有 ✕ 用例名(旧跨行 mocha 误捕 "Test Suites",PR #117 已修)',
208
+ output: JEST_FAILURES_WITH_STACK,
209
+ expected: ['renders title'],
210
+ },
211
+ {
212
+ name: 'mocha 单行形状 → 套件 + 标题',
213
+ output: MOCHA_ONE_LINE,
214
+ expected: ['Account "should open"', 'Account "should close"'],
215
+ },
216
+ { name: '⚠ mocha 10 两行形状 → 识别不到任何失败', output: MOCHA_TWO_LINE, expected: [] },
217
+ {
218
+ name: 'mocha 两行 + 堆栈 → [](旧跨行误捕堆栈帧 "at processImmediate (node",PR #117 已修)',
219
+ output: MOCHA_TWO_LINE_WITH_STACK,
220
+ expected: [],
221
+ },
222
+ {
223
+ name: '全绿 jest 输出混 console 噪音(行尾数字+")" 跨行诱饵)→ [](PR #117 实发误否决)',
224
+ output: JEST_GREEN_WITH_CONSOLE_NOISE,
225
+ expected: [],
226
+ },
227
+ {
228
+ name: '⚠ pytest 节点 id 在首个 :: 前截断 → 同文件多条失败重复且丢测试名',
229
+ output: PYTEST_FAILURES,
230
+ expected: ['tests/test_app.py', 'tests/test_app.py'],
231
+ },
232
+ { name: 'go test --- FAIL: → 函数名', output: GO_FAILURES, expected: ['TestLogin', 'TestLogout'] },
233
+ { name: '无匹配:全绿 jest 输出 → []', output: JEST_COV, expected: [] },
234
+ { name: '无匹配:空字符串 → []', output: '', expected: [] },
235
+ ];
236
+
237
+ describe('extractFailures', () => {
238
+ for (const c of FAILURES_CASES) {
239
+ it(c.name, () => {
240
+ expect(extractFailures(c.output)).toEqual(c.expected);
241
+ });
242
+ }
243
+ });
244
+
245
+ // ========================================
246
+ // judgeTestRun — 判定唯一入口(ADR-0014 / #93)
247
+ // ========================================
248
+
249
+ type JudgeCase = {
250
+ name: string;
251
+ exitCode: number;
252
+ output: string;
253
+ allowPartialPass?: boolean;
254
+ expected: boolean;
255
+ };
256
+
257
+ const JUDGE_CASES: JudgeCase[] = [
258
+ // ── 退出码为主:文本不能把非零退出救成 pass ──
259
+ { name: 'exit 1 + 全绿 jest 输出 → false(文本不赦免非零退出)', exitCode: 1, output: JEST_COV, expected: false },
260
+ { name: 'exit 1 + 空输出 → false', exitCode: 1, output: '', expected: false },
261
+ {
262
+ name: 'exit 2 + allowPartialPass → false(部分通过不碰退出码这一维)',
263
+ exitCode: 2,
264
+ output: JEST_COV,
265
+ allowPartialPass: true,
266
+ expected: false,
267
+ },
268
+ // ── 后果1:exit 0 但输出印着失败 → 文本交叉否决 ──
269
+ { name: 'exit 0 + jest ✕ 用例清单 → false', exitCode: 0, output: JEST_FAILURES, expected: false },
270
+ { name: 'exit 0 + jest 带堆栈失败清单 → false', exitCode: 0, output: JEST_FAILURES_WITH_STACK, expected: false },
271
+ {
272
+ name: 'exit 0 + 只有 jest 汇总行(无 ✕ 行,非 verbose)→ false(统一用结构化汇总行)',
273
+ exitCode: 0,
274
+ output: JEST_ALL_FAILED,
275
+ expected: false,
276
+ },
277
+ {
278
+ name: 'exit 0 + jest 汇总行有 failed 也有 passed → false',
279
+ exitCode: 0,
280
+ output: JEST_SUITES_FAIL,
281
+ expected: false,
282
+ },
283
+ { name: 'exit 0 + 套件级 FAIL 行 → false', exitCode: 0, output: GENERIC_MIXED, expected: false },
284
+ { name: 'exit 0 + mocha 汇总行 1 failing → false', exitCode: 0, output: MOCHA_PLAIN, expected: false },
285
+ { name: 'exit 0 + pytest FAILED 行 → false', exitCode: 0, output: PYTEST_FAILURES, expected: false },
286
+ { name: 'exit 0 + go --- FAIL: 行 → false', exitCode: 0, output: GO_FAILURES, expected: false },
287
+ { name: 'exit 0 + playwright 失败汇总 → false', exitCode: 0, output: PW_FAIL, expected: false },
288
+ // ── 后果2:裸 includes(FAIL) 兜底弃用后不再误伤 ──
289
+ {
290
+ name: 'exit 0 + 全绿但通过的用例名里带大写 FAIL → true(旧兜底子串反转已修)',
291
+ exitCode: 0,
292
+ output: GENERIC_FAIL_IN_TEST_NAME,
293
+ expected: true,
294
+ },
295
+ {
296
+ name: 'exit 0 + 路径含大写 FAIL 目录名 → true(子串兜底已弃用)',
297
+ exitCode: 0,
298
+ output: 'PASS src/fixtures/FAIL/app.test.js\nTests: 3 passed, 3 total\n',
299
+ expected: true,
300
+ },
301
+ // ── 全绿样本 ──
302
+ { name: 'exit 0 + jest 全绿带覆盖率表 → true', exitCode: 0, output: JEST_COV, expected: true },
303
+ { name: 'exit 0 + jest 全绿汇总行 → true', exitCode: 0, output: JEST_SUITES_PASS, expected: true },
304
+ {
305
+ name: 'exit 0 + jest 零失败但无 "passed" 字样 → true(旧判定要求该字样,误伤)',
306
+ exitCode: 0,
307
+ output: JEST_SUITES_NO_PASSED_WORD,
308
+ expected: true,
309
+ },
310
+ { name: 'exit 0 + playwright 全过 → true', exitCode: 0, output: PW_PASS, expected: true },
311
+ { name: 'exit 0 + 通用 PASS 行 → true', exitCode: 0, output: GENERIC_PASS, expected: true },
312
+ {
313
+ name: 'exit 0 + 全绿输出混 console 噪音 → true(PR #117 实发:extractFailures 跨行误捕曾否决绿色输出)',
314
+ exitCode: 0,
315
+ output: JEST_GREEN_WITH_CONSOLE_NOISE,
316
+ expected: true,
317
+ },
318
+ // ── allowPartialPass 的新位置:只作用于文本否决这一维 ──
319
+ {
320
+ name: 'exit 0 + jest ✕ 清单 + allowPartialPass → true(部分通过 = 放弃文本否决)',
321
+ exitCode: 0,
322
+ output: JEST_FAILURES,
323
+ allowPartialPass: true,
324
+ expected: true,
325
+ },
326
+ // ── 退出码权威的边界:文本否决只管「看出失败」,不管「没跑出测试」 ──
327
+ {
328
+ name: '⚠ exit 0 + 空输出 → true(零测试识别不属本判定,另票)',
329
+ exitCode: 0,
330
+ output: '',
331
+ expected: true,
332
+ },
333
+ {
334
+ name: '⚠ exit 0 + 零测试汇总 "0 passed" → true(同上)',
335
+ exitCode: 0,
336
+ output: ' 0 passed (1.0s)\n',
337
+ expected: true,
338
+ },
339
+ {
340
+ name: '⚠ exit 0 + 畸形 "X passed X failed"(计数位非数字)→ true(同上:无结构化失败信号)',
341
+ exitCode: 0,
342
+ output: ' X passed X failed\n',
343
+ expected: true,
344
+ },
345
+ { name: 'exit 0 + 仅覆盖率表格分隔线 → true(无失败信号)', exitCode: 0, output: '----------|---------|\n', expected: true },
346
+ ];
347
+
348
+ describe('judgeTestRun', () => {
349
+ for (const c of JUDGE_CASES) {
350
+ it(c.name, () => {
351
+ expect(judgeTestRun({ exitCode: c.exitCode, output: c.output, allowPartialPass: c.allowPartialPass })).toEqual(
352
+ expect.objectContaining({ passed: c.expected }),
353
+ );
354
+ });
355
+ }
356
+
357
+ it('allowPartialPass 缺省 = false(否决默认生效)', () => {
358
+ expect(judgeTestRun({ exitCode: 0, output: JEST_FAILURES }).passed).toBe(false);
359
+ });
360
+
361
+ it('否决时 failures 带出用例名(判负有据)', () => {
362
+ expect(judgeTestRun({ exitCode: 0, output: JEST_FAILURES }).failures).toEqual(['renders title', 'handles click']);
363
+ });
364
+
365
+ it('全绿时 failures 为空数组', () => {
366
+ expect(judgeTestRun({ exitCode: 0, output: GENERIC_FAIL_IN_TEST_NAME }).failures).toEqual([]);
367
+ });
368
+
369
+ it('非零退出时仍带出文本里的失败名(供上层拼错误信息)', () => {
370
+ expect(judgeTestRun({ exitCode: 1, output: GO_FAILURES }).failures).toEqual(['TestLogin', 'TestLogout']);
371
+ });
372
+ });