@dommaker/harness 1.7.0 → 1.8.1

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 (563) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/bin/harness.js +17 -1
  3. package/dist/agents/index.d.ts +6 -2
  4. package/dist/agents/index.d.ts.map +1 -1
  5. package/dist/agents/index.js +6 -16
  6. package/dist/agents/index.js.map +1 -1
  7. package/dist/cli/commands/__tests__/gate-decision.d.ts +18 -0
  8. package/dist/cli/commands/__tests__/gate-decision.d.ts.map +1 -0
  9. package/dist/cli/commands/__tests__/gate-decision.js +26 -0
  10. package/dist/cli/commands/__tests__/gate-decision.js.map +1 -0
  11. package/dist/cli/commands/acceptance.d.ts.map +1 -1
  12. package/dist/cli/commands/acceptance.js +17 -28
  13. package/dist/cli/commands/acceptance.js.map +1 -1
  14. package/dist/cli/commands/check.d.ts +19 -3
  15. package/dist/cli/commands/check.d.ts.map +1 -1
  16. package/dist/cli/commands/check.js +36 -22
  17. package/dist/cli/commands/check.js.map +1 -1
  18. package/dist/cli/commands/command.d.ts +0 -1
  19. package/dist/cli/commands/command.d.ts.map +1 -1
  20. package/dist/cli/commands/command.js +8 -6
  21. package/dist/cli/commands/command.js.map +1 -1
  22. package/dist/cli/commands/constraints-retire.d.ts.map +1 -1
  23. package/dist/cli/commands/constraints-retire.js +36 -57
  24. package/dist/cli/commands/constraints-retire.js.map +1 -1
  25. package/dist/cli/commands/contract.d.ts.map +1 -1
  26. package/dist/cli/commands/contract.js +36 -42
  27. package/dist/cli/commands/contract.js.map +1 -1
  28. package/dist/cli/commands/definitions.d.ts +2 -0
  29. package/dist/cli/commands/definitions.d.ts.map +1 -1
  30. package/dist/cli/commands/definitions.js +11 -6
  31. package/dist/cli/commands/definitions.js.map +1 -1
  32. package/dist/cli/commands/failure.d.ts.map +1 -1
  33. package/dist/cli/commands/failure.js +16 -2
  34. package/dist/cli/commands/failure.js.map +1 -1
  35. package/dist/cli/commands/init.d.ts +14 -8
  36. package/dist/cli/commands/init.d.ts.map +1 -1
  37. package/dist/cli/commands/init.js +172 -364
  38. package/dist/cli/commands/init.js.map +1 -1
  39. package/dist/cli/commands/knowledge-view.d.ts +90 -0
  40. package/dist/cli/commands/knowledge-view.d.ts.map +1 -0
  41. package/dist/cli/commands/knowledge-view.js +198 -0
  42. package/dist/cli/commands/knowledge-view.js.map +1 -0
  43. package/dist/cli/commands/knowledge.d.ts +137 -52
  44. package/dist/cli/commands/knowledge.d.ts.map +1 -1
  45. package/dist/cli/commands/knowledge.js +534 -400
  46. package/dist/cli/commands/knowledge.js.map +1 -1
  47. package/dist/cli/commands/passes-gate.d.ts +4 -1
  48. package/dist/cli/commands/passes-gate.d.ts.map +1 -1
  49. package/dist/cli/commands/passes-gate.js +11 -2
  50. package/dist/cli/commands/passes-gate.js.map +1 -1
  51. package/dist/cli/commands/performance.d.ts.map +1 -1
  52. package/dist/cli/commands/performance.js +19 -31
  53. package/dist/cli/commands/performance.js.map +1 -1
  54. package/dist/cli/commands/report.d.ts.map +1 -1
  55. package/dist/cli/commands/report.js +2 -1
  56. package/dist/cli/commands/report.js.map +1 -1
  57. package/dist/cli/commands/review.d.ts.map +1 -1
  58. package/dist/cli/commands/review.js +13 -25
  59. package/dist/cli/commands/review.js.map +1 -1
  60. package/dist/cli/commands/scaffold-templates.d.ts +73 -0
  61. package/dist/cli/commands/scaffold-templates.d.ts.map +1 -0
  62. package/dist/cli/commands/scaffold-templates.js +424 -0
  63. package/dist/cli/commands/scaffold-templates.js.map +1 -0
  64. package/dist/cli/commands/scaffold.d.ts +105 -0
  65. package/dist/cli/commands/scaffold.d.ts.map +1 -0
  66. package/dist/cli/commands/scaffold.js +263 -0
  67. package/dist/cli/commands/scaffold.js.map +1 -0
  68. package/dist/cli/commands/security.d.ts.map +1 -1
  69. package/dist/cli/commands/security.js +22 -24
  70. package/dist/cli/commands/security.js.map +1 -1
  71. package/dist/cli/commands/spec-baseline-check.d.ts +43 -0
  72. package/dist/cli/commands/spec-baseline-check.d.ts.map +1 -1
  73. package/dist/cli/commands/spec-baseline-check.js +109 -34
  74. package/dist/cli/commands/spec-baseline-check.js.map +1 -1
  75. package/dist/cli/commands/status.d.ts +8 -0
  76. package/dist/cli/commands/status.d.ts.map +1 -1
  77. package/dist/cli/commands/status.js +5 -7
  78. package/dist/cli/commands/status.js.map +1 -1
  79. package/dist/cli/commands/sync-docs/context-syncer.d.ts +21 -2
  80. package/dist/cli/commands/sync-docs/context-syncer.d.ts.map +1 -1
  81. package/dist/cli/commands/sync-docs/context-syncer.js +112 -28
  82. package/dist/cli/commands/sync-docs/context-syncer.js.map +1 -1
  83. package/dist/cli/commands/sync-docs/index.d.ts +1 -1
  84. package/dist/cli/commands/sync-docs/index.d.ts.map +1 -1
  85. package/dist/cli/commands/sync-docs/index.js +86 -27
  86. package/dist/cli/commands/sync-docs/index.js.map +1 -1
  87. package/dist/cli/commands/sync-docs/project-reader.d.ts +24 -1
  88. package/dist/cli/commands/sync-docs/project-reader.d.ts.map +1 -1
  89. package/dist/cli/commands/sync-docs/project-reader.js +33 -7
  90. package/dist/cli/commands/sync-docs/project-reader.js.map +1 -1
  91. package/dist/cli/commands/validate.d.ts +0 -16
  92. package/dist/cli/commands/validate.d.ts.map +1 -1
  93. package/dist/cli/commands/validate.js +2 -97
  94. package/dist/cli/commands/validate.js.map +1 -1
  95. package/dist/cli/gate-command.d.ts +37 -0
  96. package/dist/cli/gate-command.d.ts.map +1 -0
  97. package/dist/cli/gate-command.js +64 -0
  98. package/dist/cli/gate-command.js.map +1 -0
  99. package/dist/cli/state-io.d.ts +34 -0
  100. package/dist/cli/state-io.d.ts.map +1 -0
  101. package/dist/cli/state-io.js +71 -0
  102. package/dist/cli/state-io.js.map +1 -0
  103. package/dist/completion-checkers/index.d.ts +1 -1
  104. package/dist/completion-checkers/index.d.ts.map +1 -1
  105. package/dist/completion-checkers/index.js +0 -15
  106. package/dist/completion-checkers/index.js.map +1 -1
  107. package/dist/context/knowledge-injector.d.ts +4 -2
  108. package/dist/context/knowledge-injector.d.ts.map +1 -1
  109. package/dist/context/knowledge-injector.js +13 -6
  110. package/dist/context/knowledge-injector.js.map +1 -1
  111. package/dist/core/constraints/agent-prompt-renderer.js +2 -2
  112. package/dist/core/constraints/agent-prompt-renderer.js.map +1 -1
  113. package/dist/core/constraints/capabilities-reconcile.d.ts +20 -0
  114. package/dist/core/constraints/capabilities-reconcile.d.ts.map +1 -1
  115. package/dist/core/constraints/capabilities-reconcile.js +26 -4
  116. package/dist/core/constraints/capabilities-reconcile.js.map +1 -1
  117. package/dist/core/constraints/check-cache.d.ts +1 -1
  118. package/dist/core/constraints/check-cache.js +1 -1
  119. package/dist/core/constraints/checker.d.ts +8 -3
  120. package/dist/core/constraints/checker.d.ts.map +1 -1
  121. package/dist/core/constraints/checker.js +30 -19
  122. package/dist/core/constraints/checker.js.map +1 -1
  123. package/dist/core/constraints/checkers/capability-sync.d.ts +3 -1
  124. package/dist/core/constraints/checkers/capability-sync.d.ts.map +1 -1
  125. package/dist/core/constraints/checkers/capability-sync.js +17 -24
  126. package/dist/core/constraints/checkers/capability-sync.js.map +1 -1
  127. package/dist/core/constraints/checkers/context-doc-sync.d.ts +1 -1
  128. package/dist/core/constraints/checkers/context-doc-sync.d.ts.map +1 -1
  129. package/dist/core/constraints/checkers/context-doc-sync.js +9 -6
  130. package/dist/core/constraints/checkers/context-doc-sync.js.map +1 -1
  131. package/dist/core/constraints/checkers/docs-freshness.d.ts.map +1 -1
  132. package/dist/core/constraints/checkers/docs-freshness.js +24 -30
  133. package/dist/core/constraints/checkers/docs-freshness.js.map +1 -1
  134. package/dist/core/constraints/checkers/governance-presence.d.ts.map +1 -1
  135. package/dist/core/constraints/checkers/governance-presence.js +10 -4
  136. package/dist/core/constraints/checkers/governance-presence.js.map +1 -1
  137. package/dist/core/constraints/checkers/types.d.ts +10 -6
  138. package/dist/core/constraints/checkers/types.d.ts.map +1 -1
  139. package/dist/core/constraints/checkers/types.js +7 -3
  140. package/dist/core/constraints/checkers/types.js.map +1 -1
  141. package/dist/core/constraints/context-builder.d.ts +11 -10
  142. package/dist/core/constraints/context-builder.d.ts.map +1 -1
  143. package/dist/core/constraints/context-builder.js +31 -27
  144. package/dist/core/constraints/context-builder.js.map +1 -1
  145. package/dist/core/constraints/context-reconcile.d.ts +75 -0
  146. package/dist/core/constraints/context-reconcile.d.ts.map +1 -0
  147. package/dist/core/constraints/context-reconcile.js +161 -0
  148. package/dist/core/constraints/context-reconcile.js.map +1 -0
  149. package/dist/core/constraints/doc-freshness/runner.d.ts +7 -0
  150. package/dist/core/constraints/doc-freshness/runner.d.ts.map +1 -1
  151. package/dist/core/constraints/doc-freshness/runner.js +8 -3
  152. package/dist/core/constraints/doc-freshness/runner.js.map +1 -1
  153. package/dist/core/constraints/git-evidence.js +1 -1
  154. package/dist/core/constraints/git-evidence.js.map +1 -1
  155. package/dist/core/constraints/injection-drift.d.ts +7 -2
  156. package/dist/core/constraints/injection-drift.d.ts.map +1 -1
  157. package/dist/core/constraints/injection-drift.js +13 -7
  158. package/dist/core/constraints/injection-drift.js.map +1 -1
  159. package/dist/core/constraints/run-env.d.ts +92 -0
  160. package/dist/core/constraints/run-env.d.ts.map +1 -0
  161. package/dist/core/constraints/run-env.js +175 -0
  162. package/dist/core/constraints/run-env.js.map +1 -0
  163. package/dist/core/constraints/triggers.d.ts +22 -0
  164. package/dist/core/constraints/triggers.d.ts.map +1 -0
  165. package/dist/core/constraints/triggers.js +31 -0
  166. package/dist/core/constraints/triggers.js.map +1 -0
  167. package/dist/core/effective-constraints.d.ts +13 -4
  168. package/dist/core/effective-constraints.d.ts.map +1 -1
  169. package/dist/core/effective-constraints.js +16 -6
  170. package/dist/core/effective-constraints.js.map +1 -1
  171. package/dist/core/effective-set.d.ts +8 -15
  172. package/dist/core/effective-set.d.ts.map +1 -1
  173. package/dist/core/effective-set.js +7 -12
  174. package/dist/core/effective-set.js.map +1 -1
  175. package/dist/core/index.d.ts +1 -0
  176. package/dist/core/index.d.ts.map +1 -1
  177. package/dist/core/index.js.map +1 -1
  178. package/dist/core/project-config-loader.d.ts +39 -17
  179. package/dist/core/project-config-loader.d.ts.map +1 -1
  180. package/dist/core/project-config-loader.js +51 -122
  181. package/dist/core/project-config-loader.js.map +1 -1
  182. package/dist/core/validators/check-handlers/http.d.ts +2 -2
  183. package/dist/core/validators/check-handlers/http.d.ts.map +1 -1
  184. package/dist/core/validators/check-handlers/http.js +12 -7
  185. package/dist/core/validators/check-handlers/http.js.map +1 -1
  186. package/dist/failure/classifier.d.ts +1 -1
  187. package/dist/failure/classifier.d.ts.map +1 -1
  188. package/dist/failure/classifier.js +8 -8
  189. package/dist/failure/classifier.js.map +1 -1
  190. package/dist/failure/index.d.ts +2 -1
  191. package/dist/failure/index.d.ts.map +1 -1
  192. package/dist/failure/index.js +9 -17
  193. package/dist/failure/index.js.map +1 -1
  194. package/dist/failure/recorder.d.ts +1 -1
  195. package/dist/failure/recorder.d.ts.map +1 -1
  196. package/dist/gates/checker-gate.d.ts +2 -1
  197. package/dist/gates/checker-gate.d.ts.map +1 -1
  198. package/dist/gates/checker-gate.js +3 -2
  199. package/dist/gates/checker-gate.js.map +1 -1
  200. package/dist/gates/command.d.ts +10 -4
  201. package/dist/gates/command.d.ts.map +1 -1
  202. package/dist/gates/command.js +36 -62
  203. package/dist/gates/command.js.map +1 -1
  204. package/dist/gates/contract.d.ts.map +1 -1
  205. package/dist/gates/contract.js +0 -4
  206. package/dist/gates/contract.js.map +1 -1
  207. package/dist/gates/definitions.d.ts +2 -1
  208. package/dist/gates/definitions.d.ts.map +1 -1
  209. package/dist/gates/definitions.js +6 -5
  210. package/dist/gates/definitions.js.map +1 -1
  211. package/dist/gates/index.d.ts +0 -4
  212. package/dist/gates/index.d.ts.map +1 -1
  213. package/dist/gates/index.js +1 -6
  214. package/dist/gates/index.js.map +1 -1
  215. package/dist/gates/performance.d.ts.map +1 -1
  216. package/dist/gates/performance.js +0 -4
  217. package/dist/gates/performance.js.map +1 -1
  218. package/dist/gates/runner.d.ts +1 -1
  219. package/dist/gates/runner.js +1 -1
  220. package/dist/gates/security.d.ts +1 -1
  221. package/dist/gates/security.d.ts.map +1 -1
  222. package/dist/gates/security.js +5 -6
  223. package/dist/gates/security.js.map +1 -1
  224. package/dist/gates/types.d.ts +14 -17
  225. package/dist/gates/types.d.ts.map +1 -1
  226. package/dist/gates/types.js.map +1 -1
  227. package/dist/hooks/bootstrap.d.ts +6 -4
  228. package/dist/hooks/bootstrap.d.ts.map +1 -1
  229. package/dist/hooks/bootstrap.js +25 -13
  230. package/dist/hooks/bootstrap.js.map +1 -1
  231. package/dist/hooks/config.d.ts +6 -2
  232. package/dist/hooks/config.d.ts.map +1 -1
  233. package/dist/hooks/config.js +5 -1
  234. package/dist/hooks/config.js.map +1 -1
  235. package/dist/hooks/index.d.ts +1 -1
  236. package/dist/hooks/index.d.ts.map +1 -1
  237. package/dist/hooks/index.js +0 -15
  238. package/dist/hooks/index.js.map +1 -1
  239. package/dist/hooks/pipeline.d.ts +19 -1
  240. package/dist/hooks/pipeline.d.ts.map +1 -1
  241. package/dist/hooks/pipeline.js +42 -4
  242. package/dist/hooks/pipeline.js.map +1 -1
  243. package/dist/hooks/registry.d.ts +11 -8
  244. package/dist/hooks/registry.d.ts.map +1 -1
  245. package/dist/hooks/registry.js +22 -7
  246. package/dist/hooks/registry.js.map +1 -1
  247. package/dist/hooks/types.d.ts +25 -7
  248. package/dist/hooks/types.d.ts.map +1 -1
  249. package/dist/index.d.ts +3 -3
  250. package/dist/index.d.ts.map +1 -1
  251. package/dist/index.js +3 -4
  252. package/dist/index.js.map +1 -1
  253. package/dist/knowledge/audit-scoring.d.ts +87 -0
  254. package/dist/knowledge/audit-scoring.d.ts.map +1 -0
  255. package/dist/knowledge/audit-scoring.js +470 -0
  256. package/dist/knowledge/audit-scoring.js.map +1 -0
  257. package/dist/knowledge/audit.d.ts +11 -59
  258. package/dist/knowledge/audit.d.ts.map +1 -1
  259. package/dist/knowledge/audit.js +47 -522
  260. package/dist/knowledge/audit.js.map +1 -1
  261. package/dist/knowledge/import.d.ts.map +1 -1
  262. package/dist/knowledge/import.js +2 -0
  263. package/dist/knowledge/import.js.map +1 -1
  264. package/dist/knowledge/index-generator.d.ts.map +1 -1
  265. package/dist/knowledge/index-generator.js +4 -5
  266. package/dist/knowledge/index-generator.js.map +1 -1
  267. package/dist/knowledge/index.d.ts +3 -2
  268. package/dist/knowledge/index.d.ts.map +1 -1
  269. package/dist/knowledge/index.js +3 -16
  270. package/dist/knowledge/index.js.map +1 -1
  271. package/dist/knowledge/ingest.js +1 -1
  272. package/dist/knowledge/ingest.js.map +1 -1
  273. package/dist/knowledge/lifecycle.d.ts.map +1 -1
  274. package/dist/knowledge/lifecycle.js +4 -2
  275. package/dist/knowledge/lifecycle.js.map +1 -1
  276. package/dist/knowledge/migration.d.ts +3 -0
  277. package/dist/knowledge/migration.d.ts.map +1 -1
  278. package/dist/knowledge/migration.js +8 -2
  279. package/dist/knowledge/migration.js.map +1 -1
  280. package/dist/knowledge/query.d.ts +6 -0
  281. package/dist/knowledge/query.d.ts.map +1 -1
  282. package/dist/knowledge/query.js +8 -2
  283. package/dist/knowledge/query.js.map +1 -1
  284. package/dist/knowledge/reference-tracker.d.ts.map +1 -1
  285. package/dist/knowledge/reference-tracker.js +4 -6
  286. package/dist/knowledge/reference-tracker.js.map +1 -1
  287. package/dist/knowledge/store.d.ts +22 -16
  288. package/dist/knowledge/store.d.ts.map +1 -1
  289. package/dist/knowledge/store.js +53 -12
  290. package/dist/knowledge/store.js.map +1 -1
  291. package/dist/knowledge/tree-walker.d.ts +19 -0
  292. package/dist/knowledge/tree-walker.d.ts.map +1 -0
  293. package/dist/knowledge/tree-walker.js +30 -0
  294. package/dist/knowledge/tree-walker.js.map +1 -0
  295. package/dist/knowledge/types.d.ts +16 -0
  296. package/dist/knowledge/types.d.ts.map +1 -1
  297. package/dist/monitoring/traces.d.ts +5 -3
  298. package/dist/monitoring/traces.d.ts.map +1 -1
  299. package/dist/monitoring/traces.js +19 -5
  300. package/dist/monitoring/traces.js.map +1 -1
  301. package/dist/test-setup/jsonl-fake-fs.d.ts +30 -0
  302. package/dist/test-setup/jsonl-fake-fs.d.ts.map +1 -0
  303. package/dist/test-setup/jsonl-fake-fs.js +49 -0
  304. package/dist/test-setup/jsonl-fake-fs.js.map +1 -0
  305. package/dist/tools/index.d.ts +4 -1
  306. package/dist/tools/index.d.ts.map +1 -1
  307. package/dist/tools/index.js +7 -15
  308. package/dist/tools/index.js.map +1 -1
  309. package/dist/types/checkpoint.d.ts +5 -0
  310. package/dist/types/checkpoint.d.ts.map +1 -1
  311. package/dist/types/project-config.d.ts +18 -0
  312. package/dist/types/project-config.d.ts.map +1 -1
  313. package/dist/types/trace.d.ts +13 -4
  314. package/dist/types/trace.d.ts.map +1 -1
  315. package/dist/types/trace.js +4 -3
  316. package/dist/types/trace.js.map +1 -1
  317. package/dist/utils/exec.d.ts +4 -27
  318. package/dist/utils/exec.d.ts.map +1 -1
  319. package/dist/utils/exec.js +4 -94
  320. package/dist/utils/exec.js.map +1 -1
  321. package/dist/utils/jsonl.d.ts +17 -7
  322. package/dist/utils/jsonl.d.ts.map +1 -1
  323. package/dist/utils/jsonl.js +144 -17
  324. package/dist/utils/jsonl.js.map +1 -1
  325. package/dist/utils/numeric-flag.d.ts +44 -0
  326. package/dist/utils/numeric-flag.d.ts.map +1 -0
  327. package/dist/utils/numeric-flag.js +62 -0
  328. package/dist/utils/numeric-flag.js.map +1 -0
  329. package/package.json +1 -1
  330. package/src/CONTEXT.md +5 -2
  331. package/src/__tests__/acceptance-gate.test.ts +7 -4
  332. package/src/__tests__/checker-extra.test.ts +3 -2
  333. package/src/__tests__/checker.test.ts +4 -3
  334. package/src/__tests__/checkpoint.test.ts +26 -9
  335. package/src/__tests__/context-files-resolution.test.ts +29 -15
  336. package/src/__tests__/contract-gate.test.ts +19 -40
  337. package/src/__tests__/error-classifier.test.ts +1 -1
  338. package/src/__tests__/exec.test.ts +45 -107
  339. package/src/__tests__/failure-recorder.test.ts +7 -5
  340. package/src/__tests__/hooks-pipeline.test.ts +34 -47
  341. package/src/__tests__/layering.test.ts +217 -25
  342. package/src/__tests__/passes-gate.test.ts +9 -4
  343. package/src/__tests__/performance-gate.test.ts +3 -15
  344. package/src/__tests__/project-config-loader-extra.test.ts +31 -57
  345. package/src/__tests__/project-config-loader.test.ts +6 -3
  346. package/src/__tests__/public-exports.test.ts +0 -1
  347. package/src/__tests__/public-type-surface.test.ts +5 -4
  348. package/src/__tests__/public-value-surface.test.ts +182 -0
  349. package/src/__tests__/review-gate.test.ts +4 -6
  350. package/src/__tests__/security-gate.test.ts +5 -20
  351. package/src/__tests__/skip-semantics.test.ts +5 -3
  352. package/src/__tests__/spec-validator.test.ts +3 -2
  353. package/src/__tests__/sub-barrels-explicit.test.ts +87 -0
  354. package/src/__tests__/test-fixture-hygiene.test.ts +53 -0
  355. package/src/__tests__/trace-analyzer-extra.test.ts +5 -3
  356. package/src/__tests__/trace-analyzer.test.ts +5 -3
  357. package/src/__tests__/trace-collector.test.ts +5 -3
  358. package/src/agents/index.ts +13 -2
  359. package/src/cli/__tests__/gate-command.test.ts +162 -0
  360. package/src/cli/__tests__/state-io.test.ts +50 -0
  361. package/src/cli/commands/CONTEXT.md +30 -5
  362. package/src/cli/commands/__tests__/acceptance.test.ts +24 -25
  363. package/src/cli/commands/__tests__/bin-exit-mapping.test.ts +15 -0
  364. package/src/cli/commands/__tests__/check-drift.test.ts +42 -1
  365. package/src/cli/commands/__tests__/check-read-count.test.ts +170 -0
  366. package/src/cli/commands/__tests__/check-skip-output.test.ts +4 -1
  367. package/src/cli/commands/__tests__/check.test.ts +63 -44
  368. package/src/cli/commands/__tests__/command-gate-dead-options.test.ts +60 -0
  369. package/src/cli/commands/__tests__/command.test.ts +33 -17
  370. package/src/cli/commands/__tests__/constraints-retire.test.ts +52 -0
  371. package/src/cli/commands/__tests__/context-syncer.test.ts +141 -0
  372. package/src/cli/commands/__tests__/contract.test.ts +20 -20
  373. package/src/cli/commands/__tests__/failure.test.ts +5 -4
  374. package/src/cli/commands/__tests__/gate-decision.ts +30 -0
  375. package/src/cli/commands/__tests__/init-dead-options.test.ts +50 -0
  376. package/src/cli/commands/__tests__/init-governance-io.test.ts +139 -0
  377. package/src/cli/commands/__tests__/init-injection.test.ts +3 -3
  378. package/src/cli/commands/__tests__/init-ondisk.test.ts +867 -0
  379. package/src/cli/commands/__tests__/init.test.ts +82 -6
  380. package/src/cli/commands/__tests__/knowledge-audit-threshold.test.ts +146 -0
  381. package/src/cli/commands/__tests__/knowledge-flywheel-consistency.test.ts +1 -1
  382. package/src/cli/commands/__tests__/knowledge-tone-mapping.test.ts +244 -0
  383. package/src/cli/commands/__tests__/knowledge-view.test.ts +839 -0
  384. package/src/cli/commands/__tests__/knowledge.test.ts +33 -15
  385. package/src/cli/commands/__tests__/numeric-flag-assembly.test.ts +368 -0
  386. package/src/cli/commands/__tests__/performance.test.ts +19 -21
  387. package/src/cli/commands/__tests__/posteval-plan.test.ts +5 -3
  388. package/src/cli/commands/__tests__/pre-push-hook.test.ts +181 -0
  389. package/src/cli/commands/__tests__/project-path-anchoring.test.ts +95 -2
  390. package/src/cli/commands/__tests__/project-path-convention.test.ts +103 -25
  391. package/src/cli/commands/__tests__/registry.test.ts +2 -0
  392. package/src/cli/commands/__tests__/report.test.ts +23 -1
  393. package/src/cli/commands/__tests__/review.test.ts +10 -17
  394. package/src/cli/commands/__tests__/scaffold.test.ts +505 -0
  395. package/src/cli/commands/__tests__/security-default-scan.test.ts +75 -0
  396. package/src/cli/commands/__tests__/security.test.ts +21 -24
  397. package/src/cli/commands/__tests__/spec-baseline-check.test.ts +3 -2
  398. package/src/cli/commands/__tests__/spec-baseline-index-cap.test.ts +131 -0
  399. package/src/cli/commands/__tests__/spec-baseline-read-count.test.ts +325 -0
  400. package/src/cli/commands/__tests__/status-extra.test.ts +25 -8
  401. package/src/cli/commands/__tests__/status.test.ts +46 -18
  402. package/src/cli/commands/__tests__/sync-docs-agents.test.ts +19 -4
  403. package/src/cli/commands/__tests__/sync-docs-context-drift.test.ts +232 -0
  404. package/src/cli/commands/__tests__/sync-docs-module-order.test.ts +111 -0
  405. package/src/cli/commands/__tests__/sync-docs-read-count.test.ts +192 -0
  406. package/src/cli/commands/__tests__/sync-docs.test.ts +3 -2
  407. package/src/cli/commands/__tests__/validate.test.ts +1 -48
  408. package/src/cli/commands/acceptance.ts +24 -29
  409. package/src/cli/commands/check.ts +60 -35
  410. package/src/cli/commands/command.ts +9 -8
  411. package/src/cli/commands/constraints-retire.ts +57 -70
  412. package/src/cli/commands/contract.ts +44 -47
  413. package/src/cli/commands/definitions.ts +12 -6
  414. package/src/cli/commands/failure.ts +16 -3
  415. package/src/cli/commands/init.ts +242 -389
  416. package/src/cli/commands/knowledge-view.ts +224 -0
  417. package/src/cli/commands/knowledge.ts +643 -448
  418. package/src/cli/commands/passes-gate.ts +12 -3
  419. package/src/cli/commands/performance.ts +31 -38
  420. package/src/cli/commands/report.ts +3 -2
  421. package/src/cli/commands/review.ts +22 -28
  422. package/src/cli/commands/scaffold-templates.ts +406 -0
  423. package/src/cli/commands/scaffold.ts +302 -0
  424. package/src/cli/commands/security.ts +27 -23
  425. package/src/cli/commands/spec-baseline-check.ts +158 -33
  426. package/src/cli/commands/status.ts +12 -7
  427. package/src/cli/commands/sync-docs/__tests__/context-export-surface.test.ts +102 -0
  428. package/src/cli/commands/sync-docs/__tests__/module-descriptions.test.ts +196 -0
  429. package/src/cli/commands/sync-docs/context-syncer.ts +137 -31
  430. package/src/cli/commands/sync-docs/index.ts +103 -28
  431. package/src/cli/commands/sync-docs/project-reader.ts +51 -7
  432. package/src/cli/commands/validate.ts +1 -104
  433. package/src/cli/gate-command.ts +87 -0
  434. package/src/cli/state-io.ts +53 -0
  435. package/src/completion-checkers/index.ts +10 -1
  436. package/src/context/CONTEXT.md +2 -1
  437. package/src/context/__tests__/knowledge-injector.test.ts +27 -0
  438. package/src/context/__tests__/session-manager.test.ts +19 -12
  439. package/src/context/knowledge-injector.ts +14 -7
  440. package/src/core/CONTEXT.md +10 -7
  441. package/src/core/__tests__/effective-set.test.ts +36 -60
  442. package/src/core/constraints/__tests__/context-reconcile.test.ts +246 -0
  443. package/src/core/constraints/__tests__/run-env.test.ts +377 -0
  444. package/src/core/constraints/__tests__/triggers.test.ts +70 -0
  445. package/src/core/constraints/agent-prompt-renderer.ts +1 -1
  446. package/src/core/constraints/capabilities-reconcile.ts +28 -4
  447. package/src/core/constraints/check-cache.ts +1 -1
  448. package/src/core/constraints/checker.ts +30 -14
  449. package/src/core/constraints/checkers/__tests__/context-doc-sync.test.ts +8 -3
  450. package/src/core/constraints/checkers/__tests__/governance-presence.test.ts +16 -7
  451. package/src/core/constraints/checkers/__tests__/no-hardcoded-credentials.test.ts +2 -1
  452. package/src/core/constraints/checkers/capability-sync.ts +27 -28
  453. package/src/core/constraints/checkers/context-doc-sync.ts +9 -7
  454. package/src/core/constraints/checkers/docs-freshness.ts +28 -33
  455. package/src/core/constraints/checkers/governance-presence.ts +10 -6
  456. package/src/core/constraints/checkers/types.ts +14 -8
  457. package/src/core/constraints/context-builder.ts +35 -26
  458. package/src/core/constraints/context-reconcile.ts +200 -0
  459. package/src/core/constraints/doc-freshness/__tests__/runner.test.ts +25 -0
  460. package/src/core/constraints/doc-freshness/runner.ts +18 -4
  461. package/src/core/constraints/git-evidence.ts +1 -1
  462. package/src/core/constraints/injection-drift.ts +19 -8
  463. package/src/core/constraints/run-env.ts +207 -0
  464. package/src/core/constraints/triggers.ts +33 -0
  465. package/src/core/effective-constraints.ts +17 -6
  466. package/src/core/effective-set.ts +8 -24
  467. package/src/core/index.ts +2 -0
  468. package/src/core/project-config-loader.ts +54 -102
  469. package/src/core/validators/__tests__/http-retry-sleep.test.ts +231 -0
  470. package/src/core/validators/check-handlers/http.ts +18 -7
  471. package/src/failure/CONTEXT.md +2 -1
  472. package/src/failure/classifier.ts +2 -2
  473. package/src/failure/index.ts +14 -2
  474. package/src/failure/recorder.ts +1 -1
  475. package/src/gates/CONTEXT.md +13 -7
  476. package/src/gates/__tests__/checker-gate.test.ts +1 -1
  477. package/src/gates/__tests__/command-single-predicate.test.ts +135 -0
  478. package/src/gates/__tests__/command.test.ts +8 -15
  479. package/src/gates/__tests__/contract.test.ts +5 -5
  480. package/src/gates/__tests__/gate-interface.test.ts +0 -17
  481. package/src/gates/__tests__/performance.test.ts +0 -13
  482. package/src/gates/__tests__/review.test.ts +0 -1
  483. package/src/gates/__tests__/runner.test.ts +1 -1
  484. package/src/gates/__tests__/security-default-scan.test.ts +97 -0
  485. package/src/gates/__tests__/security.test.ts +0 -13
  486. package/src/gates/checker-gate.ts +3 -2
  487. package/src/gates/command.ts +51 -74
  488. package/src/gates/contract.ts +0 -5
  489. package/src/gates/definitions.ts +6 -5
  490. package/src/gates/index.ts +0 -5
  491. package/src/gates/performance.ts +1 -6
  492. package/src/gates/runner.ts +1 -1
  493. package/src/gates/security.ts +9 -11
  494. package/src/gates/types.ts +20 -23
  495. package/src/hooks/CONTEXT.md +10 -9
  496. package/src/hooks/__tests__/bootstrap.test.ts +29 -6
  497. package/src/hooks/__tests__/pipeline.test.ts +133 -17
  498. package/src/hooks/__tests__/registry.test.ts +51 -3
  499. package/src/hooks/bootstrap.ts +35 -15
  500. package/src/hooks/config.ts +6 -2
  501. package/src/hooks/index.ts +10 -1
  502. package/src/hooks/pipeline.ts +51 -6
  503. package/src/hooks/registry.ts +31 -12
  504. package/src/hooks/types.ts +26 -7
  505. package/src/index.ts +1 -2
  506. package/src/knowledge/CONTEXT.md +14 -7
  507. package/src/knowledge/__tests__/audit-labels.test.ts +8 -5
  508. package/src/knowledge/__tests__/audit-scoring.test.ts +230 -0
  509. package/src/knowledge/__tests__/audit-write-count.test.ts +131 -0
  510. package/src/knowledge/__tests__/audit.test.ts +291 -208
  511. package/src/knowledge/__tests__/doctor.test.ts +3 -2
  512. package/src/knowledge/__tests__/ingest.test.ts +3 -2
  513. package/src/knowledge/__tests__/lifecycle.test.ts +57 -2
  514. package/src/knowledge/__tests__/migration.test.ts +35 -6
  515. package/src/knowledge/__tests__/query.test.ts +3 -2
  516. package/src/knowledge/__tests__/reference-tracker.test.ts +23 -2
  517. package/src/knowledge/__tests__/store.test.ts +149 -4
  518. package/src/knowledge/__tests__/tree-walker.test.ts +132 -0
  519. package/src/knowledge/audit-scoring.ts +589 -0
  520. package/src/knowledge/audit.ts +55 -599
  521. package/src/knowledge/import.ts +2 -0
  522. package/src/knowledge/index-generator.ts +4 -6
  523. package/src/knowledge/index.ts +27 -2
  524. package/src/knowledge/ingest.ts +1 -1
  525. package/src/knowledge/lifecycle.ts +5 -2
  526. package/src/knowledge/migration.ts +8 -2
  527. package/src/knowledge/query.ts +8 -1
  528. package/src/knowledge/reference-tracker.ts +5 -7
  529. package/src/knowledge/store.ts +75 -16
  530. package/src/knowledge/tree-walker.ts +29 -0
  531. package/src/knowledge/types.ts +19 -0
  532. package/src/monitoring/CONTEXT.md +5 -2
  533. package/src/monitoring/__tests__/context-tracker.test.ts +16 -8
  534. package/src/monitoring/__tests__/trace-file-anchoring.test.ts +80 -0
  535. package/src/monitoring/traces.ts +19 -5
  536. package/src/release/CONTEXT.md +1 -1
  537. package/src/release/__tests__/integrity.test.ts +21 -12
  538. package/src/test-setup/__tests__/jsonl-fake-fs.test.ts +98 -0
  539. package/src/test-setup/jsonl-fake-fs.ts +59 -0
  540. package/src/tools/index.ts +5 -1
  541. package/src/types/checkpoint.ts +6 -0
  542. package/src/types/project-config.ts +21 -0
  543. package/src/types/trace.ts +14 -4
  544. package/src/utils/__tests__/file-walk.test.ts +3 -2
  545. package/src/utils/__tests__/jsonl-bounded-read.test.ts +106 -0
  546. package/src/utils/__tests__/jsonl-skip-disposition.test.ts +10 -6
  547. package/src/utils/__tests__/jsonl.test.ts +61 -14
  548. package/src/utils/__tests__/numeric-flag.test.ts +80 -0
  549. package/src/utils/__tests__/package-version.test.ts +2 -2
  550. package/src/utils/exec.ts +4 -64
  551. package/src/utils/jsonl.ts +159 -20
  552. package/src/utils/numeric-flag.ts +64 -0
  553. package/dist/failure/types.d.ts +0 -9
  554. package/dist/failure/types.d.ts.map +0 -1
  555. package/dist/failure/types.js +0 -25
  556. package/dist/failure/types.js.map +0 -1
  557. package/dist/gates/effective-gates.d.ts +0 -30
  558. package/dist/gates/effective-gates.d.ts.map +0 -1
  559. package/dist/gates/effective-gates.js +0 -81
  560. package/dist/gates/effective-gates.js.map +0 -1
  561. package/src/failure/types.ts +0 -9
  562. package/src/gates/__tests__/effective-gates.test.ts +0 -77
  563. package/src/gates/effective-gates.ts +0 -99
@@ -0,0 +1,192 @@
1
+ /**
2
+ * sync-docs 的 .ts 内容读取计数闸(#147 B 票,母票 #140「verifier 自己找文件」之二)
3
+ *
4
+ * 形状照 `check-read-count.test.ts` / `spec-baseline-read-count.test.ts`:真执行、
5
+ * 只在中间记一笔,不改任何行为。数的是**底层文件内容读取发生了几次**。
6
+ *
7
+ * 本票的承诺面 = **capability-listing 格式下模块清单无人消费,一份 `.ts` 内容都不读**
8
+ * (改造前:入口无条件全树扫描,逐文件 `await readFile` 只为首行注释)。
9
+ * 反证用同一棵源码树换成 file-table 格式:描述照旧提取,每份文件一次运行内恰读一次。
10
+ *
11
+ * 夹具一律不放 CONTEXT.md:CONTEXT 侧的 `.ts` 读取属导出面采集(#142),不在本票范围,
12
+ * 放进来会把「扫描分支零内容读」这条闸洗成模糊口径。
13
+ */
14
+
15
+ import * as fs from 'fs';
16
+ import * as os from 'os';
17
+ import * as path from 'path';
18
+ import { syncDocs } from '../sync-docs';
19
+ import { captureIO, type CapturingIO } from '../../command-contract';
20
+
21
+ type ReadCall = { file: string; via: 'readFile' | 'readFileSync' };
22
+
23
+ // 计数器挂在 globalThis:jest.mock 工厂会被提前调用,闭包外提会撞 TDZ
24
+ jest.mock('fs/promises', () => {
25
+ const actual = jest.requireActual<typeof import('fs/promises')>('fs/promises');
26
+ const g = globalThis as unknown as { __SD147_READS__?: ReadCall[] };
27
+ if (!g.__SD147_READS__) g.__SD147_READS__ = [];
28
+ const bucket = g.__SD147_READS__;
29
+ const name = (p: unknown): string => (Buffer.isBuffer(p) ? p.toString('utf8') : String(p));
30
+
31
+ return {
32
+ ...actual,
33
+ readFile: jest.fn((p: unknown, ...rest: unknown[]) => {
34
+ bucket.push({ file: name(p), via: 'readFile' });
35
+ return actual.readFile(p as fs.PathLike, ...(rest as [BufferEncoding])) as Promise<string>;
36
+ }),
37
+ };
38
+ });
39
+
40
+ jest.mock('fs', () => {
41
+ const actual = jest.requireActual<typeof import('fs')>('fs');
42
+ const g = globalThis as unknown as { __SD147_READS__?: ReadCall[] };
43
+ if (!g.__SD147_READS__) g.__SD147_READS__ = [];
44
+ const bucket = g.__SD147_READS__;
45
+ const name = (p: unknown): string => (Buffer.isBuffer(p) ? p.toString('utf8') : String(p));
46
+
47
+ return {
48
+ ...actual,
49
+ readFileSync: jest.fn((p: unknown, ...rest: unknown[]) => {
50
+ bucket.push({ file: name(p), via: 'readFileSync' });
51
+ return (actual.readFileSync as unknown as (path: unknown, options?: unknown) => unknown)(
52
+ p,
53
+ ...rest
54
+ );
55
+ }),
56
+ };
57
+ });
58
+
59
+ const reads = () =>
60
+ ((globalThis as unknown as { __SD147_READS__?: ReadCall[] }).__SD147_READS__ ||= []);
61
+
62
+ const SOURCE_FILES = [
63
+ 'src/alpha.ts',
64
+ 'src/beta.tsx',
65
+ 'src/nested/gamma.ts',
66
+ 'src/nested/deep/delta.ts',
67
+ ];
68
+
69
+ /** 清单格式与文件表格式共用的源码树(含三处必须被跳过口径排除的同名内容) */
70
+ function fixtureProject(capabilities: 'listing' | 'table' | 'absent'): string {
71
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'sd147-read-count-'));
72
+ const write = (rel: string, content: string): void => {
73
+ const target = path.join(dir, rel);
74
+ fs.mkdirSync(path.dirname(target), { recursive: true });
75
+ fs.writeFileSync(target, content, 'utf-8');
76
+ };
77
+
78
+ write('src/alpha.ts', '// alpha 的描述\nexport const a = 1;\n');
79
+ write('src/beta.tsx', 'export const b = 1;\n');
80
+ write('src/nested/gamma.ts', '/**\n * gamma 的描述\n */\nexport const c = 1;\n');
81
+ write('src/nested/deep/delta.ts', 'export const d = 1;\n');
82
+ // 跳过口径的三份对照:barrel、.d.ts、__tests__(外加 node_modules 与 dist)
83
+ write('src/index.ts', 'export * from "./alpha";\n');
84
+ write('src/ambient.d.ts', 'export const t = 1;\n');
85
+ write('src/__tests__/alpha.test.ts', '// 不该被读\nexport const x = 1;\n');
86
+ write('src/node_modules/pkg/index.ts', '// 不该被读\n');
87
+ write('src/dist/built.ts', '// 不该被读\n');
88
+
89
+ if (capabilities === 'listing') {
90
+ write(
91
+ 'CAPABILITIES.md',
92
+ '# Harness Capabilities\n\n## CLI Commands (21)\ncheck, validate, sync-docs\n'
93
+ );
94
+ } else if (capabilities === 'table') {
95
+ write(
96
+ 'CAPABILITIES.md',
97
+ [
98
+ '# Harness Capabilities',
99
+ '',
100
+ '| 模块 | 文件 | 说明 |',
101
+ '|------|------|------|',
102
+ '| alpha | src/alpha.ts | alpha 的描述 |',
103
+ '',
104
+ ].join('\n')
105
+ );
106
+ }
107
+ return dir;
108
+ }
109
+
110
+ const isTsContent = (rel: string): boolean => /\.tsx?$/.test(rel) && !rel.endsWith('.d.ts');
111
+
112
+ describe('sync-docs 的 .ts 内容读取计数闸(#147)', () => {
113
+ let io: CapturingIO;
114
+ let dir: string;
115
+
116
+ /** 相对项目根的落点 → 内容读取次数(readFileSync 与异步 readFile 各算一次) */
117
+ function contentCounts(): Map<string, number> {
118
+ const counts = new Map<string, number>();
119
+ for (const call of reads()) {
120
+ const rel = path.relative(dir, call.file);
121
+ if (!rel || rel.startsWith('..')) continue; // 非本项目文件(模块加载等)不计
122
+ counts.set(rel, (counts.get(rel) ?? 0) + 1);
123
+ }
124
+ return counts;
125
+ }
126
+
127
+ function tsContentReads(): Array<[string, number]> {
128
+ return [...contentCounts().entries()].filter(([rel]) => isTsContent(rel)).sort();
129
+ }
130
+
131
+ beforeEach(() => {
132
+ // 原地清空:mock 工厂在装载时就 captured 了这个数组引用,换新数组计数会落到旧的去向(假绿)
133
+ reads().length = 0;
134
+ io = captureIO();
135
+ });
136
+
137
+ afterEach(() => {
138
+ fs.rmSync(dir, { recursive: true, force: true });
139
+ });
140
+
141
+ it('capability-listing 模式:模块清单无人消费 → 一份 .ts 内容都不读', async () => {
142
+ dir = fixtureProject('listing');
143
+
144
+ await syncDocs({ projectPath: dir, check: true, json: true }, io);
145
+
146
+ // 正对照:真走了 listing 分支(否则下面的 0 是空跑出来的)
147
+ expect(JSON.parse(io.outText()).format).toBe('capability-listing');
148
+ expect(tsContentReads()).toEqual([]);
149
+ });
150
+
151
+ it('反证:file-table 格式照旧逐文件取描述,且每份文件一次运行内恰读一次', async () => {
152
+ dir = fixtureProject('table');
153
+
154
+ await syncDocs({ projectPath: dir, check: true, json: true }, io);
155
+
156
+ // 正对照:走了 file-table 分支,描述确实进了对外 JSON(判定面未被这次改造削掉)
157
+ const json = JSON.parse(io.outText());
158
+ expect(json.format).toBe('file-table');
159
+ const described = json.added.map(
160
+ (a: { module: { file: string; description: string } }) => `${a.module.file}#${a.module.description}`
161
+ );
162
+ expect(described.sort()).toEqual([
163
+ 'src/beta.tsx#beta',
164
+ 'src/nested/deep/delta.ts#delta',
165
+ 'src/nested/gamma.ts#gamma 的描述',
166
+ ]);
167
+
168
+ expect(tsContentReads()).toEqual(
169
+ SOURCE_FILES.map((f) => [f, 1]).sort()
170
+ );
171
+ });
172
+
173
+ it('CAPABILITIES.md 缺席时同样走 file-table 分支:读取表只含源码清单那几份文件', async () => {
174
+ dir = fixtureProject('absent');
175
+
176
+ await syncDocs({ projectPath: dir, check: true, json: true }, io);
177
+
178
+ expect(JSON.parse(io.outText()).format).toBe('file-table');
179
+ expect(tsContentReads()).toEqual(SOURCE_FILES.map((f) => [f, 1]).sort());
180
+ });
181
+
182
+ it('listing 模式的整张读取表冻结:本次运行只碰 CAPABILITIES.md,源码树零读取', async () => {
183
+ dir = fixtureProject('listing');
184
+
185
+ await syncDocs({ projectPath: dir, check: true, json: true }, io);
186
+
187
+ expect([...contentCounts().entries()].sort()).toEqual([['CAPABILITIES.md', 5]]);
188
+ // CAPABILITIES.md = 5 是**本票范围外的既有重复读**:入口一次异步读 + 计数核对
189
+ // (checkCapabilityCounts → FreshnessRunner 每条计数规则各读一次)。此处如实冻结,
190
+ // 既不为它改动也不放行——数字变了就是扫描分支被改动的信号(登记在 #147 resolution)。
191
+ });
192
+ });
@@ -5,6 +5,7 @@
5
5
  import * as fs from 'fs';
6
6
  import { captureIO, type CapturingIO } from '../../command-contract';
7
7
  import * as path from 'path';
8
+ import * as os from 'os';
8
9
  import { syncDocs } from '../sync-docs';
9
10
 
10
11
  let io: CapturingIO;
@@ -13,10 +14,10 @@ beforeEach(() => {
13
14
  });
14
15
 
15
16
  describe('sync-docs command', () => {
16
- const tempDir = path.join(process.cwd(), 'temp-test-sync-docs');
17
+ let tempDir: string;
17
18
 
18
19
  beforeAll(() => {
19
- fs.mkdirSync(tempDir, { recursive: true });
20
+ tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'temp-test-sync-docs-'));
20
21
  });
21
22
 
22
23
  afterAll(() => {
@@ -2,7 +2,7 @@
2
2
  * validate 命令测试
3
3
  */
4
4
 
5
- import { validate, createExampleCheckpoint, createExampleResolutions } from '../validate';
5
+ import { validate } from '../validate';
6
6
  import { captureIO, type CapturingIO } from '../../command-contract';
7
7
  import * as fs from 'fs/promises';
8
8
  import { CheckpointValidator } from '../../../core/validators/checkpoint';
@@ -126,51 +126,4 @@ describe('validate command', () => {
126
126
  expect(result).toEqual({ kind: 'fail', reason: '1 个检查点未通过: test-1' });
127
127
  });
128
128
  });
129
-
130
- describe('createExampleCheckpoint', () => {
131
- it('应该创建示例检查点文件', async () => {
132
- mockFs.access.mockRejectedValue(new Error('ENOENT'));
133
- mockFs.mkdir.mockResolvedValue(undefined);
134
- mockFs.writeFile.mockResolvedValue(undefined);
135
- mockYaml.dump.mockReturnValue('yaml content');
136
-
137
- await createExampleCheckpoint('/project', io);
138
-
139
- expect(mockFs.mkdir).toHaveBeenCalled();
140
- expect(mockFs.writeFile).toHaveBeenCalled();
141
- expect(io.outText()).toContain('已创建示例检查点');
142
- });
143
-
144
- it('已存在时不覆盖', async () => {
145
- mockFs.access.mockResolvedValue(undefined);
146
-
147
- await createExampleCheckpoint('/project', io);
148
-
149
- expect(mockFs.writeFile).not.toHaveBeenCalled();
150
- expect(io.outText()).toContain('checkpoints.yml 已存在,跳过');
151
- });
152
- });
153
-
154
- describe('createExampleResolutions', () => {
155
- it('应该创建 Resolutions 文件', async () => {
156
- mockFs.access.mockRejectedValue(new Error('ENOENT'));
157
- mockFs.mkdir.mockResolvedValue(undefined);
158
- mockFs.writeFile.mockResolvedValue(undefined);
159
-
160
- await createExampleResolutions('/project', io);
161
-
162
- expect(mockFs.mkdir).toHaveBeenCalled();
163
- expect(mockFs.writeFile).toHaveBeenCalled();
164
- expect(io.outText()).toContain('已创建 Resolutions 文件');
165
- });
166
-
167
- it('已存在时不覆盖', async () => {
168
- mockFs.access.mockResolvedValue(undefined);
169
-
170
- await createExampleResolutions('/project', io);
171
-
172
- expect(mockFs.writeFile).not.toHaveBeenCalled();
173
- expect(io.outText()).toContain('resolutions.json 已存在,跳过');
174
- });
175
- });
176
129
  });
@@ -9,6 +9,7 @@ import * as fs from 'fs/promises';
9
9
  import * as path from 'path';
10
10
  import { SpecAcceptanceGate } from '../../gates/acceptance';
11
11
  import { log, processIO, type CommandIO, type CommandResult } from '../command-contract';
12
+ import { reportGateDecision, reportGateError } from '../gate-command';
12
13
 
13
14
 
14
15
  export interface AcceptanceOptions {
@@ -43,38 +44,32 @@ export async function acceptance(
43
44
  });
44
45
 
45
46
  try {
46
- // 执行检查
47
- const context = {
47
+ const decision = await gate.evaluate({
48
48
  projectPath,
49
49
  taskId: options.taskId,
50
- };
50
+ });
51
51
 
52
- const result = await gate.check(context as any);
53
-
54
- if (result.passed) {
55
- log(io);
56
- log(io, chalk.green('✅ 验收标准检查通过'));
57
- if (result.details) {
58
- log(io, chalk.gray(` 通过项: ${result.details.checkedCriteria ?? 0}`));
59
- log(io, chalk.gray(` 总项数: ${result.details.totalCriteria ?? 0}`));
60
- }
61
- } else {
62
- log(io);
63
- log(io, chalk.red('❌ 验收标准检查失败'));
64
- log(io, chalk.red(` ${result.message}`));
65
- if (result.details?.uncheckedCriteria) {
66
- (result.details.uncheckedCriteria as string[]).forEach((criteria: string) => {
67
- log(io, chalk.red(` - ${criteria}`));
68
- });
69
- }
70
- return { kind: 'fail', reason: `acceptance gate denied: ${result.message}` };
71
- }
72
- return { kind: 'ok' };
73
- } catch (error: any) {
74
- log(io);
75
- log(io, chalk.red('❌ 验收标准检查出错'));
76
- log(io, chalk.red(` ${error.message}`));
77
- return { kind: 'fail', reason: `acceptance gate error: ${error.message}` };
52
+ return reportGateDecision(
53
+ io,
54
+ {
55
+ gateId: 'acceptance',
56
+ label: '验收标准',
57
+ onPass: (r) =>
58
+ r.details
59
+ ? [
60
+ chalk.gray(` 通过项: ${r.details.checkedCriteria ?? 0}`),
61
+ chalk.gray(` 总项数: ${r.details.totalCriteria ?? 0}`),
62
+ ]
63
+ : [],
64
+ onFail: (r) =>
65
+ r.details?.uncheckedCriteria
66
+ ? (r.details.uncheckedCriteria as string[]).map((criteria: string) => chalk.red(` - ${criteria}`))
67
+ : [],
68
+ },
69
+ decision
70
+ );
71
+ } catch (error) {
72
+ return reportGateError(io, 'acceptance', '验收标准', error);
78
73
  }
79
74
  }
80
75
 
@@ -5,24 +5,25 @@
5
5
  * 工单 23:触发条件与证据检测迁至 core/constraints/context-builder
6
6
  * ADR-0001:约束集统一走 getMergedConstraintsConfig 生效集链路(preset/config 禁用/custom/scenes)
7
7
  * harness#88:本命令是 trace 记录器的组合根——core 不上行依赖 monitoring,
8
- * 真实收集器在此经构造参数接线
8
+ * 真实收集器在此经构造参数接线;#139:收集器锚根构造,trace 落点跟 --project-path 走
9
9
  */
10
10
 
11
11
  import chalk from 'chalk';
12
- import * as fs from 'fs';
13
12
  import * as path from 'path';
14
13
  import { ConstraintChecker } from '../../core/constraints/checker';
15
14
  import { IRON_LAWS, GUIDELINES, PROMPTS } from '../../core/constraints/definitions';
16
- import { getMergedConstraintsConfig } from '../../core/effective-constraints';
15
+ import { getMergedConstraintsConfig, constraintsFromMerged } from '../../core/effective-constraints';
17
16
  import { buildConstraintContext } from '../../core/constraints/context-builder';
18
17
  import { createGitEvidence, type GitEvidence } from '../../core/constraints/git-evidence';
18
+ import { createRunEnv, type RunEnv } from '../../core/constraints/run-env';
19
19
  import { detectInjectionDrift } from '../../core/constraints/injection-drift';
20
20
  import { GOVERNANCE_HEADING } from '../../core/constraints/injection-writer';
21
- import { getTraceCollector } from '../../monitoring/traces';
22
- import { countJsonlLines } from '../../utils/jsonl';
23
- import { DEFAULT_TRACE_FILE } from '../../types/trace';
21
+ import { TraceCollector } from '../../monitoring/traces';
22
+ import { readJsonl } from '../../utils/jsonl';
23
+ import { DEFAULT_TRACE_FILE, type ExecutionTrace } from '../../types/trace';
24
24
  import type { ConstraintResult, ConstraintTrigger } from '../../types/constraint';
25
25
  import { log, processIO, type CommandIO, type CommandResult } from '../command-contract';
26
+ import { fileStateIO, type StateIO } from '../state-io';
26
27
 
27
28
  /** 证据行着色(与调用处所属结论块一致) */
28
29
  const EVIDENCE_PAINT = {
@@ -51,8 +52,8 @@ function logEvidence(
51
52
  }
52
53
 
53
54
  export interface CheckOptions {
54
- /** 预设名称 */
55
- preset: string;
55
+ /** 预设名称;**不传 = 按项目 `.harness/config.yml` 的 preset**(CLI 不给缺省值,见 commands/definitions.ts) */
56
+ preset?: string;
56
57
  /** 是否只检查暂存文件 */
57
58
  staged: boolean;
58
59
  /** 触发条件 */
@@ -66,6 +67,20 @@ export interface CheckOptions {
66
67
  * 测试据此断言"同一 run 内每条 git 命令至多执行一次"。
67
68
  */
68
69
  evidence?: GitEvidence;
70
+ /**
71
+ * 运行级观察面(非 CLI flag;ADR-0023)
72
+ *
73
+ * 缺省 = 本 run 独占一份。注入则与调用方共用同一份上行数据读取,
74
+ * 测试据此断言「同一次运行内同一项目文件至多读一次」。
75
+ */
76
+ runEnv?: RunEnv;
77
+ /**
78
+ * 状态文件接缝(非 CLI flag;ADR-0026)
79
+ *
80
+ * 缺省 = 真实 fs 实现(fileStateIO)。注入则 `.harness/.state.json` 的读写
81
+ * 走替身,测试据此不碰真文件系统。
82
+ */
83
+ stateIO?: StateIO;
69
84
  }
70
85
 
71
86
  /**
@@ -76,15 +91,20 @@ export async function check(
76
91
  io: CommandIO = processIO,
77
92
  ): Promise<CommandResult> {
78
93
  log(io, chalk.blue('🔍 检查约束...'));
79
- log(io, chalk.gray(`预设: ${options.preset}`));
94
+ log(io, chalk.gray(`预设: ${options.preset ?? '(按 config.yml,缺省 standard)'}`));
80
95
 
81
96
  try {
82
97
  const projectPath = options.projectPath || process.cwd();
98
+ // 一次 run 一份证据与观察面(#87 / ADR-0023):入口构造,沿生效集、context、checker 向下传
99
+ const evidence = options.evidence ?? createGitEvidence(projectPath);
100
+ const runEnv = options.runEnv ?? createRunEnv(projectPath);
101
+ const stateIO = options.stateIO ?? fileStateIO(projectPath);
83
102
 
84
103
  // 生效约束集(ADR-0001):内置 → preset → config.yml 禁用 → custom 追加 → scenes 过滤。
85
104
  // --preset 仅在没有项目自定义配置时覆盖 config.yml 的 preset(工单 23 语义:
86
105
  // 项目自定义配置优先于 CLI 预设),优先级规则收在 getMergedConstraintsConfig 一处。
87
- const merged = getMergedConstraintsConfig(projectPath, { preset: options.preset });
106
+ // CLI 不给 -p 缺省值:没传 = 尊重 config.yml(ADR-0023 步骤 4.5,缺省值曾让两者不可区分)
107
+ const merged = getMergedConstraintsConfig(runEnv, { preset: options.preset });
88
108
  if (merged.custom.length > 0) {
89
109
  log(io, chalk.gray(`自定义约束: ${merged.custom.length} 条`));
90
110
  }
@@ -98,12 +118,13 @@ export async function check(
98
118
 
99
119
  // 构建上下文(工单 23:触发条件与证据检测收敛至 core/constraints/context-builder)
100
120
  // #87:一次 run 一份 git 证据——context-builder 与 checker 层共用同一实例
101
- const evidence = options.evidence ?? createGitEvidence(projectPath);
121
+ // ADR-0023:一次 run 一份运行级观察面——配置、源根探测、trace 证据探测全部共用同一份读取
102
122
  const context = await buildConstraintContext({
103
123
  projectPath: options.projectPath,
104
124
  staged: options.staged,
105
125
  trigger: options.trigger,
106
126
  evidence,
127
+ runEnv,
107
128
  });
108
129
  const changedFiles = context.changedFiles ?? [];
109
130
  if (changedFiles.length > 0) {
@@ -113,8 +134,9 @@ export async function check(
113
134
 
114
135
  // 执行三层检查(per-request 传 customConfig,避免单例状态污染;证据同 run 同源)
115
136
  // trace 记录器经构造参数接线(harness#88):一次命令一个 checker 实例
116
- const checker = new ConstraintChecker(getTraceCollector());
117
- const result = await checker.checkConstraints(context, merged, evidence);
137
+ // #139:收集器锚根构造——不传 projectPath trace 会落进调用方 cwd,B 侧读不到
138
+ const checker = new ConstraintChecker(new TraceCollector({ projectPath }));
139
+ const result = await checker.checkConstraints(context, merged, evidence, runEnv);
118
140
 
119
141
  // 输出结果
120
142
  log(io);
@@ -183,7 +205,8 @@ export async function check(
183
205
  // 注入漂移校验(ADR-0001 决策 7):黄色警告块,不改 exit code、不影响门禁结果。
184
206
  // 无漂移/未注入零输出;漂移检测自身异常静默吞掉,绝不影响 check。
185
207
  try {
186
- const drift = detectInjectionDrift(projectPath);
208
+ // 生效集直接用本 run 那一份:一遍算完,且比对对象就是本次实际执法的规则集(ADR-0023 步骤 4.5)
209
+ const drift = detectInjectionDrift(runEnv, undefined, constraintsFromMerged(merged));
187
210
  if (drift.hasDrift) {
188
211
  log(io);
189
212
  log(io, chalk.yellow(`⚠️ 检测到 ${drift.injectionFile ?? '治理文档'} 约束注入漂移(仅警告,不阻断):`));
@@ -206,7 +229,7 @@ export async function check(
206
229
  log(io, chalk.green('✅ 约束检查通过'));
207
230
 
208
231
  // 智能提示
209
- const hint = await getSmartHint(projectPath);
232
+ const hint = await getSmartHint(projectPath, stateIO);
210
233
  if (hint) {
211
234
  log(io);
212
235
  log(io, chalk.gray('────────────────────────────────────'));
@@ -221,44 +244,46 @@ export async function check(
221
244
  }
222
245
  }
223
246
 
247
+ /** 智能提示阈值:trace 累计条数首次达到此数才提示跑 status(判定只要「够不够」,不要总数) */
248
+ const TRACE_HINT_THRESHOLD = 50;
249
+
224
250
  /**
225
251
  * 智能提示:检查是否需要提示用户下一步操作
252
+ *
253
+ * 状态读写经 StateIO(ADR-0026):读-改-写,`status` 不再把 `shownHints` 抹掉,
254
+ * 「首次达到阈值」的去重自此真生效。
226
255
  */
227
- async function getSmartHint(projectPath: string): Promise<string | null> {
256
+ async function getSmartHint(projectPath: string, stateIO: StateIO): Promise<string | null> {
228
257
  const tracesPath = path.join(projectPath, DEFAULT_TRACE_FILE);
229
- const statePath = path.join(projectPath, '.harness', '.state.json');
230
258
 
231
- // 只数非空行数(含坏行),零 parse——原语义不变,走 jsonl 正本(harness#82)
232
- const traceCount = countJsonlLines(tracesPath);
259
+ // 只读够 TRACE_HINT_THRESHOLD 行即停(坏行照旧占位,条数口径与改前的纯计数逐字一致)——
260
+ // traces.log append-only 无上限文件,为一个比较符整读不成立
261
+ // 计数去向:豁免(harness#100)——本消费面只输出「够不够」的提示行,没有可挂坏行计数的输出位
262
+ const { records, skippedLines } = readJsonl<ExecutionTrace>(tracesPath, 'skip', {
263
+ head: TRACE_HINT_THRESHOLD,
264
+ });
265
+ const traceCount = records.length + skippedLines;
233
266
  if (traceCount === 0) {
234
267
  return null;
235
268
  }
236
- // 读取状态
237
- let state: {
238
- shownHints?: string[];
239
- lastStatusRun?: string;
240
- lastDiagnoseRun?: string;
241
- } = {};
242
- if (fs.existsSync(statePath)) {
243
- state = JSON.parse(fs.readFileSync(statePath, 'utf-8'));
244
- }
269
+ // 读取状态(经接缝;文件缺失 → {})
270
+ const state = stateIO.read();
245
271
  state.shownHints = state.shownHints || [];
246
-
272
+
247
273
  const hints: string[] = [];
248
-
249
- // 条件 1: 记录数首次达到 50
250
- if (traceCount >= 50 && !state.shownHints.includes('trace_50')) {
274
+
275
+ // 条件 1: 记录数首次达到阈值
276
+ if (traceCount >= TRACE_HINT_THRESHOLD && !state.shownHints.includes('trace_50')) {
251
277
  hints.push('📊 记录已足够,运行 harness status 查看统计');
252
278
  state.shownHints.push('trace_50');
253
279
  }
254
280
 
255
281
  // 保存状态
256
282
  if (hints.length > 0) {
257
- fs.mkdirSync(path.dirname(statePath), { recursive: true });
258
- fs.writeFileSync(statePath, JSON.stringify(state, null, 2));
283
+ stateIO.write(state);
259
284
  return hints.join('\n');
260
285
  }
261
-
286
+
262
287
  return null;
263
288
  }
264
289
 
@@ -10,14 +10,14 @@
10
10
  * 退出码映射收敛在 bin 一处。
11
11
  */
12
12
 
13
- import { createCommandGate, getCommandRiskLevel, DEFAULT_COMMAND_BLACKLIST, type CommandBlacklistRule } from '../../gates';
13
+ import { createCommandGate, DEFAULT_COMMAND_BLACKLIST, type CommandBlacklistRule } from '../../gates';
14
14
  import { log, logError, processIO, type CommandIO, type CommandResult } from '../command-contract';
15
+ import { gateCommandResult } from '../gate-command';
15
16
 
16
17
  export interface CommandCheckOptions {
17
18
  level?: boolean;
18
19
  list?: boolean;
19
20
  json?: boolean;
20
- strict?: boolean;
21
21
  }
22
22
 
23
23
  /**
@@ -65,11 +65,14 @@ export async function executeCommand(
65
65
  return { kind: 'usage-error', reason: '缺少要检查的命令参数' };
66
66
  }
67
67
 
68
- const gate = createCommandGate({ strict: options.strict });
69
- const result = await gate.check(cmd);
68
+ const gate = createCommandGate();
69
+ // 命令门禁只判命令串、不读项目根;GateContext 仍要求项目根——本命令无 -p 旗帜,取真实 cwd
70
+ const decision = await gate.evaluate({ projectPath: process.cwd(), command: cmd });
71
+ const result = decision.result;
70
72
 
71
73
  if (options.level) {
72
- const level = getCommandRiskLevel(cmd);
74
+ // 等级取自本命令创建的这台实例:与默认分支同一来源,配置不再中途丢失(#135)
75
+ const level = gate.getRiskLevel(cmd);
73
76
  if (options.json) {
74
77
  log(io, JSON.stringify({ level, command: cmd }));
75
78
  } else {
@@ -97,7 +100,5 @@ export async function executeCommand(
97
100
  log(io, result.passed ? `\x1b[32m✓\x1b[0m ${result.message}` : `\x1b[31m✗\x1b[0m ${result.message}`);
98
101
  }
99
102
 
100
- return result.passed
101
- ? { kind: 'ok' }
102
- : { kind: 'fail', reason: `command gate denied: ${result.message}` };
103
+ return gateCommandResult('command', decision);
103
104
  }