@dommaker/harness 1.9.0 → 1.10.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 (253) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +9 -12
  3. package/dist/cli/commands/check.d.ts +3 -3
  4. package/dist/cli/commands/check.d.ts.map +1 -1
  5. package/dist/cli/commands/check.js +41 -78
  6. package/dist/cli/commands/check.js.map +1 -1
  7. package/dist/cli/commands/constraints-report.d.ts +2 -10
  8. package/dist/cli/commands/constraints-report.d.ts.map +1 -1
  9. package/dist/cli/commands/constraints-report.js +4 -57
  10. package/dist/cli/commands/constraints-report.js.map +1 -1
  11. package/dist/cli/commands/constraints-retire.d.ts +9 -23
  12. package/dist/cli/commands/constraints-retire.d.ts.map +1 -1
  13. package/dist/cli/commands/constraints-retire.js +39 -121
  14. package/dist/cli/commands/constraints-retire.js.map +1 -1
  15. package/dist/cli/commands/constraints.d.ts +3 -8
  16. package/dist/cli/commands/constraints.d.ts.map +1 -1
  17. package/dist/cli/commands/constraints.js +8 -23
  18. package/dist/cli/commands/constraints.js.map +1 -1
  19. package/dist/cli/commands/definitions.js +2 -2
  20. package/dist/cli/commands/init.d.ts +0 -32
  21. package/dist/cli/commands/init.d.ts.map +1 -1
  22. package/dist/cli/commands/init.js +7 -149
  23. package/dist/cli/commands/init.js.map +1 -1
  24. package/dist/cli/commands/report.d.ts.map +1 -1
  25. package/dist/cli/commands/report.js +14 -17
  26. package/dist/cli/commands/report.js.map +1 -1
  27. package/dist/cli/commands/scaffold-templates.d.ts +0 -2
  28. package/dist/cli/commands/scaffold-templates.d.ts.map +1 -1
  29. package/dist/cli/commands/scaffold-templates.js +2 -37
  30. package/dist/cli/commands/scaffold-templates.js.map +1 -1
  31. package/dist/cli/commands/scaffold.d.ts +0 -2
  32. package/dist/cli/commands/scaffold.d.ts.map +1 -1
  33. package/dist/cli/commands/scaffold.js +0 -10
  34. package/dist/cli/commands/scaffold.js.map +1 -1
  35. package/dist/cli/commands/status.js +10 -10
  36. package/dist/cli/commands/status.js.map +1 -1
  37. package/dist/cli/commands/sync-docs/agents-syncer.d.ts +0 -2
  38. package/dist/cli/commands/sync-docs/agents-syncer.d.ts.map +1 -1
  39. package/dist/cli/commands/sync-docs/agents-syncer.js +4 -23
  40. package/dist/cli/commands/sync-docs/agents-syncer.js.map +1 -1
  41. package/dist/core/constraints/capabilities-parser.d.ts.map +1 -1
  42. package/dist/core/constraints/capabilities-parser.js +16 -4
  43. package/dist/core/constraints/capabilities-parser.js.map +1 -1
  44. package/dist/core/constraints/checker.d.ts +15 -24
  45. package/dist/core/constraints/checker.d.ts.map +1 -1
  46. package/dist/core/constraints/checker.js +33 -72
  47. package/dist/core/constraints/checker.js.map +1 -1
  48. package/dist/core/constraints/checkers/docs-freshness.js +1 -1
  49. package/dist/core/constraints/checkers/docs-freshness.js.map +1 -1
  50. package/dist/core/constraints/checkers/governance-presence.d.ts +2 -1
  51. package/dist/core/constraints/checkers/governance-presence.d.ts.map +1 -1
  52. package/dist/core/constraints/checkers/governance-presence.js +4 -3
  53. package/dist/core/constraints/checkers/governance-presence.js.map +1 -1
  54. package/dist/core/constraints/checkers/index.d.ts +1 -1
  55. package/dist/core/constraints/checkers/index.d.ts.map +1 -1
  56. package/dist/core/constraints/checkers/index.js +4 -8
  57. package/dist/core/constraints/checkers/index.js.map +1 -1
  58. package/dist/core/constraints/checkers/iron-flags.d.ts +3 -4
  59. package/dist/core/constraints/checkers/iron-flags.d.ts.map +1 -1
  60. package/dist/core/constraints/checkers/iron-flags.js +4 -5
  61. package/dist/core/constraints/checkers/iron-flags.js.map +1 -1
  62. package/dist/core/constraints/checkers/no-test-simplification.js +1 -1
  63. package/dist/core/constraints/checkers/no-test-simplification.js.map +1 -1
  64. package/dist/core/constraints/checkers/types.d.ts +1 -1
  65. package/dist/core/constraints/checkers/types.js +1 -1
  66. package/dist/core/constraints/definitions/guidelines.d.ts +4 -4
  67. package/dist/core/constraints/definitions/guidelines.d.ts.map +1 -1
  68. package/dist/core/constraints/definitions/guidelines.js +9 -25
  69. package/dist/core/constraints/definitions/guidelines.js.map +1 -1
  70. package/dist/core/constraints/definitions/iron-laws.d.ts +4 -4
  71. package/dist/core/constraints/definitions/iron-laws.d.ts.map +1 -1
  72. package/dist/core/constraints/definitions/iron-laws.js +10 -81
  73. package/dist/core/constraints/definitions/iron-laws.js.map +1 -1
  74. package/dist/core/constraints/definitions.d.ts +7 -9
  75. package/dist/core/constraints/definitions.d.ts.map +1 -1
  76. package/dist/core/constraints/definitions.js +13 -16
  77. package/dist/core/constraints/definitions.js.map +1 -1
  78. package/dist/core/constraints/index.d.ts +2 -5
  79. package/dist/core/constraints/index.d.ts.map +1 -1
  80. package/dist/core/constraints/index.js +3 -13
  81. package/dist/core/constraints/index.js.map +1 -1
  82. package/dist/core/constraints/injection-writer.d.ts +10 -38
  83. package/dist/core/constraints/injection-writer.d.ts.map +1 -1
  84. package/dist/core/constraints/injection-writer.js +17 -54
  85. package/dist/core/constraints/injection-writer.js.map +1 -1
  86. package/dist/core/constraints/run-env.d.ts +1 -10
  87. package/dist/core/constraints/run-env.d.ts.map +1 -1
  88. package/dist/core/constraints/run-env.js +1 -22
  89. package/dist/core/constraints/run-env.js.map +1 -1
  90. package/dist/core/constraints/usage-report.d.ts +5 -7
  91. package/dist/core/constraints/usage-report.d.ts.map +1 -1
  92. package/dist/core/constraints/usage-report.js +5 -10
  93. package/dist/core/constraints/usage-report.js.map +1 -1
  94. package/dist/core/effective-constraints.d.ts +12 -22
  95. package/dist/core/effective-constraints.d.ts.map +1 -1
  96. package/dist/core/effective-constraints.js +13 -30
  97. package/dist/core/effective-constraints.js.map +1 -1
  98. package/dist/core/index.d.ts +2 -2
  99. package/dist/core/index.d.ts.map +1 -1
  100. package/dist/core/index.js +3 -9
  101. package/dist/core/index.js.map +1 -1
  102. package/dist/core/project-config-loader.d.ts +4 -42
  103. package/dist/core/project-config-loader.d.ts.map +1 -1
  104. package/dist/core/project-config-loader.js +16 -125
  105. package/dist/core/project-config-loader.js.map +1 -1
  106. package/dist/core/validators/passes-gate.d.ts +2 -2
  107. package/dist/core/validators/passes-gate.js +6 -6
  108. package/dist/core/validators/passes-gate.js.map +1 -1
  109. package/dist/index.d.ts +7 -10
  110. package/dist/index.d.ts.map +1 -1
  111. package/dist/index.js +9 -18
  112. package/dist/index.js.map +1 -1
  113. package/dist/monitoring/trace-analyzer.d.ts.map +1 -1
  114. package/dist/monitoring/trace-analyzer.js +11 -12
  115. package/dist/monitoring/trace-analyzer.js.map +1 -1
  116. package/dist/monitoring/traces.d.ts +4 -4
  117. package/dist/monitoring/traces.d.ts.map +1 -1
  118. package/dist/monitoring/traces.js +8 -8
  119. package/dist/monitoring/traces.js.map +1 -1
  120. package/dist/presets/standard.d.ts +8 -10
  121. package/dist/presets/standard.d.ts.map +1 -1
  122. package/dist/presets/standard.js +10 -16
  123. package/dist/presets/standard.js.map +1 -1
  124. package/dist/types/constraint.d.ts +24 -35
  125. package/dist/types/constraint.d.ts.map +1 -1
  126. package/dist/types/constraint.js +8 -7
  127. package/dist/types/constraint.js.map +1 -1
  128. package/dist/types/passes-gate.d.ts +5 -5
  129. package/dist/types/passes-gate.d.ts.map +1 -1
  130. package/dist/types/project-config.d.ts +8 -66
  131. package/dist/types/project-config.d.ts.map +1 -1
  132. package/dist/types/project-config.js +3 -2
  133. package/dist/types/project-config.js.map +1 -1
  134. package/dist/types/trace.d.ts +8 -10
  135. package/dist/types/trace.d.ts.map +1 -1
  136. package/package.json +2 -2
  137. package/src/CONTEXT.md +2 -2
  138. package/src/__tests__/checker-extra.test.ts +37 -61
  139. package/src/__tests__/checker.test.ts +10 -115
  140. package/src/__tests__/effective-constraints.test.ts +18 -83
  141. package/src/__tests__/iron-laws.test.ts +71 -90
  142. package/src/__tests__/passes-gate-check.test.ts +2 -2
  143. package/src/__tests__/project-config-loader-extra.test.ts +22 -123
  144. package/src/__tests__/project-config-loader.test.ts +5 -33
  145. package/src/__tests__/public-exports.test.ts +1 -7
  146. package/src/__tests__/public-type-surface.test.ts +2 -5
  147. package/src/__tests__/public-value-surface.test.ts +1 -7
  148. package/src/__tests__/skip-semantics.test.ts +21 -37
  149. package/src/__tests__/trace-analyzer-extra.test.ts +14 -14
  150. package/src/__tests__/trace-analyzer.test.ts +21 -21
  151. package/src/__tests__/trace-collector.test.ts +22 -22
  152. package/src/__tests__/traces.test.ts +27 -28
  153. package/src/cli/commands/CONTEXT.md +9 -9
  154. package/src/cli/commands/__tests__/check-read-count.test.ts +4 -15
  155. package/src/cli/commands/__tests__/check-skip-output.test.ts +14 -14
  156. package/src/cli/commands/__tests__/check.test.ts +14 -31
  157. package/src/cli/commands/__tests__/constraints-report.test.ts +12 -80
  158. package/src/cli/commands/__tests__/constraints-retire.test.ts +42 -231
  159. package/src/cli/commands/__tests__/init-governance-io.test.ts +12 -58
  160. package/src/cli/commands/__tests__/init-ondisk.test.ts +12 -20
  161. package/src/cli/commands/__tests__/init.test.ts +0 -11
  162. package/src/cli/commands/__tests__/project-path-anchoring.test.ts +2 -2
  163. package/src/cli/commands/__tests__/report-extra.test.ts +4 -4
  164. package/src/cli/commands/__tests__/report.test.ts +1 -1
  165. package/src/cli/commands/__tests__/scaffold.test.ts +4 -14
  166. package/src/cli/commands/__tests__/status-analysis-wiring.test.ts +3 -3
  167. package/src/cli/commands/__tests__/status-extra.test.ts +14 -14
  168. package/src/cli/commands/__tests__/status.test.ts +12 -12
  169. package/src/cli/commands/__tests__/sync-docs-agents.test.ts +1 -1
  170. package/src/cli/commands/check.ts +43 -82
  171. package/src/cli/commands/constraints-report.ts +4 -59
  172. package/src/cli/commands/constraints-retire.ts +49 -154
  173. package/src/cli/commands/constraints.ts +11 -26
  174. package/src/cli/commands/definitions.ts +2 -2
  175. package/src/cli/commands/init.ts +8 -179
  176. package/src/cli/commands/report.ts +19 -23
  177. package/src/cli/commands/scaffold-templates.ts +1 -37
  178. package/src/cli/commands/scaffold.ts +0 -11
  179. package/src/cli/commands/status.ts +10 -10
  180. package/src/cli/commands/sync-docs/agents-syncer.ts +4 -25
  181. package/src/core/CONTEXT.md +9 -9
  182. package/src/core/constraints/__tests__/capability-counts.test.ts +5 -5
  183. package/src/core/constraints/__tests__/collect-constraints.test.ts +13 -8
  184. package/src/core/constraints/__tests__/git-evidence.test.ts +4 -7
  185. package/src/core/constraints/__tests__/injection-writer.test.ts +8 -61
  186. package/src/core/constraints/__tests__/run-env.test.ts +5 -34
  187. package/src/core/constraints/__tests__/trace-injection.test.ts +1 -1
  188. package/src/core/constraints/capabilities-parser.ts +17 -5
  189. package/src/core/constraints/checker.ts +39 -88
  190. package/src/core/constraints/checkers/__tests__/check-outcome.test.ts +5 -8
  191. package/src/core/constraints/checkers/__tests__/governance-presence.test.ts +1 -53
  192. package/src/core/constraints/checkers/__tests__/iron-flags.test.ts +5 -25
  193. package/src/core/constraints/checkers/docs-freshness.ts +1 -1
  194. package/src/core/constraints/checkers/governance-presence.ts +4 -3
  195. package/src/core/constraints/checkers/index.ts +4 -10
  196. package/src/core/constraints/checkers/iron-flags.ts +3 -12
  197. package/src/core/constraints/checkers/no-test-simplification.ts +1 -1
  198. package/src/core/constraints/checkers/types.ts +1 -1
  199. package/src/core/constraints/definitions/guidelines.ts +8 -25
  200. package/src/core/constraints/definitions/iron-laws.ts +9 -82
  201. package/src/core/constraints/definitions.ts +14 -15
  202. package/src/core/constraints/index.ts +4 -19
  203. package/src/core/constraints/injection-writer.ts +16 -61
  204. package/src/core/constraints/run-env.ts +1 -33
  205. package/src/core/constraints/usage-report.ts +8 -15
  206. package/src/core/effective-constraints.ts +14 -45
  207. package/src/core/index.ts +3 -10
  208. package/src/core/project-config-loader.ts +20 -145
  209. package/src/core/validators/passes-gate.ts +6 -6
  210. package/src/failure/CONTEXT.md +1 -1
  211. package/src/hooks/__tests__/bootstrap.test.ts +3 -5
  212. package/src/index.ts +8 -18
  213. package/src/monitoring/__tests__/trace-file-anchoring.test.ts +1 -1
  214. package/src/monitoring/__tests__/traces.test.ts +22 -22
  215. package/src/monitoring/trace-analyzer.ts +12 -13
  216. package/src/monitoring/traces.ts +8 -8
  217. package/src/presets/__tests__/standard.test.ts +12 -16
  218. package/src/presets/standard.ts +14 -23
  219. package/src/types/__tests__/types.test.ts +3 -3
  220. package/src/types/constraint.ts +26 -40
  221. package/src/types/passes-gate.ts +5 -5
  222. package/src/types/project-config.ts +8 -77
  223. package/src/types/trace.ts +8 -11
  224. package/dist/core/constraints/agent-prompt-renderer.d.ts +0 -32
  225. package/dist/core/constraints/agent-prompt-renderer.d.ts.map +0 -1
  226. package/dist/core/constraints/agent-prompt-renderer.js +0 -55
  227. package/dist/core/constraints/agent-prompt-renderer.js.map +0 -1
  228. package/dist/core/constraints/checkers/no-bypass-checkpoint.d.ts +0 -6
  229. package/dist/core/constraints/checkers/no-bypass-checkpoint.d.ts.map +0 -1
  230. package/dist/core/constraints/checkers/no-bypass-checkpoint.js +0 -40
  231. package/dist/core/constraints/checkers/no-bypass-checkpoint.js.map +0 -1
  232. package/dist/core/constraints/definitions/prompts.d.ts +0 -12
  233. package/dist/core/constraints/definitions/prompts.d.ts.map +0 -1
  234. package/dist/core/constraints/definitions/prompts.js +0 -400
  235. package/dist/core/constraints/definitions/prompts.js.map +0 -1
  236. package/dist/core/constraints/injection-drift.d.ts +0 -61
  237. package/dist/core/constraints/injection-drift.d.ts.map +0 -1
  238. package/dist/core/constraints/injection-drift.js +0 -131
  239. package/dist/core/constraints/injection-drift.js.map +0 -1
  240. package/dist/core/constraints/injection-renderer.d.ts +0 -23
  241. package/dist/core/constraints/injection-renderer.d.ts.map +0 -1
  242. package/dist/core/constraints/injection-renderer.js +0 -44
  243. package/dist/core/constraints/injection-renderer.js.map +0 -1
  244. package/src/cli/commands/__tests__/check-drift.test.ts +0 -158
  245. package/src/cli/commands/__tests__/init-injection.test.ts +0 -466
  246. package/src/core/constraints/__tests__/agent-prompt-renderer.test.ts +0 -129
  247. package/src/core/constraints/__tests__/injection-drift.test.ts +0 -247
  248. package/src/core/constraints/agent-prompt-renderer.ts +0 -67
  249. package/src/core/constraints/checkers/__tests__/no-bypass-checkpoint.test.ts +0 -76
  250. package/src/core/constraints/checkers/no-bypass-checkpoint.ts +0 -40
  251. package/src/core/constraints/definitions/prompts.ts +0 -414
  252. package/src/core/constraints/injection-drift.ts +0 -142
  253. package/src/core/constraints/injection-renderer.ts +0 -44
@@ -6,15 +6,14 @@
6
6
  * ADR-0023 决策 2),一次运行内各至多读一次。
7
7
  */
8
8
 
9
- import type { Constraint, ConstraintTrigger } from '../types/constraint';
9
+ import type { Constraint } from '../types/constraint';
10
10
  import type {
11
11
  ProjectConfig,
12
- CustomConstraintDefinition,
13
12
  MergedConstraintsConfig,
14
13
  CapabilitiesConfig,
15
14
  GovernanceConfig,
16
15
  } from '../types/project-config';
17
- import { IRON_LAWS, GUIDELINES, PROMPTS } from './constraints/definitions';
16
+ import { CONSTRAINTS } from './constraints/definitions';
18
17
  import { PRESETS_BY_NAME, STANDARD_PRESET } from '../presets';
19
18
  import { filterEnabledEntries } from './effective-set';
20
19
  import { resolveRunEnv, type RunEnv, type RunTarget } from './constraints/run-env';
@@ -24,7 +23,6 @@ import { resolveRunEnv, type RunEnv, type RunTarget } from './constraints/run-en
24
23
  */
25
24
  const DEFAULT_CONFIG: ProjectConfig = {
26
25
  preset: 'standard',
27
- custom_constraints_file: 'custom-constraints.yml',
28
26
  };
29
27
 
30
28
  /**
@@ -103,25 +101,6 @@ export function getCapabilitiesMode(target: RunTarget): CapabilitiesMode {
103
101
  return 'file';
104
102
  }
105
103
 
106
- /**
107
- * 退役判定单点(studio#82 D6 一处真相)
108
- *
109
- * 两个落点合成一条规则:禁用(config.yml `constraints.<id>.enabled: false`,内置约束的
110
- * 退役落点)或 custom 条目自带 `retired` 元数据(custom 约束的退役落点,不拆 config.yml
111
- * 第二处)。`mergeConstraints` 的 custom 追加跳过与 `harness constraints retire` 的
112
- * already_retired 检查共用本函数——后者此前是这条规则的手写复印(harness#137 收口)。
113
- *
114
- * `disabled` 由调用方给:mergeConstraints 传的是含 preset 裁剪的完整禁用集,
115
- * retire 传的是 config.yml 单点(退役落点只有这一处,preset 语义不掺进退役判定)。
116
- * `retired` 按 truthiness 判,与 mergeConstraints 历史口径逐字一致。
117
- */
118
- export function isConstraintRetired(
119
- customDef: { retired?: unknown } | undefined,
120
- disabled: boolean
121
- ): boolean {
122
- return disabled || Boolean(customDef?.retired);
123
- }
124
-
125
104
  /**
126
105
  * 项目配置加载器
127
106
  */
@@ -129,7 +108,6 @@ export class ProjectConfigLoader {
129
108
  private env: RunEnv;
130
109
  private projectPath: string;
131
110
  private config: ProjectConfig;
132
- private customConstraints: Record<string, CustomConstraintDefinition>;
133
111
 
134
112
  /**
135
113
  * @param target 项目根路径,或本 run 已构造的运行级观察面(ADR-0023 决策 2)
@@ -139,51 +117,23 @@ export class ProjectConfigLoader {
139
117
  this.env = resolveRunEnv(target);
140
118
  this.projectPath = this.env.projectPath;
141
119
  this.config = { ...DEFAULT_CONFIG };
142
- this.customConstraints = {};
143
120
  }
144
121
 
145
122
  /**
146
- * 加载项目配置
123
+ * 加载项目配置(run 内 memo 在观察面上,同一份解析结果供全部消费方共用)
147
124
  */
148
125
  load(): ProjectConfig {
149
- // 1. 加载主配置(run 内 memo 在观察面上,同一份解析结果供全部消费方共用)
150
126
  const raw = this.env.rawConfig();
151
127
  if (raw) {
152
128
  this.config = { ...DEFAULT_CONFIG, ...(raw as Partial<ProjectConfig>) };
153
129
  }
154
-
155
- // 2. 加载自定义约束
156
- this.loadCustomConstraints();
157
-
158
130
  return this.config;
159
131
  }
160
132
 
161
133
  /**
162
- * 加载自定义约束
163
- *
164
- * 文件读取经观察面(ADR-0023 决策 2):同一次运行内多个加载器共用同一份内容,
165
- * 「哪个文件名算数」与合并顺序仍由本函数决定(方式 1 文件 → 方式 2 主配置内联,后者覆盖)。
166
- */
167
- private loadCustomConstraints(): void {
168
- // 方式 1:从单独文件加载
169
- if (this.config.custom_constraints_file) {
170
- const defs = this.env.customConstraints(this.config.custom_constraints_file);
171
- this.customConstraints = { ...this.customConstraints, ...defs };
172
- }
173
-
174
- // 方式 2:从主配置文件中加载
175
- if (this.config.custom_constraints) {
176
- this.customConstraints = { ...this.customConstraints, ...this.config.custom_constraints };
177
- }
178
- }
179
-
180
- /**
181
- * 合并内置约束和自定义约束(ADR-0001 生效集完整链路)
134
+ * 合并内置约束(生效集完整链路,ADR-0029)
182
135
  *
183
- * 合并顺序:内置 → preset 裁剪 → config.yml `constraints.<id>.enabled:false`
184
- * 删除(对内置与 custom 同效)→ custom-constraints 追加
185
- * (禁用/已退役的 custom 不追加)→ scenes 过滤
186
- * (带 appliesTo 的 prompt 仅当 scenes 交集非空时保留)。
136
+ * 合并顺序:内置 → preset 裁剪 → config.yml `constraints.<id>.enabled:false` 删除。
187
137
  *
188
138
  * config.yml 中未知约束 id(如已移除约束的禁用残留)静默忽略,
189
139
  * 记录在结果 unknownIds 中供诊断。
@@ -199,6 +149,9 @@ export class ProjectConfigLoader {
199
149
  console.error(`[harness] 未知预设 "${presetName}",已回落 standard`);
200
150
  preset = STANDARD_PRESET;
201
151
  }
152
+ // preset 按 severity 分键;展开为「id → 是否启用」的单桶视图
153
+ const bySeverity = (severity: 'error' | 'warning'): Record<string, Constraint> =>
154
+ Object.fromEntries(Object.entries(CONSTRAINTS).filter(([, c]) => c.severity === severity));
202
155
  const pick = (
203
156
  source: Record<string, Constraint>,
204
157
  ids: string[] | null
@@ -215,104 +168,36 @@ export class ProjectConfigLoader {
215
168
  ids: string[] | null
216
169
  ): string[] => (ids === null ? [] : Object.keys(source).filter(id => !ids.includes(id)));
217
170
 
171
+ const errorConstraints = bySeverity('error');
172
+ const warningConstraints = bySeverity('warning');
173
+
218
174
  const unknownIds: string[] = [];
219
175
  const result: MergedConstraintsConfig = {
220
- ironLaws: pick(IRON_LAWS, preset.ironLaws),
221
- guidelines: pick(GUIDELINES, preset.guidelines),
222
- prompts: pick(PROMPTS, preset.prompts),
176
+ constraints: {
177
+ ...pick(errorConstraints, preset.errors),
178
+ ...pick(warningConstraints, preset.warnings),
179
+ },
223
180
  disabled: [
224
- ...presetDisabled(IRON_LAWS, preset.ironLaws),
225
- ...presetDisabled(GUIDELINES, preset.guidelines),
226
- ...presetDisabled(PROMPTS, preset.prompts),
181
+ ...presetDisabled(errorConstraints, preset.errors),
182
+ ...presetDisabled(warningConstraints, preset.warnings),
227
183
  ],
228
- custom: [],
229
184
  unknownIds,
230
185
  };
231
186
 
232
187
  // 1. 处理启用/禁用配置(未知 id 静默忽略,记录供诊断)
233
188
  if (this.config.constraints) {
234
- const knownIds = new Set([
235
- ...Object.keys(IRON_LAWS),
236
- ...Object.keys(GUIDELINES),
237
- ...Object.keys(PROMPTS),
238
- ...Object.keys(this.customConstraints),
239
- ]);
189
+ const knownIds = new Set(Object.keys(CONSTRAINTS));
240
190
  const filtered = filterEnabledEntries(knownIds, this.config.constraints);
241
191
  unknownIds.push(...filtered.unknownIds);
242
192
  for (const constraintId of filtered.disabledIds) {
243
193
  result.disabled.push(constraintId);
244
- // 从对应层级中移除
245
- delete result.ironLaws[constraintId];
246
- delete result.guidelines[constraintId];
247
- delete result.prompts![constraintId];
248
- }
249
- }
250
-
251
- // 2. 添加自定义约束(config.yml 禁用的 id 不追加:step 1 已将其
252
- // 收集进 disabled,custom 在 step 1 时尚未入桶,须在此兜底跳过;
253
- // 条目带 retired 元数据的同样不追加——studio#82 D6 退役落点在条目自身)
254
- for (const [id, customDef] of Object.entries(this.customConstraints)) {
255
- if (isConstraintRetired(customDef, result.disabled.includes(id))) {
256
- continue;
257
- }
258
- const constraint = this.toConstraint(customDef, id);
259
-
260
- result.custom.push(id);
261
-
262
- const level = customDef.level || 'guideline';
263
- switch (level) {
264
- case 'iron_law':
265
- result.ironLaws[id] = constraint;
266
- break;
267
- case 'guideline':
268
- result.guidelines[id] = constraint;
269
- break;
270
- case 'prompt':
271
- result.prompts![id] = constraint;
272
- break;
273
- }
274
- }
275
-
276
- // 3. scenes 过滤(ADR-0001):带 appliesTo 标签的 prompt 仅当项目 scenes
277
- // 与其交集非空时保留;无 appliesTo 的条目不受影响。缺省 scenes=[] 即
278
- // 场景专属 prompt 默认不进入生效集。
279
- const scenes = this.config.scenes ?? [];
280
- for (const [id, constraint] of Object.entries(result.prompts!)) {
281
- if (
282
- constraint.appliesTo &&
283
- constraint.appliesTo.length > 0 &&
284
- !constraint.appliesTo.some(scene => scenes.includes(scene))
285
- ) {
286
- delete result.prompts![id];
194
+ delete result.constraints[constraintId];
287
195
  }
288
196
  }
289
197
 
290
198
  return result;
291
199
  }
292
200
 
293
- /**
294
- * 将自定义约束定义转换为 Constraint
295
- *
296
- * kind 推导(ADR-0001):自定义约束没有注册表中的 checker,统一归为
297
- * kind='prompt'(不执行 checker,check() 短路通过),level 仅决定其所在
298
- * 桶与严重性行为,保持与历史"未注册默认通过"相同的执行语义。
299
- */
300
- private toConstraint(def: CustomConstraintDefinition, defaultId: string): Constraint {
301
- const level = def.level || 'guideline';
302
- return {
303
- id: def.id || defaultId,
304
- kind: 'prompt',
305
- level,
306
- rule: def.rule || '',
307
- message: def.message || '',
308
- trigger: (def.trigger || 'manual') as ConstraintTrigger | ConstraintTrigger[],
309
- description: def.description,
310
- promptInjection: def.promptInjection,
311
- enabled: def.enabled !== false,
312
- enforcement: 'custom',
313
- };
314
- }
315
-
316
201
  /**
317
202
  * 获取当前配置
318
203
  */
@@ -320,20 +205,10 @@ export class ProjectConfigLoader {
320
205
  return this.config;
321
206
  }
322
207
 
323
- /**
324
- * 获取自定义约束
325
- */
326
- getCustomConstraints(): Record<string, CustomConstraintDefinition> {
327
- return this.customConstraints;
328
- }
329
-
330
208
  /**
331
209
  * 检查是否有自定义配置
332
210
  */
333
211
  hasCustomConfig(): boolean {
334
- return (
335
- Object.keys(this.customConstraints).length > 0 ||
336
- (this.config.constraints !== undefined && Object.keys(this.config.constraints).length > 0)
337
- );
212
+ return this.config.constraints !== undefined && Object.keys(this.config.constraints).length > 0;
338
213
  }
339
214
  }
@@ -97,7 +97,7 @@ export class PassesGate {
97
97
  * - 业务层自己运行测试,传入结果
98
98
  *
99
99
  * @param testResult 测试结果(由业务层运行测试后传入)
100
- * @returns 验证结果(是否允许标记完成 + Iron Law 违规)
100
+ * @returns 验证结果(是否允许标记完成 + 阻断级违规)
101
101
  *
102
102
  * @example
103
103
  * ```typescript
@@ -107,7 +107,7 @@ export class PassesGate {
107
107
  *
108
108
  * if (!passesResult.allowed) {
109
109
  * return res.status(400).json({
110
- * error: 'Iron Law 违规',
110
+ * error: '约束违规',
111
111
  * violations: passesResult.violations,
112
112
  * });
113
113
  * }
@@ -116,23 +116,23 @@ export class PassesGate {
116
116
  check(testResult: TestResult): PassesGateCheckResult {
117
117
  const violations: PassesGateViolation[] = [];
118
118
 
119
- // 1. 测试未通过 → Iron Law #2: NO SELF APPROVAL WITHOUT TEST EVIDENCE
119
+ // 1. 测试未通过 → NO SELF APPROVAL WITHOUT TEST EVIDENCE
120
120
  if (!testResult.passed) {
121
121
  violations.push({
122
122
  id: 'no_self_approval',
123
123
  rule: 'NO SELF APPROVAL WITHOUT TEST EVIDENCE',
124
124
  message: '测试未通过',
125
- level: 'iron_law',
125
+ severity: 'error',
126
126
  });
127
127
  }
128
128
 
129
- // 2. 缺少证据 → Iron Law #3: NO COMPLETION CLAIMS WITHOUT FRESH VERIFICATION
129
+ // 2. 缺少证据 → NO COMPLETION CLAIMS WITHOUT FRESH VERIFICATION
130
130
  if (this.config.requireEvidence && !testResult.evidence) {
131
131
  violations.push({
132
132
  id: 'no_completion_without_verification',
133
133
  rule: 'NO COMPLETION CLAIMS WITHOUT FRESH VERIFICATION',
134
134
  message: '缺少测试证据',
135
- level: 'iron_law',
135
+ severity: 'error',
136
136
  });
137
137
  }
138
138
 
@@ -22,6 +22,6 @@
22
22
  - 分类器基于规则匹配,不调用 LLM
23
23
  - S4 约束违规处理策略模块(ConstraintViolationHandler / executeWithBlock /
24
24
  executeWithCollect / executeWithSafeBoolean)已删除(架构评审候选1):
25
- COLLECT 对真实 checker 结构上不可交付(checker 首个铁律违规即 throw,
25
+ COLLECT 对真实 checker 结构上不可交付(checker 首个 error 级违规即 throw,
26
26
  handler 的 catch 只能吞证据造假绿)。语义归宿——阻断 = `checkConstraints` 本体,
27
27
  收集 = `checker.collectConstraints`(report 直调);BLOCK/SAFE_BOOLEAN 零生产消费者随迁
@@ -22,7 +22,6 @@ function setupTempDir(dir: string): string {
22
22
  fs.mkdirSync(harnessDir, { recursive: true });
23
23
  const config = {
24
24
  preset: 'standard',
25
- custom_constraints_file: 'custom-constraints.yml',
26
25
  };
27
26
  fs.writeFileSync(path.join(harnessDir, 'config.yml'), yaml.dump(config), 'utf-8');
28
27
  return harnessDir;
@@ -85,7 +84,7 @@ describe('bootstrapHarness', () => {
85
84
  const result = await bootstrapHarness(noConfigDir);
86
85
  expect(result).toHaveProperty('checker');
87
86
  expect(result).toHaveProperty('projectPath', noConfigDir);
88
- expect(result.mergedConstraints).toHaveProperty('ironLaws');
87
+ expect(result.mergedConstraints).toHaveProperty('constraints');
89
88
  } finally {
90
89
  fs.rmSync(noConfigDir, { recursive: true, force: true });
91
90
  }
@@ -121,9 +120,8 @@ describe('bootstrapHarnessSync', () => {
121
120
  it('initializes ConstraintChecker with merged constraints', () => {
122
121
  const result = bootstrapHarnessSync(tempDir);
123
122
  // Check that mergedConstraints has the expected structure
124
- expect(result.mergedConstraints).toHaveProperty('ironLaws');
125
- expect(result.mergedConstraints).toHaveProperty('guidelines');
126
- });
123
+ expect(result.mergedConstraints).toHaveProperty('constraints');
124
+ });
127
125
 
128
126
  it('uses process.cwd() when no project path is given', () => {
129
127
  // We cannot easily test process.cwd() fallback without mocking cwd,
package/src/index.ts CHANGED
@@ -3,9 +3,9 @@
3
3
  *
4
4
  * 通用工程约束框架
5
5
  *
6
- * 约束体系(ADR-0001 kind 二元):
7
- * - check:可执行检查(Iron Laws 阻断 / Guidelines 告警)
8
- * - prompt:纯文本注入,不参与检查
6
+ * 约束体系(ADR-0029 severity 显式模型):
7
+ * - 全部约束 kind='check':可执行检查(error 阻断 / warning 告警)
8
+ * - 纯文本提示层已整体关停(ADR-0029)
9
9
  *
10
10
  * 门禁系统:
11
11
  * - PassesGate:测试门控
@@ -16,13 +16,13 @@
16
16
  * - CheckpointValidator:检查点验证
17
17
  *
18
18
  * 公共导出(ADR-0003):显式清单,禁 export *。
19
- * 收录标准:属 harness 定位(约束数据 / 执行引擎 / 注入工具 / 知识基建)、
19
+ * 收录标准:属 harness 定位(约束数据 / 执行引擎 / 知识基建)、
20
20
  * 实现真实可用、无同名冲突。内部 seam
21
21
  * (ConstraintChecker / constraintChecker / ProjectConfigLoader)不进公共清单。
22
22
  */
23
23
 
24
24
  // ========================================
25
- // 约束类型(三层体系 + kind 二元)
25
+ // 约束类型(severity 显式模型)
26
26
  // ========================================
27
27
  export {
28
28
  ConstraintViolationError,
@@ -31,7 +31,7 @@ export type {
31
31
  Constraint,
32
32
  ConstraintId,
33
33
  ConstraintKind,
34
- ConstraintLevel,
34
+ ConstraintSeverity,
35
35
  ConstraintTrigger,
36
36
  ConstraintContext,
37
37
  ConstraintResult,
@@ -43,9 +43,7 @@ export type {
43
43
  // 约束数据(内置定义 + 生效集)
44
44
  // ========================================
45
45
  export {
46
- IRON_LAWS,
47
- GUIDELINES,
48
- PROMPTS,
46
+ CONSTRAINTS,
49
47
  getAllConstraints,
50
48
  getConstraint,
51
49
  findConstraintsByTrigger,
@@ -67,17 +65,10 @@ export {
67
65
  export type { CheckConstraintsOptions } from './core/constraints/checker';
68
66
 
69
67
  // ========================================
70
- // 约束缓存与注入渲染
68
+ // 约束缓存
71
69
  // ========================================
72
70
  export { CheckCache } from './core/constraints/check-cache';
73
71
  export type { CheckCacheConfig, CheckSamplingConfig } from './core/constraints/check-cache';
74
- export { renderConstraintsByTrigger } from './core/constraints/agent-prompt-renderer';
75
- export type { RenderConstraintsByTriggerOptions } from './core/constraints/agent-prompt-renderer';
76
- export {
77
- CONSTRAINTS_START_MARKER,
78
- CONSTRAINTS_END_MARKER,
79
- renderConstraintsSection,
80
- } from './core/constraints/injection-renderer';
81
72
 
82
73
  // ========================================
83
74
  // 检查点与验证器
@@ -373,7 +364,6 @@ export type {
373
364
  export type {
374
365
  ProjectConfig,
375
366
  MergedConstraintsConfig,
376
- CustomConstraintDefinition,
377
367
  GovernanceConfig,
378
368
  CapabilitiesConfig,
379
369
  ChangelogConfig,
@@ -14,7 +14,7 @@ import { createProjectFixture } from '../../test-setup/project-fixture';
14
14
 
15
15
  const trace = (constraintId: string): ExecutionTrace => ({
16
16
  constraintId,
17
- level: 'guideline',
17
+ severity: 'warning',
18
18
  timestamp: 1700000000000,
19
19
  result: 'pass',
20
20
  });
@@ -42,7 +42,7 @@ describe('TraceCollector', () => {
42
42
  const disabledCollector = new TraceCollector({ enabled: false });
43
43
  disabledCollector.record({
44
44
  constraintId: 'test',
45
- level: 'iron_law',
45
+ severity: 'error',
46
46
  timestamp: Date.now(),
47
47
  result: 'pass',
48
48
  });
@@ -54,7 +54,7 @@ describe('TraceCollector', () => {
54
54
  it('should append trace to file', () => {
55
55
  collector.record({
56
56
  constraintId: 'test',
57
- level: 'iron_law',
57
+ severity: 'error',
58
58
  timestamp: Date.now(),
59
59
  result: 'pass',
60
60
  });
@@ -64,7 +64,7 @@ describe('TraceCollector', () => {
64
64
 
65
65
  describe('recordPass()', () => {
66
66
  it('should record pass trace', () => {
67
- collector.recordPass('test_constraint', 'iron_law');
67
+ collector.recordPass('test_constraint', 'error');
68
68
  const call = mockFs.appendFileSync.mock.calls[0];
69
69
  const content = JSON.parse(call[1] as string);
70
70
  expect(content.result).toBe('pass');
@@ -73,7 +73,7 @@ describe('TraceCollector', () => {
73
73
 
74
74
  describe('recordFail()', () => {
75
75
  it('should record fail trace', () => {
76
- collector.recordFail('test_constraint', 'iron_law');
76
+ collector.recordFail('test_constraint', 'error');
77
77
  const call = mockFs.appendFileSync.mock.calls[0];
78
78
  const content = JSON.parse(call[1] as string);
79
79
  expect(content.result).toBe('fail');
@@ -91,8 +91,8 @@ describe('TraceCollector', () => {
91
91
 
92
92
  it('should parse all traces from file', () => {
93
93
  mockFs.readFileSync.mockReturnValueOnce(
94
- '{"constraintId":"a","level":"iron_law","timestamp":100,"result":"pass"}\n' +
95
- '{"constraintId":"b","level":"guideline","timestamp":200,"result":"fail"}\n'
94
+ '{"constraintId":"a","severity":"error","timestamp":100,"result":"pass"}\n' +
95
+ '{"constraintId":"b","severity":"warning","timestamp":200,"result":"fail"}\n'
96
96
  );
97
97
  const traces = collector.read();
98
98
  expect(traces.length).toBe(2);
@@ -100,19 +100,19 @@ describe('TraceCollector', () => {
100
100
 
101
101
  it('should apply constraintId filter', () => {
102
102
  mockFs.readFileSync.mockReturnValueOnce(
103
- '{"constraintId":"a","level":"iron_law","timestamp":100,"result":"pass"}\n' +
104
- '{"constraintId":"b","level":"guideline","timestamp":200,"result":"fail"}\n'
103
+ '{"constraintId":"a","severity":"error","timestamp":100,"result":"pass"}\n' +
104
+ '{"constraintId":"b","severity":"warning","timestamp":200,"result":"fail"}\n'
105
105
  );
106
106
  const traces = collector.read({ constraintId: 'a' });
107
107
  expect(traces.length).toBe(1);
108
108
  });
109
109
 
110
- it('should apply level filter', () => {
110
+ it('should apply severity filter', () => {
111
111
  mockFs.readFileSync.mockReturnValueOnce(
112
- '{"constraintId":"a","level":"iron_law","timestamp":100,"result":"pass"}\n' +
113
- '{"constraintId":"b","level":"guideline","timestamp":200,"result":"fail"}\n'
112
+ '{"constraintId":"a","severity":"error","timestamp":100,"result":"pass"}\n' +
113
+ '{"constraintId":"b","severity":"warning","timestamp":200,"result":"fail"}\n'
114
114
  );
115
- const traces = collector.read({ level: 'guideline' });
115
+ const traces = collector.read({ severity: 'warning' });
116
116
  expect(traces.length).toBe(1);
117
117
  });
118
118
  });
@@ -121,7 +121,7 @@ describe('TraceCollector', () => {
121
121
  it('should read recent traces', () => {
122
122
  const now = Date.now();
123
123
  mockFs.readFileSync.mockReturnValueOnce(
124
- `{"constraintId":"new","level":"iron_law","timestamp":${now - 1000},"result":"pass"}\n`
124
+ `{"constraintId":"new","severity":"error","timestamp":${now - 1000},"result":"pass"}\n`
125
125
  );
126
126
  const traces = collector.readRecent(1);
127
127
  expect(traces.length).toBe(1);
@@ -131,7 +131,7 @@ describe('TraceCollector', () => {
131
131
  describe('readByConstraint()', () => {
132
132
  it('should read by constraint', () => {
133
133
  mockFs.readFileSync.mockReturnValueOnce(
134
- '{"constraintId":"a","level":"iron_law","timestamp":100,"result":"pass"}\n'
134
+ '{"constraintId":"a","severity":"error","timestamp":100,"result":"pass"}\n'
135
135
  );
136
136
  const traces = collector.readByConstraint('a');
137
137
  expect(traces.length).toBe(1);
@@ -143,7 +143,7 @@ describe('TraceCollector', () => {
143
143
  mockFs.statSync.mockReturnValueOnce({ size: 11 * 1024 * 1024 } as any);
144
144
  collector.record({
145
145
  constraintId: 'test',
146
- level: 'iron_law',
146
+ severity: 'error',
147
147
  timestamp: Date.now(),
148
148
  result: 'pass',
149
149
  });
@@ -155,7 +155,7 @@ describe('TraceCollector', () => {
155
155
  it('should return stats', () => {
156
156
  mockFs.existsSync.mockReturnValueOnce(true);
157
157
  mockFs.readFileSync.mockReturnValueOnce(
158
- '{"constraintId":"a","level":"iron_law","timestamp":100,"result":"pass"}\n'
158
+ '{"constraintId":"a","severity":"error","timestamp":100,"result":"pass"}\n'
159
159
  );
160
160
  mockFs.statSync.mockReturnValueOnce({ size: 1024 } as any);
161
161
  const stats = collector.getStats();
@@ -166,9 +166,9 @@ describe('TraceCollector', () => {
166
166
  describe('坏行容错(harness#82 裁决 4:原「抛」改 skip,签名与返回类型不变)', () => {
167
167
  it('read() 单行损坏只丢该行,合法 trace 照常返回', () => {
168
168
  mockFs.readFileSync.mockReturnValueOnce(
169
- '{"constraintId":"a","level":"iron_law","timestamp":100,"result":"pass"}\n' +
169
+ '{"constraintId":"a","severity":"error","timestamp":100,"result":"pass"}\n' +
170
170
  '{"constraintId":"b","broken"\n' +
171
- '{"constraintId":"c","level":"guideline","timestamp":200,"result":"fail"}\n'
171
+ '{"constraintId":"c","severity":"warning","timestamp":200,"result":"fail"}\n'
172
172
  );
173
173
  const traces = collector.read();
174
174
  expect(traces.map(t => t.constraintId)).toEqual(['a', 'c']);
@@ -176,9 +176,9 @@ describe('TraceCollector', () => {
176
176
 
177
177
  it('read() 坏行不阻断过滤', () => {
178
178
  mockFs.readFileSync.mockReturnValueOnce(
179
- '{"constraintId":"a","level":"iron_law","timestamp":100,"result":"pass"}\n' +
179
+ '{"constraintId":"a","severity":"error","timestamp":100,"result":"pass"}\n' +
180
180
  'not-json\n' +
181
- '{"constraintId":"a","level":"iron_law","timestamp":200,"result":"fail"}\n'
181
+ '{"constraintId":"a","severity":"error","timestamp":200,"result":"fail"}\n'
182
182
  );
183
183
  const traces = collector.read({ constraintId: 'a' });
184
184
  expect(traces).toHaveLength(2);
@@ -187,8 +187,8 @@ describe('TraceCollector', () => {
187
187
  it('getStats() 首末行坏时不抛:totalLines 保持原始行数,时间戳取合法记录', () => {
188
188
  mockFs.readFileSync.mockReturnValueOnce(
189
189
  'not-json\n' +
190
- '{"constraintId":"a","level":"iron_law","timestamp":100,"result":"pass"}\n' +
191
- '{"constraintId":"b","level":"guideline","timestamp":200,"result":"fail"}\n' +
190
+ '{"constraintId":"a","severity":"error","timestamp":100,"result":"pass"}\n' +
191
+ '{"constraintId":"b","severity":"warning","timestamp":200,"result":"fail"}\n' +
192
192
  'also-bad\n'
193
193
  );
194
194
  mockFs.statSync.mockReturnValueOnce({ size: 2048 } as any);
@@ -94,8 +94,8 @@ export function summarizeTraces(traces: ExecutionTrace[]): TraceSummary[] {
94
94
  const summaries: TraceSummary[] = [];
95
95
 
96
96
  for (const [constraintId, group] of grouped) {
97
- // 提取层级(从第一条 trace)
98
- const level = group[0].level;
97
+ // 提取严重性(从第一条 trace)
98
+ const severity = group[0].severity;
99
99
 
100
100
  // 计算时间范围
101
101
  const timeRange = timeRangeOf(group.map(t => t.timestamp));
@@ -120,7 +120,7 @@ export function summarizeTraces(traces: ExecutionTrace[]): TraceSummary[] {
120
120
 
121
121
  summaries.push({
122
122
  constraintId,
123
- level,
123
+ severity,
124
124
  timeRange,
125
125
  totalChecks,
126
126
  passCount,
@@ -155,7 +155,7 @@ export function detectTraceAnomalies(
155
155
  anomalies.push({
156
156
  type: 'rising_fail_rate',
157
157
  constraintId: summary.constraintId,
158
- level: summary.level,
158
+ severity: summary.severity,
159
159
  message: `约束 ${summary.constraintId} 失败率 ${Math.round(summary.failRate * 100)}% 且趋势上升`,
160
160
  data: {
161
161
  currentRate: summary.failRate,
@@ -172,7 +172,7 @@ export function detectTraceAnomalies(
172
172
  anomalies.push({
173
173
  type: 'low_pass_rate',
174
174
  constraintId: summary.constraintId,
175
- level: summary.level,
175
+ severity: summary.severity,
176
176
  message: `约束 ${summary.constraintId} 通过率 ${Math.round(summary.passRate * 100)}%,低于 30%`,
177
177
  data: {
178
178
  currentRate: summary.passRate,
@@ -358,14 +358,13 @@ export class TraceAnalyzer {
358
358
  lines.push('');
359
359
 
360
360
  for (const summary of summaries) {
361
- const levelEmoji = {
362
- iron_law: '🔴',
363
- guideline: '🟡',
364
- prompt: '🟣',
365
- tip: '🔵',
366
- }[summary.level];
367
-
368
- lines.push(`${levelEmoji} **${summary.constraintId}**`);
361
+ const severityEmoji = {
362
+ error: '🔴',
363
+ warning: '🟡',
364
+ info: '🔵',
365
+ }[summary.severity];
366
+
367
+ lines.push(`${severityEmoji} **${summary.constraintId}**`);
369
368
  lines.push(` - Checks: ${summary.totalChecks}`);
370
369
  lines.push(` - Pass: ${Math.round(summary.passRate * 100)}%`);
371
370
  lines.push(` - Fail: ${Math.round(summary.failRate * 100)}%`);