/** * Local placement plan / doctor report — SP-216, #116 (Colibri plan/doctor analog). * * Builds a READ-ONLY operator report describing local placement readiness: * encoder resident status, local model warm/cold, RAM/disk constraints, * cold vs warm throughput, and a bottleneck guess. Never mutates routes, * pins, gates, or any runtime state. * * JSON-stable shape (schemaVersion 1): all keys always present; unknown * values are `null`, never omitted. Safe for automation. * * Quality-preserving policy: under resource pressure this module prefers * reporting "local unavailable / escalate safely" over silently weakening * encoder fidelity or inventing cheaper cascades. */ import { type HardwareProbeConfig, type HardwareProbeResult, type SystemInfo, type SystemInfoPort } from './hardware-probe.js'; import { type HttpFetchPort, type LocalReadinessResult, type LocalZeroTierConfig, type ServicePingResult } from '../local/local-zero-tier.js'; import { type LocalViabilityPolicy, type ThroughputBreakdown, type ThroughputMeter } from './throughput-meter.js'; export declare const PLACEMENT_PLAN_SCHEMA_VERSION: 1; export declare const PLACEMENT_PLAN_KIND: "smart-router-placement-plan"; /** Below this much free disk (GiB) the report flags disk as constrained. */ export declare const DISK_CONSTRAINED_FREE_GB = 2; /** * Mirrors DEFAULT_OPERATOR_CONFIG.local; duplicated here so this module stays * a leaf import (no config/defaults dependency chain). */ export declare const DEFAULT_PLACEMENT_HARDWARE_CONFIG: Readonly; export declare const DEFAULT_ENCODER_CACHE_PATH = ".pi-smart-router/models/"; export declare const DEFAULT_ENCODER_MODEL = "Xenova/all-MiniLM-L6-v2"; export declare const QUALITY_POLICY_NOTES: readonly string[]; export type BottleneckGuess = 'none' | 'unsupported-platform' | 'battery' | 'memory' | 'disk' | 'no-local-runtime' | 'cold-start' | 'cold-throughput' | 'warm-throughput'; export type PlacementRecommendation = 'local-ready' | 'local-warmup-needed' | 'local-unavailable'; export interface PlacementPlanReport { readonly schemaVersion: typeof PLACEMENT_PLAN_SCHEMA_VERSION; readonly kind: typeof PLACEMENT_PLAN_KIND; readonly generatedAt: string; /** This report never mutates routing state. */ readonly readOnly: true; readonly encoder: { readonly resident: boolean; readonly model: string; readonly cachePath: string; readonly detail: string; }; readonly localModel: { /** A local model is loaded in LM Studio or Ollama right now. */ readonly warm: boolean; /** Runtime reachable but no model loaded — first request pays load cost. */ readonly coldStartExpected: boolean; readonly lmStudio: ServicePingResult; readonly ollama: ServicePingResult; }; readonly hardware: { readonly platform: string; readonly arch: string; readonly totalMemoryGb: number; readonly freeMemoryGb: number | null; readonly probe: HardwareProbeResult; readonly batteryLevelPct: number | null; readonly isOnAcPower: boolean | null; }; readonly disk: { readonly path: string; readonly freeGb: number | null; readonly constrained: boolean; }; readonly throughput: { readonly classification: ThroughputBreakdown['classification']; readonly warmMedianTps: number | null; readonly coldMedianTps: number | null; readonly warmSamples: number; readonly coldSamples: number; readonly thresholdTps: number; readonly requireWarmSamples: boolean; readonly viable: boolean; }; readonly bottleneck: { readonly guess: BottleneckGuess; readonly rationale: string; }; readonly policy: { readonly qualityPreserving: true; readonly onResourcePressure: 'report-local-unavailable-and-escalate'; readonly notes: readonly string[]; }; readonly recommendation: PlacementRecommendation; } export interface PlacementPlanInputs { readonly systemInfo: SystemInfo; readonly freeMemoryGb: number | null; readonly hardwareProbe: HardwareProbeResult; readonly hardwareConfig: HardwareProbeConfig; readonly localReadiness: LocalReadinessResult; readonly encoderResident: boolean; readonly encoderModel: string; readonly encoderCachePath: string; readonly diskPath: string; readonly diskFreeGb: number | null; readonly throughput: ThroughputBreakdown | null; readonly throughputThresholdTps: number; readonly viabilityPolicy: LocalViabilityPolicy; /** Injectable clock for deterministic tests. */ readonly generatedAt?: string; } /** Port for filesystem / OS probes — injectable for tests. */ export interface PlacementPlanSystemPort { /** True when the directory exists and contains at least one entry. */ dirHasEntries(path: string): boolean; /** Free disk in GiB for the filesystem containing path; null when unknown. */ freeDiskGb(path: string): number | null; /** Free system memory in GiB. */ freeMemoryGb(): number; } export declare const defaultPlacementPlanSystemPort: PlacementPlanSystemPort; /** Cold/warm viability formula — see throughput-meter.ts docblock. */ export declare function isThroughputViable(breakdown: ThroughputBreakdown, thresholdTps: number, policy: LocalViabilityPolicy): boolean; /** * Build the read-only placement report from already-collected inputs. * Pure: no I/O, no mutation — safe to call anywhere. */ export declare function buildPlacementPlan(inputs: PlacementPlanInputs): PlacementPlanReport; export interface CollectPlacementPlanDeps { readonly systemInfoPort?: SystemInfoPort; readonly httpFetch?: HttpFetchPort; readonly localConfig?: LocalZeroTierConfig; readonly hardwareConfig?: HardwareProbeConfig; readonly throughputMeter?: ThroughputMeter; readonly viabilityPolicy?: LocalViabilityPolicy; readonly throughputThresholdTps?: number; readonly encoderModel?: string; readonly encoderCachePath?: string; readonly diskPath?: string; readonly systemPort?: PlacementPlanSystemPort; readonly now?: () => Date; } /** * Collect live placement inputs and build the report. Read-only: performs * readiness pings and filesystem stats only; never mutates routing state. */ export declare function collectPlacementPlan(deps?: CollectPlacementPlanDeps): Promise; //# sourceMappingURL=placement-plan.d.ts.map