/** * Session footprint — the "how degraded is this session" sensor * (docs/proposals/session-regen-and-footprint.md §11). * * Control-plane only by construction: every axis is answered from CMS * aggregates, persisted metric summaries, and orchestration runtime stats — * computing a footprint never wakes a dehydrated session. * * The context/compaction counters are DERIVED from persisted SDK transcript * events (`session.usage_info`, `session.compaction_start/_complete` — none * of which are in the ephemeral filter), using the type-scoped event index. * Definitions (per the proposal): * - compactionCount completes observed this epoch * - compactionGeneration summaries-of-summaries depth. Under infinite * sessions the transcript permanently contains a * summary after the first compaction, so every * subsequent compaction's input includes one: * generation = max(0, completes - 1). * - failedOrStuck explicitly failed completes + a stuck trailing start * - unknownCompactions starts with no recorded complete. NOT failures: * the CLI frequently omits the complete event even * when the compaction succeeded. * - sustained utilization the last SUSTAINED_WINDOW usage readings all * above the threshold — never a single reading. */ import type { SessionCompactionStats, SessionEventStats, SessionMetricSummary } from "./cms.js"; export declare const FOOTPRINT_UTILIZATION_ELEVATED = 0.7; export declare const FOOTPRINT_UTILIZATION_DEGRADED = 0.85; export declare const FOOTPRINT_SUSTAINED_WINDOW = 3; export declare const FOOTPRINT_GENERATION_DEGRADED = 2; export declare const FOOTPRINT_EVENTS_PRUNE_BYTES: number; export declare const FOOTPRINT_CACHE_TTL_MS = 15000; /** An unmatched compaction start younger than this is RUNNING, not stuck. */ export declare const FOOTPRINT_STUCK_COMPACTION_MS: number; /** Sweep threshold: entries are pruned on write once the cache exceeds this. */ export declare const FOOTPRINT_CACHE_SWEEP_SIZE = 512; export type FootprintLevel = "ok" | "elevated" | "degraded" | "rebuilding"; export type FootprintRecommendation = "none" | "regenerate" | "prune-events"; export interface SessionFootprint { sessionId: string; transcriptEpoch: number; regenCount: number; epochAgeDays: number | null; turnsThisEpoch: number | null; context: { tokenLimit: number | null; currentTokens: number | null; utilization: number | null; /** True when the last SUSTAINED_WINDOW readings all exceed the degraded threshold. */ sustainedHighUtilization: boolean; compactionCount: number; compactionGeneration: number; tokensRemovedCumulative: number; failedOrStuckCompactions: number; /** Starts with no recorded complete — the CLI often omits the event, so these are UNKNOWN outcomes, not failures. */ unknownCompactions: number; }; transcript: { snapshotSizeBytes: number | null; rawSizeBytes: number | null; }; events: { count: number; bytes: number; maxSeq: number; sinceEpochStart: number; }; facts: { count: number; bytes: number; } | null; children: { descendantCount: number; } | null; orchestration: { historyEventCount?: number; historySizeBytes?: number; queuePendingCount?: number; orchestrationVersion?: string; } | null; /** Regen eligibility read model (§10.2). Advisory; the cmd handler is the authority. */ regenEligibility: { eligible: boolean; reason?: string; }; assessment: { level: FootprintLevel; reasons: string[]; recommendation: FootprintRecommendation; }; computedAt: number; } /** Structural dependencies — satisfied by ManagementClient's catalog + helpers. */ export interface FootprintSources { getSession(sessionId: string): Promise<{ createdAt?: number | Date | null; currentIteration?: number | null; transcriptEpoch?: number | null; lastRegeneratedAt?: number | Date | null; } | null>; getSessionEventStats(sessionId: string, afterSeq?: number): Promise; getSessionCompactionStats(sessionId: string, afterSeq?: number): Promise; /** Reverse-ordered read of typed events (existing getSessionEventsBefore proc). */ getSessionEventsBefore(sessionId: string, beforeSeq: number, limit?: number, eventTypes?: string[]): Promise>; getSessionMetricSummary(sessionId: string): Promise; getDescendantSessionIds?(sessionId: string): Promise; getSessionFactsStats?(sessionId: string): Promise<{ totalCount: number; totalBytes: number; }>; getOrchestrationStats?(sessionId: string): Promise | null>; /** * Epoch boundary seq (the session.epoch_committed event) when the session * has regenerated. Absent/0 → epoch 0, whole-session axes. Wired in M1. */ getEpochBoundarySeq?(sessionId: string): Promise; } /** * Compute a session's footprint. `notFoundOk` is false: callers should have * resolved the session first; a missing session throws. */ export declare function computeSessionFootprint(sources: FootprintSources, sessionId: string): Promise; export declare class FootprintCache { private readonly ttlMs; private readonly entries; constructor(ttlMs?: number); get(sessionId: string): SessionFootprint | null; set(footprint: SessionFootprint): void; clear(): void; } //# sourceMappingURL=footprint.d.ts.map