{"version":3,"file":"signature.mjs","names":[],"sources":["../../../../../../../ai/src/supervisor/signature.ts"],"sourcesContent":["import { ClassifierAgentEntry, ClassifierRunEntry } from \"../contracts\";\nimport type { SupervisorConfig } from \"../contracts/supervisor/supervisor-config.type\";\nimport type { ResolvedIntentEntry } from \"./entries\";\n\n/**\n * Deterministic structural fingerprint of a supervisor definition.\n * Persisted on every snapshot so `resume()` can detect drift between\n * the saved run and the current definition. Covers:\n *\n * - Supervisor name.\n * - Every intent key + its resolved description + the underlying\n *   unit's stable identity (agent name, workflow name + signature,\n *   or `\"callback\"` marker for dev-callback intents).\n * - Router agent's name (if the supervisor uses LLM routing).\n * - Whether a deterministic `route` callback is configured (but not\n *   its contents — route callbacks are code, not data).\n * - Whether an `evaluate` callback is configured.\n * - `initialAgent` when set.\n * - `maxIterations` (a semantic shape change, not a cosmetic one).\n *\n * Does NOT cover: system prompt text, logger, store identity, per-\n * event handlers — all runtime knobs that don't change the shape of\n * a resumable run.\n */\nexport function computeSignature(\n  config: SupervisorConfig<unknown>,\n  entries: Map<string, ResolvedIntentEntry>,\n): string {\n  const intentsFingerprint = [...entries.entries()]\n    .sort(([a], [b]) => a.localeCompare(b))\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    // Phase 7 / decisions §37 — classifier is part of structural identity.\n    // Resume drift detection notices when the classifier swap changes\n    // routing semantics. Same fingerprint shape as router (agent name\n    // when applicable; \"callback\" marker for callback form).\n    c: resolveClassifierFingerprint(config.classifier),\n  };\n\n  return hash(JSON.stringify(fingerprint));\n}\n\nfunction resolveRouterName(router: SupervisorConfig<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\nfunction resolveClassifierFingerprint(\n  classifier: SupervisorConfig<unknown>[\"classifier\"],\n): unknown {\n  if (!classifier) {\n    return null;\n  }\n\n  if (typeof classifier === \"function\") {\n    return { t: \"callback\" };\n  }\n\n  if (typeof (classifier as { execute?: unknown }).execute === \"function\") {\n    return { t: \"agent\", n: (classifier as { name?: string }).name ?? null };\n  }\n\n  if (typeof (classifier as ClassifierRunEntry).run === \"function\") {\n    return { t: \"callback\" };\n  }\n\n  if (typeof (classifier as ClassifierAgentEntry).agent?.execute === \"function\") {\n    return {\n      t: \"agent\",\n      n: (classifier as ClassifierAgentEntry).agent?.name ?? null,\n    };\n  }\n\n  return { t: \"unknown\" };\n}\n\nfunction fingerprintUnit(entry: ResolvedIntentEntry): unknown {\n  if (entry.type === \"callback\") {\n    // Callbacks are dev code — fingerprint the type + intent name\n    // only (the closure itself can't be hashed deterministically).\n    // Drift detection covers add/remove/rename of callback intents,\n    // not edits to the function body. Same trade-off as `route`.\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 — same hash `workflow/signature.ts` uses. Deterministic,\n * no crypto dependency, 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":";;;;;;;;;;;;;;;;;;;;;AAwBA,SAAgB,iBACd,QACA,SACQ;CACR,MAAM,qBAAqB,CAAC,GAAG,QAAQ,QAAQ,CAAC,CAAC,CAC9C,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,CACtC,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;EAK3B,GAAG,6BAA6B,OAAO,UAAU;CACnD;CAEA,OAAO,KAAK,KAAK,UAAU,WAAW,CAAC;AACzC;AAEA,SAAS,kBAAkB,QAA4D;CACrF,IAAI,CAAC,QACH,OAAO;CAGT,IAAI,OAAQ,OAAiC,YAAY,YACvD,OAAQ,OAA6B,QAAQ;CAG/C,OAAQ,OAAyC,OAAO,QAAQ;AAClE;AAEA,SAAS,6BACP,YACS;CACT,IAAI,CAAC,YACH,OAAO;CAGT,IAAI,OAAO,eAAe,YACxB,OAAO,EAAE,GAAG,WAAW;CAGzB,IAAI,OAAQ,WAAqC,YAAY,YAC3D,OAAO;EAAE,GAAG;EAAS,GAAI,WAAiC,QAAQ;CAAK;CAGzE,IAAI,OAAQ,WAAkC,QAAQ,YACpD,OAAO,EAAE,GAAG,WAAW;CAGzB,IAAI,OAAQ,WAAoC,OAAO,YAAY,YACjE,OAAO;EACL,GAAG;EACH,GAAI,WAAoC,OAAO,QAAQ;CACzD;CAGF,OAAO,EAAE,GAAG,UAAU;AACxB;AAEA,SAAS,gBAAgB,OAAqC;CAC5D,IAAI,MAAM,SAAS,YAKjB,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;;;;;AAMA,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"}