@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
@@ -1,10 +1,14 @@
1
1
  /**
2
- * 单向分层守卫(架构评审 2026-09-02 · 候选9 / harness#88)
2
+ * 单向分层守卫(架构评审 2026-09-02 · 候选9 / harness#88;逐目录参数化 harness#137
3
3
  *
4
- * 分层 `types → utils → core → 领域层 → cli` 此前只是文档约定。本文件把它落成两件事:
5
- * 1. 真扫描:src/core/** 对 cli / gates / monitoring 零**值**导入(type-only 允许)
6
- * 2. 真规则:eslint.config.mjs no-restricted-imports 对上行值导入报 error,
7
- * 并允许 type-only(探针在纯 node 进程里跑仓内真配置,代码不落盘)
4
+ * 分层 `types → utils → core → 领域层 → cli` 此前只是文档约定。本文件把它落成三件事:
5
+ * 1. 真扫描:**每个顶层单元(目录或 src 根文件)声明允许值导入的下行集合**,集合外的跨目录
6
+ * import 一律红。harness#88 时只守 `src/core/** cli/gates/monitoring` 一条边,
7
+ * types/utils 的回边与领域层互 import 全部放行;#137 改成逐目录冻结。
8
+ * 2. 真规则:eslint.config.mjs 的 no-restricted-imports 对 core 上行值导入报 error,
9
+ * 并允许 type-only(探针在纯 node 进程里跑仓内真配置,代码不落盘)。
10
+ * 3. 反证:扫描器对合成 import 语句真报违例、指名到目录与边,且合法边不误报
11
+ * (不靠往 src 里塞临时文件——那是能被别的测试与 tsc 扫到的污染)。
8
12
  */
9
13
 
10
14
  import * as fs from 'fs';
@@ -31,9 +35,73 @@ new FlatESLint({ cwd: process.cwd() })
31
35
  `;
32
36
 
33
37
  const REPO_ROOT = path.resolve(__dirname, '../..');
34
- const CORE_DIR = path.join(REPO_ROOT, 'src', 'core');
35
- /** core 之下不得出现值导入的上层目录 */
36
- const UPPER_LAYERS = ['cli', 'gates', 'monitoring'];
38
+ const SRC_DIR = path.join(REPO_ROOT, 'src');
39
+ const SEP = path.sep;
40
+
41
+ /** 声明「可下行到任意单元」的记号,只给顶层组合面与测试面用 */
42
+ const ANY = '*';
43
+
44
+ /**
45
+ * 每个顶层单元允许**值导入**的其他单元(目录名 / src 根文件名)。
46
+ *
47
+ * 口径:
48
+ * - 只管跨目录的**值** import:type-only 一律放行(与 eslint 侧 allowTypeImports 同口径),
49
+ * 同目录内的 import 也不管——本闸钉的是方向,不是模块粒度;
50
+ * - 集合 = 该单元的分层位置允许的下行面 + **现状冻结**的同层边(逐条注理由)。
51
+ * 新增一条跨目录边必须先在这里登记,diff 即评审材料;集合只多不减,
52
+ * 还清一条债就把对应条目删掉,留着即虚账(登记闸只管活账)。
53
+ */
54
+ const DOWNSTREAM: Record<string, string[]> = {
55
+ // ── 叶子层 ──
56
+ types: [], // 谁都能 import 它,它谁都不 import:回边即分层违例(#88 前无闸可跑)
57
+ utils: ['types'],
58
+ presets: ['types'], // 纯数据(CLAUDE.md),零内部依赖
59
+
60
+ // ── core:数据/能力由调用方注入(harness#88)──
61
+ // presets 属数据面,project-config-loader 合并 preset 不算上行
62
+ core: ['presets', 'types', 'utils'],
63
+
64
+ // ── 领域层:理想下行面 = core 以下;同层边逐条记名 ──
65
+ agents: ['types', 'utils'],
66
+ 'completion-checkers': ['types', 'utils'], // 纯判定函数库,commits 由调用方供给
67
+ failure: ['types', 'utils'],
68
+ gates: ['core', 'types', 'utils'],
69
+ knowledge: ['types', 'utils'],
70
+ monitoring: ['types', 'utils'],
71
+ release: [], // 「无内部依赖(只依赖 node fs/path)」= release/CONTEXT.md 的自我声明落成闸
72
+ sdd: ['types', 'utils'],
73
+ tools: ['types', 'utils'],
74
+ // 同层互 import(现状冻结,不是许可):context 注入取知识、SessionManager 取 trace 采集器。
75
+ // 收口方向同 harness#88 对 core 的裁决——改注入,另票评估
76
+ context: ['knowledge', 'monitoring', 'types', 'utils'],
77
+ // bootstrapHarness 是本包组合根(装配 checker / SessionManager / TraceCollector),
78
+ // monitoring 对它是下行而非债
79
+ hooks: ['context', 'core', 'monitoring', 'types', 'utils'],
80
+
81
+ // ── 测试夹具:被各目录的测试依赖,故排在它们之下 ──
82
+ 'test-setup': ['types', 'utils'],
83
+
84
+ // ── 顶层组合面 / 测试面:可下行到任何单元 ──
85
+ cli: [ANY], // CLI 是唯一的上层,per-command 懒加载各命令实现
86
+ 'index.ts': [ANY], // 包根 barrel(ADR-0003 显式清单)
87
+ 'pretool-use-hook.ts': ['gates', 'types', 'utils'], // 钩子入口:PreToolUse 决策取 CommandGate
88
+ __tests__: [ANY], // 根测试面:跨目录取生产码是本职
89
+ };
90
+
91
+ /**
92
+ * 测试文件(目录段含 `__tests__`)在 `DOWNSTREAM` 之外额外放行的边。
93
+ *
94
+ * 单列而不并进目录集合,是因为并进去等于宣布生产面也有这条边:
95
+ * - `'*'`:任何目录的测试都能用 test-setup 夹具;
96
+ * - core 的测试回读包根 barrel,钉「公共面确实经 `src/index.ts` 导出」这条链
97
+ * (`agent-prompt-renderer` / `check-cache` 两处,ADR-0022 手法);
98
+ * - failure 的 recorder 测试顺带覆盖 CLI `failure list/stats`。
99
+ */
100
+ const TEST_ONLY_EDGES: Record<string, string[]> = {
101
+ '*': ['test-setup'],
102
+ core: ['index.ts'],
103
+ failure: ['cli'],
104
+ };
37
105
 
38
106
  /** import / export-from / require / 动态 import 的源串 + 子句 */
39
107
  const MODULE_SOURCE_REGEX =
@@ -62,22 +130,68 @@ function isTypeOnlyClause(clause: string): boolean {
62
130
  return /^\s*type(\s|\{|$)/.test(clause);
63
131
  }
64
132
 
65
- /** 收集一个文件里所有指向上层的值导入源串 */
66
- function upwardValueImports(file: string): string[] {
67
- const text = stripComments(fs.readFileSync(file, 'utf-8'));
68
- const hits: string[] = [];
133
+ /** src 相对路径 → 顶层单元名(目录名,或 src 根文件名) */
134
+ function unitOf(relFromSrc: string): string {
135
+ const sep = relFromSrc.indexOf(SEP);
136
+ return sep === -1 ? relFromSrc : relFromSrc.slice(0, sep);
137
+ }
138
+
139
+ /** 一个 import 源串指向的单元;非相对路径(node/包名)与 src 之外返回 null */
140
+ function unitOfImport(fromFile: string, source: string): string | null {
141
+ if (!source.startsWith('.')) return null;
142
+ const resolved = path.resolve(path.dirname(fromFile), source);
143
+ const relToSrc = path.relative(SRC_DIR, resolved);
144
+ if (!relToSrc || relToSrc.startsWith('..')) return null;
145
+ const unit = unitOf(relToSrc);
146
+ // src 根文件的 import 不带扩展名(`'../index'` → src/index.ts):单元名按磁盘真名补回扩展,
147
+ // 否则根文件单元在 import 侧叫 index、在登记侧叫 index.ts,两边对不上
148
+ if (unit === relToSrc && fs.existsSync(path.join(SRC_DIR, `${unit}.ts`))) return `${unit}.ts`;
149
+ return unit;
150
+ }
151
+
152
+ function isTestFile(relFromSrc: string): boolean {
153
+ return `${SEP}${relFromSrc}${SEP}`.includes(`${SEP}__tests__${SEP}`);
154
+ }
155
+
156
+ interface Violation {
157
+ unit: string;
158
+ file: string;
159
+ target: string;
160
+ source: string;
161
+ }
162
+
163
+ /** 一个单元的允许集合(含测试放行与自身) */
164
+ function allowedTargetsFor(relFromSrc: string): Set<string> {
165
+ const unit = unitOf(relFromSrc);
166
+ const allowed = new Set(DOWNSTREAM[unit] ?? []);
167
+ if (isTestFile(relFromSrc)) {
168
+ for (const extra of TEST_ONLY_EDGES['*'] ?? []) allowed.add(extra);
169
+ for (const extra of TEST_ONLY_EDGES[unit] ?? []) allowed.add(extra);
170
+ }
171
+ allowed.add(unit);
172
+ return allowed;
173
+ }
174
+
175
+ /**
176
+ * 扫一段代码里越界的跨目录值 import(纯函数:代码不来自磁盘,真扫描与反证共用一把尺)
177
+ *
178
+ * `relPath` 用于算自身单元,并出现在报错形状里(指名到文件与边)。
179
+ */
180
+ function scanViolations(relPath: string, code: string): Violation[] {
181
+ const unit = unitOf(relPath);
182
+ const allowed = allowedTargetsFor(relPath);
183
+ const absFile = path.join(SRC_DIR, relPath);
184
+
185
+ const hits: Violation[] = [];
69
186
  MODULE_SOURCE_REGEX.lastIndex = 0;
70
187
  let match: RegExpExecArray | null;
71
- while ((match = MODULE_SOURCE_REGEX.exec(text)) !== null) {
188
+ while ((match = MODULE_SOURCE_REGEX.exec(code)) !== null) {
72
189
  const clause = match[1] ?? '';
73
190
  const source = match[2] ?? match[3];
74
191
  if (match[1] && isTypeOnlyClause(clause)) continue;
75
- if (!source.startsWith('.')) continue;
76
- const resolved = path.resolve(path.dirname(file), source);
77
- const relToSrc = path.relative(path.join(REPO_ROOT, 'src'), resolved);
78
- if (UPPER_LAYERS.some(layer => relToSrc === layer || relToSrc.startsWith(layer + path.sep))) {
79
- hits.push(source);
80
- }
192
+ const target = unitOfImport(absFile, source);
193
+ if (target === null || allowed.has(ANY) || allowed.has(target)) continue;
194
+ hits.push({ unit, file: relPath, target, source });
81
195
  }
82
196
  return hits;
83
197
  }
@@ -93,17 +207,95 @@ function probeCore(code: string, filePath = 'src/core/constraints/__layering_pro
93
207
  return messages.filter(m => m.ruleId === '@typescript-eslint/no-restricted-imports');
94
208
  }
95
209
 
96
- describe('core 单向分层(harness#88)', () => {
97
- describe('真扫描:core/** 零上行值导入', () => {
98
- it('src/core 下每个文件对 cli/gates/monitoring 都没有值导入', () => {
99
- const offenders = listTsFiles(CORE_DIR)
100
- .map(file => ({ file: path.relative(REPO_ROOT, file), hits: upwardValueImports(file) }))
101
- .filter(entry => entry.hits.length > 0);
210
+ /** src 下现存的顶层单元(目录 + 根 .ts 文件),供登记闸对撞 */
211
+ function currentUnits(): string[] {
212
+ const units: string[] = [];
213
+ for (const entry of fs.readdirSync(SRC_DIR, { withFileTypes: true })) {
214
+ if (entry.isDirectory()) units.push(entry.name);
215
+ else if (entry.isFile() && entry.name.endsWith('.ts') && !entry.name.endsWith('.d.ts')) {
216
+ units.push(entry.name);
217
+ }
218
+ }
219
+ return units;
220
+ }
221
+
222
+ describe('逐目录单向分层(harness#88 / #137)', () => {
223
+ describe('登记闸:每个顶层单元都声明了下行集合', () => {
224
+ it('src 下没有未登记的单元(新增目录先登记,不得绕过本闸)', () => {
225
+ const unregistered = currentUnits().filter(unit => !(unit in DOWNSTREAM));
226
+ expect(unregistered).toEqual([]);
227
+ });
228
+
229
+ it('登记的单元在 src 下真实存在(目录改名或删除后不留死账)', () => {
230
+ const alive = new Set(currentUnits());
231
+ const dead = Object.keys(DOWNSTREAM).filter(unit => !alive.has(unit));
232
+ expect(dead).toEqual([]);
233
+ });
234
+ });
102
235
 
236
+ describe('真扫描:每个文件的值 import 都落在声明过的下行集合内', () => {
237
+ it.each(Object.keys(DOWNSTREAM))('%s 零越界值 import', unit => {
238
+ const root = path.join(SRC_DIR, unit); // 目录或 src 根文件
239
+ const files = fs.statSync(root).isDirectory() ? listTsFiles(root) : [root];
240
+ const offenders = files
241
+ .map(file =>
242
+ scanViolations(path.relative(SRC_DIR, file), stripComments(fs.readFileSync(file, 'utf-8')))
243
+ )
244
+ .filter(hits => hits.length > 0);
103
245
  expect(offenders).toEqual([]);
104
246
  });
105
247
  });
106
248
 
249
+ describe('反证:越界方向真被报出并指名到目录与边', () => {
250
+ it.each([
251
+ // [注入位置(src 相对), 值 import 源串, 目录, 被禁目标]
252
+ ['types/probe.ts', '../cli/commands/definitions', 'types', 'cli'],
253
+ ['types/probe.ts', '../core/project-config-loader', 'types', 'core'],
254
+ ['types/probe.ts', '../utils/jsonl', 'types', 'utils'],
255
+ ['utils/probe.ts', '../core/constraints/checker', 'utils', 'core'],
256
+ ['core/constraints/probe.ts', '../../monitoring/traces', 'core', 'monitoring'],
257
+ ['core/constraints/probe.ts', '../../knowledge/store', 'core', 'knowledge'],
258
+ ['core/constraints/probe.ts', '../../cli/commands/definitions', 'core', 'cli'],
259
+ ['knowledge/probe.ts', '../context/session-manager', 'knowledge', 'context'],
260
+ ['monitoring/probe.ts', '../gates/registry', 'monitoring', 'gates'],
261
+ ['presets/probe.ts', '../core/constraints/definitions', 'presets', 'core'],
262
+ ['release/probe.ts', '../core/effective-constraints', 'release', 'core'],
263
+ ])('%s 值导入 %s 报违例(%s ↛ %s)', (rel, source, unit, target) => {
264
+ const code = `import { something } from '${source}';\nexport const use = something;\n`;
265
+ expect(scanViolations(rel, code)).toEqual([{ unit, file: rel, target, source }]);
266
+ });
267
+
268
+ it('报错形状带得出是哪条边(源串与文件都在内,不需人再 grep)', () => {
269
+ // 行首动态 import(正则的另一支;行中 require 从来不在 MODULE_SOURCE_REGEX 覆盖面内)
270
+ const [violation] = scanViolations(
271
+ 'types/probe.ts',
272
+ `import('../cli/commands/check').then(m => m.check);\n`
273
+ );
274
+ expect(violation).toMatchObject({ unit: 'types', target: 'cli', source: '../cli/commands/check' });
275
+ });
276
+
277
+ it.each([
278
+ ['core/constraints/probe.ts', `import type { GateDefinition } from '../../gates/definitions';`],
279
+ ['types/probe.ts', `import type { RunEnv } from '../core/constraints/run-env';`],
280
+ ['knowledge/probe.ts', `import { DEFAULT_DECAY_CONFIG } from './types';`],
281
+ ['context/probe.ts', `import { KnowledgeQuery } from '../knowledge/query';`],
282
+ ['hooks/probe.ts', `import { getTraceCollector } from '../monitoring/traces';`],
283
+ ['core/probe.ts', `import { PRESETS_BY_NAME } from '../presets';`],
284
+ ['failure/__tests__/probe.test.ts', `import { failureList } from '../../cli/commands/failure';`],
285
+ ['core/constraints/__tests__/probe.test.ts', `import { checkConstraints } from '../../index';`],
286
+ ['gates/__tests__/probe.test.ts', `import { createProjectFixture } from '../../test-setup/project-fixture';`],
287
+ ['monitoring/probe.ts', `import * as fs from 'fs';`],
288
+ ['monitoring/probe.ts', `const hint = 'src/gates/registry.ts';\nexport const h = hint;`],
289
+ ])('合法边与噪声不误报:%s', (rel, statement) => {
290
+ expect(scanViolations(rel, `${statement}\n`)).toEqual([]);
291
+ });
292
+
293
+ it('文档注释里的示例 import 不算依赖', () => {
294
+ const code = `/** 用法:import { check } from '../../cli/commands/check'; */\nexport const x = 1;\n`;
295
+ expect(scanViolations('core/constraints/probe.ts', code)).toEqual([]);
296
+ });
297
+ });
298
+
107
299
  describe('真规则:eslint 上行值导入报 error', () => {
108
300
  it.each([
109
301
  ['monitoring', '../../monitoring/traces'],
@@ -6,15 +6,16 @@ import { describe, it, expect, beforeAll, afterAll } from '@jest/globals';
6
6
  import { PassesGate, createPassesGate, detectTestCommand } from '../core/validators/passes-gate';
7
7
  import type { TaskTestResult } from '../types/passes-gate';
8
8
  import { createProjectFixture } from '../test-setup/project-fixture';
9
- import { mkdirSync, rmSync, writeFileSync } from 'fs';
9
+ import { mkdirSync, rmSync, writeFileSync, mkdtempSync } from 'fs';
10
10
  import { join } from 'path';
11
+ import { tmpdir } from 'os';
11
12
 
12
13
  describe('PassesGate', () => {
13
- const tempDir = join(process.cwd(), 'temp-test-passes-gate');
14
+ let tempDir: string;
14
15
  let gate: PassesGate;
15
16
 
16
17
  beforeAll(() => {
17
- mkdirSync(tempDir, { recursive: true });
18
+ tempDir = mkdtempSync(join(tmpdir(), 'temp-test-passes-gate-'));
18
19
 
19
20
  // 创建简单的 package.json
20
21
  writeFileSync(join(tempDir, 'package.json'), JSON.stringify({
@@ -47,13 +48,17 @@ describe('PassesGate', () => {
47
48
  // 探测正本行为钉住(架构评审 A2:CLI/core 双版收口后的统一语义,
48
49
  // 此前 e2e 优先级、echo 排除、兜底均无测试钉住)
49
50
  describe('detectTestCommand 正本(统一探测顺序)', () => {
50
- const detectDir = join(process.cwd(), 'temp-test-detect-command');
51
+ let detectDir: string;
51
52
 
52
53
  const writePkg = (dir: string, scripts: Record<string, string>) => {
53
54
  mkdirSync(dir, { recursive: true });
54
55
  writeFileSync(join(dir, 'package.json'), JSON.stringify({ name: 'detect-case', scripts }));
55
56
  };
56
57
 
58
+ beforeAll(() => {
59
+ detectDir = mkdtempSync(join(tmpdir(), 'temp-test-detect-command-'));
60
+ });
61
+
57
62
  afterAll(() => {
58
63
  try {
59
64
  rmSync(detectDir, { recursive: true, force: true });
@@ -6,12 +6,13 @@ import { describe, it, expect, beforeAll, afterAll } from '@jest/globals';
6
6
  import { PerformanceGate } from '../gates/performance';
7
7
  import * as fs from 'fs';
8
8
  import * as path from 'path';
9
+ import * as os from 'os';
9
10
 
10
11
  describe('PerformanceGate', () => {
11
- const tempDir = path.join(process.cwd(), 'temp-test-perf-gate');
12
+ let tempDir: string;
12
13
 
13
14
  beforeAll(() => {
14
- fs.mkdirSync(tempDir, { recursive: true });
15
+ tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'temp-test-perf-gate-'));
15
16
  });
16
17
 
17
18
  afterAll(() => {
@@ -23,27 +24,14 @@ describe('PerformanceGate', () => {
23
24
  });
24
25
 
25
26
  describe('check', () => {
26
- it('禁用时应该返回通过', async () => {
27
- const gate = new PerformanceGate({ enabled: false });
28
-
29
- const result = await gate.check({
30
- projectId: 'test',
31
- projectPath: tempDir,
32
- });
33
-
34
- expect(result.passed).toBe(true);
35
- });
36
-
37
27
  it('应该返回检查结果', async () => {
38
28
  const gate = new PerformanceGate({
39
- enabled: true,
40
29
  thresholds: {
41
30
  maxBundleSize: 1000,
42
31
  },
43
32
  });
44
33
 
45
34
  const result = await gate.check({
46
- projectId: 'test',
47
35
  projectPath: tempDir,
48
36
  });
49
37
 
@@ -3,15 +3,18 @@
3
3
  */
4
4
 
5
5
  import { describe, it, expect, beforeAll, afterAll, jest } from '@jest/globals';
6
- import { ProjectConfigLoader } from '../core/project-config-loader';
6
+ import { ProjectConfigLoader, isConstraintRetired } from '../core/project-config-loader';
7
7
  import * as fs from 'fs';
8
8
  import * as path from 'path';
9
+ import * as os from 'os';
9
10
 
10
11
  describe('ProjectConfigLoader - 补充覆盖', () => {
11
- const tempDir = path.join(process.cwd(), 'temp-test-config-extra');
12
- const harnessDir = path.join(tempDir, '.harness');
12
+ let tempDir: string;
13
+ let harnessDir: string;
13
14
 
14
15
  beforeAll(() => {
16
+ tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'temp-test-config-extra-'));
17
+ harnessDir = path.join(tempDir, '.harness');
15
18
  fs.mkdirSync(harnessDir, { recursive: true });
16
19
  });
17
20
 
@@ -123,71 +126,42 @@ custom_constraints:
123
126
  });
124
127
  });
125
128
 
126
- describe('isConstraintEnabled', () => {
127
- it('启用的约束应该返回 true', () => {
129
+ describe('零消费者收缩(harness#137)', () => {
130
+ /**
131
+ * `isConstraintEnabled` / `getConstraintSource` 属 ADR-0022 型漏收:
132
+ * 除本文件与自身测试外双仓零消费者,生效集判定唯一来源是
133
+ * `mergeConstraints` → `getEffectiveConstraints`(ADR-0001),这两个查询函数是它的平行复印。
134
+ */
135
+ it('isConstraintEnabled / getConstraintSource 已从类面删除', () => {
128
136
  const loader = new ProjectConfigLoader(tempDir);
129
137
  loader.load();
130
138
 
131
- expect(loader.isConstraintEnabled('no_bypass_checkpoint')).toBe(true);
132
- });
133
-
134
- it('禁用的约束应该返回 false', () => {
135
- fs.writeFileSync(
136
- path.join(harnessDir, 'config.yml'),
137
- `
138
- constraints:
139
- test_disabled:
140
- enabled: false
141
- `
142
- );
143
-
144
- const loader = new ProjectConfigLoader(tempDir);
145
- loader.load();
146
-
147
- expect(loader.isConstraintEnabled('test_disabled')).toBe(false);
139
+ // @ts-expect-error isConstraintEnabled 零消费者,随 harness#137 删除
140
+ expect(loader.isConstraintEnabled).toBeUndefined();
141
+ // @ts-expect-error getConstraintSource 零消费者,随 harness#137 删除
142
+ expect(loader.getConstraintSource).toBeUndefined();
143
+ expect(ProjectConfigLoader.prototype).not.toHaveProperty('isConstraintEnabled');
144
+ expect(ProjectConfigLoader.prototype).not.toHaveProperty('getConstraintSource');
148
145
  });
149
146
  });
150
147
 
151
- describe('getConstraintSource', () => {
152
- it('内置约束应该返回 built-in', () => {
153
- const loader = new ProjectConfigLoader(tempDir);
154
- loader.load();
155
-
156
- expect(loader.getConstraintSource('no_bypass_checkpoint')).toBe('built-in');
148
+ describe('isConstraintRetired(退役判定单点,harness#137)', () => {
149
+ it('config.yml enabled:false 即已退役,与 custom 条目无关', () => {
150
+ expect(isConstraintRetired(undefined, true)).toBe(true);
157
151
  });
158
152
 
159
- it('自定义约束应该返回 custom', () => {
160
- fs.writeFileSync(
161
- path.join(harnessDir, 'config.yml'),
162
- `
163
- custom_constraints:
164
- custom_source_test:
165
- rule: CUSTOM
166
- message: Custom
167
- trigger: commit
168
- `
169
- );
170
-
171
- const loader = new ProjectConfigLoader(tempDir);
172
- loader.load();
173
-
174
- expect(loader.getConstraintSource('custom_source_test')).toBe('custom');
153
+ it('custom 条目带 retired 元数据即已退役(studio#82 D6 落点在条目自身)', () => {
154
+ expect(isConstraintRetired({ retired: { at: '2026-08-08T12:00:00.000Z' } }, false)).toBe(true);
175
155
  });
176
156
 
177
- it('禁用约束应该返回 disabled', () => {
178
- fs.writeFileSync(
179
- path.join(harnessDir, 'config.yml'),
180
- `
181
- constraints:
182
- source_disabled:
183
- enabled: false
184
- `
185
- );
186
-
187
- const loader = new ProjectConfigLoader(tempDir);
188
- loader.load();
157
+ it('两个落点都没命中 → 未退役', () => {
158
+ expect(isConstraintRetired(undefined, false)).toBe(false);
159
+ expect(isConstraintRetired({ retired: undefined }, false)).toBe(false);
160
+ });
189
161
 
190
- expect(loader.getConstraintSource('source_disabled')).toBe('disabled');
162
+ it('retired 段的假值(null / 空串)不算退役——mergeConstraints 用的是 truthiness', () => {
163
+ expect(isConstraintRetired({ retired: null }, false)).toBe(false);
164
+ expect(isConstraintRetired({ retired: '' }, false)).toBe(false);
191
165
  });
192
166
  });
193
167
 
@@ -6,12 +6,15 @@ import { describe, it, expect, beforeAll, afterAll } from '@jest/globals';
6
6
  import { ProjectConfigLoader, getCapabilitiesMode } from '../core/project-config-loader';
7
7
  import * as fs from 'fs';
8
8
  import * as path from 'path';
9
+ import * as os from 'os';
9
10
 
10
11
  describe('ProjectConfigLoader', () => {
11
- const tempDir = path.join(process.cwd(), 'temp-test-config');
12
- const harnessDir = path.join(tempDir, '.harness');
12
+ let tempDir: string;
13
+ let harnessDir: string;
13
14
 
14
15
  beforeAll(() => {
16
+ tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'temp-test-config-'));
17
+ harnessDir = path.join(tempDir, '.harness');
15
18
  fs.mkdirSync(harnessDir, { recursive: true });
16
19
  });
17
20
 
@@ -125,7 +128,7 @@ custom_rules:
125
128
  });
126
129
 
127
130
  describe('getCapabilitiesMode', () => {
128
- /** 建一个带独立 .harness/config.yml 的临时项目目录(避免进程级缓存串扰) */
131
+ /** 建一个带独立 .harness/config.yml 的临时项目目录(各用例独占自己的配置内容) */
129
132
  const setupConfigDir = (name: string, configYaml: string): string => {
130
133
  const dir = path.join(tempDir, name);
131
134
  fs.mkdirSync(path.join(dir, '.harness'), { recursive: true });
@@ -5,9 +5,13 @@
5
5
  * 改动 src/index.ts 导出清单时同步更新本文件的 EXPECTED_RUNTIME_EXPORTS,
6
6
  * diff 即 PR 评审材料。
7
7
  *
8
- * 两个面两道闸:运行时(值)导出由 Object.keys 逐字冻结;纯类型导出在运行时不可见,
9
- * 由下方「包根类型面」闸把关——编译期 `@ts-expect-error` 钉已删类型 + 源形状钉整条 barrel 链。
10
- * 类型面曾有此空缺时 `PassesGateResult` 漏删未被抓到(review A2),钉子据此补上。
8
+ * 类型面共三道闸,本文件占前两道:① 运行时(值)导出由 Object.keys 逐字冻结;② 下方「包根
9
+ * 类型面」闸钉的是**删完之后**——编译期 `@ts-expect-error` 钉已删类型 + 源形状钉整条 barrel
10
+ * (`PassesGateResult` 曾从 #125「关联类型导出随迁」漏删且无测试可捕获,review A2 据此补钉)。
11
+ * 第 ③ 道是类型面**全量清单**冻结,在 `public-type-surface.test.ts`(ADR-0022 追记 4);它刻意
12
+ * 不 import 包根,因为本文件的编译期钉在类型面被改动时会让整套 suite「failed to run」(实测注入
13
+ * 一条 `export type { DynamicTask }` 得 0 tests),拿不到可执行的清单 diff——定级阶段那句
14
+ * 「这个符号在不在包根导出面」由第 ③ 道回答,不由人的 grep 记忆回答。
11
15
  */
12
16
 
13
17
  import * as fs from 'fs';
@@ -96,7 +100,6 @@ const EXPECTED_RUNTIME_EXPORTS = [
96
100
  'getConstraint',
97
101
  'getCriticalArtifacts',
98
102
  'getEffectiveConstraints',
99
- 'getEffectiveGates',
100
103
  'getFailureLevel',
101
104
  'getGate',
102
105
  'getRegistryPath',
@@ -137,6 +140,10 @@ describe('公共导出清单(ADR-0003)', () => {
137
140
  * `PassesGateResult`(已删 `setPasses` 的返回形状)正是这样从 #125 的「关联类型导出随迁」
138
141
  * 里漏掉、经四级 barrel 存活为公开类型。手法同 #125 的 AC-007:编译期 `@ts-expect-error`
139
142
  * 钉住删除 + 源形状钉住整条链,活类型正钉防删多。
143
+ *
144
+ * `DynamicTask` 是同案的第二个漏收项(二次复审 B1):它是 `setPasses(taskId, workDir, task?)`
145
+ * 的入参形状,#125 删掉 setPasses 后只剩私有 `runTest` 那个从不读取的 `_task` 形参在供养它,
146
+ * 而包根同名导出取自 `./types/passes-gate`(见 5959b79),所以它是**公开的**死类型。
140
147
  */
141
148
  describe('包根类型面(ADR-0022 关联类型随迁)', () => {
142
149
  const BARREL_CHAIN = [
@@ -146,14 +153,22 @@ describe('包根类型面(ADR-0022 关联类型随迁)', () => {
146
153
  '../index.ts',
147
154
  ];
148
155
 
149
- it('PassesGateResult 在整条 barrel 链四级都已消失', () => {
156
+ function expectAbsentAcrossBarrelChain(typeName: string): void {
150
157
  for (const rel of BARREL_CHAIN) {
151
158
  const source = fs.readFileSync(path.join(__dirname, rel), 'utf-8');
152
- expect({ file: rel, mentions: /PassesGateResult/.test(source) }).toEqual({
159
+ expect({ file: rel, mentions: source.includes(typeName) }).toEqual({
153
160
  file: rel,
154
161
  mentions: false,
155
162
  });
156
163
  }
164
+ }
165
+
166
+ it('PassesGateResult 在整条 barrel 链四级都已消失', () => {
167
+ expectAbsentAcrossBarrelChain('PassesGateResult');
168
+ });
169
+
170
+ it('DynamicTask 在整条 barrel 链四级都已消失', () => {
171
+ expectAbsentAcrossBarrelChain('DynamicTask');
157
172
  });
158
173
 
159
174
  it('PassesGateResult 不再是包根可导入类型(编译期钉)', () => {
@@ -162,6 +177,12 @@ describe('包根类型面(ADR-0022 关联类型随迁)', () => {
162
177
  expect(removedType).toBeUndefined();
163
178
  });
164
179
 
180
+ it('DynamicTask 不再是包根可导入类型(编译期钉)', () => {
181
+ // @ts-expect-error 该类型是已删 setPasses 的 task 入参形状,消费者净删后随 A2 同案收口
182
+ const removedType: import('../index').DynamicTask | undefined = undefined;
183
+ expect(removedType).toBeUndefined();
184
+ });
185
+
165
186
  it('活类型仍可经包根导入(防止删多)', () => {
166
187
  const liveCheck: import('../index').PassesGateCheckResult = { allowed: true };
167
188
  const liveTask: import('../index').TaskTestResult = { passed: true, command: 'npm test' };