@dommaker/harness 1.8.1 → 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 (299) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +10 -13
  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/cli/commands/sync-docs/capabilities-syncer.d.ts +22 -0
  42. package/dist/cli/commands/sync-docs/capabilities-syncer.d.ts.map +1 -1
  43. package/dist/cli/commands/sync-docs/capabilities-syncer.js +113 -8
  44. package/dist/cli/commands/sync-docs/capabilities-syncer.js.map +1 -1
  45. package/dist/cli/commands/sync-docs/index.d.ts.map +1 -1
  46. package/dist/cli/commands/sync-docs/index.js +36 -4
  47. package/dist/cli/commands/sync-docs/index.js.map +1 -1
  48. package/dist/core/constraints/capabilities-parser.d.ts.map +1 -1
  49. package/dist/core/constraints/capabilities-parser.js +16 -4
  50. package/dist/core/constraints/capabilities-parser.js.map +1 -1
  51. package/dist/core/constraints/checker.d.ts +15 -24
  52. package/dist/core/constraints/checker.d.ts.map +1 -1
  53. package/dist/core/constraints/checker.js +33 -72
  54. package/dist/core/constraints/checker.js.map +1 -1
  55. package/dist/core/constraints/checkers/docs-freshness.js +1 -1
  56. package/dist/core/constraints/checkers/docs-freshness.js.map +1 -1
  57. package/dist/core/constraints/checkers/governance-presence.d.ts +2 -1
  58. package/dist/core/constraints/checkers/governance-presence.d.ts.map +1 -1
  59. package/dist/core/constraints/checkers/governance-presence.js +4 -3
  60. package/dist/core/constraints/checkers/governance-presence.js.map +1 -1
  61. package/dist/core/constraints/checkers/index.d.ts +1 -1
  62. package/dist/core/constraints/checkers/index.d.ts.map +1 -1
  63. package/dist/core/constraints/checkers/index.js +4 -8
  64. package/dist/core/constraints/checkers/index.js.map +1 -1
  65. package/dist/core/constraints/checkers/iron-flags.d.ts +3 -4
  66. package/dist/core/constraints/checkers/iron-flags.d.ts.map +1 -1
  67. package/dist/core/constraints/checkers/iron-flags.js +4 -5
  68. package/dist/core/constraints/checkers/iron-flags.js.map +1 -1
  69. package/dist/core/constraints/checkers/no-test-simplification.js +1 -1
  70. package/dist/core/constraints/checkers/no-test-simplification.js.map +1 -1
  71. package/dist/core/constraints/checkers/types.d.ts +1 -1
  72. package/dist/core/constraints/checkers/types.js +1 -1
  73. package/dist/core/constraints/definitions/guidelines.d.ts +4 -4
  74. package/dist/core/constraints/definitions/guidelines.d.ts.map +1 -1
  75. package/dist/core/constraints/definitions/guidelines.js +9 -25
  76. package/dist/core/constraints/definitions/guidelines.js.map +1 -1
  77. package/dist/core/constraints/definitions/iron-laws.d.ts +4 -4
  78. package/dist/core/constraints/definitions/iron-laws.d.ts.map +1 -1
  79. package/dist/core/constraints/definitions/iron-laws.js +10 -81
  80. package/dist/core/constraints/definitions/iron-laws.js.map +1 -1
  81. package/dist/core/constraints/definitions.d.ts +7 -9
  82. package/dist/core/constraints/definitions.d.ts.map +1 -1
  83. package/dist/core/constraints/definitions.js +13 -16
  84. package/dist/core/constraints/definitions.js.map +1 -1
  85. package/dist/core/constraints/index.d.ts +2 -5
  86. package/dist/core/constraints/index.d.ts.map +1 -1
  87. package/dist/core/constraints/index.js +3 -13
  88. package/dist/core/constraints/index.js.map +1 -1
  89. package/dist/core/constraints/injection-writer.d.ts +10 -38
  90. package/dist/core/constraints/injection-writer.d.ts.map +1 -1
  91. package/dist/core/constraints/injection-writer.js +17 -54
  92. package/dist/core/constraints/injection-writer.js.map +1 -1
  93. package/dist/core/constraints/run-env.d.ts +1 -10
  94. package/dist/core/constraints/run-env.d.ts.map +1 -1
  95. package/dist/core/constraints/run-env.js +1 -22
  96. package/dist/core/constraints/run-env.js.map +1 -1
  97. package/dist/core/constraints/usage-report.d.ts +5 -7
  98. package/dist/core/constraints/usage-report.d.ts.map +1 -1
  99. package/dist/core/constraints/usage-report.js +5 -10
  100. package/dist/core/constraints/usage-report.js.map +1 -1
  101. package/dist/core/effective-constraints.d.ts +12 -22
  102. package/dist/core/effective-constraints.d.ts.map +1 -1
  103. package/dist/core/effective-constraints.js +13 -30
  104. package/dist/core/effective-constraints.js.map +1 -1
  105. package/dist/core/index.d.ts +2 -2
  106. package/dist/core/index.d.ts.map +1 -1
  107. package/dist/core/index.js +3 -9
  108. package/dist/core/index.js.map +1 -1
  109. package/dist/core/project-config-loader.d.ts +4 -42
  110. package/dist/core/project-config-loader.d.ts.map +1 -1
  111. package/dist/core/project-config-loader.js +16 -125
  112. package/dist/core/project-config-loader.js.map +1 -1
  113. package/dist/core/validators/passes-gate.d.ts +2 -2
  114. package/dist/core/validators/passes-gate.js +6 -6
  115. package/dist/core/validators/passes-gate.js.map +1 -1
  116. package/dist/hooks/bootstrap.d.ts +9 -12
  117. package/dist/hooks/bootstrap.d.ts.map +1 -1
  118. package/dist/hooks/bootstrap.js +9 -31
  119. package/dist/hooks/bootstrap.js.map +1 -1
  120. package/dist/hooks/index.d.ts +5 -7
  121. package/dist/hooks/index.d.ts.map +1 -1
  122. package/dist/hooks/index.js +4 -10
  123. package/dist/hooks/index.js.map +1 -1
  124. package/dist/index.d.ts +9 -12
  125. package/dist/index.d.ts.map +1 -1
  126. package/dist/index.js +10 -23
  127. package/dist/index.js.map +1 -1
  128. package/dist/monitoring/trace-analyzer.d.ts.map +1 -1
  129. package/dist/monitoring/trace-analyzer.js +11 -12
  130. package/dist/monitoring/trace-analyzer.js.map +1 -1
  131. package/dist/monitoring/traces.d.ts +4 -4
  132. package/dist/monitoring/traces.d.ts.map +1 -1
  133. package/dist/monitoring/traces.js +8 -8
  134. package/dist/monitoring/traces.js.map +1 -1
  135. package/dist/presets/standard.d.ts +8 -10
  136. package/dist/presets/standard.d.ts.map +1 -1
  137. package/dist/presets/standard.js +10 -16
  138. package/dist/presets/standard.js.map +1 -1
  139. package/dist/types/constraint.d.ts +24 -35
  140. package/dist/types/constraint.d.ts.map +1 -1
  141. package/dist/types/constraint.js +8 -7
  142. package/dist/types/constraint.js.map +1 -1
  143. package/dist/types/passes-gate.d.ts +5 -5
  144. package/dist/types/passes-gate.d.ts.map +1 -1
  145. package/dist/types/project-config.d.ts +8 -66
  146. package/dist/types/project-config.d.ts.map +1 -1
  147. package/dist/types/project-config.js +3 -2
  148. package/dist/types/project-config.js.map +1 -1
  149. package/dist/types/trace.d.ts +8 -10
  150. package/dist/types/trace.d.ts.map +1 -1
  151. package/package.json +2 -2
  152. package/src/CONTEXT.md +3 -3
  153. package/src/__tests__/checker-extra.test.ts +37 -61
  154. package/src/__tests__/checker.test.ts +10 -115
  155. package/src/__tests__/effective-constraints.test.ts +18 -83
  156. package/src/__tests__/iron-laws.test.ts +71 -90
  157. package/src/__tests__/passes-gate-check.test.ts +2 -2
  158. package/src/__tests__/project-config-loader-extra.test.ts +22 -123
  159. package/src/__tests__/project-config-loader.test.ts +5 -33
  160. package/src/__tests__/public-exports.test.ts +31 -11
  161. package/src/__tests__/public-type-surface.test.ts +2 -13
  162. package/src/__tests__/public-value-surface.test.ts +1 -7
  163. package/src/__tests__/skip-semantics.test.ts +21 -37
  164. package/src/__tests__/trace-analyzer-extra.test.ts +14 -14
  165. package/src/__tests__/trace-analyzer.test.ts +21 -21
  166. package/src/__tests__/trace-collector.test.ts +22 -22
  167. package/src/__tests__/traces.test.ts +27 -28
  168. package/src/cli/commands/CONTEXT.md +12 -9
  169. package/src/cli/commands/__tests__/check-read-count.test.ts +4 -15
  170. package/src/cli/commands/__tests__/check-skip-output.test.ts +14 -14
  171. package/src/cli/commands/__tests__/check.test.ts +14 -31
  172. package/src/cli/commands/__tests__/constraints-report.test.ts +12 -80
  173. package/src/cli/commands/__tests__/constraints-retire.test.ts +42 -231
  174. package/src/cli/commands/__tests__/init-governance-io.test.ts +12 -58
  175. package/src/cli/commands/__tests__/init-ondisk.test.ts +12 -20
  176. package/src/cli/commands/__tests__/init.test.ts +0 -11
  177. package/src/cli/commands/__tests__/project-path-anchoring.test.ts +2 -2
  178. package/src/cli/commands/__tests__/registry.test.ts +39 -3
  179. package/src/cli/commands/__tests__/report-extra.test.ts +4 -4
  180. package/src/cli/commands/__tests__/report.test.ts +1 -1
  181. package/src/cli/commands/__tests__/scaffold.test.ts +4 -14
  182. package/src/cli/commands/__tests__/status-analysis-wiring.test.ts +3 -3
  183. package/src/cli/commands/__tests__/status-extra.test.ts +14 -14
  184. package/src/cli/commands/__tests__/status.test.ts +12 -12
  185. package/src/cli/commands/__tests__/sync-docs-agents.test.ts +1 -1
  186. package/src/cli/commands/__tests__/sync-docs-table-layout.test.ts +259 -0
  187. package/src/cli/commands/check.ts +43 -82
  188. package/src/cli/commands/constraints-report.ts +4 -59
  189. package/src/cli/commands/constraints-retire.ts +49 -154
  190. package/src/cli/commands/constraints.ts +11 -26
  191. package/src/cli/commands/definitions.ts +2 -2
  192. package/src/cli/commands/init.ts +8 -179
  193. package/src/cli/commands/report.ts +19 -23
  194. package/src/cli/commands/scaffold-templates.ts +1 -37
  195. package/src/cli/commands/scaffold.ts +0 -11
  196. package/src/cli/commands/status.ts +10 -10
  197. package/src/cli/commands/sync-docs/agents-syncer.ts +4 -25
  198. package/src/cli/commands/sync-docs/capabilities-syncer.ts +139 -9
  199. package/src/cli/commands/sync-docs/index.ts +41 -4
  200. package/src/core/CONTEXT.md +9 -9
  201. package/src/core/constraints/__tests__/capability-counts.test.ts +5 -5
  202. package/src/core/constraints/__tests__/collect-constraints.test.ts +13 -8
  203. package/src/core/constraints/__tests__/git-evidence.test.ts +4 -7
  204. package/src/core/constraints/__tests__/injection-writer.test.ts +8 -61
  205. package/src/core/constraints/__tests__/run-env.test.ts +5 -34
  206. package/src/core/constraints/__tests__/trace-injection.test.ts +1 -1
  207. package/src/core/constraints/capabilities-parser.ts +17 -5
  208. package/src/core/constraints/checker.ts +39 -88
  209. package/src/core/constraints/checkers/__tests__/check-outcome.test.ts +5 -8
  210. package/src/core/constraints/checkers/__tests__/governance-presence.test.ts +1 -53
  211. package/src/core/constraints/checkers/__tests__/iron-flags.test.ts +5 -25
  212. package/src/core/constraints/checkers/docs-freshness.ts +1 -1
  213. package/src/core/constraints/checkers/governance-presence.ts +4 -3
  214. package/src/core/constraints/checkers/index.ts +4 -10
  215. package/src/core/constraints/checkers/iron-flags.ts +3 -12
  216. package/src/core/constraints/checkers/no-test-simplification.ts +1 -1
  217. package/src/core/constraints/checkers/types.ts +1 -1
  218. package/src/core/constraints/definitions/guidelines.ts +8 -25
  219. package/src/core/constraints/definitions/iron-laws.ts +9 -82
  220. package/src/core/constraints/definitions.ts +14 -15
  221. package/src/core/constraints/index.ts +4 -19
  222. package/src/core/constraints/injection-writer.ts +16 -61
  223. package/src/core/constraints/run-env.ts +1 -33
  224. package/src/core/constraints/usage-report.ts +8 -15
  225. package/src/core/effective-constraints.ts +14 -45
  226. package/src/core/index.ts +3 -10
  227. package/src/core/project-config-loader.ts +20 -145
  228. package/src/core/validators/passes-gate.ts +6 -6
  229. package/src/failure/CONTEXT.md +1 -1
  230. package/src/hooks/CONTEXT.md +12 -22
  231. package/src/hooks/__tests__/bootstrap.test.ts +24 -75
  232. package/src/hooks/bootstrap.ts +9 -48
  233. package/src/hooks/index.ts +5 -20
  234. package/src/index.ts +9 -31
  235. package/src/monitoring/__tests__/trace-file-anchoring.test.ts +1 -1
  236. package/src/monitoring/__tests__/traces.test.ts +22 -22
  237. package/src/monitoring/trace-analyzer.ts +12 -13
  238. package/src/monitoring/traces.ts +8 -8
  239. package/src/presets/__tests__/standard.test.ts +12 -16
  240. package/src/presets/standard.ts +14 -23
  241. package/src/types/__tests__/types.test.ts +3 -3
  242. package/src/types/constraint.ts +26 -40
  243. package/src/types/passes-gate.ts +5 -5
  244. package/src/types/project-config.ts +8 -77
  245. package/src/types/trace.ts +8 -11
  246. package/dist/core/constraints/agent-prompt-renderer.d.ts +0 -32
  247. package/dist/core/constraints/agent-prompt-renderer.d.ts.map +0 -1
  248. package/dist/core/constraints/agent-prompt-renderer.js +0 -55
  249. package/dist/core/constraints/agent-prompt-renderer.js.map +0 -1
  250. package/dist/core/constraints/checkers/no-bypass-checkpoint.d.ts +0 -6
  251. package/dist/core/constraints/checkers/no-bypass-checkpoint.d.ts.map +0 -1
  252. package/dist/core/constraints/checkers/no-bypass-checkpoint.js +0 -40
  253. package/dist/core/constraints/checkers/no-bypass-checkpoint.js.map +0 -1
  254. package/dist/core/constraints/definitions/prompts.d.ts +0 -12
  255. package/dist/core/constraints/definitions/prompts.d.ts.map +0 -1
  256. package/dist/core/constraints/definitions/prompts.js +0 -400
  257. package/dist/core/constraints/definitions/prompts.js.map +0 -1
  258. package/dist/core/constraints/injection-drift.d.ts +0 -61
  259. package/dist/core/constraints/injection-drift.d.ts.map +0 -1
  260. package/dist/core/constraints/injection-drift.js +0 -131
  261. package/dist/core/constraints/injection-drift.js.map +0 -1
  262. package/dist/core/constraints/injection-renderer.d.ts +0 -23
  263. package/dist/core/constraints/injection-renderer.d.ts.map +0 -1
  264. package/dist/core/constraints/injection-renderer.js +0 -44
  265. package/dist/core/constraints/injection-renderer.js.map +0 -1
  266. package/dist/hooks/config.d.ts +0 -30
  267. package/dist/hooks/config.d.ts.map +0 -1
  268. package/dist/hooks/config.js +0 -34
  269. package/dist/hooks/config.js.map +0 -1
  270. package/dist/hooks/pipeline.d.ts +0 -54
  271. package/dist/hooks/pipeline.d.ts.map +0 -1
  272. package/dist/hooks/pipeline.js +0 -173
  273. package/dist/hooks/pipeline.js.map +0 -1
  274. package/dist/hooks/registry.d.ts +0 -70
  275. package/dist/hooks/registry.d.ts.map +0 -1
  276. package/dist/hooks/registry.js +0 -141
  277. package/dist/hooks/registry.js.map +0 -1
  278. package/dist/hooks/types.d.ts +0 -113
  279. package/dist/hooks/types.d.ts.map +0 -1
  280. package/dist/hooks/types.js +0 -9
  281. package/dist/hooks/types.js.map +0 -1
  282. package/src/__tests__/hooks-pipeline.test.ts +0 -201
  283. package/src/cli/commands/__tests__/check-drift.test.ts +0 -158
  284. package/src/cli/commands/__tests__/init-injection.test.ts +0 -466
  285. package/src/core/constraints/__tests__/agent-prompt-renderer.test.ts +0 -129
  286. package/src/core/constraints/__tests__/injection-drift.test.ts +0 -247
  287. package/src/core/constraints/agent-prompt-renderer.ts +0 -67
  288. package/src/core/constraints/checkers/__tests__/no-bypass-checkpoint.test.ts +0 -76
  289. package/src/core/constraints/checkers/no-bypass-checkpoint.ts +0 -40
  290. package/src/core/constraints/definitions/prompts.ts +0 -414
  291. package/src/core/constraints/injection-drift.ts +0 -142
  292. package/src/core/constraints/injection-renderer.ts +0 -44
  293. package/src/hooks/__tests__/config.test.ts +0 -19
  294. package/src/hooks/__tests__/pipeline.test.ts +0 -195
  295. package/src/hooks/__tests__/registry.test.ts +0 -115
  296. package/src/hooks/config.ts +0 -33
  297. package/src/hooks/pipeline.ts +0 -202
  298. package/src/hooks/registry.ts +0 -166
  299. package/src/hooks/types.ts +0 -120
@@ -1,13 +1,14 @@
1
1
  /**
2
- * 治理链路的 io 注入不逃逸(harness#149
2
+ * 治理链路的 io 注入不逃逸(harness#149,ADR-0029 收窄)
3
3
  *
4
- * setupGovernance 手握 io,却在两个调用点把它丢了(`setupClaudeMdOutputStyle(projectPath)`
5
- * / `setupGovernanceConstraints(projectPath)`),被调方一律 `io: CommandIO = processIO`
6
- * 兜成真实 stdout。真机输出正常,但注入面的测试看不见那 14 条提示——`⚠️ …标记残缺…`
7
- * 这类唯一提示写坏了没有测试会红。
4
+ * setupGovernance 手握 io,曾在调用点把它丢了(`setupClaudeMdOutputStyle(projectPath)`),
5
+ * 被调方一律 `io: CommandIO = processIO` 兜成真实 stdout。真机输出正常,但注入面的
6
+ * 测试看不见那些提示——`⚠️ …标记残缺…` 这类唯一提示写坏了没有测试会红。
8
7
  *
9
8
  * 本文件不 mock 任何 IO:在临时目录里真跑 init,断言治理段提示落在**注入面**。
10
- * 改造前这些断言逐条为红(文本逃到了 process.stdout)。
9
+ * ADR-0029:约束注入段 writer(setupAgentsMdConstraints / setupClaudeMdConstraints /
10
+ * setupGovernanceConstraints)已随文本注入层关停删除,相关用例移除;
11
+ * Output Style 段(通用 marker 机制)保留。
11
12
  */
12
13
 
13
14
  import * as fs from 'fs/promises';
@@ -63,49 +64,10 @@ describe('init 治理链路的提示落在注入面(harness#149)', () => {
63
64
  expect(io.outText()).toContain('✅ 已在 CLAUDE.md 顶部写入 Output Style 段');
64
65
  });
65
66
 
66
- it('治理契约追加到既有 AGENTS.md:`已追加治理契约` 进捕获 stdout', async () => {
67
- const io = await runInit({ 'AGENTS.md': '# AGENTS.md\n\n既有导读\n' });
68
- expect(io.outText()).toContain('✅ 已追加治理契约 PRESERVE:governance 段到 AGENTS.md');
69
- });
70
-
71
- it('标记残缺(唯一提示):`标记残缺…请人工修复` 进捕获 stdout', async () => {
72
- const io = await runInit({ 'AGENTS.md': '# AGENTS.md\n\n<!-- PRESERVE:governance -->\n残缺段\n' });
73
- expect(io.outText()).toContain('⚠️ AGENTS.md 中 PRESERVE:governance 标记残缺(只有单边),跳过治理契约写入,请人工修复');
74
- });
75
-
76
- // #158 补钉:这类提示在 init.ts 实测有四处,#149 只钉住上面一条——其余三处各补一条
77
- // 捕获面断言。四处分支不同文件/不同段位,fixture 各自单建,不共用残缺文件。
78
-
79
- it('标记残缺四处之二:CLAUDE.md 的 HARNESS_OUTPUT_STYLE 单边 → Output Style 注入告警', async () => {
67
+ it('标记残缺(唯一提示):HARNESS_OUTPUT_STYLE 单边 Output Style 注入告警进捕获 stdout', async () => {
80
68
  const io = await runInit({ 'CLAUDE.md': '# CLAUDE.md\n\n<!-- HARNESS_OUTPUT_STYLE_START -->\n半残段\n' });
81
69
  expect(io.outText()).toContain('⚠️ CLAUDE.md 中 HARNESS_OUTPUT_STYLE 标记残缺(单边或乱序),跳过 Output Style 注入,请人工修复');
82
70
  });
83
-
84
- it('标记残缺四处之三:AGENTS.md 的 PRESERVE 段内 HARNESS_CONSTRAINTS 单边 → 段内告警', async () => {
85
- const broken = [
86
- '# AGENTS.md',
87
- '',
88
- '<!-- PRESERVE:governance -->',
89
- '手写契约',
90
- '',
91
- '<!-- HARNESS_CONSTRAINTS_START -->',
92
- '半残注入',
93
- '<!-- /PRESERVE:governance -->',
94
- '',
95
- ].join('\n');
96
- const io = await runInit({ 'AGENTS.md': broken });
97
- expect(io.outText()).toContain('⚠️ AGENTS.md PRESERVE:governance 段内 HARNESS_CONSTRAINTS 标记残缺(单边或乱序),跳过治理契约写入,请人工修复');
98
- });
99
-
100
- it('标记残缺四处之四:CLAUDE.md 的 HARNESS_CONSTRAINTS 单边 → 治理约束注入告警(旧模型仓落点)', async () => {
101
- const io = await runInit({ 'CLAUDE.md': '# CLAUDE.md\n\n<!-- HARNESS_CONSTRAINTS_START -->\n半残段\n' });
102
- expect(io.outText()).toContain('⚠️ CLAUDE.md 中 HARNESS_CONSTRAINTS 标记残缺(单边或乱序),跳过治理约束注入,请人工修复');
103
- });
104
-
105
- it('新仓创建 AGENTS.md 治理段:创建提示进捕获 stdout', async () => {
106
- const io = await runInit({});
107
- expect(io.outText()).toContain('✅ 已创建 AGENTS.md 并写入治理契约 PRESERVE:governance 段');
108
- });
109
71
  });
110
72
 
111
73
  describe('writer 层 io 必传(源形状闸,防缺省兜底再回来)', () => {
@@ -115,17 +77,10 @@ describe('writer 层 io 必传(源形状闸,防缺省兜底再回来)', ()
115
77
  expect(sites[0]).toMatch(/^export async function init\(/);
116
78
  });
117
79
 
118
- it('三个 writer 与落点路由的 io 均为必传形参', () => {
119
- for (const writer of [
120
- 'setupClaudeMdOutputStyle',
121
- 'setupAgentsMdConstraints',
122
- 'setupClaudeMdConstraints',
123
- 'setupGovernanceConstraints',
124
- ]) {
125
- expect(INIT_SOURCE).toMatch(
126
- new RegExp(`export async function ${writer}\\(projectPath: string, io: CommandIO\\)`),
127
- );
128
- }
80
+ it('Output Style writer io 为必传形参', () => {
81
+ expect(INIT_SOURCE).toMatch(
82
+ /export async function setupClaudeMdOutputStyle\(projectPath: string, io: CommandIO\)/,
83
+ );
129
84
  });
130
85
 
131
86
  it('setupGovernance 的调用点逐个传 io(不留裸 projectPath 调用)', () => {
@@ -134,6 +89,5 @@ describe('writer 层 io 必传(源形状闸,防缺省兜底再回来)', ()
134
89
  INIT_SOURCE.indexOf('/**\n * 目录 CONTEXT.md 骨架的 plan'),
135
90
  );
136
91
  expect(governanceBody).toMatch(/await setupClaudeMdOutputStyle\(projectPath, io\)/);
137
- expect(governanceBody).toMatch(/await setupGovernanceConstraints\(projectPath, io\)/);
138
92
  });
139
93
  });
@@ -3,8 +3,10 @@
3
3
  *
4
4
  * init.test.ts 把 fs/promises 整体 mock 掉,只能看到「调过 writeFile」,看不到
5
5
  * 真写出了什么内容。本文件不 mock 任何 IO:在临时目录里真跑两遍 init——
6
- * 第一遍断言 9 个受管文件的落盘字节,第二遍(文件已在场且被用户改过)断言
7
- * 9 站点各自的第三态、用户内容一字节不动、以及「打印片段 == 真正落盘的内容」。
6
+ * 第一遍断言 8 个受管文件的落盘字节,第二遍(文件已在场且被用户改过)断言
7
+ * 8 站点各自的第三态、用户内容一字节不动、以及「打印片段 == 真正落盘的内容」。
8
+ * ADR-0029:custom-constraints.yml 示例站与 AGENTS.md 治理契约段 writer 已随
9
+ * 文本注入层关停移除,落盘集合同步收缩。
8
10
  */
9
11
 
10
12
  import * as fs from 'fs/promises';
@@ -120,9 +122,9 @@ describe('init 真落盘(无 IO mock)', () => {
120
122
 
121
123
  expect(await init({ ...INIT_OPTIONS, projectPath: root }, io)).toEqual({ kind: 'ok' });
122
124
 
123
- // 冻结的整屏 = scaffold 9 站点 + 治理段 writer 的落盘提示。#149 前 io 在
124
- // setupGovernance 两个调用点被丢,治理 writer 的提示逃到 process.stdout、不进捕获面
125
- // (本文件因此曾缺这一行);io 贯通后它回到捕获面,真机输出的字节不变。
125
+ // 冻结的整屏 = scaffold 8 站点 + 治理段 writer 的落盘提示。#149 前 io 在
126
+ // setupGovernance 调用点被丢,治理 writer 的提示逃到 process.stdout、不进捕获面;
127
+ // io 贯通后它回到捕获面,真机输出的字节不变。
126
128
  expect(normalize(io.outText(), root)).toBe(`🚀 初始化 harness 配置...
127
129
  配置目录: <P>/.harness
128
130
  预设: standard
@@ -130,14 +132,12 @@ describe('init 真落盘(无 IO mock)', () => {
130
132
  ✅ 已创建配置文件: <P>/.harness/config.yml (v*)
131
133
  ✅ 已创建示例检查点文件: <P>/.harness/checkpoints.yml
132
134
  ✅ 已创建 Resolutions 文件: <P>/.harness/resolutions.json
133
- ✅ 已创建自定义约束示例: custom-constraints.yml
134
135
  ✅ 已创建 .git/hooks/pre-commit
135
136
  ✅ 已创建 .git/hooks/pre-push
136
137
  ✅ 已创建 .github/workflows/harness-check.yml
137
138
 
138
139
  📋 设置治理文件...
139
140
  ✅ 已创建 CHANGELOG.md
140
- ✅ 已创建 AGENTS.md 并写入治理契约 PRESERVE:governance 段 (v*)
141
141
  ✅ 已创建 src/CONTEXT.md
142
142
  治理检查已由 harness-check.yml 覆盖,跳过创建 harness-governance.yml
143
143
 
@@ -145,9 +145,8 @@ describe('init 真落盘(无 IO mock)', () => {
145
145
 
146
146
  下一步:
147
147
  1. 编辑 .harness/config.yml 自定义配置
148
- 2. 编辑 .harness/custom-constraints.yml 添加项目约束
149
- 3. 正常开发:每次 git commit 查暂存的(增量快反馈),每次 git push 查整仓的(全量兜底)——重复是设计使然
150
- 4. 运行 harness status 查看状态
148
+ 2. 正常开发:每次 git commit 查暂存的(增量快反馈),每次 git push 查整仓的(全量兜底)——重复是设计使然
149
+ 3. 运行 harness status 查看状态
151
150
 
152
151
  💡 提示: 使用 harness init --print-snippets 查看配置代码片段
153
152
  `);
@@ -164,7 +163,6 @@ describe('init 真落盘(无 IO mock)', () => {
164
163
  expect(await read('.git/hooks/pre-push')).toBe(PRE_PUSH_HOOK_BYTES);
165
164
 
166
165
  expect(await read('.github/workflows/harness-check.yml')).toContain('name: Harness Check');
167
- expect(await read('.harness/custom-constraints.yml')).toContain('custom_constraints:');
168
166
  expect(await read('.harness/checkpoints.yml')).toContain('id: build-success');
169
167
  expect(JSON.parse(await read('.harness/resolutions.json')).capability_sync).toBeDefined();
170
168
  expect(await read('CHANGELOG.md')).toContain('Keep a Changelog');
@@ -186,11 +184,10 @@ describe('init 真落盘(无 IO mock)', () => {
186
184
  await init({ ...INIT_OPTIONS, projectPath: root }, io);
187
185
  const lines = io.outLines();
188
186
 
189
- // 顺序 = init 的落盘顺序;harness-governance.yml(第九站)因既有 workflow 覆盖而跳过
187
+ // 顺序 = init 的落盘顺序;harness-governance.yml(末站)因既有 workflow 覆盖而跳过
190
188
  expectOrderedSubsequence(lines, [
191
189
  'checkpoints.yml 已存在,跳过',
192
190
  'resolutions.json 已存在,跳过',
193
- 'custom-constraints.yml 已存在',
194
191
  '⚠️ .git/hooks/pre-commit 已存在',
195
192
  '💡 请手动添加以下内容到文件末尾:',
196
193
  '⚠️ .git/hooks/pre-push 已存在',
@@ -223,7 +220,6 @@ describe('init 真落盘(无 IO mock)', () => {
223
220
  '.git/hooks/pre-commit': '#!/bin/sh\n# 我自己的钩子\n',
224
221
  '.git/hooks/pre-push': '#!/bin/sh\n# 我自己的推送钩子\n',
225
222
  '.github/workflows/harness-check.yml': 'name: 我自己的流水线\n',
226
- '.harness/custom-constraints.yml': 'custom_constraints: {}\n',
227
223
  '.harness/checkpoints.yml': 'checkpoints: []\n',
228
224
  '.harness/resolutions.json': '{}\n',
229
225
  'CHANGELOG.md': '# 我的更新日志\n',
@@ -274,9 +270,8 @@ describe('init 真落盘(无 IO mock)', () => {
274
270
  expect(io.outText()).not.toContain('harness-governance.yml');
275
271
  expect(await exists(path.join(root, '.github'))).toBe(false);
276
272
  expect(await exists(path.join(root, '.gitlab-ci.yml'))).toBe(false);
277
- // 治理文档面照常:CHANGELOG / 约束段 / CONTEXT.md 不受 CI 豁免影响
273
+ // 治理文档面照常:CHANGELOG / CONTEXT.md 不受 CI 豁免影响
278
274
  expect(await exists(path.join(root, 'CHANGELOG.md'))).toBe(true);
279
- expect(await exists(path.join(root, 'AGENTS.md'))).toBe(true);
280
275
  });
281
276
 
282
277
  it('无 .git 与无源码目录时仍按原措辞告知,不写任何文件', async () => {
@@ -556,9 +551,7 @@ describe('init --ci × -g 组合边界(harness#156,真落盘)', () => {
556
551
  '.git/hooks/pre-push',
557
552
  '.harness/checkpoints.yml',
558
553
  '.harness/config.yml',
559
- '.harness/custom-constraints.yml',
560
554
  '.harness/resolutions.json',
561
- 'AGENTS.md',
562
555
  'CHANGELOG.md',
563
556
  'src/CONTEXT.md',
564
557
  'src/index.ts',
@@ -591,9 +584,8 @@ harness:
591
584
  version: *
592
585
  `);
593
586
 
594
- // 治理文档面(CHANGELOG / 约束段 / CONTEXT.md)在 none 下照常生成,不受 CI 豁免影响
587
+ // 治理文档面(CHANGELOG / CONTEXT.md)在 none 下照常生成,不受 CI 豁免影响
595
588
  expect(await fs.readFile(path.join(root, 'CHANGELOG.md'), 'utf-8')).toContain('Keep a Changelog');
596
- expect(await fs.readFile(path.join(root, 'AGENTS.md'), 'utf-8')).toContain('PRESERVE:governance');
597
589
  expect(await fs.readFile(path.join(root, 'src/CONTEXT.md'), 'utf-8')).toBe(CONTEXT_MD_BYTES);
598
590
  });
599
591
 
@@ -308,17 +308,6 @@ describe('init command', () => {
308
308
  });
309
309
  });
310
310
 
311
- describe('custom-constraints', () => {
312
- it('应该跳过创建当已存在', async () => {
313
- mockFs.mkdir.mockResolvedValue(undefined);
314
- mockFs.writeFile.mockResolvedValue(undefined);
315
- existingFiles.add(`${PROJECT}/.harness/custom-constraints.yml`);
316
-
317
- await init({ preset: 'standard', projectPath: PROJECT }, io);
318
- expect(io.outText()).toContain('custom-constraints.yml 已存在');
319
- });
320
- });
321
-
322
311
  describe('governance', () => {
323
312
  it('应该在配置中包含 governance 段', async () => {
324
313
  mockFs.mkdir.mockResolvedValue(undefined);
@@ -210,7 +210,7 @@ describe('-p 锚定:执行与 IO 必须落在 projectPath(cwd ≠ projectPat
210
210
  .slice(seeded)
211
211
  .map(l => JSON.parse(l) as { constraintId: string; projectPath?: string });
212
212
  expect(written.map(t => t.constraintId)).toEqual(
213
- expect.arrayContaining(['incremental_progress', 'no_implementation_without_requirement'])
213
+ expect.arrayContaining(['no_completion_without_verification', 'no_hardcoded_credentials'])
214
214
  );
215
215
  expect(written.every(t => t.projectPath === projectSide)).toBe(true);
216
216
  // 病灶:修复前这一支落在调用方 cwd(A),B 侧 mtime 不动
@@ -231,7 +231,7 @@ describe('-p 锚定:执行与 IO 必须落在 projectPath(cwd ≠ projectPat
231
231
  expect(await status({ projectPath: projectSide }, io)).toEqual({ kind: 'ok' });
232
232
  // 记录数取自 B 的正本行数:写侧漏到 A 就必然对不上(假绿),读到 A 也读不到 check 的落点
233
233
  expect(io.outText()).toContain(`记录数: ${traceLinesOf(projectSide).length} 条`);
234
- expect(io.outText()).toContain('no_implementation_without_requirement');
234
+ expect(io.outText()).toContain('no_completion_without_verification');
235
235
  });
236
236
 
237
237
  it('不带 --project-path 的项目内使用:落点仍是当下 cwd(存量使用者无感)', async () => {
@@ -15,6 +15,7 @@ import * as path from 'path';
15
15
  import { spawnSync } from 'child_process';
16
16
  import { COMMAND_DEFINITIONS, type CommandDefinition, type CommandImplRef } from '../definitions';
17
17
  import { GATE_DEFINITIONS } from '../../../gates/definitions';
18
+ import { FileKnowledgeStore } from '../../../knowledge/store';
18
19
 
19
20
  function collectRefs(defs: CommandDefinition[]): CommandImplRef[] {
20
21
  const refs: CommandImplRef[] = [];
@@ -189,8 +190,17 @@ const hasDist = fs.existsSync(distCommands);
189
190
  * 经 NODE_OPTIONS=--require 预加载探针 spawn bin(进程退出时打印加载的
190
191
  * 命令实现模块清单)。不用 node -e(commander 在 -e 下走 eval 分支,
191
192
  * argv 解析不同,会误判位置参数)。
193
+ *
194
+ * env 用于把命令指向临时夹具(见「别名子命令」用例),第二参随调用方并入。
195
+ * maxBuffer 显式抬高:spawnSync 缺省 1MB,子进程 stdout 超限是被 ENOBUFS **杀掉**
196
+ * 而非报错——status 变 null、stderr 一句解释都没有,看着像路由崩了。2026-09-20 本机
197
+ * 发版即以此形状暴露(真实库 221 条 / 1.35MB JSON)。抬高上限只是别再吞掉诊断信息,
198
+ * **数据面隔离仍由各用例的夹具负责**,不拿它当免罪符。
192
199
  */
193
- function runWithModuleProbe(argv: string[]): { status: number | null; implModules: string[]; stdout: string; stderr: string } {
200
+ function runWithModuleProbe(
201
+ argv: string[],
202
+ extraEnv: Record<string, string> = {},
203
+ ): { status: number | null; implModules: string[]; stdout: string; stderr: string } {
194
204
  const probeDir = fs.mkdtempSync(path.join(os.tmpdir(), 'harness-lazy-probe-'));
195
205
  const probeFile = path.join(probeDir, 'probe.js');
196
206
  fs.writeFileSync(probeFile, [
@@ -204,7 +214,8 @@ function runWithModuleProbe(argv: string[]): { status: number | null; implModule
204
214
  cwd: repoRoot,
205
215
  encoding: 'utf-8',
206
216
  timeout: 30000,
207
- env: { ...process.env, NODE_OPTIONS: `--require ${probeFile}` },
217
+ maxBuffer: 32 * 1024 * 1024,
218
+ env: { ...process.env, NODE_OPTIONS: `--require ${probeFile}`, ...extraEnv },
208
219
  });
209
220
  const match = r.stderr.match(/IMPL_MODULES=(.*)/);
210
221
  return {
@@ -270,7 +281,32 @@ smoke('bin/harness.js 端到端(dist 存在时)', () => {
270
281
  });
271
282
 
272
283
  it('别名子命令解析到同一实现(knowledge ls = list,候选7)', () => {
273
- const r = runWithModuleProbe(['knowledge', 'ls', '--json']);
284
+ // 数据面隔离:本用例判的是**路由**(别名 ls 与主名 list 命中同一实现、只加载 knowledge
285
+ // 侧两个模块),知识库内容纯属旁证。不指夹具时它读的是操作机的真实库(本机实测 221 条 /
286
+ // 1.35MB JSON),而 CI 全新 checkout 上该库为空——两侧取数规模差三个数量级,大的一侧
287
+ // stdout 越过 spawnSync 缺省缓冲直接被杀掉(形状见 runWithModuleProbe 注释)。
288
+ // 夹具目录由 src/test-setup/mkdtemp-cleanup.ts 在 afterAll 统一回收。
289
+ const kbDir = fs.mkdtempSync(path.join(os.tmpdir(), 'harness-smoke-kb-'));
290
+ new FileKnowledgeStore({ baseDir: kbDir }).save({
291
+ id: 'SMOKE-001',
292
+ type: 'guideline',
293
+ title: 'Smoke Fixture Entry',
294
+ content: '别名路由用例的夹具条目,只为了让 --json 出口有真实记录可数',
295
+ maturity: 'verified',
296
+ layer: 'project',
297
+ created: new Date().toISOString(),
298
+ lastReferenced: new Date().toISOString(),
299
+ contributors: ['tester'],
300
+ projects: ['smoke'],
301
+ tags: [],
302
+ applicablePhases: [],
303
+ sourceReferences: [],
304
+ referencedBy: [],
305
+ executionResults: [],
306
+ consumptionMode: 'reference',
307
+ origin: 'system',
308
+ });
309
+ const r = runWithModuleProbe(['knowledge', 'ls', '--json'], { KNOWLEDGE_BASE_DIR: kbDir });
274
310
  expect(r.status).toBe(0);
275
311
  expect(JSON.parse(r.stdout)).toHaveProperty('total');
276
312
  expect(r.implModules).toEqual([
@@ -46,8 +46,8 @@ describe('report command - 补充覆盖', () => {
46
46
 
47
47
  expect(output).toContain('# Harness 检查报告');
48
48
  expect(output).toContain('## 约束检查');
49
- expect(output).toContain('Iron Laws');
50
- expect(output).toContain('Guidelines');
49
+ expect(output).toContain('error ');
50
+ expect(output).toContain('warning 级');
51
51
  expect(output).toContain('@dommaker/harness');
52
52
  });
53
53
  });
@@ -71,8 +71,8 @@ describe('report command - 补充覆盖', () => {
71
71
  expect(data).toHaveProperty('timestamp');
72
72
  expect(data).toHaveProperty('constraints');
73
73
  expect(data.constraints).toHaveProperty('total');
74
- expect(data.constraints).toHaveProperty('ironLaws');
75
- expect(data.constraints).toHaveProperty('guidelines');
74
+ expect(data.constraints).toHaveProperty('errors');
75
+ expect(data.constraints).toHaveProperty('warnings');
76
76
  expect(data.constraints).toHaveProperty('violations');
77
77
  });
78
78
  });
@@ -97,7 +97,7 @@ describe('report command', () => {
97
97
  const parsed = JSON.parse(jsonStr);
98
98
  expect(parsed.constraints).toBeDefined();
99
99
  expect(parsed.constraints.total).toBeGreaterThan(0);
100
- expect(parsed.constraints.ironLaws).toBeGreaterThan(0);
100
+ expect(parsed.constraints.errors).toBeGreaterThan(0);
101
101
  expect(parsed.timestamp).toBeDefined();
102
102
  expect(parsed.projectPath).toBeDefined();
103
103
  });
@@ -26,7 +26,6 @@ import {
26
26
  preCommitHookFile,
27
27
  prePushHookFile,
28
28
  harnessCheckCiFile,
29
- customConstraintsFile,
30
29
  changelogFile,
31
30
  contextDocFile,
32
31
  governanceWorkflowFile,
@@ -72,12 +71,11 @@ class MemoryFs implements ScaffoldFileSystem {
72
71
  const PROJECT = '/srv/project';
73
72
  const USER_CONTENT = '用户自己的内容,不许覆盖\n';
74
73
 
75
- /** 全部 9 站点,顺序 = init 的落盘顺序 */
74
+ /** 全部 8 站点,顺序 = init 的落盘顺序 */
76
75
  function allSites(): ManagedFile[] {
77
76
  return [
78
77
  checkpointsFile(PROJECT),
79
78
  resolutionsFile(PROJECT),
80
- customConstraintsFile(PROJECT),
81
79
  preCommitHookFile(PROJECT),
82
80
  prePushHookFile(PROJECT),
83
81
  harnessCheckCiFile(PROJECT, 'github', ['ci.yml']),
@@ -113,7 +111,7 @@ beforeEach(() => {
113
111
 
114
112
  describe('writeManagedFile:三态判定', () => {
115
113
  it('不在场 → created:建父目录、落盘模板正文、绿字告知', async () => {
116
- const file = customConstraintsFile(PROJECT);
114
+ const file = changelogFile(PROJECT, 'keep-a-changelog');
117
115
 
118
116
  expect(await writeManagedFile(file, io, fs)).toBe('created');
119
117
 
@@ -179,7 +177,7 @@ describe('writeManagedFile:三态判定', () => {
179
177
  });
180
178
 
181
179
  it('runPlan 按顺序逐站点落盘并逐站点回报状态', async () => {
182
- const plan = [customConstraintsFile(PROJECT), changelogFile(PROJECT, 'keep-a-changelog')];
180
+ const plan = [checkpointsFile(PROJECT), changelogFile(PROJECT, 'keep-a-changelog')];
183
181
  fs.seed(plan[1].target, USER_CONTENT);
184
182
 
185
183
  expect(await runPlan(plan, io, fs)).toEqual(['created', 'exists']);
@@ -188,11 +186,10 @@ describe('writeManagedFile:三态判定', () => {
188
186
  });
189
187
 
190
188
  describe('init 的脚手架 plan 站点面', () => {
191
- it('9 站点齐备且目标路径逐字冻结(init 7 + validate 2 同源收口)', () => {
189
+ it('8 站点齐备且目标路径逐字冻结(init 6 + validate 2 同源收口)', () => {
192
190
  expect(allSites().map(f => f.target)).toEqual([
193
191
  `${PROJECT}/.harness/checkpoints.yml`,
194
192
  `${PROJECT}/.harness/resolutions.json`,
195
- `${PROJECT}/.harness/custom-constraints.yml`,
196
193
  `${PROJECT}/.git/hooks/pre-commit`,
197
194
  `${PROJECT}/.git/hooks/pre-push`,
198
195
  `${PROJECT}/.github/workflows/harness-check.yml`,
@@ -342,13 +339,6 @@ describe('对外文案逐字冻结(9 站点 × 落盘态 / 在场态)', () =
342
339
  ],
343
340
  'name: Harness Check',
344
341
  ],
345
- [
346
- 'custom-constraints.yml',
347
- () => customConstraintsFile(PROJECT),
348
- '✅ 已创建自定义约束示例: custom-constraints.yml',
349
- ['custom-constraints.yml 已存在'],
350
- '',
351
- ],
352
342
  [
353
343
  'checkpoints.yml',
354
344
  () => checkpointsFile(PROJECT),
@@ -18,8 +18,8 @@ import { status } from '../status';
18
18
  const STATUS_SOURCE = fs.readFileSync(path.join(__dirname, '..', 'status.ts'), 'utf-8');
19
19
 
20
20
  /** 1 pass + 1 fail:failRate 0.5、passRate 0.5 → 无异常;2 fail:passRate 0 → low_pass_rate */
21
- const PASS = { constraintId: 'alpha', level: 'iron_law' as const, result: 'pass' as const };
22
- const FAIL = { constraintId: 'beta', level: 'guideline' as const, result: 'fail' as const };
21
+ const PASS = { constraintId: 'alpha', severity: 'error' as const, result: 'pass' as const };
22
+ const FAIL = { constraintId: 'beta', severity: 'warning' as const, result: 'fail' as const };
23
23
 
24
24
  let io: CapturingIO;
25
25
  beforeEach(() => {
@@ -47,7 +47,7 @@ describe('status 分析接线(ADR-0020)', () => {
47
47
 
48
48
  await status({ projectPath: root, detail: true }, io);
49
49
 
50
- expect(io.outText()).toContain('🔴 Iron Laws:');
50
+ expect(io.outText()).toContain('🔴 error 级约束:');
51
51
  expect(io.outText()).toContain('alpha');
52
52
  expect(io.outText()).toContain('检查: 2 | 通过: 100% | 失败: 0%');
53
53
  expect(io.outText()).not.toContain('个异常');
@@ -34,7 +34,7 @@ const mockFs = fs as jest.Mocked<typeof fs>;
34
34
  /** trace 文件内容:一 trace 一行,缺省字段补齐成合法 ExecutionTrace(timestamp 递增) */
35
35
  function traceFile(traces: Array<Partial<ExecutionTrace>>): string {
36
36
  return traces
37
- .map((t, i) => JSON.stringify({ level: 'iron_law', timestamp: i + 1, result: 'pass', ...t }))
37
+ .map((t, i) => JSON.stringify({ severity: 'error', timestamp: i + 1, result: 'pass', ...t }))
38
38
  .join('\n');
39
39
  }
40
40
 
@@ -77,7 +77,7 @@ describe('status command - 补充覆盖', () => {
77
77
  it('有异常时应该显示详细信息和下一步建议', async () => {
78
78
  // 两个约束各自全失败 → 各自判出一枚 low_pass_rate
79
79
  mockFs.readFileSync.mockReturnValue(traceFile([
80
- ...repeats('no_bypass_checkpoint', 2, 'fail'),
80
+ ...repeats('docs_freshness', 2, 'fail'),
81
81
  ...repeats('no_completion_without_verification', 2, 'fail'),
82
82
  ]));
83
83
 
@@ -102,9 +102,9 @@ describe('status command - 补充覆盖', () => {
102
102
  });
103
103
 
104
104
  describe('约束级别统计', () => {
105
- it('应该显示 Iron Laws 统计', async () => {
105
+ it('应该显示 error 级约束统计', async () => {
106
106
  mockFs.readFileSync.mockReturnValue(traceFile([
107
- { constraintId: 'no_bypass_checkpoint' },
107
+ { constraintId: 'docs_freshness' },
108
108
  { constraintId: 'no_completion_without_verification' },
109
109
  ]));
110
110
 
@@ -112,35 +112,35 @@ describe('status command - 补充覆盖', () => {
112
112
 
113
113
  const output = io.outText();
114
114
  expect(output).toContain('📈 约束统计:');
115
- expect(output).toContain('🔴 Iron Laws:');
115
+ expect(output).toContain('🔴 error 级约束:');
116
116
  expect(output).toContain('✅ no_completion_without_verification');
117
117
  });
118
118
 
119
- it('应该显示 Guidelines 统计', async () => {
119
+ it('应该显示 warning 级约束统计', async () => {
120
120
  mockFs.readFileSync.mockReturnValue(traceFile([
121
- { constraintId: 'capability_sync', level: 'guideline', result: 'pass' },
121
+ { constraintId: 'capability_sync', severity: 'warning', result: 'pass' },
122
122
  ]));
123
123
 
124
124
  await runStatus();
125
125
 
126
- expect(io.outText()).toContain('🟡 Guidelines:');
126
+ expect(io.outText()).toContain('🟡 warning 级约束:');
127
127
  });
128
128
  });
129
129
 
130
130
  describe('详细模式扩展', () => {
131
131
  it('详细模式应该显示所有级别详情', async () => {
132
132
  mockFs.readFileSync.mockReturnValue(traceFile([
133
- { constraintId: 'no_bypass_checkpoint', level: 'iron_law' },
134
- { constraintId: 'capability_sync', level: 'guideline' },
135
- { constraintId: 'capability_sync', level: 'guideline' },
133
+ { constraintId: 'docs_freshness', severity: 'error' },
134
+ { constraintId: 'capability_sync', severity: 'warning' },
135
+ { constraintId: 'capability_sync', severity: 'warning' },
136
136
  ]));
137
137
 
138
138
  await runStatus({ detail: true });
139
139
 
140
140
  const output = io.outText();
141
141
  expect(output).toContain('📈 约束统计:');
142
- expect(output).toContain('🔴 Iron Laws:');
143
- expect(output).toContain('🟡 Guidelines:');
142
+ expect(output).toContain('🔴 error 级约束:');
143
+ expect(output).toContain('🟡 warning 级约束:');
144
144
  expect(output).toContain('检查: 2 | 通过: 100% | 失败: 0%');
145
145
  });
146
146
  });
@@ -148,7 +148,7 @@ describe('status command - 补充覆盖', () => {
148
148
  describe('JSON parse 异常处理', () => {
149
149
  it('无效 JSON 行应该被过滤', async () => {
150
150
  mockFs.readFileSync.mockReturnValue(
151
- ['invalid json', JSON.stringify({ constraintId: 'valid', level: 'iron_law', timestamp: 1, result: 'pass' }), 'also invalid'].join('\n')
151
+ ['invalid json', JSON.stringify({ constraintId: 'valid', severity: 'error', timestamp: 1, result: 'pass' }), 'also invalid'].join('\n')
152
152
  );
153
153
 
154
154
  await runStatus();
@@ -34,7 +34,7 @@ const mockFs = fs as jest.Mocked<typeof fs>;
34
34
  /** trace 文件内容:一 trace 一行,缺省字段补齐成合法 ExecutionTrace(timestamp 递增) */
35
35
  function traceFile(traces: Array<Partial<ExecutionTrace>>): string {
36
36
  return traces
37
- .map((t, i) => JSON.stringify({ level: 'iron_law', timestamp: i + 1, result: 'pass', ...t }))
37
+ .map((t, i) => JSON.stringify({ severity: 'error', timestamp: i + 1, result: 'pass', ...t }))
38
38
  .join('\n');
39
39
  }
40
40
 
@@ -99,7 +99,7 @@ describe('status command', () => {
99
99
  it('应该显示记录数', async () => {
100
100
  mockFs.readFileSync.mockReturnValue(traceFile([
101
101
  { constraintId: 'test1' },
102
- { constraintId: 'test2', level: 'guideline' },
102
+ { constraintId: 'test2', severity: 'warning' },
103
103
  ]));
104
104
 
105
105
  await runStatus();
@@ -107,14 +107,14 @@ describe('status command', () => {
107
107
  expect(io.outText()).toContain('📈 约束统计:');
108
108
  });
109
109
 
110
- it('应该显示 Iron Laws 统计', async () => {
110
+ it('应该显示 error 级约束统计', async () => {
111
111
  mockFs.readFileSync.mockReturnValue(traceFile([
112
- { constraintId: 'no_bypass_checkpoint' },
112
+ { constraintId: 'no_completion_without_verification' },
113
113
  ]));
114
114
 
115
115
  await runStatus({ detail: true });
116
- expect(io.outText()).toContain('🔴 Iron Laws:');
117
- expect(io.outText()).toContain('✅ no_bypass_checkpoint');
116
+ expect(io.outText()).toContain('🔴 error 级约束:');
117
+ expect(io.outText()).toContain('✅ no_completion_without_verification');
118
118
  expect(io.outText()).toContain('检查: 1 | 通过: 100% | 失败: 0%');
119
119
  });
120
120
  });
@@ -162,14 +162,14 @@ describe('status command', () => {
162
162
  });
163
163
  });
164
164
 
165
- describe('Guidelines 统计', () => {
166
- it('应该显示 Guidelines 统计', async () => {
165
+ describe('warning 级约束统计', () => {
166
+ it('应该显示 warning 级约束统计', async () => {
167
167
  mockFs.readFileSync.mockReturnValue(traceFile([
168
- { constraintId: 'test_guide', level: 'guideline' },
168
+ { constraintId: 'test_guide', severity: 'warning' },
169
169
  ]));
170
170
 
171
171
  await runStatus();
172
- expect(io.outText()).toContain('🟡 Guidelines:');
172
+ expect(io.outText()).toContain('🟡 warning 级约束:');
173
173
  expect(io.outText()).toContain('✅ test_guide');
174
174
  });
175
175
  });
@@ -221,11 +221,11 @@ describe('status command', () => {
221
221
  });
222
222
 
223
223
  describe('详细模式扩展', () => {
224
- it('应该显示 Guidelines 详细统计', async () => {
224
+ it('应该显示 warning 级约束详细统计', async () => {
225
225
  mockFs.readFileSync.mockReturnValue(traceFile([
226
226
  ...repeats('test_guide', 3, 'pass'),
227
227
  ...repeats('test_guide', 2, 'fail'),
228
- ].map(t => ({ ...t, level: 'guideline' as const }))));
228
+ ].map(t => ({ ...t, severity: 'warning' as const }))));
229
229
 
230
230
  await runStatus({ detail: true });
231
231
  expect(io.outText()).toContain('⚠️ test_guide');
@@ -126,7 +126,7 @@ describe('sync-docs --agents', () => {
126
126
  expect(content).not.toContain('clean');
127
127
  // 约束与治理
128
128
  expect(content).toContain('preset: standard');
129
- expect(content).toContain('Iron Laws 2 条、Guidelines 3 条');
129
+ expect(content).toContain('约束清单:`CLAUDE.md` Governance Rules ');
130
130
  // 知识入口(只写目录存在性,不写易变的条目数——避免 --check 漂移竞态)
131
131
  expect(content).toContain('项目知识库,用 `harness knowledge` 查询');
132
132
  expect(content).not.toContain('知识库(');