@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
@@ -0,0 +1,259 @@
1
+ /**
2
+ * sync-docs 表格排版回归测试(harness#171)
3
+ *
4
+ * 症状:撤下 CAPABILITIES.md 的模块登记行时清空该行而非删行,残留空行把
5
+ * CommonMark 表格切断。判定面 = 「上一行与下一行都是 `|` 表格行、本行为空」不得存在。
6
+ * 正本修复在写路径(整行删除 + 存量收拢 + 空表收掉),--check 侧必须报待清理
7
+ * (check/fix 同规则才收敛,ADR-0009 口径)。
8
+ */
9
+ import * as fs from 'fs';
10
+ import * as os from 'os';
11
+ import * as path from 'path';
12
+ import { captureIO, type CapturingIO } from '../../command-contract';
13
+ import { normalizeCapabilitiesTableLayout } from '../sync-docs/capabilities-syncer';
14
+ import { syncDocs } from '../sync-docs';
15
+
16
+ let io: CapturingIO;
17
+ beforeEach(() => {
18
+ io = captureIO();
19
+ });
20
+
21
+ const HEADER = '| 模块 | 文件 | 说明 |\n|------|------|------|\n';
22
+
23
+ /** 「上一行与下一行都是表格行、本行为空」的行数 —— 本票的判定面 */
24
+ function countBlankRowsInsideTable(content: string): number {
25
+ const lines = content.split('\n');
26
+ let n = 0;
27
+ for (let i = 1; i < lines.length - 1; i++) {
28
+ if (
29
+ lines[i].trim() === '' &&
30
+ /^\s*\|/.test(lines[i - 1]) &&
31
+ /^\s*\|/.test(lines[i + 1])
32
+ ) {
33
+ n++;
34
+ }
35
+ }
36
+ return n;
37
+ }
38
+
39
+ /** 建一个 file 模式的最小工程:srcFiles 存在,CAPABILITIES.md 由 rows 拼出 */
40
+ function makeProject(
41
+ name: string,
42
+ srcFiles: string[],
43
+ doc: string
44
+ ): string {
45
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), `sync-docs-layout-${name}-`));
46
+ fs.mkdirSync(path.join(dir, 'src'), { recursive: true });
47
+ for (const f of srcFiles) {
48
+ const file = path.join(dir, 'src', f);
49
+ fs.mkdirSync(path.dirname(file), { recursive: true });
50
+ fs.writeFileSync(file, 'export const x = 1;\n');
51
+ }
52
+ fs.writeFileSync(path.join(dir, 'CAPABILITIES.md'), doc);
53
+ return dir;
54
+ }
55
+ const read = (dir: string) => fs.readFileSync(path.join(dir, 'CAPABILITIES.md'), 'utf-8');
56
+ const dataRow = (name: string, file: string, desc = 'D') => `| ${name} | ${file} | ${desc} |`;
57
+
58
+ describe('sync-docs CAPABILITIES.md 表格排版(#171)', () => {
59
+ it('撤中间登记行:整行删除,表格保持连续', async () => {
60
+ const dir = makeProject(
61
+ 'middle',
62
+ ['a.ts', 'c.ts'],
63
+ `# Capabilities\n\n${HEADER}${dataRow('a', 'src/a.ts')}\n${dataRow('b', 'src/b.ts')}\n${dataRow('c', 'src/c.ts')}\n`
64
+ );
65
+
66
+ await syncDocs({ projectPath: dir }, io);
67
+
68
+ const out = read(dir);
69
+ expect(out).not.toContain('src/b.ts');
70
+ expect(countBlankRowsInsideTable(out)).toBe(0);
71
+ expect(out).toBe(`# Capabilities\n\n${HEADER}${dataRow('a', 'src/a.ts')}\n${dataRow('c', 'src/c.ts')}\n`);
72
+ fs.rmSync(dir, { recursive: true, force: true });
73
+ });
74
+
75
+ it('撤目录条目行(studio 撤登记形状):同样整行删除', async () => {
76
+ const dir = makeProject(
77
+ 'dir-entry',
78
+ ['cli/cli.ts', 'harness/h.ts'],
79
+ `# Capabilities\n\n${HEADER}` +
80
+ `${dataRow('cli', 'src/cli/', 'C')}\n` +
81
+ `${dataRow('hooks', 'src/hooks/', 'H')}\n` +
82
+ `${dataRow('harness', 'src/harness/', 'A')}\n`
83
+ );
84
+
85
+ await syncDocs({ projectPath: dir }, io);
86
+
87
+ const out = read(dir);
88
+ expect(out).not.toContain('src/hooks/');
89
+ expect(countBlankRowsInsideTable(out)).toBe(0);
90
+ expect(out).toContain(`${dataRow('cli', 'src/cli/', 'C')}\n${dataRow('harness', 'src/harness/', 'A')}`);
91
+ fs.rmSync(dir, { recursive: true, force: true });
92
+ });
93
+
94
+ it('撤最后一行:不留文件末尾空行', async () => {
95
+ const dir = makeProject(
96
+ 'last',
97
+ ['a.ts'],
98
+ `# Capabilities\n\n${HEADER}${dataRow('a', 'src/a.ts')}\n${dataRow('gone', 'src/gone.ts')}\n`
99
+ );
100
+
101
+ await syncDocs({ projectPath: dir }, io);
102
+
103
+ expect(read(dir)).toBe(`# Capabilities\n\n${HEADER}${dataRow('a', 'src/a.ts')}\n`);
104
+ fs.rmSync(dir, { recursive: true, force: true });
105
+ });
106
+
107
+ it('存量脏行(无其它漂移):--check 报待清理,写模式收拢且收拢后 check 转绿', async () => {
108
+ const dirty = `# Capabilities\n\n${HEADER}${dataRow('a', 'src/a.ts')}\n\n${dataRow('z', 'src/z.ts')}\n`;
109
+ const dir = makeProject('legacy', ['a.ts', 'z.ts'], dirty);
110
+
111
+ expect(countBlankRowsInsideTable(read(dir))).toBe(1);
112
+ const check = await syncDocs({ projectPath: dir, check: true }, io);
113
+ expect(check).toEqual({ kind: 'fail', reason: expect.stringContaining('表格') });
114
+
115
+ await syncDocs({ projectPath: dir }, io);
116
+ const out = read(dir);
117
+ expect(countBlankRowsInsideTable(out)).toBe(0);
118
+ expect(out).toContain('src/a.ts');
119
+ expect(out).toContain('src/z.ts');
120
+ expect(await syncDocs({ projectPath: dir, check: true }, io)).toEqual({ kind: 'ok' });
121
+ fs.rmSync(dir, { recursive: true, force: true });
122
+ });
123
+
124
+ it('表格被撤空:连表头/分隔行一起收掉', async () => {
125
+ const dir = makeProject(
126
+ 'empty-table',
127
+ [],
128
+ `# Capabilities\n\n${HEADER}${dataRow('gone1', 'src/gone1.ts')}\n${dataRow('gone2', 'src/gone2.ts')}\n`
129
+ );
130
+
131
+ await syncDocs({ projectPath: dir }, io);
132
+
133
+ const out = read(dir);
134
+ expect(out).not.toContain('|------|');
135
+ expect(out).not.toContain('模块 | 文件');
136
+ expect(out).not.toMatch(/\n{3,}/);
137
+ expect(await syncDocs({ projectPath: dir, check: true }, io)).toEqual({ kind: 'ok' });
138
+ fs.rmSync(dir, { recursive: true, force: true });
139
+ });
140
+
141
+ it('撤登同时有新增:不得把仍要使用的表头收掉', async () => {
142
+ const dir = makeProject(
143
+ 'remove-and-add',
144
+ ['b.ts', 'fresh.ts'],
145
+ `# Capabilities\n\n${HEADER}${dataRow('a', 'src/gone.ts')}\n${dataRow('b', 'src/b.ts')}\n`
146
+ );
147
+
148
+ await syncDocs({ projectPath: dir }, io);
149
+
150
+ const out = read(dir);
151
+ expect(out).toContain('模块 | 文件 | 说明');
152
+ expect(out).toContain('fresh.ts');
153
+ expect(countBlankRowsInsideTable(out)).toBe(0);
154
+ fs.rmSync(dir, { recursive: true, force: true });
155
+ });
156
+
157
+ it('表格外的空行不动(段落分隔不是脏行)', async () => {
158
+ const doc = `# Capabilities\n\n${HEADER}${dataRow('a', 'src/a.ts')}\n\n## 说明\n\n散文。\n`;
159
+ const dir = makeProject('prose', ['a.ts'], doc);
160
+
161
+ const check = await syncDocs({ projectPath: dir, check: true }, io);
162
+ expect(check).toEqual({ kind: 'ok' });
163
+ expect(read(dir)).toBe(doc);
164
+ fs.rmSync(dir, { recursive: true, force: true });
165
+ });
166
+
167
+ it('代码块内「表头+分隔行无数据行」的示例不被收掉', async () => {
168
+ const doc =
169
+ `# Capabilities\n\n${HEADER}${dataRow('a', 'src/a.ts')}\n\n` +
170
+ `登记格式:\n\n\`\`\`markdown\n| 模块 | 文件 | 说明 |\n|------|------|------|\n\`\`\`\n\n散文。\n`;
171
+ const dir = makeProject('fenced-empty-table', ['a.ts'], doc);
172
+
173
+ expect(await syncDocs({ projectPath: dir, check: true }, io)).toEqual({ kind: 'ok' });
174
+
175
+ await syncDocs({ projectPath: dir }, io);
176
+ expect(read(dir)).toBe(doc);
177
+ fs.rmSync(dir, { recursive: true, force: true });
178
+ });
179
+
180
+ it('代码块内的表格样式行不被收拢(含块内空行)', async () => {
181
+ const doc =
182
+ `# Capabilities\n\n${HEADER}${dataRow('a', 'src/a.ts')}\n\n` +
183
+ `示例:\n\n\`\`\`\n| x | y |\n\n| z | w |\n\`\`\`\n`;
184
+ const dir = makeProject('fenced-blank-row', ['a.ts'], doc);
185
+
186
+ expect(await syncDocs({ projectPath: dir, check: true }, io)).toEqual({ kind: 'ok' });
187
+
188
+ await syncDocs({ projectPath: dir }, io);
189
+ expect(read(dir)).toBe(doc);
190
+ fs.rmSync(dir, { recursive: true, force: true });
191
+ });
192
+
193
+ it('两张空表相邻:一次收拢即干净(规则互相制造触发点,须跑到不动点)', () => {
194
+ // 规则①先吃掉两张空表之间的那个空行(两侧都是表格行),规则②在同一轮里
195
+ // 只看得到「表头+分隔行后面还有表格行」的前一张,收得掉后一张。不迭代就收不干净。
196
+ const first = normalizeCapabilitiesTableLayout(`${HEADER}\n${HEADER}`);
197
+
198
+ expect(first).toEqual({ content: '', blankLines: 1, emptyTables: 2 });
199
+ // 不动点:再跑一次零改动,`--check` 才不会修完还红
200
+ expect(normalizeCapabilitiesTableLayout(first.content)).toEqual({
201
+ content: '',
202
+ blankLines: 0,
203
+ emptyTables: 0,
204
+ });
205
+ });
206
+
207
+ it('收掉空表后不留三个以上连续换行(写模式收干净)', async () => {
208
+ const dir = makeProject(
209
+ 'no-triple-newline',
210
+ [],
211
+ `# Capabilities\n\n${HEADER}${dataRow('gone', 'src/gone.ts')}\n\n## 说明\n\n散文。\n`
212
+ );
213
+
214
+ await syncDocs({ projectPath: dir }, io);
215
+
216
+ const out = read(dir);
217
+ expect(out).not.toMatch(/\n{3,}/);
218
+ expect(out).toContain('## 说明');
219
+ expect(out).toContain('散文。');
220
+ expect(await syncDocs({ projectPath: dir, check: true }, io)).toEqual({ kind: 'ok' });
221
+ fs.rmSync(dir, { recursive: true, force: true });
222
+ });
223
+
224
+ it('围栏内示例行引用已删文件:随幽灵行一起删掉,且 check 收敛(取舍见实现注释)', async () => {
225
+ // 登记条目由 capabilities-parser 全文扫描得出(ADR-0009),块内行也算登记项;
226
+ // 只让幽灵行删除豁免围栏,这个示例会永远被报成已删模块且修不掉。
227
+ const doc =
228
+ `# Capabilities\n\n${HEADER}${dataRow('a', 'src/a.ts')}\n\n` +
229
+ `登记格式示例:\n\n\`\`\`markdown\n${HEADER}${dataRow('gone', 'src/gone.ts')}\n\`\`\`\n`;
230
+ const dir = makeProject('fenced-ghost-entry', ['a.ts'], doc);
231
+
232
+ expect(await syncDocs({ projectPath: dir, check: true }, io)).toMatchObject({ kind: 'fail' });
233
+ expect(io.outText()).toContain('src/gone.ts');
234
+
235
+ await syncDocs({ projectPath: dir }, io);
236
+
237
+ const out = read(dir);
238
+ expect(out).not.toContain('src/gone.ts');
239
+ expect(out).toContain(dataRow('a', 'src/a.ts'));
240
+ // 只吃掉引用已删文件的那一行,块内其余正文留着(不是「把围栏里所有行一起删」)
241
+ expect(out).toContain('```markdown\n' + HEADER);
242
+ expect(countBlankRowsInsideTable(out)).toBe(0);
243
+ expect(await syncDocs({ projectPath: dir, check: true }, io)).toEqual({ kind: 'ok' });
244
+ fs.rmSync(dir, { recursive: true, force: true });
245
+ });
246
+
247
+ it('CRLF 文档撤行:整行连行尾一起删除', async () => {
248
+ const doc = `# Capabilities\r\n\r\n${HEADER.replace(/\n/g, '\r\n')}${dataRow('a', 'src/a.ts')}\r\n${dataRow('gone', 'src/gone.ts')}\r\n`;
249
+ const dir = makeProject('crlf', ['a.ts'], doc);
250
+
251
+ await syncDocs({ projectPath: dir }, io);
252
+
253
+ const out = read(dir);
254
+ expect(out).not.toContain('src/gone.ts');
255
+ expect(out.endsWith(`${dataRow('a', 'src/a.ts')}\r\n`)).toBe(true);
256
+ expect(countBlankRowsInsideTable(out)).toBe(0);
257
+ fs.rmSync(dir, { recursive: true, force: true });
258
+ });
259
+ });
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * harness check 命令
3
3
  *
4
- * 检查约束是否满足(check 层:Iron Laws / Guidelines;prompt 层仅注入不检查)
4
+ * 检查约束是否满足(severity='error' 阻断 / severity='warning' 告警)
5
5
  * 工单 23:触发条件与证据检测迁至 core/constraints/context-builder
6
- * ADR-0001:约束集统一走 getMergedConstraintsConfig 生效集链路(preset/config 禁用/custom/scenes)
6
+ * 约束集统一走 getMergedConstraintsConfig 生效集链路(preset/config 禁用)
7
7
  * harness#88:本命令是 trace 记录器的组合根——core 不上行依赖 monitoring,
8
8
  * 真实收集器在此经构造参数接线;#139:收集器锚根构造,trace 落点跟 --project-path 走
9
9
  */
@@ -11,13 +11,11 @@
11
11
  import chalk from 'chalk';
12
12
  import * as path from 'path';
13
13
  import { ConstraintChecker } from '../../core/constraints/checker';
14
- import { IRON_LAWS, GUIDELINES, PROMPTS } from '../../core/constraints/definitions';
15
- import { getMergedConstraintsConfig, constraintsFromMerged } from '../../core/effective-constraints';
14
+ import { CONSTRAINTS } from '../../core/constraints/definitions';
15
+ import { getMergedConstraintsConfig } from '../../core/effective-constraints';
16
16
  import { buildConstraintContext } from '../../core/constraints/context-builder';
17
17
  import { createGitEvidence, type GitEvidence } from '../../core/constraints/git-evidence';
18
18
  import { createRunEnv, type RunEnv } from '../../core/constraints/run-env';
19
- import { detectInjectionDrift } from '../../core/constraints/injection-drift';
20
- import { GOVERNANCE_HEADING } from '../../core/constraints/injection-writer';
21
19
  import { TraceCollector } from '../../monitoring/traces';
22
20
  import { readJsonl } from '../../utils/jsonl';
23
21
  import { DEFAULT_TRACE_FILE, type ExecutionTrace } from '../../types/trace';
@@ -100,14 +98,11 @@ export async function check(
100
98
  const runEnv = options.runEnv ?? createRunEnv(projectPath);
101
99
  const stateIO = options.stateIO ?? fileStateIO(projectPath);
102
100
 
103
- // 生效约束集(ADR-0001):内置 → preset → config.yml 禁用 → custom 追加 → scenes 过滤。
101
+ // 生效约束集:内置 → preset → config.yml 禁用。
104
102
  // --preset 仅在没有项目自定义配置时覆盖 config.yml 的 preset(工单 23 语义:
105
103
  // 项目自定义配置优先于 CLI 预设),优先级规则收在 getMergedConstraintsConfig 一处。
106
104
  // CLI 不给 -p 缺省值:没传 = 尊重 config.yml(ADR-0023 步骤 4.5,缺省值曾让两者不可区分)
107
105
  const merged = getMergedConstraintsConfig(runEnv, { preset: options.preset });
108
- if (merged.custom.length > 0) {
109
- log(io, chalk.gray(`自定义约束: ${merged.custom.length} 条`));
110
- }
111
106
  if (merged.disabled.length > 0) {
112
107
  log(io, chalk.gray(`已禁用约束: ${merged.disabled.join(', ')}`));
113
108
  }
@@ -132,7 +127,7 @@ export async function check(
132
127
  }
133
128
  log(io, chalk.gray(`触发条件: ${[context.operation, ...(context.extraTriggers ?? [])].join(', ')}`));
134
129
 
135
- // 执行三层检查(per-request 传 customConfig,避免单例状态污染;证据同 run 同源)
130
+ // 执行约束检查(per-request 传 customConfig,避免单例状态污染;证据同 run 同源)
136
131
  // trace 记录器经构造参数接线(harness#88):一次命令一个 checker 实例
137
132
  // #139:收集器锚根构造——不传 projectPath 时 trace 会落进调用方 cwd,B 侧读不到
138
133
  const checker = new ConstraintChecker(new TraceCollector({ projectPath }));
@@ -141,20 +136,20 @@ export async function check(
141
136
  // 输出结果
142
137
  log(io);
143
138
 
144
- // skipped(约定未采用/证据未接线)单独列示,不进 pass/fail 统计(ADR-0001)
139
+ // skipped(约定未采用/证据未接线)单独列示,不进 pass/fail 统计
145
140
  const skippedResults = [
146
- ...result.ironLaws,
147
- ...result.guidelines,
141
+ ...result.errors,
142
+ ...result.warnings,
148
143
  ].filter(r => r.skipped);
149
144
 
150
- // Iron Laws
151
- const evaluatedIronLaws = result.ironLaws.filter(r => !r.skipped);
152
- const ironLawViolations = evaluatedIronLaws.filter(r => !r.satisfied);
153
- if (ironLawViolations.length === 0 && evaluatedIronLaws.length > 0) {
154
- log(io, chalk.green(`✅ 铁律: 全部通过 (${evaluatedIronLaws.length} 条)`));
155
- } else if (ironLawViolations.length > 0) {
156
- log(io, chalk.red(`❌ 铁律违规: ${ironLawViolations.length} 条`));
157
- ironLawViolations.forEach(r => {
145
+ // severity='error'(违规即阻断)
146
+ const evaluatedErrors = result.errors.filter(r => !r.skipped);
147
+ const errorViolations = evaluatedErrors.filter(r => !r.satisfied);
148
+ if (errorViolations.length === 0 && evaluatedErrors.length > 0) {
149
+ log(io, chalk.green(`✅ error 级约束: 全部通过 (${evaluatedErrors.length} 条)`));
150
+ } else if (errorViolations.length > 0) {
151
+ log(io, chalk.red(`❌ error 级约束违规: ${errorViolations.length} 条`));
152
+ errorViolations.forEach(r => {
158
153
  if (r.constraint) {
159
154
  log(io, chalk.red(` - ${r.constraint.id}: ${r.constraint.message}`));
160
155
  log(io, chalk.red(` ${r.constraint.rule}`));
@@ -162,31 +157,31 @@ export async function check(
162
157
  }
163
158
  });
164
159
  log(io);
165
- log(io, chalk.red('🛑 铁律检查失败,请修复后再提交'));
160
+ log(io, chalk.red('🛑 error 级约束检查失败,请修复后再提交'));
166
161
  return {
167
162
  kind: 'fail',
168
- reason: `iron law violated: ${ironLawViolations.map(r => r.constraint?.id ?? 'unknown').join(', ')}`,
163
+ reason: `error-severity constraint violated: ${errorViolations.map(r => r.constraint?.id ?? 'unknown').join(', ')}`,
169
164
  };
170
165
  }
171
166
 
172
- // Guidelines
167
+ // severity='warning'(告警不阻断)
173
168
  if (result.warningCount > 0) {
174
- log(io, chalk.yellow(`⚠️ 指导原则警告: ${result.warningCount} 条`));
175
- result.guidelines.filter(r => !r.satisfied).forEach(r => {
169
+ log(io, chalk.yellow(`⚠️ warning 级约束警告: ${result.warningCount} 条`));
170
+ result.warnings.filter(r => !r.satisfied).forEach(r => {
176
171
  if (r.constraint) {
177
172
  log(io, chalk.yellow(` - ${r.constraint.id}: ${r.constraint.message}`));
178
173
  logEvidence(io, r, 'yellow');
179
174
  }
180
175
  });
181
- } else if (result.guidelines.length > 0) {
182
- const evaluatedGuidelines = result.guidelines.filter(r => !r.skipped);
183
- const passedGuidelines = evaluatedGuidelines.filter(r => r.satisfied).length;
184
- log(io, chalk.green(`✅ 指导原则: ${passedGuidelines}/${evaluatedGuidelines.length} 通过`));
176
+ } else if (result.warnings.length > 0) {
177
+ const evaluatedWarnings = result.warnings.filter(r => !r.skipped);
178
+ const passedWarnings = evaluatedWarnings.filter(r => r.satisfied).length;
179
+ log(io, chalk.green(`✅ warning 级约束: ${passedWarnings}/${evaluatedWarnings.length} 通过`));
185
180
  }
186
181
 
187
182
  // 提示:通过但带证据(harness#119)——与本次变更无因果的仓库级漂移在此露出,
188
183
  // 不判违规、不改 exit code,只保证「看得见且能自己修」
189
- const hints = [...result.ironLaws, ...result.guidelines].filter(
184
+ const hints = [...result.errors, ...result.warnings].filter(
190
185
  r => !r.skipped && r.satisfied && (r.evidence?.length ?? 0) > 0
191
186
  );
192
187
  if (hints.length > 0) {
@@ -202,29 +197,6 @@ export async function check(
202
197
  });
203
198
  }
204
199
 
205
- // 注入漂移校验(ADR-0001 决策 7):黄色警告块,不改 exit code、不影响门禁结果。
206
- // 无漂移/未注入零输出;漂移检测自身异常静默吞掉,绝不影响 check。
207
- try {
208
- // 生效集直接用本 run 那一份:一遍算完,且比对对象就是本次实际执法的规则集(ADR-0023 步骤 4.5)
209
- const drift = detectInjectionDrift(runEnv, undefined, constraintsFromMerged(merged));
210
- if (drift.hasDrift) {
211
- log(io);
212
- log(io, chalk.yellow(`⚠️ 检测到 ${drift.injectionFile ?? '治理文档'} 约束注入漂移(仅警告,不阻断):`));
213
- if (drift.versionDrift) {
214
- log(io, chalk.yellow(` ⚠️⚠️ 注入段版本 (${drift.versionDrift.actual}) ≠ 已安装 harness 版本 (${drift.versionDrift.expected}):agent 上下文中的规则与已安装 harness 版本不一致`));
215
- }
216
- if (drift.contentDrift) {
217
- log(io, chalk.yellow(` 内容漂移: 缺失 ${drift.contentDrift.missing.length} 条 / 多余 ${drift.contentDrift.extra.length} 条(条目级差异见 harness constraints report)`));
218
- }
219
- if (drift.duplicateHeading) {
220
- log(io, chalk.yellow(` 检测到重复的 "${GOVERNANCE_HEADING}" 章节`));
221
- }
222
- log(io, chalk.yellow(` 修复: ${drift.fixHint}`));
223
- }
224
- } catch {
225
- // 漂移检测失败不影响 check 结果
226
- }
227
-
228
200
  log(io);
229
201
  log(io, chalk.green('✅ 约束检查通过'));
230
202
 
@@ -288,37 +260,26 @@ async function getSmartHint(projectPath: string, stateIO: StateIO): Promise<stri
288
260
  }
289
261
 
290
262
  /**
291
- * 列出所有约束
263
+ * 列出所有约束(按 severity 分组)
292
264
  */
293
265
  /** optionRoutes 一律以 (options) 调用;--list 不消费检查选项,形参仅占位 */
294
266
  export function listLaws(_options: Partial<CheckOptions> = {}, io: CommandIO = processIO): CommandResult {
295
267
  log(io, chalk.blue('\n📜 所有约束:\n'));
296
268
 
297
- // Iron Laws
298
- log(io, chalk.red('🔴 铁律 (Iron Laws) - 绝对禁止,无例外:\n'));
299
- Object.values(IRON_LAWS).forEach(constraint => {
300
- log(io, chalk.red(` ${constraint.id}`));
301
- log(io, chalk.gray(` ${constraint.rule}`));
302
- log(io, chalk.gray(` ${constraint.message}`));
303
- log(io);
304
- });
305
-
306
- // Guidelines
307
- log(io, chalk.yellow('🟡 指导原则 (Guidelines) - 优先建议,违背发警告但不阻止:\n'));
308
- Object.values(GUIDELINES).forEach(constraint => {
309
- log(io, chalk.yellow(` ${constraint.id}`));
310
- log(io, chalk.gray(` ${constraint.rule}`));
311
- log(io, chalk.gray(` ${constraint.message}`));
312
- log(io);
313
- });
314
-
315
- // Prompts(ADR-0001:纯注入层,不执行检查)
316
- log(io, chalk.blue('🔵 提示 (Prompts) - 纯文本注入,不参与检查:\n'));
317
- Object.values(PROMPTS).forEach(constraint => {
318
- log(io, chalk.blue(` ${constraint.id}`));
319
- log(io, chalk.gray(` ${constraint.rule}`));
320
- log(io, chalk.gray(` ${constraint.message}`));
321
- log(io);
322
- });
269
+ const groups: Array<{ severity: 'error' | 'warning'; heading: string; paint: (s: string) => string }> = [
270
+ { severity: 'error', heading: '🔴 error - 违规即阻断,无例外:', paint: chalk.red },
271
+ { severity: 'warning', heading: '🟡 warning 级 - 违规发警告但不阻止:', paint: chalk.yellow },
272
+ ];
273
+ for (const group of groups) {
274
+ log(io, group.paint(group.heading + '\n'));
275
+ Object.values(CONSTRAINTS)
276
+ .filter(c => c.severity === group.severity)
277
+ .forEach(constraint => {
278
+ log(io, group.paint(` ${constraint.id}`));
279
+ log(io, chalk.gray(` ${constraint.rule}`));
280
+ log(io, chalk.gray(` ${constraint.message}`));
281
+ log(io);
282
+ });
283
+ }
323
284
  return { kind: 'ok' };
324
285
  }
@@ -1,10 +1,9 @@
1
1
  /**
2
- * harness constraints report —— 约束使用报告(ADR-0001 决策 3/4
2
+ * harness constraints report —— 约束使用报告(ADR-0001 决策 3/4,ADR-0029 收窄)
3
3
  *
4
4
  * 只读。面向"人审约束"场景:
5
- * - check 层统计表(total/pass/fail/skip、fail 率、首次/最近触发)
5
+ * - check 约束统计表(total/pass/fail/skip、fail 率、首次/最近触发)
6
6
  * - 退役候选诊断(零触发/零拦截/不可评估/高噪),retire 交互模式的数据源
7
- * - 当前生效 prompt 注入清单
8
7
  * - 配置健康(unknownIds 残留提示)
9
8
  * - --export [file]:脱敏 markdown 摘要(不含项目路径)
10
9
  */
@@ -21,8 +20,6 @@ import {
21
20
  type DiagnoseThresholds,
22
21
  } from '../../core/constraints/usage-report';
23
22
  import { getConstraintsMeta } from './constraints';
24
- import { detectInjectionDrift, type InjectionDrift } from '../../core/constraints/injection-drift';
25
- import { GOVERNANCE_HEADING } from '../../core/constraints/injection-writer';
26
23
  import { log, processIO, type CommandIO, type CommandResult } from '../command-contract';
27
24
 
28
25
  export interface ConstraintsReportOptions {
@@ -75,7 +72,7 @@ export function renderExportMarkdown(
75
72
  }
76
73
  lines.push('');
77
74
 
78
- lines.push('## 统计表(check 层)');
75
+ lines.push('## 统计表');
79
76
  lines.push('');
80
77
  lines.push('| id | total | pass | fail | skip | fail 率 | 首次触发 | 最近触发 |');
81
78
  lines.push('| --- | ---: | ---: | ---: | ---: | ---: | --- | --- |');
@@ -109,43 +106,6 @@ export function renderExportMarkdown(
109
106
  return lines.join('\n');
110
107
  }
111
108
 
112
- /**
113
- * 渲染"注入漂移"小节的文本行(ADR-0001 决策 7:详细条目级差异进 report)
114
- *
115
- * 返回纯文本行数组(不含 chalk 着色),调用方逐行 console.log。
116
- */
117
- export function renderInjectionDriftLines(drift: InjectionDrift): string[] {
118
- const lines: string[] = [];
119
- if (drift.notInjected) {
120
- lines.push(' CLAUDE.md / AGENTS.md 均无约束注入标记段(未注入,不算漂移);可运行 npx @dommaker/harness init 注入');
121
- if (drift.duplicateHeading) {
122
- lines.push(` 另检测到多个 "${GOVERNANCE_HEADING}" 标题(历史遗留重复章节),建议手工清理后重跑 npx @dommaker/harness init`);
123
- }
124
- return lines;
125
- }
126
- if (!drift.hasDrift) {
127
- lines.push(' 无漂移');
128
- return lines;
129
- }
130
- if (drift.versionDrift) {
131
- lines.push(` 版本漂移: 注入段版本 (${drift.versionDrift.actual}) ≠ 当前 harness 版本 (${drift.versionDrift.expected})`);
132
- }
133
- if (drift.contentDrift) {
134
- lines.push(' 内容漂移(条目级差异):');
135
- for (const l of drift.contentDrift.missing) {
136
- lines.push(` 缺失: ${l}`);
137
- }
138
- for (const l of drift.contentDrift.extra) {
139
- lines.push(` 多余: ${l}`);
140
- }
141
- }
142
- if (drift.duplicateHeading) {
143
- lines.push(` 重复章节: 标记段之外还存在另一个 "${GOVERNANCE_HEADING}" 标题`);
144
- }
145
- lines.push(` 修复: ${drift.fixHint}`);
146
- return lines;
147
- }
148
-
149
109
  /**
150
110
  * CLI handler: harness constraints report
151
111
  */
@@ -173,7 +133,7 @@ export async function constraintsReport(options: ConstraintsReportOptions = {},
173
133
  log(io);
174
134
 
175
135
  // 统计表
176
- log(io, chalk.bold('统计表(check 层):'));
136
+ log(io, chalk.bold('统计表:'));
177
137
  for (const s of report.stats) {
178
138
  log(io, ` ${renderStatsRow(s)}`);
179
139
  }
@@ -191,13 +151,6 @@ export async function constraintsReport(options: ConstraintsReportOptions = {},
191
151
  }
192
152
  log(io);
193
153
 
194
- // 注入清单
195
- log(io, chalk.bold(`当前生效 prompt 注入(${report.activePromptIds.length} 条):`));
196
- for (const id of report.activePromptIds) {
197
- log(io, ` ${id}`);
198
- }
199
- log(io);
200
-
201
154
  // 配置健康
202
155
  if (report.lint.unknownIds.length > 0) {
203
156
  log(io, chalk.yellow('⚠️ 配置健康:'));
@@ -207,14 +160,6 @@ export async function constraintsReport(options: ConstraintsReportOptions = {},
207
160
  log(io);
208
161
  }
209
162
 
210
- // 注入漂移(ADR-0001 决策 7:条目级差异 + 修复指引;--export 摘要不含本地漂移状态)
211
- log(io, chalk.bold('注入漂移:'));
212
- const drift = detectInjectionDrift(projectRoot);
213
- for (const line of renderInjectionDriftLines(drift)) {
214
- log(io, drift.hasDrift ? chalk.yellow(line) : line);
215
- }
216
- log(io);
217
-
218
163
  // --export
219
164
  if (options.export !== undefined && options.export !== false) {
220
165
  const version = getConstraintsMeta().version;