/** * Phenotype Atlas — reference classification (anti-drift defense). * * In addition to profile-based matching (comparing an agent against its own * history), the sensorium maintains a phenotype atlas: reference profiles for * all known agent genomes, populated from experiment data and community * observations. * * Every interaction is classified against the atlas independently of the * agent's own profile history. The question is not "has this agent changed?" * but "what does this agent look like right now?" * * If the current observation is closer to GPT-4o-mini's reference profile * than to Claude's, that's RED — regardless of how the agent's profile * evolved to get there. * * This defeats slow drift poisoning (Attack 7). An attacker who gradually * shifts from Claude to GPT-4o-mini over weeks doesn't trigger drift velocity * alerts — but the atlas classifier says "this looks like GPT-4o-mini" and * flags RED. The check is memoryless and instantaneous, like a biological * immune system checking self vs non-self markers. * * Two independent detection channels work in parallel: * - Behavioral landscape: catches sudden changes (historical, profile-based) * - Phenotype atlas: catches slow drift (memoryless, reference-based) */ import type { FeatureStats } from "./matcher.js"; /** Welford stats used by atlas reference profiles (same as matcher). */ export type WelfordStats = FeatureStats; /** A reference profile for a known genome in the atlas. */ export interface ReferenceProfile { /** The genome hash this profile describes. */ genomeHash: string; /** Human-readable label (e.g., "claude-sonnet-4", "gpt-4o-mini"). */ label: string; /** Per-sense feature statistics. Keys are feature names. */ temporal: Record; topology: Record; vocabulary: Record; /** Total observations that built this profile. */ observationCount: number; } /** Features extracted from a single observation, organized by sense. */ export interface SenseFeatures { temporal: Record; topology: Record; vocabulary: Record; } /** Result of classifying an observation against the atlas. */ export interface AtlasClassification { /** Which reference profile is closest. */ nearestGenome: string; /** Human-readable label of nearest. */ nearestLabel: string; /** Weighted Mahalanobis-like distance to nearest. */ distance: number; /** What the agent claims to be. */ declaredGenome: string; /** Does nearest match declared? */ match: boolean; /** Second-closest genome hash. */ secondNearest: string; /** Second-closest label. */ secondNearestLabel: string; /** Distance to second nearest. */ secondDistance: number; /** Margin = secondDistance - distance. Larger margin = more confident classification. */ margin: number; } /** Sense weights for the weighted classifier. */ export interface SenseWeights { temporal: number; topology: number; vocabulary: number; } export declare const DEFAULT_SENSE_WEIGHTS: SenseWeights; export declare class PhenotypeAtlas { private readonly profiles; private readonly weights; constructor(weights?: SenseWeights); /** Number of reference profiles in the atlas. */ get size(): number; /** Get all genome hashes in the atlas. */ get genomeHashes(): string[]; /** Get a reference profile by genome hash. */ getProfile(genomeHash: string): ReferenceProfile | undefined; /** * Add or update a reference profile in the atlas. * Typically populated from experiment data or community observations. */ setProfile(profile: ReferenceProfile): void; /** * Update a reference profile with a new observation using Welford's algorithm. * Creates the profile if it doesn't exist. */ updateProfile(genomeHash: string, label: string, features: SenseFeatures): void; /** * Classify an observation against the atlas. * * Computes weighted distance to every reference profile and returns * the nearest match. The weighting ensures temporal features (5x) dominate * the classification, with topology (2x) and vocabulary (1x) refining it. * * This is memoryless — it doesn't care about the agent's history, only * what the agent looks like right now. */ classifyObservation(features: SenseFeatures, declaredGenome: string): AtlasClassification; /** Serialize the atlas to a plain object for persistence. */ toJSON(): { profiles: ReferenceProfile[]; weights: SenseWeights; }; /** Restore an atlas from serialized data. */ static fromJSON(data: { profiles: ReferenceProfile[]; weights?: SenseWeights; }): PhenotypeAtlas; } //# sourceMappingURL=atlas.d.ts.map