@dommaker/harness 0.16.8 → 0.17.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 (344) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +33 -32
  3. package/bin/harness.js +34 -20
  4. package/dist/cli/commands/check.d.ts +3 -2
  5. package/dist/cli/commands/check.d.ts.map +1 -1
  6. package/dist/cli/commands/check.js +69 -36
  7. package/dist/cli/commands/check.js.map +1 -1
  8. package/dist/cli/commands/constraints-report.d.ts +42 -0
  9. package/dist/cli/commands/constraints-report.d.ts.map +1 -0
  10. package/dist/cli/commands/constraints-report.js +233 -0
  11. package/dist/cli/commands/constraints-report.js.map +1 -0
  12. package/dist/cli/commands/constraints-retire.d.ts +71 -0
  13. package/dist/cli/commands/constraints-retire.d.ts.map +1 -0
  14. package/dist/cli/commands/constraints-retire.js +384 -0
  15. package/dist/cli/commands/constraints-retire.js.map +1 -0
  16. package/dist/cli/commands/constraints.d.ts +1 -1
  17. package/dist/cli/commands/constraints.d.ts.map +1 -1
  18. package/dist/cli/commands/constraints.js +4 -4
  19. package/dist/cli/commands/constraints.js.map +1 -1
  20. package/dist/cli/commands/index.d.ts +2 -1
  21. package/dist/cli/commands/index.d.ts.map +1 -1
  22. package/dist/cli/commands/index.js +10 -4
  23. package/dist/cli/commands/index.js.map +1 -1
  24. package/dist/cli/commands/init.d.ts +20 -0
  25. package/dist/cli/commands/init.d.ts.map +1 -1
  26. package/dist/cli/commands/init.js +81 -59
  27. package/dist/cli/commands/init.js.map +1 -1
  28. package/dist/cli/commands/report.js +4 -4
  29. package/dist/cli/commands/report.js.map +1 -1
  30. package/dist/cli/commands/status.d.ts.map +1 -1
  31. package/dist/cli/commands/status.js +3 -4
  32. package/dist/cli/commands/status.js.map +1 -1
  33. package/dist/cli/commands/sync-docs/capabilities-syncer.d.ts +19 -2
  34. package/dist/cli/commands/sync-docs/capabilities-syncer.d.ts.map +1 -1
  35. package/dist/cli/commands/sync-docs/capabilities-syncer.js +79 -19
  36. package/dist/cli/commands/sync-docs/capabilities-syncer.js.map +1 -1
  37. package/dist/cli/commands/sync-docs/index.d.ts +2 -0
  38. package/dist/cli/commands/sync-docs/index.d.ts.map +1 -1
  39. package/dist/cli/commands/sync-docs/index.js +83 -20
  40. package/dist/cli/commands/sync-docs/index.js.map +1 -1
  41. package/dist/cli/commands/validate.d.ts.map +1 -1
  42. package/dist/cli/commands/validate.js +1 -5
  43. package/dist/cli/commands/validate.js.map +1 -1
  44. package/dist/core/constraints/capabilities-parser.d.ts +14 -0
  45. package/dist/core/constraints/capabilities-parser.d.ts.map +1 -1
  46. package/dist/core/constraints/capabilities-parser.js +30 -0
  47. package/dist/core/constraints/capabilities-parser.js.map +1 -1
  48. package/dist/core/constraints/checker.d.ts +13 -5
  49. package/dist/core/constraints/checker.d.ts.map +1 -1
  50. package/dist/core/constraints/checker.js +62 -25
  51. package/dist/core/constraints/checker.js.map +1 -1
  52. package/dist/core/constraints/checkers/capability-sync.d.ts +10 -0
  53. package/dist/core/constraints/checkers/capability-sync.d.ts.map +1 -1
  54. package/dist/core/constraints/checkers/capability-sync.js +73 -11
  55. package/dist/core/constraints/checkers/capability-sync.js.map +1 -1
  56. package/dist/core/constraints/checkers/context-doc-sync.d.ts +3 -0
  57. package/dist/core/constraints/checkers/context-doc-sync.d.ts.map +1 -1
  58. package/dist/core/constraints/checkers/context-doc-sync.js +8 -2
  59. package/dist/core/constraints/checkers/context-doc-sync.js.map +1 -1
  60. package/dist/core/constraints/checkers/docs-freshness.d.ts +1 -0
  61. package/dist/core/constraints/checkers/docs-freshness.d.ts.map +1 -1
  62. package/dist/core/constraints/checkers/docs-freshness.js +39 -0
  63. package/dist/core/constraints/checkers/docs-freshness.js.map +1 -1
  64. package/dist/core/constraints/checkers/index.d.ts +8 -4
  65. package/dist/core/constraints/checkers/index.d.ts.map +1 -1
  66. package/dist/core/constraints/checkers/index.js +29 -46
  67. package/dist/core/constraints/checkers/index.js.map +1 -1
  68. package/dist/core/constraints/checkers/iron-flags.d.ts +6 -7
  69. package/dist/core/constraints/checkers/iron-flags.d.ts.map +1 -1
  70. package/dist/core/constraints/checkers/iron-flags.js +10 -17
  71. package/dist/core/constraints/checkers/iron-flags.js.map +1 -1
  72. package/dist/core/constraints/checkers/no-hardcoded-credentials.d.ts +13 -0
  73. package/dist/core/constraints/checkers/no-hardcoded-credentials.d.ts.map +1 -0
  74. package/dist/core/constraints/checkers/no-hardcoded-credentials.js +91 -0
  75. package/dist/core/constraints/checkers/no-hardcoded-credentials.js.map +1 -0
  76. package/dist/core/constraints/checkers/types.d.ts +15 -4
  77. package/dist/core/constraints/checkers/types.d.ts.map +1 -1
  78. package/dist/core/constraints/checkers/types.js +16 -4
  79. package/dist/core/constraints/checkers/types.js.map +1 -1
  80. package/dist/core/constraints/context-builder.d.ts +6 -3
  81. package/dist/core/constraints/context-builder.d.ts.map +1 -1
  82. package/dist/core/constraints/context-builder.js +29 -20
  83. package/dist/core/constraints/context-builder.js.map +1 -1
  84. package/dist/core/constraints/definitions/guidelines.d.ts +6 -2
  85. package/dist/core/constraints/definitions/guidelines.d.ts.map +1 -1
  86. package/dist/core/constraints/definitions/guidelines.js +33 -574
  87. package/dist/core/constraints/definitions/guidelines.js.map +1 -1
  88. package/dist/core/constraints/definitions/iron-laws.d.ts +6 -2
  89. package/dist/core/constraints/definitions/iron-laws.d.ts.map +1 -1
  90. package/dist/core/constraints/definitions/iron-laws.js +48 -231
  91. package/dist/core/constraints/definitions/iron-laws.js.map +1 -1
  92. package/dist/core/constraints/definitions/prompts.d.ts +12 -0
  93. package/dist/core/constraints/definitions/prompts.d.ts.map +1 -0
  94. package/dist/core/constraints/definitions/prompts.js +405 -0
  95. package/dist/core/constraints/definitions/prompts.js.map +1 -0
  96. package/dist/core/constraints/definitions.d.ts +15 -9
  97. package/dist/core/constraints/definitions.d.ts.map +1 -1
  98. package/dist/core/constraints/definitions.js +18 -12
  99. package/dist/core/constraints/definitions.js.map +1 -1
  100. package/dist/core/constraints/index.d.ts +3 -2
  101. package/dist/core/constraints/index.d.ts.map +1 -1
  102. package/dist/core/constraints/index.js +8 -2
  103. package/dist/core/constraints/index.js.map +1 -1
  104. package/dist/core/constraints/injection-drift.d.ts +48 -0
  105. package/dist/core/constraints/injection-drift.d.ts.map +1 -0
  106. package/dist/core/constraints/injection-drift.js +140 -0
  107. package/dist/core/constraints/injection-drift.js.map +1 -0
  108. package/dist/core/constraints/injection-renderer.d.ts +23 -0
  109. package/dist/core/constraints/injection-renderer.d.ts.map +1 -0
  110. package/dist/core/constraints/injection-renderer.js +44 -0
  111. package/dist/core/constraints/injection-renderer.js.map +1 -0
  112. package/dist/core/constraints/interceptor.d.ts.map +1 -1
  113. package/dist/core/constraints/interceptor.js +3 -2
  114. package/dist/core/constraints/interceptor.js.map +1 -1
  115. package/dist/core/constraints/usage-report.d.ts +95 -0
  116. package/dist/core/constraints/usage-report.d.ts.map +1 -0
  117. package/dist/core/constraints/usage-report.js +206 -0
  118. package/dist/core/constraints/usage-report.js.map +1 -0
  119. package/dist/core/effective-constraints.d.ts +47 -0
  120. package/dist/core/effective-constraints.d.ts.map +1 -0
  121. package/dist/core/effective-constraints.js +60 -0
  122. package/dist/core/effective-constraints.js.map +1 -0
  123. package/dist/core/index.d.ts +1 -0
  124. package/dist/core/index.d.ts.map +1 -1
  125. package/dist/core/index.js +2 -0
  126. package/dist/core/index.js.map +1 -1
  127. package/dist/core/project-config-loader.d.ts +28 -3
  128. package/dist/core/project-config-loader.d.ts.map +1 -1
  129. package/dist/core/project-config-loader.js +74 -8
  130. package/dist/core/project-config-loader.js.map +1 -1
  131. package/dist/dashboard/data.d.ts +1 -9
  132. package/dist/dashboard/data.d.ts.map +1 -1
  133. package/dist/dashboard/data.js +7 -15
  134. package/dist/dashboard/data.js.map +1 -1
  135. package/dist/dashboard/types.d.ts +13 -1
  136. package/dist/dashboard/types.d.ts.map +1 -1
  137. package/dist/index.d.ts +0 -4
  138. package/dist/index.d.ts.map +1 -1
  139. package/dist/index.js +1 -13
  140. package/dist/index.js.map +1 -1
  141. package/dist/monitoring/index.d.ts +0 -2
  142. package/dist/monitoring/index.d.ts.map +1 -1
  143. package/dist/monitoring/index.js +0 -2
  144. package/dist/monitoring/index.js.map +1 -1
  145. package/dist/monitoring/knowledge-evolver.d.ts +1 -1
  146. package/dist/monitoring/knowledge-evolver.js +1 -1
  147. package/dist/monitoring/trace-analyzer.d.ts +1 -1
  148. package/dist/monitoring/trace-analyzer.d.ts.map +1 -1
  149. package/dist/monitoring/trace-analyzer.js +16 -10
  150. package/dist/monitoring/trace-analyzer.js.map +1 -1
  151. package/dist/monitoring/traces.d.ts +2 -1
  152. package/dist/monitoring/traces.d.ts.map +1 -1
  153. package/dist/monitoring/traces.js +5 -3
  154. package/dist/monitoring/traces.js.map +1 -1
  155. package/dist/presets/standard.d.ts +3 -1
  156. package/dist/presets/standard.d.ts.map +1 -1
  157. package/dist/presets/standard.js +18 -8
  158. package/dist/presets/standard.js.map +1 -1
  159. package/dist/types/constraint.d.ts +51 -11
  160. package/dist/types/constraint.d.ts.map +1 -1
  161. package/dist/types/constraint.js +8 -4
  162. package/dist/types/constraint.js.map +1 -1
  163. package/dist/types/index.d.ts +1 -1
  164. package/dist/types/index.d.ts.map +1 -1
  165. package/dist/types/index.js.map +1 -1
  166. package/dist/types/monitoring-types.d.ts +2 -63
  167. package/dist/types/monitoring-types.d.ts.map +1 -1
  168. package/dist/types/monitoring-types.js +2 -2
  169. package/dist/types/project-config.d.ts +32 -1
  170. package/dist/types/project-config.d.ts.map +1 -1
  171. package/dist/types/trace.d.ts +16 -7
  172. package/dist/types/trace.d.ts.map +1 -1
  173. package/dist/types/trace.js +8 -0
  174. package/dist/types/trace.js.map +1 -1
  175. package/package.json +1 -1
  176. package/src/CONTEXT.md +2 -2
  177. package/src/__tests__/checker-extra.test.ts +356 -331
  178. package/src/__tests__/checker.test.ts +87 -724
  179. package/src/__tests__/constraint-doctor.test.ts +5 -5
  180. package/src/__tests__/doctor-extra.test.ts +164 -0
  181. package/src/__tests__/effective-constraints.test.ts +147 -0
  182. package/src/__tests__/extend-exceptions.test.ts +3 -3
  183. package/src/__tests__/iron-laws.test.ts +115 -91
  184. package/src/__tests__/no-hardcoded-credentials.test.ts +90 -0
  185. package/src/__tests__/presets.test.ts +7 -7
  186. package/src/__tests__/project-config-loader-extra.test.ts +4 -4
  187. package/src/__tests__/project-config-loader.test.ts +40 -1
  188. package/src/__tests__/skip-semantics.test.ts +322 -0
  189. package/src/cli/commands/CONTEXT.md +5 -3
  190. package/src/cli/commands/__tests__/check-drift.test.ts +127 -0
  191. package/src/cli/commands/__tests__/check-skip-output.test.ts +128 -0
  192. package/src/cli/commands/__tests__/check.test.ts +14 -25
  193. package/src/cli/commands/__tests__/constraints-report.test.ts +327 -0
  194. package/src/cli/commands/__tests__/constraints-retire.test.ts +283 -0
  195. package/src/cli/commands/__tests__/init-injection.test.ts +234 -0
  196. package/src/cli/commands/__tests__/status-extra.test.ts +11 -11
  197. package/src/cli/commands/__tests__/status.test.ts +1 -1
  198. package/src/cli/commands/__tests__/sync-docs.test.ts +163 -0
  199. package/src/cli/commands/check.ts +72 -38
  200. package/src/cli/commands/constraints-report.ts +234 -0
  201. package/src/cli/commands/constraints-retire.ts +443 -0
  202. package/src/cli/commands/constraints.ts +5 -5
  203. package/src/cli/commands/index.ts +2 -1
  204. package/src/cli/commands/init.ts +94 -66
  205. package/src/cli/commands/report.ts +6 -6
  206. package/src/cli/commands/status.ts +3 -4
  207. package/src/cli/commands/sync-docs/capabilities-syncer.ts +90 -15
  208. package/src/cli/commands/sync-docs/index.ts +87 -24
  209. package/src/cli/commands/validate.ts +1 -5
  210. package/src/core/CONTEXT.md +7 -4
  211. package/src/core/constraints/__tests__/injection-drift.test.ts +164 -0
  212. package/src/core/constraints/__tests__/interceptor.test.ts +4 -0
  213. package/src/core/constraints/capabilities-parser.ts +28 -0
  214. package/src/core/constraints/checker.ts +73 -28
  215. package/src/core/constraints/checkers/capability-sync.ts +89 -18
  216. package/src/core/constraints/checkers/context-doc-sync.ts +9 -2
  217. package/src/core/constraints/checkers/docs-freshness.ts +43 -0
  218. package/src/core/constraints/checkers/index.ts +38 -71
  219. package/src/core/constraints/checkers/iron-flags.ts +13 -49
  220. package/src/core/constraints/checkers/no-hardcoded-credentials.ts +93 -0
  221. package/src/core/constraints/checkers/types.ts +27 -5
  222. package/src/core/constraints/context-builder.ts +28 -19
  223. package/src/core/constraints/definitions/guidelines.ts +33 -599
  224. package/src/core/constraints/definitions/iron-laws.ts +48 -239
  225. package/src/core/constraints/definitions/prompts.ts +419 -0
  226. package/src/core/constraints/definitions.ts +18 -11
  227. package/src/core/constraints/index.ts +10 -1
  228. package/src/core/constraints/injection-drift.ts +139 -0
  229. package/src/core/constraints/injection-renderer.ts +44 -0
  230. package/src/core/constraints/interceptor.ts +3 -2
  231. package/src/core/constraints/usage-report.ts +254 -0
  232. package/src/core/effective-constraints.ts +85 -0
  233. package/src/core/index.ts +4 -1
  234. package/src/core/project-config-loader.ts +82 -9
  235. package/src/dashboard/__tests__/data.test.ts +5 -12
  236. package/src/dashboard/data.ts +9 -19
  237. package/src/dashboard/types.ts +18 -1
  238. package/src/index.ts +0 -12
  239. package/src/knowledge/CONTEXT.md +2 -2
  240. package/src/monitoring/CONTEXT.md +3 -4
  241. package/src/monitoring/index.ts +0 -2
  242. package/src/monitoring/knowledge-evolver.ts +1 -1
  243. package/src/monitoring/trace-analyzer.ts +15 -10
  244. package/src/monitoring/traces.ts +10 -6
  245. package/src/presets/__tests__/standard.test.ts +11 -9
  246. package/src/presets/standard.ts +24 -15
  247. package/src/types/constraint.ts +59 -14
  248. package/src/types/index.ts +1 -3
  249. package/src/types/monitoring-types.ts +2 -84
  250. package/src/types/project-config.ts +37 -1
  251. package/src/types/trace.ts +18 -7
  252. package/src/verification/CONTEXT.md +1 -1
  253. package/dist/cli/commands/flow.d.ts +0 -22
  254. package/dist/cli/commands/flow.d.ts.map +0 -1
  255. package/dist/cli/commands/flow.js +0 -275
  256. package/dist/cli/commands/flow.js.map +0 -1
  257. package/dist/constraints/lifecycle-runner.d.ts +0 -52
  258. package/dist/constraints/lifecycle-runner.d.ts.map +0 -1
  259. package/dist/constraints/lifecycle-runner.js +0 -151
  260. package/dist/constraints/lifecycle-runner.js.map +0 -1
  261. package/dist/constraints/registry.d.ts +0 -27
  262. package/dist/constraints/registry.d.ts.map +0 -1
  263. package/dist/constraints/registry.js +0 -128
  264. package/dist/constraints/registry.js.map +0 -1
  265. package/dist/constraints/types.d.ts +0 -53
  266. package/dist/constraints/types.d.ts.map +0 -1
  267. package/dist/constraints/types.js +0 -8
  268. package/dist/constraints/types.js.map +0 -1
  269. package/dist/core/constraints/checkers/always-pass.d.ts +0 -17
  270. package/dist/core/constraints/checkers/always-pass.d.ts.map +0 -1
  271. package/dist/core/constraints/checkers/always-pass.js +0 -23
  272. package/dist/core/constraints/checkers/always-pass.js.map +0 -1
  273. package/dist/core/constraints/checkers/guideline-flags.d.ts +0 -9
  274. package/dist/core/constraints/checkers/guideline-flags.d.ts.map +0 -1
  275. package/dist/core/constraints/checkers/guideline-flags.js +0 -13
  276. package/dist/core/constraints/checkers/guideline-flags.js.map +0 -1
  277. package/dist/core/constraints/checkers/no-any-type.d.ts +0 -6
  278. package/dist/core/constraints/checkers/no-any-type.d.ts.map +0 -1
  279. package/dist/core/constraints/checkers/no-any-type.js +0 -42
  280. package/dist/core/constraints/checkers/no-any-type.js.map +0 -1
  281. package/dist/core/constraints/checkers/no-excuse-patterns.d.ts +0 -6
  282. package/dist/core/constraints/checkers/no-excuse-patterns.d.ts.map +0 -1
  283. package/dist/core/constraints/checkers/no-excuse-patterns.js +0 -25
  284. package/dist/core/constraints/checkers/no-excuse-patterns.js.map +0 -1
  285. package/dist/core/constraints/checkers/no-fuzzy-completion-claim.d.ts +0 -6
  286. package/dist/core/constraints/checkers/no-fuzzy-completion-claim.d.ts.map +0 -1
  287. package/dist/core/constraints/checkers/no-fuzzy-completion-claim.js +0 -34
  288. package/dist/core/constraints/checkers/no-fuzzy-completion-claim.js.map +0 -1
  289. package/dist/core/constraints/checkers/no-performative-agreement.d.ts +0 -8
  290. package/dist/core/constraints/checkers/no-performative-agreement.d.ts.map +0 -1
  291. package/dist/core/constraints/checkers/no-performative-agreement.js +0 -23
  292. package/dist/core/constraints/checkers/no-performative-agreement.js.map +0 -1
  293. package/dist/core/constraints/checkers/no-simplification-without-approval.d.ts +0 -6
  294. package/dist/core/constraints/checkers/no-simplification-without-approval.d.ts.map +0 -1
  295. package/dist/core/constraints/checkers/no-simplification-without-approval.js +0 -30
  296. package/dist/core/constraints/checkers/no-simplification-without-approval.js.map +0 -1
  297. package/dist/core/constraints/checkers/test-coverage.d.ts +0 -6
  298. package/dist/core/constraints/checkers/test-coverage.d.ts.map +0 -1
  299. package/dist/core/constraints/checkers/test-coverage.js +0 -33
  300. package/dist/core/constraints/checkers/test-coverage.js.map +0 -1
  301. package/dist/core/constraints/checkers/yagni.d.ts +0 -8
  302. package/dist/core/constraints/checkers/yagni.d.ts.map +0 -1
  303. package/dist/core/constraints/checkers/yagni.js +0 -96
  304. package/dist/core/constraints/checkers/yagni.js.map +0 -1
  305. package/dist/core/constraints/definitions/tips.d.ts +0 -7
  306. package/dist/core/constraints/definitions/tips.d.ts.map +0 -1
  307. package/dist/core/constraints/definitions/tips.js +0 -62
  308. package/dist/core/constraints/definitions/tips.js.map +0 -1
  309. package/dist/evolution/auto-evolve.d.ts +0 -35
  310. package/dist/evolution/auto-evolve.d.ts.map +0 -1
  311. package/dist/evolution/auto-evolve.js +0 -64
  312. package/dist/evolution/auto-evolve.js.map +0 -1
  313. package/dist/evolution/index.d.ts +0 -2
  314. package/dist/evolution/index.d.ts.map +0 -1
  315. package/dist/evolution/index.js +0 -18
  316. package/dist/evolution/index.js.map +0 -1
  317. package/dist/monitoring/constraint-evolver.d.ts +0 -120
  318. package/dist/monitoring/constraint-evolver.d.ts.map +0 -1
  319. package/dist/monitoring/constraint-evolver.js +0 -410
  320. package/dist/monitoring/constraint-evolver.js.map +0 -1
  321. package/src/__tests__/constraint-evolver.test.ts +0 -405
  322. package/src/__tests__/doctor-evolver.test.ts +0 -381
  323. package/src/cli/commands/__tests__/flow.test.ts +0 -343
  324. package/src/cli/commands/flow.ts +0 -277
  325. package/src/constraints/__tests__/lifecycle-runner.test.ts +0 -246
  326. package/src/constraints/__tests__/registry.test.ts +0 -196
  327. package/src/constraints/lifecycle-runner.ts +0 -184
  328. package/src/constraints/registry.ts +0 -134
  329. package/src/constraints/types.ts +0 -59
  330. package/src/core/constraints/checkers/always-pass.ts +0 -22
  331. package/src/core/constraints/checkers/guideline-flags.ts +0 -30
  332. package/src/core/constraints/checkers/no-any-type.ts +0 -42
  333. package/src/core/constraints/checkers/no-excuse-patterns.ts +0 -24
  334. package/src/core/constraints/checkers/no-fuzzy-completion-claim.ts +0 -33
  335. package/src/core/constraints/checkers/no-performative-agreement.ts +0 -22
  336. package/src/core/constraints/checkers/no-simplification-without-approval.ts +0 -29
  337. package/src/core/constraints/checkers/test-coverage.ts +0 -35
  338. package/src/core/constraints/checkers/yagni.ts +0 -65
  339. package/src/core/constraints/definitions/tips.ts +0 -63
  340. package/src/evolution/CONTEXT.md +0 -22
  341. package/src/evolution/__tests__/auto-evolve.test.ts +0 -319
  342. package/src/evolution/auto-evolve.ts +0 -98
  343. package/src/evolution/index.ts +0 -1
  344. package/src/monitoring/constraint-evolver.ts +0 -501
@@ -0,0 +1,44 @@
1
+ /**
2
+ * CLAUDE.md 约束注入段渲染(ADR-0001)
3
+ *
4
+ * 纯函数:输入生效约束集 + harness 版本,输出标记区间的期望文本。
5
+ * 与写文件分离——init 注入与 P6 注入漂移校验(期望 vs 实际)共用此渲染。
6
+ */
7
+
8
+ import type { Constraint } from '../../types/constraint';
9
+
10
+ /** 约束注入段开始标记 */
11
+ export const CONSTRAINTS_START_MARKER = '<!-- HARNESS_CONSTRAINTS_START -->';
12
+ /** 约束注入段结束标记 */
13
+ export const CONSTRAINTS_END_MARKER = '<!-- HARNESS_CONSTRAINTS_END -->';
14
+
15
+ /**
16
+ * 渲染 CLAUDE.md 约束注入段(含 START/END 标记,不含 `## Governance Rules` 标题)
17
+ *
18
+ * 结构:### Iron Laws / ### Guidelines / ### Prompts(行为约束),
19
+ * 条目为 `- **id**: promptInjection`;无 promptInjection 的 check 条目
20
+ * (如 docs_freshness)不出现在注入段。返回文本以换行结尾。
21
+ *
22
+ * @param constraints 生效约束集(getEffectiveConstraints 的输出)
23
+ * @param version harness 版本号(写入 `<!-- version: x -->` 供漂移校验)
24
+ */
25
+ export function renderConstraintsSection(constraints: Constraint[], version: string): string {
26
+ const lines: string[] = [CONSTRAINTS_START_MARKER, `<!-- version: ${version} -->`];
27
+
28
+ const renderGroup = (level: 'iron_law' | 'guideline' | 'prompt', heading: string, first: boolean) => {
29
+ const items = constraints.filter(c => c.level === level && c.promptInjection);
30
+ if (items.length === 0) return;
31
+ if (!first) lines.push('');
32
+ lines.push(heading);
33
+ for (const c of items) {
34
+ lines.push(`- **${c.id}**: ${c.promptInjection}`);
35
+ }
36
+ };
37
+
38
+ renderGroup('iron_law', '### Iron Laws (违反将阻断)', true);
39
+ renderGroup('guideline', '### Guidelines (应遵循)', lines.length === 2);
40
+ renderGroup('prompt', '### Prompts (行为约束)', lines.length === 2);
41
+
42
+ lines.push(CONSTRAINTS_END_MARKER);
43
+ return lines.join('\n') + '\n';
44
+ }
@@ -111,17 +111,18 @@ export class ConstraintInterceptor {
111
111
  };
112
112
 
113
113
  const constraints = constraintChecker.getConstraints();
114
+ // prompt 类约束不参与拦截执行(ADR-0001:仅参与注入)
114
115
  const allConstraints = [
115
116
  ...Object.values(constraints.ironLaws),
116
117
  ...Object.values(constraints.guidelines),
117
118
  ...Object.values(constraints.tips),
118
- ];
119
+ ].filter(c => c.kind !== 'prompt');
119
120
 
120
121
  const applicableConstraints = allConstraints.filter(
121
122
  (c) => normalizeTriggers<ConstraintTrigger>(c.trigger).includes(trigger)
122
123
  );
123
124
 
124
- const order: Record<ConstraintLevel, number> = { iron_law: 0, guideline: 1, tip: 2 };
125
+ const order: Record<ConstraintLevel, number> = { iron_law: 0, guideline: 1, prompt: 2, tip: 3 };
125
126
  const ordered = applicableConstraints.sort((a, b) => order[a.level] - order[b.level]);
126
127
 
127
128
  for (const constraint of ordered) {
@@ -0,0 +1,254 @@
1
+ /**
2
+ * 约束使用统计与退役候选诊断(ADR-0001 决策 2/3)
3
+ *
4
+ * `harness constraints report` 与 `harness constraints retire`(交互模式)共用的
5
+ * 数据层:读取项目 traces.log,与生效集(getEffectiveConstraints)对齐,
6
+ * 产出 check 层统计表与四类退役候选诊断。
7
+ *
8
+ * 只读:不创建目录、不写任何文件。
9
+ */
10
+
11
+ import * as fs from 'fs';
12
+ import * as path from 'path';
13
+ import type { Constraint } from '../../types/constraint';
14
+ import type { ExecutionTrace } from '../../types/trace';
15
+ import { DEFAULT_TRACE_FILE } from '../../types/trace';
16
+ import { getEffectiveConstraints, lintEffectiveConfig } from '../effective-constraints';
17
+ import type { EffectiveConfigLint } from '../effective-constraints';
18
+
19
+ /**
20
+ * flag 型 check 约束(证据来自 ConstraintContext flag,见 checkers/iron-flags.ts)。
21
+ * 全部 skip 时标注"证据 flag 未接线"(区别于存在性探测的"约定未采用")。
22
+ */
23
+ export const FLAG_EVIDENCE_CONSTRAINT_IDS: ReadonlySet<string> = new Set([
24
+ 'no_completion_without_verification',
25
+ 'incremental_progress',
26
+ 'no_implementation_without_requirement',
27
+ ]);
28
+
29
+ /**
30
+ * 单条 check 约束的使用统计
31
+ */
32
+ export interface ConstraintUsageStats {
33
+ id: string;
34
+ level: Constraint['level'];
35
+
36
+ /** trace 总行数(含 skip/bypassed) */
37
+ total: number;
38
+ pass: number;
39
+ fail: number;
40
+ skip: number;
41
+ bypassed: number;
42
+
43
+ /** 实际评估次数(total - skip;skip 未评估不计入,与 TraceAnalyzer 一致) */
44
+ evaluated: number;
45
+
46
+ /** 失败率(fail / evaluated;evaluated=0 时为 0) */
47
+ failRate: number;
48
+
49
+ /** 首次/最近触发时间(Unix ms);无 trace 时为 undefined */
50
+ firstAt?: number;
51
+ lastAt?: number;
52
+ }
53
+
54
+ /**
55
+ * 退役候选类别
56
+ */
57
+ export type RetireCandidateKind =
58
+ | 'zero_trigger' // 零触发:生效集中从未出现在 trace
59
+ | 'unevaluable' // 不可评估:全部 skip
60
+ | 'high_noise' // 高噪:fail 率异常高,疑似误报源
61
+ | 'zero_intercept'; // 零拦截:样本充足但从未 fail
62
+
63
+ export interface RetireCandidate {
64
+ id: string;
65
+ kind: RetireCandidateKind;
66
+ stats: ConstraintUsageStats;
67
+ /** 人类可读的诊断说明(带证据数字) */
68
+ reason: string;
69
+ }
70
+
71
+ /**
72
+ * 候选诊断阈值(CLI 可覆盖)
73
+ */
74
+ export interface DiagnoseThresholds {
75
+ /** 零拦截候选的最小评估样本数,默认 50 */
76
+ zeroInterceptMinEvaluated: number;
77
+ /** 高噪候选的 fail 率阈值(严格大于),默认 0.8 */
78
+ highNoiseFailRate: number;
79
+ /** 高噪候选的最小评估样本数,默认 20 */
80
+ highNoiseMinEvaluated: number;
81
+ }
82
+
83
+ export const DEFAULT_DIAGNOSE_THRESHOLDS: DiagnoseThresholds = {
84
+ zeroInterceptMinEvaluated: 50,
85
+ highNoiseFailRate: 0.8,
86
+ highNoiseMinEvaluated: 20,
87
+ };
88
+
89
+ /**
90
+ * report 数据模型
91
+ */
92
+ export interface ConstraintsUsageReport {
93
+ /** check 层统计表(生效集内每条 check 约束一行,零出现 total=0) */
94
+ stats: ConstraintUsageStats[];
95
+ /** 退役候选诊断(按 zero_trigger → unevaluable → high_noise → zero_intercept 排序) */
96
+ candidates: RetireCandidate[];
97
+ /** 当前生效的 prompt 条目 id(注入清单) */
98
+ activePromptIds: string[];
99
+ /** 配置健康诊断(unknownIds 等) */
100
+ lint: EffectiveConfigLint;
101
+ /** trace 文件是否存在 */
102
+ traceFileExists: boolean;
103
+ }
104
+
105
+ /**
106
+ * 读取项目 traces.log(只读,容错:坏行跳过)
107
+ */
108
+ export function readProjectTraces(projectRoot: string): ExecutionTrace[] {
109
+ const tracePath = path.join(projectRoot, DEFAULT_TRACE_FILE);
110
+ if (!fs.existsSync(tracePath)) return [];
111
+
112
+ const content = fs.readFileSync(tracePath, 'utf-8');
113
+ const traces: ExecutionTrace[] = [];
114
+ for (const line of content.split('\n')) {
115
+ const trimmed = line.trim();
116
+ if (!trimmed) continue;
117
+ try {
118
+ traces.push(JSON.parse(trimmed) as ExecutionTrace);
119
+ } catch {
120
+ // 坏行跳过(report 只读,不因单行损坏失败)
121
+ }
122
+ }
123
+ return traces;
124
+ }
125
+
126
+ /**
127
+ * 按约束聚合 trace 统计(Map: constraintId → 计数)
128
+ */
129
+ export function collectUsageByConstraint(
130
+ traces: ExecutionTrace[]
131
+ ): Map<string, Omit<ConstraintUsageStats, 'id' | 'level' | 'evaluated' | 'failRate'>> {
132
+ const map = new Map<string, { total: number; pass: number; fail: number; skip: number; bypassed: number; firstAt?: number; lastAt?: number }>();
133
+ for (const t of traces) {
134
+ let agg = map.get(t.constraintId);
135
+ if (!agg) {
136
+ agg = { total: 0, pass: 0, fail: 0, skip: 0, bypassed: 0 };
137
+ map.set(t.constraintId, agg);
138
+ }
139
+ agg.total++;
140
+ if (t.result === 'pass') agg.pass++;
141
+ else if (t.result === 'fail') agg.fail++;
142
+ else if (t.result === 'skip') agg.skip++;
143
+ else if (t.result === 'bypassed') agg.bypassed++;
144
+ if (agg.firstAt === undefined || t.timestamp < agg.firstAt) agg.firstAt = t.timestamp;
145
+ if (agg.lastAt === undefined || t.timestamp > agg.lastAt) agg.lastAt = t.timestamp;
146
+ }
147
+ return map;
148
+ }
149
+
150
+ function toStats(id: string, level: Constraint['level'], agg: { total: number; pass: number; fail: number; skip: number; bypassed: number; firstAt?: number; lastAt?: number } | undefined): ConstraintUsageStats {
151
+ const a = agg ?? { total: 0, pass: 0, fail: 0, skip: 0, bypassed: 0 };
152
+ const evaluated = a.total - a.skip;
153
+ return {
154
+ id,
155
+ level,
156
+ total: a.total,
157
+ pass: a.pass,
158
+ fail: a.fail,
159
+ skip: a.skip,
160
+ bypassed: a.bypassed,
161
+ evaluated,
162
+ failRate: evaluated > 0 ? a.fail / evaluated : 0,
163
+ firstAt: a.firstAt,
164
+ lastAt: a.lastAt,
165
+ };
166
+ }
167
+
168
+ /**
169
+ * 退役候选诊断(纯函数)
170
+ *
171
+ * 每条 check 约束最多归入一个类别,优先级:
172
+ * zero_trigger → unevaluable → high_noise → zero_intercept
173
+ */
174
+ export function diagnoseRetireCandidates(
175
+ stats: ConstraintUsageStats[],
176
+ thresholds: Partial<DiagnoseThresholds> = {}
177
+ ): RetireCandidate[] {
178
+ const t = { ...DEFAULT_DIAGNOSE_THRESHOLDS, ...thresholds };
179
+ const candidates: RetireCandidate[] = [];
180
+
181
+ for (const s of stats) {
182
+ if (s.total === 0) {
183
+ candidates.push({
184
+ id: s.id,
185
+ kind: 'zero_trigger',
186
+ stats: s,
187
+ reason: '零触发:生效集内从未出现在 trace',
188
+ });
189
+ continue;
190
+ }
191
+
192
+ if (s.skip === s.total) {
193
+ const wiring = FLAG_EVIDENCE_CONSTRAINT_IDS.has(s.id)
194
+ ? '证据 flag 未接线'
195
+ : '约定未采用(存在性探测未命中)';
196
+ candidates.push({
197
+ id: s.id,
198
+ kind: 'unevaluable',
199
+ stats: s,
200
+ reason: `不可评估:全部 ${s.total} 次均为 skip(${wiring})`,
201
+ });
202
+ continue;
203
+ }
204
+
205
+ if (s.failRate > t.highNoiseFailRate && s.evaluated >= t.highNoiseMinEvaluated) {
206
+ candidates.push({
207
+ id: s.id,
208
+ kind: 'high_noise',
209
+ stats: s,
210
+ reason: `高噪:fail 率 ${Math.round(s.failRate * 100)}%(${s.fail}/${s.evaluated}),疑似误报源`,
211
+ });
212
+ continue;
213
+ }
214
+
215
+ if (s.fail === 0 && s.evaluated >= t.zeroInterceptMinEvaluated) {
216
+ candidates.push({
217
+ id: s.id,
218
+ kind: 'zero_intercept',
219
+ stats: s,
220
+ reason: `零拦截:${s.evaluated} 次评估从未 fail`,
221
+ });
222
+ }
223
+ }
224
+
225
+ return candidates;
226
+ }
227
+
228
+ /**
229
+ * 构建 report 数据模型(只读)
230
+ */
231
+ export function buildConstraintsUsageReport(
232
+ projectRoot: string = process.cwd(),
233
+ thresholds: Partial<DiagnoseThresholds> = {}
234
+ ): ConstraintsUsageReport {
235
+ const effective = getEffectiveConstraints(projectRoot);
236
+ const checkConstraints = effective.filter(c => c.kind === 'check');
237
+ const activePromptIds = effective.filter(c => c.kind === 'prompt').map(c => c.id);
238
+
239
+ const tracePath = path.join(projectRoot, DEFAULT_TRACE_FILE);
240
+ const traces = readProjectTraces(projectRoot);
241
+ const usage = collectUsageByConstraint(traces);
242
+
243
+ const stats = checkConstraints.map(c => toStats(c.id, c.level, usage.get(c.id)));
244
+ const candidates = diagnoseRetireCandidates(stats, thresholds);
245
+ const lint = lintEffectiveConfig(projectRoot);
246
+
247
+ return {
248
+ stats,
249
+ candidates,
250
+ activePromptIds,
251
+ lint,
252
+ traceFileExists: fs.existsSync(tracePath),
253
+ };
254
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * 生效约束集(ADR-0001)
3
+ *
4
+ * `getEffectiveConstraints(projectRoot)` 是全仓唯一的生效集来源:
5
+ * 内置 → preset → config.yml 禁用 → custom 追加 → scenes 过滤。
6
+ * init 注入、`harness check`、外部消费者(studio 等)全部消费它,
7
+ * 不再直接读 IRON_LAWS/GUIDELINES/PROMPTS 全集。
8
+ */
9
+
10
+ import type { Constraint } from '../types/constraint';
11
+ import { PROMPTS } from './constraints/definitions';
12
+ import { ProjectConfigLoader } from './project-config-loader';
13
+
14
+ /**
15
+ * 获取项目当前生效的约束集(check + prompt,带 kind)
16
+ *
17
+ * 内部完成完整合并:内置 → preset 裁剪 → config.yml `constraints.<id>.enabled:false`
18
+ * 删除 → custom-constraints 追加/extend_exceptions → scenes 过滤
19
+ * (带 appliesTo 的 prompt 仅当 config.yml `scenes` 与其交集非空时保留,
20
+ * 缺省 scenes=[] 即场景专属 prompt 默认不进入生效集)。
21
+ *
22
+ * @param projectRoot 项目根路径(缺省 process.cwd())
23
+ */
24
+ export function getEffectiveConstraints(projectRoot: string = process.cwd()): Constraint[] {
25
+ const loader = new ProjectConfigLoader(projectRoot);
26
+ loader.load();
27
+ const merged = loader.mergeConstraints();
28
+ return [
29
+ ...Object.values(merged.ironLaws),
30
+ ...Object.values(merged.guidelines),
31
+ ...Object.values(merged.tips),
32
+ ...Object.values(merged.prompts ?? {}),
33
+ ];
34
+ }
35
+
36
+ /**
37
+ * 生效集配置诊断结果
38
+ */
39
+ export interface EffectiveConfigLint {
40
+ /**
41
+ * config.yml `constraints.<id>` 中既非内置也非自定义的未知 id
42
+ * (如禁用了已被本版移除的约束的残留配置)。生效集计算静默忽略,
43
+ * 在此列出供 report 提示。
44
+ */
45
+ unknownIds: string[];
46
+
47
+ /** 项目配置的场景标签(config.yml `scenes`,缺省 []) */
48
+ scenes: string[];
49
+
50
+ /**
51
+ * 因 scenes 过滤而未进入生效集的场景专属 prompt id
52
+ * (已被 preset/config 禁用的不重复列出)
53
+ */
54
+ sceneExcluded: string[];
55
+ }
56
+
57
+ /**
58
+ * 诊断项目约束配置:未知 id 残留、scenes 生效情况
59
+ *
60
+ * 不抛错、不修改任何文件,供 report / check 的诊断输出使用。
61
+ *
62
+ * @param projectRoot 项目根路径(缺省 process.cwd())
63
+ */
64
+ export function lintEffectiveConfig(projectRoot: string = process.cwd()): EffectiveConfigLint {
65
+ const loader = new ProjectConfigLoader(projectRoot);
66
+ const config = loader.load();
67
+ const merged = loader.mergeConstraints();
68
+ const scenes = config.scenes ?? [];
69
+
70
+ const sceneExcluded = Object.values(PROMPTS)
71
+ .filter(
72
+ c =>
73
+ c.appliesTo &&
74
+ c.appliesTo.length > 0 &&
75
+ !c.appliesTo.some(scene => scenes.includes(scene)) &&
76
+ !merged.disabled.includes(c.id)
77
+ )
78
+ .map(c => c.id);
79
+
80
+ return {
81
+ unknownIds: merged.unknownIds ?? [],
82
+ scenes,
83
+ sceneExcluded,
84
+ };
85
+ }
package/src/core/index.ts CHANGED
@@ -20,4 +20,7 @@ export type {
20
20
  } from '../types/spec';
21
21
 
22
22
  // 项目配置加载器
23
- export * from './project-config-loader';
23
+ export * from './project-config-loader';
24
+
25
+ // 生效约束集(ADR-0001:唯一生效集来源)
26
+ export * from './effective-constraints';
@@ -13,8 +13,10 @@ import type {
13
13
  ProjectConfig,
14
14
  CustomConstraintDefinition,
15
15
  MergedConstraintsConfig,
16
+ CapabilitiesConfig,
16
17
  } from '../types/project-config';
17
- import { IRON_LAWS, GUIDELINES, TIPS } from './constraints/definitions';
18
+ import { IRON_LAWS, GUIDELINES, PROMPTS } from './constraints/definitions';
19
+ import { applyPreset } from '../presets';
18
20
 
19
21
  /**
20
22
  * 默认配置
@@ -69,6 +71,29 @@ export function loadRawProjectConfig(projectPath: string): Record<string, unknow
69
71
  return raw;
70
72
  }
71
73
 
74
+ /**
75
+ * CAPABILITIES.md 登记模式(governance.capabilities.mode)
76
+ */
77
+ export type CapabilitiesMode = NonNullable<CapabilitiesConfig['mode']>;
78
+
79
+ /**
80
+ * 读取 governance.capabilities.mode(缺省 'file',向后兼容)
81
+ *
82
+ * 配置缺失/解析失败/取值非法时一律回落 'file'。
83
+ */
84
+ export function getCapabilitiesMode(projectPath: string): CapabilitiesMode {
85
+ try {
86
+ const raw = loadRawProjectConfig(projectPath);
87
+ const governance = raw?.governance as Record<string, unknown> | undefined;
88
+ const capabilities = governance?.capabilities as Record<string, unknown> | undefined;
89
+ const mode = capabilities?.mode;
90
+ if (mode === 'file' || mode === 'module' || mode === 'listing') return mode;
91
+ } catch {
92
+ // 配置缺失或解析失败,按默认 file 处理
93
+ }
94
+ return 'file';
95
+ }
96
+
72
97
  /**
73
98
  * 项目配置加载器
74
99
  */
@@ -128,26 +153,50 @@ export class ProjectConfigLoader {
128
153
  }
129
154
 
130
155
  /**
131
- * 合并内置约束和自定义约束
156
+ * 合并内置约束和自定义约束(ADR-0001 生效集完整链路)
157
+ *
158
+ * 合并顺序:内置 → preset 裁剪 → config.yml `constraints.<id>.enabled:false`
159
+ * 删除 → custom-constraints 追加/extend_exceptions → scenes 过滤
160
+ * (带 appliesTo 的 prompt 仅当 scenes 交集非空时保留)。
161
+ *
162
+ * config.yml 中未知约束 id(如已移除约束的禁用残留)静默忽略,
163
+ * 记录在结果 unknownIds 中供诊断。
164
+ *
165
+ * @param options.preset 覆盖 config.yml 的 preset(CLI --preset 用)
132
166
  */
133
- mergeConstraints(): MergedConstraintsConfig {
167
+ mergeConstraints(options?: { preset?: string }): MergedConstraintsConfig {
168
+ // 0. preset 裁剪(未知预设名由 applyPreset 回落 standard)
169
+ const presetMerged = applyPreset(options?.preset ?? this.config.preset ?? 'standard');
170
+ const unknownIds: string[] = [];
134
171
  const result: MergedConstraintsConfig = {
135
- ironLaws: { ...IRON_LAWS },
136
- guidelines: { ...GUIDELINES },
137
- tips: { ...TIPS },
138
- disabled: [],
172
+ ironLaws: presetMerged.ironLaws,
173
+ guidelines: presetMerged.guidelines,
174
+ tips: {},
175
+ prompts: presetMerged.prompts ?? {},
176
+ disabled: [...presetMerged.disabled],
139
177
  custom: [],
178
+ unknownIds,
140
179
  };
141
180
 
142
181
  // 1. 处理启用/禁用配置
143
182
  if (this.config.constraints) {
144
183
  for (const [constraintId, config] of Object.entries(this.config.constraints)) {
184
+ const isKnown =
185
+ !!IRON_LAWS[constraintId] ||
186
+ !!GUIDELINES[constraintId] ||
187
+ !!PROMPTS[constraintId] ||
188
+ !!this.customConstraints[constraintId];
189
+ if (!isKnown) {
190
+ // 未知 id(如已移除约束的禁用残留):不报错,记录供诊断
191
+ unknownIds.push(constraintId);
192
+ }
145
193
  if (config.enabled === false) {
146
194
  result.disabled.push(constraintId);
147
195
  // 从对应层级中移除
148
196
  delete result.ironLaws[constraintId];
149
197
  delete result.guidelines[constraintId];
150
198
  delete result.tips[constraintId];
199
+ delete result.prompts![constraintId];
151
200
  }
152
201
  }
153
202
  }
@@ -171,6 +220,7 @@ export class ProjectConfigLoader {
171
220
  if (result.ironLaws[id]) result.ironLaws[id] = constraint;
172
221
  if (result.guidelines[id]) result.guidelines[id] = constraint;
173
222
  if (result.tips[id]) result.tips[id] = constraint;
223
+ if (result.prompts![id]) result.prompts![id] = constraint;
174
224
  continue;
175
225
  }
176
226
  }
@@ -196,12 +246,29 @@ export class ProjectConfigLoader {
196
246
  case 'guideline':
197
247
  result.guidelines[id] = constraint;
198
248
  break;
249
+ case 'prompt':
250
+ result.prompts![id] = constraint;
251
+ break;
199
252
  case 'tip':
200
253
  result.tips[id] = constraint;
201
254
  break;
202
255
  }
203
256
  }
204
257
 
258
+ // 3. scenes 过滤(ADR-0001):带 appliesTo 标签的 prompt 仅当项目 scenes
259
+ // 与其交集非空时保留;无 appliesTo 的条目不受影响。缺省 scenes=[] 即
260
+ // 场景专属 prompt 默认不进入生效集。
261
+ const scenes = this.config.scenes ?? [];
262
+ for (const [id, constraint] of Object.entries(result.prompts!)) {
263
+ if (
264
+ constraint.appliesTo &&
265
+ constraint.appliesTo.length > 0 &&
266
+ !constraint.appliesTo.some(scene => scenes.includes(scene))
267
+ ) {
268
+ delete result.prompts![id];
269
+ }
270
+ }
271
+
205
272
  return result;
206
273
  }
207
274
 
@@ -212,16 +279,22 @@ export class ProjectConfigLoader {
212
279
  id: string,
213
280
  merged: MergedConstraintsConfig
214
281
  ): Constraint | undefined {
215
- return merged.ironLaws[id] || merged.guidelines[id] || merged.tips[id];
282
+ return merged.ironLaws[id] || merged.guidelines[id] || merged.tips[id] || merged.prompts?.[id];
216
283
  }
217
284
 
218
285
  /**
219
286
  * 将自定义约束定义转换为 Constraint
287
+ *
288
+ * kind 推导(ADR-0001):自定义约束没有注册表中的 checker,统一归为
289
+ * kind='prompt'(不执行 checker,check() 短路通过),level 仅决定其所在
290
+ * 桶与严重性行为,保持与历史"未注册默认通过"相同的执行语义。
220
291
  */
221
292
  private toConstraint(def: CustomConstraintDefinition, defaultId: string): Constraint {
293
+ const level = def.level || 'guideline';
222
294
  return {
223
295
  id: def.id || defaultId,
224
- level: def.level || 'guideline',
296
+ kind: 'prompt',
297
+ level,
225
298
  rule: def.rule || '',
226
299
  message: def.message || '',
227
300
  trigger: (def.trigger || 'manual') as ConstraintTrigger | ConstraintTrigger[],
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { DashboardDataProvider } from '../data';
6
6
  import type { KnowledgeEntry } from '../../knowledge/types';
7
- import type { ConstraintStats } from '../../constraints/types';
7
+ import type { ConstraintStats } from '../types';
8
8
 
9
9
  function makeEntry(overrides: Partial<KnowledgeEntry> = {}): KnowledgeEntry {
10
10
  return {
@@ -50,7 +50,7 @@ describe('DashboardDataProvider', () => {
50
50
 
51
51
  it('应该接受约束统计', () => {
52
52
  const stats: ConstraintStats[] = [{
53
- constraintId: 'no_any_type',
53
+ constraintId: 'no_bypass_checkpoint',
54
54
  triggerCount: 100,
55
55
  passCount: 78,
56
56
  interceptCount: 22,
@@ -60,7 +60,7 @@ describe('DashboardDataProvider', () => {
60
60
 
61
61
  const data = provider.generate([], stats);
62
62
  const heatmap = data.constraintHeatmap;
63
- const entry = heatmap.constraints.find(c => c.id === 'no_any_type');
63
+ const entry = heatmap.constraints.find(c => c.id === 'no_bypass_checkpoint');
64
64
  expect(entry?.trigger).toBe(100);
65
65
  expect(entry?.intercept).toBe(22);
66
66
  });
@@ -87,7 +87,7 @@ describe('DashboardDataProvider', () => {
87
87
 
88
88
  it('应该检测拦截率下降的约束', () => {
89
89
  const stats: ConstraintStats[] = [{
90
- constraintId: 'no_any_type',
90
+ constraintId: 'no_bypass_checkpoint',
91
91
  triggerCount: 100,
92
92
  passCount: 90,
93
93
  interceptCount: 10,
@@ -95,7 +95,7 @@ describe('DashboardDataProvider', () => {
95
95
  }];
96
96
 
97
97
  const heatmap = provider.getConstraintHeatmap(stats);
98
- expect(heatmap.decliningInterceptRate.some(c => c.id === 'no_any_type')).toBe(true);
98
+ expect(heatmap.decliningInterceptRate.some(c => c.id === 'no_bypass_checkpoint')).toBe(true);
99
99
  });
100
100
  });
101
101
 
@@ -108,11 +108,4 @@ describe('DashboardDataProvider', () => {
108
108
  expect(loop.feedbackToKnowledge).toBeDefined();
109
109
  });
110
110
  });
111
-
112
- describe('getRegistry', () => {
113
- it('应该返回约束注册表', () => {
114
- expect(provider.getRegistry()).toBeDefined();
115
- expect(provider.getRegistry().getAll().length).toBeGreaterThan(0);
116
- });
117
- });
118
111
  });
@@ -11,19 +11,14 @@ import type {
11
11
  ConstraintHeatmap,
12
12
  KnowledgeFlow,
13
13
  FeedbackLoopStatus,
14
+ ConstraintStats,
15
+ ConstraintLayer,
14
16
  } from './types';
15
17
  import type { KnowledgeEntry } from '../knowledge/types';
16
- import type { ConstraintStats } from '../constraints/types';
17
18
  import { computeKnowledgeOverview, computeKnowledgeFlow, computeInterceptRate } from './stats';
18
- import { ConstraintRegistry } from '../constraints/registry';
19
+ import { getAllConstraints } from '../core/constraints/definitions';
19
20
 
20
21
  export class DashboardDataProvider {
21
- private registry: ConstraintRegistry;
22
-
23
- constructor(registry?: ConstraintRegistry) {
24
- this.registry = registry ?? new ConstraintRegistry();
25
- }
26
-
27
22
  /**
28
23
  * 生成完整 Dashboard 数据
29
24
  */
@@ -52,19 +47,21 @@ export class DashboardDataProvider {
52
47
  * 约束执行热力图
53
48
  */
54
49
  getConstraintHeatmap(stats: ConstraintStats[]): ConstraintHeatmap {
55
- const allConstraints = this.registry.getAll();
50
+ // P1:直接读 definitions;prompt 类不产生 trace 统计,热力图只含 check 层
51
+ const allConstraints = getAllConstraints().filter(c => c.kind === 'check');
56
52
 
57
53
  const constraints = allConstraints.map(c => {
58
54
  const stat = stats.find(s => s.constraintId === c.id);
55
+ const layer: ConstraintLayer = c.level === 'iron_law' ? 'safety' : 'quality';
59
56
  return {
60
57
  id: c.id,
61
- layer: c.layer,
58
+ layer,
62
59
  trigger: stat?.triggerCount ?? 0,
63
60
  pass: stat?.passCount ?? 0,
64
61
  intercept: stat?.interceptCount ?? 0,
65
62
  interceptRate: stat ? computeInterceptRate(stat.triggerCount, stat.interceptCount) : 0,
66
- deprecationStatus: c.deprecationStatus,
67
- permanent: c.permanent,
63
+ deprecationStatus: 'active' as const,
64
+ permanent: false,
68
65
  };
69
66
  });
70
67
 
@@ -103,11 +100,4 @@ export class DashboardDataProvider {
103
100
  feedbackToKnowledge: { total: 0, pending: 0 },
104
101
  };
105
102
  }
106
-
107
- /**
108
- * 获取约束注册表
109
- */
110
- getRegistry(): ConstraintRegistry {
111
- return this.registry;
112
- }
113
103
  }