@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
@@ -65,22 +65,21 @@ describe('TraceAnalyzer - 补充覆盖', () => {
65
65
  describe('compareWithPrevious', () => {
66
66
  it('应该计算环比变化', () => {
67
67
  const current: any[] = [
68
- { constraintId: 'test', passRate: 0.8, failRate: 0.2, bypassRate: 0.1, level: 'iron_law' },
68
+ { constraintId: 'test', passRate: 0.8, failRate: 0.2, level: 'iron_law' },
69
69
  ];
70
70
  const previous: any[] = [
71
- { constraintId: 'test', passRate: 0.6, failRate: 0.4, bypassRate: 0.2, level: 'iron_law' },
71
+ { constraintId: 'test', passRate: 0.6, failRate: 0.4, level: 'iron_law' },
72
72
  ];
73
73
 
74
74
  const result = analyzer.compareWithPrevious(current, previous);
75
-
75
+
76
76
  expect(result[0]?.changeFromLastPeriod?.passRateDelta).toBeCloseTo(0.2);
77
77
  expect(result[0]?.changeFromLastPeriod?.failRateDelta).toBeCloseTo(-0.2);
78
- expect(result[0]?.changeFromLastPeriod?.bypassRateDelta).toBeCloseTo(-0.1);
79
78
  });
80
79
 
81
80
  it('无历史数据应该不设置变化', () => {
82
81
  const current: any[] = [
83
- { constraintId: 'new_test', passRate: 0.8, failRate: 0.2, bypassRate: 0.1, level: 'iron_law' },
82
+ { constraintId: 'new_test', passRate: 0.8, failRate: 0.2, level: 'iron_law' },
84
83
  ];
85
84
  const previous: any[] = [];
86
85
 
@@ -93,7 +92,7 @@ describe('TraceAnalyzer - 补充覆盖', () => {
93
92
  describe('saveSummary/loadSummary', () => {
94
93
  it('应该保存和加载汇总', () => {
95
94
  const summaries: any[] = [
96
- { constraintId: 'test', passRate: 0.8, failRate: 0.2, bypassRate: 0.1, level: 'iron_law', totalChecks: 10 },
95
+ { constraintId: 'test', passRate: 0.8, failRate: 0.2, level: 'iron_law', totalChecks: 10 },
97
96
  ];
98
97
 
99
98
  analyzer.saveSummary(summaries);
@@ -157,7 +156,6 @@ describe('TraceAnalyzer - 补充覆盖', () => {
157
156
  level: 'iron_law',
158
157
  passRate: 0.8,
159
158
  failRate: 0.2,
160
- bypassRate: 0.1,
161
159
  totalChecks: 100,
162
160
  recentTrend: 'stable',
163
161
  },
@@ -190,46 +188,6 @@ describe('TraceAnalyzer - 补充覆盖', () => {
190
188
  });
191
189
  });
192
190
 
193
- describe('findMostCommon', () => {
194
- it('应该找出最常见元素', () => {
195
- // 通过 bypassReasons 统计来触发
196
- const traces: ExecutionTrace[] = [
197
- { constraintId: 'common_test', level: 'iron_law', timestamp: 1000, result: 'pass' },
198
- { constraintId: 'common_test', level: 'iron_law', timestamp: 2000, result: 'pass', bypassReason: 'reason_a' },
199
- { constraintId: 'common_test', level: 'iron_law', timestamp: 3000, result: 'pass', bypassReason: 'reason_a' },
200
- { constraintId: 'common_test', level: 'iron_law', timestamp: 4000, result: 'pass', bypassReason: 'reason_b' },
201
- ];
202
-
203
- const summaries = analyzer.summarize(traces);
204
-
205
- // 验证汇总结果存在
206
- expect(summaries.length).toBeGreaterThan(0);
207
- });
208
-
209
- it('应该通过 exceptionApplied 触发 findMostCommon', () => {
210
- const traces: ExecutionTrace[] = [
211
- { constraintId: 'exc_test', level: 'guideline', timestamp: 1000, result: 'pass', exceptionApplied: 'simple_typo' },
212
- { constraintId: 'exc_test', level: 'guideline', timestamp: 2000, result: 'pass', exceptionApplied: 'simple_typo' },
213
- { constraintId: 'exc_test', level: 'guideline', timestamp: 3000, result: 'pass', exceptionApplied: 'config_error' },
214
- ];
215
-
216
- const summaries = analyzer.summarize(traces);
217
- const summary = summaries.find(s => s.constraintId === 'exc_test');
218
-
219
- expect(summary?.exceptionCount).toBe(3);
220
- expect(summary?.mostCommonException).toBe('simple_typo');
221
- });
222
-
223
- it('无 exception 时 mostCommonException 应该是 undefined', () => {
224
- const traces: ExecutionTrace[] = [
225
- { constraintId: 'no_exc', level: 'iron_law', timestamp: 1000, result: 'pass' },
226
- ];
227
-
228
- const summaries = analyzer.summarize(traces);
229
- expect(summaries[0]?.mostCommonException).toBeUndefined();
230
- });
231
- });
232
-
233
191
  describe('detectAnomalies - 更多异常类型', () => {
234
192
  it('应该检测 rising_fail_rate', () => {
235
193
  // 前半段全 fail,后半段全 pass → rising 趋势
@@ -253,44 +211,6 @@ describe('TraceAnalyzer - 补充覆盖', () => {
253
211
  const risingFail = anomalies.find(a => a.type === 'rising_fail_rate');
254
212
  expect(risingFail).toBeDefined();
255
213
  });
256
-
257
- it('应该检测 rising_bypass_rate', () => {
258
- // 前半段全 fail,后半段混合 pass+bypass → rising 趋势
259
- // bypassRate 需要 > 0.1,且 trend === 'rising'
260
- const traces: ExecutionTrace[] = [];
261
- for (let i = 0; i < 6; i++) {
262
- traces.push({ constraintId: 'rising_bypass', level: 'guideline', timestamp: 1000 + i * 100, result: 'fail' });
263
- }
264
- for (let i = 6; i < 14; i++) {
265
- // 后半段有 pass 也有 bypass,使 passRate 上升(rising),同时 bypassRate > 0.1
266
- traces.push({ constraintId: 'rising_bypass', level: 'guideline', timestamp: 1000 + i * 100, result: i % 2 === 0 ? 'pass' : 'bypassed' });
267
- }
268
-
269
- const summaries = analyzer.summarize(traces);
270
- const anomalies = analyzer.detectAnomalies(summaries);
271
-
272
- const risingBypass = anomalies.find(a => a.type === 'rising_bypass_rate');
273
- expect(risingBypass).toBeDefined();
274
- });
275
-
276
- it('应该检测 exception_overuse', () => {
277
- const traces: ExecutionTrace[] = [];
278
- for (let i = 0; i < 10; i++) {
279
- traces.push({
280
- constraintId: 'exc_overuse',
281
- level: 'guideline',
282
- timestamp: 1000 + i * 100,
283
- result: 'pass',
284
- exceptionApplied: i < 8 ? 'simple_typo' : undefined,
285
- });
286
- }
287
-
288
- const summaries = analyzer.summarize(traces);
289
- const anomalies = analyzer.detectAnomalies(summaries);
290
-
291
- const excOveruse = anomalies.find(a => a.type === 'exception_overuse');
292
- expect(excOveruse).toBeDefined();
293
- });
294
214
  });
295
215
 
296
216
  describe('createAnalyzer 工厂函数', () => {
@@ -300,7 +220,7 @@ describe('TraceAnalyzer - 补充覆盖', () => {
300
220
  });
301
221
 
302
222
  it('应该支持自定义配置', () => {
303
- const a = createAnalyzer({ thresholds: { bypassRate: 0.05 } });
223
+ const a = createAnalyzer({ thresholds: { failRate: 0.05 } });
304
224
  expect(a).toBeDefined();
305
225
  });
306
226
  });
@@ -75,11 +75,11 @@ describe('TraceAnalyzer', () => {
75
75
  });
76
76
 
77
77
  describe('detectAnomalies', () => {
78
- it('应该检测高绕过率异常', () => {
78
+ it('应该检测失败率异常', () => {
79
79
  const traces: ExecutionTrace[] = [
80
- { constraintId: 'test', level: 'guideline', timestamp: 1000, result: 'bypassed' },
81
- { constraintId: 'test', level: 'guideline', timestamp: 2000, result: 'bypassed' },
82
- { constraintId: 'test', level: 'guideline', timestamp: 3000, result: 'bypassed' },
80
+ { constraintId: 'test', level: 'guideline', timestamp: 1000, result: 'fail' },
81
+ { constraintId: 'test', level: 'guideline', timestamp: 2000, result: 'fail' },
82
+ { constraintId: 'test', level: 'guideline', timestamp: 3000, result: 'fail' },
83
83
  { constraintId: 'test', level: 'guideline', timestamp: 4000, result: 'pass' },
84
84
  ];
85
85
 
@@ -120,7 +120,6 @@ describe('TraceAnalyzer', () => {
120
120
  it('应该支持自定义阈值', () => {
121
121
  const customAnalyzer = new TraceAnalyzer(collector, {
122
122
  thresholds: {
123
- bypassRate: 0.1,
124
123
  failRate: 0.2,
125
124
  },
126
125
  });
@@ -104,17 +104,6 @@ describe('TraceCollector', () => {
104
104
  });
105
105
  });
106
106
 
107
- describe('recordBypass', () => {
108
- it('应该记录绕过 trace', () => {
109
- collector.recordBypass('no_bypass_checkpoint', 'iron_law', 'Emergency fix');
110
-
111
- const traces = collector.read();
112
- expect(traces.length).toBe(1);
113
- expect(traces[0].result).toBe('bypassed');
114
- expect(traces[0].bypassReason).toBe('Emergency fix');
115
- });
116
- });
117
-
118
107
  describe('read', () => {
119
108
  it('应该返回所有 traces', () => {
120
109
  collector.record({
@@ -57,7 +57,7 @@ describe('TraceCollector', () => {
57
57
  test('should filter traces by constraint ID', () => {
58
58
  collector.recordPass('constraint_a', 'iron_law');
59
59
  collector.recordFail('constraint_b', 'guideline');
60
- collector.recordBypass('constraint_a', 'iron_law', 'user reason');
60
+ collector.recordFail('constraint_a', 'iron_law');
61
61
 
62
62
  const traces = collector.read({ constraintId: 'constraint_a' });
63
63
  expect(traces.length).toBe(2);
@@ -226,7 +226,7 @@ describe('TraceAnalyzer', () => {
226
226
  constraintId: 'constraint_b',
227
227
  level: 'iron_law',
228
228
  timestamp: Date.now() - i * 60 * 1000,
229
- result: i < 3 ? 'pass' : 'bypassed',
229
+ result: i < 3 ? 'pass' : 'fail',
230
230
  });
231
231
  }
232
232
 
@@ -243,26 +243,7 @@ describe('TraceAnalyzer', () => {
243
243
 
244
244
  const summaryB = summaries.find(s => s.constraintId === 'constraint_b');
245
245
  expect(summaryB).toBeDefined();
246
- expect(summaryB!.bypassRate).toBeCloseTo(0.4, 1);
247
- });
248
-
249
- test('should detect high bypass rate anomaly', () => {
250
- // 记录高绕过率的 traces
251
- for (let i = 0; i < 10; i++) {
252
- collector.record({
253
- constraintId: 'problematic_constraint',
254
- level: 'guideline',
255
- timestamp: Date.now(),
256
- result: i < 3 ? 'pass' : 'bypassed', // 70% 绕过率
257
- });
258
- }
259
-
260
- const traces = collector.read();
261
- const summaries = analyzer.summarize(traces);
262
- const anomalies = analyzer.detectAnomalies(summaries);
263
-
264
- expect(anomalies.length).toBeGreaterThan(0);
265
- expect(anomalies.some(a => a.type === 'high_bypass_rate')).toBe(true);
246
+ expect(summaryB!.failRate).toBeCloseTo(0.4, 1);
266
247
  });
267
248
 
268
249
  test('should detect rising fail rate anomaly', () => {
@@ -10,7 +10,7 @@ H5(#44)起:
10
10
  ## 核心导出
11
11
  - `COMMAND_DEFINITIONS`(definitions.ts)— 全部非门禁命令定义(纯数据模块,禁止 import 命令实现)
12
12
  - 各命令文件:check / validate / passes-gate / init / report / status / spec / sync-docs / knowledge / sdd / failure / posteval-plan / release / analyze-sessions / update-user-model / constraints / doc-freshness-check / spec-baseline-check
13
- - 6 门禁命令实现在 `acceptance` / `command` / `contract` / `performance` / `review` / `security`(其 CLI 元数据在 `src/gates/definitions.ts`)
13
+ - 6 门禁命令实现在 `acceptance` / `command` / `contract` / `performance` / `review` / `security`(其 CLI 元数据在 `src/gates/definitions.ts`,形状同为 `CommandDefinition`,ADR-0007)
14
14
 
15
15
  `constraints` 下挂治理子命令:`constraints report`(使用统计 + 退役候选诊断 + 配置健康 + 注入漂移,`--export` 脱敏)、`constraints retire`(交互选择 + 人确认退役;带 id 直达需显式 `--yes`(#24 人确认闸门),无 `--yes` 报错 + 非零退出码且不落盘;内置落 config.yml retired 元数据,custom 落 custom-constraints.yml 条目 retired 段(#82 D6 一处真相)+ KnowledgeStore 沉淀 + CLAUDE.md 注入段同步)。
16
16
 
@@ -31,4 +31,4 @@ H5(#44)起:
31
31
  ## 注意事项
32
32
  - 新增命令需同步更新 CLAUDE.md / CAPABILITIES.md / src/CONTEXT.md
33
33
  - knowledge 命令包含 13 个子操作(list/search/import/decay/stats/upsert/sync-status/sync-rag/audit/snapshot/migrate/index/health)
34
- - 特殊路由(选项条件、子命令兜底、退出码处理)表达在定义表的 optionRoutes / subcommands / afterRun 字段,bin 是纯通用引擎、不含单命令知识
34
+ - 特殊路由(选项条件、子命令兜底、退出码处理、裸跑语义)表达在定义表的 optionRoutes / subcommands / subcommandStrict / bareRunsAction / afterRun 字段,bin 是纯通用引擎、不含单命令知识
@@ -34,13 +34,16 @@ jest.mock('../../../core/constraints/checker', () => ({
34
34
  },
35
35
  }));
36
36
 
37
- // Mock ProjectConfigLoader
38
- jest.mock('../../../core/project-config-loader', () => ({
39
- ProjectConfigLoader: jest.fn().mockImplementation(() => ({
40
- load: jest.fn(),
41
- hasCustomConfig: jest.fn().mockReturnValue(false),
42
- mergeConstraints: jest.fn().mockReturnValue({ custom: [], disabled: [] }),
43
- })),
37
+ // Mock effective-constraints(ADR-0001:check 经 getMergedConstraintsConfig 走生效集链路)
38
+ jest.mock('../../../core/effective-constraints', () => ({
39
+ getMergedConstraintsConfig: jest.fn().mockReturnValue({
40
+ ironLaws: {},
41
+ guidelines: {},
42
+ prompts: {},
43
+ custom: [],
44
+ disabled: [],
45
+ unknownIds: [],
46
+ }),
44
47
  }));
45
48
 
46
49
  // Mock chalk
@@ -5,7 +5,7 @@
5
5
  import { check, listLaws } from '../check';
6
6
  import * as fs from 'fs';
7
7
  import { constraintChecker } from '../../../core/constraints/checker';
8
- import { ProjectConfigLoader } from '../../../core/project-config-loader';
8
+ import { getMergedConstraintsConfig } from '../../../core/effective-constraints';
9
9
  import { execAsync } from '../../../utils/exec';
10
10
 
11
11
  // Mock fs
@@ -45,13 +45,16 @@ jest.mock('../../../core/constraints/checker', () => ({
45
45
  },
46
46
  }));
47
47
 
48
- // Mock ProjectConfigLoader
49
- jest.mock('../../../core/project-config-loader', () => ({
50
- ProjectConfigLoader: jest.fn().mockImplementation(() => ({
51
- load: jest.fn(),
52
- hasCustomConfig: jest.fn().mockReturnValue(false),
53
- mergeConstraints: jest.fn().mockReturnValue({ custom: [], disabled: [] }),
54
- })),
48
+ // Mock effective-constraints(ADR-0001:check 经 getMergedConstraintsConfig 走生效集链路)
49
+ jest.mock('../../../core/effective-constraints', () => ({
50
+ getMergedConstraintsConfig: jest.fn().mockReturnValue({
51
+ ironLaws: {},
52
+ guidelines: {},
53
+ prompts: {},
54
+ custom: [],
55
+ disabled: [],
56
+ unknownIds: [],
57
+ }),
55
58
  }));
56
59
 
57
60
  // Mock chalk
@@ -65,7 +68,7 @@ jest.mock('chalk', () => ({
65
68
 
66
69
  const mockFs = fs as jest.Mocked<typeof fs> & { readdirSync: jest.Mock };
67
70
  const mockChecker = constraintChecker as jest.Mocked<typeof constraintChecker>;
68
- const MockProjectConfigLoader = ProjectConfigLoader as jest.MockedClass<typeof ProjectConfigLoader>;
71
+ const mockGetMergedConfig = getMergedConstraintsConfig as jest.MockedFunction<typeof getMergedConstraintsConfig>;
69
72
  const mockExecAsync = execAsync as jest.MockedFunction<typeof execAsync>;
70
73
 
71
74
  describe('check command', () => {
@@ -73,6 +76,15 @@ describe('check command', () => {
73
76
 
74
77
  beforeEach(() => {
75
78
  jest.clearAllMocks();
79
+ // clearAllMocks 不清实现,显式恢复默认 merged config,避免用例间泄漏
80
+ mockGetMergedConfig.mockReturnValue({
81
+ ironLaws: {},
82
+ guidelines: {},
83
+ prompts: {},
84
+ custom: [],
85
+ disabled: [],
86
+ unknownIds: [],
87
+ });
76
88
  consoleSpy = jest.spyOn(console, 'log').mockImplementation();
77
89
  process.exitCode = 0;
78
90
  });
@@ -123,12 +135,14 @@ describe('check command', () => {
123
135
  });
124
136
 
125
137
  it('应该加载自定义约束', async () => {
126
- const mockLoader = {
127
- load: jest.fn(),
128
- hasCustomConfig: jest.fn().mockReturnValue(true),
129
- mergeConstraints: jest.fn().mockReturnValue({ custom: [{ id: 'custom', rule: 'test', message: 'test', level: 'iron_law', trigger: 'code_implementation', enforcement: 'checkpoint-required' }], disabled: ['disabled_constraint'] }),
130
- };
131
- (MockProjectConfigLoader as any).mockImplementation(() => mockLoader);
138
+ mockGetMergedConfig.mockReturnValue({
139
+ ironLaws: {},
140
+ guidelines: {},
141
+ prompts: {},
142
+ custom: ['custom'],
143
+ disabled: ['disabled_constraint'],
144
+ unknownIds: [],
145
+ });
132
146
 
133
147
  mockChecker.checkConstraints.mockResolvedValue({
134
148
  passed: true,
@@ -399,23 +413,6 @@ describe('check command', () => {
399
413
  expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('记录已足够'));
400
414
  });
401
415
 
402
- it('应该在绕过率高时提示查看详情', async () => {
403
- // 20 条记录,15 条 bypassed (75% > 30%)
404
- const traces = [
405
- ...Array(5).fill('{"result":"pass"}'),
406
- ...Array(15).fill('{"result":"bypassed"}'),
407
- ].join('\n');
408
- mockFs.existsSync.mockImplementation((p: any) => {
409
- if (p.includes('traces.log')) return true;
410
- if (p.includes('.state.json')) return false;
411
- return false;
412
- });
413
- mockFs.readFileSync.mockReturnValue(traces);
414
-
415
- await check({ preset: 'default', staged: false });
416
- expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('异常趋势'));
417
- });
418
-
419
416
  it('应该不重复显示已显示的提示', async () => {
420
417
  const traces = Array(50).fill('{"result":"pass"}').join('\n');
421
418
  mockFs.existsSync.mockReturnValue(true);
@@ -445,43 +442,6 @@ describe('check command', () => {
445
442
  expect(output).not.toContain('────────────────');
446
443
  });
447
444
 
448
- it('应该在绕过率低于 30% 时不提示', async () => {
449
- // 20 条记录,2 条 bypassed (10% < 30%)
450
- const traces = [
451
- ...Array(18).fill('{"result":"pass"}'),
452
- ...Array(2).fill('{"result":"bypassed"}'),
453
- ].join('\n');
454
- mockFs.existsSync.mockImplementation((p: any) => {
455
- if (p.includes('traces.log')) return true;
456
- if (p.includes('.state.json')) return false;
457
- return false;
458
- });
459
- mockFs.readFileSync.mockReturnValue(traces);
460
-
461
- await check({ preset: 'default', staged: false });
462
- const output = consoleSpy.mock.calls.map(c => c[0]).join('\n');
463
- expect(output).not.toContain('异常趋势');
464
- });
465
-
466
- it('应该处理无效 JSON trace 行', async () => {
467
- // 20 条记录,部分无效 JSON,部分 bypassed
468
- const traces = [
469
- ...Array(5).fill('invalid json'),
470
- ...Array(5).fill('{"result":"pass"}'),
471
- ...Array(10).fill('{"result":"bypassed"}'),
472
- ].join('\n');
473
- mockFs.existsSync.mockImplementation((p: any) => {
474
- if (p.includes('traces.log')) return true;
475
- if (p.includes('.state.json')) return false;
476
- return false;
477
- });
478
- mockFs.readFileSync.mockReturnValue(traces);
479
-
480
- await check({ preset: 'default', staged: false });
481
- // 15 条有效,10 条 bypassed,bypassRate = 10/20 = 0.5 > 0.3
482
- expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('异常趋势'));
483
- });
484
-
485
445
  it('应该保存状态文件当有提示时', async () => {
486
446
  const traces = Array(50).fill('{"result":"pass"}').join('\n');
487
447
  mockFs.existsSync.mockImplementation((p: any) => {
@@ -170,7 +170,7 @@ describe('buildConstraintsUsageReport', () => {
170
170
  const candidates = diagnoseRetireCandidates([
171
171
  {
172
172
  id: 'x', level: 'guideline',
173
- total: 60, pass: 0, fail: 0, skip: 60, bypassed: 0,
173
+ total: 60, pass: 0, fail: 0, skip: 60,
174
174
  evaluated: 0, failRate: 0,
175
175
  },
176
176
  ]);
@@ -2,7 +2,7 @@
2
2
  * knowledge 命令测试 — knowledgeAudit
3
3
  */
4
4
 
5
- import { knowledgeAudit, knowledgeStats, knowledgeHealth } from '../knowledge';
5
+ import { knowledgeAudit, knowledgeStats, knowledgeHealth, knowledgeSearch } from '../knowledge';
6
6
 
7
7
  // Mock chalk
8
8
  jest.mock('chalk', () => ({
@@ -233,3 +233,92 @@ describe('knowledgeHealth CLI', () => {
233
233
  expect(parsed.summary.staleEntries).toBe(1);
234
234
  });
235
235
  });
236
+
237
+ /**
238
+ * knowledgeSearch 回归测试 — harness#63
239
+ * bug:先按 token budget 截断再文本匹配,新条目(lastReferenced 为空、排序队尾)
240
+ * 在语料超过 budget 时永远进不了匹配阶段。
241
+ */
242
+ describe('knowledgeSearch CLI (harness#63)', () => {
243
+ const fs = require('fs');
244
+ const os = require('os');
245
+ const path = require('path');
246
+ const { FileKnowledgeStore } = require('../../../knowledge/store');
247
+
248
+ let tmpProject: string;
249
+ let knowledgeDir: string;
250
+ let consoleSpy: jest.SpyInstance;
251
+
252
+ const FILLER_COUNT = 25; // 25 × ~800 tokens ≈ 20000 > maxTokens 10000
253
+ const TARGET_ID = 'PIT-020';
254
+
255
+ function makeEntry(overrides: Record<string, any>): any {
256
+ return {
257
+ id: 'X-000',
258
+ type: 'pitfall',
259
+ title: '条目',
260
+ content: '内容',
261
+ maturity: 'proven',
262
+ layer: 'project',
263
+ created: '2026-08-01T00:00:00.000Z',
264
+ lastReferenced: '2026-08-01T00:00:00.000Z',
265
+ contributors: [],
266
+ projects: [],
267
+ tags: [],
268
+ applicablePhases: [],
269
+ sourceReferences: [],
270
+ referencedBy: [],
271
+ executionResults: [],
272
+ consumptionMode: 'reference',
273
+ origin: 'agent',
274
+ ...overrides,
275
+ };
276
+ }
277
+
278
+ beforeEach(() => {
279
+ tmpProject = fs.mkdtempSync(path.join(os.tmpdir(), 'harness-k63-'));
280
+ knowledgeDir = path.join(tmpProject, '.harness', 'knowledge');
281
+ fs.mkdirSync(knowledgeDir, { recursive: true });
282
+ consoleSpy = jest.spyOn(console, 'log').mockImplementation();
283
+
284
+ const store = new FileKnowledgeStore({ baseDir: knowledgeDir });
285
+ // 高成熟度 + 有 lastReferenced 的填充条目排在前面,吃满 token budget
286
+ for (let i = 0; i < FILLER_COUNT; i++) {
287
+ store.save(makeEntry({
288
+ id: `FILL-${String(i).padStart(3, '0')}`,
289
+ title: `填充条目 ${i}`,
290
+ content: '填'.repeat(399) + '共同词',
291
+ }));
292
+ }
293
+ // 目标条目:新条目,draft + lastReferenced 为空,排在队尾
294
+ store.save(makeEntry({
295
+ id: TARGET_ID,
296
+ title: '新条目',
297
+ maturity: 'draft',
298
+ lastReferenced: '',
299
+ content: 'autolink 相关条目 共同词',
300
+ }));
301
+ });
302
+
303
+ afterEach(() => {
304
+ consoleSpy.mockRestore();
305
+ fs.rmSync(tmpProject, { recursive: true, force: true });
306
+ });
307
+
308
+ async function searchJson(query: string, limit: number): Promise<any> {
309
+ await knowledgeSearch(query, { projectPath: tmpProject, json: true, limit });
310
+ const output = consoleSpy.mock.calls.map((c: any[]) => c[0]).join('\n');
311
+ return JSON.parse(output);
312
+ }
313
+
314
+ it('语料超过 token budget 时,排在队尾的新条目仍可被搜到', async () => {
315
+ const result = await searchJson('autolink', 200);
316
+ expect(result.total).toBe(1);
317
+ expect(result.entries[0].id).toBe(TARGET_ID);
318
+ });
319
+
320
+ it('超高频关键词的返回数 = 实际匹配数(截断只发生在匹配之后)', async () => {
321
+ const result = await searchJson('共同词', 200);
322
+ expect(result.total).toBe(FILLER_COUNT + 1);
323
+ });
324
+ });
@@ -51,11 +51,10 @@ describe('命令注册表闭环', () => {
51
51
  });
52
52
 
53
53
  it('全部实现引用可解析(module 存在且 export 是函数)', () => {
54
- const refs = collectRefs(COMMAND_DEFINITIONS);
55
- for (const def of GATE_DEFINITIONS) {
56
- refs.push(def.cli.action);
57
- for (const entry of Object.values(def.cli.subcommands || {})) refs.push(entry);
58
- }
54
+ const refs = collectRefs([
55
+ ...COMMAND_DEFINITIONS,
56
+ ...GATE_DEFINITIONS.map(d => d.cli),
57
+ ]);
59
58
  expect(refs.length).toBeGreaterThan(0);
60
59
 
61
60
  for (const ref of refs) {
@@ -107,7 +106,10 @@ describe('命令注册表闭环', () => {
107
106
  }
108
107
  for (const child of def.children || []) walk(child);
109
108
  };
110
- for (const def of COMMAND_DEFINITIONS) walk(def);
109
+ for (const def of [
110
+ ...COMMAND_DEFINITIONS,
111
+ ...GATE_DEFINITIONS.map(d => d.cli),
112
+ ]) walk(def);
111
113
  // sync-docs --check 失败路径确实会请求退出
112
114
  expect(exitSpy).toHaveBeenCalled();
113
115
  } finally {
@@ -81,7 +81,7 @@ describe('status command - 补充覆盖', () => {
81
81
  ];
82
82
  const mockAnalyze = {
83
83
  summarize: jest.fn().mockReturnValue([
84
- { constraintId: 'no_bypass_checkpoint', level: 'iron_law', passRate: 0.2, totalChecks: 10, bypassRate: 0.1 },
84
+ { constraintId: 'no_bypass_checkpoint', level: 'iron_law', passRate: 0.2, failRate: 0.8, totalChecks: 10 },
85
85
  ]),
86
86
  detectAnomalies: jest.fn().mockReturnValue(mockAnomalies),
87
87
  };
@@ -119,8 +119,8 @@ describe('status command - 补充覆盖', () => {
119
119
  mockFs.readFileSync.mockReturnValue(mockTraces.map(t => JSON.stringify(t)).join('\n'));
120
120
 
121
121
  const mockSummaries = [
122
- { constraintId: 'no_bypass_checkpoint', level: 'iron_law', passRate: 1, totalChecks: 10, bypassRate: 0 },
123
- { constraintId: 'no_completion_without_verification', level: 'iron_law', passRate: 0.8, totalChecks: 5, bypassRate: 0 },
122
+ { constraintId: 'no_bypass_checkpoint', level: 'iron_law', passRate: 1, failRate: 0, totalChecks: 10 },
123
+ { constraintId: 'no_completion_without_verification', level: 'iron_law', passRate: 0.8, failRate: 0.2, totalChecks: 5 },
124
124
  ];
125
125
  const mockAnalyze = {
126
126
  summarize: jest.fn().mockReturnValue(mockSummaries),
@@ -141,27 +141,7 @@ describe('status command - 补充覆盖', () => {
141
141
  mockFs.readFileSync.mockReturnValue(mockTraces.map(t => JSON.stringify(t)).join('\n'));
142
142
 
143
143
  const mockSummaries = [
144
- { constraintId: 'capability_sync', level: 'guideline', passRate: 0.9, totalChecks: 20, bypassRate: 0.1 },
145
- ];
146
- const mockAnalyze = {
147
- summarize: jest.fn().mockReturnValue(mockSummaries),
148
- detectAnomalies: jest.fn().mockReturnValue([]),
149
- };
150
- (MockTraceAnalyzer as any).mockImplementation(() => mockAnalyze);
151
-
152
- await status({});
153
-
154
- expect(consoleSpy).toHaveBeenCalled();
155
- });
156
-
157
- it('应该显示 Tips 统计', async () => {
158
- const mockTraces = [
159
- { constraintId: 'context_doc_sync', level: 'tip', result: 'pass' },
160
- ];
161
- mockFs.readFileSync.mockReturnValue(mockTraces.map(t => JSON.stringify(t)).join('\n'));
162
-
163
- const mockSummaries = [
164
- { constraintId: 'context_doc_sync', level: 'tip', passRate: 1, totalChecks: 5, bypassRate: 0 },
144
+ { constraintId: 'capability_sync', level: 'guideline', passRate: 0.9, failRate: 0.1, totalChecks: 20 },
165
145
  ];
166
146
  const mockAnalyze = {
167
147
  summarize: jest.fn().mockReturnValue(mockSummaries),
@@ -180,14 +160,12 @@ describe('status command - 补充覆盖', () => {
180
160
  const mockTraces = [
181
161
  { constraintId: 'no_bypass_checkpoint', level: 'iron_law', result: 'pass' },
182
162
  { constraintId: 'capability_sync', level: 'guideline', result: 'pass' },
183
- { constraintId: 'context_doc_sync', level: 'tip', result: 'pass' },
184
163
  ];
185
164
  mockFs.readFileSync.mockReturnValue(mockTraces.map(t => JSON.stringify(t)).join('\n'));
186
165
 
187
166
  const mockSummaries = [
188
- { constraintId: 'no_bypass_checkpoint', level: 'iron_law', passRate: 1, totalChecks: 10, bypassRate: 0 },
189
- { constraintId: 'capability_sync', level: 'guideline', passRate: 0.9, totalChecks: 20, bypassRate: 0.1 },
190
- { constraintId: 'context_doc_sync', level: 'tip', passRate: 1, totalChecks: 5, bypassRate: 0 },
167
+ { constraintId: 'no_bypass_checkpoint', level: 'iron_law', passRate: 1, failRate: 0, totalChecks: 10 },
168
+ { constraintId: 'capability_sync', level: 'guideline', passRate: 0.9, failRate: 0.1, totalChecks: 20 },
191
169
  ];
192
170
  const mockAnalyze = {
193
171
  summarize: jest.fn().mockReturnValue(mockSummaries),