{"version":3,"file":"overlay-sQHQoN0I.mjs","names":["defaultNodeHints"],"sources":["../src/compat/policy.ts","../src/compat/schema.ts","../src/compat/ir.ts","../src/compat/config.ts","../src/compat/classify.ts","../src/compat/language-hints.ts","../src/compat/spec-filter.ts","../src/compat/differ.ts","../src/compat/extractor-registry.ts","../src/compat/overlay.ts"],"sourcesContent":["/**\n * Language-aware compatibility policy.\n *\n * Defines which aspects of the public API surface are breaking in each\n * language. Built-in defaults capture language semantics (e.g., PHP has\n * named arguments, Go does not). Config overrides allow per-SDK divergence.\n */\n\nimport type { LanguageId } from './ir.js';\n\n/** Policy hints that determine what constitutes a breaking change. */\nexport interface CompatPolicyHints {\n  /** Callers reference parameter names at the call site (PHP named args, Python/Ruby keyword args, Kotlin/C# named args). */\n  callerUsesParamNames: boolean;\n  /** Constructor positional order is part of the public API. */\n  constructorOrderMatters: boolean;\n  /** Method parameter names are visible to callers. */\n  methodParameterNamesArePublicApi: boolean;\n  /** Constructor parameter names are visible to callers. */\n  constructorParameterNamesArePublicApi: boolean;\n  /** Method overload sets are part of the public API (Kotlin, C#). */\n  overloadsArePublicApi: boolean;\n  /** Function arity is part of the public API (Elixir, Go). */\n  arityIsPublicApi: boolean;\n}\n\n/** Built-in language defaults. */\nconst LANGUAGE_DEFAULTS: Record<LanguageId, CompatPolicyHints> = {\n  php: {\n    callerUsesParamNames: true,\n    constructorOrderMatters: true,\n    methodParameterNamesArePublicApi: true,\n    constructorParameterNamesArePublicApi: true,\n    overloadsArePublicApi: false,\n    arityIsPublicApi: false,\n  },\n  python: {\n    callerUsesParamNames: true,\n    constructorOrderMatters: true,\n    methodParameterNamesArePublicApi: true,\n    constructorParameterNamesArePublicApi: true,\n    overloadsArePublicApi: false,\n    arityIsPublicApi: false,\n  },\n  ruby: {\n    callerUsesParamNames: true,\n    constructorOrderMatters: true,\n    methodParameterNamesArePublicApi: true,\n    constructorParameterNamesArePublicApi: true,\n    overloadsArePublicApi: false,\n    arityIsPublicApi: false,\n  },\n  go: {\n    callerUsesParamNames: false,\n    constructorOrderMatters: true,\n    methodParameterNamesArePublicApi: false,\n    constructorParameterNamesArePublicApi: false,\n    overloadsArePublicApi: false,\n    arityIsPublicApi: true,\n  },\n  kotlin: {\n    callerUsesParamNames: true,\n    constructorOrderMatters: false,\n    methodParameterNamesArePublicApi: true,\n    constructorParameterNamesArePublicApi: true,\n    overloadsArePublicApi: true,\n    arityIsPublicApi: false,\n  },\n  dotnet: {\n    callerUsesParamNames: true,\n    constructorOrderMatters: false,\n    methodParameterNamesArePublicApi: true,\n    constructorParameterNamesArePublicApi: true,\n    overloadsArePublicApi: true,\n    arityIsPublicApi: false,\n  },\n  elixir: {\n    callerUsesParamNames: true,\n    constructorOrderMatters: false,\n    methodParameterNamesArePublicApi: true,\n    constructorParameterNamesArePublicApi: false,\n    overloadsArePublicApi: false,\n    arityIsPublicApi: true,\n  },\n  rust: {\n    callerUsesParamNames: false,\n    constructorOrderMatters: true,\n    methodParameterNamesArePublicApi: false,\n    constructorParameterNamesArePublicApi: false,\n    overloadsArePublicApi: false,\n    arityIsPublicApi: true,\n  },\n  node: {\n    callerUsesParamNames: false,\n    constructorOrderMatters: false,\n    methodParameterNamesArePublicApi: false,\n    constructorParameterNamesArePublicApi: false,\n    overloadsArePublicApi: false,\n    arityIsPublicApi: false,\n  },\n};\n\n/** Get the built-in default policy for a language. */\nexport function getDefaultPolicy(language: LanguageId): CompatPolicyHints {\n  return { ...LANGUAGE_DEFAULTS[language] };\n}\n\n/** Merge user overrides onto language defaults. Only provided keys are overridden. */\nexport function mergePolicy(defaults: CompatPolicyHints, overrides: Partial<CompatPolicyHints>): CompatPolicyHints {\n  return { ...defaults, ...overrides };\n}\n\n/** All supported language IDs. */\nexport const ALL_LANGUAGE_IDS: readonly LanguageId[] = Object.keys(LANGUAGE_DEFAULTS) as LanguageId[];\n","/**\n * Schema versioning for compatibility snapshots.\n *\n * Snapshots are versioned so consumers can detect format changes and\n * apply migration logic if needed.\n */\n\nimport type { CompatSnapshot } from './ir.js';\n\n/** Current schema version for compatibility snapshots. */\nexport const COMPAT_SCHEMA_VERSION = '1';\n\n/** Validate that a parsed snapshot has a compatible schema version. */\nexport function isCompatibleSchemaVersion(snapshot: { schemaVersion?: string }): boolean {\n  return snapshot.schemaVersion === COMPAT_SCHEMA_VERSION;\n}\n\n/** Validate the basic structure of a parsed compat snapshot. */\nexport function validateSnapshot(data: unknown): data is CompatSnapshot {\n  if (typeof data !== 'object' || data === null) return false;\n  const obj = data as Record<string, unknown>;\n  return (\n    typeof obj.schemaVersion === 'string' &&\n    typeof obj.source === 'object' &&\n    obj.source !== null &&\n    typeof obj.policies === 'object' &&\n    obj.policies !== null &&\n    Array.isArray(obj.symbols)\n  );\n}\n","/**\n * Rich compatibility IR for cross-language compatibility verification.\n *\n * These types represent the public API surface of an SDK in a language-aware,\n * machine-readable format. They extend the basic ApiSurface with richer\n * parameter semantics, sensitivity flags, and provenance metadata.\n */\n\nimport type { CompatPolicyHints } from './policy.js';\n\n/** Language identifier for emitter targets. */\nexport type LanguageId = 'node' | 'php' | 'python' | 'ruby' | 'go' | 'kotlin' | 'dotnet' | 'elixir' | 'rust';\n\n/** A full compatibility snapshot of an SDK's public API surface. */\nexport interface CompatSnapshot {\n  schemaVersion: string;\n  source: {\n    specSha?: string;\n    extractedAt: string;\n  };\n  policies: CompatPolicyHints;\n  symbols: CompatSymbol[];\n}\n\n/** Kind of public API symbol. */\nexport type CompatSymbolKind =\n  | 'service_accessor'\n  | 'callable'\n  | 'constructor'\n  | 'field'\n  | 'property'\n  | 'enum'\n  | 'enum_member'\n  | 'alias';\n\n/** Visibility level of a symbol. */\nexport type CompatVisibility = 'public' | 'protected' | 'internal';\n\n/** Stability classification of a symbol. */\nexport type CompatStability = 'stable' | 'unstable' | 'deprecated';\n\n/** How the symbol was generated. */\nexport type CompatSourceKind =\n  | 'generated_service_wrapper'\n  | 'generated_model_constructor'\n  | 'generated_resource_constructor'\n  | 'generated_enum'\n  | 'compat_alias';\n\n/** A single public API symbol with its full metadata. */\nexport interface CompatSymbol {\n  id: string;\n  kind: CompatSymbolKind;\n  fqName: string;\n  ownerFqName?: string;\n  displayName: string;\n  visibility: CompatVisibility;\n  stability: CompatStability;\n  sourceKind: CompatSourceKind;\n  operationId?: string;\n  schemaName?: string;\n  route?: {\n    method: string;\n    path: string;\n  };\n  parameters?: CompatParameter[];\n  returns?: CompatTypeRef;\n  /** Type reference for field/property symbols. */\n  typeRef?: CompatTypeRef;\n  /** Value for enum member symbols. */\n  value?: string | number;\n  /** Relative path to the source file where this symbol is defined. */\n  sourceFile?: string;\n}\n\n/** How a parameter is passed at the call site. */\nexport type CompatPassingStyle =\n  | 'positional'\n  | 'keyword'\n  | 'named'\n  | 'keyword_or_positional'\n  | 'options_object'\n  | 'builder';\n\n/** A parameter on a callable or constructor symbol. */\nexport interface CompatParameter {\n  publicName: string;\n  wireName?: string;\n  position: number;\n  required: boolean;\n  nullable: boolean;\n  hasDefault: boolean;\n  passing: CompatPassingStyle;\n  type: CompatTypeRef;\n  sensitivity: ParameterSensitivity;\n}\n\n/** Which aspects of this parameter are part of the public API contract. */\nexport interface ParameterSensitivity {\n  order: boolean;\n  publicName: boolean;\n  requiredness: boolean;\n  type: boolean;\n}\n\n/** A type reference — either a named type or an inline description. */\nexport interface CompatTypeRef {\n  name: string;\n  nullable?: boolean;\n  array?: boolean;\n  generic?: string[];\n}\n\n// ---------------------------------------------------------------------------\n// Bridge: ApiSurface → CompatSnapshot\n// ---------------------------------------------------------------------------\n\nimport type { ApiSurface, ApiParam } from './types.js';\nimport { getDefaultPolicy } from './policy.js';\nimport { COMPAT_SCHEMA_VERSION } from './schema.js';\n\n/**\n * Convert a legacy ApiSurface to a CompatSnapshot.\n *\n * This bridge allows existing extractors (which produce ApiSurface) to feed\n * into the new classified diff engine without requiring immediate migration.\n */\nexport function apiSurfaceToSnapshot(surface: ApiSurface): CompatSnapshot {\n  const language = (surface.language || 'node') as LanguageId;\n  const symbols: CompatSymbol[] = [];\n\n  // Convert classes → service_accessor symbols + callable/constructor children\n  for (const [className, cls] of Object.entries(surface.classes)) {\n    symbols.push({\n      id: `class:${className}`,\n      kind: 'service_accessor',\n      fqName: className,\n      displayName: className,\n      visibility: 'public',\n      stability: cls.deprecationMessage ? 'deprecated' : 'stable',\n      sourceKind: 'generated_service_wrapper',\n      ...(cls.sourceFile ? { sourceFile: cls.sourceFile } : {}),\n    });\n\n    // Constructor\n    if (cls.constructorParams.length > 0) {\n      symbols.push({\n        id: `ctor:${className}`,\n        kind: 'constructor',\n        fqName: `${className}.constructor`,\n        ownerFqName: className,\n        displayName: `new ${className}`,\n        visibility: 'public',\n        stability: 'stable',\n        sourceKind: 'generated_resource_constructor',\n        parameters: cls.constructorParams.map((p, i) => apiParamToCompatParam(p, i, language)),\n        ...(cls.sourceFile ? { sourceFile: cls.sourceFile } : {}),\n      });\n    }\n\n    // Methods\n    for (const [methodName, overloads] of Object.entries(cls.methods)) {\n      for (let oi = 0; oi < overloads.length; oi++) {\n        const method = overloads[oi];\n        const suffix = overloads.length > 1 ? `#${oi}` : '';\n        symbols.push({\n          id: `method:${className}.${methodName}${suffix}`,\n          kind: 'callable',\n          fqName: `${className}.${methodName}`,\n          ownerFqName: className,\n          displayName: `${className}.${methodName}`,\n          visibility: 'public',\n          stability: 'stable',\n          sourceKind: 'generated_service_wrapper',\n          parameters: method.params.map((p, i) => apiParamToCompatParam(p, i, language)),\n          returns: { name: method.returnType },\n          ...(cls.sourceFile ? { sourceFile: cls.sourceFile } : {}),\n        });\n      }\n    }\n\n    // Properties\n    for (const [propName, prop] of Object.entries(cls.properties)) {\n      symbols.push({\n        id: `prop:${className}.${propName}`,\n        kind: 'property',\n        fqName: `${className}.${propName}`,\n        ownerFqName: className,\n        displayName: `${className}.${propName}`,\n        visibility: 'public',\n        stability: 'stable',\n        sourceKind: 'generated_service_wrapper',\n        typeRef: { name: prop.type },\n        ...(cls.sourceFile ? { sourceFile: cls.sourceFile } : {}),\n      });\n    }\n  }\n\n  // Convert interfaces → field symbols\n  for (const [ifaceName, iface] of Object.entries(surface.interfaces)) {\n    symbols.push({\n      id: `iface:${ifaceName}`,\n      kind: 'alias',\n      fqName: ifaceName,\n      displayName: ifaceName,\n      visibility: 'public',\n      stability: 'stable',\n      sourceKind: 'generated_resource_constructor',\n      ...(iface.sourceFile ? { sourceFile: iface.sourceFile } : {}),\n    });\n\n    for (const [fieldName, field] of Object.entries(iface.fields)) {\n      symbols.push({\n        id: `field:${ifaceName}.${fieldName}`,\n        kind: 'field',\n        fqName: `${ifaceName}.${fieldName}`,\n        ownerFqName: ifaceName,\n        displayName: `${ifaceName}.${fieldName}`,\n        visibility: 'public',\n        stability: 'stable',\n        sourceKind: 'generated_resource_constructor',\n        typeRef: { name: field.type },\n        ...(iface.sourceFile ? { sourceFile: iface.sourceFile } : {}),\n      });\n    }\n\n    // Constructor if interface has one\n    if (iface.hasCustomConstructor) {\n      symbols.push({\n        id: `ctor:${ifaceName}`,\n        kind: 'constructor',\n        fqName: `${ifaceName}.constructor`,\n        ownerFqName: ifaceName,\n        displayName: `new ${ifaceName}`,\n        visibility: 'public',\n        stability: 'stable',\n        sourceKind: 'generated_resource_constructor',\n        ...(iface.sourceFile ? { sourceFile: iface.sourceFile } : {}),\n      });\n    }\n  }\n\n  // Convert type aliases\n  for (const [aliasName, alias] of Object.entries(surface.typeAliases)) {\n    symbols.push({\n      id: `alias:${aliasName}`,\n      kind: 'alias',\n      fqName: aliasName,\n      displayName: aliasName,\n      visibility: 'public',\n      stability: 'stable',\n      sourceKind: 'generated_resource_constructor',\n      ...(alias.sourceFile ? { sourceFile: alias.sourceFile } : {}),\n    });\n  }\n\n  // Convert enums\n  for (const [enumName, enumDef] of Object.entries(surface.enums)) {\n    symbols.push({\n      id: `enum:${enumName}`,\n      kind: 'enum',\n      fqName: enumName,\n      displayName: enumName,\n      visibility: 'public',\n      stability: 'stable',\n      sourceKind: 'generated_enum',\n      ...(enumDef.sourceFile ? { sourceFile: enumDef.sourceFile } : {}),\n    });\n\n    for (const [memberName, memberValue] of Object.entries(enumDef.members)) {\n      symbols.push({\n        id: `enum_member:${enumName}.${memberName}`,\n        kind: 'enum_member',\n        fqName: `${enumName}.${memberName}`,\n        ownerFqName: enumName,\n        displayName: `${enumName}.${memberName}`,\n        visibility: 'public',\n        stability: 'stable',\n        sourceKind: 'generated_enum',\n        value: memberValue,\n        ...(enumDef.sourceFile ? { sourceFile: enumDef.sourceFile } : {}),\n      });\n    }\n  }\n\n  return {\n    schemaVersion: COMPAT_SCHEMA_VERSION,\n    source: { extractedAt: surface.extractedAt },\n    policies: getDefaultPolicy(language),\n    symbols,\n  };\n}\n\n/** Convert a legacy ApiParam to a CompatParameter. */\nfunction apiParamToCompatParam(param: ApiParam, position: number, language: LanguageId): CompatParameter {\n  const policy = getDefaultPolicy(language);\n  const passing = param.passingStyle ?? inferPassingStyle(language);\n  return {\n    publicName: param.name,\n    position,\n    required: !param.optional,\n    nullable: false,\n    hasDefault: param.optional,\n    passing,\n    type: { name: param.type },\n    sensitivity: {\n      // Method-call order matters only when callers pass positionally. keyword\n      // (Ruby/Python/Elixir) and options_object (Node) hide position entirely;\n      // named (PHP/Kotlin/C#) is handled as soft-risk in classify.\n      order: passing === 'positional',\n      publicName: policy.methodParameterNamesArePublicApi,\n      requiredness: true,\n      type: true,\n    },\n  };\n}\n\n/** Infer the default parameter passing style for a language. */\nfunction inferPassingStyle(language: LanguageId): CompatPassingStyle {\n  switch (language) {\n    case 'python':\n    case 'ruby':\n    case 'elixir':\n      return 'keyword';\n    case 'php':\n    case 'kotlin':\n    case 'dotnet':\n      return 'named';\n    case 'node':\n      return 'options_object';\n    default:\n      return 'positional';\n  }\n}\n","/**\n * Compat configuration types for `oagen.config.ts`.\n *\n * The `compat` section of the config holds human-authored policy:\n * fail thresholds, language overrides, and intentional break approvals.\n * Generated state (manifests, snapshots, reports) lives elsewhere.\n */\n\nimport type { LanguageId } from './ir.js';\nimport type { CompatPolicyHints } from './policy.js';\n\n// ---------------------------------------------------------------------------\n// Change categories\n// ---------------------------------------------------------------------------\n\n/** Breaking change categories — changes that break callers. */\nexport type BreakingChangeCategory =\n  | 'symbol_removed'\n  | 'symbol_renamed'\n  | 'parameter_removed'\n  | 'parameter_renamed'\n  | 'parameter_requiredness_increased'\n  | 'parameter_type_narrowed'\n  | 'parameter_position_changed_order_sensitive'\n  | 'constructor_position_changed_order_sensitive'\n  | 'named_arg_name_removed'\n  | 'keyword_name_removed'\n  | 'overload_removed'\n  | 'union_wrapper_migration_without_compat_alias'\n  | 'field_type_changed'\n  | 'return_type_changed'\n  | 'enum_member_value_changed';\n\n/** Soft-risk change categories — may affect callers depending on usage. */\nexport type SoftRiskChangeCategory =\n  | 'parameter_added_non_terminal_optional'\n  | 'constructor_reordered_named_friendly'\n  | 'default_value_changed'\n  | 'wrapper_stricter_than_previous_sdk_but_matches_spec'\n  | 'doc_surface_drift';\n\n/** Additive change categories — safe to ship. */\nexport type AdditiveChangeCategory =\n  | 'symbol_added'\n  | 'parameter_added_optional_terminal'\n  | 'new_constructor_overload_added'\n  | 'new_wrapper_alias_added';\n\n/** All change categories. */\nexport type CompatChangeCategory = BreakingChangeCategory | SoftRiskChangeCategory | AdditiveChangeCategory;\n\n/** Change severity levels. */\nexport type CompatChangeSeverity = 'breaking' | 'soft-risk' | 'additive';\n\n/** Provenance bucket — where the drift originated. */\nexport type CompatProvenance =\n  | 'spec_shape_change'\n  | 'spec_ordering_change'\n  | 'emitter_template_change'\n  | 'compat_extractor_change'\n  | 'operation_hint_change'\n  | 'manual_override_change'\n  | 'normalization_change'\n  | 'unknown';\n\n// ---------------------------------------------------------------------------\n// Fail threshold\n// ---------------------------------------------------------------------------\n\n/** Level at which `verify` should fail. */\nexport type CompatFailLevel = 'none' | 'breaking' | 'soft-risk';\n\n// ---------------------------------------------------------------------------\n// Approvals\n// ---------------------------------------------------------------------------\n\n/** A single intentional-break approval in `oagen.config.ts`. */\nexport interface CompatApproval {\n  /** Fully-qualified symbol (e.g., \"Acme\\\\Service\\\\Users::createUser\"). */\n  symbol: string;\n  /** The kind of change being approved. */\n  category: CompatChangeCategory;\n  /** Languages this approval applies to. Omit for all impacted languages. */\n  appliesTo?: LanguageId[] | 'all-impacted-languages';\n  /** Optional narrowing criteria. */\n  match?: {\n    parameter?: string;\n    member?: string;\n    oldName?: string;\n    newName?: string;\n  };\n  /** Minimum release level required for this break. */\n  allowedReleaseLevel?: 'major' | 'minor' | 'patch';\n  /** Human-readable reason for this approval. */\n  reason: string;\n  /** Issue tracker reference (e.g., \"SDK-1234\"). */\n  issue?: string;\n  /** Auto-expire this approval after a version is released. */\n  expiresAfterVersion?: string;\n  /** Whether this approval is currently active. */\n  approved?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Config section\n// ---------------------------------------------------------------------------\n\n/** The `compat` section of `oagen.config.ts`. */\nexport interface CompatConfig {\n  /** Level at which `oagen verify` should fail. Default: 'breaking'. */\n  failOn?: CompatFailLevel;\n  /** Path to write the machine-readable compat report. */\n  reportPath?: string;\n  /** Include provenance explanations in reports. */\n  explain?: boolean;\n  /** Path to the baseline compatibility snapshot. */\n  baselinePath?: string;\n  /** Per-language policy overrides. Sparse — only override what diverges. */\n  languagePolicy?: Partial<Record<LanguageId, Partial<CompatPolicyHints>>>;\n  /** Intentional break approvals. */\n  allow?: CompatApproval[];\n}\n\n// ---------------------------------------------------------------------------\n// Category → severity mapping\n// ---------------------------------------------------------------------------\n\nconst BREAKING_CATEGORIES: ReadonlySet<BreakingChangeCategory> = new Set<BreakingChangeCategory>([\n  'symbol_removed',\n  'symbol_renamed',\n  'parameter_removed',\n  'parameter_renamed',\n  'parameter_requiredness_increased',\n  'parameter_type_narrowed',\n  'parameter_position_changed_order_sensitive',\n  'constructor_position_changed_order_sensitive',\n  'named_arg_name_removed',\n  'keyword_name_removed',\n  'overload_removed',\n  'union_wrapper_migration_without_compat_alias',\n  'field_type_changed',\n  'return_type_changed',\n  'enum_member_value_changed',\n]);\n\nconst SOFT_RISK_CATEGORIES: ReadonlySet<SoftRiskChangeCategory> = new Set<SoftRiskChangeCategory>([\n  'parameter_added_non_terminal_optional',\n  'constructor_reordered_named_friendly',\n  'default_value_changed',\n  'wrapper_stricter_than_previous_sdk_but_matches_spec',\n  'doc_surface_drift',\n]);\n\n/** Get the default severity for a change category. */\nexport function defaultSeverityForCategory(category: CompatChangeCategory): CompatChangeSeverity {\n  if (BREAKING_CATEGORIES.has(category as BreakingChangeCategory)) return 'breaking';\n  if (SOFT_RISK_CATEGORIES.has(category as SoftRiskChangeCategory)) return 'soft-risk';\n  return 'additive';\n}\n\n/** Check whether a severity meets or exceeds a fail threshold. */\nexport function severityMeetsThreshold(severity: CompatChangeSeverity, threshold: CompatFailLevel): boolean {\n  if (threshold === 'none') return false;\n  if (threshold === 'soft-risk') return severity === 'breaking' || severity === 'soft-risk';\n  return severity === 'breaking';\n}\n","/**\n * Change classifier for compatibility verification.\n *\n * Takes raw diffs between baseline and candidate compat snapshots and\n * classifies each change into a specific category with policy-aware severity.\n */\n\nimport type { CompatSymbol, CompatParameter } from './ir.js';\nimport type { CompatPolicyHints } from './policy.js';\nimport type { CompatChangeCategory, CompatChangeSeverity, CompatProvenance } from './config.js';\nimport { defaultSeverityForCategory } from './config.js';\n\n/** A single classified compatibility change. */\nexport interface ClassifiedChange {\n  /** Specific change category. */\n  category: CompatChangeCategory;\n  /** Policy-aware severity (may differ from defaultSeverityForCategory). */\n  severity: CompatChangeSeverity;\n  /** Fully-qualified symbol path. */\n  symbol: string;\n  /** Deterministic ID for grouping related changes across languages. */\n  conceptualChangeId: string;\n  /** Where the drift originated. */\n  provenance: CompatProvenance;\n  /** Description of the old state. */\n  old: Record<string, string>;\n  /** Description of the new state. */\n  new: Record<string, string>;\n  /** Human-readable explanation. */\n  message: string;\n  /**\n   * Optional spec-level remediation hint. Set by post-classification rules\n   * (see `detectForkedSchemas` in differ.ts) when a change has a recognized\n   * upstream root cause that the spec author can fix. Surfaces in both the\n   * machine-readable report and the human-readable summary.\n   */\n  remediation?: string;\n}\n\n/** Result of classifying all changes between two snapshots. */\nexport interface ClassificationResult {\n  changes: ClassifiedChange[];\n  summary: {\n    breaking: number;\n    softRisk: number;\n    additive: number;\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Classification engine\n// ---------------------------------------------------------------------------\n\n/**\n * Classify changes between a baseline and candidate symbol.\n * Returns one or more classified changes for the diff.\n */\nexport function classifySymbolChanges(\n  baseline: CompatSymbol,\n  candidate: CompatSymbol | undefined,\n  policy: CompatPolicyHints,\n): ClassifiedChange[] {\n  const changes: ClassifiedChange[] = [];\n\n  // Build spec-level ref for cross-language grouping.\n  // Prefer schemaName from either symbol (baseline for removals, candidate for adds).\n  const specRef = baseline.schemaName ?? candidate?.schemaName;\n\n  // Symbol removed\n  if (!candidate) {\n    changes.push(\n      makeChange({\n        category: 'symbol_removed',\n        symbol: baseline.fqName,\n        old: { symbol: baseline.fqName },\n        new: { symbol: '(removed)' },\n        message: `Symbol \"${baseline.displayName}\" was removed`,\n        policy,\n        specRef,\n      }),\n    );\n    return changes;\n  }\n\n  // Symbol renamed\n  if (baseline.fqName !== candidate.fqName && baseline.id === candidate.id) {\n    changes.push(\n      makeChange({\n        category: 'symbol_renamed',\n        symbol: baseline.fqName,\n        old: { name: baseline.fqName },\n        new: { name: candidate.fqName },\n        message: `Symbol renamed from \"${baseline.displayName}\" to \"${candidate.displayName}\"`,\n        policy,\n        specRef,\n      }),\n    );\n  }\n\n  // Parameter-level changes (for callables and constructors)\n  if (baseline.parameters && candidate.parameters) {\n    changes.push(...classifyParameterChanges(baseline, candidate, policy, specRef));\n  }\n\n  // Return type changes (for callables)\n  if (baseline.returns && candidate.returns && baseline.returns.name !== candidate.returns.name) {\n    changes.push(\n      makeChange({\n        category: 'return_type_changed',\n        symbol: baseline.fqName,\n        old: { returnType: baseline.returns.name },\n        new: { returnType: candidate.returns.name },\n        message: `Return type changed for \"${baseline.displayName}\" from \"${baseline.returns.name}\" to \"${candidate.returns.name}\"`,\n        policy,\n        specRef,\n      }),\n    );\n  }\n\n  // Field/property type changes\n  if (baseline.typeRef && candidate.typeRef && baseline.typeRef.name !== candidate.typeRef.name) {\n    changes.push(\n      makeChange({\n        category: 'field_type_changed',\n        symbol: baseline.fqName,\n        old: { type: baseline.typeRef.name },\n        new: { type: candidate.typeRef.name },\n        message: `Type changed for \"${baseline.displayName}\" from \"${baseline.typeRef.name}\" to \"${candidate.typeRef.name}\"`,\n        policy,\n        specRef,\n      }),\n    );\n  }\n\n  // Enum member value changes\n  if (\n    baseline.kind === 'enum_member' &&\n    candidate.kind === 'enum_member' &&\n    baseline.value !== undefined &&\n    candidate.value !== undefined &&\n    baseline.value !== candidate.value\n  ) {\n    changes.push(\n      makeChange({\n        category: 'enum_member_value_changed',\n        symbol: baseline.fqName,\n        old: { value: String(baseline.value) },\n        new: { value: String(candidate.value) },\n        message: `Enum value changed for \"${baseline.displayName}\" from \"${baseline.value}\" to \"${candidate.value}\"`,\n        policy,\n      }),\n    );\n  }\n\n  return changes;\n}\n\n/**\n * Classify parameter-level changes between two symbol versions.\n */\nfunction classifyParameterChanges(\n  baseline: CompatSymbol,\n  candidate: CompatSymbol,\n  policy: CompatPolicyHints,\n  specRef?: string,\n): ClassifiedChange[] {\n  const changes: ClassifiedChange[] = [];\n  const baseParams = baseline.parameters ?? [];\n  const candParams = candidate.parameters ?? [];\n\n  const baseByName = new Map(baseParams.map((p) => [p.publicName, p]));\n  const candByName = new Map(candParams.map((p) => [p.publicName, p]));\n  const isConstructor = baseline.kind === 'constructor';\n\n  // Check each baseline parameter\n  for (const baseParam of baseParams) {\n    const candParam = candByName.get(baseParam.publicName);\n\n    if (!candParam) {\n      // Parameter removed — check if it was renamed\n      const positionalMatch = candParams[baseParam.position];\n      if (positionalMatch && !baseByName.has(positionalMatch.publicName)) {\n        // Position preserved but name changed → rename\n        const isBreakingRename = parameterNameIsPublicApi(baseParam, policy, isConstructor);\n        changes.push(\n          makeChange({\n            category: 'parameter_renamed',\n            symbol: baseline.fqName,\n            old: { parameter: baseParam.publicName },\n            new: { parameter: positionalMatch.publicName },\n            message: `Parameter \"${baseParam.publicName}\" renamed to \"${positionalMatch.publicName}\" on \"${baseline.displayName}\"`,\n            policy,\n            specRef,\n            severityOverride: isBreakingRename ? undefined : 'soft-risk',\n          }),\n        );\n      } else {\n        // Truly removed\n        changes.push(\n          makeChange({\n            category: 'parameter_removed',\n            symbol: baseline.fqName,\n            old: { parameter: baseParam.publicName },\n            new: { parameter: '(removed)' },\n            message: `Parameter \"${baseParam.publicName}\" removed from \"${baseline.displayName}\"`,\n            policy,\n            specRef,\n          }),\n        );\n      }\n      continue;\n    }\n\n    // Requiredness increased (optional → required)\n    if (!baseParam.required && candParam.required) {\n      changes.push(\n        makeChange({\n          category: 'parameter_requiredness_increased',\n          symbol: baseline.fqName,\n          old: { parameter: baseParam.publicName, required: 'false' },\n          new: { parameter: candParam.publicName, required: 'true' },\n          message: `Parameter \"${baseParam.publicName}\" became required on \"${baseline.displayName}\"`,\n          policy,\n          specRef,\n        }),\n      );\n    }\n\n    // Type narrowed\n    if (baseParam.type.name !== candParam.type.name) {\n      changes.push(\n        makeChange({\n          category: 'parameter_type_narrowed',\n          symbol: baseline.fqName,\n          old: { parameter: baseParam.publicName, type: baseParam.type.name },\n          new: { parameter: candParam.publicName, type: candParam.type.name },\n          message: `Parameter type changed for \"${baseParam.publicName}\" on \"${baseline.displayName}\"`,\n          policy,\n          specRef,\n        }),\n      );\n    }\n\n    // Position changed.\n    //\n    // Constructors are governed by `policy.constructorOrderMatters` — some\n    // languages treat ctor positional order as part of the public API even\n    // when method args are named.\n    //\n    // For methods, the parameter's `passing` style decides:\n    //   - 'positional'     → callers reference by index; reorder is breaking\n    //   - 'named'          → both styles work; reorder is soft-risk (positional callers exist)\n    //   - 'keyword'        → callers MUST use names (Ruby kwargs, Python kw-only, Elixir); position invisible\n    //   - 'options_object' → callers pass a single object literal (Node); position invisible\n    if (baseParam.position !== candParam.position) {\n      if (isConstructor) {\n        if (policy.constructorOrderMatters) {\n          changes.push(\n            makeChange({\n              category: 'constructor_position_changed_order_sensitive',\n              symbol: baseline.fqName,\n              old: { parameter: baseParam.publicName, position: String(baseParam.position) },\n              new: { parameter: candParam.publicName, position: String(candParam.position) },\n              message: `Parameter \"${baseParam.publicName}\" moved from position ${baseParam.position} to ${candParam.position} on \"${baseline.displayName}\"`,\n              policy,\n              specRef,\n            }),\n          );\n        } else {\n          changes.push(\n            makeChange({\n              category: 'constructor_reordered_named_friendly',\n              symbol: baseline.fqName,\n              old: { parameter: baseParam.publicName, position: String(baseParam.position) },\n              new: { parameter: candParam.publicName, position: String(candParam.position) },\n              message: `Parameter \"${baseParam.publicName}\" reordered on \"${baseline.displayName}\" (named-friendly language)`,\n              policy,\n              specRef,\n            }),\n          );\n        }\n      } else if (baseParam.passing === 'positional') {\n        changes.push(\n          makeChange({\n            category: 'parameter_position_changed_order_sensitive',\n            symbol: baseline.fqName,\n            old: { parameter: baseParam.publicName, position: String(baseParam.position) },\n            new: { parameter: candParam.publicName, position: String(candParam.position) },\n            message: `Parameter \"${baseParam.publicName}\" moved from position ${baseParam.position} to ${candParam.position} on \"${baseline.displayName}\"`,\n            policy,\n            specRef,\n          }),\n        );\n      } else if (baseParam.passing === 'named') {\n        changes.push(\n          makeChange({\n            category: 'constructor_reordered_named_friendly',\n            symbol: baseline.fqName,\n            old: { parameter: baseParam.publicName, position: String(baseParam.position) },\n            new: { parameter: candParam.publicName, position: String(candParam.position) },\n            message: `Parameter \"${baseParam.publicName}\" reordered on \"${baseline.displayName}\" (named-friendly language)`,\n            policy,\n            specRef,\n          }),\n        );\n      }\n      // keyword / options_object: position is invisible to callers — no change emitted.\n    }\n  }\n\n  // Check for new parameters in candidate\n  for (const candParam of candParams) {\n    if (!baseByName.has(candParam.publicName)) {\n      // Check if this was already captured as a rename\n      const isRename = changes.some(\n        (c) => c.category === 'parameter_renamed' && c.new.parameter === candParam.publicName,\n      );\n      if (isRename) continue;\n\n      const isTerminal = candParam.position === candParams.length - 1;\n      const category: CompatChangeCategory = candParam.required\n        ? 'parameter_requiredness_increased'\n        : isTerminal\n          ? 'parameter_added_optional_terminal'\n          : 'parameter_added_non_terminal_optional';\n\n      if (candParam.required) {\n        changes.push(\n          makeChange({\n            category,\n            symbol: baseline.fqName,\n            old: { parameter: '(absent)' },\n            new: { parameter: candParam.publicName, required: 'true' },\n            message: `Required parameter \"${candParam.publicName}\" added to \"${baseline.displayName}\"`,\n            policy,\n            specRef,\n          }),\n        );\n      } else {\n        changes.push(\n          makeChange({\n            category,\n            symbol: baseline.fqName,\n            old: { parameter: '(absent)' },\n            new: { parameter: candParam.publicName },\n            message: `Optional parameter \"${candParam.publicName}\" added to \"${baseline.displayName}\"`,\n            policy,\n            specRef,\n          }),\n        );\n      }\n    }\n  }\n\n  return changes;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction parameterNameIsPublicApi(param: CompatParameter, policy: CompatPolicyHints, isConstructor: boolean): boolean {\n  if (param.sensitivity.publicName) return true;\n  if (isConstructor) return policy.constructorParameterNamesArePublicApi;\n  return policy.methodParameterNamesArePublicApi;\n}\n\n/**\n * Build a deterministic conceptual change ID.\n *\n * When `specRef` is provided (e.g. \"GenerateLinkBody.admin_emails\"), it is\n * used instead of the language-specific symbol name.  This ensures the same\n * spec entity produces the same ID across all languages, enabling cross-\n * language rollup in reports.\n */\nfunction buildConceptualChangeId(\n  category: CompatChangeCategory,\n  symbol: string,\n  match: Record<string, string>,\n  specRef?: string,\n): string {\n  const identity = specRef ?? symbol;\n  const parts = ['chg', category, identity.replace(/[^a-zA-Z0-9_.]/g, '_')];\n  if (match.parameter) parts.push(match.parameter);\n  if (match.member) parts.push(match.member);\n  return parts.join('_').toLowerCase();\n}\n\nfunction makeChange(opts: {\n  category: CompatChangeCategory;\n  symbol: string;\n  old: Record<string, string>;\n  new: Record<string, string>;\n  message: string;\n  policy: CompatPolicyHints;\n  provenance?: CompatProvenance;\n  severityOverride?: CompatChangeSeverity;\n  specRef?: string;\n}): ClassifiedChange {\n  return {\n    category: opts.category,\n    severity: opts.severityOverride ?? defaultSeverityForCategory(opts.category),\n    symbol: opts.symbol,\n    conceptualChangeId: buildConceptualChangeId(opts.category, opts.symbol, opts.old, opts.specRef),\n    provenance: opts.provenance ?? 'unknown',\n    old: opts.old,\n    new: opts.new,\n    message: opts.message,\n  };\n}\n\n/**\n * Classify a new symbol as additive.\n */\nexport function classifyAddedSymbol(symbol: CompatSymbol): ClassifiedChange {\n  return {\n    category: 'symbol_added',\n    severity: 'additive',\n    symbol: symbol.fqName,\n    conceptualChangeId: buildConceptualChangeId('symbol_added', symbol.fqName, {}, symbol.schemaName),\n    provenance: 'unknown',\n    old: { symbol: '(absent)' },\n    new: { symbol: symbol.fqName },\n    message: `Symbol \"${symbol.displayName}\" was added`,\n  };\n}\n\n/** Summarize a list of classified changes by severity. */\nexport function summarizeChanges(changes: ClassifiedChange[]): ClassificationResult['summary'] {\n  let breaking = 0;\n  let softRisk = 0;\n  let additive = 0;\n  for (const c of changes) {\n    if (c.severity === 'breaking') breaking++;\n    else if (c.severity === 'soft-risk') softRisk++;\n    else additive++;\n  }\n  return { breaking, softRisk, additive };\n}\n","import type { ApiSurface, LanguageHints } from './types.js';\nimport { splitWords } from '../utils/naming.js';\n\n/** Untyped map patterns — hoisted to avoid allocation on every isTypeEquivalent call. */\nconst UNTYPED_MAP_PATTERNS = new Set([\n  'Record<string, unknown>',\n  'Record<string, any>',\n  '{ [key: string]: any; }',\n  '{ [key: string]: unknown; }',\n  'any',\n]);\n\nexport const NAMED_TYPE_RE = /^[A-Z][a-zA-Z0-9]*$/;\n\n/** Check whether a type name exists as an interface, class, or enum in a surface. */\nexport function typeExistsInSurface(name: string, surface: ApiSurface): boolean {\n  return !!(surface.interfaces[name] || surface.classes[name] || surface.enums[name]);\n}\n\n/** Split a PascalCase string into words, keeping only words > 2 chars. */\nfunction splitPascalWords(s: string): string[] {\n  return splitWords(s).filter((w) => w.length > 2);\n}\n\n/**\n * Check whether two named types share enough PascalCase word components to\n * be considered equivalent (handles name reordering from Json merges, etc.).\n * Both names have `Response$` stripped before comparison.\n */\nexport function namedTypeWordsOverlap(a: string, b: string, minOverlap = 1): boolean {\n  const aNoResp = a.replace(/Response$/, '');\n  const bNoResp = b.replace(/Response$/, '');\n  const aWords = new Set(splitPascalWords(aNoResp).map((w) => w.toLowerCase()));\n  const bWords = new Set(splitPascalWords(bNoResp).map((w) => w.toLowerCase()));\n  const overlap = [...aWords].filter((w) => bWords.has(w));\n  return overlap.length >= minOverlap && overlap.length >= Math.min(aWords.size, bWords.size) - 1;\n}\n\n/** Split a pipe-delimited union string into trimmed, non-empty members. */\nfunction parseUnionMembers(s: string): string[] {\n  return s\n    .split('|')\n    .map((p) => p.trim())\n    .filter(Boolean);\n}\n\n/**\n * Default implementation of isNullableOnlyDifference — shared across extractors.\n * Returns true when stripping nullable wrappers from both sides yields the same\n * type, but the original types differ (i.e., the only difference is nullability).\n */\nexport function defaultIsNullableOnlyDifference(\n  hints: Pick<LanguageHints, 'stripNullable'>,\n  a: string,\n  b: string,\n): boolean {\n  return (hints.stripNullable(a) ?? a) === (hints.stripNullable(b) ?? b) && a !== b;\n}\n\n/**\n * Node/TypeScript language hints — reference implementation.\n * Extracted from the hardcoded logic previously in differ.ts and overlay.ts.\n */\nexport const nodeHints: LanguageHints = {\n  stripNullable(type: string): string | null {\n    const members = parseUnionMembers(type);\n    const stripped = members.filter((p) => p !== 'null');\n    if (stripped.length === members.length) {\n      return null; // no null member found\n    }\n    return stripped.join(' | ');\n  },\n\n  isNullableOnlyDifference(a: string, b: string): boolean {\n    return (nodeHints.stripNullable(a) ?? a) === (nodeHints.stripNullable(b) ?? b) && a !== b;\n  },\n\n  isUnionReorder(a: string, b: string): boolean {\n    const membersA = parseUnionMembers(a).sort();\n    const membersB = parseUnionMembers(b).sort();\n    if (membersA.length !== membersB.length || membersA.length < 2) return false;\n    return membersA.every((m, i) => m === membersB[i]);\n  },\n\n  isGenericTypeParam(type: string): boolean {\n    if (/^[A-Z]$/.test(type)) return true;\n    if (/^T[A-Z][a-zA-Z]*$/.test(type)) return true;\n    if (/^[A-Z]\\[\\]$/.test(type) || /^T[A-Z][a-zA-Z]*\\[\\]$/.test(type)) return true;\n    return false;\n  },\n\n  isExtractionArtifact(type: string): boolean {\n    return type === 'any' || type === 'Record<string, unknown>';\n  },\n\n  tolerateCategoryMismatch: true,\n\n  extractReturnTypeName(returnType: string): string | null {\n    let inner = returnType;\n    while (inner.startsWith('Promise<') && inner.endsWith('>')) {\n      inner = inner.slice(8, -1);\n    }\n    const genericMatch = inner.match(/^[A-Za-z]+<(.+)>$/);\n    if (genericMatch) {\n      inner = genericMatch[1];\n    }\n    inner = inner.replace(/\\[\\]$/, '');\n    if (['void', 'string', 'number', 'boolean', 'any', 'unknown', 'null', 'undefined'].includes(inner)) {\n      return null;\n    }\n    return inner;\n  },\n\n  extractParamTypeName(paramType: string): string | null {\n    if (['string', 'number', 'boolean', 'any', 'unknown'].includes(paramType)) {\n      return null;\n    }\n    return paramType;\n  },\n\n  propertyMatchesClass(propertyName: string, className: string): boolean {\n    // Support both camelCase and snake_case properties matching PascalCase classes\n    // e.g., \"organizations\" ≡ \"Organizations\", \"api_keys\" ≡ \"ApiKeys\"\n    const normalizedProp = propertyName.replace(/[-_]/g, '').toLowerCase();\n    return normalizedProp === className.toLowerCase();\n  },\n\n  derivedModelNames(modelName: string): string[] {\n    return [`${modelName}Response`, `Serialized${modelName}`];\n  },\n\n  isTypeEquivalent(baselineType: string, candidateType: string, candidateSurface: ApiSurface): boolean {\n    // Check if one side is a named enum and the other is an inline union\n    // of that enum's string literal values.\n    // e.g., baseline: '\"active\" | \"inactive\"', candidate: 'ConnectionState'\n    //    or baseline: 'ConnectionState', candidate: '\"active\" | \"inactive\"'\n\n    // Try: candidate is enum name, baseline is inline union of string literals.\n    // The generated enum may have MORE members than the baseline (new spec values),\n    // so check that all baseline members exist in the enum (subset match).\n    const candEnum = candidateSurface.enums[candidateType];\n    if (candEnum) {\n      const enumValuesSet = new Set(Object.values(candEnum.members).flatMap((v) => [`\"${v}\"`, `'${v}'`]));\n      const baseMembers = parseUnionMembers(baselineType);\n      if (baseMembers.length > 0 && baseMembers.every((m) => enumValuesSet.has(m))) {\n        return true;\n      }\n    }\n\n    // Tolerate untyped-map equivalences:\n    // { [key: string]: any; } ≡ Record<string, unknown> ≡ Record<string, any>\n    if (UNTYPED_MAP_PATTERNS.has(baselineType) && UNTYPED_MAP_PATTERNS.has(candidateType)) {\n      return true;\n    }\n\n    // Tolerate inline object literal vs named model in candidate.\n    // e.g., baseline: '{ type: \"organization\"; id: string; }', candidate: 'ApiKeyOwner'\n    // The named model is more structured but semantically equivalent.\n    if (baselineType.startsWith('{') && baselineType.endsWith('}')) {\n      if (typeExistsInSurface(candidateType, candidateSurface)) {\n        return true;\n      }\n    }\n\n    // Tolerate named-type-to-named-type mismatches when both types exist\n    // as models/interfaces/enums in their respective surfaces. This handles\n    // cases where the parser qualifies inline types with parent names while\n    // the live SDK uses shared types:\n    //   baseline: RoleResponse, candidate: OrganizationMembershipRole\n    //   baseline: ConnectionType, candidate: ProfileConnectionType\n    //   baseline: AuditLogTargetSchema[], candidate: AuditLogSchemaJsonTarget[]\n    const baseClean = baselineType.replace(/\\[\\]$/, '');\n    const candClean = candidateType.replace(/\\[\\]$/, '');\n    const sameArrayness = baselineType.endsWith('[]') === candidateType.endsWith('[]');\n\n    // Response suffix equivalence (both directions)\n    if (sameArrayness) {\n      if (candClean === baseClean + 'Response' || baseClean === candClean + 'Response') {\n        return true;\n      }\n    }\n\n    // Both are named types (PascalCase, no operators) — check if candidate\n    // is a known model/interface/enum, and baseline looks like a named type too.\n    // This tolerates the parser's qualified naming vs the live SDK's shared naming.\n    if (sameArrayness && NAMED_TYPE_RE.test(baseClean) && NAMED_TYPE_RE.test(candClean)) {\n      if (typeExistsInSurface(candClean, candidateSurface)) {\n        // One name contains the other (e.g., ProfileConnectionType contains ConnectionType)\n        if (candClean.includes(baseClean) || baseClean.includes(candClean)) {\n          return true;\n        }\n        // Strip Response suffix and check containment\n        const baseNoResp = baseClean.replace(/Response$/, '');\n        const candNoResp = candClean.replace(/Response$/, '');\n        if (candNoResp.includes(baseNoResp) || baseNoResp.includes(candNoResp)) {\n          return true;\n        }\n        // Word-component overlap: split PascalCase into words and check\n        // if they share enough meaningful words (handles name reordering\n        // from Json merges: AuditLogTargetSchema vs AuditLogSchemaJsonTarget)\n        if (namedTypeWordsOverlap(baseClean, candClean, 2)) {\n          return true;\n        }\n      }\n    }\n\n    return false;\n  },\n};\n\n/**\n * Merge partial language hint overrides over nodeHints defaults.\n * Any hint not provided falls back to the Node/TypeScript implementation.\n */\nexport function resolveHints(overrides: Partial<LanguageHints>): LanguageHints {\n  return { ...nodeHints, ...overrides };\n}\n","import type { ApiSpec, TypeRef } from '../ir/types.js';\nimport { walkTypeRef } from '../ir/types.js';\nimport type { ApiSurface, LanguageHints } from './types.js';\n\n/**\n * Compute the set of symbol names that are derivable from the OpenAPI spec.\n * Only these names should be compared during compat verification — everything\n * else in the baseline is hand-written and out of scope for generation.\n */\nexport function specDerivedNames(spec: ApiSpec, hints: LanguageHints): Set<string> {\n  const names = new Set<string>();\n\n  // Build set of top-level enum names for filtering inline enums\n  const topLevelEnumNames = new Set(spec.enums.map((e) => e.name));\n\n  // Service classes\n  for (const service of spec.services) {\n    names.add(service.name);\n    for (const op of service.operations) {\n      // Operation methods are matched by the class diff, not by name here\n      collectTypeRefNames(op.response, names, hints, topLevelEnumNames);\n      if (op.requestBody) collectTypeRefNames(op.requestBody, names, hints, topLevelEnumNames);\n      for (const p of [...op.pathParams, ...op.queryParams, ...op.headerParams, ...(op.cookieParams ?? [])]) {\n        collectTypeRefNames(p.type, names, hints, topLevelEnumNames);\n      }\n    }\n  }\n\n  // Models → domain interface + language-specific derived names\n  for (const model of spec.models) {\n    names.add(model.name);\n    for (const derived of hints.derivedModelNames(model.name)) {\n      names.add(derived);\n    }\n    for (const field of model.fields) {\n      collectTypeRefNames(field.type, names, hints, topLevelEnumNames);\n    }\n  }\n\n  // Enums → type aliases\n  for (const e of spec.enums) {\n    names.add(e.name);\n  }\n\n  return names;\n}\n\n/**\n * Compute a map of enum name → set of wire values that appear in the spec.\n * Used by filterSurface to exclude hand-added enum members that aren't in the spec.\n */\nexport function specDerivedEnumValues(spec: ApiSpec): Map<string, Set<string | number>> {\n  const result = new Map<string, Set<string | number>>();\n  for (const e of spec.enums) {\n    result.set(e.name, new Set(e.values.map((v) => v.value)));\n  }\n  return result;\n}\n\n/**\n * Compute the set of field paths (e.g., \"Organization.name\") that are defined\n * in the OpenAPI spec's model schemas. Used by filterSurface to exclude\n * hand-added SDK fields that reference spec-derived types.\n */\nexport function specDerivedFieldPaths(spec: ApiSpec, hints: LanguageHints): Set<string> {\n  const paths = new Set<string>();\n  for (const model of spec.models) {\n    for (const field of model.fields) {\n      paths.add(`${model.name}.${field.name}`);\n    }\n    // Also add field paths for derived model names (e.g., OrganizationResponse.name)\n    for (const derived of hints.derivedModelNames(model.name)) {\n      for (const field of model.fields) {\n        paths.add(`${derived}.${field.name}`);\n      }\n    }\n  }\n  return paths;\n}\n\n/**\n * Compute the set of method paths (e.g., \"Auth.authorize\") that are defined\n * as operations in the OpenAPI spec's services. Used by filterSurface to\n * exclude hand-written SDK methods that don't correspond to spec operations.\n */\nexport function specDerivedMethodPaths(spec: ApiSpec): Set<string> {\n  const paths = new Set<string>();\n  for (const service of spec.services) {\n    for (const op of service.operations) {\n      paths.add(`${service.name}.${op.name}`);\n    }\n  }\n  return paths;\n}\n\n/**\n * Compute the set of HTTP operation keys (e.g., \"GET /auth/authorize\") that\n * exist in the spec. Used for overlay-based method matching.\n */\nexport function specDerivedHttpKeys(spec: ApiSpec): Set<string> {\n  const keys = new Set<string>();\n  for (const service of spec.services) {\n    for (const op of service.operations) {\n      keys.add(`${op.httpMethod.toUpperCase()} ${op.path}`);\n    }\n  }\n  return keys;\n}\n\nfunction collectTypeRefNames(ref: TypeRef, out: Set<string>, hints: LanguageHints, topLevelEnums?: Set<string>): void {\n  walkTypeRef(ref, {\n    model: (r) => {\n      out.add(r.name);\n      for (const derived of hints.derivedModelNames(r.name)) {\n        out.add(derived);\n      }\n    },\n    enum: (r) => {\n      // Only include enums that are top-level (in spec.enums). Inline enums\n      // embedded in TypeRefs (e.g., query parameter enums) may not be emitted\n      // by all emitters, so they should not create false-positive violations.\n      if (!topLevelEnums || topLevelEnums.has(r.name)) {\n        out.add(r.name);\n      }\n    },\n  });\n}\n\nfunction filterRecord<T>(record: Record<string, T>, allowed: Set<string>): Record<string, T> {\n  const result: Record<string, T> = {};\n  for (const [name, value] of Object.entries(record)) {\n    if (allowed.has(name)) result[name] = value;\n  }\n  return result;\n}\n\n/**\n * Filter an ApiSurface to only include symbols whose names appear in the\n * allowed set. Symbols not in the set are dropped entirely — they won't\n * count toward the total or produce violations.\n *\n * For interfaces: when fieldPaths is provided, only keeps fields that appear\n * in the spec-derived field paths. This prevents false positives from hand-added\n * SDK fields that reference spec-derived types but aren't defined in the spec.\n *\n * For classes: when methodPaths is provided, only keeps methods whose names\n * appear in the spec-derived method paths. This prevents false positives from\n * hand-written SDK methods (e.g., Auth.authorization_url, Webhooks.construct_event)\n * that don't correspond to spec operations. Properties on service classes are\n * also filtered: only UPPER_CASE constants that are spec-derivable are kept.\n */\nexport function filterSurface(\n  surface: ApiSurface,\n  allowedNames: Set<string>,\n  opts?: {\n    fieldPaths?: Set<string>;\n    methodPaths?: Set<string>;\n    enumValues?: Map<string, Set<string | number>>;\n  },\n): ApiSurface {\n  const { fieldPaths, methodPaths, enumValues } = opts ?? {};\n  const filteredInterfaces = filterRecord(surface.interfaces, allowedNames);\n\n  // Filter interface fields by spec-derived field paths if provided\n  if (fieldPaths) {\n    for (const [name, iface] of Object.entries(filteredInterfaces)) {\n      const filteredFields: Record<string, (typeof iface.fields)[string]> = {};\n      for (const [fieldName, field] of Object.entries(iface.fields)) {\n        // Keep the field if its path is spec-derived\n        if (fieldPaths.has(`${name}.${fieldName}`)) {\n          filteredFields[fieldName] = field;\n        }\n      }\n      filteredInterfaces[name] = { ...iface, fields: filteredFields };\n    }\n  }\n\n  let filteredClasses = filterRecord(surface.classes, allowedNames);\n\n  // Filter class methods and properties by spec-derived method paths if provided\n  if (methodPaths) {\n    // Build a set of service-class names that have spec-derived methods.\n    // Only filter methods on these classes; non-service model classes keep all members.\n    const serviceClassNames = new Set<string>();\n    for (const path of methodPaths) {\n      const dot = path.indexOf('.');\n      if (dot !== -1) serviceClassNames.add(path.slice(0, dot));\n    }\n\n    const newClasses: Record<string, (typeof filteredClasses)[string]> = {};\n    for (const [name, cls] of Object.entries(filteredClasses)) {\n      if (serviceClassNames.has(name)) {\n        // Service class — filter methods and properties by spec-derived method paths\n        const filteredMethods: typeof cls.methods = {};\n        for (const [methodName, overloads] of Object.entries(cls.methods)) {\n          if (methodPaths.has(`${name}.${methodName}`)) {\n            filteredMethods[methodName] = overloads;\n          }\n        }\n\n        // Filter properties: only keep properties that are spec-derivable.\n        // Hand-written constants (PROVIDERS, DEFAULT_TOLERANCE, WIDGET_SCOPES)\n        // are not derivable from the spec and should be excluded.\n        const filteredProperties: typeof cls.properties = {};\n        for (const [propName, prop] of Object.entries(cls.properties)) {\n          if (methodPaths.has(`${name}.${propName}`)) {\n            filteredProperties[propName] = prop;\n          }\n        }\n\n        newClasses[name] = {\n          ...cls,\n          methods: filteredMethods,\n          properties: filteredProperties,\n        };\n      } else if (fieldPaths) {\n        // Non-service (model) class — filter properties by spec-derived field paths.\n        // In some languages (Ruby, PHP), models are represented as classes with\n        // properties rather than interfaces with fields. Apply the same field-level\n        // filtering used for interfaces to exclude hand-added SDK fields.\n        const filteredProperties: typeof cls.properties = {};\n        for (const [propName, prop] of Object.entries(cls.properties)) {\n          if (fieldPaths.has(`${name}.${propName}`)) {\n            filteredProperties[propName] = prop;\n          }\n        }\n\n        // Also filter methods on model classes: convenience methods like\n        // `primary_email` are hand-written and not spec-derivable.\n        // Keep utility methods (from_json, to_json, etc.) if they appear in fieldPaths,\n        // otherwise drop non-spec methods.\n        const filteredMethods: typeof cls.methods = {};\n        for (const [methodName, overloads] of Object.entries(cls.methods)) {\n          if (fieldPaths.has(`${name}.${methodName}`) || methodPaths.has(`${name}.${methodName}`)) {\n            filteredMethods[methodName] = overloads;\n          }\n        }\n\n        newClasses[name] = {\n          ...cls,\n          methods: filteredMethods,\n          properties: filteredProperties,\n        };\n      } else {\n        // No filtering available — keep as-is\n        newClasses[name] = cls;\n      }\n    }\n    filteredClasses = newClasses;\n  }\n\n  // Filter enum members by spec-derived values if provided\n  let filteredEnums = filterRecord(surface.enums, allowedNames);\n  if (enumValues) {\n    const newEnums: Record<string, (typeof filteredEnums)[string]> = {};\n    for (const [name, enumDef] of Object.entries(filteredEnums)) {\n      const specValues = enumValues.get(name);\n      if (!specValues) {\n        // Enum not in spec values map — keep as-is\n        newEnums[name] = enumDef;\n        continue;\n      }\n      // Filter members: keep only those whose wire value is in the spec.\n      // Use case-insensitive comparison since some extractors produce\n      // PascalCase values (e.g., \"Pending\") while the spec has lowercase.\n      const specValuesLower = new Set([...specValues].map((v) => String(v).toLowerCase()));\n      const filteredMembers: typeof enumDef.members = {};\n      for (const [member, value] of Object.entries(enumDef.members)) {\n        if (specValues.has(value) || specValuesLower.has(String(value).toLowerCase())) {\n          filteredMembers[member] = value;\n        }\n      }\n      newEnums[name] = { ...enumDef, members: filteredMembers };\n    }\n    filteredEnums = newEnums;\n  }\n\n  return {\n    ...surface,\n    classes: filteredClasses,\n    interfaces: filteredInterfaces,\n    typeAliases: filterRecord(surface.typeAliases, allowedNames),\n    enums: filteredEnums,\n    exports: {}, // exports are structural, not symbol-level — skip for scoped comparison\n  };\n}\n","/**\n * Compatibility diff engine.\n *\n * Compares two API surfaces (or compat snapshots) and produces classified\n * changes with policy-aware severity, provenance, and conceptual change IDs.\n *\n * This replaces the previous unclassified diff engine with a richer model\n * that supports cross-language severity analysis and approval matching.\n */\n\nimport type { ApiSurface, ApiMethod, LanguageHints, DiffResult, Violation, Addition } from './types.js';\nimport type { CompatSnapshot, CompatSymbol } from './ir.js';\nimport type { CompatPolicyHints } from './policy.js';\nimport type { ClassifiedChange, ClassificationResult } from './classify.js';\nimport { classifySymbolChanges, classifyAddedSymbol, summarizeChanges } from './classify.js';\nimport { NAMED_TYPE_RE, typeExistsInSurface } from './language-hints.js';\n\nexport {\n  specDerivedNames,\n  specDerivedFieldPaths,\n  specDerivedMethodPaths,\n  specDerivedHttpKeys,\n  specDerivedEnumValues,\n  filterSurface,\n} from './spec-filter.js';\n\n// ---------------------------------------------------------------------------\n// New: CompatSnapshot-based diff\n// ---------------------------------------------------------------------------\n\n/** Result of diffing two compat snapshots. */\nexport interface CompatDiffResult {\n  changes: ClassifiedChange[];\n  summary: ClassificationResult['summary'];\n}\n\n/**\n * Diff two compat snapshots, producing classified changes with\n * policy-aware severity.\n */\nexport function diffSnapshots(\n  baseline: CompatSnapshot,\n  candidate: CompatSnapshot,\n  policy?: CompatPolicyHints,\n): CompatDiffResult {\n  const effectivePolicy = policy ?? baseline.policies;\n  const changes: ClassifiedChange[] = [];\n\n  // Build set of service wrapper fqNames from both snapshots so we can\n  // suppress constructor noise — users never instantiate service classes\n  // directly, so their constructor changes are not public-API breaking.\n  const serviceAccessors = new Set<string>();\n  for (const sym of baseline.symbols) {\n    if (sym.kind === 'service_accessor') serviceAccessors.add(sym.fqName);\n  }\n  for (const sym of candidate.symbols) {\n    if (sym.kind === 'service_accessor') serviceAccessors.add(sym.fqName);\n  }\n\n  // Index candidate symbols by ID and fqName for lookup\n  const candById = new Map<string, CompatSymbol>();\n  const candByFqName = new Map<string, CompatSymbol>();\n  for (const sym of candidate.symbols) {\n    candById.set(sym.id, sym);\n    candByFqName.set(sym.fqName, sym);\n  }\n\n  // Index baseline symbols by fqName\n  const baseByFqName = new Set<string>();\n  for (const sym of baseline.symbols) {\n    baseByFqName.add(sym.fqName);\n  }\n\n  // Compare each baseline symbol against candidate\n  for (const baseSym of baseline.symbols) {\n    if (isServiceWrapperConstructor(baseSym, serviceAccessors)) continue;\n    const candSym = candById.get(baseSym.id) ?? candByFqName.get(baseSym.fqName);\n    changes.push(...classifySymbolChanges(baseSym, candSym, effectivePolicy));\n  }\n\n  // Detect added symbols\n  for (const candSym of candidate.symbols) {\n    if (!baseByFqName.has(candSym.fqName)) {\n      if (isServiceWrapperConstructor(candSym, serviceAccessors)) continue;\n      changes.push(classifyAddedSymbol(candSym));\n    }\n  }\n\n  // Post-pass: attach spec-level remediation hints when recognized upstream\n  // patterns are detected. Currently flags the \"schema fork\" antipattern —\n  // a path's response type was redirected to a brand-new schema whose field\n  // set is a superset of the prior schema, which forces a breaking SDK\n  // signature change instead of an additive field on the existing schema.\n  detectForkedSchemas(changes, baseline, candidate);\n\n  // Post-pass: detect type and enum *renames* — cases where a baseline\n  // symbol disappears and a structurally-equivalent symbol takes its place\n  // in the candidate. These are reported as `symbol_removed` (breaking) by\n  // the symbol-level walker because the fqName is gone, but consumer code\n  // that uses the type's fields/methods or the enum's wire values continues\n  // to work — only explicit type annotations and (in dotnet) un-aliased\n  // enum class references actually need to migrate. Downgrade these to\n  // soft-risk so CI gates default-pass while the change stays visible.\n  //\n  // Ordered after detectForkedSchemas so the fork detector's remediation\n  // hint is preserved on the typed cases it owns; renames operate on\n  // pure removals where no fork hint applies.\n  const typeRenames = detectTypeRenames(changes, baseline, candidate);\n  const enumRenames = detectEnumRenames(changes, baseline, candidate);\n  // Transitive pass: when a typed field on a renamed parent points at an\n  // alias type that has no extractable children of its own (common for\n  // discriminated-union owner types — e.g. Go's `APIKeyWithValueOwner`,\n  // generated alongside its parent type), the structural detector can't\n  // pair them on its own. Use the recorded parent rename + the field\n  // typeRefs to derive the secondary rename.\n  inferTransitiveTypeRenames(typeRenames, baseline, candidate, changes);\n  cascadeRenameDowngrades(changes, typeRenames, enumRenames, baseline, candidate);\n\n  return {\n    changes,\n    summary: summarizeChanges(changes),\n  };\n}\n\n/**\n * Detect \"schema fork\" antipattern and attach a remediation hint.\n *\n * Fires when:\n *  1. A return type or field type changed from `OldType` → `NewType`.\n *  2. `NewType` is newly added in the candidate snapshot.\n *  3. `NewType.fields ⊇ OldType.fields` (every field on the old type still\n *     exists on the new one — the new schema is a strict superset, so the\n *     same fields could have been added to the existing schema additively).\n *\n * Mutates `changes` in place: sets `remediation` on the matching change.\n * Leaves the original category and severity alone — this is just a hint.\n *\n * Identity match is by `displayName` of the type symbol, which corresponds\n * to the type name as it appears in `change.old.returnType` / `.type` and\n * `change.new.returnType` / `.type`.\n */\nfunction detectForkedSchemas(changes: ClassifiedChange[], baseline: CompatSnapshot, candidate: CompatSnapshot): void {\n  // Build name → field-name set maps from each snapshot. A \"type\" here is any\n  // symbol that owns field/property children (alias, service_accessor, enum).\n  const baselineTypeFields = collectTypeFieldSets(baseline);\n  const candidateTypeFields = collectTypeFieldSets(candidate);\n  const baselineTypeNames = new Set(baselineTypeFields.keys());\n\n  for (const change of changes) {\n    if (change.remediation) continue;\n\n    let oldType: string | undefined;\n    let newType: string | undefined;\n    if (change.category === 'return_type_changed') {\n      oldType = change.old.returnType;\n      newType = change.new.returnType;\n    } else if (change.category === 'field_type_changed') {\n      oldType = change.old.type;\n      newType = change.new.type;\n    } else {\n      continue;\n    }\n    if (!oldType || !newType || oldType === newType) continue;\n\n    // Strip array/nullable decorations so we compare bare type names. This\n    // covers e.g. `FooList` vs `BarList`, plus simple `Foo[]` vs `Bar[]`.\n    const oldTypeBare = bareTypeName(oldType);\n    const newTypeBare = bareTypeName(newType);\n\n    // The new type must be newly introduced.\n    if (baselineTypeNames.has(newTypeBare)) continue;\n\n    const oldFields = baselineTypeFields.get(oldTypeBare);\n    const newFields = candidateTypeFields.get(newTypeBare);\n    if (!oldFields || !newFields) continue;\n    if (oldFields.size === 0) continue;\n\n    // newFields must be a (non-strict) superset of oldFields.\n    let isSuperset = true;\n    for (const f of oldFields) {\n      if (!newFields.has(f)) {\n        isSuperset = false;\n        break;\n      }\n    }\n    if (!isSuperset) continue;\n\n    change.remediation =\n      `Schema \"${newTypeBare}\" looks like \"${oldTypeBare}\" with additional fields. ` +\n      `Consider adding the new fields to \"${oldTypeBare}\" instead of forking a new schema — ` +\n      `forking forces a breaking type-name change in typed SDKs, while extending the existing ` +\n      `schema is additive.`;\n  }\n}\n\n/**\n * Build a map from type fqName → set of (lowercased) child field names.\n * Used by `detectForkedSchemas` for superset comparison.\n */\nfunction collectTypeFieldSets(snapshot: CompatSnapshot): Map<string, Set<string>> {\n  const result = new Map<string, Set<string>>();\n  for (const sym of snapshot.symbols) {\n    if (sym.kind !== 'field' && sym.kind !== 'property') continue;\n    if (!sym.ownerFqName) continue;\n    const localName = sym.fqName.includes('.') ? sym.fqName.slice(sym.fqName.lastIndexOf('.') + 1) : sym.fqName;\n    let set = result.get(sym.ownerFqName);\n    if (!set) {\n      set = new Set<string>();\n      result.set(sym.ownerFqName, set);\n    }\n    set.add(localName.toLowerCase());\n  }\n  return result;\n}\n\n/**\n * Detect type renames: a baseline type symbol disappears and a candidate\n * type symbol with the same (or superset) field set takes its place.\n *\n * Common when an upstream spec promotes a single schema into multiple\n * (e.g. `ApiKey` → `OrganizationApiKey` + `UserApiKey`). The wire shape\n * returned by individual endpoints is unchanged — `OrganizationApiKey`\n * has the same fields `ApiKey` had — so consumer code accessing those\n * fields *through a return value* keeps working. The parent symbol\n * itself, however, is gone: callers who referenced it by name (Sorbet\n * annotations, `is_a?` checks, pattern matches, deserialization targets)\n * will fail at runtime. The parent removal therefore stays `breaking`;\n * we only attach a remediation hint pointing at the new name.\n *\n * Identity criteria (must all hold):\n *   1. The removed symbol owns ≥ 1 field/property in the baseline (i.e.\n *      it's a type-shaped symbol — model/interface/class — not a plain\n *      function or constant).\n *   2. Some candidate type that did *not* exist in the baseline has a\n *      field set that is a non-strict superset of the removed type's\n *      fields. (Strict-subset would mean fields were lost — a real break.)\n *   3. The candidate type is the alphabetically-first such match, so\n *      pairing is deterministic when multiple candidates fit (e.g. both\n *      `OrganizationApiKey` and `UserApiKey` share the original fields).\n *\n * Returns a `removedName -> newName` map so a downstream cascade pass\n * can downgrade owned-field removals and `*_type_changed` pointing at\n * the same pair — those *are* downgraded to `soft-risk`, since values\n * flowing through the new type continue to expose the same fields.\n *\n * Mutates matching `symbol_removed` entries in `changes`: attaches a\n * `remediation` describing the rename. Severity is left at `breaking`.\n */\nfunction detectTypeRenames(\n  changes: ClassifiedChange[],\n  baseline: CompatSnapshot,\n  candidate: CompatSnapshot,\n): Map<string, string> {\n  const renameMap = new Map<string, string>();\n  const baselineTypeFields = collectTypeFieldSets(baseline);\n  const candidateTypeFields = collectTypeFieldSets(candidate);\n  const baselineTypeNames = new Set(baselineTypeFields.keys());\n  const candidateTypesSorted = [...candidateTypeFields.entries()].sort((a, b) => a[0].localeCompare(b[0]));\n\n  // Index parent `symbol_removed` changes by fqName so we can downgrade\n  // them when a rename is detected. Some languages (Go's enum-alias path\n  // for ordering enums; emitters that emit `type Old = New`) preserve the\n  // old fqName as a candidate alias and never report a removal — that's\n  // fine, the rename map is still populated for the cascade pass.\n  const parentRemovalByName = new Map<string, ClassifiedChange>();\n  for (const change of changes) {\n    if (change.category === 'symbol_removed' && change.severity === 'breaking') {\n      parentRemovalByName.set(change.old.symbol ?? '', change);\n    }\n  }\n\n  // Walk every baseline type *directly*, not via `symbol_removed` events.\n  // The parent-removal path alone misses rename-as-alias cases (e.g. Go\n  // emits `type ApiKey = OrganizationApiKey` to preserve the old name)\n  // because no `symbol_removed` fires for the old name. The structural\n  // match (field-set superset) is what matters, regardless of whether\n  // the old fqName persists as an alias.\n  for (const [baselineTypeName, baselineFields] of baselineTypeFields) {\n    if (baselineFields.size === 0) continue;\n\n    // No-op: same name, same fields still in candidate.\n    const sameNameFields = candidateTypeFields.get(baselineTypeName);\n    if (sameNameFields && setEquals(baselineFields, sameNameFields)) continue;\n\n    // Find a newly-added candidate type (not in baseline) whose field set\n    // is a non-strict superset of the baseline type's fields.\n    const match = candidateTypesSorted.find(([candName, candFields]) => {\n      if (baselineTypeNames.has(candName)) return false;\n      for (const f of baselineFields) {\n        if (!candFields.has(f)) return false;\n      }\n      return true;\n    });\n    if (!match) continue;\n    const [newName] = match;\n\n    renameMap.set(baselineTypeName, newName);\n\n    // Attach a remediation hint to the parent removal so reviewers can see\n    // where the symbol moved. Severity stays `breaking`: the symbol's name\n    // is gone, and callers who referenced it directly (Sorbet annotations,\n    // `is_a?` checks, pattern matches, deserialization targets) will fail\n    // at runtime. Languages that emit a `type Old = New` alias keep the\n    // parent symbol alive, so this branch may not fire — but the rename is\n    // still recorded for the cascade pass to use on field/return-type swaps.\n    const parentRemoval = parentRemovalByName.get(baselineTypeName);\n    if (parentRemoval) {\n      parentRemoval.remediation =\n        `Type \"${baselineTypeName}\" appears to have been renamed to \"${newName}\" — ` +\n        `the new type has every field of the old (a non-strict superset). ` +\n        `Field accesses and method calls on values of type \"${newName}\" continue to work; ` +\n        `only explicit \"${baselineTypeName}\" type annotations need to migrate. ` +\n        `Consider emitting a deprecated alias \\`type ${baselineTypeName} = ${newName}\\` in languages that support it.`;\n    }\n  }\n\n  return renameMap;\n}\n\n/**\n * Transitive rename inference. After `detectTypeRenames` records direct\n * structural matches (e.g. `ApiKeyWithValue → OrganizationApiKeyWithValue`),\n * walk the parent's fields and follow the `typeRef.name` of each: if the\n * baseline parent's field references an alias-type `OldOwner` and the new\n * parent's same-named field references a different alias `NewOwner`, the\n * pair is the same type-concept under a renamed name. Record the\n * secondary rename so the cascade can downgrade any `field_type_changed`\n * pointing at the pair, and attach a remediation hint to `OldOwner`'s\n * `symbol_removed` (which stays `breaking` — see `detectTypeRenames`).\n *\n * Why this is necessary: discriminated-union owner types (Go's\n * `APIKeyWithValueOwner`, PHP/Python's nested constructor params) are\n * frequently emitted as `kind: 'alias'` symbols with no extractable\n * field children — so `collectTypeFieldSets` returns empty for them and\n * the structural matcher can't pair them directly. The transitive\n * lookup gives us a deterministic, conservative way to propagate the\n * rename: it only fires when the parent rename has already been\n * positively identified, and only follows fields that share the same\n * wire name across baseline and candidate.\n */\nfunction inferTransitiveTypeRenames(\n  typeRenames: Map<string, string>,\n  baseline: CompatSnapshot,\n  candidate: CompatSnapshot,\n  changes: ClassifiedChange[],\n): void {\n  if (typeRenames.size === 0) return;\n\n  // Index field/property symbols by `${ownerFqName}.${localName}` so we\n  // can read the typeRef both sides of the rename.\n  const baselineFieldType = new Map<string, string>();\n  for (const sym of baseline.symbols) {\n    if (sym.kind !== 'field' && sym.kind !== 'property') continue;\n    if (!sym.ownerFqName || !sym.typeRef) continue;\n    const localName = sym.fqName.includes('.') ? sym.fqName.slice(sym.fqName.lastIndexOf('.') + 1) : sym.fqName;\n    baselineFieldType.set(`${sym.ownerFqName}.${localName.toLowerCase()}`, sym.typeRef.name);\n  }\n  const candidateFieldType = new Map<string, string>();\n  for (const sym of candidate.symbols) {\n    if (sym.kind !== 'field' && sym.kind !== 'property') continue;\n    if (!sym.ownerFqName || !sym.typeRef) continue;\n    const localName = sym.fqName.includes('.') ? sym.fqName.slice(sym.fqName.lastIndexOf('.') + 1) : sym.fqName;\n    candidateFieldType.set(`${sym.ownerFqName}.${localName.toLowerCase()}`, sym.typeRef.name);\n  }\n\n  // Index parent `symbol_removed` changes for downgrade.\n  const parentRemovalByName = new Map<string, ClassifiedChange>();\n  for (const change of changes) {\n    if (change.category === 'symbol_removed' && change.severity === 'breaking') {\n      parentRemovalByName.set(change.old.symbol ?? '', change);\n    }\n  }\n\n  // Walk a snapshot of the rename map — we may mutate it inside the loop\n  // but only via `set`, never `delete`, and we don't re-iterate on the\n  // additions in the same pass (one transitive hop is enough; deeper\n  // chains can be handled by re-running, which we don't need today).\n  const initialEntries = [...typeRenames.entries()];\n  for (const [oldOwner, newOwner] of initialEntries) {\n    // Find every baseline field on the renamed owner whose typeRef points\n    // at a *different* type than the same-named field on the new owner.\n    for (const [baselineKey, baselineFieldTypeRef] of baselineFieldType) {\n      if (!baselineKey.startsWith(`${oldOwner}.`)) continue;\n      const localName = baselineKey.slice(oldOwner.length + 1);\n      const candidateKey = `${newOwner}.${localName}`;\n      const candidateFieldTypeRef = candidateFieldType.get(candidateKey);\n      if (!candidateFieldTypeRef) continue;\n\n      const oldT = bareTypeName(baselineFieldTypeRef);\n      const newT = bareTypeName(candidateFieldTypeRef);\n      if (!oldT || !newT || oldT === newT) continue;\n      if (typeRenames.has(oldT)) continue; // already recorded\n\n      typeRenames.set(oldT, newT);\n      const removal = parentRemovalByName.get(oldT);\n      if (removal) {\n        // Severity stays `breaking` — see `detectTypeRenames` for the\n        // rationale. We only attach a remediation hint here.\n        removal.remediation =\n          `Type \"${oldT}\" appears to have been renamed to \"${newT}\" — ` +\n          `inferred transitively because the renamed parent \"${oldOwner}\" → \"${newOwner}\" ` +\n          `has a \"${localName}\" field whose type swapped from \"${oldT}\" to \"${newT}\". ` +\n          `Consider emitting a deprecated alias \\`type ${oldT} = ${newT}\\` in languages that support it.`;\n      }\n    }\n  }\n}\n\n/**\n * Detect enum canonical-flips: a baseline enum disappears and a candidate\n * enum with the **same wire-value set** takes its place.\n *\n * Caused by the emitter's enum-dedup heuristic picking a different\n * canonical name when a new same-shape enum joins the spec. Languages\n * that emit type aliases (Go, Ruby, Python, PHP, Kotlin) handle this\n * transparently via `type Old = New`; languages without first-class\n * aliases (dotnet) report the old enum as removed. The wire values are\n * unchanged — every legal value still serializes to the same JSON — so\n * consumer code constructing or matching on these enum values keeps\n * working. Only references to the typed enum class need migration.\n *\n * Identity criterion: a removed enum's value set is *exactly* equal to\n * a newly-added enum's value set (not superset — narrowing the value\n * set would be a real break for consumers expecting the dropped values).\n */\nfunction detectEnumRenames(\n  changes: ClassifiedChange[],\n  baseline: CompatSnapshot,\n  candidate: CompatSnapshot,\n): Map<string, string> {\n  const renameMap = new Map<string, string>();\n  const baselineEnumValues = collectEnumValueSets(baseline);\n  const candidateEnumValues = collectEnumValueSets(candidate);\n  const baselineEnumNames = new Set(baselineEnumValues.keys());\n\n  const candidateEnumsSorted = [...candidateEnumValues.entries()].sort((a, b) => a[0].localeCompare(b[0]));\n\n  // Index `symbol_removed` changes by fqName for O(1) lookup when downgrading\n  // a parent removal (only some languages report one; others alias).\n  const parentRemovalByName = new Map<string, ClassifiedChange>();\n  for (const change of changes) {\n    if (change.category === 'symbol_removed' && change.severity === 'breaking') {\n      parentRemovalByName.set(change.old.symbol ?? '', change);\n    }\n  }\n\n  // Walk every baseline enum *directly*, not via `symbol_removed` events.\n  // The parent-removal path alone misses canonical-flips in languages that\n  // alias non-canonical enums (Go, Ruby, Python, PHP, Kotlin): the old\n  // fqName persists as `type ApplicationsOrder = APIKeysOrder`, no parent\n  // `symbol_removed` fires, and the rename map stays empty — so the\n  // member-removal cascade never runs. Iterating baseline enums fixes this\n  // by deciding \"did this enum's value set move to a different owner?\"\n  // independent of whether the parent symbol survived.\n  for (const [baselineEnumName, baselineValues] of baselineEnumValues) {\n    if (baselineValues.size === 0) continue;\n\n    // No-op case: same name, same value set still present in candidate.\n    const sameNameValues = candidateEnumValues.get(baselineEnumName);\n    if (sameNameValues && setEquals(baselineValues, sameNameValues)) continue;\n\n    // Find a newly-added candidate enum (not present under that name in\n    // the baseline) with an exactly-equal wire-value set.\n    const match = candidateEnumsSorted.find(\n      ([candName, candValues]) => !baselineEnumNames.has(candName) && setEquals(baselineValues, candValues),\n    );\n    if (!match) continue;\n    const [newName] = match;\n\n    renameMap.set(baselineEnumName, newName);\n\n    // Attach a remediation hint to the parent removal if one was reported\n    // (dotnet path). Severity stays `breaking`: even though the wire values\n    // are unchanged, the typed enum class is gone, so callers referencing\n    // it by name will fail to compile or resolve. See `detectTypeRenames`\n    // for the full rationale.\n    const parentRemoval = parentRemovalByName.get(baselineEnumName);\n    if (parentRemoval) {\n      parentRemoval.remediation =\n        `Enum \"${baselineEnumName}\" appears to have been renamed to \"${newName}\" — ` +\n        `both enums have identical wire values, so on-the-wire serialization is unchanged. ` +\n        `This is typically the emitter's dedup canonical-flip after a new same-shape enum joined the spec. ` +\n        `Consider emitting a deprecated alias in languages that support it, or pinning the canonical via emitter config.`;\n    }\n  }\n\n  return renameMap;\n}\n\n/**\n * Cascade rename downgrades to changes whose meaning depends on a renamed\n * symbol. Walks every change and:\n *\n *   - Downgrades child removals (`Owner.field` removed where `Owner` was\n *     renamed) — the field still exists, just under a new owner fqName.\n *     Same logic for enum members under a renamed enum.\n *   - Downgrades `return_type_changed` / `field_type_changed` whose\n *     old → new pair matches a recorded rename — the type swap is the\n *     rename itself, not a meaningful signature break.\n *\n * Each cascaded change gets a remediation pointing at the parent rename\n * so the reviewer can find the explanation in the report.\n */\nfunction cascadeRenameDowngrades(\n  changes: ClassifiedChange[],\n  typeRenames: Map<string, string>,\n  enumRenames: Map<string, string>,\n  baseline: CompatSnapshot,\n  candidate: CompatSnapshot,\n): void {\n  // Lazy-built field-set maps for the structural-equivalence fallback used\n  // by `*_type_changed`. Both maps are needed even when no renames were\n  // recorded — the structural test handles cases where both old and new\n  // types coexist (e.g. a method's return type was redirected from an\n  // existing schema to a structurally-equivalent newly-added schema, the\n  // canonical fork antipattern).\n  let baselineTypeFields: Map<string, Set<string>> | undefined;\n  let candidateTypeFields: Map<string, Set<string>> | undefined;\n  const getBaselineFields = (): Map<string, Set<string>> => {\n    if (!baselineTypeFields) baselineTypeFields = collectTypeFieldSets(baseline);\n    return baselineTypeFields;\n  };\n  const getCandidateFields = (): Map<string, Set<string>> => {\n    if (!candidateTypeFields) candidateTypeFields = collectTypeFieldSets(candidate);\n    return candidateTypeFields;\n  };\n\n  /**\n   * Structural equivalence: candidate type's field set is a non-strict\n   * superset of baseline type's field set, AND the candidate type was\n   * newly added in this diff (not a swap to a pre-existing type, which\n   * is a real signature break the consumer chose). When `New ⊇ Old` and\n   * `New` is new, every field the consumer accessed on the old type\n   * still exists on the value they receive — so the swap is non-breaking\n   * at the value level even though the declared type changed. This is\n   * the fork-detector's positive signal, applied as a severity\n   * downgrade in addition to the existing remediation hint.\n   */\n  const isStructurallyEquivalent = (oldT: string, newT: string): boolean => {\n    if (!oldT || !newT || oldT === newT) return false;\n    const baselineFields = getBaselineFields();\n    const candidateFields = getCandidateFields();\n    // The new type must be newly introduced — a swap to an existing type\n    // is a real signature change the consumer chose, not a rename.\n    if (baselineFields.has(newT)) return false;\n    const oldFields = baselineFields.get(oldT);\n    const newFields = candidateFields.get(newT);\n    if (!oldFields || !newFields) return false;\n    if (oldFields.size === 0) return false;\n    for (const f of oldFields) {\n      if (!newFields.has(f)) return false;\n    }\n    return true;\n  };\n\n  for (const change of changes) {\n    if (change.severity !== 'breaking') continue;\n\n    if (change.category === 'symbol_removed') {\n      const removed = change.old.symbol ?? '';\n      const dotIdx = removed.indexOf('.');\n      if (dotIdx <= 0) continue;\n      const ownerName = removed.slice(0, dotIdx);\n      const renamedTo = typeRenames.get(ownerName) ?? enumRenames.get(ownerName);\n      if (!renamedTo) continue;\n      change.severity = 'soft-risk';\n      change.remediation =\n        `Owned by renamed symbol \"${ownerName}\" (now \"${renamedTo}\"). ` +\n        `The same member exists on the new symbol under \"${renamedTo}.${removed.slice(dotIdx + 1)}\".`;\n      continue;\n    }\n\n    if (change.category === 'return_type_changed') {\n      const oldT = bareTypeName(change.old.returnType ?? '');\n      const newT = bareTypeName(change.new.returnType ?? '');\n      if (typeRenames.get(oldT) === newT) {\n        change.severity = 'soft-risk';\n        change.remediation =\n          `Return type swap matches recorded rename \"${oldT}\" → \"${newT}\". ` +\n          `The underlying field set is preserved (see the rename advisory on \"${oldT}\").`;\n      } else if (isStructurallyEquivalent(oldT, newT)) {\n        // Downgrade severity for the structural-equivalence case (the\n        // fork-detector's positive signal). Preserve any remediation\n        // already attached by `detectForkedSchemas` — its message\n        // already explains the situation; we only need to flip severity.\n        change.severity = 'soft-risk';\n        if (!change.remediation) {\n          change.remediation =\n            `Return type swap from \"${oldT}\" to \"${newT}\" is structurally equivalent — ` +\n            `every field on \"${oldT}\" still exists on \"${newT}\". ` +\n            `Consumer code accessing fields on the returned value continues to work; ` +\n            `only explicit \"${oldT}\" type annotations need to migrate.`;\n        }\n      }\n      continue;\n    }\n\n    if (change.category === 'field_type_changed') {\n      const oldT = bareTypeName(change.old.type ?? '');\n      const newT = bareTypeName(change.new.type ?? '');\n      const renamedTo = typeRenames.get(oldT) ?? enumRenames.get(oldT);\n      if (renamedTo === newT) {\n        change.severity = 'soft-risk';\n        change.remediation =\n          `Field type swap matches recorded rename \"${oldT}\" → \"${newT}\". ` +\n          `On-the-wire shape is unchanged (see the rename advisory on \"${oldT}\").`;\n      } else if (isStructurallyEquivalent(oldT, newT)) {\n        change.severity = 'soft-risk';\n        if (!change.remediation) {\n          change.remediation =\n            `Field type swap from \"${oldT}\" to \"${newT}\" is structurally equivalent — ` +\n            `every field on \"${oldT}\" still exists on \"${newT}\".`;\n        }\n      }\n    }\n  }\n}\n\n/**\n * Build a map from enum fqName → set of wire values. Used by\n * `detectEnumRenames` to find structurally-identical enums across\n * baseline and candidate. Wire values come from `enum_member.value`\n * (the JSON-level value) — not the member names, which are\n * language-specific PascalCase forms.\n *\n * Members whose `value` is undefined are skipped — they contribute no\n * identity information.\n */\nfunction collectEnumValueSets(snapshot: CompatSnapshot): Map<string, Set<string>> {\n  const result = new Map<string, Set<string>>();\n  for (const sym of snapshot.symbols) {\n    if (sym.kind !== 'enum_member') continue;\n    if (!sym.ownerFqName) continue;\n    if (sym.value === undefined) continue;\n    let set = result.get(sym.ownerFqName);\n    if (!set) {\n      set = new Set<string>();\n      result.set(sym.ownerFqName, set);\n    }\n    set.add(String(sym.value));\n  }\n  return result;\n}\n\n/** Set equality for the small string sets used by rename detection. */\nfunction setEquals(a: Set<string>, b: Set<string>): boolean {\n  if (a.size !== b.size) return false;\n  for (const v of a) {\n    if (!b.has(v)) return false;\n  }\n  return true;\n}\n\n/**\n * Strip array/nullable suffixes so we compare bare type names. Languages\n * encode these differently (`Foo[]`, `Foo | null`, `Foo?`, `List<Foo>`,\n * `Optional[Foo]`); this is a best-effort common-case stripper, not an\n * exhaustive parser.\n */\nfunction bareTypeName(t: string): string {\n  let s = t.trim();\n  // Go pointer prefix: `*Foo` → `Foo`. Strip first because the rest of the\n  // patterns expect a leading identifier character.\n  s = s.replace(/^\\*/, '');\n  // PHP namespace prefix: `\\Vendor\\Pkg\\Foo` → `Foo`. PHP fully-qualified\n  // type references in generated method signatures lead with a backslash\n  // and use backslash-separated segments. Split on the last segment to\n  // preserve nested generics inside the path.\n  if (s.startsWith('\\\\')) {\n    const lastBackslash = s.lastIndexOf('\\\\');\n    s = s.slice(lastBackslash + 1);\n  }\n  // Nullable suffixes: `Foo | null`, `Foo?`.\n  s = s.replace(/\\s*\\|\\s*null$/, '').replace(/\\?$/, '');\n  // Array suffix: `Foo[]`.\n  s = s.replace(/\\[\\]$/, '');\n  // Single-arg generic. Two encodings to support:\n  //   - angle brackets: `Iterator<Foo>`, `Optional<Foo>`, `List<Foo>`\n  //   - square brackets: `Iterator[Foo]` (Go iterator returns from the\n  //     emitter, e.g. `*Iterator[APIKey]`)\n  const angleGeneric = s.match(/^[A-Za-z_][A-Za-z0-9_.]*<\\s*([A-Za-z_*][A-Za-z0-9_.*]*)\\s*>$/);\n  if (angleGeneric) return bareTypeName(angleGeneric[1]);\n  const bracketGeneric = s.match(/^[A-Za-z_][A-Za-z0-9_.]*\\[\\s*([A-Za-z_*][A-Za-z0-9_.*]*)\\s*\\]$/);\n  if (bracketGeneric) return bareTypeName(bracketGeneric[1]);\n  return s;\n}\n\n/**\n * Check if a symbol is a constructor belonging to a service wrapper class.\n *\n * Service wrapper constructors are internal plumbing (taking a client/config\n * object) — users interact with services via `client.admin_portal`, not\n * `new AdminPortal(...)`.  Changes to these constructors should not be\n * reported as breaking.\n *\n * Catches two patterns:\n *  - Ruby: kind === 'constructor', ownerFqName is a service_accessor\n *  - PHP:  kind === 'callable' with fqName ending in '.__construct'\n */\nfunction isServiceWrapperConstructor(sym: CompatSymbol, serviceAccessors: Set<string>): boolean {\n  if (!sym.ownerFqName || !serviceAccessors.has(sym.ownerFqName)) return false;\n  if (sym.kind === 'constructor') return true;\n  if (sym.kind === 'callable' && sym.fqName.endsWith('.__construct')) return true;\n  return false;\n}\n\n// ---------------------------------------------------------------------------\n// Legacy: ApiSurface-based diff (delegates to existing logic)\n// ---------------------------------------------------------------------------\n\n/**\n * Compare two ApiSurface objects and return a DiffResult.\n *\n * This preserves the existing diffing behavior used by the overlay retry loop,\n * compat check, and all existing tests. The internal implementation uses the\n * same algorithms as before to maintain full backward compatibility with\n * overlay patching and verification workflows.\n */\nexport function diffSurfaces(baseline: ApiSurface, candidate: ApiSurface, hints: LanguageHints): DiffResult {\n  const violations: Violation[] = [];\n  const additions: Addition[] = [];\n  let totalBaseline = 0;\n  let preserved = 0;\n\n  // Diff classes\n  for (const [name, baseClass] of Object.entries(baseline.classes)) {\n    totalBaseline++;\n    const candClass = candidate.classes[name];\n    if (!candClass) {\n      violations.push({\n        category: 'public-api',\n        severity: 'breaking',\n        symbolPath: name,\n        baseline: name,\n        candidate: '(missing)',\n        message: `Class \"${name}\" exists in baseline but not in generated output`,\n      });\n      totalBaseline += Object.values(baseClass.methods).reduce((sum, overloads) => sum + overloads.length, 0);\n      totalBaseline += Object.keys(baseClass.properties).length;\n      continue;\n    }\n    preserved++;\n\n    // Diff methods (each method name maps to an array of overloads)\n    for (const [methodName, baseOverloads] of Object.entries(baseClass.methods)) {\n      const candOverloads = candClass.methods[methodName];\n      for (const baseMethod of baseOverloads) {\n        totalBaseline++;\n        if (!candOverloads || candOverloads.length === 0) {\n          violations.push({\n            category: 'public-api',\n            severity: 'breaking',\n            symbolPath: `${name}.${methodName}`,\n            baseline: methodName,\n            candidate: '(missing)',\n            message: `Method \"${name}.${methodName}\" exists in baseline but not in generated output`,\n          });\n          continue;\n        }\n        const candMethod = candOverloads.find((c) => signaturesMatch(baseMethod, c));\n        if (!candMethod) {\n          // Fallback: check language-specific signature equivalence\n          const equivalentMethod = hints.isSignatureEquivalent\n            ? candOverloads.find((c) => hints.isSignatureEquivalent!(baseMethod, c, candidate))\n            : undefined;\n          if (equivalentMethod) {\n            preserved++;\n            continue;\n          }\n          violations.push({\n            category: 'signature',\n            severity: 'breaking',\n            symbolPath: `${name}.${methodName}`,\n            baseline: formatSignature(baseMethod),\n            candidate: formatSignature(candOverloads[0]),\n            message: `Signature mismatch for \"${name}.${methodName}\"`,\n          });\n          continue;\n        }\n        preserved++;\n      }\n    }\n\n    // Check for new methods (additions)\n    for (const methodName of Object.keys(candClass.methods)) {\n      if (!baseClass.methods[methodName]) {\n        additions.push({ symbolPath: `${name}.${methodName}`, symbolType: 'method' });\n      }\n    }\n\n    // Diff properties\n    for (const [propName, baseProp] of Object.entries(baseClass.properties)) {\n      totalBaseline++;\n      const candProp = candClass.properties[propName];\n      if (!candProp) {\n        violations.push({\n          category: 'public-api',\n          severity: 'breaking',\n          symbolPath: `${name}.${propName}`,\n          baseline: baseProp.type,\n          candidate: '(missing)',\n          message: `Property \"${name}.${propName}\" exists in baseline but not in generated output`,\n        });\n        continue;\n      }\n      if (baseProp.type !== candProp.type) {\n        const nullableOnly = hints.isNullableOnlyDifference(baseProp.type, candProp.type);\n        violations.push({\n          category: 'signature',\n          severity: nullableOnly ? 'warning' : 'breaking',\n          symbolPath: `${name}.${propName}`,\n          baseline: baseProp.type,\n          candidate: candProp.type,\n          message: `Property type mismatch for \"${name}.${propName}\"`,\n        });\n        if (nullableOnly) preserved++;\n        continue;\n      }\n      preserved++;\n    }\n\n    // Check for new properties (additions)\n    for (const propName of Object.keys(candClass.properties)) {\n      if (!baseClass.properties[propName]) {\n        additions.push({ symbolPath: `${name}.${propName}`, symbolType: 'property' });\n      }\n    }\n  }\n\n  // Check for new classes (additions)\n  for (const name of Object.keys(candidate.classes)) {\n    if (!baseline.classes[name]) {\n      additions.push({ symbolPath: name, symbolType: 'class' });\n    }\n  }\n\n  // Precompute lowercased field/property name sets for field-structure matching\n  const candIfaceFieldSets = new Map<string, Set<string>>();\n  for (const [n, iface] of Object.entries(candidate.interfaces)) {\n    candIfaceFieldSets.set(n, new Set(Object.keys(iface.fields).map((f) => f.toLowerCase())));\n  }\n  const candClassPropSets = new Map<string, Set<string>>();\n  for (const [n, cls] of Object.entries(candidate.classes)) {\n    candClassPropSets.set(n, new Set(Object.keys(cls.properties).map((f) => f.toLowerCase())));\n  }\n\n  // Diff interfaces\n  for (const [name, baseIface] of Object.entries(baseline.interfaces)) {\n    totalBaseline++;\n    const candIface = candidate.interfaces[name];\n    if (!candIface) {\n      let tolerated = false;\n      if (hints.tolerateCategoryMismatch && name.startsWith('Serialized')) {\n        const baseName = name.slice('Serialized'.length);\n        if (candidate.interfaces[baseName] || candidate.classes[baseName]) {\n          tolerated = true;\n        }\n      }\n      if (tolerated) {\n        preserved++;\n        totalBaseline += Object.keys(baseIface.fields).length;\n        preserved += Object.keys(baseIface.fields).length;\n        continue;\n      }\n      if (!tolerated) {\n        const baseFieldNamesLower = new Set(Object.keys(baseIface.fields).map((f) => f.toLowerCase()));\n        if (baseFieldNamesLower.size > 0) {\n          for (const [, candFieldNamesLower] of candIfaceFieldSets) {\n            if (\n              candFieldNamesLower.size === baseFieldNamesLower.size &&\n              [...baseFieldNamesLower].every((f) => candFieldNamesLower.has(f))\n            ) {\n              tolerated = true;\n              break;\n            }\n          }\n          if (!tolerated) {\n            for (const [, candPropNamesLower] of candClassPropSets) {\n              if (\n                candPropNamesLower.size === baseFieldNamesLower.size &&\n                [...baseFieldNamesLower].every((f) => candPropNamesLower.has(f))\n              ) {\n                tolerated = true;\n                break;\n              }\n            }\n          }\n        } else {\n          tolerated = true;\n        }\n      }\n      if (tolerated) {\n        preserved++;\n        totalBaseline += Object.keys(baseIface.fields).length;\n        preserved += Object.keys(baseIface.fields).length;\n        continue;\n      }\n      violations.push({\n        category: 'public-api',\n        severity: 'breaking',\n        symbolPath: name,\n        baseline: name,\n        candidate: '(missing)',\n        message: `Interface \"${name}\" exists in baseline but not in generated output`,\n      });\n      totalBaseline += Object.keys(baseIface.fields).length;\n      continue;\n    }\n    preserved++;\n\n    for (const [fieldName, baseField] of Object.entries(baseIface.fields)) {\n      totalBaseline++;\n      const candField = candIface.fields[fieldName];\n      if (!candField) {\n        const baseTypeClean = baseField.type.replace(/\\[\\]$/, '').replace(/ \\| null$/, '');\n        const typeIsUnresolvable = NAMED_TYPE_RE.test(baseTypeClean) && !typeExistsInSurface(baseTypeClean, candidate);\n        violations.push({\n          category: 'public-api',\n          severity: typeIsUnresolvable ? 'warning' : 'breaking',\n          symbolPath: `${name}.${fieldName}`,\n          baseline: baseField.type,\n          candidate: '(missing)',\n          message: `Field \"${name}.${fieldName}\" exists in baseline but not in generated output`,\n        });\n        if (typeIsUnresolvable) preserved++;\n        continue;\n      }\n      if (baseField.type !== candField.type) {\n        if (hints.isUnionReorder(baseField.type, candField.type)) {\n          preserved++;\n          continue;\n        }\n        if (hints.isTypeEquivalent?.(baseField.type, candField.type, candidate)) {\n          preserved++;\n          continue;\n        }\n        const nullableOnly = hints.isNullableOnlyDifference(baseField.type, candField.type);\n        const genericParam = hints.isGenericTypeParam(baseField.type);\n        const extractionArtifact = hints.isExtractionArtifact(candField.type);\n        const isWarning = nullableOnly || genericParam || extractionArtifact;\n        violations.push({\n          category: 'signature',\n          severity: isWarning ? 'warning' : 'breaking',\n          symbolPath: `${name}.${fieldName}`,\n          baseline: baseField.type,\n          candidate: candField.type,\n          message: `Field type mismatch for \"${name}.${fieldName}\"`,\n        });\n        if (isWarning) preserved++;\n        continue;\n      }\n      preserved++;\n    }\n\n    for (const fieldName of Object.keys(candIface.fields)) {\n      if (!baseIface.fields[fieldName]) {\n        additions.push({ symbolPath: `${name}.${fieldName}`, symbolType: 'property' });\n      }\n    }\n  }\n\n  // Check for new interfaces (additions)\n  for (const name of Object.keys(candidate.interfaces)) {\n    if (!baseline.interfaces[name]) {\n      additions.push({ symbolPath: name, symbolType: 'interface' });\n    }\n  }\n\n  // Diff type aliases\n  for (const [name, baseAlias] of Object.entries(baseline.typeAliases)) {\n    totalBaseline++;\n    const candAlias = candidate.typeAliases[name];\n    if (!candAlias) {\n      if (hints.tolerateCategoryMismatch && typeExistsInSurface(name, candidate)) {\n        preserved++;\n        continue;\n      }\n      violations.push({\n        category: 'public-api',\n        severity: 'breaking',\n        symbolPath: name,\n        baseline: baseAlias.value,\n        candidate: '(missing)',\n        message: `Type alias \"${name}\" exists in baseline but not in generated output`,\n      });\n      continue;\n    }\n    if (baseAlias.value !== candAlias.value) {\n      if (hints.isUnionReorder(baseAlias.value, candAlias.value)) {\n        preserved++;\n        continue;\n      }\n      const nullableOnly = hints.isNullableOnlyDifference(baseAlias.value, candAlias.value);\n      violations.push({\n        category: 'signature',\n        severity: nullableOnly ? 'warning' : 'breaking',\n        symbolPath: name,\n        baseline: baseAlias.value,\n        candidate: candAlias.value,\n        message: `Type alias value mismatch for \"${name}\"`,\n      });\n      if (nullableOnly) preserved++;\n      continue;\n    }\n    preserved++;\n  }\n\n  // Check for new type aliases (additions)\n  for (const name of Object.keys(candidate.typeAliases)) {\n    if (!baseline.typeAliases[name]) {\n      additions.push({ symbolPath: name, symbolType: 'type-alias' });\n    }\n  }\n\n  // Diff enums\n  for (const [name, baseEnum] of Object.entries(baseline.enums)) {\n    totalBaseline++;\n    const candEnum = candidate.enums[name];\n    if (!candEnum) {\n      violations.push({\n        category: 'public-api',\n        severity: 'breaking',\n        symbolPath: name,\n        baseline: name,\n        candidate: '(missing)',\n        message: `Enum \"${name}\" exists in baseline but not in generated output`,\n      });\n      continue;\n    }\n\n    const candValueToMembers = new Map<string | number, string[]>();\n    for (const [candMember, candValue] of Object.entries(candEnum.members)) {\n      const existing = candValueToMembers.get(candValue);\n      if (existing) {\n        existing.push(candMember);\n      } else {\n        candValueToMembers.set(candValue, [candMember]);\n      }\n    }\n\n    let enumMatch = true;\n    for (const [member, value] of Object.entries(baseEnum.members)) {\n      if (candEnum.members[member] === value) {\n        continue;\n      }\n\n      const valueMatches = candValueToMembers.get(value);\n      if (valueMatches && valueMatches.length > 0) {\n        violations.push({\n          category: 'signature',\n          severity: 'warning',\n          symbolPath: `${name}.${member}`,\n          baseline: `${member}=${String(value)}`,\n          candidate: `${valueMatches[0]}=${String(value)}`,\n          message: `Enum member name differs for \"${name}.${member}\" (value \"${value}\" preserved as \"${valueMatches[0]}\")`,\n        });\n        continue;\n      }\n\n      const lowerValue = String(value).toLowerCase();\n      const caseInsensitiveMatch = [...candValueToMembers.entries()].find(\n        ([candVal]) => String(candVal).toLowerCase() === lowerValue,\n      );\n      if (caseInsensitiveMatch) {\n        violations.push({\n          category: 'signature',\n          severity: 'warning',\n          symbolPath: `${name}.${member}`,\n          baseline: `${member}=${String(value)}`,\n          candidate: `${caseInsensitiveMatch[1][0]}=${String(caseInsensitiveMatch[0])}`,\n          message: `Enum member value case differs for \"${name}.${member}\" (baseline \"${value}\" vs candidate \"${caseInsensitiveMatch[0]}\")`,\n        });\n        continue;\n      }\n\n      const isExtractionArtifact =\n        String(value) === member || member === 'JsonEnumDefaultValue' || member === 'JsonProperty';\n      if (isExtractionArtifact) {\n        violations.push({\n          category: 'signature',\n          severity: 'warning',\n          symbolPath: `${name}.${member}`,\n          baseline: String(value),\n          candidate: '(extraction artifact)',\n          message: `Enum member \"${name}.${member}\" appears to be an extraction artifact`,\n        });\n        continue;\n      }\n\n      violations.push({\n        category: 'signature',\n        severity: 'breaking',\n        symbolPath: `${name}.${member}`,\n        baseline: String(value),\n        candidate: member in candEnum.members ? String(candEnum.members[member]) : '(missing)',\n        message: `Enum member mismatch for \"${name}.${member}\"`,\n      });\n      enumMatch = false;\n    }\n    if (enumMatch) {\n      preserved++;\n    }\n  }\n\n  // Check for new enums (additions)\n  for (const name of Object.keys(candidate.enums)) {\n    if (!baseline.enums[name]) {\n      additions.push({ symbolPath: name, symbolType: 'enum' });\n    }\n  }\n\n  // Diff barrel exports\n  for (const [path, baseExports] of Object.entries(baseline.exports)) {\n    const candExports = candidate.exports[path];\n    if (!candExports) {\n      for (const exp of baseExports) {\n        violations.push({\n          category: 'export-structure',\n          severity: 'warning',\n          symbolPath: `exports[${path}].${exp}`,\n          baseline: exp,\n          candidate: '(missing)',\n          message: `Export \"${exp}\" from \"${path}\" not found in generated output`,\n        });\n      }\n      continue;\n    }\n    const candSet = new Set(candExports);\n    for (const exp of baseExports) {\n      if (!candSet.has(exp)) {\n        violations.push({\n          category: 'export-structure',\n          severity: 'warning',\n          symbolPath: `exports[${path}].${exp}`,\n          baseline: exp,\n          candidate: '(missing)',\n          message: `Export \"${exp}\" from \"${path}\" not found in generated output`,\n        });\n      }\n    }\n  }\n\n  return {\n    preservationScore: totalBaseline > 0 ? Math.round((preserved / totalBaseline) * 100) : 100,\n    totalBaselineSymbols: totalBaseline,\n    preservedSymbols: preserved,\n    violations,\n    additions,\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers (legacy)\n// ---------------------------------------------------------------------------\n\nfunction signaturesMatch(baseline: ApiMethod, candidate: ApiMethod): boolean {\n  if (baseline.returnType !== candidate.returnType) return false;\n  for (let i = 0; i < baseline.params.length; i++) {\n    const baseParam = baseline.params[i];\n    const candParam = candidate.params[i];\n    if (!candParam) return false;\n    if (baseParam.type !== candParam.type) return false;\n    if (baseParam.name !== candParam.name) return false;\n  }\n  for (let i = baseline.params.length; i < candidate.params.length; i++) {\n    if (!candidate.params[i].optional) return false;\n  }\n  return true;\n}\n\nfunction formatSignature(method: ApiMethod): string {\n  const params = method.params.map((p) => `${p.name}${p.optional ? '?' : ''}: ${p.type}`).join(', ');\n  return `(${params}) => ${method.returnType}`;\n}\n","import { RegistryError } from '../errors.js';\nimport type { Extractor } from './types.js';\n\nconst extractors = new Map<string, Extractor>();\n\nexport function registerExtractor(extractor: Extractor): void {\n  extractors.set(extractor.language, extractor);\n}\n\nexport function getExtractor(language: string): Extractor {\n  const extractor = extractors.get(language);\n  if (!extractor) {\n    const available = [...extractors.keys()].join(', ') || '(none)';\n    throw new RegistryError(\n      `No extractor registered for language: ${language}. Available: ${available}`,\n      `Register an extractor for \"${language}\" via registerExtractor() or add one in your oagen.config.ts plugin.`,\n    );\n  }\n  return extractor;\n}\n","import type { ApiSurface, ApiInterface, ApiMethod, OverlayLookup, LanguageHints } from './types.js';\nimport type { ClassifiedChange } from './classify.js';\nimport type { ApiSpec, Model } from '../ir/types.js';\nimport { toSnakeCase, splitWords } from '../utils/naming.js';\nimport { nodeHints as defaultNodeHints } from './language-hints.js';\n\nexport type { MethodOverlay, OverlayLookup } from './types.js';\n\nexport interface ManifestEntry {\n  operationId: string;\n  sdkResourceProperty: string;\n  sdkMethodName: string;\n  httpMethod: string;\n  path: string;\n  pathParams: string[];\n  bodyFields: string[];\n  queryFields: string[];\n}\n\n/**\n * Find the class name that owns a given SDK resource property.\n * E.g. if the surface has a class \"Organizations\" with property \"organizations\",\n * and sdkResourceProperty is \"organizations\", return \"Organizations\".\n */\nfunction findClassForProperty(\n  surface: ApiSurface,\n  sdkResourceProperty: string,\n  hints: LanguageHints,\n): string | undefined {\n  for (const [className, cls] of Object.entries(surface.classes)) {\n    // Check if the class itself maps to this property (language-specific match)\n    if (hints.propertyMatchesClass(sdkResourceProperty, className)) {\n      return className;\n    }\n    // Check properties — resolve to the property's type class, not the parent.\n    // This prevents generic parent classes (e.g., Client) from being returned\n    // when the actual resource class (e.g., ApiKeys) should be used.\n    for (const [propName, prop] of Object.entries(cls.properties)) {\n      if (propName === sdkResourceProperty) {\n        const propType = (prop as { type?: string }).type;\n        if (propType && surface.classes[propType]) {\n          return propType;\n        }\n        // Property type not in surface — skip rather than return the parent\n        return undefined;\n      }\n    }\n  }\n\n  // Strategy 3: Word-suffix fallback\n  // \"adminPortal\" → [\"admin\",\"portal\"]; class \"Portal\" → [\"portal\"]\n  // [\"portal\"] is a suffix of [\"admin\",\"portal\"] → match\n  const propWords = splitWords(sdkResourceProperty).map((w) => w.toLowerCase());\n  if (propWords.length > 1) {\n    for (const [className] of Object.entries(surface.classes)) {\n      const classWords = splitWords(className).map((w) => w.toLowerCase());\n      if (classWords.length > 0 && classWords.length < propWords.length) {\n        const suffix = propWords.slice(propWords.length - classWords.length);\n        if (classWords.every((w, i) => w === suffix[i])) {\n          return className;\n        }\n      }\n    }\n  }\n\n  return undefined;\n}\n\nexport function buildOverlayLookup(\n  surface: ApiSurface,\n  manifest?: ManifestEntry[],\n  spec?: ApiSpec,\n  hints?: LanguageHints,\n  options?: { strictModelMatch?: boolean },\n): OverlayLookup {\n  const resolvedHints = hints ?? defaultNodeHints;\n  const lookup: OverlayLookup = {\n    methodByOperation: new Map(),\n    httpKeyByMethod: new Map(),\n    interfaceByName: new Map(),\n    typeAliasByName: new Map(),\n    requiredExports: new Map(),\n    modelNameByIR: new Map(),\n    fileBySymbol: new Map(),\n  };\n\n  // If manifest available, map operationId → HTTP method + path → existing method\n  if (manifest) {\n    for (const entry of manifest) {\n      const key = `${entry.httpMethod.toUpperCase()} ${entry.path}`;\n      const className = findClassForProperty(surface, entry.sdkResourceProperty, resolvedHints);\n      if (className) {\n        let resolvedMethodName = entry.sdkMethodName;\n        let methods = surface.classes[className]?.methods[resolvedMethodName];\n\n        // Exact match failed — try prefix match on the resolved class.\n        // Handles cases where the generated name is shorter than the existing name\n        // (e.g., manifest says \"delete\" but existing SDK has \"deleteApiKey\").\n        // Only accept when exactly one candidate matches — ambiguous matches are worse than no match.\n        if (!methods) {\n          const classMethods = surface.classes[className]?.methods ?? {};\n          const prefix = resolvedMethodName.toLowerCase();\n          const candidates: [string, ApiMethod[]][] = [];\n          for (const [name, overloads] of Object.entries(classMethods)) {\n            if (name.toLowerCase().startsWith(prefix) && name !== resolvedMethodName) {\n              candidates.push([name, overloads]);\n            }\n          }\n          if (candidates.length === 1) {\n            methods = candidates[0][1];\n            resolvedMethodName = candidates[0][0];\n          } else if (candidates.length > 1) {\n            // Disambiguate: prefer the candidate whose name is <prefix><pathSegment>\n            // derived from the FIRST segment of the operation path. This avoids\n            // mismatching when a class combines operations from multiple path groups\n            // (e.g., /organizations and /organization_domains both in Organizations).\n            const firstSegment =\n              entry.path\n                .split('/')\n                .filter(Boolean)[0]\n                ?.replace(/[{}_-]/g, '') ?? '';\n            if (firstSegment) {\n              const segLower = firstSegment.toLowerCase();\n              // Try the path segment as-is and as singular\n              const segSingular = segLower.endsWith('s') ? segLower.slice(0, -1) : segLower;\n              const best = candidates.find(([name]) => {\n                const lower = name.toLowerCase();\n                return lower === prefix + segLower || lower === prefix + segSingular;\n              });\n              if (best) {\n                methods = best[1];\n                resolvedMethodName = best[0];\n              }\n            }\n\n            // HTTP verb disambiguation: when path disambiguation fails, use the\n            // HTTP method to prefer method names that match the verb semantics.\n            // E.g., GET → list/get, POST → create, PUT → set/update, DELETE → delete/remove.\n            if (!methods) {\n              const verbMatch = disambiguateByHttpVerb(candidates, entry.httpMethod);\n              if (verbMatch) {\n                methods = verbMatch[1];\n                resolvedMethodName = verbMatch[0];\n              }\n            }\n          }\n        }\n\n        // Suffix match: the existing SDK may use a longer controller-prefixed\n        // method name that ends with the transformed name.\n        // (e.g., manifest says \"validate_api_key\" but existing SDK has\n        // \"api_keys_controller_validate_api_key\").\n        // Only accept when exactly one candidate matches — ambiguous matches are worse than no match.\n        if (!methods) {\n          const classMethods = surface.classes[className]?.methods ?? {};\n          const suffix = resolvedMethodName.toLowerCase();\n          const candidates: [string, ApiMethod[]][] = [];\n          for (const [name, overloads] of Object.entries(classMethods)) {\n            if (name.toLowerCase().endsWith(suffix) && name !== resolvedMethodName) {\n              candidates.push([name, overloads]);\n            }\n          }\n          if (candidates.length === 1) {\n            methods = candidates[0][1];\n            resolvedMethodName = candidates[0][0];\n          }\n        }\n\n        // Word-part subsequence match: the surface method may have extra words\n        // inserted into the manifest method name. For example:\n        //   \"disableFlag\" → \"disableFeatureFlag\" ([\"disable\",\"Flag\"] ⊂ [\"disable\",\"Feature\",\"Flag\"])\n        //   \"getByExternalId\" → \"getOrganizationByExternalId\"\n        // Only accept when exactly one candidate matches, or use HTTP verb disambiguation.\n        if (!methods) {\n          const manifestWords = splitCamelCase(resolvedMethodName);\n          if (manifestWords.length >= 2) {\n            const classMethods = surface.classes[className]?.methods ?? {};\n            const candidates: [string, ApiMethod[]][] = [];\n            for (const [name, overloads] of Object.entries(classMethods)) {\n              if (name === resolvedMethodName) continue;\n              const surfaceWords = splitCamelCase(name);\n              if (surfaceWords.length > manifestWords.length && isSubsequence(manifestWords, surfaceWords)) {\n                candidates.push([name, overloads]);\n              }\n            }\n            if (candidates.length === 1) {\n              methods = candidates[0][1];\n              resolvedMethodName = candidates[0][0];\n            } else if (candidates.length > 1) {\n              const verbMatch = disambiguateByHttpVerb(candidates, entry.httpMethod);\n              if (verbMatch) {\n                methods = verbMatch[1];\n                resolvedMethodName = verbMatch[0];\n              }\n            }\n          }\n        }\n\n        // Reverse prefix match: the manifest name may be LONGER than the surface\n        // name (e.g., \"createResources\" → \"createResource\", \"removeRoleByCriteria\" → \"removeRole\").\n        // Check if the manifest name starts with a surface name. Only accept unique matches.\n        if (!methods) {\n          const classMethods = surface.classes[className]?.methods ?? {};\n          const manifestLower = resolvedMethodName.toLowerCase();\n          const candidates: [string, ApiMethod[]][] = [];\n          for (const [name, overloads] of Object.entries(classMethods)) {\n            if (name === resolvedMethodName) continue;\n            if (manifestLower.startsWith(name.toLowerCase()) && name.length >= 3) {\n              candidates.push([name, overloads]);\n            }\n          }\n          if (candidates.length === 1) {\n            methods = candidates[0][1];\n            resolvedMethodName = candidates[0][0];\n          } else if (candidates.length > 1) {\n            const verbMatch = disambiguateByHttpVerb(candidates, entry.httpMethod);\n            if (verbMatch) {\n              methods = verbMatch[1];\n              resolvedMethodName = verbMatch[0];\n            }\n          }\n        }\n\n        const method = methods?.[0];\n        if (method) {\n          lookup.methodByOperation.set(key, {\n            className,\n            methodName: resolvedMethodName,\n            params: method.params,\n            returnType: method.returnType,\n          });\n          lookup.httpKeyByMethod.set(`${className}.${resolvedMethodName}`, key);\n        }\n      }\n    }\n  }\n\n  // Map interface and type alias names\n  for (const name of Object.keys(surface.interfaces)) {\n    lookup.interfaceByName.set(name, name);\n  }\n  for (const name of Object.keys(surface.typeAliases)) {\n    lookup.typeAliasByName.set(name, name);\n  }\n\n  // Map barrel exports\n  for (const [path, symbols] of Object.entries(surface.exports)) {\n    lookup.requiredExports.set(path, new Set(symbols));\n  }\n\n  // Populate fileBySymbol from enriched surface\n  for (const record of [surface.classes, surface.interfaces, surface.typeAliases, surface.enums] as Record<\n    string,\n    { sourceFile?: string }\n  >[]) {\n    for (const [name, item] of Object.entries(record)) {\n      if (item.sourceFile) lookup.fileBySymbol.set(name, item.sourceFile);\n    }\n  }\n\n  // Auto-infer IR model name → SDK interface name mappings\n  if (spec) {\n    buildModelNameMap(surface, spec, lookup, resolvedHints, options);\n\n    // Remap fileBySymbol so IR model names point to the SDK symbol's file\n    for (const [irName, sdkName] of lookup.modelNameByIR) {\n      const filePath = lookup.fileBySymbol.get(sdkName);\n      if (filePath) {\n        lookup.fileBySymbol.set(irName, filePath);\n      }\n    }\n  }\n\n  return lookup;\n}\n\n// ---------------------------------------------------------------------------\n// HTTP verb disambiguation\n// ---------------------------------------------------------------------------\n\n/** Map HTTP methods to preferred method name prefixes for disambiguation. */\nconst HTTP_VERB_PREFIXES: Record<string, string[]> = {\n  GET: ['list', 'get', 'fetch', 'retrieve', 'find'],\n  POST: ['create', 'add', 'insert', 'send'],\n  PUT: ['set', 'update', 'replace', 'put'],\n  PATCH: ['update', 'patch', 'modify'],\n  DELETE: ['delete', 'remove', 'revoke'],\n};\n\n/**\n * Disambiguate multiple method candidates using HTTP verb semantics.\n * Returns the best match or undefined if no unique match is found.\n */\nfunction disambiguateByHttpVerb<T>(candidates: [string, T][], httpMethod: string): [string, T] | undefined {\n  const prefixes = HTTP_VERB_PREFIXES[httpMethod.toUpperCase()];\n  if (!prefixes) return undefined;\n\n  const verbCandidates = candidates.filter(([name]) => {\n    const lower = name.toLowerCase();\n    return prefixes.some((p) => lower.startsWith(p));\n  });\n\n  if (verbCandidates.length === 1) return verbCandidates[0];\n  return undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Word-part matching helpers\n// ---------------------------------------------------------------------------\n\n/** Split a camelCase identifier into its word parts (e.g., \"getByExternalId\" → [\"get\",\"By\",\"External\",\"Id\"]). */\nfunction splitCamelCase(name: string): string[] {\n  const parts: string[] = [];\n  let start = 0;\n  for (let i = 1; i < name.length; i++) {\n    if (name[i] >= 'A' && name[i] <= 'Z') {\n      parts.push(name.slice(start, i));\n      start = i;\n    }\n  }\n  parts.push(name.slice(start));\n  return parts;\n}\n\n/** Check if `needle` words form a subsequence of `haystack` words (case-insensitive). */\nfunction isSubsequence(needle: string[], haystack: string[]): boolean {\n  let ni = 0;\n  for (let hi = 0; hi < haystack.length && ni < needle.length; hi++) {\n    if (needle[ni].toLowerCase() === haystack[hi].toLowerCase()) ni++;\n  }\n  return ni === needle.length;\n}\n\n// ---------------------------------------------------------------------------\n// Automatic model name inference\n// ---------------------------------------------------------------------------\n\n/**\n * Normalize a field name to a canonical form for comparison.\n * Handles camelCase → snake_case so \"createdAt\" and \"created_at\" match.\n */\nfunction normalizeFieldName(name: string): string {\n  return toSnakeCase(name);\n}\n\n/**\n * Compute the Jaccard similarity between two sets of normalized field names.\n * Returns score (0–1) and raw intersection count.\n */\nfunction jaccardSimilarity(a: Set<string>, b: Set<string>): { score: number; intersection: number } {\n  if (a.size === 0 && b.size === 0) return { score: 0, intersection: 0 };\n  let intersection = 0;\n  for (const item of a) {\n    if (b.has(item)) intersection++;\n  }\n  const union = a.size + b.size - intersection;\n  return { score: union === 0 ? 0 : intersection / union, intersection };\n}\n\n/**\n * Build a set of normalized field names from an IR model.\n */\nfunction irModelFieldSignature(model: Model): Set<string> {\n  return new Set(model.fields.map((f) => normalizeFieldName(f.name)));\n}\n\n/**\n * Build a set of normalized field names from an SDK interface.\n */\nfunction sdkInterfaceFieldSignature(iface: ApiInterface): Set<string> {\n  return new Set(Object.keys(iface.fields).map(normalizeFieldName));\n}\n\n/**\n * Populate the modelNameByIR map using two strategies:\n *\n * 1. Operation-based matching (high confidence):\n *    When a manifest maps an HTTP operation to an SDK method, extract the\n *    method's return type and parameter types. Match them against the IR\n *    operation's response model and request body model.\n *\n * 2. Field-structure matching (fallback):\n *    For IR models not matched by operations, compare their field names\n *    against all SDK interfaces using Jaccard similarity. A match requires\n *    ≥60% field overlap with ≥3 fields in common.\n */\nfunction buildModelNameMap(\n  surface: ApiSurface,\n  spec: ApiSpec,\n  lookup: OverlayLookup,\n  hints: LanguageHints,\n  options?: { strictModelMatch?: boolean },\n): void {\n  const mapped = new Set<string>(); // IR model names already mapped\n  const usedSdkNames = new Set<string>(); // SDK names already claimed\n\n  // --- Strategy 1: Operation-based matching ---\n  if (lookup.methodByOperation.size > 0) {\n    for (const service of spec.services) {\n      for (const op of service.operations) {\n        const httpKey = `${op.httpMethod.toUpperCase()} ${op.path}`;\n        const methodOverlay = lookup.methodByOperation.get(httpKey);\n        if (!methodOverlay) continue;\n\n        // Match response model → SDK return type\n        if (op.response.kind === 'model' && !mapped.has(op.response.name)) {\n          const sdkTypeName = hints.extractReturnTypeName(methodOverlay.returnType);\n          if (sdkTypeName && surface.interfaces[sdkTypeName]) {\n            lookup.modelNameByIR.set(op.response.name, sdkTypeName);\n            mapped.add(op.response.name);\n            usedSdkNames.add(sdkTypeName);\n          }\n        }\n\n        // Match request body model → SDK param type\n        if (op.requestBody?.kind === 'model' && !mapped.has(op.requestBody.name)) {\n          for (const param of methodOverlay.params) {\n            const sdkTypeName = hints.extractParamTypeName(param.type);\n            if (sdkTypeName && surface.interfaces[sdkTypeName]) {\n              lookup.modelNameByIR.set(op.requestBody.name, sdkTypeName);\n              mapped.add(op.requestBody.name);\n              usedSdkNames.add(sdkTypeName);\n              break;\n            }\n          }\n        }\n      }\n    }\n  }\n\n  // --- Strategy 2: Field-structure matching ---\n  // Pre-compute SDK interface field signatures\n  const sdkSignatures: { name: string; fields: Set<string>; fieldCount: number }[] = [];\n  for (const [name, iface] of Object.entries(surface.interfaces)) {\n    if (usedSdkNames.has(name)) continue;\n    const fields = sdkInterfaceFieldSignature(iface);\n    if (fields.size >= 2) {\n      sdkSignatures.push({ name, fields, fieldCount: fields.size });\n    }\n  }\n\n  const sdkSignatureNames = new Set(sdkSignatures.map((s) => s.name));\n\n  for (const model of spec.models) {\n    if (mapped.has(model.name)) continue;\n    if (model.fields.length < 2) continue;\n\n    // Strategy 2a: Prefer exact name match — if the IR model name matches an SDK\n    // interface name exactly, use it without Jaccard scoring. This prevents\n    // false positives when a superset interface (e.g., DirectoryUserWithGroups)\n    // scores higher than the exact match (DirectoryUser).\n    if (sdkSignatureNames.has(model.name) && !usedSdkNames.has(model.name)) {\n      lookup.modelNameByIR.set(model.name, model.name);\n      mapped.add(model.name);\n      usedSdkNames.add(model.name);\n      continue;\n    }\n\n    // Strategy 2a+: Try derived model names before falling back to Jaccard\n    const derivedNames = hints.derivedModelNames(model.name);\n    for (const derived of derivedNames) {\n      if (sdkSignatureNames.has(derived) && !usedSdkNames.has(derived)) {\n        lookup.modelNameByIR.set(model.name, derived);\n        mapped.add(model.name);\n        usedSdkNames.add(derived);\n        break;\n      }\n    }\n    if (mapped.has(model.name)) continue;\n\n    // In strict mode, skip Jaccard entirely\n    if (options?.strictModelMatch) continue;\n\n    // Strategy 2b: Fall back to Jaccard field-similarity matching\n    const irFields = irModelFieldSignature(model);\n    let bestMatch: string | null = null;\n    let bestScore = 0;\n\n    for (const sdk of sdkSignatures) {\n      if (usedSdkNames.has(sdk.name)) continue;\n\n      const { score, intersection } = jaccardSimilarity(irFields, sdk.fields);\n\n      // Require ≥60% Jaccard AND enough fields in common (scaled by model size)\n      const minIntersection = Math.max(3, Math.ceil(irFields.size * 0.5));\n      if (score > bestScore && score >= 0.6 && intersection >= minIntersection) {\n        bestScore = score;\n        bestMatch = sdk.name;\n      }\n    }\n\n    if (bestMatch) {\n      lookup.modelNameByIR.set(model.name, bestMatch);\n      mapped.add(model.name);\n      usedSdkNames.add(bestMatch);\n    }\n  }\n}\n\n/** Categories that can be patched by the overlay retry loop. */\nconst PATCHABLE_CATEGORIES = new Set(['symbol_removed', 'symbol_renamed']);\n\n/** Check if a classified change is patchable by the overlay loop. */\nexport function isPatchableChange(change: ClassifiedChange): boolean {\n  return PATCHABLE_CATEGORIES.has(change.category);\n}\n\n/**\n * Patch overlay with classified changes from a failed verification.\n * Adds explicit name mappings for symbols that were generated with wrong names.\n * Returns a new OverlayLookup (immutable).\n */\nexport function patchOverlay(overlay: OverlayLookup, changes: ClassifiedChange[], baseline: ApiSurface): OverlayLookup {\n  const patched: OverlayLookup = {\n    methodByOperation: new Map(overlay.methodByOperation),\n    httpKeyByMethod: new Map(overlay.httpKeyByMethod),\n    interfaceByName: new Map(overlay.interfaceByName),\n    typeAliasByName: new Map(overlay.typeAliasByName),\n    requiredExports: new Map(Array.from(overlay.requiredExports.entries()).map(([k, v]) => [k, new Set(v)])),\n    modelNameByIR: new Map(overlay.modelNameByIR),\n    fileBySymbol: new Map(overlay.fileBySymbol),\n  };\n\n  let warnedManifest = false;\n\n  for (const c of changes) {\n    if (!isPatchableChange(c)) continue;\n\n    // symbol is the fqName, e.g. \"ClassName.methodName\" or \"ClassName\"\n    const parts = c.symbol.split('.');\n    if (parts.length === 2) {\n      const [className, methodName] = parts;\n      const baseClass = baseline.classes[className];\n      if (baseClass && baseClass.methods[methodName]?.length > 0) {\n        const httpKey = overlay.httpKeyByMethod.get(`${className}.${methodName}`);\n        if (!httpKey && overlay.httpKeyByMethod.size === 0 && !warnedManifest) {\n          console.warn(\n            'Warning: No operations map in .oagen-manifest.json. Method-level violations cannot be auto-patched. ' +\n              'Implement buildOperationsMap in your emitter for the self-correcting loop to resolve these.',\n          );\n          warnedManifest = true;\n        }\n        if (httpKey) {\n          const method = baseClass.methods[methodName][0];\n          patched.methodByOperation.set(httpKey, {\n            className,\n            methodName,\n            params: method.params,\n            returnType: method.returnType,\n          });\n        }\n      }\n      const baseIface = baseline.interfaces[className];\n      if (baseIface) {\n        patched.interfaceByName.set(className, className);\n      }\n    } else if (parts.length === 1) {\n      const name = parts[0];\n      if (baseline.interfaces[name]) {\n        patched.interfaceByName.set(name, name);\n      }\n      if (baseline.typeAliases[name]) {\n        patched.typeAliasByName.set(name, name);\n      }\n    }\n  }\n\n  return patched;\n}\n"],"mappings":"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"}