@dommaker/harness 1.5.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 (208) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +0 -2
  3. package/dist/cli/commands/definitions.d.ts.map +1 -1
  4. package/dist/cli/commands/definitions.js +1 -32
  5. package/dist/cli/commands/definitions.js.map +1 -1
  6. package/dist/cli/commands/passes-gate.d.ts +0 -2
  7. package/dist/cli/commands/passes-gate.d.ts.map +1 -1
  8. package/dist/cli/commands/passes-gate.js +0 -1
  9. package/dist/cli/commands/passes-gate.js.map +1 -1
  10. package/dist/cli/commands/performance.d.ts +0 -4
  11. package/dist/cli/commands/performance.d.ts.map +1 -1
  12. package/dist/cli/commands/performance.js +10 -20
  13. package/dist/cli/commands/performance.js.map +1 -1
  14. package/dist/cli/commands/report.d.ts +1 -1
  15. package/dist/cli/commands/report.d.ts.map +1 -1
  16. package/dist/cli/commands/report.js +2 -55
  17. package/dist/cli/commands/report.js.map +1 -1
  18. package/dist/cli/commands/status.d.ts.map +1 -1
  19. package/dist/cli/commands/status.js +4 -8
  20. package/dist/cli/commands/status.js.map +1 -1
  21. package/dist/context/index.d.ts +2 -5
  22. package/dist/context/index.d.ts.map +1 -1
  23. package/dist/context/index.js +2 -8
  24. package/dist/context/index.js.map +1 -1
  25. package/dist/context/token-budget.d.ts +0 -29
  26. package/dist/context/token-budget.d.ts.map +1 -1
  27. package/dist/context/token-budget.js +1 -65
  28. package/dist/context/token-budget.js.map +1 -1
  29. package/dist/context/types.d.ts +0 -1
  30. package/dist/context/types.d.ts.map +1 -1
  31. package/dist/context/types.js +0 -9
  32. package/dist/context/types.js.map +1 -1
  33. package/dist/core/constraints/checker.d.ts +14 -0
  34. package/dist/core/constraints/checker.d.ts.map +1 -1
  35. package/dist/core/constraints/checker.js +22 -2
  36. package/dist/core/constraints/checker.js.map +1 -1
  37. package/dist/core/constraints/git-evidence.d.ts +6 -3
  38. package/dist/core/constraints/git-evidence.d.ts.map +1 -1
  39. package/dist/core/constraints/git-evidence.js +6 -3
  40. package/dist/core/constraints/git-evidence.js.map +1 -1
  41. package/dist/core/index.d.ts +1 -2
  42. package/dist/core/index.d.ts.map +1 -1
  43. package/dist/core/index.js +1 -9
  44. package/dist/core/index.js.map +1 -1
  45. package/dist/core/spec/validator.d.ts +2 -0
  46. package/dist/core/spec/validator.d.ts.map +1 -1
  47. package/dist/core/spec/validator.js +9 -11
  48. package/dist/core/spec/validator.js.map +1 -1
  49. package/dist/core/validators/index.d.ts +1 -1
  50. package/dist/core/validators/index.d.ts.map +1 -1
  51. package/dist/core/validators/passes-gate.d.ts +1 -15
  52. package/dist/core/validators/passes-gate.d.ts.map +1 -1
  53. package/dist/core/validators/passes-gate.js +0 -125
  54. package/dist/core/validators/passes-gate.js.map +1 -1
  55. package/dist/failure/index.d.ts +0 -1
  56. package/dist/failure/index.d.ts.map +1 -1
  57. package/dist/failure/index.js +1 -7
  58. package/dist/failure/index.js.map +1 -1
  59. package/dist/gates/definitions.d.ts.map +1 -1
  60. package/dist/gates/definitions.js +0 -4
  61. package/dist/gates/definitions.js.map +1 -1
  62. package/dist/gates/performance.d.ts +7 -22
  63. package/dist/gates/performance.d.ts.map +1 -1
  64. package/dist/gates/performance.js +7 -89
  65. package/dist/gates/performance.js.map +1 -1
  66. package/dist/gates/types.d.ts +2 -8
  67. package/dist/gates/types.d.ts.map +1 -1
  68. package/dist/index.d.ts +6 -8
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +4 -22
  71. package/dist/index.js.map +1 -1
  72. package/dist/knowledge/index.d.ts +0 -1
  73. package/dist/knowledge/index.d.ts.map +1 -1
  74. package/dist/knowledge/index.js +1 -3
  75. package/dist/knowledge/index.js.map +1 -1
  76. package/dist/monitoring/trace-analyzer.d.ts +25 -10
  77. package/dist/monitoring/trace-analyzer.d.ts.map +1 -1
  78. package/dist/monitoring/trace-analyzer.js +147 -116
  79. package/dist/monitoring/trace-analyzer.js.map +1 -1
  80. package/dist/types/passes-gate.d.ts +0 -19
  81. package/dist/types/passes-gate.d.ts.map +1 -1
  82. package/package.json +1 -1
  83. package/src/__tests__/passes-gate-check.test.ts +20 -4
  84. package/src/__tests__/passes-gate.test.ts +5 -99
  85. package/src/__tests__/performance-gate.test.ts +3 -11
  86. package/src/__tests__/public-exports.test.ts +46 -16
  87. package/src/__tests__/trace-analyzer.test.ts +52 -2
  88. package/src/cli/commands/CONTEXT.md +3 -2
  89. package/src/cli/commands/__tests__/passes-gate-dead-options.test.ts +70 -0
  90. package/src/cli/commands/__tests__/passes-gate.test.ts +7 -3
  91. package/src/cli/commands/__tests__/performance.test.ts +5 -16
  92. package/src/cli/commands/__tests__/registry.test.ts +46 -3
  93. package/src/cli/commands/__tests__/report-extra.test.ts +0 -19
  94. package/src/cli/commands/__tests__/report-false-green.test.ts +46 -0
  95. package/src/cli/commands/__tests__/report.test.ts +0 -20
  96. package/src/cli/commands/__tests__/status-analysis-wiring.test.ts +68 -0
  97. package/src/cli/commands/__tests__/status-extra.test.ts +63 -116
  98. package/src/cli/commands/__tests__/status.test.ts +66 -148
  99. package/src/cli/commands/definitions.ts +1 -32
  100. package/src/cli/commands/passes-gate.ts +0 -3
  101. package/src/cli/commands/performance.ts +13 -27
  102. package/src/cli/commands/report.ts +3 -61
  103. package/src/cli/commands/status.ts +5 -10
  104. package/src/context/CONTEXT.md +2 -3
  105. package/src/context/__tests__/token-budget.test.ts +1 -81
  106. package/src/context/index.ts +2 -7
  107. package/src/context/token-budget.ts +0 -73
  108. package/src/context/types.ts +0 -9
  109. package/src/core/CONTEXT.md +5 -6
  110. package/src/core/constraints/__tests__/collect-constraints.test.ts +66 -0
  111. package/src/core/constraints/checker.ts +33 -2
  112. package/src/core/constraints/git-evidence.ts +6 -3
  113. package/src/core/index.ts +0 -11
  114. package/src/core/spec/__tests__/validator.test.ts +24 -0
  115. package/src/core/spec/validator.ts +9 -10
  116. package/src/core/validators/__tests__/passes-gate.test.ts +2 -9
  117. package/src/core/validators/index.ts +0 -1
  118. package/src/core/validators/passes-gate.ts +1 -149
  119. package/src/failure/CONTEXT.md +8 -6
  120. package/src/failure/index.ts +0 -10
  121. package/src/gates/CONTEXT.md +3 -2
  122. package/src/gates/__tests__/performance.test.ts +6 -74
  123. package/src/gates/definitions.ts +0 -4
  124. package/src/gates/performance.ts +9 -111
  125. package/src/gates/types.ts +2 -8
  126. package/src/index.ts +1 -36
  127. package/src/knowledge/CONTEXT.md +1 -2
  128. package/src/knowledge/index.ts +0 -1
  129. package/src/monitoring/CONTEXT.md +2 -2
  130. package/src/monitoring/trace-analyzer.ts +160 -126
  131. package/src/types/passes-gate.ts +0 -26
  132. package/src/utils/__tests__/jsonl-skip-disposition.test.ts +0 -1
  133. package/dist/cli/commands/analyze-sessions.d.ts +0 -20
  134. package/dist/cli/commands/analyze-sessions.d.ts.map +0 -1
  135. package/dist/cli/commands/analyze-sessions.js +0 -290
  136. package/dist/cli/commands/analyze-sessions.js.map +0 -1
  137. package/dist/cli/commands/update-user-model.d.ts +0 -30
  138. package/dist/cli/commands/update-user-model.d.ts.map +0 -1
  139. package/dist/cli/commands/update-user-model.js +0 -406
  140. package/dist/cli/commands/update-user-model.js.map +0 -1
  141. package/dist/cli/session-mining/corrections.d.ts +0 -17
  142. package/dist/cli/session-mining/corrections.d.ts.map +0 -1
  143. package/dist/cli/session-mining/corrections.js +0 -58
  144. package/dist/cli/session-mining/corrections.js.map +0 -1
  145. package/dist/cli/session-mining/index.d.ts +0 -13
  146. package/dist/cli/session-mining/index.d.ts.map +0 -1
  147. package/dist/cli/session-mining/index.js +0 -29
  148. package/dist/cli/session-mining/index.js.map +0 -1
  149. package/dist/cli/session-mining/text.d.ts +0 -31
  150. package/dist/cli/session-mining/text.d.ts.map +0 -1
  151. package/dist/cli/session-mining/text.js +0 -126
  152. package/dist/cli/session-mining/text.js.map +0 -1
  153. package/dist/cli/session-mining/transcript.d.ts +0 -34
  154. package/dist/cli/session-mining/transcript.d.ts.map +0 -1
  155. package/dist/cli/session-mining/transcript.js +0 -130
  156. package/dist/cli/session-mining/transcript.js.map +0 -1
  157. package/dist/context/compaction.d.ts +0 -57
  158. package/dist/context/compaction.d.ts.map +0 -1
  159. package/dist/context/compaction.js +0 -165
  160. package/dist/context/compaction.js.map +0 -1
  161. package/dist/core/session/clean-state.d.ts +0 -17
  162. package/dist/core/session/clean-state.d.ts.map +0 -1
  163. package/dist/core/session/clean-state.js +0 -192
  164. package/dist/core/session/clean-state.js.map +0 -1
  165. package/dist/core/session/index.d.ts +0 -6
  166. package/dist/core/session/index.d.ts.map +0 -1
  167. package/dist/core/session/index.js +0 -15
  168. package/dist/core/session/index.js.map +0 -1
  169. package/dist/core/session/startup.d.ts +0 -47
  170. package/dist/core/session/startup.d.ts.map +0 -1
  171. package/dist/core/session/startup.js +0 -263
  172. package/dist/core/session/startup.js.map +0 -1
  173. package/dist/failure/constraint-handler.d.ts +0 -83
  174. package/dist/failure/constraint-handler.d.ts.map +0 -1
  175. package/dist/failure/constraint-handler.js +0 -138
  176. package/dist/failure/constraint-handler.js.map +0 -1
  177. package/dist/knowledge/lifecycle-hooks.d.ts +0 -62
  178. package/dist/knowledge/lifecycle-hooks.d.ts.map +0 -1
  179. package/dist/knowledge/lifecycle-hooks.js +0 -143
  180. package/dist/knowledge/lifecycle-hooks.js.map +0 -1
  181. package/dist/types/session.d.ts +0 -113
  182. package/dist/types/session.d.ts.map +0 -1
  183. package/dist/types/session.js +0 -6
  184. package/dist/types/session.js.map +0 -1
  185. package/src/__tests__/clean-state-extra.test.ts +0 -301
  186. package/src/__tests__/clean-state.test.ts +0 -169
  187. package/src/__tests__/constraint-handler.test.ts +0 -132
  188. package/src/__tests__/passes-gate-extra.test.ts +0 -93
  189. package/src/__tests__/session-startup.test.ts +0 -334
  190. package/src/cli/commands/__tests__/analyze-sessions.test.ts +0 -184
  191. package/src/cli/commands/__tests__/update-user-model.test.ts +0 -268
  192. package/src/cli/commands/analyze-sessions.ts +0 -335
  193. package/src/cli/commands/update-user-model.ts +0 -476
  194. package/src/cli/session-mining/__tests__/transcript.test.ts +0 -118
  195. package/src/cli/session-mining/corrections.ts +0 -56
  196. package/src/cli/session-mining/index.ts +0 -13
  197. package/src/cli/session-mining/text.ts +0 -117
  198. package/src/cli/session-mining/transcript.ts +0 -125
  199. package/src/context/__tests__/compaction.test.ts +0 -169
  200. package/src/context/compaction.ts +0 -201
  201. package/src/core/session/__tests__/startup.test.ts +0 -281
  202. package/src/core/session/clean-state.ts +0 -178
  203. package/src/core/session/index.ts +0 -15
  204. package/src/core/session/startup.ts +0 -253
  205. package/src/failure/constraint-handler.ts +0 -171
  206. package/src/knowledge/__tests__/lifecycle-hooks.test.ts +0 -140
  207. package/src/knowledge/lifecycle-hooks.ts +0 -202
  208. package/src/types/session.ts +0 -132
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
  */
@@ -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
  */
@@ -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"}