{"version":3,"file":"signature.mjs","names":[],"sources":["../../../../../../../ai/src/orchestrator/signature.ts"],"sourcesContent":["import type { OrchestratorConfig } from \"../contracts/orchestrator/orchestrator-config.type\";\nimport type { ResolvedIntentEntry } from \"../supervisor/entries\";\n\n/**\n * Shape of the `historyWindow` config a fingerprint records. A number\n * window is recorded as `\"number\"`; a callback window as `\"callback\"`;\n * an absent role as `null`. The window VALUE (the literal `5`, the\n * callback body) is deliberately excluded — only the structural choice\n * of windowing strategy per role drifts the signature (§10.1).\n */\ntype HistoryWindowRoleFingerprint = \"number\" | \"callback\" | null;\n\n/**\n * Deterministic structural fingerprint of an orchestrator definition\n * (orchestrator.md §10.1). Persisted on every checkpoint so Phase 2 can\n * refuse a turn when the live definition no longer matches the saved\n * session shape. Covers exactly the dispatch contract:\n *\n * - `name`.\n * - The `intents` map — each intent key + its resolved description +\n *   the underlying unit's stable identity (agent name, workflow name +\n *   signature, or a `\"callback\"` marker for dev-callback intents).\n *   Reuses the supervisor's resolved-entry fingerprinting verbatim.\n * - `route` callback presence (its body is code, not data).\n * - `router` agent identity when LLM routing is configured.\n * - `evaluate` callback presence.\n * - `initialAgent` when set.\n * - `maxIterations`.\n * - The `iterate` flag — flipping single-dispatch to delegated\n *   iteration is a semantic shape change.\n * - The `historyWindow` config SHAPE — which roles window and whether\n *   each is a number or a callback (not the window value itself).\n *\n * Does NOT cover (§10.1): `version` (metadata only), `systemPrompt`\n * text, logger config, store identities, event handlers, or callback\n * function bodies (callbacks fingerprint as their presence/`\"callback\"`\n * marker only). The orchestrator signature does NOT aggregate the\n * internal supervisor's signature — that is a per-run concern delegated\n * to `supervisor.resume()`'s own drift check on `iterate: true`.\n *\n * @example\n * const signature = computeOrchestratorSignature(config, resolvedEntries);\n * // \"1a2b3c4d\" — 8-char FNV-1a hex, stable across process restarts.\n */\nexport function computeOrchestratorSignature(\n  config: OrchestratorConfig<unknown>,\n  entries: Map<string, ResolvedIntentEntry>,\n): string {\n  const intentsFingerprint = [...entries.entries()]\n    .sort(([first], [second]) => first.localeCompare(second))\n    .map(([intent, entry]) => ({\n      k: intent,\n      d: entry.description,\n      u: fingerprintUnit(entry),\n    }));\n\n  const fingerprint = {\n    n: config.name,\n    a: intentsFingerprint,\n    r: resolveRouterName(config.router),\n    rc: config.route ? 1 : 0,\n    e: config.evaluate ? 1 : 0,\n    i: config.initialAgent ?? null,\n    m: config.maxIterations ?? null,\n    it: config.iterate ? 1 : 0,\n    hw: fingerprintHistoryWindow(config.historyWindow),\n  };\n\n  return hash(JSON.stringify(fingerprint));\n}\n\n/**\n * Router identity for the fingerprint. Accepts both the bare-agent\n * shorthand and the `{ agent, ... }` entry form, returning the agent's\n * name (or `null` when no router is configured). Mirrors the\n * supervisor's `resolveRouterName`.\n */\nfunction resolveRouterName(router: OrchestratorConfig<unknown>[\"router\"]): string | null {\n  if (!router) {\n    return null;\n  }\n\n  if (typeof (router as { execute?: unknown }).execute === \"function\") {\n    return (router as { name?: string }).name ?? null;\n  }\n\n  return (router as { agent?: { name?: string } }).agent?.name ?? null;\n}\n\n/**\n * Structural fingerprint of the `historyWindow` config. Records the\n * windowing strategy per role (`\"number\"` / `\"callback\"` / `null`) so a\n * dev swapping a fixed-size window for a token-counting callback drifts\n * the signature, while tuning the window value (e.g. `5` → `8`) does\n * not. The window value is a runtime knob, not a shape change.\n */\nfunction fingerprintHistoryWindow(\n  historyWindow: OrchestratorConfig<unknown>[\"historyWindow\"],\n): { router: HistoryWindowRoleFingerprint; agents: HistoryWindowRoleFingerprint } {\n  return {\n    router: fingerprintHistoryWindowRole(historyWindow?.router),\n    agents: fingerprintHistoryWindowRole(historyWindow?.agents),\n  };\n}\n\nfunction fingerprintHistoryWindowRole(\n  window: number | ((...args: never[]) => unknown) | undefined,\n): HistoryWindowRoleFingerprint {\n  if (window === undefined) {\n    return null;\n  }\n\n  if (typeof window === \"function\") {\n    return \"callback\";\n  }\n\n  return \"number\";\n}\n\n/**\n * Stable identity of one resolved intent's underlying unit. Agents\n * fingerprint by name; workflows by name + their own signature;\n * callbacks by a type marker only (their closure can't be hashed\n * deterministically, so drift covers add/remove/rename, not body\n * edits). Identical to the supervisor's `fingerprintUnit`.\n */\nfunction fingerprintUnit(entry: ResolvedIntentEntry): unknown {\n  if (entry.type === \"callback\") {\n    return { t: \"callback\" };\n  }\n\n  if (entry.type === \"workflow\") {\n    const workflow = entry.unit;\n    return { t: \"workflow\", n: workflow.name, s: workflow.signature };\n  }\n\n  return { t: \"agent\", n: entry.unit.name };\n}\n\n/**\n * FNV-1a 32-bit — the same hash `supervisor/signature.ts` and\n * `workflow/signature.ts` use. Deterministic, no crypto dependency,\n * cheap; signatures are 8-char hex.\n */\nfunction hash(input: string): string {\n  let h = 0x811c9dc5;\n\n  for (let i = 0; i < input.length; i++) {\n    h ^= input.charCodeAt(i);\n    h = (h + ((h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24))) >>> 0;\n  }\n\n  return h.toString(16).padStart(8, \"0\");\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CA,SAAgB,6BACd,QACA,SACQ;CACR,MAAM,qBAAqB,CAAC,GAAG,QAAQ,QAAQ,CAAC,CAAC,CAC9C,MAAM,CAAC,QAAQ,CAAC,YAAY,MAAM,cAAc,MAAM,CAAC,CAAC,CACxD,KAAK,CAAC,QAAQ,YAAY;EACzB,GAAG;EACH,GAAG,MAAM;EACT,GAAG,gBAAgB,KAAK;CAC1B,EAAE;CAEJ,MAAM,cAAc;EAClB,GAAG,OAAO;EACV,GAAG;EACH,GAAG,kBAAkB,OAAO,MAAM;EAClC,IAAI,OAAO,QAAQ,IAAI;EACvB,GAAG,OAAO,WAAW,IAAI;EACzB,GAAG,OAAO,gBAAgB;EAC1B,GAAG,OAAO,iBAAiB;EAC3B,IAAI,OAAO,UAAU,IAAI;EACzB,IAAI,yBAAyB,OAAO,aAAa;CACnD;CAEA,OAAO,KAAK,KAAK,UAAU,WAAW,CAAC;AACzC;;;;;;;AAQA,SAAS,kBAAkB,QAA8D;CACvF,IAAI,CAAC,QACH,OAAO;CAGT,IAAI,OAAQ,OAAiC,YAAY,YACvD,OAAQ,OAA6B,QAAQ;CAG/C,OAAQ,OAAyC,OAAO,QAAQ;AAClE;;;;;;;;AASA,SAAS,yBACP,eACgF;CAChF,OAAO;EACL,QAAQ,6BAA6B,eAAe,MAAM;EAC1D,QAAQ,6BAA6B,eAAe,MAAM;CAC5D;AACF;AAEA,SAAS,6BACP,QAC8B;CAC9B,IAAI,WAAW,QACb,OAAO;CAGT,IAAI,OAAO,WAAW,YACpB,OAAO;CAGT,OAAO;AACT;;;;;;;;AASA,SAAS,gBAAgB,OAAqC;CAC5D,IAAI,MAAM,SAAS,YACjB,OAAO,EAAE,GAAG,WAAW;CAGzB,IAAI,MAAM,SAAS,YAAY;EAC7B,MAAM,WAAW,MAAM;EACvB,OAAO;GAAE,GAAG;GAAY,GAAG,SAAS;GAAM,GAAG,SAAS;EAAU;CAClE;CAEA,OAAO;EAAE,GAAG;EAAS,GAAG,MAAM,KAAK;CAAK;AAC1C;;;;;;AAOA,SAAS,KAAK,OAAuB;CACnC,IAAI,IAAI;CAER,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,KAAK,MAAM,WAAW,CAAC;EACvB,IAAK,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,SAAU;CACxE;CAEA,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG;AACvC"}