{"version":3,"sources":["../src/backend/capabilities/resolve.ts","../src/backend/capabilities/catalog.ts"],"names":["createDataKeyedBag","ConfigurationError","requireDefined","CLAIMS","UNIQUE_SIDECAR_BATCH","BATCH_POINT_READ","ENDPOINT_SET_READ","STATEMENT_EXECUTION","CONTRIBUTION_HEALTH","RECORDED_REVISION_ORIGINS"],"mappings":";;;;;;;AA8IA,SAAS,aAAA,CAMP,SACA,MAAA,EAIC;AACD,EAAA,MAAM,WACJA,oCAAA,EAA6D;AAC/D,EAAA,MAAM,gBAA0B,EAAC;AACjC,EAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,IAAA,MAAM,OAAA,GAAU,MAAM,OAAA,CAAQ,MAAA;AAAA,MAC5B,CAAC,MAAA,KAAW,OAAA,CAAQ,MAAM,CAAA,KAAM;AAAA,KAClC;AACA,IAAA,IAAI,OAAA,CAAQ,WAAW,CAAA,EAAG;AACxB,MAAA,QAAA,CAAS,KAAA,CAAM,EAAE,CAAA,GAAI,EAAE,SAAS,IAAA,EAAM,OAAA,EAAS,MAAM,OAAA,EAAQ;AAAA,IAC/D,CAAA,MAAO;AACL,MAAA,QAAA,CAAS,KAAA,CAAM,EAAE,CAAA,GAAI;AAAA,QACnB,OAAA,EAAS,KAAA;AAAA,QACT,OAAA;AAAA,QACA,aAAa,KAAA,CAAM;AAAA,OACrB;AACA,MAAA,aAAA,CAAc,IAAA,CAAK,MAAM,EAAE,CAAA;AAAA,IAC7B;AAAA,EACF;AACA,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,QAAA;AAAA,IACR;AAAA,GACF;AACF;AAgBA,SAAS,kCAAA,CACP,SACA,UAAA,EAKM;AACN,EAAA,IAAI,UAAA,CAAW,gBAAgB,MAAA,EAAW;AAC1C,EAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,YAAA,CAAa,UAAA,CAAW,WAAW,CAAA,KAAM,IAAA;AAClE,EAAA,MAAM,OAAA,GAAU,WAAW,IAAA,CAAK,MAAA;AAAA,IAC9B,CAAC,MAAA,KAAW,OAAA,CAAQ,MAAM,CAAA,KAAM;AAAA,GAClC;AACA,EAAA,IAAI,QAAA,IAAY,OAAA,CAAQ,MAAA,KAAW,UAAA,CAAW,KAAK,MAAA,EAAQ;AAC3D,EAAA,IAAI,CAAC,QAAA,IAAY,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG;AAEvC,EAAA,MAAM,OAAA,GAAU,WAAW,IAAA,CAAK,MAAA;AAAA,IAC9B,CAAC,MAAA,KAAW,OAAA,CAAQ,MAAM,CAAA,KAAM;AAAA,GAClC;AACA,EAAA,MAAM,kBAAkB,UAAA,CAAW,WAAA;AACnC,EAAA,MAAM,IAAIC,oCAAA;AAAA,IACR,QAAA,GACE,CAAA,wBAAA,EAA2B,eAAe,CAAA,gCAAA,EAAmC,QAAQ,IAAA,CAAK,IAAI,CAAC,CAAA,yFAAA,CAAA,GAE/F,2BAA2B,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAC,2BAA2B,eAAe,CAAA,6FAAA,CAAA;AAAA,IAEzF,EAAE,IAAA,EAAM,UAAA,CAAW,eAAA,EAAiB,SAAS,OAAA,EAAQ;AAAA,IACrD;AAAA,MACE,YACE,QAAA,GACE,CAAA,yCAAA,EAA4C,eAAe,CAAA,mCAAA,CAAA,GAC3D,aAAa,eAAe,CAAA,kEAAA;AAAA;AAClC,GACF;AACF;AAaO,SAAS,aAAA,CACd,SACA,UAAA,EACoB;AACpB,EAAA,MAAM,MAAA,GAAU,UAAA,CAAW,MAAA,IAAU,EAAC;AAItC,EAAA,MAAM,EAAE,MAAA,EAAQ,aAAA,EAAe,aAAA,EAAc,GAAI,aAAA;AAAA,IAC/C,OAAA;AAAA,IACA;AAAA,GACF;AAQA,EAAA,IAAI,UAAA,CAAW,eAAe,eAAA,EAAiB;AAC7C,IAAA,MAAM,SAAA,GACJ,UAAA,CAAW,IAAA,KAAS,OAAA,GAClB,UAAA,CAAW,IAAA,GACX,MAAA,CAAO,OAAA,CAAQ,CAAC,KAAA,KAAU,KAAA,CAAM,OAAO,CAAA;AAC3C,IAAA,kCAAA,CAAmC,OAAA,EAAS;AAAA,MAC1C,GAAI,WAAW,WAAA,KAAgB,MAAA,GAC7B,EAAC,GACD,EAAE,WAAA,EAAa,UAAA,CAAW,WAAA,EAAY;AAAA,MACxC,IAAA,EAAM,SAAA;AAAA,MACN,iBAAiB,UAAA,CAAW;AAAA,KAC7B,CAAA;AAAA,EACH;AAEA,EAAA,IAAI,UAAA,CAAW,SAAS,WAAA,EAAa;AACnC,IAAA,OAAO;AAAA,MACL,QAAQ,UAAA,CAAW,EAAA;AAAA,MACnB,MAAA,EAAQ,aAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AAEA,EAAA,MAAM,OAAA,GAAU,WAAW,IAAA,CAAK,MAAA;AAAA,IAC9B,CAAC,MAAA,KAAW,OAAA,CAAQ,MAAM,CAAA,KAAM;AAAA,GAClC;AACA,EAAA,IAAI,OAAA,CAAQ,SAAS,CAAA,EAAG;AACtB,IAAA,OAAO;AAAA,MACL,SAAA,EAAW,KAAA;AAAA,MACX,QAAQ,UAAA,CAAW,EAAA;AAAA,MACnB,OAAA;AAAA,MACA,aAAa,UAAA,CAAW;AAAA,KAC1B;AAAA,EACF;AACA,EAAA,OAAO;AAAA,IACL,SAAA,EAAW,IAAA;AAAA,IACX,QAAQ,UAAA,CAAW,EAAA;AAAA,IACnB,SAAS,UAAA,CAAW,IAAA;AAAA,IACpB,MAAA,EAAQ,aAAA;AAAA,IACR;AAAA,GACF;AACF;AA8BO,SAAS,qBAAA,CAId,UAAA,EACA,OAAA,EACA,SAAA,EACmB;AACnB,EAAA,MAAM,GAAA,GAAM,WAAW,UAAA,CAAW,IAAA;AAAA,IAChC,CAAC,SAAA,KAAc,SAAA,CAAU,SAAA,KAAc;AAAA,GACzC;AACA,EAAA,IAAI,QAAQ,MAAA,EAAW;AACrB,IAAA,MAAM,IAAIA,oCAAA;AAAA,MACR,CAAA,mBAAA,EAAsB,SAAS,CAAA,yBAAA,EAA4B,UAAA,CAAW,EAAE,CAAA,EAAA,CAAA;AAAA,MACxE,EAAE,MAAA,EAAQ,UAAA,CAAW,EAAA,EAAI,SAAA;AAAU,KACrC;AAAA,EACF;AACA,EAAA,MAAM,QAAA,GAAW,GAAA,CAAI,QAAA,IAAY,EAAC;AAClC,EAAA,MAAM,MAAA,GAEU,QAAA,IAAY,OAAA,GAAU,OAAA,CAAQ,MAAA,GAAS,MAAA;AACvD,EAAA,OAAO,QAAA,CAAS,MAAA;AAAA,IACd,CAAC,EAAA,KAAO,MAAA,KAAW,UAAa,MAAA,CAAO,EAAE,GAAG,OAAA,KAAY;AAAA,GAC1D;AACF;AAmBO,SAAS,aAAA,CAId,UAAA,EACA,OAAA,EACA,SAAA,EACA,MAAA,EAQA;AACA,EAAA,MAAM,OAAA,GAAU,qBAAA,CAAsB,UAAA,EAAY,OAAA,EAAS,SAAS,CAAA;AACpE,EAAA,IAAI,OAAA,CAAQ,WAAW,CAAA,EAAG;AAE1B,EAAA,IAAI,MAAA,KAAW,MAAA,EAAW,MAAA,CAAO,OAAO,CAAA;AAKxC,EAAA,MAAM,EAAE,aAAY,GAAIC,gCAAA;AAAA,IACtB,WAAW,UAAA,CAAW,IAAA;AAAA,MACpB,CAAC,SAAA,KAAc,SAAA,CAAU,SAAA,KAAc;AAAA;AACzC,GACF;AACA,EAAA,IAAI,WAAA,CAAY,SAAS,QAAA,EAAU;AACjC,IAAA,MAAM,IAAID,oCAAA;AAAA,MACR,CAAA,WAAA,EAAc,SAAS,CAAA,wBAAA,EAA2B,UAAA,CAAW,EAAE,CAAA,WAAA,EAAc,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,CAAA;AAAA,MAC/F,EAAE,MAAM,WAAA,CAAY,IAAA,EAAM,QAAQ,UAAA,CAAW,EAAA,EAAI,WAAW,OAAA;AAAQ,KACtE;AAAA,EACF;AAMA,EAAA,MAAM,IAAIA,oCAAA;AAAA,IACR,CAAA,WAAA,EAAc,SAAS,CAAA,wBAAA,EAA2B,UAAA,CAAW,EAAE,CAAA,WAAA,EAAc,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAC,CAAA,6EAAA,CAAA;AAAA,IAC/F,EAAE,MAAA,EAAQ,UAAA,CAAW,EAAA,EAAI,WAAW,OAAA;AAAQ,GAC9C;AACF;AAMO,SAAS,cACd,OAAA,EACgC;AAChC,EAAA,OAAO,aAAA,CAAc,SAASE,wBAAM,CAAA;AACtC;AAEO,SAAS,0BACd,OAAA,EAC8C;AAC9C,EAAA,OAAO,aAAA,CAAc,SAASC,sCAAoB,CAAA;AACpD;AAEO,SAAS,sBACd,OAAA,EAC0C;AAC1C,EAAA,OAAO,aAAA,CAAc,SAASC,kCAAgB,CAAA;AAChD;AAEO,SAAS,uBACd,OAAA,EAC2C;AAC3C,EAAA,OAAO,aAAA,CAAc,SAASC,mCAAiB,CAAA;AACjD;AAEO,SAAS,0BACd,OAAA,EAC6C;AAC7C,EAAA,OAAO,aAAA,CAAc,SAASC,qCAAmB,CAAA;AACnD;AAEO,SAAS,0BACd,OAAA,EAC6C;AAC7C,EAAA,OAAO,aAAA,CAAc,SAASC,qCAAmB,CAAA;AACnD;AAEO,SAAS,+BACd,OAAA,EACmD;AACnD,EAAA,OAAO,aAAA,CAAc,SAASC,2CAAyB,CAAA;AACzD;AAiCA,IAAM,qBAAA,uBAA4B,OAAA,EAA0C;AAerE,SAAS,yBACd,OAAA,EACoB;AACpB,EAAA,MAAM,QAAA,GAAW,qBAAA,CAAsB,GAAA,CAAI,OAAO,CAAA;AAClD,EAAA,IAAI,QAAA,KAAa,QAAW,OAAO,QAAA;AAKnC,EAAA,IAAI,IAAA;AAEJ,EAAA,MAAM,QAA4B,MAAM;AACtC,IAAA,IAAI,SAAS,MAAA,EAAW;AACtB,MAAA,IAAI;AACF,QAAA,IAAA,GAAO,EAAE,KAAA,EAAO,UAAA,EAAY,SAAS,aAAA,CAAc,OAAA,EAASN,wBAAM,CAAA,EAAE;AAAA,MACtE,SAAS,KAAA,EAAO;AACd,QAAA,IAAA,GAAO,EAAE,KAAA,EAAO,QAAA,EAAU,KAAA,EAAM;AAChC,QAAA,MAAM,KAAA;AAAA,MACR;AAAA,IACF;AACA,IAAA,IAAI,IAAA,CAAK,KAAA,KAAU,QAAA,EAAU,MAAM,IAAA,CAAK,KAAA;AACxC,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,EACd,CAAA;AAEA,EAAA,qBAAA,CAAsB,GAAA,CAAI,SAAS,KAAK,CAAA;AACxC,EAAA,OAAO,KAAA;AACT;;;ACzdO,IAAM,qBAAA,GAAyD;AAAA,EACpE;AACF;AAWO,IAAM,sBAAA,GAA0D;AAAA,EACrE,MAAA;AAAA,EACA;AACF;AAmHO,SAAS,cAAA,CACd,SACA,SAAA,EACsB;AACtB,EAAA,MAAM,UAAU,OAAA,CAAQ,OAAA;AACxB,EAAA,IAAI,YAAY,MAAA,EAAW;AACzB,IAAA,MAAM,IAAIF,oCAAA;AAAA,MACR,GAAG,SAAS,CAAA,iFAAA,CAAA;AAAA,MACZ,EAAE,IAAA,EAAM,qBAAA,EAAuB,SAAA,EAAU;AAAA,MACzC;AAAA,QACE,UAAA,EACE;AAAA;AACJ,KACF;AAAA,EACF;AACA,EAAA,OAAO,OAAA;AACT","file":"chunk-7LQTDGV5.cjs","sourcesContent":["/**\n * The bundle verdict resolver — generalizing `claimSupport`\n * (`store/claims/backing.ts`).\n *\n * Resolution splits in two (ruling B1): the VERDICT — the support decision,\n * resolved once against `GraphBackend` and threaded — and the BINDING\n * (`bind.ts`) — the actual member functions, bound at the call site off\n * whichever port the site holds. A verdict carries names, never functions\n * (I19), so it crosses transaction boundaries safely.\n */\nimport { ConfigurationError } from \"../../errors\";\nimport { createDataKeyedBag } from \"../../utils/object\";\nimport { requireDefined } from \"../../utils/presence\";\nimport { type BackendCapabilities, type GraphBackend } from \"../types\";\nimport {\n  BATCH_POINT_READ,\n  type CapabilityBundleDefinition,\n  type CapabilityBundleDisposition,\n  type CapabilityBundleExtra,\n  CLAIMS,\n  CONTRIBUTION_HEALTH,\n  ENDPOINT_SET_READ,\n  type OptionalGraphBackendMember,\n  RECORDED_REVISION_ORIGINS,\n  STATEMENT_EXECUTION,\n  UNIQUE_SIDECAR_BATCH,\n} from \"./bundle-registry\";\n\n/**\n * A bundle's extras, as a type-level map from extra id to the UNION of\n * member names that extra covers — derived from the definition's `extras`\n * array by `const` inference, never hand-written.\n */\nexport type CapabilityExtraSpec = Readonly<\n  Record<string, OptionalGraphBackendMember>\n>;\n\n/**\n * One extra's verdict. `present: true` carries the member NAMES, not the\n * member functions (ruling B1) — the names are what the accessor binds\n * from, at the site, off the port.\n */\nexport type ExtraVerdict<M extends OptionalGraphBackendMember> =\n  | Readonly<{ present: true; members: readonly M[] }>\n  | Readonly<{\n      present: false;\n      missing: readonly M[];\n      disposition: CapabilityBundleDisposition;\n    }>;\n\n/** The verdict map: one entry per extra id, never a boolean. */\nexport type ExtraVerdicts<X extends CapabilityExtraSpec> = Readonly<{\n  [K in keyof X]: ExtraVerdict<X[K]>;\n}>;\n\nexport type GatedBundleVerdict<\n  MCore extends OptionalGraphBackendMember,\n  X extends CapabilityExtraSpec,\n> =\n  | Readonly<{\n      supported: true;\n      bundle: string;\n      /** The core, guaranteed present. Names, not functions. */\n      members: readonly MCore[];\n      extras: ExtraVerdicts<X>;\n      /** The `present: false` keys of `extras`. */\n      missingExtras: readonly (keyof X)[];\n    }>\n  | Readonly<{\n      supported: false;\n      bundle: string;\n      missing: readonly MCore[];\n      /** Why it is unsupported: the bundle's own `disposition`, verbatim. */\n      disposition: CapabilityBundleDisposition;\n    }>;\n\n/** No `supported` field: a graduated bundle has no bundle-level verdict. */\nexport type GraduatedBundleVerdict<X extends CapabilityExtraSpec> = Readonly<{\n  bundle: string;\n  extras: ExtraVerdicts<X>;\n  missingExtras: readonly (keyof X)[];\n}>;\n\n/**\n * Recovers the id→members map from a definition's `extras` TUPLE (not\n * `readonly CapabilityBundleExtra<XId, MExtra>[]` — over the array type the\n * id→members association is erased and `ExtraVerdicts<X>` degenerates to an\n * index signature).\n */\nexport type SpecOf<\n  XS extends readonly CapabilityBundleExtra<\n    string,\n    OptionalGraphBackendMember\n  >[],\n> = { [K in XS[number] as K[\"id\"]]: K[\"members\"][number] };\n\nexport type ExtrasOf<D extends CapabilityBundleDefinition> = SpecOf<\n  NonNullable<D[\"extras\"]>\n>;\nexport type ExtraMember<\n  D extends CapabilityBundleDefinition,\n  X extends keyof ExtrasOf<D>,\n> = Extract<ExtrasOf<D>[X], OptionalGraphBackendMember>;\n\n/**\n * The definition union and the return-type mapping. Structural, matching\n * `bundle-registry.ts`'s `BundleMembers` helper's own lesson: reading `core`\n * off `D` directly (rather than re-matching `GatedBundleDefinition`) avoids\n * an unmatched `infer` silently widening to the member constraint.\n */\nexport type BundleVerdictOf<D extends CapabilityBundleDefinition> =\n  D extends (\n    {\n      kind: \"graduated\";\n      extras: infer XS extends readonly CapabilityBundleExtra<\n        string,\n        OptionalGraphBackendMember\n      >[];\n    }\n  ) ?\n    GraduatedBundleVerdict<SpecOf<XS>>\n  : D extends (\n    {\n      kind: \"gated\";\n      core: readonly (infer MCore extends OptionalGraphBackendMember)[];\n      extras?: infer XS extends\n        | readonly CapabilityBundleExtra<string, OptionalGraphBackendMember>[]\n        | undefined;\n    }\n  ) ?\n    GatedBundleVerdict<\n      MCore,\n      SpecOf<\n        XS extends (\n          readonly CapabilityBundleExtra<string, OptionalGraphBackendMember>[]\n        ) ?\n          XS\n        : []\n      >\n    >\n  : never;\n\nfunction resolveExtras<\n  const XS extends readonly CapabilityBundleExtra<\n    string,\n    OptionalGraphBackendMember\n  >[],\n>(\n  backend: GraphBackend,\n  extras: XS,\n): Readonly<{\n  extras: ExtraVerdicts<SpecOf<XS>>;\n  missingExtras: readonly (keyof SpecOf<XS>)[];\n}> {\n  const verdicts =\n    createDataKeyedBag<ExtraVerdict<OptionalGraphBackendMember>>();\n  const missingExtras: string[] = [];\n  for (const extra of extras) {\n    const missing = extra.members.filter(\n      (member) => backend[member] === undefined,\n    );\n    if (missing.length === 0) {\n      verdicts[extra.id] = { present: true, members: extra.members };\n    } else {\n      verdicts[extra.id] = {\n        present: false,\n        missing,\n        disposition: extra.disposition,\n      };\n      missingExtras.push(extra.id);\n    }\n  }\n  return {\n    extras: verdicts as ExtraVerdicts<SpecOf<XS>>,\n    missingExtras: missingExtras,\n  };\n}\n\n/**\n * The `claims` bidirectional cross-check (ruling F2), reproducing\n * `store/claims/backing.ts`'s pre-B7 message text, code and suggestion\n * BYTE-FOR-BYTE. B7 made `claimSupport` (`backing.ts`) delegate to\n * {@link resolveBundle}, so this is now the ONLY place the check runs — there\n * is no second copy left to keep in sync. `bidirectional` is `claims`-only by\n * design (§5.2.1): the two trailing sentences below name \"claim\"/\"fence\"\n * vocabulary that is specific to that one bundle, and a future bundle raising\n * `crossCheck` to `\"bidirectional\"` must carry its own justification row and,\n * with it, its own message pair here.\n *\n * @throws {ConfigurationError} when the declaration and the member surface\n *   disagree in either direction.\n */\nfunction assertClaimsBidirectionalAgreement(\n  backend: GraphBackend,\n  definition: Readonly<{\n    declaration?: keyof BackendCapabilities;\n    core: readonly OptionalGraphBackendMember[];\n    portSurfaceCode: string;\n  }>,\n): void {\n  if (definition.declaration === undefined) return;\n  const declared = backend.capabilities[definition.declaration] === true;\n  const present = definition.core.filter(\n    (member) => backend[member] !== undefined,\n  );\n  if (declared && present.length === definition.core.length) return;\n  if (!declared && present.length === 0) return;\n\n  const missing = definition.core.filter(\n    (member) => backend[member] === undefined,\n  );\n  const declarationName = definition.declaration;\n  throw new ConfigurationError(\n    declared ?\n      `This backend declares \\`${declarationName}: true\\` but does not implement ${missing.join(\", \")}. ` +\n        \"A declared constraint would then be written without the fence the declaration promises.\"\n    : `This backend implements ${present.join(\", \")} but does not declare \\`${declarationName}: true\\`. ` +\n        \"Claim support is read from the declaration, so these members would never be called.\",\n    { code: definition.portSurfaceCode, missing, present },\n    {\n      suggestion:\n        declared ?\n          `Implement the missing members, or drop \\`${declarationName}\\` from the backend's capabilities.`\n        : `Declare \\`${declarationName}: true\\` in the backend's capabilities, or drop the claim members.`,\n    },\n  );\n}\n\n/**\n * Resolved ONCE, at construction or entry, against the top-level backend —\n * never against a `TransactionBackend` (I15's `@ts-expect-error` row).\n *\n * Rules: the member surface is read always; the declaration is read only\n * when the definition names one AND `crossCheck !== \"none\"` (only `claims`\n * qualifies in the pilot registry); a gated bundle's core must be complete\n * or the bundle is unsupported with `missing`; a graduated bundle has no\n * bundle-level verdict, only per-extra verdicts. `missingExtras` is built by\n * the SAME fold that builds `extras` (one pass, one owner).\n */\nexport function resolveBundle<const D extends CapabilityBundleDefinition>(\n  backend: GraphBackend,\n  definition: D,\n): BundleVerdictOf<D> {\n  const extras = (definition.extras ?? []) as readonly CapabilityBundleExtra<\n    string,\n    OptionalGraphBackendMember\n  >[];\n  const { extras: extraVerdicts, missingExtras } = resolveExtras(\n    backend,\n    extras,\n  );\n\n  // Rule 1: the declaration is read whenever `crossCheck !== \"none\"`,\n  // regardless of kind — a graduated bundle's \"core\" for this purpose is the\n  // union of every extra's members, since it has no core of its own. Only\n  // `claims` (gated) exercises this in the pilot registry, but the check\n  // itself must not silently no-op for a hypothetical graduated bidirectional\n  // bundle (T11's mutation pins exactly this).\n  if (definition.crossCheck === \"bidirectional\") {\n    const memberSet =\n      definition.kind === \"gated\" ?\n        definition.core\n      : extras.flatMap((extra) => extra.members);\n    assertClaimsBidirectionalAgreement(backend, {\n      ...(definition.declaration === undefined ?\n        {}\n      : { declaration: definition.declaration }),\n      core: memberSet,\n      portSurfaceCode: definition.portSurfaceCode,\n    });\n  }\n\n  if (definition.kind === \"graduated\") {\n    return {\n      bundle: definition.id,\n      extras: extraVerdicts,\n      missingExtras,\n    } as unknown as BundleVerdictOf<D>;\n  }\n\n  const missing = definition.core.filter(\n    (member) => backend[member] === undefined,\n  );\n  if (missing.length > 0) {\n    return {\n      supported: false,\n      bundle: definition.id,\n      missing,\n      disposition: definition.disposition,\n    } as unknown as BundleVerdictOf<D>;\n  }\n  return {\n    supported: true,\n    bundle: definition.id,\n    members: definition.core,\n    extras: extraVerdicts,\n    missingExtras,\n  } as unknown as BundleVerdictOf<D>;\n}\n\n/** The literal operation names a bundle's `operations` table declares. */\nexport type OperationNames<D extends CapabilityBundleDefinition> =\n  D[\"operations\"][number][\"operation\"];\n\n/** The extras a named operation `requires`, read from the ROW — never re-spelled at the call site. */\nexport type RequiredExtrasOf<\n  D extends CapabilityBundleDefinition,\n  Op extends OperationNames<D>,\n> =\n  Extract<D[\"operations\"][number], { operation: Op }> extends (\n    { requires: infer R extends readonly string[] }\n  ) ?\n    R[number]\n  : never;\n\n/**\n * The registry's row lookup plus the presence fold, extracted verbatim from\n * {@link requireExtras}'s body (ruling B8 spec item 3): the ONE owner of\n * \"what this operation requires\" that both `requireExtras`'s default throw\n * and a call site's own `refuse` callback consult.\n *\n * `operation` is the literal key of the bundle's `operations` tuple, so the\n * required extras are looked up TYPE-LEVEL from the registry — no second\n * spelling of `requires` at the call site.\n *\n * @throws {ConfigurationError} naming the unknown operation when `operation`\n *   is not a row of `definition.operations`.\n */\nexport function missingRequiredExtras<\n  const D extends CapabilityBundleDefinition,\n  Op extends OperationNames<D>,\n>(\n  definition: D,\n  verdict: BundleVerdictOf<D>,\n  operation: Op,\n): readonly string[] {\n  const row = definition.operations.find(\n    (candidate) => candidate.operation === operation,\n  );\n  if (row === undefined) {\n    throw new ConfigurationError(\n      `Unknown operation \"${operation}\" for capability bundle \"${definition.id}\".`,\n      { bundle: definition.id, operation },\n    );\n  }\n  const required = row.requires ?? [];\n  const extras:\n    | Readonly<Record<string, ExtraVerdict<OptionalGraphBackendMember>>>\n    | undefined = \"extras\" in verdict ? verdict.extras : undefined;\n  return required.filter(\n    (id) => extras === undefined || extras[id]?.present !== true,\n  );\n}\n\n/**\n * The refusal for an operation whose `requires` extras are absent — how a\n * GRADUATED bundle refuses where the tree refuses today: the row names the\n * operation and the extras, this asserts they are present, and\n * {@link bindExtra} (`bind.ts`) binds them off the port.\n *\n * `refuse`, when supplied, is called instead of the registry-coded throw\n * below — this is how a call site keeps its OWN existing error text (message,\n * `details` shape, order relative to other refusals) while the registry\n * stays the one owner of \"what this operation requires\" (ruling B8 spec item\n * 3). Omitting it keeps the default behavior byte-identical to before this\n * parameter existed.\n *\n * @throws {ConfigurationError} naming the row's own `code` when one or more\n *   required extras is absent from the verdict and no `refuse` callback is\n *   supplied; otherwise calls `refuse(missing)`, which never returns.\n */\nexport function requireExtras<\n  const D extends CapabilityBundleDefinition,\n  Op extends OperationNames<D>,\n>(\n  definition: D,\n  verdict: BundleVerdictOf<D>,\n  operation: Op,\n  refuse?: (missing: readonly string[]) => never,\n): asserts verdict is BundleVerdictOf<D> & {\n  extras: {\n    [K in RequiredExtrasOf<D, Op> & keyof ExtrasOf<D>]: Extract<\n      ExtraVerdict<ExtraMember<D, K>>,\n      { present: true }\n    >;\n  };\n} {\n  const missing = missingRequiredExtras(definition, verdict, operation);\n  if (missing.length === 0) return;\n\n  if (refuse !== undefined) refuse(missing);\n\n  // `missingRequiredExtras` already threw the unknown-operation error above\n  // when the row would be undefined, so `requireDefined` here is a redundant\n  // (never-failing) narrowing, not a second lookup that could disagree.\n  const { disposition } = requireDefined(\n    definition.operations.find(\n      (candidate) => candidate.operation === operation,\n    ),\n  );\n  if (disposition.kind === \"refuse\") {\n    throw new ConfigurationError(\n      `Operation \"${operation}\" on capability bundle \"${definition.id}\" requires ${missing.join(\", \")}.`,\n      { code: disposition.code, bundle: definition.id, operation, missing },\n    );\n  }\n  // No pilot row reaches this: every row with a non-empty `requires` in the\n  // registry disposes `refuse` (a graduated bundle's fallback rows never\n  // name `requires` — the fallback IS the degrade path). Kept as a named,\n  // typed refusal rather than a silent pass so a future `fallback` +\n  // `requires` row cannot pass `requireExtras` unnoticed.\n  throw new ConfigurationError(\n    `Operation \"${operation}\" on capability bundle \"${definition.id}\" requires ${missing.join(\", \")}, and the registry names no refusal code for this fallback-dispositioned row.`,\n    { bundle: definition.id, operation, missing },\n  );\n}\n\n// ---------------------------------------------------------------------------\n// The seven named verdict accessors — GraphBackend-only, no exceptions (I15).\n// ---------------------------------------------------------------------------\n\nexport function claimsVerdict(\n  backend: GraphBackend,\n): BundleVerdictOf<typeof CLAIMS> {\n  return resolveBundle(backend, CLAIMS);\n}\n\nexport function uniqueSidecarBatchVerdict(\n  backend: GraphBackend,\n): BundleVerdictOf<typeof UNIQUE_SIDECAR_BATCH> {\n  return resolveBundle(backend, UNIQUE_SIDECAR_BATCH);\n}\n\nexport function batchPointReadVerdict(\n  backend: GraphBackend,\n): BundleVerdictOf<typeof BATCH_POINT_READ> {\n  return resolveBundle(backend, BATCH_POINT_READ);\n}\n\nexport function endpointSetReadVerdict(\n  backend: GraphBackend,\n): BundleVerdictOf<typeof ENDPOINT_SET_READ> {\n  return resolveBundle(backend, ENDPOINT_SET_READ);\n}\n\nexport function statementExecutionVerdict(\n  backend: GraphBackend,\n): BundleVerdictOf<typeof STATEMENT_EXECUTION> {\n  return resolveBundle(backend, STATEMENT_EXECUTION);\n}\n\nexport function contributionHealthVerdict(\n  backend: GraphBackend,\n): BundleVerdictOf<typeof CONTRIBUTION_HEALTH> {\n  return resolveBundle(backend, CONTRIBUTION_HEALTH);\n}\n\nexport function recordedRevisionOriginsVerdict(\n  backend: GraphBackend,\n): BundleVerdictOf<typeof RECORDED_REVISION_ORIGINS> {\n  return resolveBundle(backend, RECORDED_REVISION_ORIGINS);\n}\n\n// ---------------------------------------------------------------------------\n// The claims verdict THUNK — the reference implementation of §5.2.3's INTENT\n// (one owner, at-most-once resolution, no re-derivation) moved to WHEN it\n// resolves rather than IF (ruling B7 refinement 2).\n// ---------------------------------------------------------------------------\n\n/**\n * A memoized, at-most-once resolution of the `claims` bundle's verdict\n * against ONE backend.\n *\n * Eager resolution at store construction is forbidden: T14's\n * contradictory-declaration backends must still be able to construct a store\n * and create nodes — only a constrained edge write may legally reach the\n * bidirectional cross-check's throw, and it must do so lazily, at the first\n * write that needs the verdict.\n *\n * A cached verdict cannot go stale because `GraphBackend` is deep-frozen (B1):\n * nothing can flip `capabilities.constraintClaims` or add/remove a claim\n * member on a backend object after this thunk has already resolved it, so\n * \"resolve once and reuse forever\" is exactly as safe as \"resolve every\n * time\" — for one backend object, they observe the same immutable answer.\n */\nexport type ClaimsVerdictThunk = () => BundleVerdictOf<typeof CLAIMS>;\n\n/**\n * Interning: the same backend object always gets back the SAME thunk object.\n * This is what makes \"one shared thunk per backend\" structural rather than a\n * convention every population site has to honor — a second call to\n * {@link createClaimsVerdictThunk} for a backend already minted cannot produce\n * a second, independently-memoized verdict.\n */\nconst CLAIMS_VERDICT_THUNKS = new WeakMap<GraphBackend, ClaimsVerdictThunk>();\n\n/**\n * Mints — or returns the already-minted — {@link ClaimsVerdictThunk} for\n * `backend`.\n *\n * The thunk resolves {@link resolveBundle}`(backend, CLAIMS)` on its first\n * call and caches the outcome, INCLUDING a thrown `ConfigurationError`: a\n * refusal is cached and re-thrown on every subsequent call, never\n * re-resolved. Both layers — interning here, memoization inside the thunk —\n * are required: interning alone would still let two independently-memoized\n * thunks exist for one backend if a caller ignored the shared one; memoizing\n * alone would still let two different call sites mint two different thunks\n * that could disagree about whether they had already resolved.\n */\nexport function createClaimsVerdictThunk(\n  backend: GraphBackend,\n): ClaimsVerdictThunk {\n  const existing = CLAIMS_VERDICT_THUNKS.get(backend);\n  if (existing !== undefined) return existing;\n\n  type Memo =\n    | Readonly<{ state: \"resolved\"; verdict: BundleVerdictOf<typeof CLAIMS> }>\n    | Readonly<{ state: \"thrown\"; error: unknown }>;\n  let memo: Memo | undefined;\n\n  const thunk: ClaimsVerdictThunk = () => {\n    if (memo === undefined) {\n      try {\n        memo = { state: \"resolved\", verdict: resolveBundle(backend, CLAIMS) };\n      } catch (error) {\n        memo = { state: \"thrown\", error };\n        throw error;\n      }\n    }\n    if (memo.state === \"thrown\") throw memo.error;\n    return memo.verdict;\n  };\n\n  CLAIMS_VERDICT_THUNKS.set(backend, thunk);\n  return thunk;\n}\n","/**\n * The backend's optional catalog-introspection surface: physical-schema\n * probes a store path consults directly, spelled once per dialect by the\n * two bundled profiles instead of a `dialect === \"postgres\"` branch at each\n * call site.\n *\n * Every member is a read-only probe except `dropInvalidIndex`, which issues\n * the one DDL statement that heals a crashed concurrent index build.\n * Nothing here writes a graph row, a sidecar row, or a status row.\n */\nimport { ConfigurationError } from \"../../errors\";\nimport { type GraphBackend } from \"../types\";\n\n/**\n * A physical index's presence and, on engines that can leave a build\n * half-finished, whether the leftover is usable.\n *\n * `invalid` is PostgreSQL's `pg_index.indisvalid = false` — an interrupted\n * `CREATE INDEX CONCURRENTLY` leaves a same-named index behind that a later\n * `IF NOT EXISTS` build would otherwise accept silently. SQLite has no such\n * state: `invalid` is always `false` there, and `exists` alone is the whole\n * answer.\n */\nexport type IndexState = Readonly<{\n  /** The physical SQL index name that was probed. */\n  name: string;\n  /** Whether an index with this name exists in the engine catalog. */\n  exists: boolean;\n  /** PostgreSQL's invalid-build leftover flag; always `false` on SQLite. */\n  invalid: boolean;\n}>;\n\n/**\n * A physical column's declared type, reduced to the family the two callers\n * that classify a recorded-time column actually distinguish: an integer\n * counter, text (SQLite's affinity for a wall-clock column stored as an\n * ISO-8601 string), PostgreSQL's exact `timestamp with time zone`, or\n * anything else. Kept this coarse on purpose — no caller needs a finer\n * classification, and each dialect's own probe decides which of these a\n * given declared type maps to, using that engine's own type rules (exact\n * match on PostgreSQL, affinity on SQLite).\n *\n * PostgreSQL's own normalizer never reports `\"text\"` — a declared `text`\n * column on that dialect falls through to `\"other\"`, since nothing\n * PostgreSQL-side stores a recorded-time column that way. That asymmetry is\n * why a revision or wall-time comparison must compare against\n * {@link REVISION_COLUMN_KINDS} / {@link WALL_TIME_COLUMN_KINDS} rather than\n * a single literal: the two dialects agree on the revision kind but not on\n * the wall-time one.\n */\nexport type NormalizedColumnKind =\n  \"integer\" | \"text\" | \"timestamp-with-time-zone\" | \"other\";\n\n/**\n * The `columnTypes` kinds that count as a revision counter. Both dialects\n * normalize one to `\"integer\"`, so this is a single-member set today — named\n * and exported so a caller compares against ONE owned set instead of\n * re-spelling `=== \"integer\"` inline. Consumed by\n * `store/recorded-capture/schema-version.ts`'s `isCompatibleColumnKind`,\n * which replaced that file's dialect-branching `isCompatibleColumnType` and\n * its SQLite-affinity twin (`hasSqliteAffinity`) with this owned set.\n */\nexport const REVISION_COLUMN_KINDS: readonly NormalizedColumnKind[] = [\n  \"integer\",\n];\n\n/**\n * The `columnTypes` kinds that count as a wall-clock timestamp. SQLite\n * stores one as an ISO-8601 string (`\"text\"`); PostgreSQL stores one as\n * `timestamp with time zone` (`\"timestamp-with-time-zone\"`) and never\n * normalizes a declared column to `\"text\"` at all — so this set stays exact\n * on both dialects without a caller ever branching on `dialect`. Consumed\n * by `store/recorded-capture/schema-version.ts`'s `isCompatibleColumnKind`,\n * alongside {@link REVISION_COLUMN_KINDS}.\n */\nexport const WALL_TIME_COLUMN_KINDS: readonly NormalizedColumnKind[] = [\n  \"text\",\n  \"timestamp-with-time-zone\",\n];\n\n/**\n * One physical column's name, normalized type family, and raw declared\n * type — trimmed and lower-cased, but otherwise exactly what the engine's\n * own catalog reports (`\"bigint\"`, `\"timestamp with time zone\"`, a SQLite\n * declared type such as `\"integer\"` or `\"text\"`, and so on). `kind` is what\n * a comparison should classify against; `declaredType` is what a\n * diagnostic should show a human, since `kind` discards the declared\n * spelling entirely.\n */\nexport type CatalogColumn = Readonly<{\n  name: string;\n  kind: NormalizedColumnKind;\n  declaredType: string;\n}>;\n\n/** One physical table's catalog presence. See {@link BackendCatalogProbes.tablesExist}. */\nexport type TableState = Readonly<{\n  /** The physical SQL table name that was probed. */\n  name: string;\n  /** Whether a table with this name exists in the engine catalog. */\n  exists: boolean;\n}>;\n\n/**\n * The three facts index materialization used to keep in its own\n * dialect-keyed record: whether this engine can build an index\n * concurrently (without blocking readers/writers), whether a concurrent\n * build can be interrupted into a usable-but-invalid leftover, and whether\n * it offers the GIN index family fulltext/trigram indexing needs.\n */\nexport type CatalogIndexBehavior = Readonly<{\n  concurrentBuilds: boolean;\n  hasInvalidIndexState: boolean;\n  supportsGinFamily: boolean;\n}>;\n\n/**\n * Physical-schema introspection a store path consults directly: table and\n * index presence, PostgreSQL's invalid-index leftover state and its\n * self-heal, normalized column types, and the per-dialect index-build\n * facts above.\n *\n * Optional: a custom backend that omits it loses the store paths that\n * consult it directly — index materialization (`store.materializeIndexes()`\n * refuses only once its empty-candidate short circuit and the status-table\n * ensure step have already run; `store.materializeSystemIndexes()`, which\n * has no candidate short circuit, refuses only once that same status-table\n * ensure step has run), the recorded-time schema check, and the\n * recorded-time migration's column read.\n */\nexport type BackendCatalogProbes = Readonly<{\n  /**\n   * Whether a table with this physical name exists in the engine catalog —\n   * on PostgreSQL, anything an unqualified `DELETE`/`ANALYZE` against the\n   * name could hit (ordinary and partitioned tables, views, materialized\n   * views, foreign tables), matching the dialect operation strategy's own\n   * DDL-target probe. A caller that means specifically \"is this a TABLE\",\n   * as opposed to any relation an unqualified statement could resolve to,\n   * wants {@link BackendCatalogProbes.tablesExist} instead — its narrower\n   * predicate excludes views, materialized views, and foreign tables.\n   */\n  tableExists: (this: void, name: string) => Promise<boolean>;\n  /**\n   * The catalog state of each named physical TABLE, one entry per input\n   * name (an absent name reports `exists: false`), resolved in one round\n   * trip. On PostgreSQL this is ordinary and partitioned tables only\n   * (`relkind IN ('r', 'p')`) — narrower than {@link tableExists}, which\n   * also matches views, materialized views, and foreign tables. A caller\n   * gating bulk, table-scoped work (a preload ahead of table DDL, say)\n   * wants this member so it gets one round trip and the strict predicate,\n   * rather than looping {@link tableExists} or accepting its wider match.\n   */\n  tablesExist: (\n    this: void,\n    names: readonly string[],\n  ) => Promise<readonly TableState[]>;\n  /**\n   * The catalog state of each named physical index, one entry per input\n   * name (an absent index reports `exists: false`), resolved in one\n   * round trip.\n   */\n  indexStates: (\n    this: void,\n    names: readonly string[],\n  ) => Promise<readonly IndexState[]>;\n  /**\n   * Drops the named index if — and only if — it is a PostgreSQL INVALID\n   * leftover from an interrupted `CREATE INDEX CONCURRENTLY`. A no-op on\n   * an engine whose `indexBehavior.hasInvalidIndexState` is `false`, and\n   * a no-op for a valid or absent index on every engine.\n   *\n   * A ROOT-BACKEND operation on an engine with an invalid-index state:\n   * PostgreSQL refuses `DROP INDEX CONCURRENTLY` inside a transaction\n   * block, so there the `catalog` a `transaction()` handle exposes throws a\n   * typed `ConfigurationError` from this member instead of attempting the\n   * DDL. An engine whose `indexBehavior.hasInvalidIndexState` is `false`\n   * (SQLite) has no invalid leftover to ever drop and stays a no-op in\n   * both scopes — every other member here stays a plain read on that same\n   * transaction-scoped bag regardless of engine.\n   */\n  dropInvalidIndex: (this: void, name: string) => Promise<void>;\n  /** Every column's name and normalized type family for one physical table. */\n  columnTypes: (this: void, table: string) => Promise<readonly CatalogColumn[]>;\n  /** This engine's index-build facts. See {@link CatalogIndexBehavior}. */\n  indexBehavior: CatalogIndexBehavior;\n}>;\n\n/**\n * THE refusal for a store path that needs the backend's catalog probes and\n * finds them absent, naming the missing port so a caller can add it — or\n * switch to a bundled backend — instead of chasing a `TypeError` two calls\n * deep into `materializeIndexes` or a recorded-time migration.\n */\nexport function requireCatalog(\n  backend: Pick<GraphBackend, \"catalog\">,\n  operation: string,\n): BackendCatalogProbes {\n  const catalog = backend.catalog;\n  if (catalog === undefined) {\n    throw new ConfigurationError(\n      `${operation} requires the backend's catalog probes, but this backend declares no \\`catalog\\`.`,\n      { code: \"CATALOG_UNAVAILABLE\", operation },\n      {\n        suggestion:\n          \"Implement `catalog` on this backend, or use a built-in SQLite or PostgreSQL backend.\",\n      },\n    );\n  }\n  return catalog;\n}\n"]}