@dommaker/harness 1.1.0 → 1.2.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 (349) hide show
  1. package/CHANGELOG.md +19 -2
  2. package/README.md +2 -4
  3. package/bin/harness.js +12 -37
  4. package/dist/cli/commands/check.d.ts +2 -2
  5. package/dist/cli/commands/check.d.ts.map +1 -1
  6. package/dist/cli/commands/check.js +7 -32
  7. package/dist/cli/commands/check.js.map +1 -1
  8. package/dist/cli/commands/definitions.d.ts +2 -0
  9. package/dist/cli/commands/definitions.d.ts.map +1 -1
  10. package/dist/cli/commands/definitions.js.map +1 -1
  11. package/dist/cli/commands/init.d.ts.map +1 -1
  12. package/dist/cli/commands/init.js +6 -37
  13. package/dist/cli/commands/init.js.map +1 -1
  14. package/dist/cli/commands/knowledge.d.ts.map +1 -1
  15. package/dist/cli/commands/knowledge.js +1 -12
  16. package/dist/cli/commands/knowledge.js.map +1 -1
  17. package/dist/cli/commands/report.d.ts.map +1 -1
  18. package/dist/cli/commands/report.js +0 -2
  19. package/dist/cli/commands/report.js.map +1 -1
  20. package/dist/cli/commands/status.d.ts.map +1 -1
  21. package/dist/cli/commands/status.js +2 -11
  22. package/dist/cli/commands/status.js.map +1 -1
  23. package/dist/context/index.d.ts +9 -6
  24. package/dist/context/index.d.ts.map +1 -1
  25. package/dist/context/index.js +18 -20
  26. package/dist/context/index.js.map +1 -1
  27. package/dist/core/constraints/capabilities-parser.d.ts +3 -2
  28. package/dist/core/constraints/capabilities-parser.d.ts.map +1 -1
  29. package/dist/core/constraints/capabilities-parser.js +25 -47
  30. package/dist/core/constraints/capabilities-parser.js.map +1 -1
  31. package/dist/core/constraints/checker.d.ts +32 -33
  32. package/dist/core/constraints/checker.d.ts.map +1 -1
  33. package/dist/core/constraints/checker.js +38 -128
  34. package/dist/core/constraints/checker.js.map +1 -1
  35. package/dist/core/constraints/checkers/index.d.ts +2 -1
  36. package/dist/core/constraints/checkers/index.d.ts.map +1 -1
  37. package/dist/core/constraints/checkers/index.js +3 -0
  38. package/dist/core/constraints/checkers/index.js.map +1 -1
  39. package/dist/core/constraints/checkers/types.d.ts +25 -0
  40. package/dist/core/constraints/checkers/types.d.ts.map +1 -1
  41. package/dist/core/constraints/checkers/types.js +24 -0
  42. package/dist/core/constraints/checkers/types.js.map +1 -1
  43. package/dist/core/constraints/definitions/guidelines.d.ts.map +1 -1
  44. package/dist/core/constraints/definitions/guidelines.js +0 -2
  45. package/dist/core/constraints/definitions/guidelines.js.map +1 -1
  46. package/dist/core/constraints/definitions/prompts.d.ts.map +1 -1
  47. package/dist/core/constraints/definitions/prompts.js +0 -5
  48. package/dist/core/constraints/definitions/prompts.js.map +1 -1
  49. package/dist/core/constraints/index.d.ts +1 -2
  50. package/dist/core/constraints/index.d.ts.map +1 -1
  51. package/dist/core/constraints/index.js +1 -7
  52. package/dist/core/constraints/index.js.map +1 -1
  53. package/dist/core/constraints/usage-report.d.ts +1 -2
  54. package/dist/core/constraints/usage-report.d.ts.map +1 -1
  55. package/dist/core/constraints/usage-report.js +2 -5
  56. package/dist/core/constraints/usage-report.js.map +1 -1
  57. package/dist/core/effective-constraints.d.ts +24 -4
  58. package/dist/core/effective-constraints.d.ts.map +1 -1
  59. package/dist/core/effective-constraints.js +28 -7
  60. package/dist/core/effective-constraints.js.map +1 -1
  61. package/dist/core/effective-set.d.ts +30 -0
  62. package/dist/core/effective-set.d.ts.map +1 -0
  63. package/dist/core/effective-set.js +35 -0
  64. package/dist/core/effective-set.js.map +1 -0
  65. package/dist/core/index.d.ts +13 -6
  66. package/dist/core/index.d.ts.map +1 -1
  67. package/dist/core/index.js +44 -21
  68. package/dist/core/index.js.map +1 -1
  69. package/dist/core/project-config-loader.d.ts +3 -6
  70. package/dist/core/project-config-loader.d.ts.map +1 -1
  71. package/dist/core/project-config-loader.js +47 -61
  72. package/dist/core/project-config-loader.js.map +1 -1
  73. package/dist/failure/constraint-handler.d.ts +1 -1
  74. package/dist/failure/constraint-handler.js +1 -1
  75. package/dist/gates/checker-gate.d.ts +1 -4
  76. package/dist/gates/checker-gate.d.ts.map +1 -1
  77. package/dist/gates/checker-gate.js +3 -11
  78. package/dist/gates/checker-gate.js.map +1 -1
  79. package/dist/gates/definitions.d.ts +9 -38
  80. package/dist/gates/definitions.d.ts.map +1 -1
  81. package/dist/gates/definitions.js +24 -13
  82. package/dist/gates/definitions.js.map +1 -1
  83. package/dist/gates/effective-gates.d.ts.map +1 -1
  84. package/dist/gates/effective-gates.js +14 -18
  85. package/dist/gates/effective-gates.js.map +1 -1
  86. package/dist/gates/index.d.ts +1 -1
  87. package/dist/gates/index.d.ts.map +1 -1
  88. package/dist/gates/index.js.map +1 -1
  89. package/dist/hooks/bootstrap.d.ts.map +1 -1
  90. package/dist/hooks/bootstrap.js +0 -3
  91. package/dist/hooks/bootstrap.js.map +1 -1
  92. package/dist/index.d.ts +43 -53
  93. package/dist/index.d.ts.map +1 -1
  94. package/dist/index.js +180 -138
  95. package/dist/index.js.map +1 -1
  96. package/dist/knowledge/query.d.ts +15 -0
  97. package/dist/knowledge/query.d.ts.map +1 -1
  98. package/dist/knowledge/query.js +23 -0
  99. package/dist/knowledge/query.js.map +1 -1
  100. package/dist/monitoring/analyzer-base.d.ts +0 -4
  101. package/dist/monitoring/analyzer-base.d.ts.map +1 -1
  102. package/dist/monitoring/analyzer-base.js +0 -21
  103. package/dist/monitoring/analyzer-base.js.map +1 -1
  104. package/dist/monitoring/index.d.ts +6 -12
  105. package/dist/monitoring/index.d.ts.map +1 -1
  106. package/dist/monitoring/index.js +13 -29
  107. package/dist/monitoring/index.js.map +1 -1
  108. package/dist/monitoring/trace-analyzer.d.ts.map +1 -1
  109. package/dist/monitoring/trace-analyzer.js +2 -68
  110. package/dist/monitoring/trace-analyzer.js.map +1 -1
  111. package/dist/monitoring/traces.d.ts +2 -6
  112. package/dist/monitoring/traces.d.ts.map +1 -1
  113. package/dist/monitoring/traces.js +0 -14
  114. package/dist/monitoring/traces.js.map +1 -1
  115. package/dist/presets/index.d.ts +2 -2
  116. package/dist/presets/index.d.ts.map +1 -1
  117. package/dist/presets/index.js +3 -4
  118. package/dist/presets/index.js.map +1 -1
  119. package/dist/presets/standard.d.ts +10 -22
  120. package/dist/presets/standard.d.ts.map +1 -1
  121. package/dist/presets/standard.js +15 -75
  122. package/dist/presets/standard.js.map +1 -1
  123. package/dist/types/constraint.d.ts +1 -29
  124. package/dist/types/constraint.d.ts.map +1 -1
  125. package/dist/types/constraint.js +1 -1
  126. package/dist/types/constraint.js.map +1 -1
  127. package/dist/types/index.d.ts +0 -3
  128. package/dist/types/index.d.ts.map +1 -1
  129. package/dist/types/index.js +0 -4
  130. package/dist/types/index.js.map +1 -1
  131. package/dist/types/project-config.d.ts +4 -8
  132. package/dist/types/project-config.d.ts.map +1 -1
  133. package/dist/types/trace.d.ts +9 -22
  134. package/dist/types/trace.d.ts.map +1 -1
  135. package/package.json +2 -2
  136. package/src/CONTEXT.md +5 -7
  137. package/src/__tests__/checker-extra.test.ts +80 -139
  138. package/src/__tests__/checker.test.ts +0 -376
  139. package/src/__tests__/project-config-loader-extra.test.ts +42 -29
  140. package/src/__tests__/public-exports.test.ts +138 -0
  141. package/src/__tests__/trace-analyzer-extra.test.ts +6 -86
  142. package/src/__tests__/trace-analyzer.test.ts +4 -5
  143. package/src/__tests__/trace-collector.test.ts +0 -11
  144. package/src/__tests__/traces.test.ts +3 -22
  145. package/src/cli/commands/CONTEXT.md +2 -2
  146. package/src/cli/commands/__tests__/check-skip-output.test.ts +10 -7
  147. package/src/cli/commands/__tests__/check.test.ts +29 -69
  148. package/src/cli/commands/__tests__/constraints-report.test.ts +1 -1
  149. package/src/cli/commands/__tests__/knowledge.test.ts +90 -1
  150. package/src/cli/commands/__tests__/registry.test.ts +8 -6
  151. package/src/cli/commands/__tests__/status-extra.test.ts +6 -28
  152. package/src/cli/commands/__tests__/status.test.ts +6 -21
  153. package/src/cli/commands/check.ts +8 -34
  154. package/src/cli/commands/definitions.ts +2 -0
  155. package/src/cli/commands/init.ts +6 -37
  156. package/src/cli/commands/knowledge.ts +1 -16
  157. package/src/cli/commands/report.ts +0 -2
  158. package/src/cli/commands/status.ts +2 -12
  159. package/src/context/index.ts +29 -6
  160. package/src/core/CONTEXT.md +4 -3
  161. package/src/core/__tests__/effective-set.test.ts +80 -0
  162. package/src/core/constraints/capabilities-parser.ts +43 -49
  163. package/src/core/constraints/checker.ts +56 -147
  164. package/src/core/constraints/checkers/index.ts +2 -1
  165. package/src/core/constraints/checkers/types.ts +42 -0
  166. package/src/core/constraints/definitions/guidelines.ts +0 -2
  167. package/src/core/constraints/definitions/prompts.ts +0 -5
  168. package/src/core/constraints/index.ts +2 -17
  169. package/src/core/constraints/usage-report.ts +5 -8
  170. package/src/core/effective-constraints.ts +35 -7
  171. package/src/core/effective-set.ts +56 -0
  172. package/src/core/index.ts +80 -6
  173. package/src/core/project-config-loader.ts +53 -68
  174. package/src/failure/CONTEXT.md +1 -1
  175. package/src/failure/constraint-handler.ts +1 -1
  176. package/src/gates/CONTEXT.md +3 -3
  177. package/src/gates/checker-gate.ts +4 -12
  178. package/src/gates/definitions.ts +27 -50
  179. package/src/gates/effective-gates.ts +14 -21
  180. package/src/gates/index.ts +1 -1
  181. package/src/hooks/bootstrap.ts +0 -3
  182. package/src/index.ts +384 -137
  183. package/src/knowledge/CONTEXT.md +2 -2
  184. package/src/knowledge/__tests__/query.test.ts +64 -0
  185. package/src/knowledge/query.ts +28 -0
  186. package/src/monitoring/CONTEXT.md +7 -13
  187. package/src/monitoring/__tests__/traces.test.ts +0 -10
  188. package/src/monitoring/analyzer-base.ts +0 -22
  189. package/src/monitoring/index.ts +6 -12
  190. package/src/monitoring/trace-analyzer.ts +2 -73
  191. package/src/monitoring/traces.ts +2 -22
  192. package/src/presets/__tests__/standard.test.ts +48 -69
  193. package/src/presets/index.ts +3 -5
  194. package/src/presets/standard.ts +14 -79
  195. package/src/spec/CONTEXT.md +5 -13
  196. package/src/types/constraint.ts +1 -51
  197. package/src/types/index.ts +0 -12
  198. package/src/types/project-config.ts +4 -10
  199. package/src/types/trace.ts +9 -34
  200. package/dist/core/constraints/interceptor.d.ts +0 -38
  201. package/dist/core/constraints/interceptor.d.ts.map +0 -1
  202. package/dist/core/constraints/interceptor.js +0 -166
  203. package/dist/core/constraints/interceptor.js.map +0 -1
  204. package/dist/dashboard/data.d.ts +0 -31
  205. package/dist/dashboard/data.d.ts.map +0 -1
  206. package/dist/dashboard/data.js +0 -81
  207. package/dist/dashboard/data.js.map +0 -1
  208. package/dist/dashboard/index.d.ts +0 -4
  209. package/dist/dashboard/index.d.ts.map +0 -1
  210. package/dist/dashboard/index.js +0 -20
  211. package/dist/dashboard/index.js.map +0 -1
  212. package/dist/dashboard/stats.d.ts +0 -20
  213. package/dist/dashboard/stats.d.ts.map +0 -1
  214. package/dist/dashboard/stats.js +0 -115
  215. package/dist/dashboard/stats.js.map +0 -1
  216. package/dist/dashboard/types.d.ts +0 -110
  217. package/dist/dashboard/types.d.ts.map +0 -1
  218. package/dist/dashboard/types.js +0 -8
  219. package/dist/dashboard/types.js.map +0 -1
  220. package/dist/monitoring/constraint-doctor.d.ts +0 -82
  221. package/dist/monitoring/constraint-doctor.d.ts.map +0 -1
  222. package/dist/monitoring/constraint-doctor.js +0 -191
  223. package/dist/monitoring/constraint-doctor.js.map +0 -1
  224. package/dist/monitoring/diagnosis-rules.d.ts +0 -18
  225. package/dist/monitoring/diagnosis-rules.d.ts.map +0 -1
  226. package/dist/monitoring/diagnosis-rules.js +0 -119
  227. package/dist/monitoring/diagnosis-rules.js.map +0 -1
  228. package/dist/monitoring/knowledge-doctor.d.ts +0 -78
  229. package/dist/monitoring/knowledge-doctor.d.ts.map +0 -1
  230. package/dist/monitoring/knowledge-doctor.js +0 -266
  231. package/dist/monitoring/knowledge-doctor.js.map +0 -1
  232. package/dist/monitoring/knowledge-evolver.d.ts +0 -72
  233. package/dist/monitoring/knowledge-evolver.d.ts.map +0 -1
  234. package/dist/monitoring/knowledge-evolver.js +0 -205
  235. package/dist/monitoring/knowledge-evolver.js.map +0 -1
  236. package/dist/monitoring/performance-analyzer.d.ts +0 -92
  237. package/dist/monitoring/performance-analyzer.d.ts.map +0 -1
  238. package/dist/monitoring/performance-analyzer.js +0 -343
  239. package/dist/monitoring/performance-analyzer.js.map +0 -1
  240. package/dist/monitoring/performance-collector.d.ts +0 -103
  241. package/dist/monitoring/performance-collector.d.ts.map +0 -1
  242. package/dist/monitoring/performance-collector.js +0 -298
  243. package/dist/monitoring/performance-collector.js.map +0 -1
  244. package/dist/safety/index.d.ts +0 -6
  245. package/dist/safety/index.d.ts.map +0 -1
  246. package/dist/safety/index.js +0 -22
  247. package/dist/safety/index.js.map +0 -1
  248. package/dist/safety/input-guardrail.d.ts +0 -36
  249. package/dist/safety/input-guardrail.d.ts.map +0 -1
  250. package/dist/safety/input-guardrail.js +0 -118
  251. package/dist/safety/input-guardrail.js.map +0 -1
  252. package/dist/safety/output-guardrail.d.ts +0 -39
  253. package/dist/safety/output-guardrail.d.ts.map +0 -1
  254. package/dist/safety/output-guardrail.js +0 -147
  255. package/dist/safety/output-guardrail.js.map +0 -1
  256. package/dist/safety/sandbox.d.ts +0 -45
  257. package/dist/safety/sandbox.d.ts.map +0 -1
  258. package/dist/safety/sandbox.js +0 -134
  259. package/dist/safety/sandbox.js.map +0 -1
  260. package/dist/safety/tool-guardrail.d.ts +0 -51
  261. package/dist/safety/tool-guardrail.d.ts.map +0 -1
  262. package/dist/safety/tool-guardrail.js +0 -147
  263. package/dist/safety/tool-guardrail.js.map +0 -1
  264. package/dist/safety/types.d.ts +0 -104
  265. package/dist/safety/types.d.ts.map +0 -1
  266. package/dist/safety/types.js +0 -6
  267. package/dist/safety/types.js.map +0 -1
  268. package/dist/spec/annotation-checker.d.ts +0 -47
  269. package/dist/spec/annotation-checker.d.ts.map +0 -1
  270. package/dist/spec/annotation-checker.js +0 -279
  271. package/dist/spec/annotation-checker.js.map +0 -1
  272. package/dist/types/enforcement.d.ts +0 -42
  273. package/dist/types/enforcement.d.ts.map +0 -1
  274. package/dist/types/enforcement.js +0 -6
  275. package/dist/types/enforcement.js.map +0 -1
  276. package/dist/types/monitoring-types.d.ts +0 -53
  277. package/dist/types/monitoring-types.d.ts.map +0 -1
  278. package/dist/types/monitoring-types.js +0 -10
  279. package/dist/types/monitoring-types.js.map +0 -1
  280. package/dist/types/performance.d.ts +0 -204
  281. package/dist/types/performance.d.ts.map +0 -1
  282. package/dist/types/performance.js +0 -12
  283. package/dist/types/performance.js.map +0 -1
  284. package/dist/verification/index.d.ts +0 -4
  285. package/dist/verification/index.d.ts.map +0 -1
  286. package/dist/verification/index.js +0 -20
  287. package/dist/verification/index.js.map +0 -1
  288. package/dist/verification/loop.d.ts +0 -30
  289. package/dist/verification/loop.d.ts.map +0 -1
  290. package/dist/verification/loop.js +0 -114
  291. package/dist/verification/loop.js.map +0 -1
  292. package/dist/verification/rules-based.d.ts +0 -40
  293. package/dist/verification/rules-based.d.ts.map +0 -1
  294. package/dist/verification/rules-based.js +0 -130
  295. package/dist/verification/rules-based.js.map +0 -1
  296. package/dist/verification/types.d.ts +0 -69
  297. package/dist/verification/types.d.ts.map +0 -1
  298. package/dist/verification/types.js +0 -6
  299. package/dist/verification/types.js.map +0 -1
  300. package/src/__tests__/annotation-checker.test.ts +0 -183
  301. package/src/__tests__/constraint-doctor.test.ts +0 -271
  302. package/src/__tests__/doctor-extra.test.ts +0 -155
  303. package/src/__tests__/extend-exceptions.test.ts +0 -149
  304. package/src/__tests__/interceptor.test.ts +0 -89
  305. package/src/__tests__/performance-analyzer.test.ts +0 -499
  306. package/src/__tests__/performance-collector.test.ts +0 -276
  307. package/src/__tests__/presets.test.ts +0 -65
  308. package/src/core/constraints/__tests__/interceptor.test.ts +0 -253
  309. package/src/core/constraints/interceptor.ts +0 -214
  310. package/src/dashboard/CONTEXT.md +0 -21
  311. package/src/dashboard/__tests__/data.test.ts +0 -111
  312. package/src/dashboard/__tests__/stats.test.ts +0 -159
  313. package/src/dashboard/data.ts +0 -103
  314. package/src/dashboard/index.ts +0 -3
  315. package/src/dashboard/stats.ts +0 -127
  316. package/src/dashboard/types.ts +0 -130
  317. package/src/monitoring/__tests__/knowledge-doctor.test.ts +0 -278
  318. package/src/monitoring/__tests__/knowledge-evolver.test.ts +0 -368
  319. package/src/monitoring/__tests__/performance-analyzer.test.ts +0 -137
  320. package/src/monitoring/__tests__/performance-collector.test.ts +0 -331
  321. package/src/monitoring/constraint-doctor.ts +0 -239
  322. package/src/monitoring/diagnosis-rules.ts +0 -132
  323. package/src/monitoring/knowledge-doctor.ts +0 -322
  324. package/src/monitoring/knowledge-evolver.ts +0 -289
  325. package/src/monitoring/performance-analyzer.ts +0 -400
  326. package/src/monitoring/performance-collector.ts +0 -326
  327. package/src/safety/CONTEXT.md +0 -23
  328. package/src/safety/__tests__/input-guardrail.test.ts +0 -105
  329. package/src/safety/__tests__/output-guardrail.test.ts +0 -108
  330. package/src/safety/__tests__/sandbox.test.ts +0 -158
  331. package/src/safety/__tests__/tool-guardrail.test.ts +0 -127
  332. package/src/safety/index.ts +0 -5
  333. package/src/safety/input-guardrail.ts +0 -133
  334. package/src/safety/output-guardrail.ts +0 -170
  335. package/src/safety/sandbox.ts +0 -148
  336. package/src/safety/tool-guardrail.ts +0 -176
  337. package/src/safety/types.ts +0 -124
  338. package/src/spec/__tests__/annotation-checker.test.ts +0 -294
  339. package/src/spec/annotation-checker.ts +0 -320
  340. package/src/types/enforcement.ts +0 -48
  341. package/src/types/monitoring-types.ts +0 -68
  342. package/src/types/performance.ts +0 -295
  343. package/src/verification/CONTEXT.md +0 -23
  344. package/src/verification/__tests__/loop.test.ts +0 -303
  345. package/src/verification/__tests__/rules-based.test.ts +0 -240
  346. package/src/verification/index.ts +0 -3
  347. package/src/verification/loop.ts +0 -137
  348. package/src/verification/rules-based.ts +0 -152
  349. package/src/verification/types.ts +0 -81
@@ -87,7 +87,7 @@ describe('status command', () => {
87
87
  mockFs.readFileSync.mockReturnValue(mockTraces.map(t => JSON.stringify(t)).join('\n'));
88
88
 
89
89
  const mockSummarize = jest.fn().mockReturnValue([
90
- { constraintId: 'test1', level: 'iron_law', passRate: 1, totalChecks: 1, bypassRate: 0 },
90
+ { constraintId: 'test1', level: 'iron_law', passRate: 1, failRate: 0, totalChecks: 1 },
91
91
  ]);
92
92
  const mockAnalyze = {
93
93
  summarize: mockSummarize,
@@ -106,7 +106,7 @@ describe('status command', () => {
106
106
  mockFs.readFileSync.mockReturnValue(mockTraces.map(t => JSON.stringify(t)).join('\n'));
107
107
 
108
108
  const mockSummarize = jest.fn().mockReturnValue([
109
- { constraintId: 'no_bypass_checkpoint', level: 'iron_law', passRate: 1, totalChecks: 5, bypassRate: 0 },
109
+ { constraintId: 'no_bypass_checkpoint', level: 'iron_law', passRate: 1, failRate: 0, totalChecks: 5 },
110
110
  ]);
111
111
  const mockAnalyze = {
112
112
  summarize: mockSummarize,
@@ -131,7 +131,7 @@ describe('status command', () => {
131
131
  ];
132
132
  const mockAnalyze = {
133
133
  summarize: jest.fn().mockReturnValue([
134
- { constraintId: 'test1', level: 'iron_law', passRate: 0.2, totalChecks: 5, bypassRate: 0 },
134
+ { constraintId: 'test1', level: 'iron_law', passRate: 0.2, failRate: 0.8, totalChecks: 5 },
135
135
  ]),
136
136
  detectAnomalies: jest.fn().mockReturnValue(mockAnomalies),
137
137
  };
@@ -150,7 +150,7 @@ describe('status command', () => {
150
150
  mockFs.readFileSync.mockReturnValue(mockTraces.map(t => JSON.stringify(t)).join('\n'));
151
151
 
152
152
  const mockSummarize = jest.fn().mockReturnValue([
153
- { constraintId: 'test1', level: 'iron_law', passRate: 0.8, totalChecks: 10, bypassRate: 0.1 },
153
+ { constraintId: 'test1', level: 'iron_law', passRate: 0.8, failRate: 0.2, totalChecks: 10 },
154
154
  ]);
155
155
  const mockAnalyze = {
156
156
  summarize: mockSummarize,
@@ -184,7 +184,7 @@ describe('status command', () => {
184
184
 
185
185
  const mockAnalyze = {
186
186
  summarize: jest.fn().mockReturnValue([
187
- { constraintId: 'test_guide', level: 'guideline', passRate: 0.9, totalChecks: 10, bypassRate: 0 },
187
+ { constraintId: 'test_guide', level: 'guideline', passRate: 0.9, failRate: 0.1, totalChecks: 10 },
188
188
  ]),
189
189
  detectAnomalies: jest.fn().mockReturnValue([]),
190
190
  };
@@ -193,21 +193,6 @@ describe('status command', () => {
193
193
  await status({});
194
194
  expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Guidelines'));
195
195
  });
196
-
197
- it('应该显示 Tips 统计', async () => {
198
- mockFs.readFileSync.mockReturnValue('{"constraintId":"test"}');
199
-
200
- const mockAnalyze = {
201
- summarize: jest.fn().mockReturnValue([
202
- { constraintId: 'test_tip', level: 'tip', passRate: 1, totalChecks: 5, bypassRate: 0 },
203
- ]),
204
- detectAnomalies: jest.fn().mockReturnValue([]),
205
- };
206
- (MockTraceAnalyzer as any).mockImplementation(() => mockAnalyze);
207
-
208
- await status({});
209
- expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Tips'));
210
- });
211
196
  });
212
197
 
213
198
  describe('异常模式', () => {
@@ -291,7 +276,7 @@ describe('status command', () => {
291
276
 
292
277
  const mockAnalyze = {
293
278
  summarize: jest.fn().mockReturnValue([
294
- { constraintId: 'test_guide', level: 'guideline', passRate: 0.6, totalChecks: 10, bypassRate: 0.1 },
279
+ { constraintId: 'test_guide', level: 'guideline', passRate: 0.6, failRate: 0.4, totalChecks: 10 },
295
280
  ]),
296
281
  detectAnomalies: jest.fn().mockReturnValue([]),
297
282
  };
@@ -2,17 +2,16 @@
2
2
  * harness check 命令
3
3
  *
4
4
  * 检查约束是否满足(check 层:Iron Laws / Guidelines;prompt 层仅注入不检查)
5
- * 工单 23:触发条件与证据检测迁至 core/constraints/context-builder;--preset 经 mergeConstraints 生效
6
- * ADR-0001:约束集统一走 mergeConstraints 生效集链路(preset/config 禁用/custom/scenes)
5
+ * 工单 23:触发条件与证据检测迁至 core/constraints/context-builder
6
+ * ADR-0001:约束集统一走 getMergedConstraintsConfig 生效集链路(preset/config 禁用/custom/scenes)
7
7
  */
8
8
 
9
9
  import chalk from 'chalk';
10
10
  import * as fs from 'fs';
11
11
  import * as path from 'path';
12
12
  import { constraintChecker } from '../../core/constraints/checker';
13
- import { getTraceCollector } from '../../monitoring/traces';
14
13
  import { IRON_LAWS, GUIDELINES, PROMPTS } from '../../core/constraints/definitions';
15
- import { ProjectConfigLoader } from '../../core/project-config-loader';
14
+ import { getMergedConstraintsConfig } from '../../core/effective-constraints';
16
15
  import { buildConstraintContext } from '../../core/constraints/context-builder';
17
16
  import { detectInjectionDrift } from '../../core/constraints/injection-drift';
18
17
  import { DEFAULT_TRACE_FILE } from '../../types/trace';
@@ -37,18 +36,12 @@ export async function check(options: CheckOptions): Promise<void> {
37
36
  console.log(chalk.gray(`预设: ${options.preset}`));
38
37
 
39
38
  try {
40
- // 加载项目级自定义约束
41
39
  const projectPath = options.projectPath || process.cwd();
42
- const configLoader = new ProjectConfigLoader(projectPath);
43
- configLoader.load();
44
- constraintChecker.setTraceRecorder(getTraceCollector());
45
40
 
46
41
  // 生效约束集(ADR-0001):内置 → preset → config.yml 禁用 → custom 追加 → scenes 过滤。
47
- // --preset 仅在没有项目自定义配置时覆盖 config.yml 的 preset(保持工单 23 语义:
48
- // 项目自定义配置优先于 CLI 预设)。
49
- const merged = configLoader.hasCustomConfig()
50
- ? configLoader.mergeConstraints()
51
- : configLoader.mergeConstraints({ preset: options.preset || 'standard' });
42
+ // --preset 仅在没有项目自定义配置时覆盖 config.yml 的 preset(工单 23 语义:
43
+ // 项目自定义配置优先于 CLI 预设),优先级规则收在 getMergedConstraintsConfig 一处。
44
+ const merged = getMergedConstraintsConfig(projectPath, { preset: options.preset });
52
45
  if (merged.custom.length > 0) {
53
46
  console.log(chalk.gray(`自定义约束: ${merged.custom.length} 条`));
54
47
  }
@@ -199,23 +192,7 @@ async function getSmartHint(projectPath: string): Promise<string | null> {
199
192
  hints.push('📊 记录已足够,运行 harness status 查看统计');
200
193
  state.shownHints.push('trace_50');
201
194
  }
202
-
203
- // 条件 2: 检查异常趋势(简单检查绕过率)
204
- const bypassCount = lines.filter(line => {
205
- try {
206
- const trace = JSON.parse(line);
207
- return trace.result === 'bypassed';
208
- } catch {
209
- return false;
210
- }
211
- }).length;
212
-
213
- const bypassRate = traceCount > 10 ? bypassCount / traceCount : 0;
214
- if (bypassRate > 0.3 && !state.shownHints.includes('high_bypass')) {
215
- hints.push('⚠️ 发现异常趋势,建议运行 harness status 查看详情');
216
- state.shownHints.push('high_bypass');
217
- }
218
-
195
+
219
196
  // 保存状态
220
197
  if (hints.length > 0) {
221
198
  fs.mkdirSync(path.dirname(statePath), { recursive: true });
@@ -242,14 +219,11 @@ export function listLaws(): void {
242
219
  });
243
220
 
244
221
  // Guidelines
245
- console.log(chalk.yellow('🟡 指导原则 (Guidelines) - 优先建议,有例外:\n'));
222
+ console.log(chalk.yellow('🟡 指导原则 (Guidelines) - 优先建议,违背发警告但不阻止:\n'));
246
223
  Object.values(GUIDELINES).forEach(constraint => {
247
224
  console.log(chalk.yellow(` ${constraint.id}`));
248
225
  console.log(chalk.gray(` ${constraint.rule}`));
249
226
  console.log(chalk.gray(` ${constraint.message}`));
250
- if (constraint.exceptions && constraint.exceptions.length > 0) {
251
- console.log(chalk.gray(` 例外: ${constraint.exceptions.join(', ')}`));
252
- }
253
227
  console.log();
254
228
  });
255
229
 
@@ -81,6 +81,8 @@ export interface CommandDefinition {
81
81
  subcommands?: Record<string, CommandSubcommand>;
82
82
  /** false = 未知位置参数不报错、落回默认 action(spec 的文件参数用法) */
83
83
  subcommandStrict?: boolean;
84
+ /** true = 有 subcommands 但无位置参数时运行默认 action 而非显示帮助(门禁命令语义) */
85
+ bareRunsAction?: boolean;
84
86
  /** 选项条件路由(匹配时替代默认 action 执行) */
85
87
  optionRoutes?: CommandOptionRoute[];
86
88
  /** 默认 action 实参构造(缺省为 [options]) */
@@ -37,19 +37,15 @@ export interface InitOptions {
37
37
 
38
38
  /**
39
39
  * 默认配置
40
+ *
41
+ * 只写有运行时消费者的字段:preset(ADR-0001 生效集链路由 mergeConstraints 消费)。
42
+ * 历史模板里的 enabled / ironLaws.enforceErrors / ironLaws.warnWarnings /
43
+ * validators.{checkpoint,passesGate,cso} 均为零消费者的死字段,不再写入;
44
+ * strict/standard/relaxed 三档差异曾只存在于这些死字段上(实为两档),
45
+ * 现在三档差异完全由 preset 键经生效集链路体现。
40
46
  */
41
47
  const DEFAULT_CONFIG = {
42
48
  preset: 'standard',
43
- enabled: true,
44
- ironLaws: {
45
- enforceErrors: true,
46
- warnWarnings: true,
47
- },
48
- validators: {
49
- checkpoint: true,
50
- passesGate: true,
51
- cso: false,
52
- },
53
49
  };
54
50
 
55
51
  /**
@@ -59,15 +55,6 @@ const PRESETS = {
59
55
  strict: {
60
56
  ...DEFAULT_CONFIG,
61
57
  preset: 'strict',
62
- ironLaws: {
63
- enforceErrors: true,
64
- warnWarnings: true,
65
- },
66
- validators: {
67
- checkpoint: true,
68
- passesGate: true,
69
- cso: true,
70
- },
71
58
  },
72
59
  standard: {
73
60
  ...DEFAULT_CONFIG,
@@ -76,10 +63,6 @@ const PRESETS = {
76
63
  relaxed: {
77
64
  ...DEFAULT_CONFIG,
78
65
  preset: 'relaxed',
79
- ironLaws: {
80
- enforceErrors: true,
81
- warnWarnings: false,
82
- },
83
66
  },
84
67
  };
85
68
 
@@ -483,7 +466,6 @@ custom_constraints:
483
466
  # rule: "NO MOMENT.JS IMPORTS"
484
467
  # message: "禁止使用 moment.js,请使用 date-fns 或 dayjs"
485
468
  # trigger: ["code_implementation"]
486
- # exceptions: ["legacy_migration"]
487
469
 
488
470
  # 示例 3:要求特定的文件命名
489
471
  # my_project_component_naming:
@@ -492,19 +474,6 @@ custom_constraints:
492
474
  # rule: "REACT COMPONENTS SHOULD BE PASCAL CASE"
493
475
  # message: "React 组件文件名应使用 PascalCase"
494
476
  # trigger: ["file_creation"]
495
-
496
- # ========================================
497
- # 扩展内置约束的例外
498
- # ========================================
499
-
500
- # 如果需要为内置约束添加项目特定的例外,
501
- # 可以在 .harness/config.yml 中配置:
502
-
503
- # constraints:
504
- # no_fix_without_root_cause:
505
- # # 添加项目特定的例外
506
- # exceptions:
507
- # - my_custom_exception
508
477
  `;
509
478
 
510
479
  await fs.writeFile(customConstraintsPath, content, 'utf-8');
@@ -81,22 +81,7 @@ export async function knowledgeSearch(
81
81
  const store = new KnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath) });
82
82
  const queryEngine = new KnowledgeQuery(store);
83
83
 
84
- const budget = {
85
- phase: 'cli',
86
- maxTokens: 10000,
87
- maxEntries: options.limit || 20,
88
- focusTypes: [] as KnowledgeSubsystem[],
89
- };
90
-
91
- const result = queryEngine.query(budget);
92
-
93
- // 简单文本匹配过滤
94
- const q = query.toLowerCase();
95
- const matched = result.entries.filter(e =>
96
- e.title.toLowerCase().includes(q) ||
97
- e.content.toLowerCase().includes(q) ||
98
- e.tags.some(t => t.toLowerCase().includes(q))
99
- );
84
+ const matched = queryEngine.search(query, { limit: options.limit || 20 });
100
85
 
101
86
  if (options.json) {
102
87
  console.log(JSON.stringify({ query, total: matched.length, entries: matched }, null, 2));
@@ -7,7 +7,6 @@
7
7
  import chalk from 'chalk';
8
8
  import * as fs from 'fs/promises';
9
9
  import { ConstraintChecker } from '../../core/constraints/checker';
10
- import { getTraceCollector } from '../../monitoring/traces';
11
10
  import { IRON_LAWS, GUIDELINES, PROMPTS } from '../../core/constraints/definitions';
12
11
  import { executeWithCollect } from '../../failure/constraint-handler';
13
12
  import type { ConstraintContext } from '../../types/constraint';
@@ -48,7 +47,6 @@ export async function report(options: ReportOptions): Promise<void> {
48
47
 
49
48
  const projectPath = options.projectPath || process.cwd();
50
49
  const checker = ConstraintChecker.getInstance();
51
- checker.setTraceRecorder(getTraceCollector());
52
50
 
53
51
  const allConstraints = { ...IRON_LAWS, ...GUIDELINES, ...PROMPTS };
54
52
  const totalConstraints = Object.keys(allConstraints).length;
@@ -109,7 +109,7 @@ export async function status(options: StatusOptions): Promise<void> {
109
109
  const status = s.passRate >= 1 ? '✅' : '❌';
110
110
  console.log(` ${status} ${s.constraintId}`);
111
111
  if (options.detail) {
112
- console.log(chalk.gray(` 检查: ${s.totalChecks} | 通过: ${(s.passRate * 100).toFixed(0)}% | 绕过: ${(s.bypassRate * 100).toFixed(0)}%`));
112
+ console.log(chalk.gray(` 检查: ${s.totalChecks} | 通过: ${(s.passRate * 100).toFixed(0)}% | 失败: ${(s.failRate * 100).toFixed(0)}%`));
113
113
  }
114
114
  });
115
115
  console.log();
@@ -123,22 +123,12 @@ export async function status(options: StatusOptions): Promise<void> {
123
123
  const status = s.passRate >= 0.8 ? '✅' : s.passRate >= 0.5 ? '⚠️' : '❌';
124
124
  console.log(` ${status} ${s.constraintId}`);
125
125
  if (options.detail) {
126
- console.log(chalk.gray(` 检查: ${s.totalChecks} | 通过: ${(s.passRate * 100).toFixed(0)}% | 绕过: ${(s.bypassRate * 100).toFixed(0)}%`));
126
+ console.log(chalk.gray(` 检查: ${s.totalChecks} | 通过: ${(s.passRate * 100).toFixed(0)}% | 失败: ${(s.failRate * 100).toFixed(0)}%`));
127
127
  }
128
128
  });
129
129
  console.log();
130
130
  }
131
131
 
132
- // Tips
133
- const tipSummaries = summaries.filter((s: TraceSummary) => s.level === 'tip');
134
- if (tipSummaries.length > 0) {
135
- console.log(chalk.blue('🔵 Tips:'));
136
- tipSummaries.forEach((s: TraceSummary) => {
137
- console.log(` 💡 ${s.constraintId}`);
138
- });
139
- console.log();
140
- }
141
-
142
132
  // 异常检测
143
133
  if (anomalies.length > 0) {
144
134
  console.log(chalk.yellow(`⚠️ 发现 ${anomalies.length} 个异常`));
@@ -1,11 +1,34 @@
1
1
  /**
2
- * 上下文管理模块
2
+ * 上下文管理模块(ADR-0003:显式清单,禁 export *)
3
3
  *
4
4
  * Token 预算 + 会话压缩 + 知识注入
5
5
  */
6
6
 
7
- export * from './types';
8
- export * from './token-budget';
9
- export * from './compaction';
10
- export * from './session-manager';
11
- export * from './knowledge-injector';
7
+ // 类型
8
+ export type {
9
+ CompactionConfig,
10
+ CompactionLevel,
11
+ ContextSource,
12
+ ContextSourceType,
13
+ ContextUsageSnapshot,
14
+ SessionCheckpoint,
15
+ SessionEvent,
16
+ SessionEventType,
17
+ SessionHandle,
18
+ SessionMessage,
19
+ } from './types';
20
+ export { DEFAULT_COMPACTION_CONFIG } from './types';
21
+
22
+ // Token 预算
23
+ export { AdaptiveTokenBudget, TokenBudget, TokenEstimator } from './token-budget';
24
+
25
+ // 会话压缩
26
+ export { SessionCompaction } from './compaction';
27
+ export type { CompactionResult } from './compaction';
28
+
29
+ // 会话管理
30
+ export { SessionManager } from './session-manager';
31
+
32
+ // 知识注入
33
+ export { KnowledgeInjector } from './knowledge-injector';
34
+ export type { InjectionConfig, InjectionResult } from './knowledge-injector';
@@ -4,12 +4,13 @@
4
4
  约束引擎核心:check/prompt 二元约束系统(ADR-0001)、生效集合并(effective-constraints)、检查点验证器(CSO/passes-gate)、会话管理、Spec 验证器、项目配置加载。
5
5
 
6
6
  ## 核心导出
7
- - `constraints/` — 约束定义(IRON_LAWS/GUIDELINES/PROMPTS;TIPS 已退役为空表) + 检查引擎(ConstraintChecker) + 拦截器(ConstraintInterceptor) + 缓存(CheckCache:TTL 缓存 + 计数采样,H6/G5 起公开导出) + 注入渲染(injection-renderer) + Agent prompt 渲染(agent-prompt-renderer:trigger 参数化分组渲染,role 路由留 studio,H6/G6)/漂移校验(injection-drift)/使用统计(usage-report)
8
- - `effective-constraints.ts` — `getEffectiveConstraints(projectRoot)`:全仓唯一生效集来源(内置 → preset → config.yml 禁用(内置与 custom 同效)→ custom 追加(禁用/已退役的不追加)→ scenes 过滤);`lintEffectiveConfig` 配置诊断
7
+ - `constraints/` — 约束定义(IRON_LAWS/GUIDELINES/PROMPTS) + 检查引擎(ConstraintChecker,拦截统一由 checkBeforeExecution 承担,ADR-0004) + 缓存(CheckCache:TTL 缓存 + 计数采样,H6/G5 起公开导出) + 注入渲染(injection-renderer) + Agent prompt 渲染(agent-prompt-renderer:trigger 参数化分组渲染,role 路由留 studio,H6/G6)/漂移校验(injection-drift)/使用统计(usage-report);CheckEnv 生产侧唯一构造点 `buildCheckEnv(context, providers|'none')`(checkers/types.ts:providers = 证据接线,'none' = 显式不接 → evidence flag checker 按契约 skip)
8
+ - `effective-constraints.ts` — `getEffectiveConstraints(projectRoot, {preset?})`:全仓唯一生效集来源(内置 → preset → config.yml 禁用(内置与 custom 同效)→ custom 追加(禁用/已退役的不追加)→ scenes 过滤);`getMergedConstraintsConfig(projectRoot, {preset?})`:同链路的完整 MergedConstraintsConfig 形状(含 disabled/custom/unknownIds),内置工单 23 优先级规则(--preset 仅在无项目自定义配置时生效),check 命令经此入口;`lintEffectiveConfig` 配置诊断
9
+ - `effective-set.ts` — `filterEnabledEntries(knownIds, entries, {onUnknownId})`:约束侧(collect)与门禁侧(throw)共用的 config 条目筛选器
9
10
  - `validators/` — checkpoints、passes-gate、CSO 验证器
10
11
  - `session/` — 会话管理
11
12
  - `spec/validator` — SpecValidator
12
- - `project-config-loader` — 项目配置加载 + 约束合并
13
+ - `project-config-loader` — 项目配置加载 + 约束合并(mergeConstraints 内含 preset 裁剪:presets/ 纯数据 + 未知名回落 standard,禁用到未知 id 经 effective-set 共享筛选器 collect 模式)
13
14
 
14
15
  ## 依赖关系
15
16
  - 被所有模块依赖(基础层,无上层依赖)
@@ -0,0 +1,80 @@
1
+ /**
2
+ * effective-set 共享筛选器测试
3
+ *
4
+ * 覆盖约束侧(collect)与门禁侧(throw)两种 onUnknownId 模式。
5
+ */
6
+
7
+ import { filterEnabledEntries } from '../effective-set';
8
+
9
+ const KNOWN = new Set(['a', 'b', 'c']);
10
+
11
+ describe('filterEnabledEntries', () => {
12
+ describe('onUnknownId: collect(约束侧)', () => {
13
+ it('已知 id 全部通过,enabled:false 收进 disabledIds', () => {
14
+ const result = filterEnabledEntries(
15
+ KNOWN,
16
+ { a: { enabled: false }, b: { enabled: true }, c: {} },
17
+ { onUnknownId: 'collect' }
18
+ );
19
+ expect(result.disabledIds).toEqual(['a']);
20
+ expect(result.unknownIds).toEqual([]);
21
+ });
22
+
23
+ it('未知 id 静默忽略并收集进 unknownIds', () => {
24
+ const result = filterEnabledEntries(
25
+ KNOWN,
26
+ { a: {}, ghost: { enabled: false } },
27
+ { onUnknownId: 'collect' }
28
+ );
29
+ expect(result.unknownIds).toEqual(['ghost']);
30
+ // 未知 id 带 enabled:false 同样计入 disabledIds(历史行为:delete 空桶为 no-op)
31
+ expect(result.disabledIds).toEqual(['ghost']);
32
+ });
33
+
34
+ it('未知 id 无 enabled 标记时只收集不进 disabledIds', () => {
35
+ const result = filterEnabledEntries(
36
+ KNOWN,
37
+ { ghost: {} },
38
+ { onUnknownId: 'collect' }
39
+ );
40
+ expect(result.unknownIds).toEqual(['ghost']);
41
+ expect(result.disabledIds).toEqual([]);
42
+ });
43
+
44
+ it('空 entries → 空结果', () => {
45
+ const result = filterEnabledEntries(KNOWN, {}, { onUnknownId: 'collect' });
46
+ expect(result).toEqual({ disabledIds: [], unknownIds: [] });
47
+ });
48
+ });
49
+
50
+ describe('onUnknownId: throw(门禁侧)', () => {
51
+ it('未知 id 抛错(默认消息)', () => {
52
+ expect(() =>
53
+ filterEnabledEntries(KNOWN, { nope: { enabled: false } }, { onUnknownId: 'throw' })
54
+ ).toThrow(/未注册的 id "nope"/);
55
+ });
56
+
57
+ it('未知 id 抛错(unknownIdError 定制消息)', () => {
58
+ expect(() =>
59
+ filterEnabledEntries(
60
+ KNOWN,
61
+ { nope: {} },
62
+ {
63
+ onUnknownId: 'throw',
64
+ unknownIdError: id => `gates.${id} 引用了未注册的门禁。可用门禁: a, b, c。`,
65
+ }
66
+ )
67
+ ).toThrow(/gates\.nope 引用了未注册的门禁/);
68
+ });
69
+
70
+ it('已知 id 的 enabled:false 正常收集,不抛错', () => {
71
+ const result = filterEnabledEntries(
72
+ KNOWN,
73
+ { a: { enabled: false }, b: { enabled: true } },
74
+ { onUnknownId: 'throw' }
75
+ );
76
+ expect(result.disabledIds).toEqual(['a']);
77
+ expect(result.unknownIds).toEqual([]);
78
+ });
79
+ });
80
+ });
@@ -9,9 +9,16 @@
9
9
 
10
10
  import * as fs from 'fs';
11
11
  import { IRON_LAWS, GUIDELINES } from './definitions';
12
+ import { COMMAND_DEFINITIONS } from '../../cli/commands/definitions';
13
+ import { GATE_DEFINITIONS } from '../../gates/definitions';
12
14
  import { FreshnessRunner } from './doc-freshness/runner';
13
15
  import type { DocFreshnessCheck } from '../../types/project-config';
14
16
 
17
+ /** CLI 命令数 = 非门禁命令定义 + 门禁命令定义(ADR-0002:定义表是命令形状单一来源) */
18
+ function cliCommandCount(): number {
19
+ return COMMAND_DEFINITIONS.length + GATE_DEFINITIONS.filter(g => g.cli).length;
20
+ }
21
+
15
22
  /** 匹配表格单元格中的源码文件条目(如 `src/foo.ts`、`foo.tsx`) */
16
23
  const FILE_CELL_REGEX = /\|\s*([^|]+?\.(?:ts|tsx|js|jsx))\s*\|/g;
17
24
 
@@ -104,41 +111,40 @@ export function aggregateToSourceSubdir(root: string, file: string): string {
104
111
 
105
112
  // ── 能力清单计数 ────────────────────────────────────────────
106
113
 
114
+ /**
115
+ * 能力清单统计规则单份定义(ADR-0008:check/write 两方向共用,
116
+ * 此前 label+pattern 在 buildCapabilityChecks 与 updateCapabilityCounts 各写一遍)
117
+ *
118
+ * - label:CAPABILITIES.md 计数行 label(check 的 DocFreshnessCheck.label +
119
+ * write 的替换文本前缀,如 `Quality Gates (6)`)
120
+ * - pattern:同时供 check(doc_regex_count 字符串 pattern,捕获组为文档计数)
121
+ * 与 write(编译为替换 regex)
122
+ * - actual:定义表实际计数(ADR-0002 单一来源)
123
+ */
124
+ interface CapabilityCountRule {
125
+ label: string;
126
+ pattern: string;
127
+ actual: () => number;
128
+ }
129
+
130
+ const CAPABILITY_COUNT_RULES: CapabilityCountRule[] = [
131
+ { label: 'CLI Commands', pattern: 'CLI Commands\\s*\\((\\d+)\\)', actual: cliCommandCount },
132
+ { label: 'Quality Gates', pattern: 'Quality Gates?\\s*\\((\\d+)\\)', actual: () => GATE_DEFINITIONS.length },
133
+ { label: 'Iron Laws', pattern: 'Iron Laws?\\s*\\((\\d+)\\)', actual: () => Object.keys(IRON_LAWS).length },
134
+ { label: 'Guidelines', pattern: 'Guidelines?\\s*\\((\\d+)\\)', actual: () => Object.keys(GUIDELINES).length },
135
+ ];
136
+
107
137
  /**
108
138
  * 构建 CAPABILITIES.md 能力清单格式的检查配置
109
139
  */
110
140
  function buildCapabilityChecks(): DocFreshnessCheck[] {
111
- return [
112
- {
113
- type: 'doc_regex_count',
114
- doc: 'CAPABILITIES.md',
115
- label: 'CLI Commands',
116
- pattern: 'CLI Commands\\s*\\((\\d+)\\)',
117
- // index.ts(已删 barrel)与 definitions.ts(命令注册表纯数据)不是命令实现,不计入
118
- actual: { kind: 'dir_count', path: 'src/cli/commands', extension: '.ts', exclude: ['index.ts', 'definitions.ts'] },
119
- },
120
- {
121
- type: 'doc_regex_count',
122
- doc: 'CAPABILITIES.md',
123
- label: 'Quality Gates',
124
- pattern: 'Quality Gates?\\s*\\((\\d+)\\)',
125
- actual: { kind: 'dir_count', path: 'src/gates', extension: '.ts', exclude: ['index.ts', 'types.ts'] },
126
- },
127
- {
128
- type: 'doc_regex_count',
129
- doc: 'CAPABILITIES.md',
130
- label: 'Iron Laws',
131
- pattern: 'Iron Laws?\\s*\\((\\d+)\\)',
132
- actual: { kind: 'const_count', value: Object.keys(IRON_LAWS).length },
133
- },
134
- {
135
- type: 'doc_regex_count',
136
- doc: 'CAPABILITIES.md',
137
- label: 'Guidelines',
138
- pattern: 'Guidelines?\\s*\\((\\d+)\\)',
139
- actual: { kind: 'const_count', value: Object.keys(GUIDELINES).length },
140
- },
141
- ];
141
+ return CAPABILITY_COUNT_RULES.map(rule => ({
142
+ type: 'doc_regex_count' as const,
143
+ doc: 'CAPABILITIES.md',
144
+ label: rule.label,
145
+ pattern: rule.pattern,
146
+ actual: { kind: 'const_count' as const, value: rule.actual() },
147
+ }));
142
148
  }
143
149
 
144
150
  /**
@@ -164,26 +170,14 @@ export function checkCapabilityCounts(
164
170
  /**
165
171
  * 更新 CAPABILITIES.md 中的能力清单计数(write 模式)
166
172
  *
167
- * 使用 FreshnessRunner 获取实际计数,然后 regex 替换文档计数行。
173
+ * 命令/门禁计数取自定义表(ADR-0002 单一来源),regex 替换文档计数行;
174
+ * 规则与 check 方向共用 CAPABILITY_COUNT_RULES(ADR-0008)。
168
175
  */
169
- export function updateCapabilityCounts(content: string, projectPath: string): string {
170
- const runner = new FreshnessRunner();
171
-
172
- const cliCount = runner.countFromDir('src/cli/commands', '.ts', ['index.ts', 'definitions.ts'], projectPath);
173
- const gateCount = runner.countFromDir('src/gates', '.ts', ['index.ts', 'types.ts'], projectPath);
174
- const ironCount = Object.keys(IRON_LAWS).length;
175
- const guideCount = Object.keys(GUIDELINES).length;
176
-
177
- const replacements: [RegExp, string][] = [
178
- [/CLI Commands\s*\(\d+\)/, `CLI Commands (${cliCount})`],
179
- [/Quality Gates?\s*\(\d+\)/, `Quality Gates (${gateCount})`],
180
- [/Iron Laws?\s*\(\d+\)/, `Iron Laws (${ironCount})`],
181
- [/Guidelines?\s*\(\d+\)/, `Guidelines (${guideCount})`],
182
- ];
183
-
184
- for (const [regex, replacement] of replacements) {
176
+ export function updateCapabilityCounts(content: string, _projectPath: string): string {
177
+ for (const rule of CAPABILITY_COUNT_RULES) {
178
+ const regex = new RegExp(rule.pattern);
185
179
  if (regex.test(content)) {
186
- content = content.replace(regex, replacement);
180
+ content = content.replace(regex, `${rule.label} (${rule.actual()})`);
187
181
  }
188
182
  }
189
183