@dommaker/harness 1.1.1 → 1.2.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 (373) hide show
  1. package/CHANGELOG.md +17 -0
  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 +8 -33
  7. package/dist/cli/commands/check.js.map +1 -1
  8. package/dist/cli/commands/constraints-report.js +1 -1
  9. package/dist/cli/commands/constraints-report.js.map +1 -1
  10. package/dist/cli/commands/constraints-retire.d.ts +6 -3
  11. package/dist/cli/commands/constraints-retire.d.ts.map +1 -1
  12. package/dist/cli/commands/constraints-retire.js +34 -25
  13. package/dist/cli/commands/constraints-retire.js.map +1 -1
  14. package/dist/cli/commands/definitions.d.ts +2 -0
  15. package/dist/cli/commands/definitions.d.ts.map +1 -1
  16. package/dist/cli/commands/definitions.js.map +1 -1
  17. package/dist/cli/commands/init.d.ts +21 -1
  18. package/dist/cli/commands/init.d.ts.map +1 -1
  19. package/dist/cli/commands/init.js +118 -40
  20. package/dist/cli/commands/init.js.map +1 -1
  21. package/dist/cli/commands/knowledge.d.ts.map +1 -1
  22. package/dist/cli/commands/knowledge.js +1 -12
  23. package/dist/cli/commands/knowledge.js.map +1 -1
  24. package/dist/cli/commands/report.d.ts.map +1 -1
  25. package/dist/cli/commands/report.js +0 -2
  26. package/dist/cli/commands/report.js.map +1 -1
  27. package/dist/cli/commands/status.js +2 -2
  28. package/dist/cli/commands/status.js.map +1 -1
  29. package/dist/context/index.d.ts +9 -6
  30. package/dist/context/index.d.ts.map +1 -1
  31. package/dist/context/index.js +18 -20
  32. package/dist/context/index.js.map +1 -1
  33. package/dist/core/constraints/capabilities-parser.d.ts +3 -2
  34. package/dist/core/constraints/capabilities-parser.d.ts.map +1 -1
  35. package/dist/core/constraints/capabilities-parser.js +25 -47
  36. package/dist/core/constraints/capabilities-parser.js.map +1 -1
  37. package/dist/core/constraints/checker.d.ts +29 -32
  38. package/dist/core/constraints/checker.d.ts.map +1 -1
  39. package/dist/core/constraints/checker.js +34 -126
  40. package/dist/core/constraints/checker.js.map +1 -1
  41. package/dist/core/constraints/checkers/governance-presence.d.ts +20 -0
  42. package/dist/core/constraints/checkers/governance-presence.d.ts.map +1 -0
  43. package/dist/core/constraints/checkers/governance-presence.js +76 -0
  44. package/dist/core/constraints/checkers/governance-presence.js.map +1 -0
  45. package/dist/core/constraints/checkers/index.d.ts +2 -1
  46. package/dist/core/constraints/checkers/index.d.ts.map +1 -1
  47. package/dist/core/constraints/checkers/index.js +5 -0
  48. package/dist/core/constraints/checkers/index.js.map +1 -1
  49. package/dist/core/constraints/checkers/types.d.ts +25 -0
  50. package/dist/core/constraints/checkers/types.d.ts.map +1 -1
  51. package/dist/core/constraints/checkers/types.js +24 -0
  52. package/dist/core/constraints/checkers/types.js.map +1 -1
  53. package/dist/core/constraints/definitions/guidelines.d.ts.map +1 -1
  54. package/dist/core/constraints/definitions/guidelines.js +21 -2
  55. package/dist/core/constraints/definitions/guidelines.js.map +1 -1
  56. package/dist/core/constraints/definitions/prompts.d.ts.map +1 -1
  57. package/dist/core/constraints/definitions/prompts.js +0 -5
  58. package/dist/core/constraints/definitions/prompts.js.map +1 -1
  59. package/dist/core/constraints/index.d.ts +1 -2
  60. package/dist/core/constraints/index.d.ts.map +1 -1
  61. package/dist/core/constraints/index.js +1 -7
  62. package/dist/core/constraints/index.js.map +1 -1
  63. package/dist/core/constraints/injection-drift.d.ts +29 -4
  64. package/dist/core/constraints/injection-drift.d.ts.map +1 -1
  65. package/dist/core/constraints/injection-drift.js +52 -20
  66. package/dist/core/constraints/injection-drift.js.map +1 -1
  67. package/dist/core/constraints/usage-report.d.ts +1 -2
  68. package/dist/core/constraints/usage-report.d.ts.map +1 -1
  69. package/dist/core/constraints/usage-report.js +2 -5
  70. package/dist/core/constraints/usage-report.js.map +1 -1
  71. package/dist/core/effective-constraints.d.ts +24 -4
  72. package/dist/core/effective-constraints.d.ts.map +1 -1
  73. package/dist/core/effective-constraints.js +28 -7
  74. package/dist/core/effective-constraints.js.map +1 -1
  75. package/dist/core/effective-set.d.ts +30 -0
  76. package/dist/core/effective-set.d.ts.map +1 -0
  77. package/dist/core/effective-set.js +35 -0
  78. package/dist/core/effective-set.js.map +1 -0
  79. package/dist/core/index.d.ts +13 -6
  80. package/dist/core/index.d.ts.map +1 -1
  81. package/dist/core/index.js +44 -21
  82. package/dist/core/index.js.map +1 -1
  83. package/dist/core/project-config-loader.d.ts +3 -6
  84. package/dist/core/project-config-loader.d.ts.map +1 -1
  85. package/dist/core/project-config-loader.js +47 -61
  86. package/dist/core/project-config-loader.js.map +1 -1
  87. package/dist/failure/constraint-handler.d.ts +1 -1
  88. package/dist/failure/constraint-handler.js +1 -1
  89. package/dist/gates/checker-gate.d.ts +1 -4
  90. package/dist/gates/checker-gate.d.ts.map +1 -1
  91. package/dist/gates/checker-gate.js +3 -11
  92. package/dist/gates/checker-gate.js.map +1 -1
  93. package/dist/gates/definitions.d.ts +9 -38
  94. package/dist/gates/definitions.d.ts.map +1 -1
  95. package/dist/gates/definitions.js +24 -13
  96. package/dist/gates/definitions.js.map +1 -1
  97. package/dist/gates/effective-gates.d.ts.map +1 -1
  98. package/dist/gates/effective-gates.js +14 -18
  99. package/dist/gates/effective-gates.js.map +1 -1
  100. package/dist/gates/index.d.ts +1 -1
  101. package/dist/gates/index.d.ts.map +1 -1
  102. package/dist/gates/index.js.map +1 -1
  103. package/dist/hooks/bootstrap.d.ts.map +1 -1
  104. package/dist/hooks/bootstrap.js +0 -3
  105. package/dist/hooks/bootstrap.js.map +1 -1
  106. package/dist/index.d.ts +43 -60
  107. package/dist/index.d.ts.map +1 -1
  108. package/dist/index.js +180 -143
  109. package/dist/index.js.map +1 -1
  110. package/dist/knowledge/query.d.ts +15 -0
  111. package/dist/knowledge/query.d.ts.map +1 -1
  112. package/dist/knowledge/query.js +23 -0
  113. package/dist/knowledge/query.js.map +1 -1
  114. package/dist/monitoring/analyzer-base.d.ts +0 -4
  115. package/dist/monitoring/analyzer-base.d.ts.map +1 -1
  116. package/dist/monitoring/analyzer-base.js +0 -21
  117. package/dist/monitoring/analyzer-base.js.map +1 -1
  118. package/dist/monitoring/index.d.ts +6 -12
  119. package/dist/monitoring/index.d.ts.map +1 -1
  120. package/dist/monitoring/index.js +13 -29
  121. package/dist/monitoring/index.js.map +1 -1
  122. package/dist/monitoring/trace-analyzer.d.ts.map +1 -1
  123. package/dist/monitoring/trace-analyzer.js +2 -68
  124. package/dist/monitoring/trace-analyzer.js.map +1 -1
  125. package/dist/monitoring/traces.d.ts +0 -4
  126. package/dist/monitoring/traces.d.ts.map +1 -1
  127. package/dist/monitoring/traces.js +0 -14
  128. package/dist/monitoring/traces.js.map +1 -1
  129. package/dist/presets/index.d.ts +2 -2
  130. package/dist/presets/index.d.ts.map +1 -1
  131. package/dist/presets/index.js +3 -4
  132. package/dist/presets/index.js.map +1 -1
  133. package/dist/presets/standard.d.ts +10 -22
  134. package/dist/presets/standard.d.ts.map +1 -1
  135. package/dist/presets/standard.js +15 -75
  136. package/dist/presets/standard.js.map +1 -1
  137. package/dist/types/constraint.d.ts +1 -29
  138. package/dist/types/constraint.d.ts.map +1 -1
  139. package/dist/types/constraint.js +1 -1
  140. package/dist/types/constraint.js.map +1 -1
  141. package/dist/types/index.d.ts +0 -3
  142. package/dist/types/index.d.ts.map +1 -1
  143. package/dist/types/index.js +0 -4
  144. package/dist/types/index.js.map +1 -1
  145. package/dist/types/project-config.d.ts +4 -8
  146. package/dist/types/project-config.d.ts.map +1 -1
  147. package/dist/types/trace.d.ts +5 -18
  148. package/dist/types/trace.d.ts.map +1 -1
  149. package/package.json +2 -2
  150. package/src/CONTEXT.md +4 -5
  151. package/src/__tests__/checker-extra.test.ts +33 -139
  152. package/src/__tests__/checker.test.ts +0 -376
  153. package/src/__tests__/governance-presence.test.ts +129 -0
  154. package/src/__tests__/iron-laws.test.ts +7 -7
  155. package/src/__tests__/project-config-loader-extra.test.ts +42 -29
  156. package/src/__tests__/public-exports.test.ts +138 -0
  157. package/src/__tests__/trace-analyzer-extra.test.ts +6 -86
  158. package/src/__tests__/trace-analyzer.test.ts +4 -5
  159. package/src/__tests__/trace-collector.test.ts +0 -11
  160. package/src/__tests__/traces.test.ts +3 -22
  161. package/src/cli/commands/CONTEXT.md +6 -3
  162. package/src/cli/commands/__tests__/check-skip-output.test.ts +10 -7
  163. package/src/cli/commands/__tests__/check.test.ts +29 -69
  164. package/src/cli/commands/__tests__/constraints-report.test.ts +3 -3
  165. package/src/cli/commands/__tests__/constraints-retire.test.ts +45 -4
  166. package/src/cli/commands/__tests__/init-injection.test.ts +202 -0
  167. package/src/cli/commands/__tests__/knowledge.test.ts +90 -1
  168. package/src/cli/commands/__tests__/registry.test.ts +8 -6
  169. package/src/cli/commands/__tests__/status-extra.test.ts +6 -6
  170. package/src/cli/commands/__tests__/status.test.ts +6 -6
  171. package/src/cli/commands/__tests__/sync-docs-agents.test.ts +28 -0
  172. package/src/cli/commands/check.ts +9 -35
  173. package/src/cli/commands/constraints-report.ts +1 -1
  174. package/src/cli/commands/constraints-retire.ts +38 -27
  175. package/src/cli/commands/definitions.ts +2 -0
  176. package/src/cli/commands/init.ts +129 -40
  177. package/src/cli/commands/knowledge.ts +1 -16
  178. package/src/cli/commands/report.ts +0 -2
  179. package/src/cli/commands/status.ts +2 -2
  180. package/src/context/index.ts +29 -6
  181. package/src/core/CONTEXT.md +4 -3
  182. package/src/core/__tests__/effective-set.test.ts +80 -0
  183. package/src/core/constraints/__tests__/injection-drift.test.ts +90 -0
  184. package/src/core/constraints/capabilities-parser.ts +43 -49
  185. package/src/core/constraints/checker.ts +51 -145
  186. package/src/core/constraints/checkers/governance-presence.ts +74 -0
  187. package/src/core/constraints/checkers/index.ts +4 -1
  188. package/src/core/constraints/checkers/types.ts +42 -0
  189. package/src/core/constraints/definitions/guidelines.ts +22 -2
  190. package/src/core/constraints/definitions/prompts.ts +0 -5
  191. package/src/core/constraints/index.ts +2 -17
  192. package/src/core/constraints/injection-drift.ts +60 -21
  193. package/src/core/constraints/usage-report.ts +5 -8
  194. package/src/core/effective-constraints.ts +35 -7
  195. package/src/core/effective-set.ts +56 -0
  196. package/src/core/index.ts +80 -6
  197. package/src/core/project-config-loader.ts +53 -68
  198. package/src/failure/CONTEXT.md +1 -1
  199. package/src/failure/constraint-handler.ts +1 -1
  200. package/src/gates/CONTEXT.md +3 -3
  201. package/src/gates/checker-gate.ts +4 -12
  202. package/src/gates/definitions.ts +27 -50
  203. package/src/gates/effective-gates.ts +14 -21
  204. package/src/gates/index.ts +1 -1
  205. package/src/hooks/bootstrap.ts +0 -3
  206. package/src/index.ts +384 -148
  207. package/src/knowledge/CONTEXT.md +2 -2
  208. package/src/knowledge/__tests__/query.test.ts +64 -0
  209. package/src/knowledge/query.ts +28 -0
  210. package/src/monitoring/CONTEXT.md +7 -13
  211. package/src/monitoring/__tests__/traces.test.ts +0 -10
  212. package/src/monitoring/analyzer-base.ts +0 -22
  213. package/src/monitoring/index.ts +6 -12
  214. package/src/monitoring/trace-analyzer.ts +2 -73
  215. package/src/monitoring/traces.ts +0 -20
  216. package/src/presets/__tests__/standard.test.ts +48 -69
  217. package/src/presets/index.ts +3 -5
  218. package/src/presets/standard.ts +14 -79
  219. package/src/spec/CONTEXT.md +5 -13
  220. package/src/types/constraint.ts +1 -51
  221. package/src/types/index.ts +0 -12
  222. package/src/types/project-config.ts +4 -10
  223. package/src/types/trace.ts +5 -30
  224. package/dist/core/constraints/interceptor.d.ts +0 -39
  225. package/dist/core/constraints/interceptor.d.ts.map +0 -1
  226. package/dist/core/constraints/interceptor.js +0 -166
  227. package/dist/core/constraints/interceptor.js.map +0 -1
  228. package/dist/dashboard/data.d.ts +0 -31
  229. package/dist/dashboard/data.d.ts.map +0 -1
  230. package/dist/dashboard/data.js +0 -81
  231. package/dist/dashboard/data.js.map +0 -1
  232. package/dist/dashboard/index.d.ts +0 -4
  233. package/dist/dashboard/index.d.ts.map +0 -1
  234. package/dist/dashboard/index.js +0 -20
  235. package/dist/dashboard/index.js.map +0 -1
  236. package/dist/dashboard/stats.d.ts +0 -20
  237. package/dist/dashboard/stats.d.ts.map +0 -1
  238. package/dist/dashboard/stats.js +0 -115
  239. package/dist/dashboard/stats.js.map +0 -1
  240. package/dist/dashboard/types.d.ts +0 -110
  241. package/dist/dashboard/types.d.ts.map +0 -1
  242. package/dist/dashboard/types.js +0 -8
  243. package/dist/dashboard/types.js.map +0 -1
  244. package/dist/monitoring/constraint-doctor.d.ts +0 -76
  245. package/dist/monitoring/constraint-doctor.d.ts.map +0 -1
  246. package/dist/monitoring/constraint-doctor.js +0 -189
  247. package/dist/monitoring/constraint-doctor.js.map +0 -1
  248. package/dist/monitoring/diagnosis-rules.d.ts +0 -18
  249. package/dist/monitoring/diagnosis-rules.d.ts.map +0 -1
  250. package/dist/monitoring/diagnosis-rules.js +0 -119
  251. package/dist/monitoring/diagnosis-rules.js.map +0 -1
  252. package/dist/monitoring/knowledge-doctor.d.ts +0 -78
  253. package/dist/monitoring/knowledge-doctor.d.ts.map +0 -1
  254. package/dist/monitoring/knowledge-doctor.js +0 -266
  255. package/dist/monitoring/knowledge-doctor.js.map +0 -1
  256. package/dist/monitoring/knowledge-evolver.d.ts +0 -72
  257. package/dist/monitoring/knowledge-evolver.d.ts.map +0 -1
  258. package/dist/monitoring/knowledge-evolver.js +0 -205
  259. package/dist/monitoring/knowledge-evolver.js.map +0 -1
  260. package/dist/monitoring/performance-analyzer.d.ts +0 -92
  261. package/dist/monitoring/performance-analyzer.d.ts.map +0 -1
  262. package/dist/monitoring/performance-analyzer.js +0 -343
  263. package/dist/monitoring/performance-analyzer.js.map +0 -1
  264. package/dist/monitoring/performance-collector.d.ts +0 -103
  265. package/dist/monitoring/performance-collector.d.ts.map +0 -1
  266. package/dist/monitoring/performance-collector.js +0 -298
  267. package/dist/monitoring/performance-collector.js.map +0 -1
  268. package/dist/safety/index.d.ts +0 -6
  269. package/dist/safety/index.d.ts.map +0 -1
  270. package/dist/safety/index.js +0 -22
  271. package/dist/safety/index.js.map +0 -1
  272. package/dist/safety/input-guardrail.d.ts +0 -36
  273. package/dist/safety/input-guardrail.d.ts.map +0 -1
  274. package/dist/safety/input-guardrail.js +0 -118
  275. package/dist/safety/input-guardrail.js.map +0 -1
  276. package/dist/safety/output-guardrail.d.ts +0 -39
  277. package/dist/safety/output-guardrail.d.ts.map +0 -1
  278. package/dist/safety/output-guardrail.js +0 -147
  279. package/dist/safety/output-guardrail.js.map +0 -1
  280. package/dist/safety/sandbox.d.ts +0 -45
  281. package/dist/safety/sandbox.d.ts.map +0 -1
  282. package/dist/safety/sandbox.js +0 -134
  283. package/dist/safety/sandbox.js.map +0 -1
  284. package/dist/safety/tool-guardrail.d.ts +0 -51
  285. package/dist/safety/tool-guardrail.d.ts.map +0 -1
  286. package/dist/safety/tool-guardrail.js +0 -147
  287. package/dist/safety/tool-guardrail.js.map +0 -1
  288. package/dist/safety/types.d.ts +0 -104
  289. package/dist/safety/types.d.ts.map +0 -1
  290. package/dist/safety/types.js +0 -6
  291. package/dist/safety/types.js.map +0 -1
  292. package/dist/spec/annotation-checker.d.ts +0 -47
  293. package/dist/spec/annotation-checker.d.ts.map +0 -1
  294. package/dist/spec/annotation-checker.js +0 -279
  295. package/dist/spec/annotation-checker.js.map +0 -1
  296. package/dist/types/enforcement.d.ts +0 -42
  297. package/dist/types/enforcement.d.ts.map +0 -1
  298. package/dist/types/enforcement.js +0 -6
  299. package/dist/types/enforcement.js.map +0 -1
  300. package/dist/types/monitoring-types.d.ts +0 -53
  301. package/dist/types/monitoring-types.d.ts.map +0 -1
  302. package/dist/types/monitoring-types.js +0 -10
  303. package/dist/types/monitoring-types.js.map +0 -1
  304. package/dist/types/performance.d.ts +0 -204
  305. package/dist/types/performance.d.ts.map +0 -1
  306. package/dist/types/performance.js +0 -12
  307. package/dist/types/performance.js.map +0 -1
  308. package/dist/verification/index.d.ts +0 -4
  309. package/dist/verification/index.d.ts.map +0 -1
  310. package/dist/verification/index.js +0 -20
  311. package/dist/verification/index.js.map +0 -1
  312. package/dist/verification/loop.d.ts +0 -30
  313. package/dist/verification/loop.d.ts.map +0 -1
  314. package/dist/verification/loop.js +0 -114
  315. package/dist/verification/loop.js.map +0 -1
  316. package/dist/verification/rules-based.d.ts +0 -40
  317. package/dist/verification/rules-based.d.ts.map +0 -1
  318. package/dist/verification/rules-based.js +0 -130
  319. package/dist/verification/rules-based.js.map +0 -1
  320. package/dist/verification/types.d.ts +0 -69
  321. package/dist/verification/types.d.ts.map +0 -1
  322. package/dist/verification/types.js +0 -6
  323. package/dist/verification/types.js.map +0 -1
  324. package/src/__tests__/annotation-checker.test.ts +0 -183
  325. package/src/__tests__/constraint-doctor.test.ts +0 -271
  326. package/src/__tests__/doctor-extra.test.ts +0 -155
  327. package/src/__tests__/extend-exceptions.test.ts +0 -149
  328. package/src/__tests__/interceptor.test.ts +0 -89
  329. package/src/__tests__/performance-analyzer.test.ts +0 -499
  330. package/src/__tests__/performance-collector.test.ts +0 -276
  331. package/src/__tests__/presets.test.ts +0 -65
  332. package/src/core/constraints/__tests__/interceptor.test.ts +0 -267
  333. package/src/core/constraints/interceptor.ts +0 -217
  334. package/src/dashboard/CONTEXT.md +0 -21
  335. package/src/dashboard/__tests__/data.test.ts +0 -111
  336. package/src/dashboard/__tests__/stats.test.ts +0 -159
  337. package/src/dashboard/data.ts +0 -103
  338. package/src/dashboard/index.ts +0 -3
  339. package/src/dashboard/stats.ts +0 -127
  340. package/src/dashboard/types.ts +0 -130
  341. package/src/monitoring/__tests__/knowledge-doctor.test.ts +0 -278
  342. package/src/monitoring/__tests__/knowledge-evolver.test.ts +0 -368
  343. package/src/monitoring/__tests__/performance-analyzer.test.ts +0 -137
  344. package/src/monitoring/__tests__/performance-collector.test.ts +0 -331
  345. package/src/monitoring/constraint-doctor.ts +0 -228
  346. package/src/monitoring/diagnosis-rules.ts +0 -132
  347. package/src/monitoring/knowledge-doctor.ts +0 -322
  348. package/src/monitoring/knowledge-evolver.ts +0 -289
  349. package/src/monitoring/performance-analyzer.ts +0 -400
  350. package/src/monitoring/performance-collector.ts +0 -326
  351. package/src/safety/CONTEXT.md +0 -23
  352. package/src/safety/__tests__/input-guardrail.test.ts +0 -105
  353. package/src/safety/__tests__/output-guardrail.test.ts +0 -108
  354. package/src/safety/__tests__/sandbox.test.ts +0 -158
  355. package/src/safety/__tests__/tool-guardrail.test.ts +0 -127
  356. package/src/safety/index.ts +0 -5
  357. package/src/safety/input-guardrail.ts +0 -133
  358. package/src/safety/output-guardrail.ts +0 -170
  359. package/src/safety/sandbox.ts +0 -148
  360. package/src/safety/tool-guardrail.ts +0 -176
  361. package/src/safety/types.ts +0 -124
  362. package/src/spec/__tests__/annotation-checker.test.ts +0 -294
  363. package/src/spec/annotation-checker.ts +0 -320
  364. package/src/types/enforcement.ts +0 -48
  365. package/src/types/monitoring-types.ts +0 -68
  366. package/src/types/performance.ts +0 -295
  367. package/src/verification/CONTEXT.md +0 -23
  368. package/src/verification/__tests__/loop.test.ts +0 -303
  369. package/src/verification/__tests__/rules-based.test.ts +0 -240
  370. package/src/verification/index.ts +0 -3
  371. package/src/verification/loop.ts +0 -137
  372. package/src/verification/rules-based.ts +0 -152
  373. package/src/verification/types.ts +0 -81
@@ -1,331 +0,0 @@
1
- /**
2
- * PerformanceCollector 测试
3
- */
4
-
5
- import { describe, it, expect, beforeEach } from '@jest/globals';
6
- import { PerformanceCollector } from '../performance-collector';
7
- import * as fs from 'fs';
8
-
9
- // Mock fs
10
- jest.mock('fs', () => ({
11
- existsSync: jest.fn(),
12
- mkdirSync: jest.fn(),
13
- appendFileSync: jest.fn(),
14
- statSync: jest.fn().mockReturnValue({ size: 100 }),
15
- renameSync: jest.fn(),
16
- writeFileSync: jest.fn(),
17
- readdirSync: jest.fn().mockReturnValue([]),
18
- readFileSync: jest.fn().mockReturnValue(''),
19
- }));
20
-
21
- const mockFs = fs as jest.Mocked<typeof fs>;
22
-
23
- describe('PerformanceCollector', () => {
24
- let collector: PerformanceCollector;
25
-
26
- beforeEach(() => {
27
- jest.clearAllMocks();
28
- mockFs.existsSync.mockReturnValue(true);
29
- mockFs.statSync.mockReturnValue({ size: 100 } as any);
30
- collector = new PerformanceCollector();
31
- });
32
-
33
- describe('constructor', () => {
34
- it('should create log directory if not exists', () => {
35
- mockFs.existsSync.mockReturnValueOnce(false);
36
- new PerformanceCollector();
37
- expect(mockFs.mkdirSync).toHaveBeenCalled();
38
- });
39
-
40
- it('should be disabled when enabled=false', () => {
41
- const disabledCollector = new PerformanceCollector({ enabled: false });
42
- disabledCollector.recordOk('test', 100);
43
- expect(mockFs.appendFileSync).not.toHaveBeenCalled();
44
- });
45
-
46
- it('should accept custom config', () => {
47
- const customCollector = new PerformanceCollector({
48
- enabled: true,
49
- logFile: '.harness/perf.log',
50
- maxFileSize: 5 * 1024 * 1024,
51
- });
52
- expect(customCollector).toBeDefined();
53
- });
54
-
55
- it('should use default config', () => {
56
- const defaultCollector = new PerformanceCollector();
57
- expect(defaultCollector).toBeDefined();
58
- });
59
- });
60
-
61
- describe('record()', () => {
62
- it('should append trace to file', () => {
63
- collector.record({
64
- operation: 'test',
65
- timestamp: Date.now(),
66
- duration: 100,
67
- result: 'ok',
68
- });
69
- expect(mockFs.appendFileSync).toHaveBeenCalled();
70
- });
71
-
72
- it('should not record when disabled', () => {
73
- const disabledCollector = new PerformanceCollector({ enabled: false });
74
- disabledCollector.record({
75
- operation: 'test',
76
- timestamp: Date.now(),
77
- duration: 100,
78
- result: 'ok',
79
- });
80
- expect(mockFs.appendFileSync).not.toHaveBeenCalled();
81
- });
82
-
83
- it('should record with all fields', () => {
84
- collector.record({
85
- operation: 'full-test',
86
- timestamp: 1234567890,
87
- duration: 500,
88
- result: 'exceeded',
89
- threshold: 300,
90
- metadata: { key: 'value' },
91
- });
92
- expect(mockFs.appendFileSync).toHaveBeenCalled();
93
- const call = mockFs.appendFileSync.mock.calls[0];
94
- const content = call[1] as string;
95
- expect(content).toContain('full-test');
96
- expect(content).toContain('exceeded');
97
- });
98
- });
99
-
100
- describe('recordOk()', () => {
101
- it('should record ok trace', () => {
102
- collector.recordOk('test', 150);
103
- const call = mockFs.appendFileSync.mock.calls[0];
104
- const content = call[1] as string;
105
- const trace = JSON.parse(content.trim());
106
- expect(trace.result).toBe('ok');
107
- expect(trace.operation).toBe('test');
108
- expect(trace.duration).toBe(150);
109
- });
110
-
111
- it('should record with metadata', () => {
112
- collector.recordOk('test', 100, { key: 'value' });
113
- const call = mockFs.appendFileSync.mock.calls[0];
114
- const content = call[1] as string;
115
- const trace = JSON.parse(content.trim());
116
- expect(trace.metadata).toEqual({ key: 'value' });
117
- });
118
-
119
- it('should auto-generate timestamp', () => {
120
- collector.recordOk('test', 100);
121
- const call = mockFs.appendFileSync.mock.calls[0];
122
- const content = call[1] as string;
123
- const trace = JSON.parse(content.trim());
124
- expect(trace.timestamp).toBeDefined();
125
- expect(typeof trace.timestamp).toBe('number');
126
- });
127
-
128
- it('should not record when disabled', () => {
129
- const disabledCollector = new PerformanceCollector({ enabled: false });
130
- disabledCollector.recordOk('test', 100);
131
- expect(mockFs.appendFileSync).not.toHaveBeenCalled();
132
- });
133
- });
134
-
135
- describe('recordExceeded()', () => {
136
- it('should record exceeded trace', () => {
137
- collector.recordExceeded('test', 35000, 30000);
138
- const call = mockFs.appendFileSync.mock.calls[0];
139
- const content = call[1] as string;
140
- const trace = JSON.parse(content.trim());
141
- expect(trace.result).toBe('exceeded');
142
- expect(trace.threshold).toBe(30000);
143
- });
144
-
145
- it('should include duration', () => {
146
- collector.recordExceeded('test', 35000, 30000);
147
- const call = mockFs.appendFileSync.mock.calls[0];
148
- const content = call[1] as string;
149
- const trace = JSON.parse(content.trim());
150
- expect(trace.duration).toBe(35000);
151
- });
152
-
153
- it('should not record when disabled', () => {
154
- const disabledCollector = new PerformanceCollector({ enabled: false });
155
- disabledCollector.recordExceeded('test', 35000, 30000);
156
- expect(mockFs.appendFileSync).not.toHaveBeenCalled();
157
- });
158
- });
159
-
160
- describe('recordError()', () => {
161
- it('should record error trace', () => {
162
- collector.recordError('test', 100, 'Test error');
163
- const call = mockFs.appendFileSync.mock.calls[0];
164
- const content = call[1] as string;
165
- const trace = JSON.parse(content.trim());
166
- expect(trace.result).toBe('error');
167
- expect(trace.metadata.error).toBe('Test error');
168
- });
169
-
170
- it('should include duration', () => {
171
- collector.recordError('test', 100, 'Test error');
172
- const call = mockFs.appendFileSync.mock.calls[0];
173
- const content = call[1] as string;
174
- const trace = JSON.parse(content.trim());
175
- expect(trace.duration).toBe(100);
176
- });
177
-
178
- it('should not record when disabled', () => {
179
- const disabledCollector = new PerformanceCollector({ enabled: false });
180
- disabledCollector.recordError('test', 100, 'Test error');
181
- expect(mockFs.appendFileSync).not.toHaveBeenCalled();
182
- });
183
- });
184
-
185
- describe('read()', () => {
186
- it('should return empty array if file not exists', () => {
187
- mockFs.existsSync.mockReturnValueOnce(false);
188
- const c = new PerformanceCollector();
189
- const traces = c.read();
190
- expect(traces).toEqual([]);
191
- });
192
-
193
- it('should return traces from file', () => {
194
- mockFs.existsSync.mockReturnValue(true);
195
- mockFs.readFileSync.mockReturnValueOnce(
196
- JSON.stringify({ operation: 'test1', duration: 100, result: 'ok', timestamp: 1 }) + '\n' +
197
- JSON.stringify({ operation: 'test2', duration: 200, result: 'ok', timestamp: 2 }) + '\n'
198
- );
199
-
200
- const c = new PerformanceCollector();
201
- const traces = c.read();
202
- expect(traces.length).toBe(2);
203
- expect(traces[0].operation).toBe('test1');
204
- expect(traces[1].operation).toBe('test2');
205
- });
206
-
207
- it('should handle empty file', () => {
208
- mockFs.existsSync.mockReturnValue(true);
209
- mockFs.readFileSync.mockReturnValueOnce('');
210
-
211
- const c = new PerformanceCollector();
212
- const traces = c.read();
213
- expect(traces).toEqual([]);
214
- });
215
-
216
- it('should filter by period', () => {
217
- mockFs.existsSync.mockReturnValue(true);
218
- mockFs.readFileSync.mockReturnValueOnce(
219
- JSON.stringify({ operation: 'test1', duration: 100, result: 'ok', timestamp: Date.now() - 100000 }) + '\n' +
220
- JSON.stringify({ operation: 'test2', duration: 200, result: 'ok', timestamp: Date.now() }) + '\n'
221
- );
222
-
223
- const c = new PerformanceCollector();
224
- const traces = c.read({ timeRange: { start: Date.now() - 50000, end: Date.now() } });
225
- expect(traces.length).toBe(1);
226
- expect(traces[0].operation).toBe('test2');
227
- });
228
-
229
- it('should filter by operation', () => {
230
- mockFs.existsSync.mockReturnValue(true);
231
- mockFs.readFileSync.mockReturnValueOnce(
232
- JSON.stringify({ operation: 'test1', duration: 100, result: 'ok', timestamp: Date.now() }) + '\n' +
233
- JSON.stringify({ operation: 'test2', duration: 200, result: 'ok', timestamp: Date.now() }) + '\n'
234
- );
235
-
236
- const c = new PerformanceCollector();
237
- const traces = c.read({ operation: 'test1' });
238
- expect(traces.length).toBe(1);
239
- expect(traces[0].operation).toBe('test1');
240
- });
241
-
242
- it('should filter by result', () => {
243
- mockFs.existsSync.mockReturnValue(true);
244
- mockFs.readFileSync.mockReturnValueOnce(
245
- JSON.stringify({ operation: 'test1', duration: 100, result: 'ok', timestamp: Date.now() }) + '\n' +
246
- JSON.stringify({ operation: 'test2', duration: 200, result: 'exceeded', timestamp: Date.now() }) + '\n'
247
- );
248
-
249
- const c = new PerformanceCollector();
250
- const traces = c.read({ result: 'exceeded' });
251
- expect(traces.length).toBe(1);
252
- expect(traces[0].result).toBe('exceeded');
253
- });
254
- });
255
-
256
- describe('getStats()', () => {
257
- it('should return stats', () => {
258
- mockFs.existsSync.mockReturnValue(true);
259
- mockFs.statSync.mockReturnValue({ size: 1024 } as any);
260
-
261
- const stats = collector.getStats();
262
- expect(stats).toHaveProperty('fileExists');
263
- });
264
-
265
- it('should return stats when file not exists', () => {
266
- // 先让目录检查通过,再让文件检查失败
267
- mockFs.existsSync
268
- .mockReturnValueOnce(true) // 目录检查
269
- .mockReturnValueOnce(false); // 文件检查
270
-
271
- const c = new PerformanceCollector();
272
- mockFs.existsSync.mockReturnValue(false); // getStats 检查
273
- const stats = c.getStats();
274
- expect(stats.fileExists).toBe(false);
275
- });
276
-
277
- it('should include file size', () => {
278
- mockFs.existsSync.mockReturnValue(true);
279
- mockFs.statSync.mockReturnValue({ size: 2048 } as any);
280
-
281
- const stats = collector.getStats();
282
- expect(stats.fileSize).toBe(2048);
283
- });
284
- });
285
-
286
- describe('file rolling', () => {
287
- it('should roll file when size exceeds limit', () => {
288
- mockFs.statSync.mockReturnValue({ size: 15 * 1024 * 1024 } as any); // 15MB
289
-
290
- collector.recordOk('test', 100);
291
- expect(mockFs.renameSync).toHaveBeenCalled();
292
- });
293
-
294
- it('should not roll when under limit', () => {
295
- mockFs.statSync.mockReturnValue({ size: 5 * 1024 * 1024 } as any); // 5MB
296
-
297
- collector.recordOk('test', 100);
298
- expect(mockFs.renameSync).not.toHaveBeenCalled();
299
- });
300
- });
301
-
302
- describe('clear()', () => {
303
- it('should exist if implemented', () => {
304
- // Check if method exists
305
- const hasClear = typeof (collector as any).clear === 'function';
306
- if (hasClear) {
307
- mockFs.existsSync.mockReturnValue(true);
308
- (collector as any).clear();
309
- expect(mockFs.writeFileSync).toHaveBeenCalled();
310
- }
311
- });
312
- });
313
-
314
- describe('getRecentTraces()', () => {
315
- it('should return recent traces', () => {
316
- mockFs.existsSync.mockReturnValue(true);
317
- mockFs.readFileSync.mockReturnValueOnce(
318
- JSON.stringify({ operation: 'test1', duration: 100, result: 'ok', timestamp: Date.now() }) + '\n' +
319
- JSON.stringify({ operation: 'test2', duration: 200, result: 'ok', timestamp: Date.now() }) + '\n' +
320
- JSON.stringify({ operation: 'test3', duration: 300, result: 'ok', timestamp: Date.now() }) + '\n'
321
- );
322
-
323
- // Check if method exists
324
- const hasRecent = typeof (collector as any).getRecentTraces === 'function';
325
- if (hasRecent) {
326
- const traces = (collector as any).getRecentTraces(2);
327
- expect(traces.length).toBe(2);
328
- }
329
- });
330
- });
331
- });
@@ -1,228 +0,0 @@
1
- /**
2
- * 约束诊断器
3
- *
4
- * 当检测到异常时,基于预设规则分析 traces 给出诊断(零 Token,不调用 LLM)。
5
- */
6
-
7
- import type {
8
- ExecutionTrace,
9
- TraceAnomaly,
10
- TraceSummary,
11
- } from '../types/trace';
12
- import type { Diagnosis } from '../types/monitoring-types';
13
- import { DIAGNOSIS_RULES } from './diagnosis-rules';
14
-
15
- // 类型定义已归位 types 层(工单 14),此处再导出保持模块公开面不变
16
- export type { Diagnosis };
17
-
18
- /**
19
- * 诊断配置
20
- */
21
- export interface ConstraintDoctorConfig {
22
- /** 最大 traces 数量(用于构造诊断证据) */
23
- maxTraces?: number;
24
- }
25
-
26
- /**
27
- * Constraint Doctor - 约束诊断器
28
- *
29
- * 使用方式:
30
- * ```typescript
31
- * const doctor = new ConstraintDoctor(analyzer);
32
- * const diagnosis = await doctor.diagnose(anomaly);
33
- *
34
- * if (diagnosis.needsChange) {
35
- * const proposal = await evolver.propose(diagnosis);
36
- * }
37
- * ```
38
- */
39
- export class ConstraintDoctor {
40
- private config: ConstraintDoctorConfig;
41
- private traces: ExecutionTrace[];
42
-
43
- constructor(config?: ConstraintDoctorConfig) {
44
- this.config = {
45
- maxTraces: 20,
46
- ...config,
47
- };
48
- this.traces = [];
49
- }
50
-
51
- /**
52
- * 设置诊断数据
53
- */
54
- setData(traces: ExecutionTrace[], _summary?: TraceSummary): void {
55
- this.traces = traces;
56
- }
57
-
58
- /**
59
- * 诊断异常
60
- *
61
- * 如果 Agent 未启用,返回基于规则的诊断
62
- */
63
- async diagnose(anomaly: TraceAnomaly): Promise<Diagnosis> {
64
- // 过滤相关 traces
65
- const relevantTraces = this.filterRelevantTraces(anomaly);
66
-
67
- // 基于规则的诊断(不消耗 Token)
68
- return this.ruleBasedDiagnose(anomaly, relevantTraces);
69
- }
70
-
71
- /**
72
- * 基于规则的诊断(零 Token)
73
- *
74
- * 根据异常类型应用预设的诊断规则
75
- */
76
- private ruleBasedDiagnose(
77
- anomaly: TraceAnomaly,
78
- traces: ExecutionTrace[]
79
- ): Diagnosis {
80
- const diagnosis: Diagnosis = {
81
- anomalyId: `${anomaly.constraintId}-${anomaly.type}-${Date.now()}`,
82
- constraintId: anomaly.constraintId,
83
- diagnosedAt: Date.now(),
84
- rootCause: {
85
- primary: '',
86
- secondary: [],
87
- evidence: traces.slice(0, this.config.maxTraces!),
88
- },
89
- impact: {
90
- severity: 'medium',
91
- scope: 'single_project',
92
- userImpact: '',
93
- },
94
- recommendations: [],
95
- needsChange: false,
96
- urgency: 'low',
97
- };
98
-
99
- // 根据异常类型诊断(工单 23-B:规则数据化,见 diagnosis-rules.ts)
100
- const rule = DIAGNOSIS_RULES[anomaly.type];
101
- if (rule) {
102
- diagnosis.rootCause.primary = rule.primary;
103
- diagnosis.rootCause.secondary = rule.secondary;
104
- diagnosis.impact.userImpact = rule.userImpact;
105
- diagnosis.recommendations = rule.recommendations(anomaly);
106
- diagnosis.needsChange = rule.needsChange;
107
- diagnosis.urgency = rule.urgency(anomaly);
108
- }
109
-
110
- // 根据约束层级调整严重性
111
- if (anomaly.level === 'iron_law') {
112
- diagnosis.impact.severity = 'high';
113
- diagnosis.urgency = 'medium'; // Iron law 总是至少 medium
114
- }
115
-
116
- return diagnosis;
117
- }
118
-
119
- /**
120
- * 过滤相关 traces
121
- *
122
- * 只保留与异常相关的 traces,减少 prompt 内容
123
- */
124
- private filterRelevantTraces(anomaly: TraceAnomaly): ExecutionTrace[] {
125
- return this.traces.filter(t => {
126
- // 必须是同一个约束
127
- if (t.constraintId !== anomaly.constraintId) return false;
128
-
129
- // 失败或绕过的更有诊断价值
130
- if (t.result === 'fail' || t.result === 'bypassed') return true;
131
-
132
- // 保留少量通过的作为对比
133
- return true;
134
- });
135
- }
136
-
137
- /**
138
- * 批量诊断多个异常
139
- */
140
- async diagnoseBatch(anomalies: TraceAnomaly[]): Promise<Diagnosis[]> {
141
- return Promise.all(anomalies.map(a => this.diagnose(a)));
142
- }
143
-
144
- /**
145
- * 生成诊断报告(文本格式)
146
- */
147
- generateReport(diagnosis: Diagnosis): string {
148
- const lines: string[] = [];
149
-
150
- lines.push(`# Diagnosis Report`);
151
- lines.push(`Constraint: ${diagnosis.constraintId}`);
152
- lines.push(`Anomaly: ${diagnosis.anomalyId}`);
153
- lines.push(`Diagnosed: ${new Date(diagnosis.diagnosedAt).toISOString()}`);
154
- lines.push('');
155
-
156
- // 根因
157
- lines.push(`## Root Cause`);
158
- lines.push('');
159
- lines.push(`**Primary**: ${diagnosis.rootCause.primary}`);
160
- if (diagnosis.rootCause.secondary?.length) {
161
- lines.push('');
162
- lines.push('**Secondary**:');
163
- for (const s of diagnosis.rootCause.secondary) {
164
- lines.push(`- ${s}`);
165
- }
166
- }
167
- lines.push('');
168
-
169
- // 影响
170
- lines.push(`## Impact`);
171
- lines.push('');
172
- lines.push(`- Severity: ${diagnosis.impact.severity}`);
173
- lines.push(`- Scope: ${diagnosis.impact.scope}`);
174
- lines.push(`- User Impact: ${diagnosis.impact.userImpact}`);
175
- lines.push('');
176
-
177
- // 建议
178
- lines.push(`## Recommendations`);
179
- lines.push('');
180
-
181
- for (const r of diagnosis.recommendations) {
182
- lines.push(`### ${r.type}`);
183
- lines.push(`- Content: ${r.content}`);
184
- lines.push(`- Expected: ${r.expectedOutcome}`);
185
- lines.push(`- Cost: ${r.implementationCost}`);
186
- lines.push('');
187
- }
188
-
189
- // 决策
190
- lines.push(`## Decision`);
191
- lines.push('');
192
- lines.push(`- Needs Change: ${diagnosis.needsChange ? '✅ Yes' : '❌ No'}`);
193
- lines.push(`- Urgency: ${diagnosis.urgency}`);
194
-
195
- return lines.join('\n');
196
- }
197
-
198
- /**
199
- * 保存诊断结果
200
- */
201
- saveDiagnosis(diagnosis: Diagnosis, outputPath: string): void {
202
- const fs = require('fs');
203
- const path = require('path');
204
-
205
- const dir = path.dirname(outputPath);
206
- if (!fs.existsSync(dir)) {
207
- fs.mkdirSync(dir, { recursive: true });
208
- }
209
-
210
- fs.writeFileSync(outputPath, JSON.stringify(diagnosis, null, 2), 'utf-8');
211
- }
212
-
213
- /**
214
- * 加载诊断结果
215
- */
216
- loadDiagnosis(inputPath: string): Diagnosis {
217
- const fs = require('fs');
218
- const content = fs.readFileSync(inputPath, 'utf-8');
219
- return JSON.parse(content) as Diagnosis;
220
- }
221
- }
222
-
223
- /**
224
- * 创建诊断器
225
- */
226
- export function createDoctor(config?: ConstraintDoctorConfig): ConstraintDoctor {
227
- return new ConstraintDoctor(config);
228
- }
@@ -1,132 +0,0 @@
1
- /**
2
- * 诊断规则表(工单 23-B)
3
- *
4
- * constraint-doctor.ruleBasedDiagnose 的巨型 switch 数据化:
5
- * 每种异常类型一条规则(根因/影响/建议/紧急度),新增异常类型只需加表项。
6
- */
7
-
8
- import type { TraceAnomaly } from '../types/trace';
9
- import type { Diagnosis } from '../types/monitoring-types';
10
-
11
- export interface DiagnosisRule {
12
- primary: string;
13
- secondary: string[];
14
- userImpact: string;
15
- recommendations: (anomaly: TraceAnomaly) => Diagnosis['recommendations'];
16
- needsChange: boolean;
17
- urgency: (anomaly: TraceAnomaly) => Diagnosis['urgency'];
18
- }
19
-
20
- export const DIAGNOSIS_RULES: Record<string, DiagnosisRule> = {
21
- high_bypass_rate: {
22
- primary: '约束过于严格,用户频繁绕过',
23
- secondary: [
24
- '约束触发条件过于宽泛',
25
- '缺乏必要的例外条件',
26
- '约束定义与实际场景不匹配',
27
- ],
28
- userImpact: '用户被迫绕过约束,降低信任度',
29
- recommendations: (anomaly) => [
30
- {
31
- type: 'add_exception',
32
- content: `为约束 ${anomaly.constraintId} 添加常见例外条件`,
33
- expectedOutcome: '绕过率降低至 20% 以下',
34
- implementationCost: 'low',
35
- },
36
- {
37
- type: 'adjust_threshold',
38
- content: '调整触发条件,减少误触发',
39
- expectedOutcome: '减少不必要的约束检查',
40
- implementationCost: 'medium',
41
- },
42
- ],
43
- needsChange: true,
44
- urgency: (anomaly) => ((anomaly.data.currentRate as number) > 0.5 ? 'high' : 'medium'),
45
- },
46
-
47
- rising_fail_rate: {
48
- primary: '约束失败率呈上升趋势',
49
- secondary: [
50
- '代码质量下降',
51
- '约束检查逻辑存在 bug',
52
- '环境变化导致约束不再适用',
53
- ],
54
- userImpact: '开发效率下降,约束频繁阻止正常操作',
55
- recommendations: () => [
56
- {
57
- type: 'modify_constraint',
58
- content: '审查约束逻辑,确认是否符合预期',
59
- expectedOutcome: '恢复正常的失败率水平',
60
- implementationCost: 'medium',
61
- },
62
- {
63
- type: 'user_training',
64
- content: '指导用户正确理解约束要求',
65
- expectedOutcome: '减少因误解导致的失败',
66
- implementationCost: 'low',
67
- },
68
- ],
69
- needsChange: true,
70
- urgency: () => 'medium',
71
- },
72
-
73
- rising_bypass_rate: {
74
- primary: '绕过率呈上升趋势',
75
- secondary: [
76
- '用户对约束的接受度下降',
77
- '约束规则逐渐不适应新的开发模式',
78
- '用户发现了绕过约束的"捷径"',
79
- ],
80
- userImpact: '约束逐渐失去约束力',
81
- recommendations: () => [
82
- {
83
- type: 'modify_constraint',
84
- content: '重新评估约束的必要性',
85
- expectedOutcome: '恢复约束的权威性',
86
- implementationCost: 'high',
87
- },
88
- ],
89
- needsChange: true,
90
- urgency: () => 'high',
91
- },
92
-
93
- low_pass_rate: {
94
- primary: '约束通过率过低',
95
- secondary: [
96
- '约束要求过于严格',
97
- '实际代码质量不达标',
98
- '约束定义存在歧义',
99
- ],
100
- userImpact: '几乎所有操作都被阻止,开发受阻',
101
- recommendations: () => [
102
- {
103
- type: 'adjust_threshold',
104
- content: '放宽约束要求,设置合理阈值',
105
- expectedOutcome: '通过率提升至 50% 以上',
106
- implementationCost: 'low',
107
- },
108
- ],
109
- needsChange: true,
110
- urgency: () => 'high',
111
- },
112
-
113
- exception_overuse: {
114
- primary: '例外条件被过度使用',
115
- secondary: [
116
- '例外条件过于宽泛',
117
- '例外条件定义不够精确',
118
- '用户习惯性申请例外',
119
- ],
120
- userImpact: '例外成为常态,约束失去意义',
121
- recommendations: () => [
122
- {
123
- type: 'modify_constraint',
124
- content: '缩小例外条件范围,提高例外门槛',
125
- expectedOutcome: '例外使用率降低至 20% 以下',
126
- implementationCost: 'medium',
127
- },
128
- ],
129
- needsChange: true,
130
- urgency: () => 'medium',
131
- },
132
- };