{"version":3,"file":"owed.cjs","names":["compareVersions"],"sources":["../../../src/services/deploy/owed.ts"],"sourcesContent":["/**\n * Owed-work detection (#571): the train derives release work from live\n * state — npm registry reads and the FastKV platform-manifest pointer —\n * never git history. Two facts decide the release leg:\n *\n * - `npmOwed` — a publishable workspace's version is not on npm yet\n * - `manifestOwed` — the published pointer's frameworkVersion trails the\n *   repo's (or no pointer exists at all)\n *\n * Unknown states (npm unreachable, FastKV read failure) never block: they\n * read as not-owed, matching the preflight npm gate's tolerance. The\n * cross-check — owed on one side only, with a completed release cycle on\n * record — is drift and fails the train loudly (#568's silent-skip class).\n */\n\nimport { compareSemver as compareVersions } from \"../../utils/semver\";\nimport { fetchRegistryKeyOrNull } from \"../registry/fastkv\";\nimport { readFrameworkVersion } from \"./image\";\nimport { findUnpublishedFrameworkPackages } from \"./preflight\";\n\n/** Tri-state pointer read: `present` (a completed release cycle exists),\n * `absent` (read succeeded, no slot — a first release), or `unknown` (the\n * read itself failed). */\nexport interface PointerRead {\n  state: \"absent\" | \"present\" | \"unknown\";\n  frameworkVersion?: string;\n}\n\nexport interface OwedWorkDetail {\n  /** Publishable workspaces whose version npm does not serve yet. */\n  unpublished: Array<{ name: string; version: string }>;\n  localFrameworkVersion?: string;\n  /** The published pointer's frameworkVersion — absent when no pointer exists. */\n  pointerFrameworkVersion?: string;\n  /** The pointer read succeeded and found a slot — a completed release cycle. */\n  pointerExists: boolean;\n}\n\nexport interface OwedWork {\n  npmOwed: boolean;\n  manifestOwed: boolean;\n  /** The release leg — any owed work. Drives release-conditional image tags. */\n  release: boolean;\n  detail: OwedWorkDetail;\n}\n\nexport type UnpublishedPackage = { name: string; version: string };\n\n/**\n * The pure decision core — no I/O. `pointer` is tri-state; `unpublished` is\n * optional (the npm leg is not consulted everywhere: the deploy train's\n * preflight npm gate already hard-fails unpublished versions before the\n * build, so in-train the release classifier is the pointer alone).\n */\nexport function computeOwedWork(input: {\n  pointer: PointerRead;\n  localFrameworkVersion?: string;\n  unpublished?: UnpublishedPackage[];\n}): OwedWork {\n  const unpublished = input.unpublished ?? [];\n  const npmOwed = unpublished.length > 0;\n  const { pointer, localFrameworkVersion } = input;\n  const manifestOwed =\n    pointer.state === \"unknown\"\n      ? false\n      : pointer.state === \"absent\"\n        ? Boolean(localFrameworkVersion)\n        : Boolean(\n            localFrameworkVersion &&\n              pointer.frameworkVersion !== undefined &&\n              compareVersions(pointer.frameworkVersion, localFrameworkVersion) < 0,\n          );\n  return {\n    npmOwed,\n    manifestOwed,\n    release: npmOwed || manifestOwed,\n    detail: {\n      unpublished,\n      ...(localFrameworkVersion ? { localFrameworkVersion } : {}),\n      ...(pointer.frameworkVersion ? { pointerFrameworkVersion: pointer.frameworkVersion } : {}),\n      pointerExists: pointer.state === \"present\",\n    },\n  };\n}\n\nexport interface OwedWorkDeps {\n  npmPublished?: typeof findUnpublishedFrameworkPackages;\n  fetchPointer?: (\n    account: string,\n    gateway: string,\n  ) => Promise<{ frameworkVersion?: string } | null>;\n}\n\n/** The full I/O detection (npm + FastKV) — the workflow-level owed-work step.\n * The deploy train uses `computeOwedWork` directly on its own single pointer\n * read instead (one read, no duplicates). */\nexport async function detectOwedWork(\n  input: { configDir: string; account?: string; gateway?: string },\n  deps: OwedWorkDeps = {},\n): Promise<OwedWork> {\n  const npmPublished = deps.npmPublished ?? findUnpublishedFrameworkPackages;\n  const fetchPointer =\n    deps.fetchPointer ?? ((a: string, g: string) => fetchRegistryKeyOrNull(a, g, \"platform.json\"));\n\n  let unpublished: UnpublishedPackage[] = [];\n  try {\n    unpublished = await npmPublished(input.configDir);\n  } catch {\n    // npm unreachable — unverifiable is not owed; never block the train\n  }\n  const localFrameworkVersion = readFrameworkVersion(input.configDir);\n\n  let pointer: PointerRead = { state: \"unknown\" };\n  if (input.account && input.gateway) {\n    try {\n      const value = await fetchPointer(input.account, input.gateway);\n      pointer = value\n        ? { state: \"present\", frameworkVersion: value.frameworkVersion }\n        : { state: \"absent\" };\n    } catch {\n      // registry unreachable — unverifiable is not owed; never block the train\n    }\n  }\n\n  return computeOwedWork({ pointer, localFrameworkVersion, unpublished });\n}\n\n/**\n * The root's in-train drift alarm: owed on exactly one side with a completed\n * release cycle on record means the last release half-landed — the #568\n * window (config + npm published, manifest pointer skipped, or the reverse).\n * Returns the human-readable drift, or undefined when consistent.\n */\nexport function owedWorkDrift(owed: OwedWork): string | undefined {\n  if (!owed.detail.pointerExists) return undefined;\n  if (owed.npmOwed === owed.manifestOwed) return undefined;\n  const npmSide = owed.npmOwed\n    ? `npm owes ${owed.detail.unpublished.map((p) => `${p.name}@${p.version}`).join(\", \")}`\n    : \"npm serves every publishable version\";\n  const manifestSide = owed.manifestOwed\n    ? `the platform-manifest pointer (${owed.detail.pointerFrameworkVersion ?? \"unset\"}) trails the repo (${owed.detail.localFrameworkVersion ?? \"unknown\"})`\n    : `the platform-manifest pointer is current (${owed.detail.pointerFrameworkVersion})`;\n  return `release-state drift: ${npmSide}, but ${manifestSide} — the last release half-landed; reconcile before deploying`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAsDA,SAAgB,gBAAgB,OAInB;CACX,MAAM,cAAc,MAAM,eAAe,CAAC;CAC1C,MAAM,UAAU,YAAY,SAAS;CACrC,MAAM,EAAE,SAAS,0BAA0B;CAC3C,MAAM,eACJ,QAAQ,UAAU,YACd,QACA,QAAQ,UAAU,WAChB,QAAQ,qBAAqB,IAC7B,QACE,yBACE,QAAQ,qBAAqB,UAC7BA,6BAAgB,QAAQ,kBAAkB,qBAAqB,IAAI,CACvE;CACR,OAAO;EACL;EACA;EACA,SAAS,WAAW;EACpB,QAAQ;GACN;GACA,GAAI,wBAAwB,EAAE,sBAAsB,IAAI,CAAC;GACzD,GAAI,QAAQ,mBAAmB,EAAE,yBAAyB,QAAQ,iBAAiB,IAAI,CAAC;GACxF,eAAe,QAAQ,UAAU;EACnC;CACF;AACF"}