/** * Skill health analyzer (v0.18 skill-health). * * 接 trace-adapter 输出 → 按 skill 维度聚合 coverage + gap,产出 SkillHealthReport。 * 复用 analysis/coverage-analyzer + analysis/gap-analyzer,跳过对照组逻辑。 * 定位是"真实使用 trace 的 skill 维度观察",不是通用 APM / 生产监控。 * * 分析流水线: * 1. tracesToResultEntries(path) → segments + ResultEntry[] * 2. 时间窗 / skill 白名单过滤 * 3. 按 skill name (variant key) 分别 computeCoverage + computeGapReport * 4. 聚合 overall 指标 + 健康度色带 */ import { type CoverageReport } from '../analysis/coverage-analyzer.js'; import type { GapReport, TraceIngestionSummary } from '../types/index.js'; import { type CcSession, type TraceSession, type SkillSegment } from './trace-adapter.js'; export interface SkillHealth { skillName: string; segmentCount: number; toolCallCount: number; toolFailureCount: number; toolCancelledCount?: number; toolUnknownCount?: number; toolResolvedCount?: number; toolOutcomeCoverage?: number; /** 失败率 = toolFailureCount / 可比较结果数;取消与未知状态不进入分母。 */ toolFailureRate: number; /** * 执行稳定性标签。阈值: * - very-unstable: failureRate >= 0.4 (gap 信号极可能是环境问题,不是真知识缺口) * - unstable: failureRate >= 0.2 (建议排查环境后再看 gap) * - unknown: 有工具调用,但没有可比较的成功 / 失败结果 * - stable: 否则 */ stability: 'stable' | 'unstable' | 'very-unstable' | 'unknown'; /** * 统计可信度(按 segment 数)。守护「1 段 + 一次失败就判 red」的过度自信: * - underpowered: segmentCount < 5 (样本太少,色带 / gap rate 不可信) * - low: segmentCount < 20 (只有大缺口可辨) * - high: >= 20 * 与 eval 侧 UNDERPOWERED(N<20)同构,渲染层据此弱化低 N 的硬色带。 */ confidence: 'high' | 'low' | 'underpowered'; /** 成本/耗时聚合(来自 SkillSegment.metrics,第四轴). 粒度是 skill 级,非单次调用级 */ usage: { inputTokens: number; outputTokens: number; cacheReadTokens: number; cacheCreationTokens: number; totalTokens: number; tokenObservedSegmentCount: number; tokenCoverage: number; durationMs: number; numTurns: number; avgTokensPerSegment: number; avgDurationMsPerSegment: number; }; coverage: CoverageReport | null; gap: GapReport; } export interface SkillHealthReport { /** 顶层判别字段,与 observe-inbox / observe-experience 同属 observe-* 报告族。 * 可选:历史文件无此字段,reader 靠 meta+overall 识别,不强制(additive,非 BREAKING-SCHEMA)。 */ kind?: 'observe-health'; meta: { tracePath: string; kbPath: string | null; sessionCount: number; segmentCount: number; messageCount: number; timestampedSegmentCount?: number; timestampCoverage?: number; excludedUntimestampedSegmentCount?: number; toolCallCount: number; toolCancelledCount?: number; toolUnknownCount?: number; toolResolvedCount?: number; toolOutcomeCoverage?: number; toolFailureRate: number; timeRange: { from: string; to: string; }; generatedAt: string; ingestion?: TraceIngestionSummary; }; bySkill: Record; overall: { gapRate: number; weightedGapRate: number; healthBand: 'green' | 'yellow' | 'red'; /** 整体色带的统计可信度(按总 segment 数)。underpowered/low 时 healthBand 仅供参考。 */ confidence: 'high' | 'low' | 'underpowered'; }; } export interface AnalyzeOptions { kbRoot?: string | null; from?: string; to?: string; skills?: string[]; } /** * 健康度色带。阈值对齐 bench ci --max-gap-rate 经验值(spec §五)。observe 报告只在 overall 给 band; * #235 受管反哺时 observe CLI 用本函数逐 skill 算 band 传入 managed —— 阈值单一来源,managed 不复制。 */ export declare function healthBandOf(weightedGapRate: number): 'green' | 'yellow' | 'red'; /** * 按 per-skill 失败率判定执行稳定性。阈值见 SkillHealth.stability。 */ export declare function toolStabilityOf(toolFailureRate: number, comparableToolCalls: number, totalToolCalls: number): SkillHealth['stability']; /** 统计可信度护栏:按 segment 数判 high / low / underpowered,守护「1 段就判 red」。 * 导出供 renderer / CLI / server 给历史报告(缺 confidence 字段)做 segmentCount 兜底。 */ export declare function confidenceOf(segmentCount: number): SkillHealth['confidence']; /** * 推断 KB root: 没传 --kb 时,取第一个 assistant record 的 cwd。 * 如果跨多个 cwd,取第一个并 warn。 */ type HealthSession = TraceSession | CcSession; /** * 主入口:从受支持的 trace 输入生成 SkillHealthReport。 */ export declare function computeSkillHealthReport(tracePath: string, opts?: AnalyzeOptions): SkillHealthReport; /** * 便利入口:直接从已准备好的 segments(跳过 loadCcSessions)算 report。 * 用于测试 / 已手工组装过 segments 的场景。 */ export declare function computeSkillHealthFromSegments(segments: SkillSegment[], sessions: HealthSession[], tracePath: string, opts?: AnalyzeOptions, ingestion?: TraceIngestionSummary): SkillHealthReport; export {};