/**
 * SmartPerfetto Spark Contracts
 *
 * Single source of truth for the contract shapes introduced by the Spark
 *施工计划包 (`docs/superpowers/spark/plans/*`). Each plan defines a minimal,
 * forward-compatible contract that downstream services, Skills, MCP tools,
 * UI panels, or reporters can produce or consume.
 *
 * Design rules (apply to every contract below):
 *  - Every result object carries `schemaVersion`, `source`, `createdAt` (or
 *    equivalent provenance) so old sessions and reports remain readable as the
 *    schema evolves.
 *  - Trace timestamps stay in nanoseconds; presentation layers are free to add
 *    a formatted `*_str` field but must never replace the raw ns value.
 *  - Anything an LLM can quote must expose `evidenceRef`, `artifactId`, `sql`,
 *    `skillId`, or an explicit `unsupportedReason`. Missing-data paths must be
 *    visible — never wrapped as a confident conclusion.
 *  - All new fields are optional by default to keep older sessions consumable.
 *
 * Spark mapping: see `docs/superpowers/spark/README.md` "Spark #1-#205 覆盖矩阵".
 *
 * @module sparkContracts
 */
/** Universal time range expressed in nanoseconds (Perfetto canonical unit). */
export interface NsTimeRange {
    /** Inclusive start in nanoseconds since trace start. */
    startNs: number;
    /** Exclusive end in nanoseconds since trace start. */
    endNs: number;
}
/** Provenance fields that every contract must carry. */
export interface SparkProvenance {
    /** Contract version. Bump on breaking changes. */
    schemaVersion: number;
    /** Where the data came from (skill id, MCP tool id, importer id, …). */
    source: string;
    /** Epoch ms timestamp when the artifact was generated. */
    createdAt: number;
    /**
     * Human-readable reason that explains why the result was downgraded. When
     * present the consumer must treat the contract as a low-confidence/blocked
     * artifact rather than a confident conclusion.
     */
    unsupportedReason?: string;
    /** Free-form provenance notes (e.g. trace processor build, host SHA). */
    notes?: string;
}
/** Pointer that lets consumers resolve back to evidence. */
export interface SparkEvidenceRef {
    /** Time range when the evidence is bounded (optional). */
    range?: NsTimeRange;
    /** Skill that emitted the evidence. */
    skillId?: string;
    /** Step within a composite/iterator skill. */
    stepId?: string;
    /** Backing artifact in the session-scoped artifact store. */
    artifactId?: string;
    /** Raw SQL fingerprint or stored procedure id. */
    sql?: string;
    /** External resource (importer, RAG entry, log file). */
    externalRef?: string;
    /** Optional natural-language description for UI tooltips. */
    description?: string;
}
/** Confidence band shared by decision-tree style outputs. */
export type SparkConfidence = 'low' | 'medium' | 'high' | 'unsupported';
/** Per-Spark-number mapping recorded inside each contract for traceability. */
export interface SparkCoverageEntry {
    /** Spark idea number from `docs/spark.md`. */
    sparkId: number;
    /** Plan id (`01`-`57`) consuming the idea. */
    planId: string;
    /** Status word matching `docs/superpowers/spark/TODO.md`. */
    status: 'scaffolded' | 'implemented' | 'unsupported' | 'future';
    /** Brief note explaining what landed for this Spark id. */
    note?: string;
}
/**
 * Strict enum of RAG (Retrieval-Augmented Generation) source kinds.
 *
 * Narrow on purpose — license / consent / freshness policy tables switch on
 * this value and must not silently accept unknown sources. Extending the
 * union requires an explicit contract bump and updates to those tables.
 */
export type RagSourceKind = 
/** Plan 55 — androidperformance.com blog ingester. */
'androidperformance.com'
/** Plan 55 — AOSP source ingester (license required). */
 | 'aosp'
/** Plan 55 — OEM SDK doc ingester (license required). */
 | 'oem_sdk'
/** Plan 44 — exposes project memory entries as a RAG corpus. */
 | 'project_memory'
/** Plan 44 — world-scope consolidated memory (post-review). */
 | 'world_memory'
/** Plan 54 — published case library entries. */
 | 'case_library'
/** Codebase-aware analysis — user application source. */
 | 'app_source'
/** Codebase-aware analysis — Linux kernel or vendor kernel source. */
 | 'kernel_source';
/**
 * Pointer to a RAG-indexed document chunk.
 *
 * Used by Plan 44 (project memory references) and Plan 55 (blog/AOSP/OEM
 * retrieval results). The reference travels through the artifact store so
 * downstream consumers can resolve the original text on demand.
 */
export interface RagDocumentRef {
    /** Stable chunk id (sha-256 prefix of source + offset). */
    chunkId: string;
    /** Knowledge source kind — strict enum, see `RagSourceKind`. */
    source: RagSourceKind;
    /** Display title of the parent document. */
    title?: string;
    /** Original URL or local path. */
    uri?: string;
    /** Byte offset (or token offset) into the source document. */
    offset?: number;
    /** Length of the chunk in characters. */
    length?: number;
    /** When the chunk was indexed (epoch ms). */
    indexedAt?: number;
    /**
     * License of the source. Required at ingestion time when `source` is `aosp`
     * or `oem_sdk` — the Plan 55 ingester must reject those chunks if license
     * is missing. Optional for blog / project_memory / world_memory /
     * case_library because those sources have implicit policies covered by
     * Plans 44 / 54.
     */
    license?: 'AGPL-3.0' | 'Apache-2.0' | 'CC-BY-4.0' | 'proprietary' | string;
    /** Freshness flag — true if older than the source's recommended refresh window. */
    stale?: boolean;
}
/**
 * Memory scope hierarchy — controls retention, sharing, and consolidation
 * policy for Plan 44 project memory and Plan 54 case library.
 *
 *   session → project → world
 *
 * Promotion between scopes must be explicit (see `MemoryPromotionTrigger`).
 * Auto-promotion is forbidden — `promote()` must reject any other trigger.
 */
export type MemoryScope = 
/** Ephemeral, dies with the analysis. Lives in `analysisPatternMemory.ts`. */
'session'
/** Persisted per-project (typically per app + device combo). */
 | 'project'
/** Promoted to cross-project knowledge after explicit reviewer approval. */
 | 'world';
/**
 * Composite key shared by Plan 50 baselines and Plan 54 case nodes.
 *
 * Anonymization status of each component is the responsibility of the
 * containing record's `redactionState` field — `BaselineRecord` and
 * `CaseNode` both treat raw appId/deviceId as identifiable info.
 */
export interface PerfBaselineKey {
    /** App package or product id. */
    appId: string;
    /** Device fingerprint (model + Android version + SoC). */
    deviceId: string;
    /** Build identifier (git sha, version code, or branch). */
    buildId: string;
    /** Critical-User-Journey id, e.g. `cold_start` / `scroll_feed` / `anr_dispatch`. */
    cuj: string;
}
/**
 * Curation lifecycle status for cases (Plan 54) and baselines (Plan 50).
 *
 * Note: redaction state is a separate axis. Each record (CaseNode,
 * BaselineRecord) carries its own `redactionState: 'raw' | 'partial' |
 * 'redacted'` field. A case can be `published` only if `redactionState ===
 * 'redacted'` AND a curator has signed off (double-control gate).
 */
export type CurationStatus = 'draft' | 'reviewed' | 'published' | 'private';
/**
 * Cross-plan reference to a case node (Plan 54).
 *
 * Defined here, in shared base types, to break the circular dependency
 * between Plan 44 (FeedbackPipelineEntry → caseId) and Plan 54 (CaseNode
 * findings → memory entries). Both plans depend on `CaseRef` rather than
 * importing each other's contract types directly.
 */
export interface CaseRef {
    /** Stable case id from Plan 54's case library. */
    caseId: string;
    /** Optional snapshot of the case status at reference time. */
    status?: CurationStatus;
    /** Free-form note explaining why this case is referenced. */
    citationReason?: string;
}
/**
 * What triggered a memory promotion event (Plan 44).
 *
 * Auto-promotion is intentionally absent — `projectMemory.promote()` must
 * throw when given a trigger outside this union. The audit log relies on a
 * recorded human or eval-driven trigger for every cross-scope move.
 */
export type MemoryPromotionTrigger = 
/** User explicitly said "remember this" via feedback. */
'user_feedback'
/** Admin signed off via `/api/memory/promote` (reviewer required). */
 | 'reviewer_approval'
/** Entry contributed to a passing eval case (Spark #95). */
 | 'skill_eval_pass';
/**
 * Audit record attached to every cross-scope memory promotion.
 *
 * Stored on the `ProjectMemoryEntry.promotionPolicy` field for entries
 * whose scope is `world` (required) and optionally on `project` entries
 * that were promoted (rather than created directly). Also appended to the
 * promotion audit log at `backend/logs/analysis_project_memory.json`.
 */
export interface MemoryPromotionPolicy {
    /** Source scope (lower in the hierarchy). */
    fromScope: MemoryScope;
    /** Target scope (higher). */
    toScope: MemoryScope;
    /** What triggered the promotion. */
    trigger: MemoryPromotionTrigger;
    /** Reviewer name when trigger='reviewer_approval'. */
    reviewer?: string;
    /** When the promotion happened (epoch ms). */
    promotedAt: number;
    /** Eval case id when trigger='skill_eval_pass'. */
    evalCaseId?: string;
}
/**
 * Per-Skill prerequisite usage entry.
 * Reflects how a skill (composite or atomic) declared a stdlib module either
 * via YAML `prerequisites:` or via raw SQL inspected by `sqlIncludeInjector`.
 */
export interface StdlibSkillUsage {
    skillId: string;
    /** YAML-declared prerequisites. */
    declared: string[];
    /** Modules detected via raw SQL `INCLUDE PERFETTO MODULE` scanning. */
    detected: string[];
    /** Modules declared but never used in any SQL step. */
    declaredButUnused: string[];
    /** Modules used in SQL but not declared in YAML. */
    detectedButUndeclared: string[];
}
/**
 * Stdlib module metadata used by the Skill coverage report.
 * Sourced from `perfettoStdlibScanner` (packaged asset + on-disk source).
 */
export interface StdlibModuleEntry {
    module: string;
    /** Brief module summary if surfaced by the stdlib asset. */
    summary?: string;
    /** Number of skills declaring this module as a prerequisite. */
    declaredBySkills: number;
    /** Number of skills using this module via raw SQL. */
    usedBySkills: number;
    /** True if added since the last catalog snapshot — drives the watcher. */
    newSinceLastSnapshot?: boolean;
}
/**
 * StdlibSkillCoverageContract (Plan 01)
 *
 * Output of `analyzeStdlibSkillCoverage(...)`. Surfaced via:
 *  - `npm run validate:skills` summary block
 *  - MCP tool `list_stdlib_modules` (extension)
 *  - Plan doc snapshot when triaging Skill regressions
 */
export interface StdlibSkillCoverageContract extends SparkProvenance {
    /** Total stdlib modules visible from the scanner asset. */
    totalModules: number;
    /** Modules referenced by at least one Skill (declared OR detected). */
    modulesCovered: number;
    /** Skills with at least one undeclared-but-detected stdlib usage. */
    skillsWithDrift: number;
    /** Modules that no Skill references — Skill suggestion target. */
    uncoveredModules: StdlibModuleEntry[];
    /** Per-Skill drift report, used by the watcher. */
    skillUsage: StdlibSkillUsage[];
    /** Modules added in the most recent stdlib snapshot. */
    newlyAddedModules?: StdlibModuleEntry[];
    /** Spark coverage entries explaining what landed in this contract. */
    coverage: SparkCoverageEntry[];
}
/** Hierarchical detail levels for `trace_summary` v2 output. */
export type TraceSummaryLayer = 'L0' | 'L1' | 'L2' | 'L3';
/**
 * Single metric spec entry. Drives both `trace_summary()` baseline output and
 * downstream Skill comparisons. Schema kept minimal — value/unit/range only —
 * so older snapshots remain readable when new dimensions arrive.
 */
export interface TraceSummaryMetric {
    /** Stable metric id, e.g. `frames.jank_count.p95`. */
    metricId: string;
    /** Numeric value. Always paired with `unit`. */
    value: number;
    /** Unit string: `ns`, `ms`, `count`, `percent`, `bytes`, ... */
    unit: string;
    /** Optional ns range when the metric is bounded to a window. */
    range?: NsTimeRange;
    /** Layer this metric belongs to (L0 highest-level → L3 deepest). */
    layer: TraceSummaryLayer;
    /** Skill or stdlib module that produced the value. */
    source: string;
    /** Evidence pointer for AI quoting. */
    evidence?: SparkEvidenceRef;
    /** Why this metric is unavailable for this trace (when applicable). */
    unsupportedReason?: string;
}
/**
 * Baseline artifact descriptor. Baselines live in artifact storage; the
 * contract tracks references rather than embedding full payloads.
 */
export interface TraceSummaryBaselineRef {
    /** Stable baseline id (`<app>/<device>/<build>/<cuj>`). */
    baselineId: string;
    /** Artifact id holding the full snapshot. */
    artifactId: string;
    /** When the baseline was captured (epoch ms). */
    capturedAt: number;
    /** Number of traces aggregated into the baseline. */
    sampleCount?: number;
}
/**
 * TraceSummaryV2Contract (Plan 02)
 *
 * Output of `traceSummaryV2(traceId, options?)`. Surfaces:
 *  - Hierarchical L0-L3 metrics with provenance for each.
 *  - Baseline pointer for diff/regression flows (consumed by Plan 25 / 50).
 *  - `trace_processor_shell` build identifier (Spark #102 — engine continues
 *    to be canonical).
 *  - Probe results so callers can detect feature gaps without re-running the
 *    summary.
 */
export interface TraceSummaryV2Contract extends SparkProvenance {
    /** Trace processor build (semver or git sha). Captures #102 invariant. */
    traceProcessorBuild?: string;
    /** Whole-trace ns range covered by this summary. */
    traceRange: NsTimeRange;
    /** Probe results — true if the metric was producible on this trace. */
    probes: Record<string, boolean>;
    /** L0/L1/L2/L3 metrics in a flat array (layer is per-metric). */
    metrics: TraceSummaryMetric[];
    /** Optional baseline pointer when the request asked for diff context. */
    baseline?: TraceSummaryBaselineRef;
    coverage: SparkCoverageEntry[];
}
/** Kind of SmartPerfetto-owned PerfettoSQL symbol. */
export type SmartPerfettoSqlSymbolKind = 'function' | 'view' | 'table' | 'macro' | 'index';
/** Single symbol exported by the `smartperfetto.*` SQL package. */
export interface SmartPerfettoSqlSymbol {
    /** Fully qualified docs path, e.g. `smartperfetto.scrolling.jank_frames`. */
    name: string;
    /**
     * The actual SQL identifier callers use in `SELECT ... FROM <sqlName>`,
     * e.g. `smartperfetto_scrolling_jank_frames`. Codex review caught that
     * `name` is a dotted docs path which is not a valid Perfetto SQL
     * identifier; consumers must always quote `sqlName` in generated SQL.
     */
    sqlName: string;
    kind: SmartPerfettoSqlSymbolKind;
    /** Module file containing the definition (relative to package root). */
    module: string;
    /** Brief description for docs/agent prompt injection. */
    summary?: string;
    /** Function/macro signatures, table column lists. */
    signature?: string;
    /** stdlib modules this symbol depends on. */
    dependencies?: string[];
    /** Whether the symbol is considered stable for external consumers. */
    stability: 'experimental' | 'stable' | 'deprecated';
}
/**
 * SmartPerfettoSqlPackageContract (Plan 03)
 *
 * Output of `loadSmartPerfettoSqlPackage(...)`. Powers:
 *  - `--add-sql-package smartperfetto` boot path on `trace_processor_shell`.
 *  - sqlKnowledgeBase enrichment so the agent can recall canonical symbols.
 *  - validate:strategies catalog so prompt templates can quote symbol names
 *    without drifting from the actual SQL implementation.
 */
export interface SmartPerfettoSqlPackageContract extends SparkProvenance {
    /** Package version (semver). */
    packageVersion: string;
    /** Symbols exported by the package. */
    symbols: SmartPerfettoSqlSymbol[];
    /** Symbols intentionally omitted (e.g., legacy aliases). */
    removed?: SmartPerfettoSqlSymbol[];
    /** Boot command snippet used to register the package, for docs/MCP. */
    bootSnippet?: string;
    coverage: SparkCoverageEntry[];
}
/** Sampling/clustering strategy applied to a compressed artifact. */
export type ArtifactSamplingStrategy = 'full' | 'top_k' | 'p95_tail' | 'p99_tail' | 'random' | 'cluster_representative' | 'cuj_window';
/** Per-column metadata required for schema-aware JSON output (Spark #28). */
export interface ArtifactColumnSpec {
    name: string;
    /** Semantic type aligned with `dataContract.ColumnType`. */
    type: string;
    /** Unit string (`ns`, `ms`, `bytes`, `count`, `percent`). */
    unit?: string;
    /** Where the value comes from (skill id, stdlib symbol, computation). */
    source?: string;
    /** Free-form note about sampling or clustering applied to the column. */
    samplingNote?: string;
}
/** Compression record so consumers can decide whether to fetch full payload. */
export interface ArtifactCompressionInfo {
    strategy: ArtifactSamplingStrategy;
    /** Original (pre-compression) row count. */
    originalRowCount: number;
    /** Row count after compression. */
    compressedRowCount: number;
    /** Effective sampling ratio (compressedRowCount / originalRowCount). */
    ratio: number;
    /** Window applied for `cuj_window` strategy. */
    window?: NsTimeRange;
    /** Top-K bound for `top_k` strategy. */
    topK?: number;
    /** Random seed for reproducibility on `random` strategy. */
    randomSeed?: number;
}
/**
 * ArtifactSchemaContract (Plan 04)
 *
 * Sidecar metadata attached to entries in the artifact store. The full data
 * remains in `ArtifactStore.fetch(id, 'full')`; this contract describes the
 * compressed view emitted to the LLM context window.
 */
export interface ArtifactSchemaContract extends SparkProvenance {
    /** Pointer to the artifact in `ArtifactStore`. */
    artifactId: string;
    /** Column-level schema; required for AI quoting (Spark #28). */
    columns: ArtifactColumnSpec[];
    /** Compression record. `strategy: 'full'` means no compression applied. */
    compression: ArtifactCompressionInfo;
    /** Time range covered by the artifact (CUJ window). */
    range?: NsTimeRange;
    /** When `top_k` or `p95_tail`, the metric used to rank rows. */
    rankBy?: string;
    /** Cluster representatives chosen by `cluster_representative` strategy. */
    clusterRepresentatives?: number[];
    coverage: SparkCoverageEntry[];
}
/** Single binned bucket along a timeline axis. */
export interface TimelineBin {
    /** Inclusive start of the bucket in nanoseconds. */
    startNs: number;
    /** Bucket width in nanoseconds. */
    durNs: number;
    /** Aggregated value for the bucket (sum/avg/count depending on aggregation). */
    value: number;
    /** Count of source rows aggregated into this bin. */
    rowCount?: number;
}
/** RLE turning-point record for counter tracks (Spark #27). */
export interface CounterRleSegment {
    /** Inclusive start in nanoseconds of the constant-value segment. */
    startNs: number;
    /** Exclusive end in nanoseconds. */
    endNs: number;
    /** Counter value held across the segment. */
    value: number;
    /** Optional cumulative delta from prior segment (turning-point hint). */
    delta?: number;
}
/** Aggregation function used for timeline binning. */
export type TimelineBinAggregation = 'sum' | 'avg' | 'count' | 'max' | 'min';
/**
 * TimelineBinningContract (Plan 05)
 *
 * Compact representation of timeline-style data. Two flavours:
 *  - `bins[]` — uniformly bucketed stream values (Spark #23 token compression).
 *  - `rle[]` — run-length encoded counter trail with turning points (Spark #27).
 */
export interface TimelineBinningContract extends SparkProvenance {
    /** Track id this binning describes (`process_counter_track.id`, etc.). */
    trackId: string | number;
    /** Time range covered by the binning. */
    range: NsTimeRange;
    /** Bin width in nanoseconds when `bins[]` is present. */
    binDurNs?: number;
    aggregation?: TimelineBinAggregation;
    bins?: TimelineBin[];
    rle?: CounterRleSegment[];
    /** Original (pre-compression) sample count, for ratio reporting. */
    originalSampleCount: number;
    coverage: SparkCoverageEntry[];
}
/** Domain of a redacted identifier. */
export type AnonymizationDomain = 'package' | 'process' | 'thread' | 'path' | 'user_id' | 'device_id';
/** One identifier→placeholder mapping. */
export interface AnonymizationMapping {
    domain: AnonymizationDomain;
    /** Original (sensitive) identifier. */
    original: string;
    /** Stable placeholder used in the redacted output. */
    placeholder: string;
    /** Optional collision counter when multiple originals share a placeholder. */
    collisionIndex?: number;
}
/** Streaming pipeline progress for huge traces (Spark #30). */
export interface LargeTraceStreamProgress {
    /** Total bytes the importer is expected to process. */
    totalBytes: number;
    /** Bytes processed so far. */
    processedBytes: number;
    /** Streaming chunks emitted so far. */
    chunksEmitted: number;
    /** True when the entire trace has been ingested. */
    done: boolean;
    /** Per-chunk wall-time in ms (last chunk). */
    lastChunkMs?: number;
}
/**
 * AnonymizationContract (Plan 06)
 *
 * Container that travels with redacted artifacts. Holds:
 *  - Stable mappings so the same package always becomes the same placeholder.
 *  - Streaming progress when the trace is too large for in-memory ingestion.
 *  - Redaction state — `state: 'redacted'` is required before exporting to a
 *    public report; consumers must error otherwise.
 */
export interface AnonymizationContract extends SparkProvenance {
    /** Redaction state — drives downstream gating. */
    state: 'raw' | 'partial' | 'redacted';
    /** Per-domain mapping table. */
    mappings: AnonymizationMapping[];
    /** Domains that are still raw (not yet mapped). */
    pendingDomains?: AnonymizationDomain[];
    /** Streaming progress when ingesting >1GB traces. */
    streamProgress?: LargeTraceStreamProgress;
    coverage: SparkCoverageEntry[];
}
/**
 * Canonical Perfetto data source names. Verified against
 * `perfetto/docs/data-sources/*.md` and
 * `perfetto/protos/perfetto/config/data_source_config.proto`. Codex round 4
 * caught that earlier names like `android.frametimeline` and
 * `android.input` were not real — generated trace configs would silently
 * fail to capture frame/input data.
 */
export type PerfettoDataSourceId = 'linux.ftrace' | 'linux.process_stats' | 'linux.sys_stats' | 'linux.system_info' | 'linux.sysfs_power' | 'android.surfaceflinger.frametimeline' | 'android.surfaceflinger.layers' | 'android.surfaceflinger.transactions' | 'android.input.inputevent' | 'android.power' | 'android.log' | 'android.network_packets' | 'android.java_hprof' | 'gpu.counters' | 'gpu.renderstages' | 'gpu.log' | 'vulkan.memory_tracker' | string;
/** Single trace config fragment. */
export interface PerfettoConfigFragment {
    /** Logical id of the data source. */
    dataSource: PerfettoDataSourceId;
    /** Human-readable rationale for inclusion. */
    reason: string;
    /** Optional knob set as `key: value` strings. */
    options?: Record<string, string>;
}
/** Custom slice / protobuf injection definition (Spark #53). */
export interface CustomSliceSpec {
    /** Stable slice name surfaced on the timeline. */
    name: string;
    /** Track this slice belongs to (process or async track id). */
    trackHint?: string;
    /** Schema fields the slice carries (mirrors atrace `args=`). */
    fields?: ArtifactColumnSpec[];
    /** Owning module / SDK that emits the slice. */
    emittedBy?: string;
}
/** Trace self-description metadata (Spark #201). */
export interface TraceSelfDescription extends SparkProvenance {
    /** App package the trace was captured against. */
    packageName?: string;
    /** Build id / git sha. */
    buildId?: string;
    /** CUJ scenario name (`cold_start`, `scroll_feed`, …). */
    cuj?: string;
    /** Device fingerprint (model + Android version + SoC). */
    device?: string;
    /** Hint describing how to interpret the trace ("startup", "anr", "scroll"). */
    intent?: string;
    /** Custom slices/markers expected to be present. */
    expectedCustomSlices?: CustomSliceSpec[];
}
/**
 * TraceConfigGeneratorContract (Plan 07)
 *
 * Output of `generateTraceConfig({intent})`. Surfaces:
 *  - Recommended data sources (#197 — AI generated trace config).
 *  - Custom slice schema (#53 — business-side instrumentation contract).
 *  - Self-description metadata embedded in the trace artifact (#201).
 */
export interface TraceConfigGeneratorContract extends SparkProvenance {
    /** Suggested config fragments. */
    fragments: PerfettoConfigFragment[];
    /** Custom slice / protobuf injection schema. */
    customSlices?: CustomSliceSpec[];
    /** Embedded self-description metadata for the captured trace. */
    selfDescription?: TraceSelfDescription;
    /** Compact rationale for the overall config. */
    rationale?: string;
    coverage: SparkCoverageEntry[];
}
/**
 * FrameTimeline jank_type values used as ground truth (Spark #16).
 * Mirrors `actual_frame_timeline_slice.jank_type` from Perfetto stdlib.
 */
export type FrameTimelineJankType = 'None' | 'AppDeadlineMissed' | 'SurfaceFlingerCpuDeadlineMissed' | 'SurfaceFlingerGpuDeadlineMissed' | 'DisplayHAL' | 'PredictionError' | 'Buffer Stuffing' | 'BufferStuffing' | 'Unknown' | string;
/** Single node in the jank attribution decision tree. */
export interface JankDecisionNode {
    /** Stable node id used for route tracing. */
    nodeId: string;
    /** Short human-readable label. */
    label: string;
    /** Decision rule that selected this branch. */
    rule?: string;
    /** Skill id that produced the data backing this node. */
    skillId?: string;
    /** Evidence pointer for AI quoting. */
    evidence?: SparkEvidenceRef;
    /** Confidence in this branch's diagnosis. */
    confidence?: SparkConfidence;
    /** Children — empty when this is a terminal verdict. */
    children?: JankDecisionNode[];
}
/** Per-frame attribution row. */
export interface JankFrameAttribution {
    frameId: number | string;
    /** ns range of the frame slice. */
    range: NsTimeRange;
    /** FrameTimeline ground truth jank_type. */
    jankType: FrameTimelineJankType;
    /** Path of decision tree node ids that classified this frame. */
    routePath: string[];
    /** Reason code emitted by the analysis (e.g. `cpu_starvation`). */
    reasonCode?: string;
    /** Evidence pointers backing the reason code. */
    evidence?: SparkEvidenceRef[];
}
/**
 * JankDecisionTreeContract (Plan 10)
 *
 * Output of the scrolling Skill verdict layer. Anchors every diagnosis to
 * FrameTimeline `jank_type` so the agent can never blend
 * AppDeadlineMissed / SurfaceFlinger / DisplayHAL conclusions.
 */
export interface JankDecisionTreeContract extends SparkProvenance {
    /** Root of the decision tree (start of the routing). */
    root: JankDecisionNode;
    /** Per-frame attribution rows used to validate the tree. */
    frameAttributions: JankFrameAttribution[];
    /** Frames missing FrameTimeline ground truth (cannot be classified). */
    unclassifiedFrames?: JankFrameAttribution[];
    coverage: SparkCoverageEntry[];
}
/** Per-thread runtime state breakdown over a window. */
export interface ThreadStateBreakdown {
    utid: number;
    /** Owning process pid (-1 if unknown). */
    pid: number;
    threadName: string;
    range: NsTimeRange;
    /** Aggregated durations by `thread_state.state` (Running, R, S, D, …). */
    durByStateNs: Record<string, number>;
    /** Total wakeup count in the window. */
    wakeupCount?: number;
    /** Sched runnable->Running latency p95 (ns). */
    runnableLatencyP95Ns?: number;
}
/** Wakeup edge in the wakeup graph (Spark #17). */
export interface SchedulerWakeupEdge {
    fromUtid: number;
    toUtid: number;
    fromThread?: string;
    toThread?: string;
    /** Wakeup ns timestamp. */
    ts: number;
    /** Latency until target thread runs (ns). */
    latencyNs?: number;
    /** Wakeup reason if available (irq, futex_wake, binder, …). */
    reason?: string;
}
/** Critical task chain entry (Spark #17). */
export interface CriticalTaskChainEntry {
    utid: number;
    threadName: string;
    /** ns range during which this thread was on the critical path. */
    range: NsTimeRange;
    /** Why this segment is on the critical path. */
    reason: string;
}
/**
 * ThreadSchedContextContract (Plan 11)
 *
 * Mandatory prior used by jank/ANR/startup decision trees. Without this
 * contract, downstream Skills must treat their conclusions as low-confidence
 * (Spark #6 — thread_state / sched.with_context as ground truth gate).
 */
export interface ThreadSchedContextContract extends SparkProvenance {
    /** Window the priors describe. */
    range: NsTimeRange;
    /** Per-thread breakdowns (typically focused on UI / RenderThread). */
    threadStates: ThreadStateBreakdown[];
    /** Wakeup graph edges intersecting the window. */
    wakeupEdges?: SchedulerWakeupEdge[];
    /** Ordered critical task chain (Spark #17 report-friendly view). */
    criticalChain?: CriticalTaskChainEntry[];
    coverage: SparkCoverageEntry[];
}
/** A single hop in the binder transaction chain. */
export interface BinderChainHop {
    /** Sequence index within the chain (0 = victim caller). */
    step: number;
    side: 'client' | 'server';
    /** Process+thread id pair. */
    pid: number;
    tid: number;
    process?: string;
    thread?: string;
    /** Binder method name if known. */
    method?: string;
    /** ns range for the hop slice. */
    range: NsTimeRange;
    /** Wait reason if the hop blocked (e.g. lock, IO, cpu_starvation). */
    blockedOn?: string;
    evidence?: SparkEvidenceRef;
}
/**
 * BinderRootCauseChainContract (Plan 12)
 *
 * Output of `binder_root_cause` deep skill. Renders the cross-process chain
 * from the user-visible victim caller all the way to the system server-side
 * blocker, anchored on `android.binder` stdlib slices.
 */
export interface BinderRootCauseChainContract extends SparkProvenance {
    /** Victim slice that triggered the analysis (UI-thread blocking call). */
    victim: BinderChainHop;
    /** Ordered server-side hops; chain[0] is the immediate callee. */
    chain: BinderChainHop[];
    /** Final root cause hop — usually chain[-1] when the chain terminates. */
    rootCause?: BinderChainHop;
    /** Why the chain could not be fully resolved (binder data missing, etc.). */
    truncated?: boolean;
    coverage: SparkCoverageEntry[];
}
/** CPU frequency residency entry — fraction of time at a given freq band. */
export interface CpuFreqResidency {
    cpu: number;
    freqHz: number;
    /** Time at this frequency in nanoseconds. */
    durNs: number;
    /** Fraction of the analysis window (0-1). */
    fraction: number;
}
/** Thermal counter sample (per zone). */
export interface ThermalSample {
    zone: string;
    ts: number;
    /** Temperature in millidegrees Celsius. */
    tempMc: number;
    /** Throttling state if known (0 = none, 1+ = throttling tier). */
    throttleStage?: number;
}
/** PMU / simpleperf-derived counter attribution row. */
export interface PmuAttributionRow {
    /** Counter id (`cycles`, `instructions`, `cache-misses`, …). */
    counter: string;
    utid?: number;
    process?: string;
    thread?: string;
    /** Aggregated counter value across the window. */
    value: number;
    /** Optional derived metric (`ipc`, `miss_rate`). */
    derived?: Record<string, number>;
}
/** Thermal throttling decision (Spark #35). */
export type ThermalDecision = 'cool' | 'soft_throttle' | 'hard_throttle' | 'shutdown_imminent' | 'unknown';
/**
 * CpuThermalPmuContract (Plan 13)
 *
 * Combined attribution for CPU frequency / thermal / PMU. Skills can request
 * any subset; missing facets must surface as `unsupportedReason` rather than
 * being silently zero-filled.
 */
export interface CpuThermalPmuContract extends SparkProvenance {
    /** Window covered by the analysis. */
    range: NsTimeRange;
    /** Per-CPU frequency residency. */
    cpuFreqResidency?: CpuFreqResidency[];
    /** Thermal samples + decision. */
    thermalSamples?: ThermalSample[];
    thermalDecision?: ThermalDecision;
    /** PMU attribution rows. */
    pmuAttribution?: PmuAttributionRow[];
    /** Smooth vs jank window comparison hint (Spark #8). */
    smoothVsJankComparison?: {
        smoothFraction: number;
        jankFraction: number;
        delta: number;
    };
    coverage: SparkCoverageEntry[];
}
/** Per-process memory snapshot row. */
export interface ProcessMemorySnapshot {
    pid: number;
    process?: string;
    ts: number;
    rssBytes?: number;
    swapBytes?: number;
    anonRssBytes?: number;
    /** mm_event derived metrics (page faults, OOM score). */
    mmEvent?: Record<string, number>;
    oomScoreAdj?: number;
}
/** Low-memory-killer event. */
export interface LmkKillEvent {
    ts: number;
    pid: number;
    process?: string;
    oomScoreAdj?: number;
    reason?: string;
    /** Bytes freed by the kill. */
    freedBytes?: number;
}
/** DMA / dmabuf / ion allocation snapshot. */
export interface DmaBufAllocation {
    ts: number;
    bufferBytes: number;
    allocator: 'dmabuf' | 'ion' | 'gpu' | string;
    process?: string;
    /** Refcount when known. */
    refcount?: number;
}
/** External memory artifact (LeakCanary, KOOM, hprof, …). */
export interface MemoryExternalArtifact {
    /** Source kind. */
    kind: 'leak_canary' | 'koom' | 'hprof' | 'baseline' | 'manual' | string;
    /** Pointer to raw artifact in store. */
    artifactId?: string;
    /** Brief summary. */
    summary?: string;
    /** Retained-size in bytes when known. */
    retainedBytes?: number;
    evidence?: SparkEvidenceRef;
}
/**
 * MemoryRootCauseContract (Plan 14)
 *
 * Combines RSS/Swap/MM event timelines, LMK kill events, DMA/DMABUF pressure,
 * and pointers to external memory artifacts (LeakCanary / KOOM / hprof) so the
 * memory analysis Skill can render a unified root-cause graph.
 */
export interface MemoryRootCauseContract extends SparkProvenance {
    range: NsTimeRange;
    processSnapshots?: ProcessMemorySnapshot[];
    lmkEvents?: LmkKillEvent[];
    dmaAllocations?: DmaBufAllocation[];
    externalArtifacts?: MemoryExternalArtifact[];
    /** Baseline diff hint (Spark #34). */
    baselineDiff?: {
        baselineId: string;
        deltaBytes: number;
        /** Top contributors as `{key, deltaBytes}`. */
        topContributors?: Array<{
            key: string;
            deltaBytes: number;
        }>;
    };
    coverage: SparkCoverageEntry[];
}
/** IO blocking event row (Spark #15). */
export interface IoBlockEvent {
    ts: number;
    durNs: number;
    process?: string;
    thread?: string;
    /** Filesystem operation (read, write, fsync, …). */
    op: string;
    /** Filename or device path when known. */
    path?: string;
    /** Bytes transferred. */
    bytes?: number;
    /** Filesystem driver (ext4, f2fs, …). */
    fs?: string;
}
/** Network packet/wait grouping. */
export interface NetworkAttribution {
    /** Local endpoint description. */
    endpoint: string;
    process?: string;
    ts: number;
    durNs: number;
    /** Protocol layer (`tcp`, `udp`, `http`). */
    protocol?: string;
    /** Bytes sent / received. */
    bytesIn?: number;
    bytesOut?: number;
    /** Wait reason matched to a thread state. */
    waitReason?: string;
}
/** Battery / wakelock baseline row (Spark #18). */
export interface WakelockBaselineRow {
    process?: string;
    uid?: number;
    /** Cumulative wake-time (ms). */
    totalMs: number;
    /** Wake count over baseline window. */
    wakeCount: number;
    /** Per-wake median duration (ms). */
    medianMs?: number;
}
/**
 * IoNetworkWakeupContract (Plan 15)
 *
 * Bundles IO, network and wakelock attribution. All facets optional so the
 * Skill can run on traces that captured only a subset.
 */
export interface IoNetworkWakeupContract extends SparkProvenance {
    range: NsTimeRange;
    ioEvents?: IoBlockEvent[];
    networkAttribution?: NetworkAttribution[];
    wakelockBaseline?: WakelockBaselineRow[];
    /** Wakeup edges that originated from IO / network (Spark #20). */
    wakeupEdges?: SchedulerWakeupEdge[];
    coverage: SparkCoverageEntry[];
}
/** GPU render-stage breakdown row (Spark #14). */
export interface GpuRenderStage {
    /** Stage name (`vertex_shading`, `fragment_shading`, `compute`, …). */
    stage: string;
    /** Aggregated duration on the GPU in ns. */
    durNs: number;
    /** Optional process attribution. */
    process?: string;
    /** Vendor-specific bucket (Mali / Adreno / PowerVR). */
    vendorBucket?: string;
}
/** SurfaceFlinger composition outcome row. */
export interface SurfaceFlingerComposition {
    vsyncId: number;
    ts: number;
    /** Whether HWC took the layer or composition fell back to GPU. */
    hwcFallback?: boolean;
    /** Whether buffer-stuffing was detected. */
    bufferStuffing?: boolean;
    /** Total composition duration on SF main thread (ns). */
    compositionDurNs?: number;
    /** Number of layers composited. */
    layerCount?: number;
}
/** GPU memory snapshot (Spark #14). */
export interface GpuMemorySnapshot {
    ts: number;
    process?: string;
    bytes: number;
    bucket?: string;
}
/** Vendor profiler import (Spark #65, #66, #106, #107). */
export interface GpuProfilerImport {
    /** Source kind: AGI / Mali / Snapdragon / PowerVR / GameBench. */
    kind: 'agi' | 'mali' | 'snapdragon' | 'powervr' | 'gamebench' | string;
    artifactId?: string;
    /** Time window covered by the import. */
    range?: NsTimeRange;
    /** Brief summary string. */
    summary?: string;
}
/**
 * GpuSurfaceFlingerContract (Plan 16)
 *
 * Joint root-cause contract for GPU + SurfaceFlinger + composition. Skills
 * fill in only the facets they trust; the remainder must use
 * `unsupportedReason` rather than zero-fill.
 */
export interface GpuSurfaceFlingerContract extends SparkProvenance {
    range: NsTimeRange;
    renderStages?: GpuRenderStage[];
    surfaceFlingerCompositions?: SurfaceFlingerComposition[];
    gpuMemory?: GpuMemorySnapshot[];
    vendorProfilerImports?: GpuProfilerImport[];
    /** Latency snapshot from `dumpsys SurfaceFlinger --latency` (Spark #46). */
    surfaceFlingerLatency?: {
        layerName: string;
        framesAnalyzed: number;
        p95DesiredPresentNs: number;
        droppedFrames: number;
    };
    coverage: SparkCoverageEntry[];
}
/** Startup phase identifier (mirrors `android.startup.startups` stdlib). */
export type StartupPhase = 'process_create' | 'application_create' | 'first_activity_create' | 'first_frame' | 'reportFullyDrawn' | string;
/** Per-phase startup attribution row. */
export interface StartupPhaseRow {
    phase: StartupPhase;
    range: NsTimeRange;
    /** ART/JIT/dex2oat dur if known (Spark #132). */
    artVerifierDurNs?: number;
    jitDurNs?: number;
    classLoadingDurNs?: number;
    /** Compose recomposition storms during the phase (Spark #68). */
    recompositionCount?: number;
    /** App Startup library initializers fired (Spark #69). */
    initializersFired?: string[];
    evidence?: SparkEvidenceRef;
}
/** ANR attribution from `traces.txt` (Spark #49) merged with trace evidence. */
export interface AnrAttribution {
    process: string;
    /** ANR detection ts. */
    ts: number;
    /** Threads sampled in `traces.txt` snapshot. */
    threadSamples?: Array<{
        threadName: string;
        state: string;
        /** Top frame ids referencing the method-trace graph. */
        topFrames?: string[];
    }>;
    /** Why the ANR fired (input dispatch timeout, broadcast timeout, …). */
    reason?: string;
    /** Evidence link to method-trace graph. */
    methodTraceEvidence?: SparkEvidenceRef;
}
/**
 * Method-trace graph row (Spark #72, #78). Method-trace inputs come from
 * Matrix / BTrace / RheaTrace / KOOM or from bytecode instrumentation.
 */
export interface MethodTraceNode {
    id: string;
    method: string;
    /** Flat self-time across the window (ns). */
    selfNs: number;
    /** Total time including children (ns). */
    totalNs: number;
    /** Child node ids. */
    children?: string[];
    /** Source SDK that emitted the node. */
    source?: 'matrix' | 'btrace' | 'rheatrace' | 'koom' | 'bytecode' | string;
}
/**
 * StartupAnrMethodGraphContract (Plan 17)
 *
 * Combines startup decision tree, ANR attribution, and method-trace graph.
 * Skills can populate any subset; missing facets must surface as
 * `unsupportedReason`.
 */
export interface StartupAnrMethodGraphContract extends SparkProvenance {
    range: NsTimeRange;
    /** Startup phase rows (Spark #32, #68, #69, #132). */
    startupPhases?: StartupPhaseRow[];
    /** ANR attributions (Spark #33, #49). */
    anrAttributions?: AnrAttribution[];
    /** Method-trace nodes (Spark #72, #78). */
    methodTraceGraph?: MethodTraceNode[];
    /** Optional decision-tree summary mirroring jank tree shape. */
    decisionTree?: JankDecisionNode;
    coverage: SparkCoverageEntry[];
}
/** Single eval case fixture row. */
export interface SkillEvalCase {
    /** Stable case id (`scrolling/jank/heavy_mixed`). */
    caseId: string;
    /** Path to the trace under test (relative to repo root). */
    tracePath: string;
    /** Composite skill or sub-agent under test. */
    skillId: string;
    /** Human-readable scenario description. */
    description?: string;
    /** Source of the ground truth (manual annotation, recorded baseline). */
    groundTruthSource?: string;
}
/** Ground-truth assertion against a Skill output. */
export interface SkillEvalAssertion {
    /** Path expression into the Skill output (`$.diagnostics[0].reason_code`). */
    path: string;
    /** Expected value or matcher description. */
    expected: string;
    /** Tolerance for numeric comparisons (absolute or fraction). */
    tolerance?: number;
    /** Why this assertion matters (root-cause label, missing-data signal). */
    rationale?: string;
}
/** Single run of an eval case. */
export interface SkillEvalRunResult {
    caseId: string;
    /** When the run was executed (epoch ms). */
    ranAt: number;
    /** Exit status. */
    status: 'pass' | 'fail' | 'flaky' | 'skipped';
    /** Number of assertions that passed. */
    assertionsPassed: number;
    /** Number of assertions that failed. */
    assertionsFailed: number;
    /** Per-assertion failure messages. */
    failures?: Array<{
        path: string;
        expected: string;
        actual: string;
    }>;
    /** Wall-clock duration in ms. */
    durationMs?: number;
}
/** Sub-agent expansion entry for the harness (Spark #87). */
export interface SubAgentSpec {
    /** Stable sub-agent id (`scrolling-expert`, `binder-expert`). */
    id: string;
    /** Domain it specializes in. */
    domain: string;
    /** Mandatory eval cases for this sub-agent. */
    evalCases: string[];
}
/**
 * DomainSkillEvalContract (Plan 18)
 *
 * Schema for the eval harness that gates every domain Skill change. The
 * regression command (`npm run test:scene-trace-regression`) materialises
 * `SkillEvalRunResult[]` against the cases listed here.
 */
export interface DomainSkillEvalContract extends SparkProvenance {
    cases: SkillEvalCase[];
    /** Mapping from caseId → list of assertions. */
    assertions: Record<string, SkillEvalAssertion[]>;
    /** Sub-agent specifications referencing the cases above. */
    subAgents?: SubAgentSpec[];
    /** Latest run results for the contract. */
    runs?: SkillEvalRunResult[];
    /** External importer hooks (atrace, simpleperf, bpftrace, macrobenchmark). */
    importers?: Array<{
        /** `atrace | simpleperf | bpftrace | macrobenchmark | microbenchmark`. */
        kind: string;
        /** Whether the importer is required for the harness. */
        required: boolean;
        /** Brief description. */
        note?: string;
    }>;
    coverage: SparkCoverageEntry[];
}
/**
 * One indexed knowledge chunk in the RAG store.
 *
 * License is required at ingestion when `kind` is `aosp` or `oem_sdk`; the
 * Plan 55 ingester rejects those chunks if license is missing. For other
 * kinds (blog, project_memory, world_memory, case_library) license is
 * optional because the source has its own implicit policy.
 */
export interface RagChunk {
    /** Stable chunk id (sha-256 prefix of source + offset). */
    chunkId: string;
    /** Source kind — uses the strict enum from shared base types. */
    kind: RagSourceKind;
    /** Original URL or local path. */
    uri: string;
    /** Display title of the parent document. */
    title?: string;
    /** Tokenized snippet shown to the LLM. */
    snippet: string;
    /** Embedding vector if the ingester produced one. Length is model-specific. */
    embedding?: number[];
    /** Raw token count of the snippet (for context budgeting). */
    tokenCount?: number;
    /**
     * License of the source. Required for `aosp` / `oem_sdk` kinds.
     * Optional otherwise — see comment above.
     */
    license?: string;
    /** When the chunk was indexed (epoch ms). */
    indexedAt: number;
    /** Author or curator. */
    author?: string;
    /** When the source was last verified fresh (epoch ms). */
    verifiedAt?: number;
    /**
     * Why this chunk is unavailable for retrieval, e.g. `'license expired'`,
     * `'consent revoked'`, `'source 404'`. When set, retrieval must skip the
     * chunk but the entry stays for audit so previous citations remain
     * traceable.
     */
    unsupportedReason?: string;
    /** Path relative to the registered codebase root, when this chunk is source-backed. */
    filePath?: string;
    /** 1-based source line range covered by this chunk. */
    lineRange?: {
        start: number;
        end: number;
    };
    /** Primary symbol/function/class represented by the chunk. */
    symbol?: string;
    /** Best-effort language tag for source-backed chunks. */
    language?: 'cpp' | 'c' | 'java' | 'kotlin' | 'rust' | 'go' | 'py' | 'unknown';
    /** Pinned source commit, when available. */
    commitHash?: string;
    /** Vendor tag for kernel/OEM sources. */
    vendor?: string;
    /** Build-id or equivalent artifact identity used to pin symbolization. */
    buildId?: string;
    /** Registered codebase id for user-configured source chunks. */
    codebaseId?: string;
    /** Origin that decides legacy-vs-codebase filtering. Missing old values are backfilled by RagStore. */
    registryOrigin?: 'codebase_registry' | 'legacy_plan55' | 'plan44_memory' | 'plan54_cases';
}
/** A single retrieval hit — supports per-hit missing-data paths. */
export interface RagRetrievalHit {
    chunkId: string;
    /** Similarity score 0..1. */
    score: number;
    /** Optional when the hit could not be materialized at retrieval time. */
    chunk?: RagChunk;
    /**
     * Why this hit could not be materialized, e.g. `'chunk evicted'`,
     * `'license blocked at retrieval time'`. When set, `chunk` is expected to
     * be undefined and the agent must not invent content.
     */
    unsupportedReason?: string;
}
/**
 * Output of a single retrieval call. Carries provenance so consumers can
 * audit which kinds were probed and when.
 */
export interface RagRetrievalResult extends SparkProvenance {
    /** The query string used for retrieval. */
    query: string;
    /** Ranked hits — possibly empty if the whole retrieval failed. */
    results: RagRetrievalHit[];
    /** Which source kinds were probed in this retrieval call. */
    probed: RagSourceKind[];
    /** When the retrieval ran (epoch ms). */
    retrievedAt: number;
}
/**
 * AndroidperformanceAospRagContract (Plan 55)
 *
 * Surface of the RAG service. Tracks index population per source kind plus
 * the most recent retrieval result for inline citation by reports.
 */
export interface AndroidperformanceAospRagContract extends SparkProvenance {
    /** Number of chunks per source kind currently indexed. */
    index: Record<RagSourceKind, {
        chunkCount: number;
        lastIndexedAt?: number;
    }>;
    /** Sample retrieval result attached when the contract is emitted via MCP. */
    lastRetrieval?: RagRetrievalResult;
    coverage: SparkCoverageEntry[];
}
/**
 * Per-metric aggregate within a baseline. Numeric fields ignore meaning
 * when `unsupportedReason` is set — this keeps missing-data paths explicit
 * (e.g. metric not collected on this device, sample count below threshold).
 */
export interface BaselineMetric {
    /** Reuses TraceSummaryMetric.metricId namespace, e.g. `frames.jank_count.p95`. */
    metricId: string;
    /** Unit string: `ns` | `ms` | `count` | `percent` | `bytes`. */
    unit: string;
    median: number;
    p95: number;
    p99: number;
    max: number;
    /** Sample count contributing to this metric. */
    sampleCount: number;
    /** Optional ns range when bounded to a window. */
    range?: NsTimeRange;
    /**
     * Why this metric is unavailable for this baseline. When set, consumers
     * must ignore the numeric fields above.
     */
    unsupportedReason?: string;
}
/**
 * A baseline is a curated aggregate over N traces matching the same key.
 *
 * Extends `TraceSummaryBaselineRef` (Plan 02) so consumers do not see
 * a parallel `baselineId` / `sampleCount` / `capturedAt` shape. The base
 * type provides those fields; this contract adds curation, redaction,
 * window, and metrics.
 *
 * Note: `sampleCount` is optional via the base type. The Plan 50 service
 * layer (`baselineStore.ts`) enforces `sampleCount >= 3` when status
 * advances to `'published'`. The schema does not enforce that floor so
 * older snapshots remain readable.
 */
export interface BaselineRecord extends SparkProvenance, TraceSummaryBaselineRef {
    key: PerfBaselineKey;
    status: CurationStatus;
    /**
     * Redaction state. Must be `'redacted'` when published AND `key` carries
     * identifiable info (raw appId/deviceId). When the key is anonymized at
     * capture time, `'raw'` is acceptable for `published` status.
     */
    redactionState: 'raw' | 'partial' | 'redacted';
    /** First trace timestamp in the baseline window (epoch ms). */
    windowStartMs: number;
    /** Last trace timestamp in the baseline window (epoch ms). */
    windowEndMs: number;
    metrics: BaselineMetric[];
    /** Optional pointer to the SoC/OEM matrix this baseline belongs to. */
    matrixId?: string;
    /** Notes from the curator (manual annotation). */
    curatorNote?: string;
}
/**
 * Per-metric delta entry — supports missing-data paths via
 * `unsupportedReason`. When severity is `'unsupported'`, callers must
 * ignore the numeric fields.
 */
export interface BaselineDiffDelta {
    metricId: string;
    unit: string;
    /** Numeric fields are optional so missing-data paths remain visible. */
    baseValue?: number;
    candidateValue?: number;
    deltaAbs?: number;
    deltaPct?: number;
    /** Detected regression severity. `unsupported` when delta cannot be computed. */
    severity: 'none' | 'info' | 'warning' | 'regression' | 'unsupported';
    /**
     * Why this delta could not be computed, e.g. `'missing on baseline'`,
     * `'sample count below 3'`, `'divide-by-zero'`. Required when severity
     * is `'unsupported'`.
     */
    unsupportedReason?: string;
}
/** Diff between two baselines (or trace-vs-baseline). */
export interface BaselineDiffArtifact extends SparkProvenance {
    baseBaselineId: string;
    /** Either another baseline or a single trace under analysis. */
    candidate: {
        kind: 'baseline';
        id: string;
    } | {
        kind: 'trace';
        traceId: string;
    };
    deltas: BaselineDiffDelta[];
    /** Top contributors to the largest regressions, ordered worst-first. */
    topRegressions?: Array<{
        metricId: string;
        deltaPct: number;
        evidence?: SparkEvidenceRef;
    }>;
}
/**
 * Regression gate output for CI integration (Spark #105).
 *
 * `diff` is optional when `status` is `'skipped'` — earlier drafts forced
 * a meaningless diff for skipped gates. The skipped gate must instead
 * record `skipReason` so triagers can audit why the gate did not run.
 */
export interface RegressionGateResult extends SparkProvenance {
    /** Stable gate id, e.g. `ci-pr-12345`. */
    gateId: string;
    baselineId: string;
    status: 'pass' | 'fail' | 'flaky' | 'skipped';
    /** Diff that drove the decision. Optional only when status is `'skipped'`. */
    diff?: BaselineDiffArtifact;
    /** Why the gate was skipped (only when status='skipped'). */
    skipReason?: string;
    /** Threshold rule that triggered (when status is `'fail'`). */
    rule?: {
        metricId: string;
        threshold: number;
        observed: number;
    };
}
/**
 * BaselineStoreContract (Plan 50)
 *
 * Surface of the durable baseline store. Lists all baselines with
 * optional cross-baseline matrix descriptors for SoC/OEM comparison.
 */
export interface BaselineStoreContract extends SparkProvenance {
    baselines: BaselineRecord[];
    /** Cross-baseline matrices for SoC/OEM/build comparison (Spark #177, #178). */
    matrix?: Array<{
        matrixId: string;
        baselineIds: string[];
        description?: string;
    }>;
    coverage: SparkCoverageEntry[];
}
/**
 * Status state for memory entries.
 *
 * **MUST stay in sync** with `PatternStatus` in
 * `backend/src/agentv3/types.ts`. The two unions are intentionally
 * duplicated here to keep `backend/src/types/` independent of
 * `backend/src/agentv3/` (existing layer rule — only agentv3 imports from
 * types, not the reverse). When the agentv3 union changes, mirror the
 * change here.
 *
 * - `provisional` — freshly saved, no feedback yet
 * - `confirmed` — positive feedback OR auto-promoted after 24h without negatives
 * - `rejected` — user explicitly rejected the conclusion
 * - `disputed` — reverse feedback within 10s–24h window
 * - `disputed_late` — reverse feedback >24h after first feedback
 */
export type ProjectMemoryStatus = 'provisional' | 'confirmed' | 'rejected' | 'disputed' | 'disputed_late';
/**
 * A memory entry scoped to project or world.
 *
 * Session-scope entries stay in `analysisPatternMemory.ts` (existing
 * 200-entry store with weighted Jaccard + supersede integration); this
 * contract is NOT used for session entries. Project + world entries live
 * in the new Plan 44 `projectMemory.ts` store.
 */
export interface ProjectMemoryEntry {
    /** Stable entry id (sha-256 prefix). */
    entryId: string;
    /** `'project'` or `'world'` — never `'session'`. */
    scope: MemoryScope;
    /** Stable project key — typically appId or appId+device. */
    projectKey?: string;
    /** Tag fingerprint (reuses analysisPatternMemory's tag taxonomy). */
    tags: string[];
    /** The recorded insight. */
    insight: string;
    /** Confidence 0..1. */
    confidence: number;
    /** Status — reuses the existing 5-state machine including `disputed_late`. */
    status: ProjectMemoryStatus;
    /** Hop count up the scope ladder (project → world consolidation). */
    promotionLevel?: number;
    /**
     * Promotion policy that authorized this entry's current scope.
     *
     * **Required** for any entry whose `scope` is `'world'` — the Plan 44
     * service layer (`projectMemory.saveProjectMemoryEntry`) must throw
     * when a world entry is saved without a policy. Optional on `project`
     * entries that were created directly (not promoted).
     */
    promotionPolicy?: MemoryPromotionPolicy;
    evidence?: SparkEvidenceRef[];
    createdAt: number;
    lastSeenAt?: number;
    /**
     * Why this entry is unavailable for retrieval. When set, recall and
     * RAG retrieval must skip this entry but the row stays for audit.
     */
    unsupportedReason?: string;
}
/**
 * Feedback → case → skill draft pipeline state (Spark #95).
 *
 * Tracks the lifecycle of a feedback signal as it gets enriched into a
 * case draft, then a skill draft, then reviewed and merged or rejected.
 */
export interface FeedbackPipelineEntry {
    entryId: string;
    /** Source feedback id (in selfImprove/feedbackEnricher). */
    feedbackId: string;
    /** Stage in the pipeline. */
    stage: 'feedback' | 'case_draft' | 'skill_draft' | 'reviewed' | 'merged' | 'rejected';
    /**
     * Reference to the case generated by this feedback. Uses the shared
     * `CaseRef` from base types so this contract does not depend on
     * Plan 54's CaseNode shape (breaks the #44 ↔ #54 schema cycle).
     */
    case?: CaseRef;
    /** Generated skill draft id, if any. */
    skillDraftId?: string;
    /** Reviewer name when stage advances to reviewed/merged/rejected. */
    reviewer?: string;
    /** When the pipeline last advanced (epoch ms). */
    updatedAt: number;
}
/**
 * MemoryRagSelfImprovementContract (Plan 44)
 *
 * Surface of the project memory + RAG + self-improvement layer. Sits
 * alongside the existing session-scope `analysisPatternMemory.ts`.
 *
 * Storage location for project + world entries:
 * `backend/logs/analysis_project_memory.json` with shape
 * `{entries: ProjectMemoryEntry[], promotionAudit: ...}` (see Plan 44
 * §4.3 in the design doc for the audit log layout).
 */
export interface MemoryRagSelfImprovementContract extends SparkProvenance {
    /** Project + world memory entries (session entries stay elsewhere). */
    entries: ProjectMemoryEntry[];
    /** Active feedback pipeline entries. */
    pipeline: FeedbackPipelineEntry[];
    /** Optional retrieval cache populated by the orchestrator. */
    recentRetrievals?: RagRetrievalResult[];
    coverage: SparkCoverageEntry[];
}
/**
 * Educational level used by the case browser (Spark #162).
 *
 * Drives default filters for the public case library and the "导览模式"
 * walkthrough — junior developers see novice-tagged cases first.
 */
export type CaseEducationalLevel = 'novice' | 'intermediate' | 'advanced';
/**
 * Severity of a finding linked to a case node. Mirrors the lightweight
 * severity vocabulary used across SmartPerfetto reports.
 */
export type CaseFindingSeverity = 'info' | 'warning' | 'critical';
/**
 * One finding link inside a case node — the analyst's claim about the
 * underlying trace, with optional evidence pointer.
 */
export interface CaseFindingLink {
    /** Stable finding id. */
    id: string;
    severity: CaseFindingSeverity;
    /** Short human-readable title. */
    title: string;
    evidence?: SparkEvidenceRef;
}
/**
 * A single case = curated trace + analysis snapshot + curation metadata.
 *
 * Publishing gate is double-controlled: a case can be `status='published'`
 * only when `redactionState='redacted'` AND `curatedBy` is set
 * (a curator has signed off). Anonymizer alone is not enough — see
 * §5.2 in the design doc for the boundary.
 */
export interface CaseNode extends SparkProvenance {
    caseId: string;
    /** Title for the browsing UI. */
    title: string;
    /** Curation status — uses `CurationStatus` from base types. */
    status: CurationStatus;
    /** Composite key matching the baseline namespace (when applicable). */
    key?: PerfBaselineKey;
    /**
     * Anonymization state. Tracked separately from `status` so an
     * in-review case can move toward redaction without flipping the
     * curation lifecycle.
     */
    redactionState: 'raw' | 'partial' | 'redacted';
    /**
     * Pointer to the original trace artifact (or anonymized copy when
     * published). Optional because archived / consent-revoked cases stay
     * in the library as read-only metadata. See `traceUnavailableReason`.
     */
    traceArtifactId?: string;
    /**
     * Why the trace artifact is unavailable, e.g. `'archived after 90 days'`,
     * `'evicted from artifact store'`, `'consent revoked'`. When set,
     * `traceArtifactId` may be undefined and consumers must treat the
     * case as read-only metadata.
     */
    traceUnavailableReason?: string;
    /** Pointer to the analysis report artifact. */
    reportArtifactId?: string;
    /** Tags for category filtering. */
    tags: string[];
    /** Linked findings — top-level claim ids. */
    findings: CaseFindingLink[];
    /** Curator name (required for `status='published'`). */
    curatedBy?: string;
    /** When curated (epoch ms). */
    curatedAt?: number;
    /** Educational level (Spark #162). */
    educationalLevel?: CaseEducationalLevel;
}
/**
 * A relation between two cases in the case graph.
 *
 * Edges are directional — the relation often is too (e.g.
 * `before_after_fix` from old to fixed case). Symmetric relations
 * (`similar_root_cause`) should be stored once with a documented
 * "canonical from-side" rule rather than mirrored.
 */
export interface CaseEdge {
    edgeId: string;
    fromCaseId: string;
    toCaseId: string;
    /** Relation kind. The string union below lists the canonical relations. */
    relation: 'similar_root_cause' | 'same_app' | 'same_device' | 'before_after_fix' | 'derived_pattern' | 'contradicts' | string;
    /** Confidence 0..1. */
    weight?: number;
    /** Free-form note from the curator. */
    note?: string;
}
/**
 * CaseGraphLibraryContract (Plan 54)
 *
 * Surface of the case library + graph. `lastPublishedAt` is set when the
 * library is exported as a public bundle (Spark #180); private and
 * draft cases never affect this timestamp.
 */
export interface CaseGraphLibraryContract extends SparkProvenance {
    cases: CaseNode[];
    edges: CaseEdge[];
    /** When the library was last exported as a public bundle (Spark #180). */
    lastPublishedAt?: number;
    coverage: SparkCoverageEntry[];
}
/**
 * Tool exposure level. Drives whether external hosts (Claude Code,
 * Cursor, Codex via stdio) and remote A2A peers see the tool.
 *
 * - `public` — safe for any host.
 * - `public-readonly` — externally visible read-only metadata tool.
 * - `internal` — agentv3 protocol tools (plan / hypothesis / note
 *   updates). Writing them from an external host would corrupt the
 *   active session.
 * - `requires_codebase_permission` — only visible inside a request/session
 *   with codebase permission; never exposed via stdio/A2A.
 * - `deprecated` — kept for compatibility, hidden from public surface.
 */
export type McpToolExposure = 'public' | 'public-readonly' | 'internal' | 'requires_codebase_permission' | 'deprecated';
/**
 * ACI — Agent-Callable Interface descriptor (Spark #96).
 *
 * One per tool. Used by the standalone MCP server to advertise tools
 * to external hosts and by the SDK adapter to construct `allowedTools`
 * lists.
 */
export interface McpToolAci {
    /** Short name as registered in `mcpToolRegistry`, e.g. `invoke_skill`. */
    toolName: string;
    /** Fully qualified name with SDK prefix, e.g. `mcp__smartperfetto__invoke_skill`. */
    qualifiedName: string;
    exposure: McpToolExposure;
    /** Brief description for agent system prompts. */
    summary: string;
    /** JSON-schema fragment for the input args (Zod-derived in practice). */
    inputSchema?: unknown;
    /** Example payloads pulled from the existing tool description. */
    examples?: Array<{
        args: unknown;
        expected?: unknown;
    }>;
    /** Required env vars or capability flags, e.g. `['traceProcessor']`. */
    requires?: string[];
}
/**
 * A2A AgentCard descriptor (Spark #92).
 *
 * Advertises the SmartPerfetto agent's capabilities to remote callers.
 * `trustLevel` controls the handshake required before tool calls are
 * accepted; `private` cards require a signed key exchange before any
 * exposed tool is callable from the remote peer.
 */
export interface A2aAgentCard {
    /** Stable card id, e.g. `smartperfetto-perf-analyst`. */
    cardId: string;
    /** Display name shown in remote agent UIs. */
    displayName: string;
    /** Capabilities advertised to remote callers. */
    capabilities: string[];
    /** Trust level — `public` (open) | `partner` (signed) | `private` (handshake). */
    trustLevel: 'public' | 'partner' | 'private';
    /** Subset of the `McpToolAci.toolName` set exposed via A2A. */
    tools: string[];
    /** Public key fingerprint for `partner` / `private` cards. */
    publicKey?: string;
}
/**
 * McpPublicApiContract (Plan 41)
 *
 * Surface of the standalone MCP server + A2A capabilities. Lists every
 * registered tool with its ACI plus any active A2A agent cards.
 */
export interface McpPublicApiContract extends SparkProvenance {
    /** Every tool registered in `mcpToolRegistry`, regardless of exposure. */
    tools: McpToolAci[];
    /** A2A agent cards — empty when A2A is disabled (default). */
    agentCards?: A2aAgentCard[];
    /** Server semver. */
    serverVersion: string;
    /** MCP protocol version the server speaks. */
    protocolVersion: string;
    coverage: SparkCoverageEntry[];
}
/** Build a fresh provenance block for new contract objects. */
export declare function makeSparkProvenance(opts: {
    source: string;
    schemaVersion?: number;
    unsupportedReason?: string;
    notes?: string;
}): SparkProvenance;
/** Quick guard for "did the producer flag this contract as unsupported?". */
export declare function isUnsupported(contract: SparkProvenance): boolean;
//# sourceMappingURL=sparkContracts.d.ts.map