@dommaker/harness 1.4.0 → 1.6.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 (258) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +0 -2
  3. package/dist/cli/commands/check.d.ts.map +1 -1
  4. package/dist/cli/commands/check.js +28 -0
  5. package/dist/cli/commands/check.js.map +1 -1
  6. package/dist/cli/commands/definitions.d.ts.map +1 -1
  7. package/dist/cli/commands/definitions.js +1 -39
  8. package/dist/cli/commands/definitions.js.map +1 -1
  9. package/dist/cli/commands/knowledge.d.ts +0 -19
  10. package/dist/cli/commands/knowledge.d.ts.map +1 -1
  11. package/dist/cli/commands/knowledge.js +0 -105
  12. package/dist/cli/commands/knowledge.js.map +1 -1
  13. package/dist/cli/commands/passes-gate.d.ts +0 -2
  14. package/dist/cli/commands/passes-gate.d.ts.map +1 -1
  15. package/dist/cli/commands/passes-gate.js +0 -1
  16. package/dist/cli/commands/passes-gate.js.map +1 -1
  17. package/dist/cli/commands/performance.d.ts +0 -4
  18. package/dist/cli/commands/performance.d.ts.map +1 -1
  19. package/dist/cli/commands/performance.js +10 -20
  20. package/dist/cli/commands/performance.js.map +1 -1
  21. package/dist/cli/commands/report.d.ts +1 -1
  22. package/dist/cli/commands/report.d.ts.map +1 -1
  23. package/dist/cli/commands/report.js +2 -55
  24. package/dist/cli/commands/report.js.map +1 -1
  25. package/dist/cli/commands/status.d.ts.map +1 -1
  26. package/dist/cli/commands/status.js +4 -8
  27. package/dist/cli/commands/status.js.map +1 -1
  28. package/dist/context/index.d.ts +2 -5
  29. package/dist/context/index.d.ts.map +1 -1
  30. package/dist/context/index.js +2 -8
  31. package/dist/context/index.js.map +1 -1
  32. package/dist/context/token-budget.d.ts +0 -29
  33. package/dist/context/token-budget.d.ts.map +1 -1
  34. package/dist/context/token-budget.js +1 -65
  35. package/dist/context/token-budget.js.map +1 -1
  36. package/dist/context/types.d.ts +0 -1
  37. package/dist/context/types.d.ts.map +1 -1
  38. package/dist/context/types.js +0 -9
  39. package/dist/context/types.js.map +1 -1
  40. package/dist/core/constraints/checker.d.ts +14 -0
  41. package/dist/core/constraints/checker.d.ts.map +1 -1
  42. package/dist/core/constraints/checker.js +27 -5
  43. package/dist/core/constraints/checker.js.map +1 -1
  44. package/dist/core/constraints/checkers/capability-sync.d.ts +17 -6
  45. package/dist/core/constraints/checkers/capability-sync.d.ts.map +1 -1
  46. package/dist/core/constraints/checkers/capability-sync.js +48 -19
  47. package/dist/core/constraints/checkers/capability-sync.js.map +1 -1
  48. package/dist/core/constraints/checkers/docs-freshness.d.ts.map +1 -1
  49. package/dist/core/constraints/checkers/docs-freshness.js +15 -6
  50. package/dist/core/constraints/checkers/docs-freshness.js.map +1 -1
  51. package/dist/core/constraints/checkers/index.d.ts +2 -2
  52. package/dist/core/constraints/checkers/index.d.ts.map +1 -1
  53. package/dist/core/constraints/checkers/index.js +2 -1
  54. package/dist/core/constraints/checkers/index.js.map +1 -1
  55. package/dist/core/constraints/checkers/types.d.ts +41 -2
  56. package/dist/core/constraints/checkers/types.d.ts.map +1 -1
  57. package/dist/core/constraints/checkers/types.js +33 -0
  58. package/dist/core/constraints/checkers/types.js.map +1 -1
  59. package/dist/core/constraints/git-evidence.d.ts +6 -3
  60. package/dist/core/constraints/git-evidence.d.ts.map +1 -1
  61. package/dist/core/constraints/git-evidence.js +6 -3
  62. package/dist/core/constraints/git-evidence.js.map +1 -1
  63. package/dist/core/index.d.ts +1 -2
  64. package/dist/core/index.d.ts.map +1 -1
  65. package/dist/core/index.js +1 -9
  66. package/dist/core/index.js.map +1 -1
  67. package/dist/core/spec/validator.d.ts +2 -0
  68. package/dist/core/spec/validator.d.ts.map +1 -1
  69. package/dist/core/spec/validator.js +9 -11
  70. package/dist/core/spec/validator.js.map +1 -1
  71. package/dist/core/validators/index.d.ts +1 -1
  72. package/dist/core/validators/index.d.ts.map +1 -1
  73. package/dist/core/validators/passes-gate.d.ts +1 -15
  74. package/dist/core/validators/passes-gate.d.ts.map +1 -1
  75. package/dist/core/validators/passes-gate.js +0 -125
  76. package/dist/core/validators/passes-gate.js.map +1 -1
  77. package/dist/failure/index.d.ts +0 -1
  78. package/dist/failure/index.d.ts.map +1 -1
  79. package/dist/failure/index.js +1 -7
  80. package/dist/failure/index.js.map +1 -1
  81. package/dist/gates/checker-gate.d.ts +2 -1
  82. package/dist/gates/checker-gate.d.ts.map +1 -1
  83. package/dist/gates/checker-gate.js +10 -7
  84. package/dist/gates/checker-gate.js.map +1 -1
  85. package/dist/gates/definitions.d.ts.map +1 -1
  86. package/dist/gates/definitions.js +0 -4
  87. package/dist/gates/definitions.js.map +1 -1
  88. package/dist/gates/performance.d.ts +7 -22
  89. package/dist/gates/performance.d.ts.map +1 -1
  90. package/dist/gates/performance.js +7 -89
  91. package/dist/gates/performance.js.map +1 -1
  92. package/dist/gates/types.d.ts +2 -8
  93. package/dist/gates/types.d.ts.map +1 -1
  94. package/dist/index.d.ts +6 -8
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/index.js +4 -22
  97. package/dist/index.js.map +1 -1
  98. package/dist/knowledge/index.d.ts +0 -1
  99. package/dist/knowledge/index.d.ts.map +1 -1
  100. package/dist/knowledge/index.js +1 -3
  101. package/dist/knowledge/index.js.map +1 -1
  102. package/dist/monitoring/trace-analyzer.d.ts +25 -10
  103. package/dist/monitoring/trace-analyzer.d.ts.map +1 -1
  104. package/dist/monitoring/trace-analyzer.js +147 -116
  105. package/dist/monitoring/trace-analyzer.js.map +1 -1
  106. package/dist/types/constraint.d.ts +8 -0
  107. package/dist/types/constraint.d.ts.map +1 -1
  108. package/dist/types/constraint.js +6 -1
  109. package/dist/types/constraint.js.map +1 -1
  110. package/dist/types/passes-gate.d.ts +0 -19
  111. package/dist/types/passes-gate.d.ts.map +1 -1
  112. package/dist/types/trace.d.ts +9 -0
  113. package/dist/types/trace.d.ts.map +1 -1
  114. package/package.json +1 -1
  115. package/src/CONTEXT.md +1 -0
  116. package/src/__tests__/passes-gate-check.test.ts +20 -4
  117. package/src/__tests__/passes-gate.test.ts +18 -119
  118. package/src/__tests__/performance-gate.test.ts +3 -11
  119. package/src/__tests__/public-exports.test.ts +46 -16
  120. package/src/__tests__/trace-analyzer.test.ts +52 -2
  121. package/src/cli/commands/CONTEXT.md +5 -4
  122. package/src/cli/commands/__tests__/bin-exit-mapping.test.ts +6 -0
  123. package/src/cli/commands/__tests__/check.test.ts +74 -0
  124. package/src/cli/commands/__tests__/passes-gate-dead-options.test.ts +70 -0
  125. package/src/cli/commands/__tests__/passes-gate.test.ts +7 -3
  126. package/src/cli/commands/__tests__/performance.test.ts +5 -16
  127. package/src/cli/commands/__tests__/project-path-convention.test.ts +85 -23
  128. package/src/cli/commands/__tests__/registry.test.ts +52 -3
  129. package/src/cli/commands/__tests__/report-extra.test.ts +0 -19
  130. package/src/cli/commands/__tests__/report-false-green.test.ts +46 -0
  131. package/src/cli/commands/__tests__/report.test.ts +0 -20
  132. package/src/cli/commands/__tests__/status-analysis-wiring.test.ts +68 -0
  133. package/src/cli/commands/__tests__/status-extra.test.ts +63 -116
  134. package/src/cli/commands/__tests__/status.test.ts +66 -148
  135. package/src/cli/commands/check.ts +39 -1
  136. package/src/cli/commands/definitions.ts +1 -39
  137. package/src/cli/commands/knowledge.ts +0 -119
  138. package/src/cli/commands/passes-gate.ts +0 -3
  139. package/src/cli/commands/performance.ts +13 -27
  140. package/src/cli/commands/report.ts +3 -61
  141. package/src/cli/commands/status.ts +5 -10
  142. package/src/context/CONTEXT.md +2 -3
  143. package/src/context/__tests__/token-budget.test.ts +1 -81
  144. package/src/context/index.ts +2 -7
  145. package/src/context/token-budget.ts +0 -73
  146. package/src/context/types.ts +0 -9
  147. package/src/core/CONTEXT.md +6 -6
  148. package/src/core/constraints/__tests__/collect-constraints.test.ts +66 -0
  149. package/src/core/constraints/checker.ts +41 -6
  150. package/src/core/constraints/checkers/__tests__/capability-sync.test.ts +90 -31
  151. package/src/core/constraints/checkers/__tests__/check-outcome.test.ts +176 -0
  152. package/src/core/constraints/checkers/__tests__/docs-freshness.test.ts +18 -9
  153. package/src/core/constraints/checkers/__tests__/three-state-consistency.test.ts +12 -4
  154. package/src/core/constraints/checkers/capability-sync.ts +56 -18
  155. package/src/core/constraints/checkers/docs-freshness.ts +18 -5
  156. package/src/core/constraints/checkers/index.ts +9 -2
  157. package/src/core/constraints/checkers/types.ts +58 -2
  158. package/src/core/constraints/git-evidence.ts +6 -3
  159. package/src/core/index.ts +0 -11
  160. package/src/core/spec/__tests__/validator.test.ts +24 -0
  161. package/src/core/spec/validator.ts +9 -10
  162. package/src/core/validators/__tests__/passes-gate.test.ts +2 -9
  163. package/src/core/validators/index.ts +0 -1
  164. package/src/core/validators/passes-gate.ts +1 -149
  165. package/src/failure/CONTEXT.md +8 -6
  166. package/src/failure/index.ts +0 -10
  167. package/src/gates/CONTEXT.md +4 -3
  168. package/src/gates/__tests__/checker-gate.test.ts +24 -0
  169. package/src/gates/__tests__/performance.test.ts +6 -74
  170. package/src/gates/checker-gate.ts +11 -15
  171. package/src/gates/definitions.ts +0 -4
  172. package/src/gates/performance.ts +9 -111
  173. package/src/gates/types.ts +2 -8
  174. package/src/index.ts +1 -36
  175. package/src/knowledge/CONTEXT.md +1 -2
  176. package/src/knowledge/index.ts +0 -1
  177. package/src/monitoring/CONTEXT.md +2 -2
  178. package/src/monitoring/trace-analyzer.ts +160 -126
  179. package/src/types/constraint.ts +16 -2
  180. package/src/types/passes-gate.ts +0 -26
  181. package/src/types/trace.ts +10 -0
  182. package/src/utils/__tests__/jsonl-skip-disposition.test.ts +0 -1
  183. package/dist/cli/commands/analyze-sessions.d.ts +0 -20
  184. package/dist/cli/commands/analyze-sessions.d.ts.map +0 -1
  185. package/dist/cli/commands/analyze-sessions.js +0 -290
  186. package/dist/cli/commands/analyze-sessions.js.map +0 -1
  187. package/dist/cli/commands/update-user-model.d.ts +0 -25
  188. package/dist/cli/commands/update-user-model.d.ts.map +0 -1
  189. package/dist/cli/commands/update-user-model.js +0 -397
  190. package/dist/cli/commands/update-user-model.js.map +0 -1
  191. package/dist/cli/session-mining/corrections.d.ts +0 -17
  192. package/dist/cli/session-mining/corrections.d.ts.map +0 -1
  193. package/dist/cli/session-mining/corrections.js +0 -58
  194. package/dist/cli/session-mining/corrections.js.map +0 -1
  195. package/dist/cli/session-mining/index.d.ts +0 -13
  196. package/dist/cli/session-mining/index.d.ts.map +0 -1
  197. package/dist/cli/session-mining/index.js +0 -29
  198. package/dist/cli/session-mining/index.js.map +0 -1
  199. package/dist/cli/session-mining/text.d.ts +0 -31
  200. package/dist/cli/session-mining/text.d.ts.map +0 -1
  201. package/dist/cli/session-mining/text.js +0 -126
  202. package/dist/cli/session-mining/text.js.map +0 -1
  203. package/dist/cli/session-mining/transcript.d.ts +0 -34
  204. package/dist/cli/session-mining/transcript.d.ts.map +0 -1
  205. package/dist/cli/session-mining/transcript.js +0 -130
  206. package/dist/cli/session-mining/transcript.js.map +0 -1
  207. package/dist/context/compaction.d.ts +0 -57
  208. package/dist/context/compaction.d.ts.map +0 -1
  209. package/dist/context/compaction.js +0 -165
  210. package/dist/context/compaction.js.map +0 -1
  211. package/dist/core/session/clean-state.d.ts +0 -17
  212. package/dist/core/session/clean-state.d.ts.map +0 -1
  213. package/dist/core/session/clean-state.js +0 -192
  214. package/dist/core/session/clean-state.js.map +0 -1
  215. package/dist/core/session/index.d.ts +0 -6
  216. package/dist/core/session/index.d.ts.map +0 -1
  217. package/dist/core/session/index.js +0 -15
  218. package/dist/core/session/index.js.map +0 -1
  219. package/dist/core/session/startup.d.ts +0 -47
  220. package/dist/core/session/startup.d.ts.map +0 -1
  221. package/dist/core/session/startup.js +0 -263
  222. package/dist/core/session/startup.js.map +0 -1
  223. package/dist/failure/constraint-handler.d.ts +0 -83
  224. package/dist/failure/constraint-handler.d.ts.map +0 -1
  225. package/dist/failure/constraint-handler.js +0 -138
  226. package/dist/failure/constraint-handler.js.map +0 -1
  227. package/dist/knowledge/lifecycle-hooks.d.ts +0 -62
  228. package/dist/knowledge/lifecycle-hooks.d.ts.map +0 -1
  229. package/dist/knowledge/lifecycle-hooks.js +0 -143
  230. package/dist/knowledge/lifecycle-hooks.js.map +0 -1
  231. package/dist/types/session.d.ts +0 -113
  232. package/dist/types/session.d.ts.map +0 -1
  233. package/dist/types/session.js +0 -6
  234. package/dist/types/session.js.map +0 -1
  235. package/src/__tests__/clean-state-extra.test.ts +0 -301
  236. package/src/__tests__/clean-state.test.ts +0 -169
  237. package/src/__tests__/constraint-handler.test.ts +0 -132
  238. package/src/__tests__/passes-gate-extra.test.ts +0 -93
  239. package/src/__tests__/session-startup.test.ts +0 -334
  240. package/src/cli/commands/__tests__/analyze-sessions.test.ts +0 -184
  241. package/src/cli/commands/__tests__/update-user-model.test.ts +0 -234
  242. package/src/cli/commands/analyze-sessions.ts +0 -335
  243. package/src/cli/commands/update-user-model.ts +0 -461
  244. package/src/cli/session-mining/__tests__/transcript.test.ts +0 -118
  245. package/src/cli/session-mining/corrections.ts +0 -56
  246. package/src/cli/session-mining/index.ts +0 -13
  247. package/src/cli/session-mining/text.ts +0 -117
  248. package/src/cli/session-mining/transcript.ts +0 -125
  249. package/src/context/__tests__/compaction.test.ts +0 -169
  250. package/src/context/compaction.ts +0 -201
  251. package/src/core/session/__tests__/startup.test.ts +0 -281
  252. package/src/core/session/clean-state.ts +0 -178
  253. package/src/core/session/index.ts +0 -15
  254. package/src/core/session/startup.ts +0 -253
  255. package/src/failure/constraint-handler.ts +0 -171
  256. package/src/knowledge/__tests__/lifecycle-hooks.test.ts +0 -140
  257. package/src/knowledge/lifecycle-hooks.ts +0 -202
  258. package/src/types/session.ts +0 -132
@@ -133,7 +133,6 @@ export interface GateContext {
133
133
 
134
134
  // Performance Gate
135
135
  performanceThresholds?: PerformanceThresholds;
136
- benchmarkCommand?: string;
137
136
 
138
137
  // Contract Gate
139
138
  oldContractPath?: string;
@@ -151,14 +150,12 @@ export interface GateContext {
151
150
  }
152
151
 
153
152
  /**
154
- * 性能阈值
153
+ * 性能阈值(架构评审候选2:只留有真实现的维度——coverage 走 json-summary、
154
+ * bundleSize 走 dist 目录测量;responseTime/memoryUsage/throughput 无真实现已删)
155
155
  */
156
156
  export interface PerformanceThresholds {
157
- maxResponseTime?: number; // ms
158
- maxMemoryUsage?: number; // MB
159
157
  minCoverage?: number; // %
160
158
  maxBundleSize?: number; // KB
161
- minThroughput?: number; // req/s
162
159
  }
163
160
 
164
161
  /**
@@ -187,10 +184,7 @@ export interface SecurityGateConfig {
187
184
  */
188
185
  export interface PerformanceGateConfig {
189
186
  enabled: boolean;
190
- benchmarkCommand?: string;
191
187
  thresholds: PerformanceThresholds;
192
- warmupRuns: number;
193
- measureRuns: number;
194
188
  }
195
189
 
196
190
  /**
package/src/index.ts CHANGED
@@ -100,7 +100,6 @@ export {
100
100
  export type { CSOIssue, CSOValidationResult } from './core/validators';
101
101
  export type {
102
102
  PassesGateConfig,
103
- PassesGateResult,
104
103
  PassesGateCheckResult,
105
104
  PassesGateViolation,
106
105
  TestResult,
@@ -113,29 +112,6 @@ export type {
113
112
  WorkflowMeta,
114
113
  } from './types/cso';
115
114
 
116
- // ========================================
117
- // 会话启动 / 净室状态
118
- // ========================================
119
- export {
120
- SessionStartup,
121
- createSessionStartup,
122
- DEFAULT_CODE_CHECKPOINTS,
123
- MINIMAL_CHECKPOINTS,
124
- CleanStateManager,
125
- createCleanStateManager,
126
- } from './core/session';
127
- export type {
128
- StartupCheckpoints,
129
- StartupCheckpointType,
130
- StartupCheckpointResult,
131
- CleanStateConfig,
132
- CleanStateResult,
133
- DetectedBug,
134
- TaskListJson,
135
- TaskStepStatus,
136
- SessionInfo,
137
- } from './types/session';
138
-
139
115
  // ========================================
140
116
  // Spec 验证(已接线的 spec 故事:validator + SpecAcceptanceGate)
141
117
  // ========================================
@@ -240,10 +216,6 @@ export {
240
216
  getFailureLevel,
241
217
  FailureRecorder,
242
218
  createFailureRecorder,
243
- ConstraintViolationHandler,
244
- executeWithBlock,
245
- executeWithCollect,
246
- executeWithSafeBoolean,
247
219
  } from './failure';
248
220
  export type {
249
221
  FailureRecord,
@@ -251,26 +223,20 @@ export type {
251
223
  ClassificationResult,
252
224
  ErrorClassifierConfig,
253
225
  FailureRecorderConfig,
254
- ViolationStrategy,
255
- ViolationHandlingResult,
256
226
  } from './failure';
257
227
 
258
228
  // ========================================
259
- // 上下文管理(Token 预算 + 会话压缩 + 知识注入)
229
+ // 上下文管理(Token 预算 + 会话管理 + 知识注入)
260
230
  // ========================================
261
231
  export {
262
- AdaptiveTokenBudget,
263
232
  TokenBudget,
264
233
  TokenEstimator,
265
- DEFAULT_COMPACTION_CONFIG,
266
- SessionCompaction,
267
234
  SessionManager,
268
235
  KnowledgeInjector,
269
236
  } from './context';
270
237
  export type {
271
238
  CompactionConfig,
272
239
  CompactionLevel,
273
- CompactionResult,
274
240
  ContextSource,
275
241
  ContextSourceType,
276
242
  ContextUsageSnapshot,
@@ -296,7 +262,6 @@ export {
296
262
  KnowledgeLinter,
297
263
  ColdStartImporter,
298
264
  KnowledgeHealthScorer,
299
- KnowledgeLifecycleHooks,
300
265
  KnowledgeAudit,
301
266
  migrateKnowledgeEntries,
302
267
  extractCodeStructure,
@@ -29,12 +29,11 @@
29
29
  - `KnowledgeLinter` — 知识质量检查(完整性/一致性/时效性)
30
30
  - `ColdStartImporter` — 冷启动知识导入
31
31
  - `KnowledgeHealthScorer` — 知识健康评分(doctor.ts)
32
- - `KnowledgeLifecycleHooks` — 生命周期 hook
33
32
 
34
33
  ## 依赖关系
35
34
  - 依赖 `src/types/` 知识相关类型
36
35
  - 依赖 `src/utils/frontmatter` — markdown frontmatter 解析/序列化的唯一正本(harness#89:store、migration、index-generator、ingest 共用同一套语法判定,不再各写正则)
37
- - 依赖 `src/context/types`(ContextUsageSnapshot 等类型;不依赖 monitoring——知识健康评分由本目录 doctor.ts 的 KnowledgeHealthScorer 承载)
36
+ - 不依赖 `src/context/`(原 `lifecycle-hooks.ts` 是唯一 import `context/types` 的文件,已随 ADR-0022 删除),也不依赖 monitoring——知识健康评分由本目录 doctor.ts 的 KnowledgeHealthScorer 承载
38
37
  - 被 `src/cli/commands/knowledge.ts` CLI 消费(含 `migrate` 子命令)
39
38
 
40
39
  ## 约定
@@ -15,7 +15,6 @@ export { ReferenceTracker } from './reference-tracker';
15
15
  export { KnowledgeLinter } from './lint';
16
16
  export { ColdStartImporter } from './import';
17
17
  export { KnowledgeHealthScorer } from './doctor';
18
- export { KnowledgeLifecycleHooks } from './lifecycle-hooks';
19
18
  export { KnowledgeAudit } from './audit';
20
19
  export type { AuditRuleName, AuditAction, AuditIssue, AuditReport, AuditOptions } from './audit';
21
20
  export { migrateKnowledgeEntries } from './migration';
@@ -5,12 +5,12 @@
5
5
 
6
6
  ## 核心导出
7
7
  - `TraceCollector` — 执行追踪收集(append-only JSONL,`.harness/logs/traces.log`)。读入口两个:`readReport(filter?)` 报告入口(返回 `{ traces, skippedLines }`,harness#100)与 `read()/readRecent()/readByConstraint()` 兼容包装(#82 裁决 4 冻结的签名,丢计数)
8
- - `TraceAnalyzer` — 追踪统计分析 + 异常检测(共用 analyzer-base 纯函数)。`analyzeRecentReport(hours)` 带坏行数,`analyzeRecent()/analyzeConstraint()` 仍返回 `TraceSummary[]`
8
+ - `TraceAnalyzer` — 追踪统计分析 + 异常检测(共用 analyzer-base 纯函数)。`analyzeRecentReport(hours)` 带坏行数,`analyzeRecent()/analyzeConstraint()` 仍返回 `TraceSummary[]`。**ADR-0020**:`summarize`/`detectAnomalies` 的判定本体是 trace-analyzer.ts 的模块级纯函数 `summarizeTraces(traces)` / `detectTraceAnomalies(summaries, config?)`(阈值经参数传入,不再是实例状态),类壳只转发——类壳是 studio 的运行时消费面(`new TraceAnalyzer(c)` + `analyzeRecentReport`/`detectAnomalies`,签名逐字不动),已持有数据的消费端直调纯函数。两函数**不进包根导出**(ADR-0003 零扩张),仓内经相对 import
9
9
  - `ContextTracker` — LLM 调用上下文使用快照记录
10
10
 
11
11
  ## 依赖关系
12
12
  - 依赖 `src/types/trace` ExecutionTrace 类型
13
- - 消费者:`src/cli/commands/{check,report}` 与 `src/hooks/bootstrap`——组合根经 `getTraceCollector()` 把收集器注入 `ConstraintChecker` 构造参数(harness#88);`status` 另按 projectPath 自建收集器/分析器
13
+ - 消费者:`src/cli/commands/{check,report}` 与 `src/hooks/bootstrap`——组合根经 `getTraceCollector()` 把收集器注入 `ConstraintChecker` 构造参数(harness#88);`status` projectPath 直读读链正本后**直调模块级纯函数**,不构造 collector/类壳(ADR-0020:collector 构造函数的 mkdir 副作用就此退出该路径)
14
14
  - core 不再依赖本模块(方向由 eslint no-restricted-imports 锁死,`src/__tests__/layering.test.ts` 守卫)
15
15
 
16
16
  ## 约定
@@ -7,6 +7,11 @@
7
7
  * - 统计汇总(每小时自动执行)
8
8
  * - 异常检测(每日检查)
9
9
  * - 趋势分析(对比上一周期)
10
+ *
11
+ * 形状(ADR-0020):`summarize`/`detectAnomalies` 的判定本体是模块级纯函数
12
+ * (`summarizeTraces`/`detectTraceAnomalies`),`TraceAnalyzer` 类壳转发过去——
13
+ * 类壳是 studio 的运行时消费面,纯函数是已持有数据、不需要 collector 的消费端
14
+ * (`status`)的入口。两个纯函数不进包根导出(ADR-0003 零扩张)。
10
15
  */
11
16
 
12
17
  import type {
@@ -36,6 +41,153 @@ const DEFAULT_CONFIG: TraceAnalyzerConfig = {
36
41
  },
37
42
  };
38
43
 
44
+ /**
45
+ * 计算趋势(`summarizeTraces` 的模块内助手)
46
+ *
47
+ * 对比前半段和后半段的通过率
48
+ */
49
+ function calculateTrend(traces: ExecutionTrace[]): 'stable' | 'rising' | 'falling' {
50
+ if (traces.length < MIN_TREND_SAMPLES) {
51
+ return 'stable';
52
+ }
53
+
54
+ // 分成前后两半(按时间排序)
55
+ const [firstHalf, secondHalf] = splitByTime(traces);
56
+
57
+ // 计算前半段和后半段的通过率
58
+ const firstPassRate = calcPassRate(firstHalf);
59
+ const secondPassRate = calcPassRate(secondHalf);
60
+
61
+ // 计算变化
62
+ const delta = secondPassRate - firstPassRate;
63
+
64
+ // 判断趋势(变化 > 5% 才算显著)
65
+ if (delta > 0.05) {
66
+ return 'rising';
67
+ } else if (delta < -0.05) {
68
+ return 'falling';
69
+ } else {
70
+ return 'stable';
71
+ }
72
+ }
73
+
74
+ /**
75
+ * 计算通过率(skip 未评估,不计入分母)
76
+ */
77
+ function calcPassRate(traces: ExecutionTrace[]): number {
78
+ const evaluated = traces.filter(t => t.result !== 'skip');
79
+ if (evaluated.length === 0) return 0;
80
+ const passCount = evaluated.filter(t => t.result === 'pass').length;
81
+ return passCount / evaluated.length;
82
+ }
83
+
84
+ /**
85
+ * 生成统计汇总
86
+ *
87
+ * 纯计算,零 Token 成本。判定住在这里,`TraceAnalyzer.summarize()` 只是转发(ADR-0020)——
88
+ * 只要数据的消费端(`status`)直调本函数,不必为它构造带 mkdir 副作用的 collector。
89
+ */
90
+ export function summarizeTraces(traces: ExecutionTrace[]): TraceSummary[] {
91
+ // 按约束 ID 分组
92
+ const grouped = groupByKey(traces, t => t.constraintId);
93
+
94
+ const summaries: TraceSummary[] = [];
95
+
96
+ for (const [constraintId, group] of grouped) {
97
+ // 提取层级(从第一条 trace)
98
+ const level = group[0].level;
99
+
100
+ // 计算时间范围
101
+ const timeRange = timeRangeOf(group.map(t => t.timestamp));
102
+
103
+ // 单次遍历计算核心统计(skip 单独计数,不计入 pass/fail 率分母,ADR-0001)
104
+ const totalChecks = group.length;
105
+ let passCount = 0, failCount = 0, ignoreCount = 0, skipCount = 0;
106
+ for (const t of group) {
107
+ if (t.result === 'pass') passCount++;
108
+ else if (t.result === 'fail') failCount++;
109
+ else if (t.result === 'skip') skipCount++;
110
+ if (t.userAction === 'ignore') ignoreCount++;
111
+ }
112
+
113
+ // 计算比率(分母 = 实际评估次数,skip 未评估不计入)
114
+ const evaluatedChecks = totalChecks - skipCount;
115
+ const passRate = evaluatedChecks > 0 ? passCount / evaluatedChecks : 0;
116
+ const failRate = evaluatedChecks > 0 ? failCount / evaluatedChecks : 0;
117
+
118
+ // 计算趋势
119
+ const recentTrend = calculateTrend(group);
120
+
121
+ summaries.push({
122
+ constraintId,
123
+ level,
124
+ timeRange,
125
+ totalChecks,
126
+ passCount,
127
+ failCount,
128
+ skipCount,
129
+ ignoreCount,
130
+ passRate,
131
+ failRate,
132
+ recentTrend,
133
+ });
134
+ }
135
+
136
+ return summaries;
137
+ }
138
+
139
+ /**
140
+ * 检测异常
141
+ *
142
+ * 基于阈值检测异常模式。阈值来自参数而非实例状态(ADR-0020):省略 `config` 时
143
+ * 与类壳同一默认口径(`{ ...DEFAULT_CONFIG, ...config }`)。
144
+ */
145
+ export function detectTraceAnomalies(
146
+ summaries: TraceSummary[],
147
+ config?: Partial<TraceAnalyzerConfig>
148
+ ): TraceAnomaly[] {
149
+ const anomalies: TraceAnomaly[] = [];
150
+ const thresholds = { ...DEFAULT_CONFIG, ...config }.thresholds!;
151
+
152
+ for (const summary of summaries) {
153
+ // 检测失败率上升
154
+ if (summary.failRate > thresholds.failRate! && summary.recentTrend === 'rising') {
155
+ anomalies.push({
156
+ type: 'rising_fail_rate',
157
+ constraintId: summary.constraintId,
158
+ level: summary.level,
159
+ message: `约束 ${summary.constraintId} 失败率 ${Math.round(summary.failRate * 100)}% 且趋势上升`,
160
+ data: {
161
+ currentRate: summary.failRate,
162
+ threshold: thresholds.failRate!,
163
+ trend: 'rising',
164
+ },
165
+ detectedAt: Date.now(),
166
+ suggestedAction: 'diagnose',
167
+ });
168
+ }
169
+
170
+ // 检测低通过率
171
+ if (summary.passRate < 0.3) {
172
+ anomalies.push({
173
+ type: 'low_pass_rate',
174
+ constraintId: summary.constraintId,
175
+ level: summary.level,
176
+ message: `约束 ${summary.constraintId} 通过率 ${Math.round(summary.passRate * 100)}%,低于 30%`,
177
+ data: {
178
+ currentRate: summary.passRate,
179
+ threshold: 0.3,
180
+ trend: summary.recentTrend,
181
+ },
182
+ detectedAt: Date.now(),
183
+ suggestedAction: 'adjust_threshold',
184
+ });
185
+ }
186
+ }
187
+
188
+ return anomalies;
189
+ }
190
+
39
191
  /**
40
192
  * Trace 分析器
41
193
  *
@@ -59,54 +211,12 @@ export class TraceAnalyzer {
59
211
  * 生成统计汇总
60
212
  *
61
213
  * 纯计算,零 Token 成本
214
+ *
215
+ * ADR-0020:判定本体在模块级 `summarizeTraces()`,此处只是类壳转发
216
+ * (studio 经类消费的面逐字不动)。
62
217
  */
63
218
  summarize(traces: ExecutionTrace[]): TraceSummary[] {
64
- // 按约束 ID 分组
65
- const grouped = groupByKey(traces, t => t.constraintId);
66
-
67
- const summaries: TraceSummary[] = [];
68
-
69
- for (const [constraintId, group] of grouped) {
70
- // 提取层级(从第一条 trace)
71
- const level = group[0].level;
72
-
73
- // 计算时间范围
74
- const timeRange = timeRangeOf(group.map(t => t.timestamp));
75
-
76
- // 单次遍历计算核心统计(skip 单独计数,不计入 pass/fail 率分母,ADR-0001)
77
- const totalChecks = group.length;
78
- let passCount = 0, failCount = 0, ignoreCount = 0, skipCount = 0;
79
- for (const t of group) {
80
- if (t.result === 'pass') passCount++;
81
- else if (t.result === 'fail') failCount++;
82
- else if (t.result === 'skip') skipCount++;
83
- if (t.userAction === 'ignore') ignoreCount++;
84
- }
85
-
86
- // 计算比率(分母 = 实际评估次数,skip 未评估不计入)
87
- const evaluatedChecks = totalChecks - skipCount;
88
- const passRate = evaluatedChecks > 0 ? passCount / evaluatedChecks : 0;
89
- const failRate = evaluatedChecks > 0 ? failCount / evaluatedChecks : 0;
90
-
91
- // 计算趋势
92
- const recentTrend = this.calculateTrend(group);
93
-
94
- summaries.push({
95
- constraintId,
96
- level,
97
- timeRange,
98
- totalChecks,
99
- passCount,
100
- failCount,
101
- skipCount,
102
- ignoreCount,
103
- passRate,
104
- failRate,
105
- recentTrend,
106
- });
107
- }
108
-
109
- return summaries;
219
+ return summarizeTraces(traces);
110
220
  }
111
221
 
112
222
  /**
@@ -148,48 +258,12 @@ export class TraceAnalyzer {
148
258
  * 检测异常
149
259
  *
150
260
  * 基于阈值检测异常模式
261
+ *
262
+ * ADR-0020:判定本体在模块级 `detectTraceAnomalies()`(阈值经参数传入),
263
+ * 此处只是类壳转发。
151
264
  */
152
265
  detectAnomalies(summaries: TraceSummary[]): TraceAnomaly[] {
153
- const anomalies: TraceAnomaly[] = [];
154
- const thresholds = this.config.thresholds!;
155
-
156
- for (const summary of summaries) {
157
- // 检测失败率上升
158
- if (summary.failRate > thresholds.failRate! && summary.recentTrend === 'rising') {
159
- anomalies.push({
160
- type: 'rising_fail_rate',
161
- constraintId: summary.constraintId,
162
- level: summary.level,
163
- message: `约束 ${summary.constraintId} 失败率 ${Math.round(summary.failRate * 100)}% 且趋势上升`,
164
- data: {
165
- currentRate: summary.failRate,
166
- threshold: thresholds.failRate!,
167
- trend: 'rising',
168
- },
169
- detectedAt: Date.now(),
170
- suggestedAction: 'diagnose',
171
- });
172
- }
173
-
174
- // 检测低通过率
175
- if (summary.passRate < 0.3) {
176
- anomalies.push({
177
- type: 'low_pass_rate',
178
- constraintId: summary.constraintId,
179
- level: summary.level,
180
- message: `约束 ${summary.constraintId} 通过率 ${Math.round(summary.passRate * 100)}%,低于 30%`,
181
- data: {
182
- currentRate: summary.passRate,
183
- threshold: 0.3,
184
- trend: summary.recentTrend,
185
- },
186
- detectedAt: Date.now(),
187
- suggestedAction: 'adjust_threshold',
188
- });
189
- }
190
- }
191
-
192
- return anomalies;
266
+ return detectTraceAnomalies(summaries, this.config);
193
267
  }
194
268
 
195
269
  /**
@@ -219,46 +293,6 @@ export class TraceAnalyzer {
219
293
  });
220
294
  }
221
295
 
222
- /**
223
- * 计算趋势
224
- *
225
- * 对比前半段和后半段的通过率
226
- */
227
- private calculateTrend(traces: ExecutionTrace[]): 'stable' | 'rising' | 'falling' {
228
- if (traces.length < MIN_TREND_SAMPLES) {
229
- return 'stable';
230
- }
231
-
232
- // 分成前后两半(按时间排序)
233
- const [firstHalf, secondHalf] = splitByTime(traces);
234
-
235
- // 计算前半段和后半段的通过率
236
- const firstPassRate = this.calcPassRate(firstHalf);
237
- const secondPassRate = this.calcPassRate(secondHalf);
238
-
239
- // 计算变化
240
- const delta = secondPassRate - firstPassRate;
241
-
242
- // 判断趋势(变化 > 5% 才算显著)
243
- if (delta > 0.05) {
244
- return 'rising';
245
- } else if (delta < -0.05) {
246
- return 'falling';
247
- } else {
248
- return 'stable';
249
- }
250
- }
251
-
252
- /**
253
- * 计算通过率(skip 未评估,不计入分母)
254
- */
255
- private calcPassRate(traces: ExecutionTrace[]): number {
256
- const evaluated = traces.filter(t => t.result !== 'skip');
257
- if (evaluated.length === 0) return 0;
258
- const passCount = evaluated.filter(t => t.result === 'pass').length;
259
- return passCount / evaluated.length;
260
- }
261
-
262
296
  /**
263
297
  * 保存汇总结果
264
298
  */
@@ -108,7 +108,16 @@ export interface ConstraintResult {
108
108
 
109
109
  /** 消息 */
110
110
  message?: string;
111
-
111
+
112
+ /**
113
+ * 证据行(harness#119)
114
+ *
115
+ * checker 经 CheckDetail 返回的具体判定依据(如未登记的文件路径)。
116
+ * 违规时随 message 一并展示;满足但非空时为「提示」(不进 pass/fail 统计)。
117
+ * skip 恒为空——未评估不得留下证据行。
118
+ */
119
+ evidence?: string[];
120
+
112
121
  /** 建议操作 */
113
122
  requiredAction?: string;
114
123
 
@@ -194,7 +203,12 @@ export class ConstraintViolationError extends Error {
194
203
  public readonly result: ConstraintResult;
195
204
 
196
205
  constructor(result: ConstraintResult) {
197
- super(result.message || 'Constraint violation');
206
+ // 铁律违规在 checkConstraints 处直接 throw,CLI 的结构化输出块走不到这里,
207
+ // error.message 是判定证据唯一的外溢面(harness#119)
208
+ const detail = result.evidence?.length
209
+ ? `:\n${result.evidence.map((line) => ` - ${line}`).join('\n')}`
210
+ : '';
211
+ super(`${result.message || 'Constraint violation'}${detail}`);
198
212
  this.name = 'ConstraintViolationError';
199
213
  this.result = result;
200
214
  }
@@ -24,12 +24,6 @@ export interface PassesGateConfig {
24
24
  * 不赦免非零退出码(判定依据收在 core/validators/test-output.ts 的 judgeTestRun,ADR-0014)
25
25
  */
26
26
  allowPartialPass?: boolean;
27
-
28
- /** 最大重试次数 */
29
- maxRetries?: number;
30
-
31
- /** 重试延迟(毫秒) */
32
- retryDelay?: number;
33
27
  }
34
28
 
35
29
  /**
@@ -61,26 +55,6 @@ export interface TaskTestResult {
61
55
  evidence?: string;
62
56
  }
63
57
 
64
- /**
65
- * 测试门控结果
66
- */
67
- export interface PassesGateResult {
68
- /** 任务 ID */
69
- taskId: string;
70
-
71
- /** 是否允许设置 */
72
- allowed: boolean;
73
-
74
- /** 测试结果 */
75
- testResult?: TaskTestResult;
76
-
77
- /** 尝试次数 */
78
- attempts: number;
79
-
80
- /** 错误信息 */
81
- error?: string;
82
- }
83
-
84
58
  /**
85
59
  * 动态任务(用于 passes-gate)
86
60
  */
@@ -19,6 +19,8 @@ export const DEFAULT_TRACE_FILE = '.harness/logs/traces.log';
19
19
  * - 只记录核心字段(零 Token)
20
20
  * - 不记录代码片段(需要时从 git diff 获取)
21
21
  * - 不记录决策路径(需要时从 execution logs 获取)
22
+ * - 例外(harness#119):判定证据允许记录——路径级依据不是代码片段,
23
+ * 而没有它,一条恒红的约束在统计侧根本无法回答「红在哪」
22
24
  */
23
25
  export interface ExecutionTrace {
24
26
  // ========================================
@@ -53,6 +55,14 @@ export interface ExecutionTrace {
53
55
  /** 会话 ID(用于追踪同一会话的多次检查) */
54
56
  sessionId?: string;
55
57
 
58
+ /**
59
+ * 判定证据行(harness#119)
60
+ *
61
+ * 只落 checker 给出的路径级依据(如未登记文件清单),由 checker 截断条数;
62
+ * 不落 pass 结果的空数组,避免无信息记录膨胀 JSONL。
63
+ */
64
+ evidence?: string[];
65
+
56
66
  // ========================================
57
67
  // 用户响应(可选,用于诊断)
58
68
  // ========================================
@@ -42,7 +42,6 @@ const POLICY_WINDOW_LINES = 6;
42
42
  */
43
43
  const EXPECTED_SKIP_READ_SITES: Record<string, number> = {
44
44
  'src/cli/commands/status.ts': 1,
45
- 'src/cli/session-mining/transcript.ts': 1,
46
45
  'src/context/session-manager.ts': 2,
47
46
  'src/core/constraints/context-builder.ts': 2,
48
47
  'src/core/constraints/usage-report.ts': 1,
@@ -1,20 +0,0 @@
1
- /**
2
- * harness analyze-sessions — 对话模式发现引擎
3
- *
4
- * 扫描 transcript 文件,不预设关键词,挖掘:
5
- * 1. 纠正信号(用户反复指出的问题)
6
- * 2. 高频 N-gram(跨会话重复出现的概念)
7
- * 3. 规则缺口(高频模式未被现有 memory 覆盖)
8
- *
9
- * 输出候选规则建议,供用户审核后写入 memory。
10
- *
11
- * 工单 19-C:transcript 解析/纠正模式/分词相似度收敛至 cli/session-mining/。
12
- */
13
- import { type CommandIO, type CommandResult } from '../command-contract';
14
- export interface AnalyzeSessionsOptions {
15
- days?: number;
16
- projectPath?: string;
17
- json?: boolean;
18
- }
19
- export declare function analyzeSessions(options: AnalyzeSessionsOptions, io?: CommandIO): Promise<CommandResult>;
20
- //# sourceMappingURL=analyze-sessions.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"analyze-sessions.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/analyze-sessions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAmBH,OAAO,EAAkB,KAAK,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzF,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAmBD,wBAAsB,eAAe,CAAC,OAAO,EAAE,sBAAsB,EAAE,EAAE,GAAE,SAAqB,GAAG,OAAO,CAAC,aAAa,CAAC,CA0CxH"}