@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
@@ -1,271 +0,0 @@
1
- /**
2
- * ConstraintDoctor 测试
3
- */
4
-
5
- import { describe, it, expect, beforeAll, afterAll } from '@jest/globals';
6
- import { ConstraintDoctor } from '../monitoring/constraint-doctor';
7
- import type { TraceAnomaly } from '../types/trace';
8
- import * as fs from 'fs';
9
- import * as path from 'path';
10
-
11
- describe('ConstraintDoctor', () => {
12
- const tempDir = path.join(process.cwd(), 'temp-test-doctor');
13
- let doctor: ConstraintDoctor;
14
-
15
- beforeAll(() => {
16
- fs.mkdirSync(tempDir, { recursive: true });
17
- doctor = new ConstraintDoctor();
18
- });
19
-
20
- afterAll(() => {
21
- try {
22
- fs.rmSync(tempDir, { recursive: true, force: true });
23
- } catch {
24
- // ignore
25
- }
26
- });
27
-
28
- describe('constructor', () => {
29
- it('应该创建实例', () => {
30
- expect(doctor).toBeDefined();
31
- });
32
- });
33
-
34
- describe('setData', () => {
35
- it('应该设置数据', () => {
36
- doctor.setData([], undefined);
37
-
38
- expect(doctor).toBeDefined();
39
- });
40
- });
41
-
42
- describe('diagnose', () => {
43
- it('应该诊断异常', async () => {
44
- const anomaly: TraceAnomaly = {
45
- type: 'high_bypass_rate',
46
- constraintId: 'no_fix_without_root_cause',
47
- level: 'guideline',
48
- message: '绕过率过高',
49
- data: {
50
- currentRate: 0.5,
51
- threshold: 0.3,
52
- },
53
- detectedAt: Date.now(),
54
- };
55
-
56
- const diagnosis = await doctor.diagnose(anomaly);
57
-
58
- expect(diagnosis).toBeDefined();
59
- expect(diagnosis.constraintId).toBe('no_fix_without_root_cause');
60
- });
61
-
62
- it('应该返回诊断结果', async () => {
63
- const anomaly: TraceAnomaly = {
64
- type: 'rising_fail_rate',
65
- constraintId: 'no_completion_without_verification',
66
- level: 'iron_law',
67
- message: '失败率上升',
68
- data: {
69
- currentRate: 0.6,
70
- threshold: 0.5,
71
- trend: 'rising',
72
- },
73
- detectedAt: Date.now(),
74
- };
75
-
76
- const diagnosis = await doctor.diagnose(anomaly);
77
-
78
- expect(diagnosis.rootCause).toBeDefined();
79
- expect(diagnosis.impact).toBeDefined();
80
- expect(diagnosis.needsChange).toBeDefined();
81
- });
82
- });
83
-
84
- describe('generateReport', () => {
85
- it('应该生成报告', () => {
86
- const diagnosis = {
87
- anomalyId: 'test',
88
- constraintId: 'test',
89
- diagnosedAt: Date.now(),
90
- rootCause: { primary: 'Test', evidence: [] },
91
- impact: { severity: 'medium' as const, scope: 'single_project' as const, userImpact: 'Test' },
92
- recommendations: [],
93
- needsChange: true,
94
- urgency: 'medium' as const,
95
- };
96
-
97
- const report = doctor.generateReport(diagnosis);
98
-
99
- expect(typeof report).toBe('string');
100
- expect(report.length).toBeGreaterThan(0);
101
- });
102
- });
103
-
104
- describe('saveDiagnosis', () => {
105
- it('应该保存诊断', () => {
106
- const diagnosis = {
107
- anomalyId: 'test',
108
- constraintId: 'test',
109
- diagnosedAt: Date.now(),
110
- rootCause: { primary: 'Test', evidence: [] },
111
- impact: { severity: 'medium' as const, scope: 'single_project' as const, userImpact: 'Test' },
112
- recommendations: [],
113
- needsChange: false,
114
- urgency: 'low' as const,
115
- };
116
-
117
- const outputPath = path.join(tempDir, 'diagnosis.json');
118
-
119
- doctor.saveDiagnosis(diagnosis, outputPath);
120
-
121
- expect(fs.existsSync(outputPath)).toBe(true);
122
- });
123
- });
124
-
125
- describe('loadDiagnosis', () => {
126
- it('应该加载诊断', () => {
127
- const diagnosis = {
128
- anomalyId: 'test-load',
129
- constraintId: 'test-load',
130
- diagnosedAt: Date.now(),
131
- rootCause: { primary: 'Test', evidence: [] },
132
- impact: { severity: 'low' as const, scope: 'single_project' as const, userImpact: 'Test' },
133
- recommendations: [],
134
- needsChange: false,
135
- urgency: 'low' as const,
136
- };
137
-
138
- const outputPath = path.join(tempDir, 'diagnosis-load.json');
139
- doctor.saveDiagnosis(diagnosis, outputPath);
140
-
141
- const loaded = doctor.loadDiagnosis(outputPath);
142
-
143
- expect(loaded).toBeDefined();
144
- expect(loaded.anomalyId).toBe('test-load');
145
- });
146
- });
147
-
148
- describe('diagnose - 更多异常类型', () => {
149
- it('应该诊断 rising_bypass_rate', async () => {
150
- const anomaly: TraceAnomaly = {
151
- type: 'rising_bypass_rate',
152
- constraintId: 'no_fix_without_root_cause',
153
- level: 'guideline',
154
- message: '绕过率上升',
155
- data: { currentRate: 0.4, threshold: 0.2, trend: 'rising' },
156
- detectedAt: Date.now(),
157
- };
158
-
159
- const diagnosis = await doctor.diagnose(anomaly);
160
-
161
- expect(diagnosis.rootCause.primary).toContain('绕过率');
162
- expect(diagnosis.needsChange).toBe(true);
163
- expect(diagnosis.urgency).toBe('high');
164
- });
165
-
166
- it('应该诊断 low_pass_rate', async () => {
167
- const anomaly: TraceAnomaly = {
168
- type: 'low_pass_rate',
169
- constraintId: 'capability_sync',
170
- level: 'guideline',
171
- message: '通过率过低',
172
- data: { currentRate: 0.1, threshold: 0.5 },
173
- detectedAt: Date.now(),
174
- };
175
-
176
- const diagnosis = await doctor.diagnose(anomaly);
177
-
178
- expect(diagnosis.rootCause.primary).toContain('通过率');
179
- expect(diagnosis.needsChange).toBe(true);
180
- expect(diagnosis.urgency).toBe('high');
181
- });
182
-
183
- it('应该诊断 exception_overuse', async () => {
184
- const anomaly: TraceAnomaly = {
185
- type: 'exception_overuse',
186
- constraintId: 'no_fix_without_root_cause',
187
- level: 'guideline',
188
- message: '例外过度使用',
189
- data: { currentRate: 0.6, threshold: 0.2 },
190
- detectedAt: Date.now(),
191
- };
192
-
193
- const diagnosis = await doctor.diagnose(anomaly);
194
-
195
- expect(diagnosis.rootCause.primary).toContain('例外');
196
- expect(diagnosis.needsChange).toBe(true);
197
- });
198
-
199
- it('rising_fail_rate 应该设置 severity 为 high 当 iron_law', async () => {
200
- const anomaly: TraceAnomaly = {
201
- type: 'rising_fail_rate',
202
- constraintId: 'no_completion_without_verification',
203
- level: 'iron_law',
204
- message: '失败率上升',
205
- data: { currentRate: 0.7, threshold: 0.3, trend: 'rising' },
206
- detectedAt: Date.now(),
207
- };
208
-
209
- const diagnosis = await doctor.diagnose(anomaly);
210
-
211
- expect(diagnosis.impact.severity).toBe('high');
212
- });
213
- });
214
-
215
- describe('diagnoseBatch', () => {
216
- it('应该批量诊断多个异常', async () => {
217
- const anomalies: TraceAnomaly[] = [
218
- {
219
- type: 'high_bypass_rate',
220
- constraintId: 'no_fix_without_root_cause',
221
- level: 'guideline',
222
- message: '绕过率过高',
223
- data: { currentRate: 0.5, threshold: 0.3 },
224
- detectedAt: Date.now(),
225
- },
226
- {
227
- type: 'low_pass_rate',
228
- constraintId: 'capability_sync',
229
- level: 'guideline',
230
- message: '通过率过低',
231
- data: { currentRate: 0.1, threshold: 0.5 },
232
- detectedAt: Date.now(),
233
- },
234
- ];
235
-
236
- const results = await doctor.diagnoseBatch(anomalies);
237
-
238
- expect(results.length).toBe(2);
239
- expect(results[0].constraintId).toBe('no_fix_without_root_cause');
240
- expect(results[1].constraintId).toBe('capability_sync');
241
- });
242
- });
243
-
244
- describe('saveDiagnosis - 目录不存在', () => {
245
- it('应该自动创建目录', () => {
246
- const nestedPath = path.join(tempDir, 'nested', 'deep', 'diagnosis.json');
247
- const diagnosis = {
248
- anomalyId: 'nested-test',
249
- constraintId: 'test',
250
- diagnosedAt: Date.now(),
251
- rootCause: { primary: 'Test', evidence: [] },
252
- impact: { severity: 'low' as const, scope: 'single_project' as const, userImpact: 'Test' },
253
- recommendations: [],
254
- needsChange: false,
255
- urgency: 'low' as const,
256
- };
257
-
258
- doctor.saveDiagnosis(diagnosis, nestedPath);
259
-
260
- expect(fs.existsSync(nestedPath)).toBe(true);
261
- });
262
- });
263
-
264
- describe('createDoctor 工厂函数', () => {
265
- it('应该创建实例', async () => {
266
- const { createDoctor } = await import('../monitoring/constraint-doctor');
267
- const d = createDoctor();
268
- expect(d).toBeDefined();
269
- });
270
- });
271
- });
@@ -1,155 +0,0 @@
1
- /**
2
- * ConstraintDoctor 测试
3
- */
4
-
5
- import * as fs from 'fs';
6
- import * as path from 'path';
7
- import * as os from 'os';
8
- import { ConstraintDoctor, createDoctor } from '../monitoring/constraint-doctor';
9
- import type { ExecutionTrace, TraceAnomaly } from '../types/trace';
10
-
11
- describe('ConstraintDoctor', () => {
12
- let tempDir: string;
13
- let doctor: ConstraintDoctor;
14
-
15
- beforeEach(() => {
16
- tempDir = path.join(os.tmpdir(), `harness-traces-${Date.now()}`);
17
- fs.mkdirSync(tempDir, { recursive: true });
18
- doctor = createDoctor();
19
- });
20
-
21
- afterEach(() => {
22
- if (fs.existsSync(tempDir)) {
23
- fs.rmSync(tempDir, { recursive: true });
24
- }
25
- });
26
-
27
- test('should diagnose high bypass rate anomaly', async () => {
28
- // 创建异常
29
- const anomaly: TraceAnomaly = {
30
- type: 'high_bypass_rate',
31
- constraintId: 'test_constraint',
32
- level: 'guideline',
33
- message: 'Bypass rate 40%',
34
- data: {
35
- currentRate: 0.4,
36
- threshold: 0.3,
37
- },
38
- detectedAt: Date.now(),
39
- suggestedAction: 'diagnose',
40
- };
41
-
42
- // 添加 traces
43
- const traces: ExecutionTrace[] = [];
44
- for (let i = 0; i < 10; i++) {
45
- traces.push({
46
- constraintId: 'test_constraint',
47
- level: 'guideline',
48
- timestamp: Date.now() - i * 60 * 1000,
49
- result: i < 6 ? 'bypassed' : 'pass',
50
- });
51
- }
52
- doctor.setData(traces);
53
-
54
- // 诊断
55
- const diagnosis = await doctor.diagnose(anomaly);
56
-
57
- expect(diagnosis.constraintId).toBe('test_constraint');
58
- expect(diagnosis.needsChange).toBe(true);
59
- expect(diagnosis.rootCause.primary).toContain('过于严格');
60
- expect(diagnosis.recommendations.length).toBeGreaterThan(0);
61
- expect(diagnosis.recommendations[0].type).toBe('add_exception');
62
- });
63
-
64
- test('should diagnose rising fail rate anomaly', async () => {
65
- const anomaly: TraceAnomaly = {
66
- type: 'rising_fail_rate',
67
- constraintId: 'another_constraint',
68
- level: 'iron_law',
69
- message: 'Fail rate rising',
70
- data: {
71
- currentRate: 0.6,
72
- threshold: 0.5,
73
- trend: 'rising',
74
- },
75
- detectedAt: Date.now(),
76
- suggestedAction: 'diagnose',
77
- };
78
-
79
- doctor.setData([]);
80
- const diagnosis = await doctor.diagnose(anomaly);
81
-
82
- expect(diagnosis.needsChange).toBe(true);
83
- expect(diagnosis.impact.severity).toBe('high'); // Iron law
84
- expect(diagnosis.urgency).toBe('medium'); // Iron law 强制 medium+
85
- });
86
-
87
- test('should detect exception overuse', async () => {
88
- const anomaly: TraceAnomaly = {
89
- type: 'exception_overuse',
90
- constraintId: 'constraint_with_exceptions',
91
- level: 'guideline',
92
- message: 'Exception rate 50%',
93
- data: {
94
- currentRate: 0.5,
95
- threshold: 0.4,
96
- },
97
- detectedAt: Date.now(),
98
- suggestedAction: 'add_exception',
99
- };
100
-
101
- doctor.setData([]);
102
- const diagnosis = await doctor.diagnose(anomaly);
103
-
104
- expect(diagnosis.rootCause.primary).toContain('过度使用');
105
- expect(diagnosis.recommendations[0].type).toBe('modify_constraint');
106
- });
107
-
108
- test('should generate diagnosis report', async () => {
109
- const anomaly: TraceAnomaly = {
110
- type: 'high_bypass_rate',
111
- constraintId: 'test',
112
- level: 'guideline',
113
- message: 'Test',
114
- data: {
115
- currentRate: 0.5,
116
- threshold: 0.3,
117
- },
118
- detectedAt: Date.now(),
119
- suggestedAction: 'diagnose',
120
- };
121
-
122
- doctor.setData([]);
123
- const diagnosis = await doctor.diagnose(anomaly);
124
- const report = doctor.generateReport(diagnosis);
125
-
126
- expect(report).toContain('# Diagnosis Report');
127
- expect(report).toContain('Root Cause');
128
- expect(report).toContain('Recommendations');
129
- expect(report).toContain('test');
130
- });
131
-
132
- test('should save and load diagnosis', async () => {
133
- const anomaly: TraceAnomaly = {
134
- type: 'high_bypass_rate',
135
- constraintId: 'save_test',
136
- level: 'guideline',
137
- message: 'Test',
138
- data: { currentRate: 0.5, threshold: 0.3 },
139
- detectedAt: Date.now(),
140
- suggestedAction: 'diagnose',
141
- };
142
-
143
- doctor.setData([]);
144
- const diagnosis = await doctor.diagnose(anomaly);
145
-
146
- const outputPath = path.join(tempDir, 'diagnosis.json');
147
- doctor.saveDiagnosis(diagnosis, outputPath);
148
-
149
- expect(fs.existsSync(outputPath)).toBe(true);
150
-
151
- const loaded = doctor.loadDiagnosis(outputPath);
152
- expect(loaded.constraintId).toBe('save_test');
153
- expect(loaded.needsChange).toBe(true);
154
- });
155
- });
@@ -1,149 +0,0 @@
1
- /**
2
- * extend_exceptions 功能测试
3
- */
4
-
5
- import { ProjectConfigLoader } from '../core/project-config-loader';
6
- import * as fs from 'fs';
7
-
8
- // Mock 文件系统
9
- jest.mock('fs');
10
-
11
- describe('extend_exceptions', () => {
12
- let loader: ProjectConfigLoader;
13
-
14
- beforeEach(() => {
15
- loader = new ProjectConfigLoader('/test/project');
16
- jest.clearAllMocks();
17
- });
18
-
19
- it('应该追加例外到内置约束', () => {
20
- // 模拟配置文件存在
21
- (fs.existsSync as jest.Mock).mockReturnValue(true);
22
- (fs.readFileSync as jest.Mock).mockImplementation((filePath: string) => {
23
- if (filePath.includes('config.yml')) {
24
- return 'preset: standard\n';
25
- }
26
- if (filePath.includes('custom-constraints.yml')) {
27
- return `
28
- custom_constraints:
29
- no_fix_without_root_cause:
30
- extend_exceptions:
31
- - MY_CUSTOM_EXCEPTION_1
32
- - MY_CUSTOM_EXCEPTION_2
33
- `;
34
- }
35
- return '';
36
- });
37
-
38
- loader.load();
39
- const merged = loader.mergeConstraints();
40
-
41
- // 注意:no_fix_without_root_cause 是 prompt 层约束(ADR-0001)
42
- const constraint = merged.prompts!['no_fix_without_root_cause'];
43
- expect(constraint).toBeDefined();
44
- // 应该包含内置例外
45
- expect(constraint?.exceptions).toContain('simple_typo');
46
- expect(constraint?.exceptions).toContain('config_value_error');
47
- // 应该包含新增例外
48
- expect(constraint?.exceptions).toContain('MY_CUSTOM_EXCEPTION_1');
49
- expect(constraint?.exceptions).toContain('MY_CUSTOM_EXCEPTION_2');
50
- // 总数应该是 5(3 内置 + 2 新增)
51
- expect(constraint?.exceptions?.length).toBe(5);
52
- });
53
-
54
- it('应该支持 exceptions + extend_exceptions', () => {
55
- (fs.existsSync as jest.Mock).mockReturnValue(true);
56
- (fs.readFileSync as jest.Mock).mockImplementation((filePath: string) => {
57
- if (filePath.includes('config.yml')) {
58
- return 'preset: standard\n';
59
- }
60
- if (filePath.includes('custom-constraints.yml')) {
61
- return `
62
- custom_constraints:
63
- no_fix_without_root_cause:
64
- exceptions:
65
- - MY_EXCEPTION
66
- extend_exceptions:
67
- - MY_EXTENDED
68
- `;
69
- }
70
- return '';
71
- });
72
-
73
- loader.load();
74
- const merged = loader.mergeConstraints();
75
-
76
- const constraint = merged.guidelines['no_fix_without_root_cause'];
77
- // 应该包含内置例外(因为有 extend_exceptions)
78
- expect(constraint?.exceptions).toContain('simple_typo');
79
- // 应该包含自定义例外
80
- expect(constraint?.exceptions).toContain('MY_EXCEPTION');
81
- // 应该包含扩展例外
82
- expect(constraint?.exceptions).toContain('MY_EXTENDED');
83
- // 总数应该是 5(3 内置 + 1 exceptions + 1 extend_exceptions)
84
- expect(constraint?.exceptions?.length).toBe(5);
85
- });
86
-
87
- it('没有 extend_exceptions 时应该完全覆盖', () => {
88
- (fs.existsSync as jest.Mock).mockReturnValue(true);
89
- (fs.readFileSync as jest.Mock).mockImplementation((filePath: string) => {
90
- if (filePath.includes('config.yml')) {
91
- return 'preset: standard\n';
92
- }
93
- if (filePath.includes('custom-constraints.yml')) {
94
- return `
95
- custom_constraints:
96
- no_fix_without_root_cause:
97
- level: guideline
98
- rule: Do not fix without root cause
99
- message: 禁止没有根因分析就修复
100
- trigger: bug_fix
101
- exceptions:
102
- - MY_EXCEPTION
103
- `;
104
- }
105
- return '';
106
- });
107
-
108
- loader.load();
109
- const merged = loader.mergeConstraints();
110
-
111
- const constraint = merged.guidelines['no_fix_without_root_cause'];
112
- // 应该只包含自定义例外
113
- expect(constraint?.exceptions).toEqual(['MY_EXCEPTION']);
114
- // 内置例外不应该保留
115
- expect(constraint?.exceptions).not.toContain('simple_typo');
116
- });
117
-
118
- it('纯扩展模式应该保留内置约束的其他属性', () => {
119
- (fs.existsSync as jest.Mock).mockReturnValue(true);
120
- (fs.readFileSync as jest.Mock).mockImplementation((filePath: string) => {
121
- if (filePath.includes('config.yml')) {
122
- return 'preset: standard\n';
123
- }
124
- if (filePath.includes('custom-constraints.yml')) {
125
- return `
126
- custom_constraints:
127
- no_fix_without_root_cause:
128
- extend_exceptions:
129
- - MY_PATTERN
130
- `;
131
- }
132
- return '';
133
- });
134
-
135
- loader.load();
136
- const merged = loader.mergeConstraints();
137
-
138
- const constraint = merged.prompts!['no_fix_without_root_cause'];
139
- expect(constraint).toBeDefined();
140
- // 应该保留内置约束的 rule
141
- expect(constraint?.rule).toBeTruthy();
142
- // 应该保留内置约束的 message
143
- expect(constraint?.message).toBeTruthy();
144
- // 应该包含新增的例外
145
- expect(constraint?.exceptions).toContain('MY_PATTERN');
146
- // 应该保留内置例外
147
- expect(constraint?.exceptions).toContain('simple_typo');
148
- });
149
- });
@@ -1,89 +0,0 @@
1
- /**
2
- * ConstraintInterceptor 测试
3
- */
4
-
5
- import { describe, it, expect } from '@jest/globals';
6
- import { ConstraintInterceptor } from '../core/constraints/interceptor';
7
- import type { EnforcementExecutor } from '../types/enforcement';
8
-
9
- describe('ConstraintInterceptor', () => {
10
- describe('单例模式', () => {
11
- it('应该返回单例实例', () => {
12
- const instance1 = ConstraintInterceptor.getInstance();
13
- const instance2 = ConstraintInterceptor.getInstance();
14
- expect(instance1).toBe(instance2);
15
- });
16
- });
17
-
18
- describe('setEnabled', () => {
19
- it('应该能启用/禁用拦截器', () => {
20
- const interceptor = ConstraintInterceptor.getInstance();
21
-
22
- interceptor.setEnabled(false);
23
- interceptor.setEnabled(true);
24
-
25
- expect(interceptor).toBeDefined();
26
- });
27
- });
28
-
29
- describe('register', () => {
30
- it('应该能注册执行器', () => {
31
- const interceptor = ConstraintInterceptor.getInstance();
32
-
33
- const executor: EnforcementExecutor = {
34
- execute: async () => ({
35
- passed: true,
36
- message: 'test',
37
- }),
38
- };
39
-
40
- interceptor.register('test_executor', executor);
41
-
42
- expect(interceptor).toBeDefined();
43
- });
44
- });
45
-
46
- describe('unregister', () => {
47
- it('应该能注销执行器', () => {
48
- const interceptor = ConstraintInterceptor.getInstance();
49
-
50
- const executor: EnforcementExecutor = {
51
- execute: async () => ({
52
- passed: true,
53
- message: 'temp',
54
- }),
55
- };
56
-
57
- interceptor.register('temp_executor', executor);
58
-
59
- const removed = interceptor.unregister('temp_executor');
60
- expect(removed).toBe(true);
61
- });
62
-
63
- it('注销不存在的执行器应该返回 false', () => {
64
- const interceptor = ConstraintInterceptor.getInstance();
65
-
66
- const removed = interceptor.unregister('nonexistent');
67
- expect(removed).toBe(false);
68
- });
69
- });
70
-
71
- describe('registerBatch', () => {
72
- it('应该能批量注册', () => {
73
- const interceptor = ConstraintInterceptor.getInstance();
74
-
75
- interceptor.registerBatch([
76
- {
77
- enforcementId: 'batch1',
78
- executor: { execute: async () => ({ passed: true }) },
79
- },
80
- {
81
- enforcementId: 'batch2',
82
- executor: { execute: async () => ({ passed: true }) },
83
- },
84
- ]);
85
-
86
- expect(interceptor).toBeDefined();
87
- });
88
- });
89
- });