@dommaker/harness 1.6.0 → 1.8.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 (560) hide show
  1. package/CHANGELOG.md +52 -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 +11 -3
  15. package/dist/cli/commands/check.d.ts.map +1 -1
  16. package/dist/cli/commands/check.js +26 -11
  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/sync-docs/context-syncer.d.ts +21 -2
  76. package/dist/cli/commands/sync-docs/context-syncer.d.ts.map +1 -1
  77. package/dist/cli/commands/sync-docs/context-syncer.js +112 -28
  78. package/dist/cli/commands/sync-docs/context-syncer.js.map +1 -1
  79. package/dist/cli/commands/sync-docs/index.d.ts +1 -1
  80. package/dist/cli/commands/sync-docs/index.d.ts.map +1 -1
  81. package/dist/cli/commands/sync-docs/index.js +86 -27
  82. package/dist/cli/commands/sync-docs/index.js.map +1 -1
  83. package/dist/cli/commands/sync-docs/project-reader.d.ts +24 -1
  84. package/dist/cli/commands/sync-docs/project-reader.d.ts.map +1 -1
  85. package/dist/cli/commands/sync-docs/project-reader.js +33 -7
  86. package/dist/cli/commands/sync-docs/project-reader.js.map +1 -1
  87. package/dist/cli/commands/validate.d.ts +0 -16
  88. package/dist/cli/commands/validate.d.ts.map +1 -1
  89. package/dist/cli/commands/validate.js +2 -97
  90. package/dist/cli/commands/validate.js.map +1 -1
  91. package/dist/cli/gate-command.d.ts +37 -0
  92. package/dist/cli/gate-command.d.ts.map +1 -0
  93. package/dist/cli/gate-command.js +64 -0
  94. package/dist/cli/gate-command.js.map +1 -0
  95. package/dist/completion-checkers/index.d.ts +1 -1
  96. package/dist/completion-checkers/index.d.ts.map +1 -1
  97. package/dist/completion-checkers/index.js +0 -15
  98. package/dist/completion-checkers/index.js.map +1 -1
  99. package/dist/context/knowledge-injector.d.ts +4 -2
  100. package/dist/context/knowledge-injector.d.ts.map +1 -1
  101. package/dist/context/knowledge-injector.js +13 -6
  102. package/dist/context/knowledge-injector.js.map +1 -1
  103. package/dist/core/constraints/agent-prompt-renderer.js +2 -2
  104. package/dist/core/constraints/agent-prompt-renderer.js.map +1 -1
  105. package/dist/core/constraints/capabilities-reconcile.d.ts +20 -0
  106. package/dist/core/constraints/capabilities-reconcile.d.ts.map +1 -1
  107. package/dist/core/constraints/capabilities-reconcile.js +26 -4
  108. package/dist/core/constraints/capabilities-reconcile.js.map +1 -1
  109. package/dist/core/constraints/check-cache.d.ts +1 -1
  110. package/dist/core/constraints/check-cache.js +1 -1
  111. package/dist/core/constraints/checker.d.ts +8 -3
  112. package/dist/core/constraints/checker.d.ts.map +1 -1
  113. package/dist/core/constraints/checker.js +30 -19
  114. package/dist/core/constraints/checker.js.map +1 -1
  115. package/dist/core/constraints/checkers/capability-sync.d.ts +3 -1
  116. package/dist/core/constraints/checkers/capability-sync.d.ts.map +1 -1
  117. package/dist/core/constraints/checkers/capability-sync.js +17 -24
  118. package/dist/core/constraints/checkers/capability-sync.js.map +1 -1
  119. package/dist/core/constraints/checkers/context-doc-sync.d.ts +1 -1
  120. package/dist/core/constraints/checkers/context-doc-sync.d.ts.map +1 -1
  121. package/dist/core/constraints/checkers/context-doc-sync.js +9 -6
  122. package/dist/core/constraints/checkers/context-doc-sync.js.map +1 -1
  123. package/dist/core/constraints/checkers/docs-freshness.d.ts.map +1 -1
  124. package/dist/core/constraints/checkers/docs-freshness.js +24 -30
  125. package/dist/core/constraints/checkers/docs-freshness.js.map +1 -1
  126. package/dist/core/constraints/checkers/governance-presence.d.ts.map +1 -1
  127. package/dist/core/constraints/checkers/governance-presence.js +10 -4
  128. package/dist/core/constraints/checkers/governance-presence.js.map +1 -1
  129. package/dist/core/constraints/checkers/types.d.ts +10 -6
  130. package/dist/core/constraints/checkers/types.d.ts.map +1 -1
  131. package/dist/core/constraints/checkers/types.js +7 -3
  132. package/dist/core/constraints/checkers/types.js.map +1 -1
  133. package/dist/core/constraints/context-builder.d.ts +11 -10
  134. package/dist/core/constraints/context-builder.d.ts.map +1 -1
  135. package/dist/core/constraints/context-builder.js +31 -27
  136. package/dist/core/constraints/context-builder.js.map +1 -1
  137. package/dist/core/constraints/context-reconcile.d.ts +75 -0
  138. package/dist/core/constraints/context-reconcile.d.ts.map +1 -0
  139. package/dist/core/constraints/context-reconcile.js +161 -0
  140. package/dist/core/constraints/context-reconcile.js.map +1 -0
  141. package/dist/core/constraints/doc-freshness/runner.d.ts +7 -0
  142. package/dist/core/constraints/doc-freshness/runner.d.ts.map +1 -1
  143. package/dist/core/constraints/doc-freshness/runner.js +8 -3
  144. package/dist/core/constraints/doc-freshness/runner.js.map +1 -1
  145. package/dist/core/constraints/git-evidence.js +1 -1
  146. package/dist/core/constraints/git-evidence.js.map +1 -1
  147. package/dist/core/constraints/injection-drift.d.ts +7 -2
  148. package/dist/core/constraints/injection-drift.d.ts.map +1 -1
  149. package/dist/core/constraints/injection-drift.js +13 -7
  150. package/dist/core/constraints/injection-drift.js.map +1 -1
  151. package/dist/core/constraints/run-env.d.ts +92 -0
  152. package/dist/core/constraints/run-env.d.ts.map +1 -0
  153. package/dist/core/constraints/run-env.js +175 -0
  154. package/dist/core/constraints/run-env.js.map +1 -0
  155. package/dist/core/constraints/triggers.d.ts +22 -0
  156. package/dist/core/constraints/triggers.d.ts.map +1 -0
  157. package/dist/core/constraints/triggers.js +31 -0
  158. package/dist/core/constraints/triggers.js.map +1 -0
  159. package/dist/core/effective-constraints.d.ts +13 -4
  160. package/dist/core/effective-constraints.d.ts.map +1 -1
  161. package/dist/core/effective-constraints.js +16 -6
  162. package/dist/core/effective-constraints.js.map +1 -1
  163. package/dist/core/effective-set.d.ts +8 -15
  164. package/dist/core/effective-set.d.ts.map +1 -1
  165. package/dist/core/effective-set.js +7 -12
  166. package/dist/core/effective-set.js.map +1 -1
  167. package/dist/core/index.d.ts +2 -1
  168. package/dist/core/index.d.ts.map +1 -1
  169. package/dist/core/index.js.map +1 -1
  170. package/dist/core/project-config-loader.d.ts +39 -17
  171. package/dist/core/project-config-loader.d.ts.map +1 -1
  172. package/dist/core/project-config-loader.js +51 -122
  173. package/dist/core/project-config-loader.js.map +1 -1
  174. package/dist/core/validators/check-handlers/http.d.ts +2 -2
  175. package/dist/core/validators/check-handlers/http.d.ts.map +1 -1
  176. package/dist/core/validators/check-handlers/http.js +12 -7
  177. package/dist/core/validators/check-handlers/http.js.map +1 -1
  178. package/dist/core/validators/index.d.ts +1 -1
  179. package/dist/core/validators/index.d.ts.map +1 -1
  180. package/dist/core/validators/passes-gate.d.ts.map +1 -1
  181. package/dist/core/validators/passes-gate.js +2 -2
  182. package/dist/core/validators/passes-gate.js.map +1 -1
  183. package/dist/failure/classifier.d.ts +1 -1
  184. package/dist/failure/classifier.d.ts.map +1 -1
  185. package/dist/failure/classifier.js +8 -8
  186. package/dist/failure/classifier.js.map +1 -1
  187. package/dist/failure/index.d.ts +2 -1
  188. package/dist/failure/index.d.ts.map +1 -1
  189. package/dist/failure/index.js +9 -17
  190. package/dist/failure/index.js.map +1 -1
  191. package/dist/failure/recorder.d.ts +1 -1
  192. package/dist/failure/recorder.d.ts.map +1 -1
  193. package/dist/gates/checker-gate.d.ts +2 -1
  194. package/dist/gates/checker-gate.d.ts.map +1 -1
  195. package/dist/gates/checker-gate.js +3 -2
  196. package/dist/gates/checker-gate.js.map +1 -1
  197. package/dist/gates/command.d.ts +10 -4
  198. package/dist/gates/command.d.ts.map +1 -1
  199. package/dist/gates/command.js +36 -62
  200. package/dist/gates/command.js.map +1 -1
  201. package/dist/gates/contract.d.ts.map +1 -1
  202. package/dist/gates/contract.js +0 -4
  203. package/dist/gates/contract.js.map +1 -1
  204. package/dist/gates/definitions.d.ts +2 -1
  205. package/dist/gates/definitions.d.ts.map +1 -1
  206. package/dist/gates/definitions.js +6 -5
  207. package/dist/gates/definitions.js.map +1 -1
  208. package/dist/gates/index.d.ts +0 -4
  209. package/dist/gates/index.d.ts.map +1 -1
  210. package/dist/gates/index.js +1 -6
  211. package/dist/gates/index.js.map +1 -1
  212. package/dist/gates/performance.d.ts.map +1 -1
  213. package/dist/gates/performance.js +0 -4
  214. package/dist/gates/performance.js.map +1 -1
  215. package/dist/gates/runner.d.ts +1 -1
  216. package/dist/gates/runner.js +1 -1
  217. package/dist/gates/security.d.ts +1 -1
  218. package/dist/gates/security.d.ts.map +1 -1
  219. package/dist/gates/security.js +5 -6
  220. package/dist/gates/security.js.map +1 -1
  221. package/dist/gates/types.d.ts +14 -17
  222. package/dist/gates/types.d.ts.map +1 -1
  223. package/dist/gates/types.js.map +1 -1
  224. package/dist/hooks/bootstrap.d.ts +6 -4
  225. package/dist/hooks/bootstrap.d.ts.map +1 -1
  226. package/dist/hooks/bootstrap.js +25 -13
  227. package/dist/hooks/bootstrap.js.map +1 -1
  228. package/dist/hooks/config.d.ts +6 -2
  229. package/dist/hooks/config.d.ts.map +1 -1
  230. package/dist/hooks/config.js +5 -1
  231. package/dist/hooks/config.js.map +1 -1
  232. package/dist/hooks/index.d.ts +1 -1
  233. package/dist/hooks/index.d.ts.map +1 -1
  234. package/dist/hooks/index.js +0 -15
  235. package/dist/hooks/index.js.map +1 -1
  236. package/dist/hooks/pipeline.d.ts.map +1 -1
  237. package/dist/hooks/pipeline.js +2 -4
  238. package/dist/hooks/pipeline.js.map +1 -1
  239. package/dist/hooks/registry.d.ts +11 -8
  240. package/dist/hooks/registry.d.ts.map +1 -1
  241. package/dist/hooks/registry.js +22 -7
  242. package/dist/hooks/registry.js.map +1 -1
  243. package/dist/hooks/types.d.ts +23 -7
  244. package/dist/hooks/types.d.ts.map +1 -1
  245. package/dist/index.d.ts +4 -4
  246. package/dist/index.d.ts.map +1 -1
  247. package/dist/index.js +3 -4
  248. package/dist/index.js.map +1 -1
  249. package/dist/knowledge/audit-scoring.d.ts +87 -0
  250. package/dist/knowledge/audit-scoring.d.ts.map +1 -0
  251. package/dist/knowledge/audit-scoring.js +470 -0
  252. package/dist/knowledge/audit-scoring.js.map +1 -0
  253. package/dist/knowledge/audit.d.ts +11 -59
  254. package/dist/knowledge/audit.d.ts.map +1 -1
  255. package/dist/knowledge/audit.js +47 -522
  256. package/dist/knowledge/audit.js.map +1 -1
  257. package/dist/knowledge/import.d.ts.map +1 -1
  258. package/dist/knowledge/import.js +2 -0
  259. package/dist/knowledge/import.js.map +1 -1
  260. package/dist/knowledge/index-generator.d.ts.map +1 -1
  261. package/dist/knowledge/index-generator.js +4 -5
  262. package/dist/knowledge/index-generator.js.map +1 -1
  263. package/dist/knowledge/index.d.ts +3 -2
  264. package/dist/knowledge/index.d.ts.map +1 -1
  265. package/dist/knowledge/index.js +3 -16
  266. package/dist/knowledge/index.js.map +1 -1
  267. package/dist/knowledge/ingest.js +1 -1
  268. package/dist/knowledge/ingest.js.map +1 -1
  269. package/dist/knowledge/lifecycle.d.ts.map +1 -1
  270. package/dist/knowledge/lifecycle.js +4 -2
  271. package/dist/knowledge/lifecycle.js.map +1 -1
  272. package/dist/knowledge/migration.d.ts +3 -0
  273. package/dist/knowledge/migration.d.ts.map +1 -1
  274. package/dist/knowledge/migration.js +8 -2
  275. package/dist/knowledge/migration.js.map +1 -1
  276. package/dist/knowledge/query.d.ts +6 -0
  277. package/dist/knowledge/query.d.ts.map +1 -1
  278. package/dist/knowledge/query.js +8 -2
  279. package/dist/knowledge/query.js.map +1 -1
  280. package/dist/knowledge/reference-tracker.d.ts.map +1 -1
  281. package/dist/knowledge/reference-tracker.js +4 -6
  282. package/dist/knowledge/reference-tracker.js.map +1 -1
  283. package/dist/knowledge/store.d.ts +22 -16
  284. package/dist/knowledge/store.d.ts.map +1 -1
  285. package/dist/knowledge/store.js +53 -12
  286. package/dist/knowledge/store.js.map +1 -1
  287. package/dist/knowledge/tree-walker.d.ts +19 -0
  288. package/dist/knowledge/tree-walker.d.ts.map +1 -0
  289. package/dist/knowledge/tree-walker.js +30 -0
  290. package/dist/knowledge/tree-walker.js.map +1 -0
  291. package/dist/knowledge/types.d.ts +16 -0
  292. package/dist/knowledge/types.d.ts.map +1 -1
  293. package/dist/monitoring/traces.d.ts +5 -3
  294. package/dist/monitoring/traces.d.ts.map +1 -1
  295. package/dist/monitoring/traces.js +19 -5
  296. package/dist/monitoring/traces.js.map +1 -1
  297. package/dist/test-setup/jsonl-fake-fs.d.ts +30 -0
  298. package/dist/test-setup/jsonl-fake-fs.d.ts.map +1 -0
  299. package/dist/test-setup/jsonl-fake-fs.js +49 -0
  300. package/dist/test-setup/jsonl-fake-fs.js.map +1 -0
  301. package/dist/tools/index.d.ts +4 -1
  302. package/dist/tools/index.d.ts.map +1 -1
  303. package/dist/tools/index.js +7 -15
  304. package/dist/tools/index.js.map +1 -1
  305. package/dist/types/checkpoint.d.ts +5 -0
  306. package/dist/types/checkpoint.d.ts.map +1 -1
  307. package/dist/types/passes-gate.d.ts +0 -13
  308. package/dist/types/passes-gate.d.ts.map +1 -1
  309. package/dist/types/project-config.d.ts +18 -0
  310. package/dist/types/project-config.d.ts.map +1 -1
  311. package/dist/types/trace.d.ts +13 -4
  312. package/dist/types/trace.d.ts.map +1 -1
  313. package/dist/types/trace.js +4 -3
  314. package/dist/types/trace.js.map +1 -1
  315. package/dist/utils/exec.d.ts +4 -27
  316. package/dist/utils/exec.d.ts.map +1 -1
  317. package/dist/utils/exec.js +4 -94
  318. package/dist/utils/exec.js.map +1 -1
  319. package/dist/utils/jsonl.d.ts +17 -7
  320. package/dist/utils/jsonl.d.ts.map +1 -1
  321. package/dist/utils/jsonl.js +144 -17
  322. package/dist/utils/jsonl.js.map +1 -1
  323. package/dist/utils/numeric-flag.d.ts +44 -0
  324. package/dist/utils/numeric-flag.d.ts.map +1 -0
  325. package/dist/utils/numeric-flag.js +62 -0
  326. package/dist/utils/numeric-flag.js.map +1 -0
  327. package/package.json +1 -1
  328. package/src/CONTEXT.md +5 -2
  329. package/src/__tests__/acceptance-gate.test.ts +7 -4
  330. package/src/__tests__/checker-extra.test.ts +3 -2
  331. package/src/__tests__/checker.test.ts +4 -3
  332. package/src/__tests__/checkpoint.test.ts +26 -9
  333. package/src/__tests__/context-files-resolution.test.ts +29 -15
  334. package/src/__tests__/contract-gate.test.ts +19 -40
  335. package/src/__tests__/error-classifier.test.ts +1 -1
  336. package/src/__tests__/exec.test.ts +45 -107
  337. package/src/__tests__/failure-recorder.test.ts +7 -5
  338. package/src/__tests__/hooks-pipeline.test.ts +34 -47
  339. package/src/__tests__/layering.test.ts +217 -25
  340. package/src/__tests__/passes-gate.test.ts +9 -4
  341. package/src/__tests__/performance-gate.test.ts +3 -15
  342. package/src/__tests__/project-config-loader-extra.test.ts +31 -57
  343. package/src/__tests__/project-config-loader.test.ts +6 -3
  344. package/src/__tests__/public-exports.test.ts +27 -6
  345. package/src/__tests__/public-type-surface.test.ts +360 -0
  346. package/src/__tests__/public-value-surface.test.ts +182 -0
  347. package/src/__tests__/review-gate.test.ts +4 -6
  348. package/src/__tests__/security-gate.test.ts +5 -20
  349. package/src/__tests__/skip-semantics.test.ts +5 -3
  350. package/src/__tests__/spec-validator.test.ts +3 -2
  351. package/src/__tests__/sub-barrels-explicit.test.ts +87 -0
  352. package/src/__tests__/test-fixture-hygiene.test.ts +53 -0
  353. package/src/__tests__/trace-analyzer-extra.test.ts +5 -3
  354. package/src/__tests__/trace-analyzer.test.ts +5 -3
  355. package/src/__tests__/trace-collector.test.ts +5 -3
  356. package/src/agents/index.ts +13 -2
  357. package/src/cli/__tests__/gate-command.test.ts +162 -0
  358. package/src/cli/commands/CONTEXT.md +29 -5
  359. package/src/cli/commands/__tests__/acceptance.test.ts +24 -25
  360. package/src/cli/commands/__tests__/bin-exit-mapping.test.ts +15 -0
  361. package/src/cli/commands/__tests__/check-drift.test.ts +42 -1
  362. package/src/cli/commands/__tests__/check-read-count.test.ts +167 -0
  363. package/src/cli/commands/__tests__/check-skip-output.test.ts +4 -1
  364. package/src/cli/commands/__tests__/check.test.ts +43 -36
  365. package/src/cli/commands/__tests__/command-gate-dead-options.test.ts +60 -0
  366. package/src/cli/commands/__tests__/command.test.ts +33 -17
  367. package/src/cli/commands/__tests__/constraints-retire.test.ts +52 -0
  368. package/src/cli/commands/__tests__/context-syncer.test.ts +141 -0
  369. package/src/cli/commands/__tests__/contract.test.ts +20 -20
  370. package/src/cli/commands/__tests__/failure.test.ts +5 -4
  371. package/src/cli/commands/__tests__/gate-decision.ts +30 -0
  372. package/src/cli/commands/__tests__/init-dead-options.test.ts +50 -0
  373. package/src/cli/commands/__tests__/init-governance-io.test.ts +139 -0
  374. package/src/cli/commands/__tests__/init-injection.test.ts +3 -3
  375. package/src/cli/commands/__tests__/init-ondisk.test.ts +867 -0
  376. package/src/cli/commands/__tests__/init.test.ts +82 -6
  377. package/src/cli/commands/__tests__/knowledge-audit-threshold.test.ts +146 -0
  378. package/src/cli/commands/__tests__/knowledge-flywheel-consistency.test.ts +1 -1
  379. package/src/cli/commands/__tests__/knowledge-tone-mapping.test.ts +244 -0
  380. package/src/cli/commands/__tests__/knowledge-view.test.ts +839 -0
  381. package/src/cli/commands/__tests__/knowledge.test.ts +33 -15
  382. package/src/cli/commands/__tests__/numeric-flag-assembly.test.ts +368 -0
  383. package/src/cli/commands/__tests__/passes-gate-dead-options.test.ts +89 -1
  384. package/src/cli/commands/__tests__/performance.test.ts +19 -21
  385. package/src/cli/commands/__tests__/posteval-plan.test.ts +5 -3
  386. package/src/cli/commands/__tests__/pre-push-hook.test.ts +181 -0
  387. package/src/cli/commands/__tests__/project-path-anchoring.test.ts +95 -2
  388. package/src/cli/commands/__tests__/project-path-convention.test.ts +103 -25
  389. package/src/cli/commands/__tests__/registry.test.ts +2 -0
  390. package/src/cli/commands/__tests__/report.test.ts +23 -1
  391. package/src/cli/commands/__tests__/review.test.ts +10 -17
  392. package/src/cli/commands/__tests__/scaffold.test.ts +505 -0
  393. package/src/cli/commands/__tests__/security-default-scan.test.ts +75 -0
  394. package/src/cli/commands/__tests__/security.test.ts +21 -24
  395. package/src/cli/commands/__tests__/spec-baseline-check.test.ts +3 -2
  396. package/src/cli/commands/__tests__/spec-baseline-index-cap.test.ts +131 -0
  397. package/src/cli/commands/__tests__/spec-baseline-read-count.test.ts +325 -0
  398. package/src/cli/commands/__tests__/sync-docs-agents.test.ts +19 -4
  399. package/src/cli/commands/__tests__/sync-docs-context-drift.test.ts +232 -0
  400. package/src/cli/commands/__tests__/sync-docs-module-order.test.ts +111 -0
  401. package/src/cli/commands/__tests__/sync-docs-read-count.test.ts +192 -0
  402. package/src/cli/commands/__tests__/sync-docs.test.ts +3 -2
  403. package/src/cli/commands/__tests__/validate.test.ts +1 -48
  404. package/src/cli/commands/acceptance.ts +24 -29
  405. package/src/cli/commands/check.ts +40 -17
  406. package/src/cli/commands/command.ts +9 -8
  407. package/src/cli/commands/constraints-retire.ts +57 -70
  408. package/src/cli/commands/contract.ts +44 -47
  409. package/src/cli/commands/definitions.ts +12 -6
  410. package/src/cli/commands/failure.ts +16 -3
  411. package/src/cli/commands/init.ts +242 -389
  412. package/src/cli/commands/knowledge-view.ts +224 -0
  413. package/src/cli/commands/knowledge.ts +643 -448
  414. package/src/cli/commands/passes-gate.ts +12 -3
  415. package/src/cli/commands/performance.ts +31 -38
  416. package/src/cli/commands/report.ts +3 -2
  417. package/src/cli/commands/review.ts +22 -28
  418. package/src/cli/commands/scaffold-templates.ts +406 -0
  419. package/src/cli/commands/scaffold.ts +302 -0
  420. package/src/cli/commands/security.ts +27 -23
  421. package/src/cli/commands/spec-baseline-check.ts +158 -33
  422. package/src/cli/commands/sync-docs/__tests__/context-export-surface.test.ts +102 -0
  423. package/src/cli/commands/sync-docs/__tests__/module-descriptions.test.ts +196 -0
  424. package/src/cli/commands/sync-docs/context-syncer.ts +137 -31
  425. package/src/cli/commands/sync-docs/index.ts +103 -28
  426. package/src/cli/commands/sync-docs/project-reader.ts +51 -7
  427. package/src/cli/commands/validate.ts +1 -104
  428. package/src/cli/gate-command.ts +87 -0
  429. package/src/completion-checkers/index.ts +10 -1
  430. package/src/context/CONTEXT.md +2 -1
  431. package/src/context/__tests__/knowledge-injector.test.ts +27 -0
  432. package/src/context/__tests__/session-manager.test.ts +19 -12
  433. package/src/context/knowledge-injector.ts +14 -7
  434. package/src/core/CONTEXT.md +10 -7
  435. package/src/core/__tests__/effective-set.test.ts +36 -60
  436. package/src/core/constraints/__tests__/context-reconcile.test.ts +246 -0
  437. package/src/core/constraints/__tests__/run-env.test.ts +377 -0
  438. package/src/core/constraints/__tests__/triggers.test.ts +70 -0
  439. package/src/core/constraints/agent-prompt-renderer.ts +1 -1
  440. package/src/core/constraints/capabilities-reconcile.ts +28 -4
  441. package/src/core/constraints/check-cache.ts +1 -1
  442. package/src/core/constraints/checker.ts +30 -14
  443. package/src/core/constraints/checkers/__tests__/context-doc-sync.test.ts +8 -3
  444. package/src/core/constraints/checkers/__tests__/governance-presence.test.ts +16 -7
  445. package/src/core/constraints/checkers/__tests__/no-hardcoded-credentials.test.ts +2 -1
  446. package/src/core/constraints/checkers/capability-sync.ts +27 -28
  447. package/src/core/constraints/checkers/context-doc-sync.ts +9 -7
  448. package/src/core/constraints/checkers/docs-freshness.ts +28 -33
  449. package/src/core/constraints/checkers/governance-presence.ts +10 -6
  450. package/src/core/constraints/checkers/types.ts +14 -8
  451. package/src/core/constraints/context-builder.ts +35 -26
  452. package/src/core/constraints/context-reconcile.ts +200 -0
  453. package/src/core/constraints/doc-freshness/__tests__/runner.test.ts +25 -0
  454. package/src/core/constraints/doc-freshness/runner.ts +18 -4
  455. package/src/core/constraints/git-evidence.ts +1 -1
  456. package/src/core/constraints/injection-drift.ts +19 -8
  457. package/src/core/constraints/run-env.ts +207 -0
  458. package/src/core/constraints/triggers.ts +33 -0
  459. package/src/core/effective-constraints.ts +17 -6
  460. package/src/core/effective-set.ts +8 -24
  461. package/src/core/index.ts +2 -1
  462. package/src/core/project-config-loader.ts +54 -102
  463. package/src/core/validators/__tests__/http-retry-sleep.test.ts +231 -0
  464. package/src/core/validators/check-handlers/http.ts +18 -7
  465. package/src/core/validators/index.ts +0 -1
  466. package/src/core/validators/passes-gate.ts +2 -3
  467. package/src/failure/CONTEXT.md +2 -1
  468. package/src/failure/classifier.ts +2 -2
  469. package/src/failure/index.ts +14 -2
  470. package/src/failure/recorder.ts +1 -1
  471. package/src/gates/CONTEXT.md +13 -7
  472. package/src/gates/__tests__/checker-gate.test.ts +1 -1
  473. package/src/gates/__tests__/command-single-predicate.test.ts +135 -0
  474. package/src/gates/__tests__/command.test.ts +8 -15
  475. package/src/gates/__tests__/contract.test.ts +5 -5
  476. package/src/gates/__tests__/gate-interface.test.ts +0 -17
  477. package/src/gates/__tests__/performance.test.ts +0 -13
  478. package/src/gates/__tests__/review.test.ts +0 -1
  479. package/src/gates/__tests__/runner.test.ts +1 -1
  480. package/src/gates/__tests__/security-default-scan.test.ts +97 -0
  481. package/src/gates/__tests__/security.test.ts +0 -13
  482. package/src/gates/checker-gate.ts +3 -2
  483. package/src/gates/command.ts +51 -74
  484. package/src/gates/contract.ts +0 -5
  485. package/src/gates/definitions.ts +6 -5
  486. package/src/gates/index.ts +0 -5
  487. package/src/gates/performance.ts +1 -6
  488. package/src/gates/runner.ts +1 -1
  489. package/src/gates/security.ts +9 -11
  490. package/src/gates/types.ts +20 -23
  491. package/src/hooks/CONTEXT.md +10 -9
  492. package/src/hooks/__tests__/bootstrap.test.ts +29 -6
  493. package/src/hooks/__tests__/pipeline.test.ts +28 -17
  494. package/src/hooks/__tests__/registry.test.ts +51 -3
  495. package/src/hooks/bootstrap.ts +35 -15
  496. package/src/hooks/config.ts +6 -2
  497. package/src/hooks/index.ts +10 -1
  498. package/src/hooks/pipeline.ts +4 -6
  499. package/src/hooks/registry.ts +31 -12
  500. package/src/hooks/types.ts +24 -7
  501. package/src/index.ts +1 -3
  502. package/src/knowledge/CONTEXT.md +14 -7
  503. package/src/knowledge/__tests__/audit-labels.test.ts +8 -5
  504. package/src/knowledge/__tests__/audit-scoring.test.ts +230 -0
  505. package/src/knowledge/__tests__/audit-write-count.test.ts +131 -0
  506. package/src/knowledge/__tests__/audit.test.ts +291 -208
  507. package/src/knowledge/__tests__/doctor.test.ts +3 -2
  508. package/src/knowledge/__tests__/ingest.test.ts +3 -2
  509. package/src/knowledge/__tests__/lifecycle.test.ts +57 -2
  510. package/src/knowledge/__tests__/migration.test.ts +35 -6
  511. package/src/knowledge/__tests__/query.test.ts +3 -2
  512. package/src/knowledge/__tests__/reference-tracker.test.ts +23 -2
  513. package/src/knowledge/__tests__/store.test.ts +149 -4
  514. package/src/knowledge/__tests__/tree-walker.test.ts +132 -0
  515. package/src/knowledge/audit-scoring.ts +589 -0
  516. package/src/knowledge/audit.ts +55 -599
  517. package/src/knowledge/import.ts +2 -0
  518. package/src/knowledge/index-generator.ts +4 -6
  519. package/src/knowledge/index.ts +27 -2
  520. package/src/knowledge/ingest.ts +1 -1
  521. package/src/knowledge/lifecycle.ts +5 -2
  522. package/src/knowledge/migration.ts +8 -2
  523. package/src/knowledge/query.ts +8 -1
  524. package/src/knowledge/reference-tracker.ts +5 -7
  525. package/src/knowledge/store.ts +75 -16
  526. package/src/knowledge/tree-walker.ts +29 -0
  527. package/src/knowledge/types.ts +19 -0
  528. package/src/monitoring/CONTEXT.md +5 -2
  529. package/src/monitoring/__tests__/context-tracker.test.ts +16 -8
  530. package/src/monitoring/__tests__/trace-file-anchoring.test.ts +80 -0
  531. package/src/monitoring/traces.ts +19 -5
  532. package/src/release/CONTEXT.md +1 -1
  533. package/src/release/__tests__/integrity.test.ts +21 -12
  534. package/src/test-setup/__tests__/jsonl-fake-fs.test.ts +98 -0
  535. package/src/test-setup/jsonl-fake-fs.ts +59 -0
  536. package/src/tools/index.ts +5 -1
  537. package/src/types/checkpoint.ts +6 -0
  538. package/src/types/passes-gate.ts +0 -17
  539. package/src/types/project-config.ts +21 -0
  540. package/src/types/trace.ts +14 -4
  541. package/src/utils/__tests__/file-walk.test.ts +3 -2
  542. package/src/utils/__tests__/jsonl-bounded-read.test.ts +106 -0
  543. package/src/utils/__tests__/jsonl-skip-disposition.test.ts +10 -6
  544. package/src/utils/__tests__/jsonl.test.ts +61 -14
  545. package/src/utils/__tests__/numeric-flag.test.ts +80 -0
  546. package/src/utils/__tests__/package-version.test.ts +2 -2
  547. package/src/utils/exec.ts +4 -64
  548. package/src/utils/jsonl.ts +159 -20
  549. package/src/utils/numeric-flag.ts +64 -0
  550. package/dist/failure/types.d.ts +0 -9
  551. package/dist/failure/types.d.ts.map +0 -1
  552. package/dist/failure/types.js +0 -25
  553. package/dist/failure/types.js.map +0 -1
  554. package/dist/gates/effective-gates.d.ts +0 -30
  555. package/dist/gates/effective-gates.d.ts.map +0 -1
  556. package/dist/gates/effective-gates.js +0 -81
  557. package/dist/gates/effective-gates.js.map +0 -1
  558. package/src/failure/types.ts +0 -9
  559. package/src/gates/__tests__/effective-gates.test.ts +0 -77
  560. package/src/gates/effective-gates.ts +0 -99
@@ -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,7 +5,7 @@
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';
@@ -13,14 +13,15 @@ import * as fs from 'fs';
13
13
  import * as path from 'path';
14
14
  import { ConstraintChecker } from '../../core/constraints/checker';
15
15
  import { IRON_LAWS, GUIDELINES, PROMPTS } from '../../core/constraints/definitions';
16
- import { getMergedConstraintsConfig } from '../../core/effective-constraints';
16
+ import { getMergedConstraintsConfig, constraintsFromMerged } from '../../core/effective-constraints';
17
17
  import { buildConstraintContext } from '../../core/constraints/context-builder';
18
18
  import { createGitEvidence, type GitEvidence } from '../../core/constraints/git-evidence';
19
+ import { createRunEnv, type RunEnv } from '../../core/constraints/run-env';
19
20
  import { detectInjectionDrift } from '../../core/constraints/injection-drift';
20
21
  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';
22
+ import { TraceCollector } from '../../monitoring/traces';
23
+ import { readJsonl } from '../../utils/jsonl';
24
+ import { DEFAULT_TRACE_FILE, type ExecutionTrace } from '../../types/trace';
24
25
  import type { ConstraintResult, ConstraintTrigger } from '../../types/constraint';
25
26
  import { log, processIO, type CommandIO, type CommandResult } from '../command-contract';
26
27
 
@@ -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,13 @@ 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;
69
77
  }
70
78
 
71
79
  /**
@@ -76,15 +84,19 @@ export async function check(
76
84
  io: CommandIO = processIO,
77
85
  ): Promise<CommandResult> {
78
86
  log(io, chalk.blue('🔍 检查约束...'));
79
- log(io, chalk.gray(`预设: ${options.preset}`));
87
+ log(io, chalk.gray(`预设: ${options.preset ?? '(按 config.yml,缺省 standard)'}`));
80
88
 
81
89
  try {
82
90
  const projectPath = options.projectPath || process.cwd();
91
+ // 一次 run 一份证据与观察面(#87 / ADR-0023):入口构造,沿生效集、context、checker 向下传
92
+ const evidence = options.evidence ?? createGitEvidence(projectPath);
93
+ const runEnv = options.runEnv ?? createRunEnv(projectPath);
83
94
 
84
95
  // 生效约束集(ADR-0001):内置 → preset → config.yml 禁用 → custom 追加 → scenes 过滤。
85
96
  // --preset 仅在没有项目自定义配置时覆盖 config.yml 的 preset(工单 23 语义:
86
97
  // 项目自定义配置优先于 CLI 预设),优先级规则收在 getMergedConstraintsConfig 一处。
87
- const merged = getMergedConstraintsConfig(projectPath, { preset: options.preset });
98
+ // CLI 不给 -p 缺省值:没传 = 尊重 config.yml(ADR-0023 步骤 4.5,缺省值曾让两者不可区分)
99
+ const merged = getMergedConstraintsConfig(runEnv, { preset: options.preset });
88
100
  if (merged.custom.length > 0) {
89
101
  log(io, chalk.gray(`自定义约束: ${merged.custom.length} 条`));
90
102
  }
@@ -98,12 +110,13 @@ export async function check(
98
110
 
99
111
  // 构建上下文(工单 23:触发条件与证据检测收敛至 core/constraints/context-builder)
100
112
  // #87:一次 run 一份 git 证据——context-builder 与 checker 层共用同一实例
101
- const evidence = options.evidence ?? createGitEvidence(projectPath);
113
+ // ADR-0023:一次 run 一份运行级观察面——配置、源根探测、trace 证据探测全部共用同一份读取
102
114
  const context = await buildConstraintContext({
103
115
  projectPath: options.projectPath,
104
116
  staged: options.staged,
105
117
  trigger: options.trigger,
106
118
  evidence,
119
+ runEnv,
107
120
  });
108
121
  const changedFiles = context.changedFiles ?? [];
109
122
  if (changedFiles.length > 0) {
@@ -113,8 +126,9 @@ export async function check(
113
126
 
114
127
  // 执行三层检查(per-request 传 customConfig,避免单例状态污染;证据同 run 同源)
115
128
  // trace 记录器经构造参数接线(harness#88):一次命令一个 checker 实例
116
- const checker = new ConstraintChecker(getTraceCollector());
117
- const result = await checker.checkConstraints(context, merged, evidence);
129
+ // #139:收集器锚根构造——不传 projectPath trace 会落进调用方 cwd,B 侧读不到
130
+ const checker = new ConstraintChecker(new TraceCollector({ projectPath }));
131
+ const result = await checker.checkConstraints(context, merged, evidence, runEnv);
118
132
 
119
133
  // 输出结果
120
134
  log(io);
@@ -183,7 +197,8 @@ export async function check(
183
197
  // 注入漂移校验(ADR-0001 决策 7):黄色警告块,不改 exit code、不影响门禁结果。
184
198
  // 无漂移/未注入零输出;漂移检测自身异常静默吞掉,绝不影响 check。
185
199
  try {
186
- const drift = detectInjectionDrift(projectPath);
200
+ // 生效集直接用本 run 那一份:一遍算完,且比对对象就是本次实际执法的规则集(ADR-0023 步骤 4.5)
201
+ const drift = detectInjectionDrift(runEnv, undefined, constraintsFromMerged(merged));
187
202
  if (drift.hasDrift) {
188
203
  log(io);
189
204
  log(io, chalk.yellow(`⚠️ 检测到 ${drift.injectionFile ?? '治理文档'} 约束注入漂移(仅警告,不阻断):`));
@@ -221,6 +236,9 @@ export async function check(
221
236
  }
222
237
  }
223
238
 
239
+ /** 智能提示阈值:trace 累计条数首次达到此数才提示跑 status(判定只要「够不够」,不要总数) */
240
+ const TRACE_HINT_THRESHOLD = 50;
241
+
224
242
  /**
225
243
  * 智能提示:检查是否需要提示用户下一步操作
226
244
  */
@@ -228,8 +246,13 @@ async function getSmartHint(projectPath: string): Promise<string | null> {
228
246
  const tracesPath = path.join(projectPath, DEFAULT_TRACE_FILE);
229
247
  const statePath = path.join(projectPath, '.harness', '.state.json');
230
248
 
231
- // 只数非空行数(含坏行),零 parse——原语义不变,走 jsonl 正本(harness#82)
232
- const traceCount = countJsonlLines(tracesPath);
249
+ // 只读够 TRACE_HINT_THRESHOLD 行即停(坏行照旧占位,条数口径与改前的纯计数逐字一致)——
250
+ // traces.log append-only 无上限文件,为一个比较符整读不成立
251
+ // 计数去向:豁免(harness#100)——本消费面只输出「够不够」的提示行,没有可挂坏行计数的输出位
252
+ const { records, skippedLines } = readJsonl<ExecutionTrace>(tracesPath, 'skip', {
253
+ head: TRACE_HINT_THRESHOLD,
254
+ });
255
+ const traceCount = records.length + skippedLines;
233
256
  if (traceCount === 0) {
234
257
  return null;
235
258
  }
@@ -246,8 +269,8 @@ async function getSmartHint(projectPath: string): Promise<string | null> {
246
269
 
247
270
  const hints: string[] = [];
248
271
 
249
- // 条件 1: 记录数首次达到 50
250
- if (traceCount >= 50 && !state.shownHints.includes('trace_50')) {
272
+ // 条件 1: 记录数首次达到阈值
273
+ if (traceCount >= TRACE_HINT_THRESHOLD && !state.shownHints.includes('trace_50')) {
251
274
  hints.push('📊 记录已足够,运行 harness status 查看统计');
252
275
  state.shownHints.push('trace_50');
253
276
  }
@@ -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
  }
@@ -40,7 +40,7 @@ import { getConstraint } from '../../core/constraints/definitions';
40
40
  import { renderConstraintsSection, CONSTRAINTS_START_MARKER, CONSTRAINTS_END_MARKER } from '../../core/constraints/injection-renderer';
41
41
  import { replaceStandaloneRange, resolveInjectionTarget } from '../../core/constraints/injection-writer';
42
42
  import { getEffectiveConstraints } from '../../core/effective-constraints';
43
- import { loadRawProjectConfig, ProjectConfigLoader } from '../../core/project-config-loader';
43
+ import { isConstraintRetired, ProjectConfigLoader } from '../../core/project-config-loader';
44
44
  import { getHarnessPackageVersion } from '../../utils/package-version';
45
45
  import { FileKnowledgeStore } from '../../knowledge/store';
46
46
  import type { KnowledgeEntry } from '../../knowledge/types';
@@ -97,8 +97,14 @@ interface RetireTargetInfo {
97
97
 
98
98
  /**
99
99
  * 查找约束定义(内置 definitions + 项目 custom-constraints)
100
+ *
101
+ * loader 由调用方给(一次退役一份观察面,见 retireConstraint):本函数只读它的装载结果,
102
+ * 不再自造 ProjectConfigLoader。
100
103
  */
101
- function findRetireTarget(projectRoot: string, id: string): RetireTargetInfo | undefined {
104
+ function findRetireTarget(
105
+ loader: ProjectConfigLoader,
106
+ id: string
107
+ ): RetireTargetInfo | undefined {
102
108
  const builtIn = getConstraint(id);
103
109
  if (builtIn) {
104
110
  return {
@@ -112,8 +118,6 @@ function findRetireTarget(projectRoot: string, id: string): RetireTargetInfo | u
112
118
  };
113
119
  }
114
120
 
115
- const loader = new ProjectConfigLoader(projectRoot);
116
- loader.load();
117
121
  const custom = loader.getCustomConstraints()[id];
118
122
  if (custom) {
119
123
  const level = custom.level || 'guideline';
@@ -132,52 +136,20 @@ function findRetireTarget(projectRoot: string, id: string): RetireTargetInfo | u
132
136
  }
133
137
 
134
138
  /**
135
- * config.yml 退役段(ADR-0001 决策 5
139
+ * YAML 条目的读-改-写单点(harness#137
136
140
  *
137
- * js-yaml 不保留注释:原文件含注释行时重写会丢失,console 说明。
141
+ * 内置与 custom 两处退役落点原本是两段同型的读-改-写,只差键路径与 patch 内容。
142
+ * js-yaml 不保留注释:原文件含注释行时重写会丢失,console 说明(`label` 是给用户看的
143
+ * 文件名,与合并前两处逐字一致)。落盘字节由 `__tests__/constraints-retire.test.ts`
144
+ * 的逐字节冻结用例钉住——合并属内部重构,对外产物不得漂移。
138
145
  */
139
- function writeRetireConfig(
140
- projectRoot: string,
146
+ function setYamlEntry(
147
+ filePath: string,
148
+ label: string,
149
+ section: string,
141
150
  id: string,
142
- retiredMeta: { at: string; reason: string; stats: { total: number; fail: number; failRate: number } }
151
+ patch: Record<string, unknown>
143
152
  ): void {
144
- const configPath = path.join(projectRoot, '.harness', 'config.yml');
145
-
146
- let raw: Record<string, unknown> = {};
147
- let hadComments = false;
148
- if (fs.existsSync(configPath)) {
149
- const original = fs.readFileSync(configPath, 'utf-8');
150
- hadComments = original.split('\n').some(l => l.trimStart().startsWith('#'));
151
- raw = (yaml.load(original) as Record<string, unknown>) ?? {};
152
- }
153
-
154
- const constraints = (raw.constraints ?? {}) as Record<string, unknown>;
155
- const prev = (constraints[id] ?? {}) as Record<string, unknown>;
156
- constraints[id] = { ...prev, enabled: false, retired: retiredMeta };
157
- raw.constraints = constraints;
158
-
159
- fs.mkdirSync(path.dirname(configPath), { recursive: true });
160
- fs.writeFileSync(configPath, yaml.dump(raw, { lineWidth: 120 }), 'utf-8');
161
-
162
- if (hadComments) {
163
- console.log(chalk.yellow(' ⚠️ config.yml 已重写:js-yaml 不保留原文件注释'));
164
- }
165
- }
166
-
167
- /**
168
- * 写 custom-constraints.yml 退役段(studio#82 D6 统一落点)
169
- *
170
- * 在 custom_constraints.<id> 条目内追加 retired 元数据,保留规则原文。
171
- * js-yaml 不保留注释:原文件含注释行时重写会丢失,console 说明。
172
- */
173
- function writeCustomRetireYml(
174
- projectRoot: string,
175
- fileName: string,
176
- id: string,
177
- retiredMeta: { at: string; reason: string; stats: { total: number; fail: number; failRate: number } }
178
- ): void {
179
- const filePath = path.join(projectRoot, '.harness', fileName);
180
-
181
153
  let raw: Record<string, unknown> = {};
182
154
  let hadComments = false;
183
155
  if (fs.existsSync(filePath)) {
@@ -186,16 +158,16 @@ function writeCustomRetireYml(
186
158
  raw = (yaml.load(original) as Record<string, unknown>) ?? {};
187
159
  }
188
160
 
189
- const customs = (raw.custom_constraints ?? {}) as Record<string, Record<string, unknown>>;
190
- const prev = customs[id] ?? {};
191
- customs[id] = { ...prev, retired: retiredMeta };
192
- raw.custom_constraints = customs;
161
+ const entries = (raw[section] ?? {}) as Record<string, unknown>;
162
+ const prev = (entries[id] ?? {}) as Record<string, unknown>;
163
+ entries[id] = { ...prev, ...patch };
164
+ raw[section] = entries;
193
165
 
194
166
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
195
167
  fs.writeFileSync(filePath, yaml.dump(raw, { lineWidth: 120 }), 'utf-8');
196
168
 
197
169
  if (hadComments) {
198
- console.log(chalk.yellow(' ⚠️ custom-constraints.yml 已重写:js-yaml 不保留原文件注释'));
170
+ console.log(chalk.yellow(` ⚠️ ${label} 已重写:js-yaml 不保留原文件注释`));
199
171
  }
200
172
  }
201
173
 
@@ -293,7 +265,13 @@ export function retireConstraint(
293
265
  const iso = now.toISOString();
294
266
  const reason = options.reason ?? '';
295
267
 
296
- const target = findRetireTarget(projectRoot, id);
268
+ // 一次退役一份观察面(ADR-0023 决策 2):定义查找、already_retired 判定与 custom 文件名
269
+ // 解析共用这一份装载结果。此前同一次调用 new 了 2–3 枚加载器、各带一次 load()(harness#137)。
270
+ // 只覆盖写盘**之前**的读取:写盘后 syncGovernanceInjection 必须读到新状态,另起观察面。
271
+ const loader = new ProjectConfigLoader(projectRoot);
272
+ loader.load();
273
+
274
+ const target = findRetireTarget(loader, id);
297
275
  const emptyStats = { total: 0, fail: 0, failRate: 0 };
298
276
  const landing: RetireResult['landing'] =
299
277
  target?.source === 'custom' ? 'custom-constraints.yml' : 'config.yml';
@@ -301,17 +279,12 @@ export function retireConstraint(
301
279
  return { id, status: 'unknown_id', isIronLaw: false, landing, stats: emptyStats, injectionSynced: false };
302
280
  }
303
281
 
304
- // 已退役保护:内置看 config.yml constraints.<id>.enabled === false;
305
- // custom 看 yml 条目 retired 元数据(历史落点 config.yml enabled:false 同样保护)
306
- const rawConfig = loadRawProjectConfig(projectRoot);
307
- const existing = (rawConfig?.constraints as Record<string, { enabled?: boolean; retired?: unknown }> | undefined)?.[id];
308
- if (target.source === 'custom') {
309
- const loader = new ProjectConfigLoader(projectRoot);
310
- loader.load();
311
- if (loader.getCustomConstraints()[id]?.retired || existing?.enabled === false) {
312
- return { id, status: 'already_retired', isIronLaw: target.isIronLaw, landing, stats: emptyStats, injectionSynced: false };
313
- }
314
- } else if (existing?.enabled === false) {
282
+ // 已退役保护:判定单点在 core/project-config-loader isConstraintRetired
283
+ // (内置看 config.yml enabled:false;custom 看 yml 条目 retired 元数据,
284
+ // 历史落点 config.yml enabled:false 同样保护)
285
+ const disabledInConfig = loader.getConfig().constraints?.[id]?.enabled === false;
286
+ const customDef = target.source === 'custom' ? loader.getCustomConstraints()[id] : undefined;
287
+ if (isConstraintRetired(customDef, disabledInConfig)) {
315
288
  return { id, status: 'already_retired', isIronLaw: target.isIronLaw, landing, stats: emptyStats, injectionSynced: false };
316
289
  }
317
290
 
@@ -327,14 +300,26 @@ export function retireConstraint(
327
300
  failRate: evaluated > 0 ? (usage!.fail / evaluated) : 0,
328
301
  };
329
302
 
330
- // 1. 落盘退役(custom → yml 条目 retired 段;内置 → config.yml,原文均保留)
303
+ // 1. 落盘退役(custom → yml 条目 retired 段;内置 → config.yml enabled:false + retired 段,
304
+ // 两处原文均保留)
305
+ const retiredMeta = { at: iso, reason, stats };
331
306
  if (target.source === 'custom') {
332
- const loader = new ProjectConfigLoader(projectRoot);
333
- loader.load();
334
307
  const customFile = loader.getConfig().custom_constraints_file ?? 'custom-constraints.yml';
335
- writeCustomRetireYml(projectRoot, customFile, id, { at: iso, reason, stats });
308
+ setYamlEntry(
309
+ path.join(projectRoot, '.harness', customFile),
310
+ 'custom-constraints.yml',
311
+ 'custom_constraints',
312
+ id,
313
+ { retired: retiredMeta }
314
+ );
336
315
  } else {
337
- writeRetireConfig(projectRoot, id, { at: iso, reason, stats });
316
+ setYamlEntry(
317
+ path.join(projectRoot, '.harness', 'config.yml'),
318
+ 'config.yml',
319
+ 'constraints',
320
+ id,
321
+ { enabled: false, retired: retiredMeta }
322
+ );
338
323
  }
339
324
 
340
325
  // 2. KnowledgeStore
@@ -454,10 +439,12 @@ export async function runRetireInteractive(
454
439
  selectedIds = [...new Set(selectedIds)];
455
440
  }
456
441
 
457
- // 逐条收集 reason + iron 二次确认
442
+ // 逐条收集 reason + iron 二次确认(一次交互一份装载结果:候选到确认之间不写盘)
443
+ const planLoader = new ProjectConfigLoader(projectRoot);
444
+ planLoader.load();
458
445
  const plan: { id: string; reason: string; source: RetireTargetInfo['source'] }[] = [];
459
446
  for (const id of selectedIds) {
460
- const target = findRetireTarget(projectRoot, id);
447
+ const target = findRetireTarget(planLoader, id);
461
448
  if (!target) {
462
449
  console.log(chalk.red(`❌ ${id}: 约束不存在,跳过`));
463
450
  continue;
@@ -9,6 +9,7 @@ import * as fs from 'fs/promises';
9
9
  import * as path from 'path';
10
10
  import { ContractGate } from '../../gates/contract';
11
11
  import { log, processIO, type CommandIO, type CommandResult } from '../command-contract';
12
+ import { reportGateDecision, reportGateError } from '../gate-command';
12
13
 
13
14
  export interface ContractOptions {
14
15
  /** 项目路径 */
@@ -52,55 +53,51 @@ export async function contract(
52
53
  });
53
54
 
54
55
  try {
55
- const result = await gate.check({
56
- projectPath,
57
- } as any);
58
-
59
- if (result.passed) {
60
- log(io);
61
- log(io, chalk.green('✅ 契约门控检查通过'));
62
-
63
- if (result.details) {
64
- log(io, chalk.gray(` Schema 有效: ✅`));
65
- if (result.details.endpoints) {
66
- log(io, chalk.gray(` 端点数: ${result.details.endpoints}`));
67
- }
68
- if (result.details.breakingChanges === false) {
69
- log(io, chalk.gray(` 破坏性变更: 无`));
70
- }
71
- }
72
- } else {
73
- log(io);
74
- log(io, chalk.red('❌ 契约门控检查失败'));
75
- log(io, chalk.red(` ${result.message}`));
76
-
77
- if (result.details?.errors) {
78
- log(io);
79
- log(io, chalk.red('验证错误:'));
80
- (result.details.errors as string[]).forEach((error: string) => {
81
- log(io, chalk.red(` - ${error}`));
82
- });
83
- }
84
-
85
- if (result.details?.breakingChanges) {
86
- log(io);
87
- log(io, chalk.red('破坏性变更:'));
88
- (result.details.breakingChanges as any[]).forEach((change: any) => {
89
- log(io, chalk.red(` - ${change.type}: ${change.path}`));
90
- if (change.description) {
91
- log(io, chalk.gray(` ${change.description}`));
56
+ const decision = await gate.evaluate({ projectPath });
57
+
58
+ return reportGateDecision(
59
+ io,
60
+ {
61
+ gateId: 'contract',
62
+ label: '契约门控',
63
+ onPass: (r) => {
64
+ if (!r.details) return [];
65
+ const lines = [chalk.gray(` Schema 有效: ✅`)];
66
+ if (r.details.endpoints) {
67
+ lines.push(chalk.gray(` 端点数: ${r.details.endpoints}`));
68
+ }
69
+ if (r.details.breakingChanges === false) {
70
+ lines.push(chalk.gray(` 破坏性变更: 无`));
71
+ }
72
+ return lines;
73
+ },
74
+ onFail: (r) => {
75
+ const lines: string[] = [];
76
+
77
+ if (r.details?.errors) {
78
+ lines.push('', chalk.red('验证错误:'));
79
+ (r.details.errors as string[]).forEach((issue: string) => {
80
+ lines.push(chalk.red(` - ${issue}`));
81
+ });
92
82
  }
93
- });
94
- }
95
83
 
96
- return { kind: 'fail', reason: `contract gate denied: ${result.message}` };
97
- }
98
- return { kind: 'ok' };
99
- } catch (error: any) {
100
- log(io);
101
- log(io, chalk.red('❌ 契约门控检查出错'));
102
- log(io, chalk.red(` ${error.message}`));
103
- return { kind: 'fail', reason: `contract gate error: ${error.message}` };
84
+ if (r.details?.breakingChanges) {
85
+ lines.push('', chalk.red('破坏性变更:'));
86
+ (r.details.breakingChanges as any[]).forEach((change: any) => {
87
+ lines.push(chalk.red(` - ${change.type}: ${change.path}`));
88
+ if (change.description) {
89
+ lines.push(chalk.gray(` ${change.description}`));
90
+ }
91
+ });
92
+ }
93
+
94
+ return lines;
95
+ },
96
+ },
97
+ decision
98
+ );
99
+ } catch (error) {
100
+ return reportGateError(io, 'contract', '契约门控', error);
104
101
  }
105
102
  }
106
103
 
@@ -11,8 +11,12 @@
11
11
  * 子命令别名是数据(aliases),实参编组归各命令模块的具名导出
12
12
  * (那才是它的 interface/测试面);保证 --help/--version 懒加载不被破坏;
13
13
  * 注册表完整性断言(引用实现可解析)在 __tests__/registry.test.ts 构建/测试期校验。
14
+ * - 唯一例外 import:`utils/numeric-flag` 纯函数解析器(harness#154 口径条目指名的
15
+ * 数值旗帜唯一解析器)——非命令实现、零 IO,不破坏懒加载。
14
16
  */
15
17
 
18
+ import { requireNumericFlag } from '../../utils/numeric-flag';
19
+
16
20
  /**
17
21
  * 命令 CLI 选项元数据(直接映射 commander `.option()`)
18
22
  */
@@ -99,7 +103,9 @@ export const COMMAND_DEFINITIONS: CommandDefinition[] = [
99
103
  command: 'check',
100
104
  description: '检查铁律是否满足',
101
105
  options: [
102
- { flags: '-p, --preset <preset>', description: '预设名称', defaultValue: 'standard' },
106
+ // 不给缺省值:「没传 -p」与「传了 standard」必须可区分,否则生效集侧的覆盖规则恒触发、
107
+ // config.yml 的 preset 静默失效(漂移检测侧按 config.yml 算,两边就会稳定对不上)
108
+ { flags: '-p, --preset <preset>', description: '预设名称(缺省按项目 config.yml)' },
103
109
  { flags: '-s, --staged', description: '只检查暂存文件', defaultValue: false },
104
110
  { flags: '-t, --trigger <trigger>', description: '触发条件' },
105
111
  { flags: '--project-path <path>', description: '项目路径' },
@@ -143,10 +149,10 @@ export const COMMAND_DEFINITIONS: CommandDefinition[] = [
143
149
  options: [
144
150
  { flags: '-p, --preset <preset>', description: '预设名称 (strict/standard/relaxed)', defaultValue: 'standard' },
145
151
  { flags: '-g, --governance <level>', description: '治理级别 (minimal/standard/strict)' },
146
- { flags: '-t, --type <type>', description: '项目类型 (node-api/nextjs-app/python-api/custom)' },
147
152
  { flags: '--project-path <path>', description: '项目路径' },
148
153
  { flags: '--no-git-hooks', description: '不创建 Git hooks' },
149
- { flags: '--no-github-actions', description: '不创建 GitHub Actions' },
154
+ { flags: '--ci <platform>', description: '服务端 CI 接线平台 (github/gitlab/none);none = 不创建任何 CI 文件(治理 CI 面亦不建),缺省按 .harness/config.yml 的 ci.platform' },
155
+ { flags: '--no-github-actions', description: '不创建 GitHub Actions(已废弃:等价 --ci none)' },
150
156
  { flags: '--print-snippets', description: '只输出代码片段,不创建文件' },
151
157
  ],
152
158
  action: { module: 'init', export: 'init' },
@@ -331,9 +337,9 @@ export const COMMAND_DEFINITIONS: CommandDefinition[] = [
331
337
  projectPath: options.projectPath,
332
338
  export: options.export,
333
339
  json: options.json,
334
- zeroInterceptMin: parseInt(String(options.zeroInterceptMin), 10),
335
- noiseFailRate: parseFloat(String(options.noiseFailRate)),
336
- noiseMinTotal: parseInt(String(options.noiseMinTotal), 10),
340
+ zeroInterceptMin: requireNumericFlag('--zero-intercept-min', options.zeroInterceptMin as string | undefined, 'int'),
341
+ noiseFailRate: requireNumericFlag('--noise-fail-rate', options.noiseFailRate as string | undefined, 'float'),
342
+ noiseMinTotal: requireNumericFlag('--noise-min-total', options.noiseMinTotal as string | undefined, 'int'),
337
343
  }],
338
344
  },
339
345
  {