/** * Hurricane-style name pool for the agent coordination layer. The name-pool * assignment + resolution helpers. * * Layout invariant: 260 entries (10 per starting letter A..Z). Counter N * picks COORD_NAMES[N % 260]; wraps to A at N=260. * * Gender invariant: within each 26-name pass the names alternate female/male * letter by letter, so every pass is 13 female and 13 male. Five passes start * female at A (1, 3, 5, 7, 9) and five start male (2, 4, 6, 8, 10), which gives * each letter exactly five names of each gender and the pool 130/130 overall. * This exists so a fixed set of 13 female and 13 male portraits can dress one * whole pass. Adding or reordering a name must preserve it; the expected * pattern is pinned in tests/unit/names-pool.test.ts. * * Durable persistence: `.harnery/.name-history` (JSONL, one row per assignment) * + `.harnery/.name-counter` (current counter, atomic temp+rename). * * Recreation rule: * 1. Own instance_id in name-history → latest (name, kind, agent_id) * 2. session_id in name-history (owner != session) → latest parent's * (name, agent_id) with kind="transient" * * Multiple rows for one instance are intentional. `identity assume` appends a * new binding instead of rewriting history; readers therefore resolve from the * end of the file. Older one-row histories retain their original behavior. * 3. Else: new assignment, consume a counter slot. * * Live-name skip: the pool holds 260 names and a busy repo consumes ~100 a * day, so the counter wraps roughly every three days while sessions that * resume under a stable instance_id keep a name for far longer. A counter-only * pick therefore hands a live agent's name to a new one (observed 2026-09-06: * two concurrent "Maya" agents, their pool slots exactly 520 apart). Assignment * now probes forward past any name a fresh heartbeat still holds. */ /** All 260 names. */ export declare const COORD_NAMES: readonly ["Anna", "Bob", "Carmen", "Dorian", "Erika", "Fred", "Gemma", "Hank", "Imelda", "Jerry", "Karen", "Lorenzo", "Mindy", "Nate", "Odette", "Peter", "Quinn", "Rafael", "Sara", "Tony", "Ursula", "Vinson", "Whitney", "Xander", "Yara", "Zane", "Alex", "Bertha", "Carlos", "Dalia", "Ernesto", "Francine", "Gordon", "Helene", "Isaias", "Joyce", "Kirk", "Lucia", "Milton", "Nadine", "Oscar", "Patty", "Quentin", "Rebekah", "Sean", "Tammy", "Ulrik", "Valerie", "Wallace", "Xanthe", "Yusuf", "Zara", "Adelaide", "Bruno", "Cora", "Damon", "Edna", "Felix", "Greta", "Hugo", "Ines", "Jasper", "Kaia", "Larry", "Maxine", "Nicholas", "Olive", "Paxton", "Querida", "Roman", "Stella", "Tobias", "Una", "Virgil", "Willow", "Xavier", "Yolanda", "Zephyr", "Aaron", "Beatrice", "Cyrus", "Delia", "Elias", "Florence", "Galileo", "Hester", "Ian", "Jenna", "Klaus", "Linda", "Marco", "Nora", "Otto", "Paulette", "Quill", "Renee", "Sebastian", "Theresa", "Umberto", "Vera", "Walter", "Xena", "Yves", "Zoe", "Anita", "Beau", "Celeste", "Dexter", "Edith", "Fitz", "Gloria", "Hadley", "Iris", "Jude", "Kira", "Leo", "Maya", "Nash", "Olga", "Phillip", "Quetzal", "Royce", "Sage", "Trent", "Uma", "Vincent", "Wynne", "Xerxes", "Yvette", "Zoltan", "Andre", "Bonnie", "Caleb", "Daphne", "Ezra", "Fiona", "Gibson", "Holly", "Ivan", "Juno", "Knox", "Lila", "Mason", "Nila", "Owen", "Petra", "Quincy", "Rosa", "Sterling", "Talia", "Uri", "Violet", "Wesley", "Ximena", "Yuri", "Zelda", "Astrid", "Boris", "Cassidy", "Davis", "Esme", "Forrest", "Genevieve", "Henry", "Imogen", "Joaquin", "Kestrel", "Luther", "Margot", "Nigel", "Ophelia", "Percy", "Quenby", "Reagan", "Sienna", "Truman", "Undine", "Voss", "Wren", "Xan", "Yael", "Zia", "Arthur", "Bianca", "Cody", "Dahlia", "Evander", "Fern", "Gustavo", "Harriet", "Ira", "Josephine", "Kendrick", "Lainey", "Miles", "Naomi", "Orion", "Pearl", "Quark", "Rylie", "Saul", "Tessa", "Ulysses", "Vesper", "Wyatt", "Xiomara", "Yancy", "Zinnia", "Amelia", "Barnaby", "Calliope", "Drake", "Estelle", "Foster", "Greer", "Hollis", "Irene", "Jericho", "Klara", "Logan", "Mavis", "Nico", "Oakley", "Pascal", "Quito", "Rhett", "Scout", "Theron", "Unity", "Vance", "Winifred", "Xola", "Yvonne", "Zev", "Atticus", "Brenda", "Crispin", "Dolores", "Eustace", "Felicity", "Granger", "Hazel", "Idris", "Jovi", "Kasper", "Lyric", "Magnus", "Noor", "Otis", "Phoebe", "Querubin", "Rosalind", "Silas", "Tatum", "Upton", "Vivian", "Wendell", "Xuxa", "Yann", "Zora"]; export type NameKind = "session" | "subagent" | "transient" | "workflow-child"; export interface NameHistoryRow { instance_id: string; name: string; kind: NameKind; ts: string; /** Durable persona UUID. Present after `agents identity assume`. */ agent_id?: string; /** Audit marker distinguishing an explicit role adoption from pool assignment. */ source?: "pool" | "identity.assume"; previous_name?: string; /** Instance this session was forked/branched from (recorded fork lineage). * Stamped only on the row that first assigns this instance, when the adapter * layer detected or supplied a parent conversation. */ forked_from?: string; } /** * Resolve (name, kind) for an existing owner without consuming a counter * slot. Returns null if no history match found. * * 1. Own instance_id → original (name, kind) * 2. session_id (owner != session) → (parent's name, "transient") */ export declare function resolveName(coordRoot: string, instanceId: string, sessionId?: string): { name: string; kind: NameKind; agent_id?: string; } | null; export interface NameAssumptionResult { changed: boolean; previous: { name: string; kind: NameKind; agent_id?: string; } | null; current: { name: string; kind: NameKind; agent_id: string; }; } /** * Append an explicit instance → durable-persona binding. Latest-row-wins makes * this auditable and retry-safe without mutating prior assignment history. */ export declare function recordNameAssumption(coordRoot: string, instanceId: string, name: string, agentId: string, kind?: NameKind): NameAssumptionResult; /** * Names a live agent currently holds, read from the generation-bound heartbeat * cache (`.harnery/active/.json`). * * Deliberately reads the cache directly rather than the V3 coordination view: * that view imports `resolveName` from this module, so depending on it here * would build an import cycle. The cache is the same set the view materializes * from and is pruned as sessions end, so it answers "is this name taken right * now" without one. * * Both error directions are safe for the caller. A stale row that slips past * the freshness window costs one skipped pool slot; a live agent missing from * the cache just restores the old counter-only behavior for that assignment. */ export declare function readLiveNames(coordRoot: string, opts: { freshnessSecs: number; nowMs?: number; }): Set; /** * Assign a name to with the given . Counter-consuming when * the owner is new. Idempotent: returns existing name on resume. * * Slot choice probes forward from the counter and takes the first name no live * agent holds, then advances the counter past every slot it skipped so the skip * is durable rather than re-probed on the next assignment. A full lap without a * free name means all 260 are genuinely live, so the raw counter slot is used: * a duplicate name beats refusing to name an agent at all. */ export declare function assignName(coordRoot: string, instanceId: string, kind: NameKind, opts: { freshnessSecs: number; forkedFrom?: string; nowMs?: number; }): string; /** One step of recorded fork lineage: the latest row for that * carries `forked_from` (latest-row-wins, matching resolveName). */ export declare function readForkParent(coordRoot: string, instanceId: string): { instance_id: string; name: string | null; } | null; /** * Full recorded fork ancestry for , nearest ancestor first, each * with its latest resolved name. Depth-capped and cycle-guarded: lineage is * append-only operational data, not something to trust unboundedly. */ export declare function resolveForkAncestry(coordRoot: string, instanceId: string): Array<{ instance_id: string; name: string | null; }>; //# sourceMappingURL=names.d.ts.map