@dommaker/harness 1.7.0 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (563) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/bin/harness.js +17 -1
  3. package/dist/agents/index.d.ts +6 -2
  4. package/dist/agents/index.d.ts.map +1 -1
  5. package/dist/agents/index.js +6 -16
  6. package/dist/agents/index.js.map +1 -1
  7. package/dist/cli/commands/__tests__/gate-decision.d.ts +18 -0
  8. package/dist/cli/commands/__tests__/gate-decision.d.ts.map +1 -0
  9. package/dist/cli/commands/__tests__/gate-decision.js +26 -0
  10. package/dist/cli/commands/__tests__/gate-decision.js.map +1 -0
  11. package/dist/cli/commands/acceptance.d.ts.map +1 -1
  12. package/dist/cli/commands/acceptance.js +17 -28
  13. package/dist/cli/commands/acceptance.js.map +1 -1
  14. package/dist/cli/commands/check.d.ts +19 -3
  15. package/dist/cli/commands/check.d.ts.map +1 -1
  16. package/dist/cli/commands/check.js +36 -22
  17. package/dist/cli/commands/check.js.map +1 -1
  18. package/dist/cli/commands/command.d.ts +0 -1
  19. package/dist/cli/commands/command.d.ts.map +1 -1
  20. package/dist/cli/commands/command.js +8 -6
  21. package/dist/cli/commands/command.js.map +1 -1
  22. package/dist/cli/commands/constraints-retire.d.ts.map +1 -1
  23. package/dist/cli/commands/constraints-retire.js +36 -57
  24. package/dist/cli/commands/constraints-retire.js.map +1 -1
  25. package/dist/cli/commands/contract.d.ts.map +1 -1
  26. package/dist/cli/commands/contract.js +36 -42
  27. package/dist/cli/commands/contract.js.map +1 -1
  28. package/dist/cli/commands/definitions.d.ts +2 -0
  29. package/dist/cli/commands/definitions.d.ts.map +1 -1
  30. package/dist/cli/commands/definitions.js +11 -6
  31. package/dist/cli/commands/definitions.js.map +1 -1
  32. package/dist/cli/commands/failure.d.ts.map +1 -1
  33. package/dist/cli/commands/failure.js +16 -2
  34. package/dist/cli/commands/failure.js.map +1 -1
  35. package/dist/cli/commands/init.d.ts +14 -8
  36. package/dist/cli/commands/init.d.ts.map +1 -1
  37. package/dist/cli/commands/init.js +172 -364
  38. package/dist/cli/commands/init.js.map +1 -1
  39. package/dist/cli/commands/knowledge-view.d.ts +90 -0
  40. package/dist/cli/commands/knowledge-view.d.ts.map +1 -0
  41. package/dist/cli/commands/knowledge-view.js +198 -0
  42. package/dist/cli/commands/knowledge-view.js.map +1 -0
  43. package/dist/cli/commands/knowledge.d.ts +137 -52
  44. package/dist/cli/commands/knowledge.d.ts.map +1 -1
  45. package/dist/cli/commands/knowledge.js +534 -400
  46. package/dist/cli/commands/knowledge.js.map +1 -1
  47. package/dist/cli/commands/passes-gate.d.ts +4 -1
  48. package/dist/cli/commands/passes-gate.d.ts.map +1 -1
  49. package/dist/cli/commands/passes-gate.js +11 -2
  50. package/dist/cli/commands/passes-gate.js.map +1 -1
  51. package/dist/cli/commands/performance.d.ts.map +1 -1
  52. package/dist/cli/commands/performance.js +19 -31
  53. package/dist/cli/commands/performance.js.map +1 -1
  54. package/dist/cli/commands/report.d.ts.map +1 -1
  55. package/dist/cli/commands/report.js +2 -1
  56. package/dist/cli/commands/report.js.map +1 -1
  57. package/dist/cli/commands/review.d.ts.map +1 -1
  58. package/dist/cli/commands/review.js +13 -25
  59. package/dist/cli/commands/review.js.map +1 -1
  60. package/dist/cli/commands/scaffold-templates.d.ts +73 -0
  61. package/dist/cli/commands/scaffold-templates.d.ts.map +1 -0
  62. package/dist/cli/commands/scaffold-templates.js +424 -0
  63. package/dist/cli/commands/scaffold-templates.js.map +1 -0
  64. package/dist/cli/commands/scaffold.d.ts +105 -0
  65. package/dist/cli/commands/scaffold.d.ts.map +1 -0
  66. package/dist/cli/commands/scaffold.js +263 -0
  67. package/dist/cli/commands/scaffold.js.map +1 -0
  68. package/dist/cli/commands/security.d.ts.map +1 -1
  69. package/dist/cli/commands/security.js +22 -24
  70. package/dist/cli/commands/security.js.map +1 -1
  71. package/dist/cli/commands/spec-baseline-check.d.ts +43 -0
  72. package/dist/cli/commands/spec-baseline-check.d.ts.map +1 -1
  73. package/dist/cli/commands/spec-baseline-check.js +109 -34
  74. package/dist/cli/commands/spec-baseline-check.js.map +1 -1
  75. package/dist/cli/commands/status.d.ts +8 -0
  76. package/dist/cli/commands/status.d.ts.map +1 -1
  77. package/dist/cli/commands/status.js +5 -7
  78. package/dist/cli/commands/status.js.map +1 -1
  79. package/dist/cli/commands/sync-docs/context-syncer.d.ts +21 -2
  80. package/dist/cli/commands/sync-docs/context-syncer.d.ts.map +1 -1
  81. package/dist/cli/commands/sync-docs/context-syncer.js +112 -28
  82. package/dist/cli/commands/sync-docs/context-syncer.js.map +1 -1
  83. package/dist/cli/commands/sync-docs/index.d.ts +1 -1
  84. package/dist/cli/commands/sync-docs/index.d.ts.map +1 -1
  85. package/dist/cli/commands/sync-docs/index.js +86 -27
  86. package/dist/cli/commands/sync-docs/index.js.map +1 -1
  87. package/dist/cli/commands/sync-docs/project-reader.d.ts +24 -1
  88. package/dist/cli/commands/sync-docs/project-reader.d.ts.map +1 -1
  89. package/dist/cli/commands/sync-docs/project-reader.js +33 -7
  90. package/dist/cli/commands/sync-docs/project-reader.js.map +1 -1
  91. package/dist/cli/commands/validate.d.ts +0 -16
  92. package/dist/cli/commands/validate.d.ts.map +1 -1
  93. package/dist/cli/commands/validate.js +2 -97
  94. package/dist/cli/commands/validate.js.map +1 -1
  95. package/dist/cli/gate-command.d.ts +37 -0
  96. package/dist/cli/gate-command.d.ts.map +1 -0
  97. package/dist/cli/gate-command.js +64 -0
  98. package/dist/cli/gate-command.js.map +1 -0
  99. package/dist/cli/state-io.d.ts +34 -0
  100. package/dist/cli/state-io.d.ts.map +1 -0
  101. package/dist/cli/state-io.js +71 -0
  102. package/dist/cli/state-io.js.map +1 -0
  103. package/dist/completion-checkers/index.d.ts +1 -1
  104. package/dist/completion-checkers/index.d.ts.map +1 -1
  105. package/dist/completion-checkers/index.js +0 -15
  106. package/dist/completion-checkers/index.js.map +1 -1
  107. package/dist/context/knowledge-injector.d.ts +4 -2
  108. package/dist/context/knowledge-injector.d.ts.map +1 -1
  109. package/dist/context/knowledge-injector.js +13 -6
  110. package/dist/context/knowledge-injector.js.map +1 -1
  111. package/dist/core/constraints/agent-prompt-renderer.js +2 -2
  112. package/dist/core/constraints/agent-prompt-renderer.js.map +1 -1
  113. package/dist/core/constraints/capabilities-reconcile.d.ts +20 -0
  114. package/dist/core/constraints/capabilities-reconcile.d.ts.map +1 -1
  115. package/dist/core/constraints/capabilities-reconcile.js +26 -4
  116. package/dist/core/constraints/capabilities-reconcile.js.map +1 -1
  117. package/dist/core/constraints/check-cache.d.ts +1 -1
  118. package/dist/core/constraints/check-cache.js +1 -1
  119. package/dist/core/constraints/checker.d.ts +8 -3
  120. package/dist/core/constraints/checker.d.ts.map +1 -1
  121. package/dist/core/constraints/checker.js +30 -19
  122. package/dist/core/constraints/checker.js.map +1 -1
  123. package/dist/core/constraints/checkers/capability-sync.d.ts +3 -1
  124. package/dist/core/constraints/checkers/capability-sync.d.ts.map +1 -1
  125. package/dist/core/constraints/checkers/capability-sync.js +17 -24
  126. package/dist/core/constraints/checkers/capability-sync.js.map +1 -1
  127. package/dist/core/constraints/checkers/context-doc-sync.d.ts +1 -1
  128. package/dist/core/constraints/checkers/context-doc-sync.d.ts.map +1 -1
  129. package/dist/core/constraints/checkers/context-doc-sync.js +9 -6
  130. package/dist/core/constraints/checkers/context-doc-sync.js.map +1 -1
  131. package/dist/core/constraints/checkers/docs-freshness.d.ts.map +1 -1
  132. package/dist/core/constraints/checkers/docs-freshness.js +24 -30
  133. package/dist/core/constraints/checkers/docs-freshness.js.map +1 -1
  134. package/dist/core/constraints/checkers/governance-presence.d.ts.map +1 -1
  135. package/dist/core/constraints/checkers/governance-presence.js +10 -4
  136. package/dist/core/constraints/checkers/governance-presence.js.map +1 -1
  137. package/dist/core/constraints/checkers/types.d.ts +10 -6
  138. package/dist/core/constraints/checkers/types.d.ts.map +1 -1
  139. package/dist/core/constraints/checkers/types.js +7 -3
  140. package/dist/core/constraints/checkers/types.js.map +1 -1
  141. package/dist/core/constraints/context-builder.d.ts +11 -10
  142. package/dist/core/constraints/context-builder.d.ts.map +1 -1
  143. package/dist/core/constraints/context-builder.js +31 -27
  144. package/dist/core/constraints/context-builder.js.map +1 -1
  145. package/dist/core/constraints/context-reconcile.d.ts +75 -0
  146. package/dist/core/constraints/context-reconcile.d.ts.map +1 -0
  147. package/dist/core/constraints/context-reconcile.js +161 -0
  148. package/dist/core/constraints/context-reconcile.js.map +1 -0
  149. package/dist/core/constraints/doc-freshness/runner.d.ts +7 -0
  150. package/dist/core/constraints/doc-freshness/runner.d.ts.map +1 -1
  151. package/dist/core/constraints/doc-freshness/runner.js +8 -3
  152. package/dist/core/constraints/doc-freshness/runner.js.map +1 -1
  153. package/dist/core/constraints/git-evidence.js +1 -1
  154. package/dist/core/constraints/git-evidence.js.map +1 -1
  155. package/dist/core/constraints/injection-drift.d.ts +7 -2
  156. package/dist/core/constraints/injection-drift.d.ts.map +1 -1
  157. package/dist/core/constraints/injection-drift.js +13 -7
  158. package/dist/core/constraints/injection-drift.js.map +1 -1
  159. package/dist/core/constraints/run-env.d.ts +92 -0
  160. package/dist/core/constraints/run-env.d.ts.map +1 -0
  161. package/dist/core/constraints/run-env.js +175 -0
  162. package/dist/core/constraints/run-env.js.map +1 -0
  163. package/dist/core/constraints/triggers.d.ts +22 -0
  164. package/dist/core/constraints/triggers.d.ts.map +1 -0
  165. package/dist/core/constraints/triggers.js +31 -0
  166. package/dist/core/constraints/triggers.js.map +1 -0
  167. package/dist/core/effective-constraints.d.ts +13 -4
  168. package/dist/core/effective-constraints.d.ts.map +1 -1
  169. package/dist/core/effective-constraints.js +16 -6
  170. package/dist/core/effective-constraints.js.map +1 -1
  171. package/dist/core/effective-set.d.ts +8 -15
  172. package/dist/core/effective-set.d.ts.map +1 -1
  173. package/dist/core/effective-set.js +7 -12
  174. package/dist/core/effective-set.js.map +1 -1
  175. package/dist/core/index.d.ts +1 -0
  176. package/dist/core/index.d.ts.map +1 -1
  177. package/dist/core/index.js.map +1 -1
  178. package/dist/core/project-config-loader.d.ts +39 -17
  179. package/dist/core/project-config-loader.d.ts.map +1 -1
  180. package/dist/core/project-config-loader.js +51 -122
  181. package/dist/core/project-config-loader.js.map +1 -1
  182. package/dist/core/validators/check-handlers/http.d.ts +2 -2
  183. package/dist/core/validators/check-handlers/http.d.ts.map +1 -1
  184. package/dist/core/validators/check-handlers/http.js +12 -7
  185. package/dist/core/validators/check-handlers/http.js.map +1 -1
  186. package/dist/failure/classifier.d.ts +1 -1
  187. package/dist/failure/classifier.d.ts.map +1 -1
  188. package/dist/failure/classifier.js +8 -8
  189. package/dist/failure/classifier.js.map +1 -1
  190. package/dist/failure/index.d.ts +2 -1
  191. package/dist/failure/index.d.ts.map +1 -1
  192. package/dist/failure/index.js +9 -17
  193. package/dist/failure/index.js.map +1 -1
  194. package/dist/failure/recorder.d.ts +1 -1
  195. package/dist/failure/recorder.d.ts.map +1 -1
  196. package/dist/gates/checker-gate.d.ts +2 -1
  197. package/dist/gates/checker-gate.d.ts.map +1 -1
  198. package/dist/gates/checker-gate.js +3 -2
  199. package/dist/gates/checker-gate.js.map +1 -1
  200. package/dist/gates/command.d.ts +10 -4
  201. package/dist/gates/command.d.ts.map +1 -1
  202. package/dist/gates/command.js +36 -62
  203. package/dist/gates/command.js.map +1 -1
  204. package/dist/gates/contract.d.ts.map +1 -1
  205. package/dist/gates/contract.js +0 -4
  206. package/dist/gates/contract.js.map +1 -1
  207. package/dist/gates/definitions.d.ts +2 -1
  208. package/dist/gates/definitions.d.ts.map +1 -1
  209. package/dist/gates/definitions.js +6 -5
  210. package/dist/gates/definitions.js.map +1 -1
  211. package/dist/gates/index.d.ts +0 -4
  212. package/dist/gates/index.d.ts.map +1 -1
  213. package/dist/gates/index.js +1 -6
  214. package/dist/gates/index.js.map +1 -1
  215. package/dist/gates/performance.d.ts.map +1 -1
  216. package/dist/gates/performance.js +0 -4
  217. package/dist/gates/performance.js.map +1 -1
  218. package/dist/gates/runner.d.ts +1 -1
  219. package/dist/gates/runner.js +1 -1
  220. package/dist/gates/security.d.ts +1 -1
  221. package/dist/gates/security.d.ts.map +1 -1
  222. package/dist/gates/security.js +5 -6
  223. package/dist/gates/security.js.map +1 -1
  224. package/dist/gates/types.d.ts +14 -17
  225. package/dist/gates/types.d.ts.map +1 -1
  226. package/dist/gates/types.js.map +1 -1
  227. package/dist/hooks/bootstrap.d.ts +6 -4
  228. package/dist/hooks/bootstrap.d.ts.map +1 -1
  229. package/dist/hooks/bootstrap.js +25 -13
  230. package/dist/hooks/bootstrap.js.map +1 -1
  231. package/dist/hooks/config.d.ts +6 -2
  232. package/dist/hooks/config.d.ts.map +1 -1
  233. package/dist/hooks/config.js +5 -1
  234. package/dist/hooks/config.js.map +1 -1
  235. package/dist/hooks/index.d.ts +1 -1
  236. package/dist/hooks/index.d.ts.map +1 -1
  237. package/dist/hooks/index.js +0 -15
  238. package/dist/hooks/index.js.map +1 -1
  239. package/dist/hooks/pipeline.d.ts +19 -1
  240. package/dist/hooks/pipeline.d.ts.map +1 -1
  241. package/dist/hooks/pipeline.js +42 -4
  242. package/dist/hooks/pipeline.js.map +1 -1
  243. package/dist/hooks/registry.d.ts +11 -8
  244. package/dist/hooks/registry.d.ts.map +1 -1
  245. package/dist/hooks/registry.js +22 -7
  246. package/dist/hooks/registry.js.map +1 -1
  247. package/dist/hooks/types.d.ts +25 -7
  248. package/dist/hooks/types.d.ts.map +1 -1
  249. package/dist/index.d.ts +3 -3
  250. package/dist/index.d.ts.map +1 -1
  251. package/dist/index.js +3 -4
  252. package/dist/index.js.map +1 -1
  253. package/dist/knowledge/audit-scoring.d.ts +87 -0
  254. package/dist/knowledge/audit-scoring.d.ts.map +1 -0
  255. package/dist/knowledge/audit-scoring.js +470 -0
  256. package/dist/knowledge/audit-scoring.js.map +1 -0
  257. package/dist/knowledge/audit.d.ts +11 -59
  258. package/dist/knowledge/audit.d.ts.map +1 -1
  259. package/dist/knowledge/audit.js +47 -522
  260. package/dist/knowledge/audit.js.map +1 -1
  261. package/dist/knowledge/import.d.ts.map +1 -1
  262. package/dist/knowledge/import.js +2 -0
  263. package/dist/knowledge/import.js.map +1 -1
  264. package/dist/knowledge/index-generator.d.ts.map +1 -1
  265. package/dist/knowledge/index-generator.js +4 -5
  266. package/dist/knowledge/index-generator.js.map +1 -1
  267. package/dist/knowledge/index.d.ts +3 -2
  268. package/dist/knowledge/index.d.ts.map +1 -1
  269. package/dist/knowledge/index.js +3 -16
  270. package/dist/knowledge/index.js.map +1 -1
  271. package/dist/knowledge/ingest.js +1 -1
  272. package/dist/knowledge/ingest.js.map +1 -1
  273. package/dist/knowledge/lifecycle.d.ts.map +1 -1
  274. package/dist/knowledge/lifecycle.js +4 -2
  275. package/dist/knowledge/lifecycle.js.map +1 -1
  276. package/dist/knowledge/migration.d.ts +3 -0
  277. package/dist/knowledge/migration.d.ts.map +1 -1
  278. package/dist/knowledge/migration.js +8 -2
  279. package/dist/knowledge/migration.js.map +1 -1
  280. package/dist/knowledge/query.d.ts +6 -0
  281. package/dist/knowledge/query.d.ts.map +1 -1
  282. package/dist/knowledge/query.js +8 -2
  283. package/dist/knowledge/query.js.map +1 -1
  284. package/dist/knowledge/reference-tracker.d.ts.map +1 -1
  285. package/dist/knowledge/reference-tracker.js +4 -6
  286. package/dist/knowledge/reference-tracker.js.map +1 -1
  287. package/dist/knowledge/store.d.ts +22 -16
  288. package/dist/knowledge/store.d.ts.map +1 -1
  289. package/dist/knowledge/store.js +53 -12
  290. package/dist/knowledge/store.js.map +1 -1
  291. package/dist/knowledge/tree-walker.d.ts +19 -0
  292. package/dist/knowledge/tree-walker.d.ts.map +1 -0
  293. package/dist/knowledge/tree-walker.js +30 -0
  294. package/dist/knowledge/tree-walker.js.map +1 -0
  295. package/dist/knowledge/types.d.ts +16 -0
  296. package/dist/knowledge/types.d.ts.map +1 -1
  297. package/dist/monitoring/traces.d.ts +5 -3
  298. package/dist/monitoring/traces.d.ts.map +1 -1
  299. package/dist/monitoring/traces.js +19 -5
  300. package/dist/monitoring/traces.js.map +1 -1
  301. package/dist/test-setup/jsonl-fake-fs.d.ts +30 -0
  302. package/dist/test-setup/jsonl-fake-fs.d.ts.map +1 -0
  303. package/dist/test-setup/jsonl-fake-fs.js +49 -0
  304. package/dist/test-setup/jsonl-fake-fs.js.map +1 -0
  305. package/dist/tools/index.d.ts +4 -1
  306. package/dist/tools/index.d.ts.map +1 -1
  307. package/dist/tools/index.js +7 -15
  308. package/dist/tools/index.js.map +1 -1
  309. package/dist/types/checkpoint.d.ts +5 -0
  310. package/dist/types/checkpoint.d.ts.map +1 -1
  311. package/dist/types/project-config.d.ts +18 -0
  312. package/dist/types/project-config.d.ts.map +1 -1
  313. package/dist/types/trace.d.ts +13 -4
  314. package/dist/types/trace.d.ts.map +1 -1
  315. package/dist/types/trace.js +4 -3
  316. package/dist/types/trace.js.map +1 -1
  317. package/dist/utils/exec.d.ts +4 -27
  318. package/dist/utils/exec.d.ts.map +1 -1
  319. package/dist/utils/exec.js +4 -94
  320. package/dist/utils/exec.js.map +1 -1
  321. package/dist/utils/jsonl.d.ts +17 -7
  322. package/dist/utils/jsonl.d.ts.map +1 -1
  323. package/dist/utils/jsonl.js +144 -17
  324. package/dist/utils/jsonl.js.map +1 -1
  325. package/dist/utils/numeric-flag.d.ts +44 -0
  326. package/dist/utils/numeric-flag.d.ts.map +1 -0
  327. package/dist/utils/numeric-flag.js +62 -0
  328. package/dist/utils/numeric-flag.js.map +1 -0
  329. package/package.json +1 -1
  330. package/src/CONTEXT.md +5 -2
  331. package/src/__tests__/acceptance-gate.test.ts +7 -4
  332. package/src/__tests__/checker-extra.test.ts +3 -2
  333. package/src/__tests__/checker.test.ts +4 -3
  334. package/src/__tests__/checkpoint.test.ts +26 -9
  335. package/src/__tests__/context-files-resolution.test.ts +29 -15
  336. package/src/__tests__/contract-gate.test.ts +19 -40
  337. package/src/__tests__/error-classifier.test.ts +1 -1
  338. package/src/__tests__/exec.test.ts +45 -107
  339. package/src/__tests__/failure-recorder.test.ts +7 -5
  340. package/src/__tests__/hooks-pipeline.test.ts +34 -47
  341. package/src/__tests__/layering.test.ts +217 -25
  342. package/src/__tests__/passes-gate.test.ts +9 -4
  343. package/src/__tests__/performance-gate.test.ts +3 -15
  344. package/src/__tests__/project-config-loader-extra.test.ts +31 -57
  345. package/src/__tests__/project-config-loader.test.ts +6 -3
  346. package/src/__tests__/public-exports.test.ts +0 -1
  347. package/src/__tests__/public-type-surface.test.ts +5 -4
  348. package/src/__tests__/public-value-surface.test.ts +182 -0
  349. package/src/__tests__/review-gate.test.ts +4 -6
  350. package/src/__tests__/security-gate.test.ts +5 -20
  351. package/src/__tests__/skip-semantics.test.ts +5 -3
  352. package/src/__tests__/spec-validator.test.ts +3 -2
  353. package/src/__tests__/sub-barrels-explicit.test.ts +87 -0
  354. package/src/__tests__/test-fixture-hygiene.test.ts +53 -0
  355. package/src/__tests__/trace-analyzer-extra.test.ts +5 -3
  356. package/src/__tests__/trace-analyzer.test.ts +5 -3
  357. package/src/__tests__/trace-collector.test.ts +5 -3
  358. package/src/agents/index.ts +13 -2
  359. package/src/cli/__tests__/gate-command.test.ts +162 -0
  360. package/src/cli/__tests__/state-io.test.ts +50 -0
  361. package/src/cli/commands/CONTEXT.md +30 -5
  362. package/src/cli/commands/__tests__/acceptance.test.ts +24 -25
  363. package/src/cli/commands/__tests__/bin-exit-mapping.test.ts +15 -0
  364. package/src/cli/commands/__tests__/check-drift.test.ts +42 -1
  365. package/src/cli/commands/__tests__/check-read-count.test.ts +170 -0
  366. package/src/cli/commands/__tests__/check-skip-output.test.ts +4 -1
  367. package/src/cli/commands/__tests__/check.test.ts +63 -44
  368. package/src/cli/commands/__tests__/command-gate-dead-options.test.ts +60 -0
  369. package/src/cli/commands/__tests__/command.test.ts +33 -17
  370. package/src/cli/commands/__tests__/constraints-retire.test.ts +52 -0
  371. package/src/cli/commands/__tests__/context-syncer.test.ts +141 -0
  372. package/src/cli/commands/__tests__/contract.test.ts +20 -20
  373. package/src/cli/commands/__tests__/failure.test.ts +5 -4
  374. package/src/cli/commands/__tests__/gate-decision.ts +30 -0
  375. package/src/cli/commands/__tests__/init-dead-options.test.ts +50 -0
  376. package/src/cli/commands/__tests__/init-governance-io.test.ts +139 -0
  377. package/src/cli/commands/__tests__/init-injection.test.ts +3 -3
  378. package/src/cli/commands/__tests__/init-ondisk.test.ts +867 -0
  379. package/src/cli/commands/__tests__/init.test.ts +82 -6
  380. package/src/cli/commands/__tests__/knowledge-audit-threshold.test.ts +146 -0
  381. package/src/cli/commands/__tests__/knowledge-flywheel-consistency.test.ts +1 -1
  382. package/src/cli/commands/__tests__/knowledge-tone-mapping.test.ts +244 -0
  383. package/src/cli/commands/__tests__/knowledge-view.test.ts +839 -0
  384. package/src/cli/commands/__tests__/knowledge.test.ts +33 -15
  385. package/src/cli/commands/__tests__/numeric-flag-assembly.test.ts +368 -0
  386. package/src/cli/commands/__tests__/performance.test.ts +19 -21
  387. package/src/cli/commands/__tests__/posteval-plan.test.ts +5 -3
  388. package/src/cli/commands/__tests__/pre-push-hook.test.ts +181 -0
  389. package/src/cli/commands/__tests__/project-path-anchoring.test.ts +95 -2
  390. package/src/cli/commands/__tests__/project-path-convention.test.ts +103 -25
  391. package/src/cli/commands/__tests__/registry.test.ts +2 -0
  392. package/src/cli/commands/__tests__/report.test.ts +23 -1
  393. package/src/cli/commands/__tests__/review.test.ts +10 -17
  394. package/src/cli/commands/__tests__/scaffold.test.ts +505 -0
  395. package/src/cli/commands/__tests__/security-default-scan.test.ts +75 -0
  396. package/src/cli/commands/__tests__/security.test.ts +21 -24
  397. package/src/cli/commands/__tests__/spec-baseline-check.test.ts +3 -2
  398. package/src/cli/commands/__tests__/spec-baseline-index-cap.test.ts +131 -0
  399. package/src/cli/commands/__tests__/spec-baseline-read-count.test.ts +325 -0
  400. package/src/cli/commands/__tests__/status-extra.test.ts +25 -8
  401. package/src/cli/commands/__tests__/status.test.ts +46 -18
  402. package/src/cli/commands/__tests__/sync-docs-agents.test.ts +19 -4
  403. package/src/cli/commands/__tests__/sync-docs-context-drift.test.ts +232 -0
  404. package/src/cli/commands/__tests__/sync-docs-module-order.test.ts +111 -0
  405. package/src/cli/commands/__tests__/sync-docs-read-count.test.ts +192 -0
  406. package/src/cli/commands/__tests__/sync-docs.test.ts +3 -2
  407. package/src/cli/commands/__tests__/validate.test.ts +1 -48
  408. package/src/cli/commands/acceptance.ts +24 -29
  409. package/src/cli/commands/check.ts +60 -35
  410. package/src/cli/commands/command.ts +9 -8
  411. package/src/cli/commands/constraints-retire.ts +57 -70
  412. package/src/cli/commands/contract.ts +44 -47
  413. package/src/cli/commands/definitions.ts +12 -6
  414. package/src/cli/commands/failure.ts +16 -3
  415. package/src/cli/commands/init.ts +242 -389
  416. package/src/cli/commands/knowledge-view.ts +224 -0
  417. package/src/cli/commands/knowledge.ts +643 -448
  418. package/src/cli/commands/passes-gate.ts +12 -3
  419. package/src/cli/commands/performance.ts +31 -38
  420. package/src/cli/commands/report.ts +3 -2
  421. package/src/cli/commands/review.ts +22 -28
  422. package/src/cli/commands/scaffold-templates.ts +406 -0
  423. package/src/cli/commands/scaffold.ts +302 -0
  424. package/src/cli/commands/security.ts +27 -23
  425. package/src/cli/commands/spec-baseline-check.ts +158 -33
  426. package/src/cli/commands/status.ts +12 -7
  427. package/src/cli/commands/sync-docs/__tests__/context-export-surface.test.ts +102 -0
  428. package/src/cli/commands/sync-docs/__tests__/module-descriptions.test.ts +196 -0
  429. package/src/cli/commands/sync-docs/context-syncer.ts +137 -31
  430. package/src/cli/commands/sync-docs/index.ts +103 -28
  431. package/src/cli/commands/sync-docs/project-reader.ts +51 -7
  432. package/src/cli/commands/validate.ts +1 -104
  433. package/src/cli/gate-command.ts +87 -0
  434. package/src/cli/state-io.ts +53 -0
  435. package/src/completion-checkers/index.ts +10 -1
  436. package/src/context/CONTEXT.md +2 -1
  437. package/src/context/__tests__/knowledge-injector.test.ts +27 -0
  438. package/src/context/__tests__/session-manager.test.ts +19 -12
  439. package/src/context/knowledge-injector.ts +14 -7
  440. package/src/core/CONTEXT.md +10 -7
  441. package/src/core/__tests__/effective-set.test.ts +36 -60
  442. package/src/core/constraints/__tests__/context-reconcile.test.ts +246 -0
  443. package/src/core/constraints/__tests__/run-env.test.ts +377 -0
  444. package/src/core/constraints/__tests__/triggers.test.ts +70 -0
  445. package/src/core/constraints/agent-prompt-renderer.ts +1 -1
  446. package/src/core/constraints/capabilities-reconcile.ts +28 -4
  447. package/src/core/constraints/check-cache.ts +1 -1
  448. package/src/core/constraints/checker.ts +30 -14
  449. package/src/core/constraints/checkers/__tests__/context-doc-sync.test.ts +8 -3
  450. package/src/core/constraints/checkers/__tests__/governance-presence.test.ts +16 -7
  451. package/src/core/constraints/checkers/__tests__/no-hardcoded-credentials.test.ts +2 -1
  452. package/src/core/constraints/checkers/capability-sync.ts +27 -28
  453. package/src/core/constraints/checkers/context-doc-sync.ts +9 -7
  454. package/src/core/constraints/checkers/docs-freshness.ts +28 -33
  455. package/src/core/constraints/checkers/governance-presence.ts +10 -6
  456. package/src/core/constraints/checkers/types.ts +14 -8
  457. package/src/core/constraints/context-builder.ts +35 -26
  458. package/src/core/constraints/context-reconcile.ts +200 -0
  459. package/src/core/constraints/doc-freshness/__tests__/runner.test.ts +25 -0
  460. package/src/core/constraints/doc-freshness/runner.ts +18 -4
  461. package/src/core/constraints/git-evidence.ts +1 -1
  462. package/src/core/constraints/injection-drift.ts +19 -8
  463. package/src/core/constraints/run-env.ts +207 -0
  464. package/src/core/constraints/triggers.ts +33 -0
  465. package/src/core/effective-constraints.ts +17 -6
  466. package/src/core/effective-set.ts +8 -24
  467. package/src/core/index.ts +2 -0
  468. package/src/core/project-config-loader.ts +54 -102
  469. package/src/core/validators/__tests__/http-retry-sleep.test.ts +231 -0
  470. package/src/core/validators/check-handlers/http.ts +18 -7
  471. package/src/failure/CONTEXT.md +2 -1
  472. package/src/failure/classifier.ts +2 -2
  473. package/src/failure/index.ts +14 -2
  474. package/src/failure/recorder.ts +1 -1
  475. package/src/gates/CONTEXT.md +13 -7
  476. package/src/gates/__tests__/checker-gate.test.ts +1 -1
  477. package/src/gates/__tests__/command-single-predicate.test.ts +135 -0
  478. package/src/gates/__tests__/command.test.ts +8 -15
  479. package/src/gates/__tests__/contract.test.ts +5 -5
  480. package/src/gates/__tests__/gate-interface.test.ts +0 -17
  481. package/src/gates/__tests__/performance.test.ts +0 -13
  482. package/src/gates/__tests__/review.test.ts +0 -1
  483. package/src/gates/__tests__/runner.test.ts +1 -1
  484. package/src/gates/__tests__/security-default-scan.test.ts +97 -0
  485. package/src/gates/__tests__/security.test.ts +0 -13
  486. package/src/gates/checker-gate.ts +3 -2
  487. package/src/gates/command.ts +51 -74
  488. package/src/gates/contract.ts +0 -5
  489. package/src/gates/definitions.ts +6 -5
  490. package/src/gates/index.ts +0 -5
  491. package/src/gates/performance.ts +1 -6
  492. package/src/gates/runner.ts +1 -1
  493. package/src/gates/security.ts +9 -11
  494. package/src/gates/types.ts +20 -23
  495. package/src/hooks/CONTEXT.md +10 -9
  496. package/src/hooks/__tests__/bootstrap.test.ts +29 -6
  497. package/src/hooks/__tests__/pipeline.test.ts +133 -17
  498. package/src/hooks/__tests__/registry.test.ts +51 -3
  499. package/src/hooks/bootstrap.ts +35 -15
  500. package/src/hooks/config.ts +6 -2
  501. package/src/hooks/index.ts +10 -1
  502. package/src/hooks/pipeline.ts +51 -6
  503. package/src/hooks/registry.ts +31 -12
  504. package/src/hooks/types.ts +26 -7
  505. package/src/index.ts +1 -2
  506. package/src/knowledge/CONTEXT.md +14 -7
  507. package/src/knowledge/__tests__/audit-labels.test.ts +8 -5
  508. package/src/knowledge/__tests__/audit-scoring.test.ts +230 -0
  509. package/src/knowledge/__tests__/audit-write-count.test.ts +131 -0
  510. package/src/knowledge/__tests__/audit.test.ts +291 -208
  511. package/src/knowledge/__tests__/doctor.test.ts +3 -2
  512. package/src/knowledge/__tests__/ingest.test.ts +3 -2
  513. package/src/knowledge/__tests__/lifecycle.test.ts +57 -2
  514. package/src/knowledge/__tests__/migration.test.ts +35 -6
  515. package/src/knowledge/__tests__/query.test.ts +3 -2
  516. package/src/knowledge/__tests__/reference-tracker.test.ts +23 -2
  517. package/src/knowledge/__tests__/store.test.ts +149 -4
  518. package/src/knowledge/__tests__/tree-walker.test.ts +132 -0
  519. package/src/knowledge/audit-scoring.ts +589 -0
  520. package/src/knowledge/audit.ts +55 -599
  521. package/src/knowledge/import.ts +2 -0
  522. package/src/knowledge/index-generator.ts +4 -6
  523. package/src/knowledge/index.ts +27 -2
  524. package/src/knowledge/ingest.ts +1 -1
  525. package/src/knowledge/lifecycle.ts +5 -2
  526. package/src/knowledge/migration.ts +8 -2
  527. package/src/knowledge/query.ts +8 -1
  528. package/src/knowledge/reference-tracker.ts +5 -7
  529. package/src/knowledge/store.ts +75 -16
  530. package/src/knowledge/tree-walker.ts +29 -0
  531. package/src/knowledge/types.ts +19 -0
  532. package/src/monitoring/CONTEXT.md +5 -2
  533. package/src/monitoring/__tests__/context-tracker.test.ts +16 -8
  534. package/src/monitoring/__tests__/trace-file-anchoring.test.ts +80 -0
  535. package/src/monitoring/traces.ts +19 -5
  536. package/src/release/CONTEXT.md +1 -1
  537. package/src/release/__tests__/integrity.test.ts +21 -12
  538. package/src/test-setup/__tests__/jsonl-fake-fs.test.ts +98 -0
  539. package/src/test-setup/jsonl-fake-fs.ts +59 -0
  540. package/src/tools/index.ts +5 -1
  541. package/src/types/checkpoint.ts +6 -0
  542. package/src/types/project-config.ts +21 -0
  543. package/src/types/trace.ts +14 -4
  544. package/src/utils/__tests__/file-walk.test.ts +3 -2
  545. package/src/utils/__tests__/jsonl-bounded-read.test.ts +106 -0
  546. package/src/utils/__tests__/jsonl-skip-disposition.test.ts +10 -6
  547. package/src/utils/__tests__/jsonl.test.ts +61 -14
  548. package/src/utils/__tests__/numeric-flag.test.ts +80 -0
  549. package/src/utils/__tests__/package-version.test.ts +2 -2
  550. package/src/utils/exec.ts +4 -64
  551. package/src/utils/jsonl.ts +159 -20
  552. package/src/utils/numeric-flag.ts +64 -0
  553. package/dist/failure/types.d.ts +0 -9
  554. package/dist/failure/types.d.ts.map +0 -1
  555. package/dist/failure/types.js +0 -25
  556. package/dist/failure/types.js.map +0 -1
  557. package/dist/gates/effective-gates.d.ts +0 -30
  558. package/dist/gates/effective-gates.d.ts.map +0 -1
  559. package/dist/gates/effective-gates.js +0 -81
  560. package/dist/gates/effective-gates.js.map +0 -1
  561. package/src/failure/types.ts +0 -9
  562. package/src/gates/__tests__/effective-gates.test.ts +0 -77
  563. package/src/gates/effective-gates.ts +0 -99
@@ -12,9 +12,12 @@
12
12
  * 也不反转既有容错调用点的语义。坏行指非空但 JSON.parse 失败的行
13
13
  * (半写入截断、手工编辑、磁盘满等)。
14
14
  *
15
- * tail / head:只解析尾部 / 头部 N 个非空行(文件仍全量读取,parse 才是大头),
16
- * 供「只看最近 K 条」的调用点避免全量 parse(check 等热路径)。
17
- * countJsonlLines 供纯计数消费方(完全不 parse)。
15
+ * tail:从文件末尾倒着分块 seek,只把够数的尾部行读进内存。2026-09-14 量数据推翻本文件
16
+ * 早先「文件仍全量读取,parse 才是大头」的断言:6.7MB / 32723 行的 traces.log 上,
17
+ * 完全不 parse 的整读单次仍 16.6–21.1ms——成本在 split('\n') 与空白行过滤。
18
+ * head:从文件头正向分块读,够数即停——供「有没有至少 N 条」这类阈值消费方,不再为
19
+ * 一个比较符把全文捞进内存。
20
+ * 两者同给或都不给时才整读后截断(head→tail 顺序即既有语义)。
18
21
  *
19
22
  * 计数去向(harness#100):本模块是坏行计数的唯一正本,但正本≠终点——凡以 'skip'
20
23
  * 策略读,调用点必须把 skippedLines 带到该消费面的用户可见输出(CLI 走 stderr,
@@ -67,7 +70,7 @@ var __importStar = (this && this.__importStar) || (function () {
67
70
  })();
68
71
  Object.defineProperty(exports, "__esModule", { value: true });
69
72
  exports.readJsonl = readJsonl;
70
- exports.countJsonlLines = countJsonlLines;
73
+ exports.readJsonlWindow = readJsonlWindow;
71
74
  exports.readJsonlEnds = readJsonlEnds;
72
75
  exports.appendJsonl = appendJsonl;
73
76
  const fs = __importStar(require("fs"));
@@ -81,19 +84,111 @@ function readNonEmptyLines(filePath) {
81
84
  .split('\n')
82
85
  .filter(line => line.trim().length > 0);
83
86
  }
87
+ /** tail 倒读的分块大小:trace 行约 200B,一块即够几十行 */
88
+ const TAIL_CHUNK_BYTES = 64 * 1024;
89
+ /** head 正读的分块大小 */
90
+ const HEAD_CHUNK_BYTES = 64 * 1024;
84
91
  /**
85
- * 读取 JSONL 文件:exists → read → split → parse → filter(正本读链)
92
+ * 从文件头正向分块读,只返回前 want 个非空行(够数即停,不整读)
86
93
  *
87
- * policy 必填无缺省(裁决 1);缺文件返回空结果,不抛。
94
+ * 与「整读后 slice(0, want)」逐字同语义:行以 `\n` 界定,末块无尾换行时整段收尾算一行,
95
+ * 纯空白行不计数。块边界切在多字节字符中间时,残段按字节留在缓冲里等下一块拼齐再解码。
96
+ * 供「有没有至少 N 条记录」这类阈值消费方——它要的是够不够,不是总数。
88
97
  */
89
- function readJsonl(filePath, policy, options) {
90
- let lines = readNonEmptyLines(filePath);
91
- if (options?.head !== undefined) {
92
- lines = options.head > 0 ? lines.slice(0, options.head) : [];
98
+ function readHeadNonEmptyLines(filePath, want) {
99
+ if (want <= 0)
100
+ return [];
101
+ if (!fs.existsSync(filePath))
102
+ return [];
103
+ const fd = fs.openSync(filePath, 'r');
104
+ try {
105
+ const size = fs.fstatSync(fd).size;
106
+ const kept = [];
107
+ let acc = Buffer.alloc(0);
108
+ let pos = 0;
109
+ while (kept.length < want) {
110
+ const end = Math.min(size, pos + HEAD_CHUNK_BYTES);
111
+ if (end > pos) {
112
+ const chunk = Buffer.alloc(end - pos);
113
+ fs.readSync(fd, chunk, 0, end - pos, pos);
114
+ acc = Buffer.concat([acc, chunk]);
115
+ }
116
+ let cursor = 0;
117
+ for (let i = 0; i < acc.length && kept.length < want; i++) {
118
+ if (acc[i] !== 0x0a)
119
+ continue;
120
+ const line = acc.subarray(cursor, i).toString('utf-8');
121
+ if (line.trim().length > 0)
122
+ kept.push(line);
123
+ cursor = i + 1;
124
+ }
125
+ if (end >= size) {
126
+ // 读到文件末尾:最后一段没有换行收尾,但它就是一行
127
+ if (kept.length < want && cursor < acc.length) {
128
+ const last = acc.subarray(cursor).toString('utf-8');
129
+ if (last.trim().length > 0)
130
+ kept.push(last);
131
+ }
132
+ break;
133
+ }
134
+ pos = end;
135
+ acc = acc.subarray(cursor);
136
+ }
137
+ return kept;
93
138
  }
94
- if (options?.tail !== undefined) {
95
- lines = options.tail > 0 ? lines.slice(-options.tail) : [];
139
+ finally {
140
+ fs.closeSync(fd);
96
141
  }
142
+ }
143
+ /**
144
+ * 从文件末尾倒着分块读,只返回末尾 want 个非空行(文件顺序)
145
+ *
146
+ * 与「整读后 slice(-want)」逐字同语义:行以 `\n` 界定,末行允许无换行,`\r` 随行进文本,
147
+ * 纯空白行不计数。左侧残段(块边界切在多字节字符中间)不解码,按字节留到下一轮——
148
+ * UTF-8 的多字节序列不含 0x0a,故按 `\n` 切字节再解码不会破坏字符。
149
+ */
150
+ function readTailNonEmptyLines(filePath, want) {
151
+ if (want <= 0)
152
+ return [];
153
+ if (!fs.existsSync(filePath))
154
+ return [];
155
+ const fd = fs.openSync(filePath, 'r');
156
+ try {
157
+ let pos = fs.fstatSync(fd).size;
158
+ let acc = Buffer.alloc(0);
159
+ for (;;) {
160
+ const start = Math.max(0, pos - TAIL_CHUNK_BYTES);
161
+ if (pos > start) {
162
+ const chunk = Buffer.alloc(pos - start);
163
+ fs.readSync(fd, chunk, 0, pos - start, start);
164
+ acc = Buffer.concat([chunk, acc]);
165
+ }
166
+ pos = start;
167
+ const lines = [];
168
+ let cursor = pos === 0 ? 0 : -1;
169
+ for (let i = 0; i < acc.length; i++) {
170
+ if (acc[i] !== 0x0a)
171
+ continue;
172
+ if (cursor >= 0)
173
+ lines.push(acc.subarray(cursor, i).toString('utf-8'));
174
+ cursor = i + 1;
175
+ }
176
+ if (cursor >= 0 && cursor < acc.length)
177
+ lines.push(acc.subarray(cursor).toString('utf-8'));
178
+ const kept = lines
179
+ .filter(line => line.trim().length > 0)
180
+ .slice(-want);
181
+ // 已到文件头 → 全部行都在手里;否则末尾 want 个非空行已凑齐,左侧只可能是更早的行
182
+ if (pos === 0 || kept.length >= want)
183
+ return kept;
184
+ }
185
+ }
186
+ finally {
187
+ fs.closeSync(fd);
188
+ }
189
+ }
190
+ /** parse 非空行文本(读链的末段;坏行策略同 readJsonl) */
191
+ function parseJsonlLines(lines, policy) {
97
192
  const records = [];
98
193
  let skippedLines = 0;
99
194
  for (const line of lines) {
@@ -109,13 +204,45 @@ function readJsonl(filePath, policy, options) {
109
204
  return { records, skippedLines };
110
205
  }
111
206
  /**
112
- * 统计非空行数(含坏行,完全不 parse
207
+ * 读取 JSONL 文件:exists → read → split → parse → filter(正本读链)
113
208
  *
114
- * 供只关心记录条数的调用点(如 check 智能提示)避免全量 parse;
115
- * 缺文件返回 0。
209
+ * policy 必填无缺省(裁决 1);缺文件返回空结果,不抛。
210
+ * 只给 head 走有界正读、只给 tail 走倒读 seek;两者同给或都不给走整读后截断
211
+ * (head→tail 的截断顺序即既有语义)。
116
212
  */
117
- function countJsonlLines(filePath) {
118
- return readNonEmptyLines(filePath).length;
213
+ function readJsonl(filePath, policy, options) {
214
+ let lines;
215
+ if (options?.head !== undefined && options.tail === undefined) {
216
+ lines = readHeadNonEmptyLines(filePath, options.head);
217
+ }
218
+ else if (options?.tail !== undefined && options.head === undefined) {
219
+ lines = readTailNonEmptyLines(filePath, options.tail);
220
+ }
221
+ else {
222
+ lines = applyHeadTail(readNonEmptyLines(filePath), options);
223
+ }
224
+ return parseJsonlLines(lines, policy);
225
+ }
226
+ function readJsonlWindow(filePath, policy, maxLines) {
227
+ const lines = readTailNonEmptyLines(filePath, maxLines);
228
+ return {
229
+ take: (limit) => {
230
+ if (limit > maxLines) {
231
+ throw new Error(`尾部窗口上限 ${maxLines} 行,无法取 ${limit} 行——建窗口时按最大消费方取值,或改上限(不静默少给)`);
232
+ }
233
+ return parseJsonlLines(limit > 0 ? lines.slice(-limit) : [], policy);
234
+ },
235
+ };
236
+ }
237
+ /** 整读路径上的 head → tail 截断(顺序即既有语义:先截头再截尾) */
238
+ function applyHeadTail(lines, options) {
239
+ if (options?.head !== undefined) {
240
+ lines = options.head > 0 ? lines.slice(0, options.head) : [];
241
+ }
242
+ if (options?.tail !== undefined) {
243
+ lines = options.tail > 0 ? lines.slice(-options.tail) : [];
244
+ }
245
+ return lines;
119
246
  }
120
247
  /**
121
248
  * 只取首尾:首/末条合法记录 + 原始行数,parse 停在两端首个合法行
@@ -1 +1 @@
1
- {"version":3,"file":"jsonl.js","sourceRoot":"","sources":["../../src/utils/jsonl.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"jsonl.js","sourceRoot":"","sources":["../../src/utils/jsonl.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * 数值旗帜装配解析器(harness#154;口径正本 = src/cli/commands/CONTEXT.md
3
+ * 「数值旗帜装配口径(harness#152)」条目,本模块是该条目指名的唯一解析器)
4
+ *
5
+ * 背景:commander 给到命令侧的数值旗帜恒是字符串(`defaultValue: '50'` 也是),
6
+ * 数值只在装配点转一次,转不出来必须 fail-loud——下游兜底多是 `??`/`||`,
7
+ * NaN 穿透后比较恒 false,一道质量判定被静默关掉而退出码仍是 0(#152 病灶)。
8
+ * `parseInt`/`parseFloat` 不可用:它们前缀截断('30abc'→30、'1e2'→1)同属静默误读。
9
+ *
10
+ * 两个消费形(同一条判定规则,不建第二套解析器):
11
+ * - `requireNumericFlag`:定义表 `mapActionArgs` 装配点用,脏值抛 `NumericFlagError`,
12
+ * bin/harness.js 捕获后映射 usage-error(非零退出);
13
+ * - `parseNumericFlag`:命令模块入口装配点用(knowledge/failure/passes-gate),
14
+ * 返回值判别,就地 `logError` + `usage-error`。
15
+ */
16
+ /** 数值形:int = 非负整数;float = 非负十进制(不收指数/符号/前后缀) */
17
+ export type NumericFlagKind = 'int' | 'float';
18
+ /** 装配结果:`ok: false` = 脏输入,由装配点 fail-loud(不得往判定槽塞 NaN) */
19
+ export type NumericFlagAssembly = {
20
+ ok: true;
21
+ value?: number;
22
+ } | {
23
+ ok: false;
24
+ raw: string;
25
+ };
26
+ /**
27
+ * 装配窄化:`undefined` = 未传(落下游缺省);`'0'` 是显式零值,不当「未传」兜掉。
28
+ * 规则与 #152 `assembleShortContentThreshold` 同源:trim 后全数字(float 允许一段小数),
29
+ * 溢出 double 上限(→ Infinity)同脏值处理。
30
+ */
31
+ export declare function parseNumericFlag(raw: string | undefined, kind: NumericFlagKind): NumericFlagAssembly;
32
+ /** 报错文案模板:点名旗帜与原值(可定位),int/float 措辞一致收敛 */
33
+ export declare function numericFlagMessage(flag: string, raw: string, kind: NumericFlagKind): string;
34
+ /** 定义表装配失败的专用错误:bin/harness.js 凭它映射 usage-error(非零退出) */
35
+ export declare class NumericFlagError extends Error {
36
+ constructor(message: string);
37
+ }
38
+ /**
39
+ * 定义表 `mapActionArgs` 装配点用:脏值抛 `NumericFlagError`。
40
+ * 定义表是纯数据模块,返回不了 CommandResult;退出码映射唯一出口在 bin,
41
+ * 故以抛出表达失败、bin 就地捕获映射,不新增第二条失败通道。
42
+ */
43
+ export declare function requireNumericFlag(flag: string, raw: string | undefined, kind: NumericFlagKind): number | undefined;
44
+ //# sourceMappingURL=numeric-flag.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"numeric-flag.d.ts","sourceRoot":"","sources":["../../src/utils/numeric-flag.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,gDAAgD;AAChD,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,OAAO,CAAC;AAE9C,yDAAyD;AACzD,MAAM,MAAM,mBAAmB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5F;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,eAAe,GAAG,mBAAmB,CAQpG;AAED,2CAA2C;AAC3C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,GAAG,MAAM,CAE3F;AAED,yDAAyD;AACzD,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM;CAI5B;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,IAAI,EAAE,eAAe,GACpB,MAAM,GAAG,SAAS,CAIpB"}
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ /**
3
+ * 数值旗帜装配解析器(harness#154;口径正本 = src/cli/commands/CONTEXT.md
4
+ * 「数值旗帜装配口径(harness#152)」条目,本模块是该条目指名的唯一解析器)
5
+ *
6
+ * 背景:commander 给到命令侧的数值旗帜恒是字符串(`defaultValue: '50'` 也是),
7
+ * 数值只在装配点转一次,转不出来必须 fail-loud——下游兜底多是 `??`/`||`,
8
+ * NaN 穿透后比较恒 false,一道质量判定被静默关掉而退出码仍是 0(#152 病灶)。
9
+ * `parseInt`/`parseFloat` 不可用:它们前缀截断('30abc'→30、'1e2'→1)同属静默误读。
10
+ *
11
+ * 两个消费形(同一条判定规则,不建第二套解析器):
12
+ * - `requireNumericFlag`:定义表 `mapActionArgs` 装配点用,脏值抛 `NumericFlagError`,
13
+ * bin/harness.js 捕获后映射 usage-error(非零退出);
14
+ * - `parseNumericFlag`:命令模块入口装配点用(knowledge/failure/passes-gate),
15
+ * 返回值判别,就地 `logError` + `usage-error`。
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.NumericFlagError = void 0;
19
+ exports.parseNumericFlag = parseNumericFlag;
20
+ exports.numericFlagMessage = numericFlagMessage;
21
+ exports.requireNumericFlag = requireNumericFlag;
22
+ /**
23
+ * 装配窄化:`undefined` = 未传(落下游缺省);`'0'` 是显式零值,不当「未传」兜掉。
24
+ * 规则与 #152 `assembleShortContentThreshold` 同源:trim 后全数字(float 允许一段小数),
25
+ * 溢出 double 上限(→ Infinity)同脏值处理。
26
+ */
27
+ function parseNumericFlag(raw, kind) {
28
+ if (raw === undefined)
29
+ return { ok: true };
30
+ const text = raw.trim();
31
+ const pattern = kind === 'int' ? /^\d+$/ : /^\d+(\.\d+)?$/;
32
+ if (!pattern.test(text))
33
+ return { ok: false, raw };
34
+ const value = Number(text);
35
+ if (!Number.isFinite(value))
36
+ return { ok: false, raw };
37
+ return { ok: true, value };
38
+ }
39
+ /** 报错文案模板:点名旗帜与原值(可定位),int/float 措辞一致收敛 */
40
+ function numericFlagMessage(flag, raw, kind) {
41
+ return `错误:${flag} 需要非负${kind === 'int' ? '整数' : '数值'},收到 "${raw}"`;
42
+ }
43
+ /** 定义表装配失败的专用错误:bin/harness.js 凭它映射 usage-error(非零退出) */
44
+ class NumericFlagError extends Error {
45
+ constructor(message) {
46
+ super(message);
47
+ this.name = 'NumericFlagError';
48
+ }
49
+ }
50
+ exports.NumericFlagError = NumericFlagError;
51
+ /**
52
+ * 定义表 `mapActionArgs` 装配点用:脏值抛 `NumericFlagError`。
53
+ * 定义表是纯数据模块,返回不了 CommandResult;退出码映射唯一出口在 bin,
54
+ * 故以抛出表达失败、bin 就地捕获映射,不新增第二条失败通道。
55
+ */
56
+ function requireNumericFlag(flag, raw, kind) {
57
+ const result = parseNumericFlag(raw, kind);
58
+ if (!result.ok)
59
+ throw new NumericFlagError(numericFlagMessage(flag, result.raw, kind));
60
+ return result.value;
61
+ }
62
+ //# sourceMappingURL=numeric-flag.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"numeric-flag.js","sourceRoot":"","sources":["../../src/utils/numeric-flag.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;AAaH,4CAQC;AAGD,gDAEC;AAeD,gDAQC;AAzCD;;;;GAIG;AACH,SAAgB,gBAAgB,CAAC,GAAuB,EAAE,IAAqB;IAC7E,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IAC3C,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IACxB,MAAM,OAAO,GAAG,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;IAC3D,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;IACnD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC3B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;IACvD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AAC7B,CAAC;AAED,2CAA2C;AAC3C,SAAgB,kBAAkB,CAAC,IAAY,EAAE,GAAW,EAAE,IAAqB;IACjF,OAAO,MAAM,IAAI,QAAQ,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,QAAQ,GAAG,GAAG,CAAC;AACtE,CAAC;AAED,yDAAyD;AACzD,MAAa,gBAAiB,SAAQ,KAAK;IACzC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;AALD,4CAKC;AAED;;;;GAIG;AACH,SAAgB,kBAAkB,CAChC,IAAY,EACZ,GAAuB,EACvB,IAAqB;IAErB,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAC3C,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,MAAM,IAAI,gBAAgB,CAAC,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;IACvF,OAAO,MAAM,CAAC,KAAK,CAAC;AACtB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dommaker/harness",
3
- "version": "1.7.0",
3
+ "version": "1.8.1",
4
4
  "description": "通用工程约束框架 - 铁律系统、检查点验证、测试门控",
5
5
  "keywords": [
6
6
  "harness",
package/src/CONTEXT.md CHANGED
@@ -4,7 +4,7 @@
4
4
  通用工程约束框架的 TypeScript 核心代码。定义约束系统、检查点验证、质量门控、知识基础设施。
5
5
 
6
6
  ## 核心导出 (dist/)
7
- - `index.ts`: 显式公共导出清单(ADR-0003,禁 export *)
7
+ - `index.ts`: 显式公共导出清单(ADR-0003,禁 export *;harness#137 起该禁令由 `src/__tests__/sub-barrels-explicit.test.ts` 扩到 src 下全部目录 barrel,豁免逐文件记名)
8
8
  - `core/index.ts`: 核心约束引擎
9
9
  - `presets/index.ts`: 预设纯数据(strict/standard/relaxed;筛选逻辑统一在 core mergeConstraints)
10
10
  - `context/index.ts`: 上下文管理
@@ -41,13 +41,16 @@
41
41
  | 守卫 guard | 仅 dsh 借鉴语境(工具管线单调守卫),不进入 harness 命名 |
42
42
  | 回滚 | 分工:版本化回退(单段——yml 数据文件 git 版本化,删段恢复)+ 提案回滚(多段 inverse,挂 studio#82 D6) |
43
43
  | 文件驱动 CLI | yml 状态真值 + 一次性进程、无常驻生命周期;故不引 dispose 链(止步档 1) |
44
- | 对照(reconcile) | CAPABILITIES.md 声明与源码实况的双向一致性判定(代码→文档查漏登,文档→代码查幽灵);唯一实现 `core/constraints/capabilities-reconcile.ts`,capability_sync / docs_freshness / sync-docs 共消费(ADR-0009) |
44
+ | 对照(reconcile) | CAPABILITIES.md 声明与源码实况的双向一致性判定(代码→文档查漏登,文档→代码查幽灵);唯一实现 `core/constraints/capabilities-reconcile.ts`,capability_sync / docs_freshness / sync-docs 共消费(ADR-0009)。一次 check run 内只算一次,经 `RunEnv.capabilities()` 供给两 checker(ADR-0023 决策 4) |
45
45
  | 判定证据(evidence) | checker 随判定一并返回的路径级依据(`CheckDetail{pass, evidence}`,harness#119/ADR-0016);文案由 checker 措辞、消费端只打印,出口 = `ConstraintResult` / CLI 输出 / trace / 铁律异常文案。不是第四种统计态:**违规** = 与本次变更有因果(进 pass/fail 分母),**提示** = `pass:true` + evidence(仓库级漂移等无因果缺口,只露出不拦) |
46
46
  | 测试产物解读(test-output) | 从测试运行器 stdout 读出「过了没 / 哪些失败 / 覆盖率」的判定;唯一实现 `core/validators/test-output.ts`(包内,不进导出面),passes-gate / acceptance 共消费(ADR-0012)。两门禁判定依据不一致待 #93 裁决,覆盖率取数归属待 #94 裁决 |
47
47
  | 飞轮指标(flywheel) | 知识条目的引用与消费度量(refCoverage / avgRefs / consumptionHitRate);唯一实现 `knowledge/flywheel-metrics.ts`(包内,不进导出面),canonical 分子为过滤 synthetic 后的 genuine refs,audit D6 / knowledge stats / knowledge health 共消费(ADR-0013,#81) |
48
48
  | 测试夹具(project fixture) | 临时项目根 + 落盘声明;唯一实现 `test-setup/project-fixture.ts`(测试层,不进导出面)——`config` 槽是 `.harness/config.yml` 落点唯一正本(字符串原样落盘,畸形/脏配置用例依赖此口径),`traces` 槽/`writeProjectTraces` 是 trace 落盘唯一正本(路径锚定 `DEFAULT_TRACE_FILE`、序列化走 `appendJsonl` 生产写链,harness#108),其余文件走 `files` 相对路径;非缺省根必须经 `parentDir` **显式** opt-out(cwd 锚定用例语义),回收经 `mkdtemp-cleanup` 劫持(harness#90) |
49
+ | 运行级观察面(run env) | 一次 `harness check` 运行内对项目上行数据的只读视图,口径 = **同一文件至多读一次、跑完即弃、不做进程级全局**;唯一实现 `core/constraints/run-env.ts`,承载 `rawConfig()` / `customConstraints(file)` / `capabilities(population)` / `traceTail(limit)` / `sourceRoots()` 五个观察口(配置与能力表的读取原进程级缓存已按 ADR-0023 决策 2 撤销),与 git 证据(#87/ADR-0021)同形:入口构造、沿调用链显式传递。与 `CheckEnv` 的分工是构造顺序决定的——`CheckEnv` 含 `context`,而 `context` 是经本观察面读文件算出的产物,故观察面只承载「不需要 context 就能造」的部分,`CheckEnv` 以 `extends RunEnv` 从它派生(ADR-0023);`RunEnv` / `RunTarget`(= `RunEnv \| 项目根路径`)经 `./core` 以类型面导出,供消费方共享同一份读取。**只读是硬契约**:运行期状态文件的写口不走本面,走 StateIO(#148) |
50
+ | 状态文件 IO(StateIO) | harness 自身运行期状态文件(`.harness/.state.json`)读写的可注入接缝:`read()`/`write()` 两方法、默认真实 fs 实现 `fileStateIO(projectPath)`、命令可选参数注入(照 `CommandIO` 模式,但不扩 `CommandIO`);唯一实现 `src/cli/state-io.ts`(cli 层,不进包根导出面),收编 check 智能提示与 status 两个写者,写语义统一为**读-改-写**(此前 `status` 不读就整文件重写、把 `check` 写的 `shownHints` 抹掉致提示去重失效,ADR-0026 已修)。决策 = **ADR-0026**,实现票 #148;与运行级观察面(只读、项目上行数据)分工:本面管 harness 自身状态、含写 |
49
51
 
50
52
  ## 注意事项
51
53
  - 公共包,禁止硬编码业务路径
52
54
  - 约束定义在 `core/constraints/definitions/{iron-laws,guidelines,prompts}.ts`,不应在运行时代码中定义
53
55
  - `bin/` 只有 CLI 入口发布到 npm
56
+ - `__tests__` 的文件系统夹具根一律经 `fs.mkdtempSync` 取每轮唯一目录(缺省父目录 = tmpdir;被测语义本身是 cwd 相对解析的,才显式 opt-out 留在 cwd),固定名会在并发/被 kill 的运行之间互删或被复用成脏夹具;闸 = `__tests__/test-fixture-hygiene.test.ts`(harness#145)
@@ -8,15 +8,18 @@ import { SpecAcceptanceGate } from '../gates/acceptance';
8
8
  import { createSpecAcceptanceGate } from '../gates/index';
9
9
  import * as fs from 'fs';
10
10
  import * as path from 'path';
11
+ import * as os from 'os';
11
12
  import * as yaml from 'js-yaml';
12
13
 
13
14
  describe('SpecAcceptanceGate', () => {
14
- const tempDir = path.join(process.cwd(), 'temp-test-acceptance');
15
- const tasksFile = path.join(tempDir, 'tasks.yml');
16
- const customTasksFile = path.join(tempDir, 'custom-tasks.yml');
15
+ let tempDir: string;
16
+ let tasksFile: string;
17
+ let customTasksFile: string;
17
18
 
18
19
  beforeAll(() => {
19
- fs.mkdirSync(tempDir, { recursive: true });
20
+ tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'temp-test-acceptance-'));
21
+ tasksFile = path.join(tempDir, 'tasks.yml');
22
+ customTasksFile = path.join(tempDir, 'custom-tasks.yml');
20
23
  });
21
24
 
22
25
  afterAll(() => {
@@ -18,15 +18,16 @@ import { contextEvidenceFlag } from '../core/constraints/checkers/types';
18
18
  import type { ConstraintContext } from '../types/constraint';
19
19
  import * as fs from 'fs';
20
20
  import * as path from 'path';
21
+ import * as os from 'os';
21
22
  import { execSync } from 'child_process';
22
23
 
23
24
  describe('ConstraintChecker - 补充覆盖', () => {
24
- const tempDir = path.join(process.cwd(), 'temp-test-checker-extra');
25
+ let tempDir: string;
25
26
  const checker = ConstraintChecker.getInstance();
26
27
 
27
28
  beforeAll(() => {
28
29
  // 创建临时 git 仓库
29
- fs.mkdirSync(tempDir, { recursive: true });
30
+ tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'temp-test-checker-extra-'));
30
31
  execSync('git init', { cwd: tempDir });
31
32
  execSync('git config user.email "test@test.com"', { cwd: tempDir });
32
33
  execSync('git config user.name "Test"', { cwd: tempDir });
@@ -9,16 +9,17 @@
9
9
  import { ConstraintChecker, checkConstraint } from '../core/constraints/checker';
10
10
  import { PROMPTS } from '../core/constraints/definitions';
11
11
  import type { ConstraintContext } from '../types/constraint';
12
- import { writeFileSync, mkdirSync, rmSync } from 'fs';
12
+ import { writeFileSync, rmSync, mkdtempSync } from 'fs';
13
13
  import { join } from 'path';
14
+ import { tmpdir } from 'os';
14
15
 
15
16
  describe('ConstraintChecker', () => {
16
17
  const checker = ConstraintChecker.getInstance();
17
- const tempDir = join(process.cwd(), 'temp-test-checker');
18
+ let tempDir: string;
18
19
 
19
20
  beforeAll(() => {
20
21
  // 创建临时测试目录
21
- mkdirSync(tempDir, { recursive: true });
22
+ tempDir = mkdtempSync(join(tmpdir(), 'temp-test-checker-'));
22
23
  });
23
24
 
24
25
  afterAll(() => {
@@ -4,15 +4,16 @@
4
4
 
5
5
  import { describe, it, expect, beforeAll, afterAll } from '@jest/globals';
6
6
  import { CheckpointValidator } from '../core/validators/checkpoint';
7
- import { mkdirSync, rmSync, writeFileSync } from 'fs';
7
+ import { rmSync, writeFileSync, mkdtempSync } from 'fs';
8
8
  import { join } from 'path';
9
+ import { tmpdir } from 'os';
9
10
 
10
11
  describe('CheckpointValidator', () => {
11
- const tempDir = join(process.cwd(), 'temp-test-checkpoint');
12
+ let tempDir: string;
12
13
  let validator: CheckpointValidator;
13
14
 
14
15
  beforeAll(async () => {
15
- mkdirSync(tempDir, { recursive: true });
16
+ tempDir = mkdtempSync(join(tmpdir(), 'temp-test-checkpoint-'));
16
17
  validator = CheckpointValidator.getInstance();
17
18
  // 创建测试文件
18
19
  writeFileSync(join(tempDir, 'test.txt'), 'hello world');
@@ -568,34 +569,50 @@ describe('CheckpointValidator', () => {
568
569
  afterEach(() => { globalThis.fetch = fetch; });
569
570
 
570
571
  it('fetch 网络错误应该返回失败', async () => {
571
- globalThis.fetch = (() => Promise.reject(new Error('Network error'))) as any;
572
+ const attempts: string[] = [];
573
+ globalThis.fetch = ((url: string) => {
574
+ attempts.push(String(url));
575
+ return Promise.reject(new Error('Network error'));
576
+ }) as any;
577
+ const waits: number[] = [];
572
578
  const result = await CheckpointValidator.getInstance().validate(
573
579
  {
574
580
  id: 'cp-hs-fail',
575
581
  checks: [{ id: 'c-hs-fail', type: 'http_status', config: { url: 'https://example.com', expectedStatus: 200 } }],
576
582
  },
577
- { workdir: tempDir, projectPath: tempDir }
583
+ // 注入零等待 sleep:重试语义照旧断言,不再真烧 2+4+6s(工单 #136)
584
+ { workdir: tempDir, projectPath: tempDir, sleep: async (ms: number) => { waits.push(ms); } }
578
585
  );
579
586
  expect(result.passed).toBe(false);
580
587
  expect(result.checks[0].message).toContain('请求失败');
581
- }, 20_000); // retry logic adds 2+4+6s delay
588
+ expect(attempts).toHaveLength(4);
589
+ expect(waits).toEqual([2000, 4000, 6000]);
590
+ });
582
591
  });
583
592
 
584
593
  describe('http_body 请求失败', () => {
585
594
  afterEach(() => { globalThis.fetch = fetch; });
586
595
 
587
596
  it('fetch 网络错误应该返回失败', async () => {
588
- globalThis.fetch = (() => Promise.reject(new Error('Network error'))) as any;
597
+ const attempts: string[] = [];
598
+ globalThis.fetch = ((url: string) => {
599
+ attempts.push(String(url));
600
+ return Promise.reject(new Error('Network error'));
601
+ }) as any;
602
+ const waits: number[] = [];
589
603
  const result = await CheckpointValidator.getInstance().validate(
590
604
  {
591
605
  id: 'cp-hb-fail',
592
606
  checks: [{ id: 'c-hb-fail', type: 'http_body', config: { url: 'https://example.com', expected: 'test' } }],
593
607
  },
594
- { workdir: tempDir, projectPath: tempDir }
608
+ // 注入零等待 sleep:重试语义照旧断言,不再真烧 2+4+6s(工单 #136)
609
+ { workdir: tempDir, projectPath: tempDir, sleep: async (ms: number) => { waits.push(ms); } }
595
610
  );
596
611
  expect(result.passed).toBe(false);
597
612
  expect(result.checks[0].message).toContain('请求失败');
598
- }, 20_000);
613
+ expect(attempts).toHaveLength(4);
614
+ expect(waits).toEqual([2000, 4000, 6000]);
615
+ });
599
616
  });
600
617
 
601
618
  describe('output_contains JSON 输出', () => {
@@ -2,16 +2,17 @@
2
2
  * resolveContextFiles 三态访问器测试(工单 84)
3
3
  *
4
4
  * 测试面 = project-config-loader 上的 governance.context_files 访问器:
5
- * 未配置 / enabled 但无目标 / enabled 且非空 三态可分辨;访问器基于
6
- * loadRawProjectConfig 的进程级 memoize,不触发第二次 yaml 解析。
7
- * 临时目录由 src/test-setup/mkdtemp-cleanup.ts 统一回收。
5
+ * 未配置 / enabled 但无目标 / enabled 且非空 三态可分辨;访问器的 config.yml
6
+ * 读取由运行级观察面供给(ADR-0023 决策 2:同一枚 RunEnv 内不触发第二次解析,
7
+ * 进程级缓存已撤销)。临时目录由 src/test-setup/mkdtemp-cleanup.ts 统一回收。
8
8
  */
9
9
 
10
10
  import { describe, it, expect, jest } from '@jest/globals';
11
11
  import * as fs from 'fs';
12
12
  import * as path from 'path';
13
13
  import { resolveContextFiles, loadRawProjectConfig } from '../core/project-config-loader';
14
- import { createProjectFixture } from '../test-setup/project-fixture';
14
+ import { createRunEnv } from '../core/constraints/run-env';
15
+ import { createProjectFixture, writeProjectConfig } from '../test-setup/project-fixture';
15
16
 
16
17
  // ts-jest 的 namespace 导入属性不可重定义(jest.spyOn 会抛),改为只包一层
17
18
  // readFileSync 的部分 mock——其余 fs 能力用真实实现,fixture 搭建不受影响。
@@ -94,23 +95,36 @@ describe('resolveContextFiles — 三态分辨率(工单 84 triage 裁决口
94
95
  });
95
96
  });
96
97
 
97
- describe('resolveContextFiles — memoize 语义(工单 84:不引入第二次解析)', () => {
98
- it('访问器多次调用 + 直接读 raw 共享单次 config.yml 读取', () => {
98
+ describe('resolveContextFiles — 运行级 memoize 语义(ADR-0023 决策 2:撤销进程级缓存)', () => {
99
+ const configReads = () =>
100
+ readSpy.mock.calls.filter(call =>
101
+ String(call[0]).endsWith(path.join('.harness', 'config.yml'))
102
+ ).length;
103
+
104
+ it('同一枚观察面内多次访问共享单次 config.yml 读取', () => {
99
105
  const dir = setupProject('memo', CTX_FILES(true, ['src']));
100
- const configReads = () =>
101
- readSpy.mock.calls.filter(call =>
102
- String(call[0]).endsWith(path.join('.harness', 'config.yml'))
103
- ).length;
106
+ const env = createRunEnv(dir);
104
107
 
105
108
  readSpy.mockClear();
106
109
  expect(configReads()).toBe(0); // 探针有效:fixture 搭建不读 config
107
110
 
108
- resolveContextFiles(dir);
111
+ resolveContextFiles(env);
109
112
  expect(configReads()).toBe(1); // 首次真读取+解析
110
113
 
111
- resolveContextFiles(dir);
112
- resolveContextFiles(dir);
113
- loadRawProjectConfig(dir);
114
- expect(configReads()).toBe(1); // 复用进程级 memoize,无第二次解析
114
+ resolveContextFiles(env);
115
+ resolveContextFiles(env);
116
+ loadRawProjectConfig(env);
117
+ expect(configReads()).toBe(1); // run 内复用同一份解析结果,无第二次解析
118
+ });
119
+
120
+ it('只传路径 = 一次性读取:同一路径先改后读必须读到新内容', () => {
121
+ const dir = setupProject('fresh', CTX_FILES(true, ['src']));
122
+
123
+ expect(resolveContextFiles(dir)).toEqual({ state: 'enabled', dirs: ['src'] });
124
+
125
+ writeProjectConfig(dir, CTX_FILES(false, ['src']));
126
+ // 旧进程级缓存按 mtime/size 判新鲜,同一次运行内「先改后读」照样读到老内容;
127
+ // 撤销缓存后每次调用自造一枚用完即弃的观察面,读到的必然是当下内容
128
+ expect(resolveContextFiles(dir)).toEqual({ state: 'unconfigured' });
115
129
  });
116
130
  });