@pattern-stack/codegen 0.6.5 → 0.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -1
- package/dist/runtime/subsystems/auth/auth.module.js +1 -1
- package/dist/runtime/subsystems/auth/auth.module.js.map +1 -1
- package/dist/runtime/subsystems/auth/auth.tokens.d.ts +1 -1
- package/dist/runtime/subsystems/auth/auth.tokens.js.map +1 -1
- package/dist/runtime/subsystems/auth/backends/encryption-key/env.d.ts +1 -1
- package/dist/runtime/subsystems/auth/backends/encryption-key/env.js +1 -1
- package/dist/runtime/subsystems/auth/backends/encryption-key/env.js.map +1 -1
- package/dist/runtime/subsystems/auth/controllers/auth.controller.js.map +1 -1
- package/dist/runtime/subsystems/auth/index.d.ts +1 -1
- package/dist/runtime/subsystems/auth/index.js +1 -1
- package/dist/runtime/subsystems/auth/index.js.map +1 -1
- package/dist/runtime/subsystems/auth/protocols/auth-strategy.d.ts +1 -1
- package/dist/runtime/subsystems/auth/protocols/integration-store.d.ts +2 -2
- package/dist/runtime/subsystems/auth/protocols/provider-strategy.d.ts +13 -6
- package/dist/runtime/subsystems/auth/runtime/oauth2-refresh.strategy.d.ts +2 -2
- package/dist/runtime/subsystems/auth/runtime/oauth2-refresh.strategy.js.map +1 -1
- package/dist/runtime/subsystems/auth/runtime/session-expired.error.d.ts +2 -2
- package/dist/runtime/subsystems/auth/runtime/session-expired.error.js.map +1 -1
- package/dist/runtime/subsystems/auth/runtime/with-auth-retry.d.ts +1 -1
- package/dist/runtime/subsystems/auth/runtime/with-auth-retry.js.map +1 -1
- package/dist/runtime/subsystems/index.d.ts +1 -1
- package/dist/runtime/subsystems/index.js +1 -1
- package/dist/runtime/subsystems/index.js.map +1 -1
- package/dist/runtime/subsystems/sync/deep-equal.differ.js.map +1 -1
- package/dist/runtime/subsystems/sync/execute-sync.use-case.js.map +1 -1
- package/dist/runtime/subsystems/sync/index.js.map +1 -1
- package/dist/runtime/subsystems/sync/sync-change-source.protocol.d.ts +1 -1
- package/dist/runtime/subsystems/sync/sync-cursor-store.memory-backend.js.map +1 -1
- package/dist/runtime/subsystems/sync/sync-loopback.protocol.d.ts +3 -4
- package/dist/runtime/subsystems/sync/sync-run-recorder.drizzle-backend.js.map +1 -1
- package/dist/runtime/subsystems/sync/sync.module.js.map +1 -1
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/package.json +1 -1
- package/runtime/subsystems/auth/auth.tokens.ts +1 -1
- package/runtime/subsystems/auth/backends/encryption-key/env.ts +3 -3
- package/runtime/subsystems/auth/controllers/auth.controller.ts +3 -3
- package/runtime/subsystems/auth/index.ts +2 -2
- package/runtime/subsystems/auth/protocols/auth-strategy.ts +1 -1
- package/runtime/subsystems/auth/protocols/integration-store.ts +2 -2
- package/runtime/subsystems/auth/protocols/provider-strategy.ts +12 -5
- package/runtime/subsystems/auth/runtime/oauth2-refresh.strategy.ts +2 -2
- package/runtime/subsystems/auth/runtime/session-expired.error.ts +2 -2
- package/runtime/subsystems/auth/runtime/with-auth-retry.ts +1 -1
- package/runtime/subsystems/index.ts +1 -1
- package/runtime/subsystems/sync/deep-equal.differ.ts +1 -1
- package/runtime/subsystems/sync/execute-sync.use-case.ts +1 -1
- package/runtime/subsystems/sync/sync-change-source.protocol.ts +1 -1
- package/runtime/subsystems/sync/sync-cursor-store.memory-backend.ts +1 -1
- package/runtime/subsystems/sync/sync-loopback.protocol.ts +3 -4
- package/runtime/subsystems/sync/sync-run-recorder.drizzle-backend.ts +1 -1
- package/templates/subsystem/auth/app-module-hook.ejs.t +1 -1
- package/templates/subsystem/auth/env-config.ejs.t +5 -5
- package/templates/subsystem/auth/prompt.js +3 -3
- package/templates/subsystem/auth-config/codegen-config-auth-block.ejs.t +1 -1
package/dist/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/parser/load-entities.ts","../../src/utils/yaml-loader.ts","../../src/schema/entity-definition.schema.ts","../../runtime/subsystems/sync/sync-field-diff.protocol.ts","../../runtime/subsystems/sync/detection-config.schema.ts","../../runtime/subsystems/sync/sync.tokens.ts","../../runtime/subsystems/sync/sync-errors.ts","../../runtime/subsystems/sync/sync-audit.schema.ts","../../runtime/subsystems/sync/sync-cursor-store.memory-backend.ts","../../runtime/subsystems/sync/sync-run-recorder.memory-backend.ts","../../runtime/subsystems/sync/deep-equal.differ.ts","../../runtime/subsystems/sync/execute-sync.use-case.ts","../../runtime/subsystems/sync/sync-cursor-store.drizzle-backend.ts","../../runtime/constants/tokens.ts","../../runtime/subsystems/sync/sync-run-recorder.drizzle-backend.ts","../../runtime/subsystems/sync/sync.module.ts","../../src/schema/event-definition.schema.ts","../../src/schema/relationship-definition.schema.ts","../../src/analyzer/graph-builder.ts","../../src/behaviors/external-id-tracking.ts","../../src/behaviors/soft-delete.ts","../../src/behaviors/timestamps.ts","../../src/behaviors/user-tracking.ts","../../src/behaviors/index.ts","../../src/analyzer/consistency-checker.ts","../../src/analyzer/statistics.ts","../../src/patterns/registry.ts","../../src/patterns/pattern-definition.ts","../../src/patterns/validate-composition.ts","../../src/patterns/validate-orchestration.ts","../../src/formatters/console-formatter.ts","../../src/formatters/json-formatter.ts","../../src/formatters/markdown-formatter.ts","../../src/patterns/library/activity.pattern.ts","../../src/patterns/library/base.pattern.ts","../../src/patterns/library/knowledge.pattern.ts","../../src/patterns/library/metadata.pattern.ts","../../src/patterns/library/synced.pattern.ts","../../src/patterns/library/index.ts","../../src/index.ts"],"sourcesContent":["/**\n * Entity Loader\n *\n * Loads and parses all YAML entity files from a directory.\n * Reuses existing yaml-loader and entity-definition schema from codegen.\n */\n\nimport { readdirSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport {\n\tloadEntityFromYaml,\n\tloadRelationshipFromYaml,\n\ttype LoadResult,\n\ttype LoadError,\n\ttype RelationshipLoadResult,\n\ttype RelationshipLoadError,\n} from '../utils/yaml-loader';\nimport type {\n\tParsedEntity,\n\tParsedEvent,\n\tParsedField,\n\tParsedProviderSync,\n\tParsedQuery,\n\tParsedRelationship,\n\tParsedRelationshipDefinition,\n\tParsedSync,\n\tParsedTypeDirection,\n\tAnalysisIssue,\n} from '../analyzer/types';\nimport {\n\tderiveRelationshipFKColumns,\n\tderiveTableName,\n\tderiveUniqueConstraint,\n\tcollectTypeNames,\n\ttype RelationshipDefinition,\n\ttype RelationshipTypes,\n} from '../schema/relationship-definition.schema';\n\nexport interface LoadEntitiesResult {\n\tentities: ParsedEntity[];\n\tissues: AnalysisIssue[];\n}\n\n/**\n * Transform a loaded entity definition into a ParsedEntity\n */\nfunction transformToEntity(result: LoadResult): ParsedEntity {\n\tconst { definition, filePath } = result;\n\n\t// Search queries use a different shape (name/filters/search/paginate) and\n\t// are consumed directly by the codegen templates, not by the analyzer.\n\t// Narrow to the by-column variant here for ParsedQuery mapping.\n\tconst queries: ParsedQuery[] | undefined = definition.queries\n\t\t?.filter((q): q is Extract<typeof q, { by: unknown }> => 'by' in q)\n\t\t.map((q) => ({\n\t\t\tby: q.by,\n\t\t\tunique: q.unique,\n\t\t\tselect: q.select,\n\t\t\torder: q.order,\n\t\t\tlimit: q.limit,\n\t\t\tvia: q.via,\n\t\t}));\n\n\tconst entity: ParsedEntity = {\n\t\tname: definition.entity.name,\n\t\tplural: definition.entity.plural,\n\t\ttable: definition.entity.table,\n\t\tpattern: definition.entity.pattern,\n\t\tpatterns: definition.entity.patterns,\n\t\tpatternConfig: definition.entity.config,\n\t\tscopeable: definition.entity.scopeable ?? false,\n\t\tfolderStructure: definition.entity.folder_structure ?? 'nested',\n\t\tfields: new Map(),\n\t\trelationships: new Map(),\n\t\tbehaviors: definition.behaviors.map((b) => (typeof b === 'string' ? b : b.name)),\n\t\tqueries,\n\t\tsourcePath: filePath,\n\t};\n\n\t// Parse fields\n\tfor (const [name, fieldDef] of Object.entries(definition.fields)) {\n\t\tconst field: ParsedField = {\n\t\t\tname,\n\t\t\ttype: fieldDef.type,\n\t\t\trequired: fieldDef.required ?? false,\n\t\t\tnullable: fieldDef.nullable ?? false,\n\t\t\tunique: fieldDef.unique ?? false,\n\t\t\tindex: fieldDef.index ?? false,\n\t\t\tforeignKey: fieldDef.foreign_key ? parseForeignKey(fieldDef.foreign_key) : undefined,\n\t\t\tchoices: fieldDef.choices,\n\t\t\tconstraints: {\n\t\t\t\tminLength: fieldDef.min_length,\n\t\t\t\tmaxLength: fieldDef.max_length,\n\t\t\t\tmin: fieldDef.min,\n\t\t\t\tmax: fieldDef.max,\n\t\t\t},\n\t\t\tui: {\n\t\t\t\tlabel: fieldDef.ui_label,\n\t\t\t\ttype: fieldDef.ui_type,\n\t\t\t\timportance: fieldDef.ui_importance,\n\t\t\t\tgroup: fieldDef.ui_group,\n\t\t\t\tsortable: fieldDef.ui_sortable,\n\t\t\t\tfilterable: fieldDef.ui_filterable,\n\t\t\t\tvisible: fieldDef.ui_visible,\n\t\t\t},\n\t\t};\n\t\tentity.fields.set(name, field);\n\t}\n\n\t// Parse relationships\n\tif (definition.relationships) {\n\t\tfor (const [name, relDef] of Object.entries(definition.relationships)) {\n\t\t\tconst relationship: ParsedRelationship = {\n\t\t\t\tname,\n\t\t\t\ttype: relDef.type,\n\t\t\t\ttarget: relDef.target,\n\t\t\t\tforeignKey: relDef.foreign_key,\n\t\t\t\tinverse: relDef.inverse,\n\t\t\t\tthrough: relDef.through,\n\t\t\t\tresolved: false,\n\t\t\t};\n\t\t\tentity.relationships.set(name, relationship);\n\t\t}\n\t}\n\n\t// Parse sync configuration\n\tif (definition.sync) {\n\t\tconst syncDef = definition.sync;\n\t\tconst parsedSync: ParsedSync = {\n\t\t\telectric: syncDef.electric ?? false,\n\t\t};\n\n\t\tif (syncDef.providers) {\n\t\t\tparsedSync.providers = {};\n\t\t\tfor (const [providerName, providerDef] of Object.entries(syncDef.providers)) {\n\t\t\t\tconst parsedProvider: ParsedProviderSync = {\n\t\t\t\t\tremoteEntity: providerDef.remote_entity,\n\t\t\t\t\tdirection: providerDef.direction,\n\t\t\t\t\tcdc: providerDef.cdc ?? false,\n\t\t\t\t};\n\t\t\t\tif (providerDef.field_mapping) {\n\t\t\t\t\tparsedProvider.fieldMapping = providerDef.field_mapping;\n\t\t\t\t}\n\t\t\t\tif (providerDef.read_only_fields) {\n\t\t\t\t\tparsedProvider.readOnlyFields = providerDef.read_only_fields;\n\t\t\t\t}\n\t\t\t\tparsedSync.providers[providerName] = parsedProvider;\n\t\t\t}\n\t\t}\n\n\t\tentity.sync = parsedSync;\n\t}\n\n\t// Parse events\n\tif (definition.events) {\n\t\tentity.events = definition.events.map((ev): ParsedEvent => ({\n\t\t\tname: ev.name,\n\t\t\tqueue: ev.queue,\n\t\t\tbody: ev.body,\n\t\t\tgenerateHandler: ev.generate_handler,\n\t\t}));\n\t}\n\n\t// Parse emits (EVT-7). Preserve `undefined` vs `[]` distinction — the\n\t// validator treats absence as a warning and explicit empty as opt-out.\n\tif (definition.emits !== undefined) {\n\t\tentity.emits = definition.emits;\n\t}\n\n\treturn entity;\n}\n\n/**\n * Parse a foreign key string (e.g., \"accounts.id\") into table and column\n */\nfunction parseForeignKey(fk: string): { table: string; column: string } {\n\tconst [table, column] = fk.split('.');\n\treturn { table, column: column ?? 'id' };\n}\n\n/**\n * Convert a load error to an analysis issue\n */\nfunction loadErrorToIssue(error: LoadError): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\n\tissues.push({\n\t\tseverity: 'error',\n\t\ttype: 'parse_error',\n\t\tmessage: error.error,\n\t\tpath: error.filePath,\n\t});\n\n\tif (error.details) {\n\t\tfor (const detail of error.details) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'error',\n\t\t\t\ttype: 'schema_error',\n\t\t\t\tmessage: detail,\n\t\t\t\tpath: error.filePath,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn issues;\n}\n\n/**\n * Load all entity YAML files from a directory\n */\nexport function loadEntities(entitiesDir: string): LoadEntitiesResult {\n\tconst entities: ParsedEntity[] = [];\n\tconst issues: AnalysisIssue[] = [];\n\n\tconst resolvedDir = resolve(entitiesDir);\n\n\t// Get all YAML files\n\tlet files: string[];\n\ttry {\n\t\tfiles = readdirSync(resolvedDir)\n\t\t\t.filter((f) => f.endsWith('.yaml') || f.endsWith('.yml'))\n\t\t\t.map((f) => join(resolvedDir, f));\n\t} catch (err) {\n\t\tissues.push({\n\t\t\tseverity: 'error',\n\t\t\ttype: 'parse_error',\n\t\t\tmessage: `Failed to read directory: ${resolvedDir}`,\n\t\t\tpath: resolvedDir,\n\t\t});\n\t\treturn { entities, issues };\n\t}\n\n\tif (files.length === 0) {\n\t\tissues.push({\n\t\t\tseverity: 'warning',\n\t\t\ttype: 'no_files',\n\t\t\tmessage: `No YAML files found in directory: ${resolvedDir}`,\n\t\t\tpath: resolvedDir,\n\t\t});\n\t\treturn { entities, issues };\n\t}\n\n\t// Load each file\n\tfor (const filePath of files) {\n\t\tconst result = loadEntityFromYaml(filePath);\n\n\t\tif (result.success) {\n\t\t\tentities.push(transformToEntity(result));\n\t\t} else {\n\t\t\tissues.push(...loadErrorToIssue(result));\n\t\t}\n\t}\n\n\treturn { entities, issues };\n}\n\n/**\n * Resolve cross-entity references\n */\nexport function resolveReferences(entities: ParsedEntity[]): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\tconst entityMap = new Map<string, ParsedEntity>();\n\n\t// Build entity map by name\n\tfor (const entity of entities) {\n\t\tif (entityMap.has(entity.name)) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'error',\n\t\t\t\ttype: 'duplicate_entity',\n\t\t\t\tentity: entity.name,\n\t\t\t\tmessage: `Duplicate entity name: ${entity.name}`,\n\t\t\t\tpath: entity.sourcePath,\n\t\t\t});\n\t\t}\n\t\tentityMap.set(entity.name, entity);\n\t}\n\n\t// Resolve relationships\n\tfor (const entity of entities) {\n\t\tfor (const [relName, rel] of entity.relationships) {\n\t\t\tconst targetEntity = entityMap.get(rel.target);\n\t\t\tif (targetEntity) {\n\t\t\t\trel.resolved = true;\n\t\t\t} else {\n\t\t\t\tissues.push({\n\t\t\t\t\tseverity: 'error',\n\t\t\t\t\ttype: 'missing_target',\n\t\t\t\t\tentity: entity.name,\n\t\t\t\t\tfield: relName,\n\t\t\t\t\tmessage: `Relationship '${relName}' references unknown entity '${rel.target}'`,\n\t\t\t\t\tpath: entity.sourcePath,\n\t\t\t\t\tsuggestion: `Define entity '${rel.target}' or fix the target name`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Check foreign key references\n\t\tfor (const [fieldName, field] of entity.fields) {\n\t\t\tif (field.foreignKey) {\n\t\t\t\tconst targetTable = field.foreignKey.table;\n\t\t\t\tconst targetEntity = Array.from(entityMap.values()).find(\n\t\t\t\t\t(e) => e.table === targetTable\n\t\t\t\t);\n\t\t\t\tif (!targetEntity) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tseverity: 'warning',\n\t\t\t\t\t\ttype: 'missing_fk_target',\n\t\t\t\t\t\tentity: entity.name,\n\t\t\t\t\t\tfield: fieldName,\n\t\t\t\t\t\tmessage: `Foreign key references unknown table '${targetTable}'`,\n\t\t\t\t\t\tpath: entity.sourcePath,\n\t\t\t\t\t\tsuggestion: `Define entity with table '${targetTable}' or fix the foreign_key reference`,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn issues;\n}\n\n// ============================================================================\n// Relationship Loading\n// ============================================================================\n\nexport interface LoadRelationshipsResult {\n\trelationships: ParsedRelationshipDefinition[];\n\tissues: AnalysisIssue[];\n}\n\n/**\n * Transform a loaded relationship definition into a ParsedRelationshipDefinition.\n *\n * This resolves all auto-generated fields: FK columns, type directions,\n * temporal/sourced fields, unique constraints.\n */\nfunction transformToRelationshipDefinition(\n\tresult: RelationshipLoadResult,\n): ParsedRelationshipDefinition {\n\tconst { definition, filePath } = result;\n\tconst config = definition.relationship;\n\n\tconst { fromColumn, toColumn } = deriveRelationshipFKColumns(config);\n\tconst table = deriveTableName(config);\n\tconst uniqueOn = deriveUniqueConstraint(config);\n\n\t// Resolve type directions\n\tconst types = resolveTypeDirections(config.types);\n\n\t// Parse custom fields\n\tconst fields = new Map<string, ParsedField>();\n\tif (definition.fields) {\n\t\tfor (const [name, fieldDef] of Object.entries(definition.fields)) {\n\t\t\tconst field: ParsedField = {\n\t\t\t\tname,\n\t\t\t\ttype: fieldDef.type,\n\t\t\t\trequired: fieldDef.required ?? false,\n\t\t\t\tnullable: fieldDef.nullable ?? false,\n\t\t\t\tunique: fieldDef.unique ?? false,\n\t\t\t\tindex: fieldDef.index ?? false,\n\t\t\t\tforeignKey: fieldDef.foreign_key\n\t\t\t\t\t? parseForeignKey(fieldDef.foreign_key)\n\t\t\t\t\t: undefined,\n\t\t\t\tchoices: fieldDef.choices,\n\t\t\t\tconstraints: {\n\t\t\t\t\tminLength: fieldDef.min_length,\n\t\t\t\t\tmaxLength: fieldDef.max_length,\n\t\t\t\t\tmin: fieldDef.min,\n\t\t\t\t\tmax: fieldDef.max,\n\t\t\t\t},\n\t\t\t\tui: {\n\t\t\t\t\tlabel: fieldDef.ui_label,\n\t\t\t\t\ttype: fieldDef.ui_type,\n\t\t\t\t\timportance: fieldDef.ui_importance,\n\t\t\t\t\tgroup: fieldDef.ui_group,\n\t\t\t\t\tsortable: fieldDef.ui_sortable,\n\t\t\t\t\tfilterable: fieldDef.ui_filterable,\n\t\t\t\t\tvisible: fieldDef.ui_visible,\n\t\t\t\t},\n\t\t\t};\n\t\t\tfields.set(name, field);\n\t\t}\n\t}\n\n\t// Parse queries\n\t// Relationship queries here: same filtering rationale as entity queries.\n\tconst queries: ParsedQuery[] | undefined = definition.queries\n\t\t?.filter((q): q is Extract<typeof q, { by: unknown }> => 'by' in q)\n\t\t.map((q) => ({\n\t\t\tby: q.by,\n\t\t\tunique: q.unique,\n\t\t\tselect: q.select,\n\t\t\torder: q.order,\n\t\t\tlimit: q.limit,\n\t\t}));\n\n\treturn {\n\t\tname: config.name,\n\t\ttable,\n\t\tfrom: config.from,\n\t\tto: config.to,\n\t\tselfReferential: config.from === config.to,\n\t\tfromColumn,\n\t\ttoColumn,\n\t\ttypes,\n\t\thasTypes: types.length > 0,\n\t\ttemporal: config.temporal,\n\t\tsourced: config.sourced,\n\t\tonDeleteFrom: config.on_delete_from ?? 'restrict',\n\t\tonDeleteTo: config.on_delete_to ?? 'restrict',\n\t\tuniqueOn,\n\t\tfields,\n\t\tqueries,\n\t\tsourcePath: filePath,\n\t};\n}\n\n/**\n * Resolve type directions from the YAML types: block.\n *\n * Simple list → all directed, no inverses.\n * Object map → each type has explicit direction metadata.\n */\nfunction resolveTypeDirections(\n\ttypes: RelationshipTypes | undefined,\n): ParsedTypeDirection[] {\n\tif (!types) return [];\n\n\tif (Array.isArray(types)) {\n\t\t// Simple list: all directed from→to\n\t\treturn types.map((name) => ({\n\t\t\tname,\n\t\t\tbidirectional: false,\n\t\t\tdirected: true,\n\t\t}));\n\t}\n\n\t// Object map: resolve each type's direction\n\treturn Object.entries(types).map(([name, dir]) => {\n\t\tconst direction = dir as { inverse?: string; bidirectional?: boolean; directed?: boolean };\n\t\treturn {\n\t\t\tname,\n\t\t\tinverse: direction.inverse,\n\t\t\tbidirectional: direction.bidirectional ?? false,\n\t\t\tdirected: direction.directed ?? (!direction.bidirectional && !direction.inverse),\n\t\t};\n\t});\n}\n\n/**\n * Load all relationship YAML files from a directory\n */\nexport function loadRelationships(\n\trelationshipsDir: string,\n): LoadRelationshipsResult {\n\tconst relationships: ParsedRelationshipDefinition[] = [];\n\tconst issues: AnalysisIssue[] = [];\n\n\tconst resolvedDir = resolve(relationshipsDir);\n\n\tlet files: string[];\n\ttry {\n\t\tfiles = readdirSync(resolvedDir)\n\t\t\t.filter((f) => f.endsWith('.yaml') || f.endsWith('.yml'))\n\t\t\t.map((f) => join(resolvedDir, f));\n\t} catch {\n\t\t// Directory doesn't exist — not an error, relationships are optional\n\t\treturn { relationships, issues };\n\t}\n\n\tif (files.length === 0) {\n\t\treturn { relationships, issues };\n\t}\n\n\tfor (const filePath of files) {\n\t\tconst result = loadRelationshipFromYaml(filePath);\n\n\t\tif (result.success) {\n\t\t\trelationships.push(transformToRelationshipDefinition(result));\n\t\t} else {\n\t\t\tissues.push(...loadErrorToIssue(result as unknown as LoadError));\n\t\t}\n\t}\n\n\treturn { relationships, issues };\n}\n\n/**\n * Resolve cross-references between relationship definitions and entities.\n * Validates that from/to entities exist.\n */\nexport function resolveRelationshipReferences(\n\trelationshipDefs: ParsedRelationshipDefinition[],\n\tentities: ParsedEntity[],\n): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\tconst entityNames = new Set(entities.map((e) => e.name));\n\n\tfor (const relDef of relationshipDefs) {\n\t\tif (!entityNames.has(relDef.from)) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'warning',\n\t\t\t\ttype: 'missing_relationship_endpoint',\n\t\t\t\tentity: relDef.name,\n\t\t\t\tmessage: `Relationship '${relDef.name}' references unknown 'from' entity '${relDef.from}'`,\n\t\t\t\tpath: relDef.sourcePath,\n\t\t\t\tsuggestion: `Define entity '${relDef.from}' or fix the 'from' value`,\n\t\t\t});\n\t\t}\n\n\t\tif (!entityNames.has(relDef.to)) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'warning',\n\t\t\t\ttype: 'missing_relationship_endpoint',\n\t\t\t\tentity: relDef.name,\n\t\t\t\tmessage: `Relationship '${relDef.name}' references unknown 'to' entity '${relDef.to}'`,\n\t\t\t\tpath: relDef.sourcePath,\n\t\t\t\tsuggestion: `Define entity '${relDef.to}' or fix the 'to' value`,\n\t\t\t});\n\t\t}\n\n\t\t// Check for duplicate relationship names\n\t\tconst dupes = relationshipDefs.filter((r) => r.name === relDef.name);\n\t\tif (dupes.length > 1) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'error',\n\t\t\t\ttype: 'duplicate_relationship',\n\t\t\t\tentity: relDef.name,\n\t\t\t\tmessage: `Duplicate relationship name: ${relDef.name}`,\n\t\t\t\tpath: relDef.sourcePath,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn issues;\n}\n\nexport { loadEntityFromYaml } from '../utils/yaml-loader';\nexport { loadRelationshipFromYaml } from '../utils/yaml-loader';\n","import { readFileSync, existsSync } from 'node:fs';\nimport { parse as parseYaml } from 'yaml';\nimport { ZodError } from 'zod';\nimport {\n\ttype EntityDefinition,\n\tEntityDefinitionSchema,\n} from '../schema/entity-definition.schema';\nimport {\n\ttype EventDefinition,\n\tEventDefinitionSchema,\n} from '../schema/event-definition.schema';\nimport {\n\ttype RelationshipDefinition,\n\tRelationshipDefinitionSchema,\n} from '../schema/relationship-definition.schema';\n\nexport interface LoadResult {\n\tsuccess: true;\n\tdefinition: EntityDefinition;\n\tfilePath: string;\n}\n\nexport interface LoadError {\n\tsuccess: false;\n\terror: string;\n\tdetails?: string[];\n\tfilePath: string;\n}\n\nexport type LoadEntityResult = LoadResult | LoadError;\n\n/**\n * Load and validate an entity definition from a YAML file\n */\nexport function loadEntityFromYaml(filePath: string): LoadEntityResult {\n\t// Check file exists\n\tif (!existsSync(filePath)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: `File not found: ${filePath}`,\n\t\t\tfilePath,\n\t\t};\n\t}\n\n\t// Read file\n\tlet content: string;\n\ttry {\n\t\tcontent = readFileSync(filePath, 'utf-8');\n\t} catch (err) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: `Failed to read file: ${filePath}`,\n\t\t\tdetails: [err instanceof Error ? err.message : String(err)],\n\t\t\tfilePath,\n\t\t};\n\t}\n\n\t// Parse YAML\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = parseYaml(content);\n\t} catch (err) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: `Invalid YAML syntax in ${filePath}`,\n\t\t\tdetails: [err instanceof Error ? err.message : String(err)],\n\t\t\tfilePath,\n\t\t};\n\t}\n\n\t// Validate against schema\n\tconst result = EntityDefinitionSchema.safeParse(parsed);\n\tif (!result.success) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: `Validation failed for ${filePath}`,\n\t\t\tdetails: formatZodErrors(result.error),\n\t\t\tfilePath,\n\t\t};\n\t}\n\n\treturn {\n\t\tsuccess: true,\n\t\tdefinition: result.data,\n\t\tfilePath,\n\t};\n}\n\n/**\n * Format Zod errors into human-readable messages\n */\nfunction formatZodErrors(error: ZodError): string[] {\n\treturn error.errors.map((err) => {\n\t\tconst path = err.path.join('.');\n\t\tconst location = path ? `at '${path}'` : 'at root';\n\t\treturn `${err.message} ${location}`;\n\t});\n}\n\n/**\n * Pretty-print a load error for CLI output\n */\nexport function formatLoadError(result: LoadError): string {\n\tconst lines = [`❌ ${result.error}`];\n\tif (result.details && result.details.length > 0) {\n\t\tlines.push('');\n\t\tfor (const detail of result.details) {\n\t\t\tlines.push(` • ${detail}`);\n\t\t}\n\t}\n\treturn lines.join('\\n');\n}\n\n/**\n * Load multiple entity files\n */\nexport function loadEntitiesFromYaml(filePaths: string[]): {\n\tsuccesses: LoadResult[];\n\tfailures: LoadError[];\n} {\n\tconst successes: LoadResult[] = [];\n\tconst failures: LoadError[] = [];\n\n\tfor (const filePath of filePaths) {\n\t\tconst result = loadEntityFromYaml(filePath);\n\t\tif (result.success) {\n\t\t\tsuccesses.push(result);\n\t\t} else {\n\t\t\tfailures.push(result);\n\t\t}\n\t}\n\n\treturn { successes, failures };\n}\n\n// ============================================================================\n// Relationship YAML Loading\n// ============================================================================\n\nexport interface RelationshipLoadResult {\n\tsuccess: true;\n\tdefinition: RelationshipDefinition;\n\tfilePath: string;\n}\n\nexport interface RelationshipLoadError {\n\tsuccess: false;\n\terror: string;\n\tdetails?: string[];\n\tfilePath: string;\n}\n\nexport type LoadRelationshipResult =\n\t| RelationshipLoadResult\n\t| RelationshipLoadError;\n\n/**\n * Load and validate a relationship definition from a YAML file\n */\nexport function loadRelationshipFromYaml(\n\tfilePath: string,\n): LoadRelationshipResult {\n\tif (!existsSync(filePath)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: `File not found: ${filePath}`,\n\t\t\tfilePath,\n\t\t};\n\t}\n\n\tlet content: string;\n\ttry {\n\t\tcontent = readFileSync(filePath, 'utf-8');\n\t} catch (err) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: `Failed to read file: ${filePath}`,\n\t\t\tdetails: [err instanceof Error ? err.message : String(err)],\n\t\t\tfilePath,\n\t\t};\n\t}\n\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = parseYaml(content);\n\t} catch (err) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: `Invalid YAML syntax in ${filePath}`,\n\t\t\tdetails: [err instanceof Error ? err.message : String(err)],\n\t\t\tfilePath,\n\t\t};\n\t}\n\n\tconst result = RelationshipDefinitionSchema.safeParse(parsed);\n\tif (!result.success) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: `Validation failed for ${filePath}`,\n\t\t\tdetails: formatZodErrors(result.error),\n\t\t\tfilePath,\n\t\t};\n\t}\n\n\treturn {\n\t\tsuccess: true,\n\t\tdefinition: result.data,\n\t\tfilePath,\n\t};\n}\n\n/**\n * Load multiple relationship files\n */\nexport function loadRelationshipsFromYaml(filePaths: string[]): {\n\tsuccesses: RelationshipLoadResult[];\n\tfailures: RelationshipLoadError[];\n} {\n\tconst successes: RelationshipLoadResult[] = [];\n\tconst failures: RelationshipLoadError[] = [];\n\n\tfor (const filePath of filePaths) {\n\t\tconst result = loadRelationshipFromYaml(filePath);\n\t\tif (result.success) {\n\t\t\tsuccesses.push(result);\n\t\t} else {\n\t\t\tfailures.push(result);\n\t\t}\n\t}\n\n\treturn { successes, failures };\n}\n\n// ============================================================================\n// Event YAML Loading\n// ============================================================================\n\nexport interface EventLoadResult {\n\tsuccess: true;\n\tdefinition: EventDefinition;\n\tfilePath: string;\n}\n\nexport interface EventLoadError {\n\tsuccess: false;\n\terror: string;\n\tdetails?: string[];\n\tfilePath: string;\n}\n\nexport type LoadEventResult = EventLoadResult | EventLoadError;\n\n/**\n * Load and validate a single event definition from a YAML file.\n *\n * Mirrors {@link loadEntityFromYaml}: existence check → readFileSync →\n * parseYaml → `EventDefinitionSchema.safeParse`. Returns a discriminated\n * result; callers are expected to aggregate into `AnalysisIssue`s rather\n * than throw.\n */\nexport function loadEventFromYaml(filePath: string): LoadEventResult {\n\tif (!existsSync(filePath)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: `File not found: ${filePath}`,\n\t\t\tfilePath,\n\t\t};\n\t}\n\n\tlet content: string;\n\ttry {\n\t\tcontent = readFileSync(filePath, 'utf-8');\n\t} catch (err) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: `Failed to read file: ${filePath}`,\n\t\t\tdetails: [err instanceof Error ? err.message : String(err)],\n\t\t\tfilePath,\n\t\t};\n\t}\n\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = parseYaml(content);\n\t} catch (err) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: `Invalid YAML syntax in ${filePath}`,\n\t\t\tdetails: [err instanceof Error ? err.message : String(err)],\n\t\t\tfilePath,\n\t\t};\n\t}\n\n\tconst result = EventDefinitionSchema.safeParse(parsed);\n\tif (!result.success) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: `Validation failed for ${filePath}`,\n\t\t\tdetails: formatZodErrors(result.error),\n\t\t\tfilePath,\n\t\t};\n\t}\n\n\treturn {\n\t\tsuccess: true,\n\t\tdefinition: result.data,\n\t\tfilePath,\n\t};\n}\n\n/**\n * Detect whether a YAML file is an entity or relationship definition.\n * Checks for the top-level discriminator key.\n */\nexport function detectYamlType(\n\tfilePath: string,\n): 'entity' | 'relationship' | 'unknown' {\n\tif (!existsSync(filePath)) return 'unknown';\n\n\ttry {\n\t\tconst content = readFileSync(filePath, 'utf-8');\n\t\tconst parsed = parseYaml(content) as Record<string, unknown>;\n\t\tif (parsed && typeof parsed === 'object') {\n\t\t\tif ('entity' in parsed) return 'entity';\n\t\t\tif ('relationship' in parsed) return 'relationship';\n\t\t}\n\t} catch {\n\t\t// Fall through\n\t}\n\treturn 'unknown';\n}\n","import { z } from \"zod\";\nimport { DetectionConfigSchema } from \"../../runtime/subsystems/sync\";\n\n/**\n * Entity Definition Schema\n *\n * Generates backend code:\n * - Domain entity + repository interface\n * - Application DTOs, use-cases, queries\n * - Infrastructure Drizzle schema + repository\n * - Presentation controller\n * - NestJS module wiring\n * - Shared Zod schema in packages/db\n *\n * Generates frontend code:\n * - Entity metadata for automatic admin panels\n * - UI type, importance, grouping for fields\n */\n\n// ============================================================================\n// Field Types\n// ============================================================================\n\nconst FieldTypeSchema = z.enum([\n \"string\",\n \"integer\",\n \"decimal\",\n \"boolean\",\n \"uuid\",\n \"date\",\n \"datetime\",\n \"json\",\n \"entity_ref\", // Polymorphic reference: generates {field}EntityType + {field}EntityId columns\n \"string_array\", // Array of strings: generates text[] column\n \"enum\", // Enum type with choices or choices_from\n]);\n\nexport type FieldType = z.infer<typeof FieldTypeSchema>;\n\n// ============================================================================\n// UI Metadata Types\n// ============================================================================\n\nconst UiTypeSchema = z.enum([\n \"text\",\n \"textarea\",\n \"number\",\n \"money\",\n \"percentage\",\n \"email\",\n \"url\",\n \"date\",\n \"datetime\",\n \"boolean\",\n \"enum\",\n \"reference\",\n \"json\",\n \"badge\",\n \"password\",\n]);\n\nexport type UiType = z.infer<typeof UiTypeSchema>;\n\nconst UiImportanceSchema = z.enum([\"primary\", \"secondary\", \"tertiary\"]);\n\nexport type UiImportance = z.infer<typeof UiImportanceSchema>;\n\n/**\n * UI Metadata Schema - Optional field-level UI properties\n *\n * All properties are optional and will be inferred at generation time\n * if not explicitly specified in the YAML definition.\n */\n// ============================================================================\n// Semantic / Analytics Metadata Types\n// ============================================================================\n\nconst AnalyticsAggregationSchema = z.enum([\n 'sum',\n 'min',\n 'max',\n 'count',\n 'count_distinct',\n 'average',\n 'median',\n 'percentile',\n 'sum_boolean',\n]);\n\nconst AnalyticsDimensionTypeSchema = z.enum(['categorical', 'time']);\n\nconst AnalyticsEntityTypeSchema = z.enum(['primary', 'unique', 'foreign', 'natural']);\n\nconst AnalyticsTimeGranularitySchema = z.enum(['day', 'week', 'month', 'quarter', 'year']);\n\nconst AnalyticsVisibilitySchema = z.enum(['internal', 'agent', 'public']);\n\nconst NonAdditiveDimensionSchema = z.union([\n z.string(),\n z.object({\n name: z.string(),\n window_choice: z.string().optional(),\n window_groupings: z.array(z.string()).optional(),\n }),\n]);\n\n/**\n * Semantic Metadata Schema - Optional field-level analytics properties\n *\n * Controls how a field is exposed to the cube.js semantic layer:\n * measures, dimensions, entities, and their configuration.\n */\nconst SemanticMetadataSchema = z.object({\n measure: z.boolean().optional(),\n analytics_aggregation: AnalyticsAggregationSchema.optional(),\n agg_time_dimension: z.string().optional(),\n non_additive_dimension: NonAdditiveDimensionSchema.optional(),\n dimension: z.boolean().optional(),\n dimension_type: AnalyticsDimensionTypeSchema.optional(),\n time_granularity: AnalyticsTimeGranularitySchema.optional(),\n is_partition: z.boolean().optional(),\n entity: z.boolean().optional(),\n entity_type: AnalyticsEntityTypeSchema.optional(),\n entity_role: z.string().optional(),\n analytics_visibility: AnalyticsVisibilitySchema.optional(),\n semantic_expr: z.string().optional(),\n semantic_label: z.string().optional(),\n});\n\nconst UiMetadataSchema = z.object({\n ui_label: z.string().optional(),\n ui_type: UiTypeSchema.optional(),\n ui_importance: UiImportanceSchema.optional(),\n ui_group: z.string().optional(),\n ui_sortable: z.boolean().optional(),\n ui_filterable: z.boolean().optional(),\n ui_visible: z.boolean().optional(),\n ui_placeholder: z.string().optional(),\n ui_help: z.string().optional(),\n ui_format: z.record(z.unknown()).optional(),\n});\n\n// ============================================================================\n// Field Definition\n// ============================================================================\n\n/**\n * Field Definition Schema\n *\n * Semantics:\n * - `required: true` → Field must be provided on CREATE (DTO validation)\n * - `required: false` → Field is optional on CREATE (DTO validation)\n * - `nullable: true` → Database column allows NULL\n * - `nullable: false` (default) → Database column is NOT NULL\n *\n * Common patterns:\n * - `required: true` (nullable defaults to false) → Must provide, cannot be null\n * - `required: false, nullable: true` → Optional field, can be null\n * - `required: true, nullable: true` → INVALID (rejected by validator)\n * - `required: false, nullable: false` → Has default value in DB\n */\n/**\n * Base Field Schema - Core database/type properties\n */\nconst BaseFieldSchema = z.object({\n type: FieldTypeSchema,\n required: z.boolean().optional().default(false),\n nullable: z.boolean().optional().default(false),\n\n // String constraints\n max_length: z.number().int().positive().optional(),\n min_length: z.number().int().nonnegative().optional(),\n\n // Numeric constraints\n min: z.number().optional(),\n max: z.number().optional(),\n\n // Enum/choices (inline definition)\n choices: z.array(z.string()).optional(),\n\n // Enum/choices from external file (e.g., \"relationship_types.yaml\")\n // Mutually exclusive with choices - parser loads file and extracts keys\n choices_from: z.string().optional(),\n\n // Entity reference: allowed entity types for polymorphic refs\n // Required when type is 'entity_ref'\n allowed_types: z.array(z.string()).optional(),\n\n // Default value\n default: z.unknown().optional(),\n\n // Indexing\n index: z.boolean().optional(),\n unique: z.boolean().optional(),\n\n // Foreign key reference (e.g., \"accounts.id\")\n foreign_key: z.string().optional(),\n});\n\n/**\n * Field Definition Schema - Combines base fields with optional UI metadata\n */\nconst FieldDefinitionSchema = BaseFieldSchema.merge(UiMetadataSchema).merge(SemanticMetadataSchema)\n .refine((data) => !(data.required === true && data.nullable === true), {\n message:\n \"'required: true' and 'nullable: true' cannot both be set. A required field cannot be null.\",\n path: [\"required\"],\n })\n .refine(\n (data) => {\n if (data.min_length !== undefined && data.type !== \"string\") {\n return false;\n }\n return true;\n },\n {\n message: \"'min_length' can only be used with type 'string'\",\n path: [\"min_length\"],\n },\n )\n .refine(\n (data) => {\n if (data.max_length !== undefined && data.type !== \"string\") {\n return false;\n }\n return true;\n },\n {\n message: \"'max_length' can only be used with type 'string'\",\n path: [\"max_length\"],\n },\n )\n .refine(\n (data) => {\n if (\n data.min !== undefined &&\n ![\"integer\", \"decimal\"].includes(data.type)\n ) {\n return false;\n }\n return true;\n },\n {\n message: \"'min' can only be used with numeric types\",\n path: [\"min\"],\n },\n )\n .refine(\n (data) => {\n if (\n data.max !== undefined &&\n ![\"integer\", \"decimal\"].includes(data.type)\n ) {\n return false;\n }\n return true;\n },\n {\n message: \"'max' can only be used with numeric types\",\n path: [\"max\"],\n },\n )\n .refine(\n (data) => {\n // entity_ref requires allowed_types\n if (data.type === \"entity_ref\" && !data.allowed_types?.length) {\n return false;\n }\n return true;\n },\n {\n message: \"'entity_ref' type requires 'allowed_types' to be specified\",\n path: [\"allowed_types\"],\n },\n )\n .refine(\n (data) => {\n // allowed_types only valid for entity_ref\n if (data.allowed_types !== undefined && data.type !== \"entity_ref\") {\n return false;\n }\n return true;\n },\n {\n message: \"'allowed_types' can only be used with type 'entity_ref'\",\n path: [\"allowed_types\"],\n },\n )\n .refine(\n (data) => {\n // choices and choices_from are mutually exclusive\n if (data.choices !== undefined && data.choices_from !== undefined) {\n return false;\n }\n return true;\n },\n {\n message: \"'choices' and 'choices_from' cannot both be specified\",\n path: [\"choices_from\"],\n },\n )\n .refine(\n (data) => {\n // enum type requires either choices or choices_from\n if (data.type === \"enum\" && !data.choices?.length && !data.choices_from) {\n return false;\n }\n return true;\n },\n {\n message: \"'enum' type requires either 'choices' or 'choices_from'\",\n path: [\"choices\"],\n },\n )\n .refine(\n (data) => {\n // If measure is true, analytics_aggregation must be present\n if (data.measure === true && !data.analytics_aggregation) {\n return false;\n }\n return true;\n },\n {\n message:\n \"When 'measure' is true, 'analytics_aggregation' must be specified\",\n path: [\"analytics_aggregation\"],\n },\n );\n\nexport type FieldDefinition = z.infer<typeof FieldDefinitionSchema>;\n\n// ============================================================================\n// Relationship Definition\n// ============================================================================\n\nconst RelationshipTypeSchema = z.enum([\"belongs_to\", \"has_many\", \"has_one\"]);\n\n/**\n * on_delete — governs database-level FK cascade behaviour for hard-deletes.\n *\n * Applies only to belongs_to relations; ignored on has_many / has_one.\n * Per ADR-021, this has NO effect under soft-delete: BaseService.delete()\n * issues an UPDATE (sets deleted_at), never a DELETE, so Postgres cascade\n * rules never fire for a soft-deleted parent.\n *\n * | Value | Emitted Drizzle | Postgres behaviour |\n * |-------------|------------------------------|---------------------------------------|\n * | restrict | { onDelete: 'restrict' } | Parent DELETE fails if children exist. DEFAULT. |\n * | cascade | { onDelete: 'cascade' } | Parent DELETE removes children. |\n * | set_null | { onDelete: 'set null' } | Parent DELETE nulls FK on children. Requires nullable: true. |\n * | no_action | { onDelete: 'no action' } | Deferred check (equivalent to restrict in single-statement txns). |\n *\n * See docs/adrs/ADR-021-on-delete-semantics.md for the full decision.\n */\nexport const OnDeleteSchema = z.enum([\"restrict\", \"cascade\", \"set_null\", \"no_action\"]);\n\nexport type OnDelete = z.infer<typeof OnDeleteSchema>;\n\nconst RelationshipSchema = z\n .object({\n type: RelationshipTypeSchema,\n target: z.string(), // Target entity name (e.g., \"account\")\n foreign_key: z.string(), // FK field name (e.g., \"account_id\")\n through: z.string().optional(), // For transitive: \"owned_opportunities.updates\"\n inverse: z.string().optional(), // Name of inverse relationship on target entity\n nullable: z.boolean().optional(), // Whether the FK column allows NULL\n on_delete: OnDeleteSchema.optional().default(\"restrict\"), // FK cascade action (belongs_to only; hard-delete only)\n })\n .strict()\n .refine(\n (data) => {\n // set_null requires nullable: true — Postgres cannot null a NOT NULL column\n if (data.on_delete === \"set_null\" && data.nullable !== true) {\n return false;\n }\n return true;\n },\n {\n message:\n \"'on_delete: set_null' requires 'nullable: true' — Postgres cannot null a NOT NULL FK column.\",\n path: [\"on_delete\"],\n },\n );\n\nexport type Relationship = z.infer<typeof RelationshipSchema>;\n\n// ============================================================================\n// Behavior Configuration\n// ============================================================================\n\n/**\n * Behavior configuration can be:\n * - A simple string: \"timestamps\"\n * - An object with options: { name: \"sluggable\", options: { source: \"title\" } }\n *\n * Built-in behaviors:\n * - timestamps: Adds created_at, updated_at fields\n * - soft_delete: Adds deleted_at field, filters deleted records\n * - user_tracking: Adds created_by, updated_by fields\n * - temporal_validity: Adds valid_from, valid_to, is_active fields\n * with deactivate() method and validity-aware query filtering\n */\nconst BehaviorConfigSchema = z.union([\n z.string(),\n z.object({\n name: z.string(),\n options: z.record(z.unknown()).optional(),\n }),\n]);\n\nexport type BehaviorConfig = z.infer<typeof BehaviorConfigSchema>;\n\n/**\n * Behavior strategy for repository code generation\n * - base_class: Extend BaseRepository (DRY, recommended)\n * - inline: Generate all code directly (WET, full transparency)\n */\nconst BehaviorStrategySchema = z.enum([\"base_class\", \"inline\"]);\n\nexport type BehaviorStrategy = z.infer<typeof BehaviorStrategySchema>;\n\n// ============================================================================\n// Entity Configuration\n// ============================================================================\n\n/**\n * Layout: Folder structure - controls directory nesting\n * - nested: domain/opportunity/opportunity.entity.ts\n * - flat: domain/opportunity.entity.ts\n */\nconst FolderStructureSchema = z.enum([\"nested\", \"flat\"]).default(\"nested\");\n\n/**\n * Layout: File grouping - controls how related code is organized\n * - separate: Each concern in its own file (entity.ts, repository.interface.ts)\n * - grouped: Related concerns combined into index.ts\n *\n * This is orthogonal to folder_structure:\n * | folder_structure | file_grouping | Result |\n * |-----------------|---------------|--------|\n * | nested | separate | domain/opportunity/opportunity.entity.ts |\n * | nested | grouped | domain/opportunity/index.ts (combined) |\n * | flat | separate | domain/opportunity.entity.ts |\n * | flat | grouped | domain/opportunity.ts (combined) |\n */\nconst FileGroupingSchema = z.enum([\"separate\", \"grouped\"]).default(\"separate\");\n\n/**\n * Expose configuration - which layers to generate for this entity\n * - repository: Always generated (domain entity, repository interface/impl)\n * - rest: Generate REST controller\n * - trpc: Generate tRPC module\n * - electric: Generate Electric SQL migration (REPLICA IDENTITY + publication)\n *\n * Default: ['repository', 'rest', 'trpc'] (all layers)\n */\nconst ExposeLayerSchema = z.enum([\"repository\", \"rest\", \"trpc\", \"electric\"]);\nexport type ExposeLayer = z.infer<typeof ExposeLayerSchema>;\n\nconst EntityConfigSchema = z\n .object({\n name: z\n .string()\n .regex(\n /^[a-z][a-z0-9_]*$/,\n \"Entity name must be lowercase with underscores (e.g., 'opportunity')\",\n ),\n plural: z.string().regex(/^[a-z][a-z0-9_]*$/, \"Plural must be lowercase\"),\n table: z.string().regex(/^[a-z][a-z0-9_]*$/, \"Table must be lowercase\"),\n\n // Layout options (orthogonal concerns)\n // folder_structure: controls directory nesting\n // file_grouping: controls file organization\n folder_structure: FolderStructureSchema.optional(),\n file_grouping: FileGroupingSchema.optional(),\n\n // Per-entity behavior strategy override (overrides codegen.config.yaml)\n behavior_strategy: BehaviorStrategySchema.optional(),\n // Which layers to generate (default: all)\n expose: z\n .array(ExposeLayerSchema)\n .optional()\n .default([\"repository\", \"rest\", \"trpc\"]),\n\n // App-defined patterns (ADR-031, supersedes ADR-005 family:).\n // `pattern:` and `patterns:` are mutually exclusive — use `pattern:`\n // for a single pattern and `patterns:` for multi-pattern composition.\n // Pattern names resolve against the registry at codegen time.\n pattern: z.string().optional(),\n patterns: z.array(z.string()).optional(),\n // Per-pattern config, keyed by pattern name. Each value is validated\n // against the pattern's `configSchema` in composition validation\n // (src/patterns/validate-composition.ts — PATTERN-4).\n config: z.record(z.string(), z.unknown()).optional(),\n\n // JOB-7: marks this entity as a valid scope target for job scoping.\n // Drives the generated ScopeEntityType union in\n // runtime/subsystems/jobs/generated/scope-entity-type.ts.\n scopeable: z.boolean().optional(),\n })\n .strict()\n .refine((d) => !(d.pattern && d.patterns), {\n message: \"'pattern' and 'patterns' are mutually exclusive\",\n });\n\nexport type EntityConfig = z.infer<typeof EntityConfigSchema>;\n\n// ============================================================================\n// Query Declaration\n// ============================================================================\n\n/**\n * Query Declaration Schema - Declarative query generation (ADR-005)\n *\n * Each declaration generates repository + service + use case methods.\n *\n * Examples:\n * { by: [\"user_id\"] }\n * { by: [\"email\"], unique: true }\n * { by: [\"account_id\"], order: \"created_at desc\", limit: true }\n * { by: [\"opportunity_id\"], select: [\"email\"], via: \"opportunity_contact_link\" }\n */\nconst QueryDeclarationSchema = z.object({\n by: z.array(z.string()).min(1),\n unique: z.boolean().optional(),\n select: z.array(z.string()).optional(),\n order: z.string().optional(),\n limit: z.boolean().optional(),\n via: z.string().optional(),\n});\n\nexport type QueryDeclaration = z.infer<typeof QueryDeclarationSchema>;\n\n/**\n * Search Query Declaration — filtered search with pagination.\n *\n * Emits:\n * - `searchXs(input): Promise<Page<Entity>>` on the service\n * - `GET /xs/search` controller route with Zod filter schema\n * - `SearchXsUseCase` with filter-AND + count-for-total semantics\n *\n * Example:\n * - name: search\n * filters: [user_id, provider, is_visible, canonical_state, is_closed]\n * search: name # optional ilike on a single text column\n * paginate: true # defaults to limit 50, max 200, offset 0\n *\n * Consumer contract: `@shared/http/pagination` must export\n * `PaginationSchema` (z.object with limit+offset defaults) and a\n * `Page<T>` interface with `{ items, total, limit, offset }`.\n */\nconst SearchQueryDeclarationSchema = z.object({\n name: z.literal('search'),\n filters: z.array(z.string()).min(1),\n search: z.string().optional(),\n paginate: z.boolean().optional().default(true),\n order: z.string().optional(),\n});\n\nexport type SearchQueryDeclaration = z.infer<typeof SearchQueryDeclarationSchema>;\n\n/**\n * Discriminated union: query declarations can be either the legacy\n * by-column findByX form or the named-search form. The two shapes are\n * disjoint (no `name` vs required `name: 'search'`), so consumers can\n * mix them in the same `queries:` block.\n */\nconst AnyQueryDeclarationSchema = z.union([\n SearchQueryDeclarationSchema,\n QueryDeclarationSchema,\n]);\n\n// ============================================================================\n// Sync Configuration\n// ============================================================================\n\n/**\n * Direction of sync with an external provider\n */\nexport const SyncDirectionSchema = z.enum([\n 'inbound',\n 'outbound',\n 'bidirectional',\n]);\n\nexport type SyncDirection = z.infer<typeof SyncDirectionSchema>;\n\n/**\n * Per-provider sync configuration\n */\nexport const ProviderSyncSchema = z.object({\n remote_entity: z.string(),\n direction: SyncDirectionSchema,\n cdc: z.boolean().optional().default(false),\n field_mapping: z.record(z.string(), z.string()).optional(),\n read_only_fields: z.array(z.string()).optional(),\n});\n\nexport type ProviderSync = z.infer<typeof ProviderSyncSchema>;\n\n/**\n * Top-level sync block: Electric SQL + named provider configs\n */\nexport const SyncConfigSchema = z.object({\n electric: z.boolean().optional().default(false),\n providers: z.record(z.string(), ProviderSyncSchema).optional(),\n});\n\nexport type SyncConfig = z.infer<typeof SyncConfigSchema>;\n\n// ============================================================================\n// Event Declaration\n// ============================================================================\n\n/**\n * Event Declaration Schema - Domain event declarations (CODEGEN-EVOLUTION-PLAN Phase 2)\n *\n * Each declaration generates typed event classes, handlers, and queue registration.\n *\n * Example:\n * name: opportunity_stage_changed\n * queue: domain-events\n * body:\n * opportunity_id: uuid\n * old_stage: string\n * generate_handler: true\n */\nconst EventDeclarationSchema = z.object({\n name: z\n .string()\n .regex(/^[a-z][a-z0-9_]*$/, \"Event name must be snake_case\"),\n queue: z.string(),\n body: z.record(z.string(), z.string()),\n generate_handler: z.boolean().optional().default(false),\n});\n\nexport type EventDeclaration = z.infer<typeof EventDeclarationSchema>;\n\n// ============================================================================\n// Analytics Block (entity-level)\n// ============================================================================\n\n/**\n * Simple metric in a YAML metric definition\n */\nconst SimpleMetricSchema = z.object({\n type: z.literal('simple'),\n measure: z.string(),\n agg: AnalyticsAggregationSchema.optional(),\n filter: z.string().optional(),\n description: z.string().optional(),\n label: z.string().optional(),\n});\n\n/**\n * Derived metric — expression combining other metrics\n */\nconst DerivedMetricSchema = z.object({\n type: z.literal('derived'),\n expr: z.string(),\n metrics: z.array(z.string()),\n description: z.string().optional(),\n label: z.string().optional(),\n});\n\n/**\n * Ratio metric — numerator / denominator\n */\nconst RatioMetricSchema = z.object({\n type: z.literal('ratio'),\n numerator: z.union([z.string(), SimpleMetricSchema]),\n denominator: z.union([z.string(), SimpleMetricSchema]),\n filter: z.string().optional(),\n description: z.string().optional(),\n label: z.string().optional(),\n});\n\n/**\n * Cumulative metric — time-series accumulation\n */\nconst CumulativeMetricSchema = z.object({\n type: z.literal('cumulative'),\n measure: z.string(),\n window: z.string().optional(),\n grain_to_date: AnalyticsTimeGranularitySchema.optional(),\n description: z.string().optional(),\n label: z.string().optional(),\n});\n\n/**\n * Discriminated union of all four metric types\n */\nconst MetricDefinitionSchema = z.discriminatedUnion('type', [\n SimpleMetricSchema,\n DerivedMetricSchema,\n RatioMetricSchema,\n CumulativeMetricSchema,\n]);\n\nexport type MetricDefinition = z.infer<typeof MetricDefinitionSchema>;\n\n/**\n * Entity-level analytics block\n *\n * Declared in the YAML under `analytics:` alongside fields and relationships.\n */\nconst AnalyticsBlockSchema = z.object({\n measure_packs: z.array(z.string()).optional(),\n cube_name: z.string().optional(),\n metrics: z.record(z.string(), MetricDefinitionSchema).optional(),\n});\n\nexport type AnalyticsBlock = z.infer<typeof AnalyticsBlockSchema>;\n\n// ============================================================================\n// Full Entity Definition\n// ============================================================================\n\n// ============================================================================\n// Generation Toggles\n// ============================================================================\n\n/**\n * Per-entity opt-outs for code generation.\n *\n * - `writes`: when `false`, suppresses create/update/delete use cases,\n * matching controller routes, and module providers. Defaults to `true`.\n */\nconst GenerateConfigSchema = z\n .object({\n writes: z.boolean().optional().default(true),\n })\n .strict();\n\nexport type GenerateConfig = z.infer<typeof GenerateConfigSchema>;\n\nexport const EntityDefinitionSchema = z\n .object({\n entity: EntityConfigSchema,\n fields: z.record(z.string(), FieldDefinitionSchema),\n relationships: z.record(z.string(), RelationshipSchema).optional(),\n // Behaviors add cross-cutting concerns (timestamps, soft_delete, user_tracking, etc.)\n behaviors: z.array(BehaviorConfigSchema).optional().default([]),\n\n // Per-entity generation toggles (e.g. disable write-side emission)\n generate: GenerateConfigSchema.optional(),\n\n // EAV (entity-attribute-value) dual-write + paired reads (ADR-13).\n // When `true`, codegen emits:\n // - FindXWithFieldsUseCase + ListXWithFieldsUseCase (paired reads)\n // - CreateX / UpdateX use cases in transactional compound-write shape\n // (composes entity service + FieldValueService in one db.transaction,\n // splits `{ fields, ...core }` from the DTO)\n // - GET /:id/with-fields + GET /with-fields controller routes\n // - Service with injected FieldValueRepository + findByIdWithFields /\n // listWithFields paired read methods\n //\n // Consumer contract (must be in place before regen):\n // - BaseService.create/update/delete accept optional `tx` parameter\n // - `@shared/eav-helpers` exports `toEavRows(entityId, entityType, fields)`\n // and `mergeEavRows(rows)`\n // - FieldValueService exposes `upsertMany(rows, tx?)` (inherited from\n // MetadataEntityService)\n // - DRIZZLE_DB injection token available via `@shared/constants/tokens`\n //\n // Defaults to `false` — opt in per entity that needs dynamic/custom fields.\n eav: z.boolean().optional().default(false),\n\n // Declare this entity IS an EAV value table. When `true`, codegen emits\n // the compound EAV methods (upsertFieldsTransactional, findMergedByEntity)\n // on the service and the upsertCurrentValues method on the repository —\n // no hand extension required. Companion flag `eav_definition_table`\n // identifies the sibling entity that stores the field-key ↔ id lookup.\n //\n // Mutually exclusive with `eav: true` in practice — a value table holds\n // OTHER entities' dynamic fields, it isn't itself an EAV-opt-in entity.\n //\n // Assumption (v1): value tables have a `user_id` column. Future\n // `eav_user_scoped: false` flag will relax this for audit/system EAV.\n eav_value_table: z.boolean().optional().default(false),\n\n // Singular entity name of the field-definitions entity that pairs with\n // this value table (matches the `target:` convention in relationship\n // YAMLs). Required when `eav_value_table: true`; ignored otherwise.\n eav_definition_table: z.string().optional(),\n\n\n // v2: Declarative query generation (ADR-005)\n // Generates repository + service + use case methods from declarations\n queries: z.array(AnyQueryDeclarationSchema).optional(),\n\n // v2: Integration sync configuration (CODEGEN-EVOLUTION-PLAN Phase 2)\n // Electric SQL + provider sync (Salesforce, HubSpot, etc.)\n sync: SyncConfigSchema.optional(),\n\n // ADR-033.1: Provider-keyed change-source detection.\n //\n // Map of provider name → DetectionConfig. Single-provider entities use\n // a one-key map; multi-provider entities list each provider as a\n // separate key. Each value is an independent `DetectionConfig` (its\n // own mode/cursor/mapping/filters) sourced from the canonical schema\n // in `runtime/subsystems/sync` so this validator and the runtime\n // parser stay in lockstep.\n //\n // Within-file cross-check (ADR-033.1 §6): every key here must also\n // appear in `sync.providers` — see the superRefine on\n // `EntityDefinitionSchema` below.\n detection: z.record(z.string(), DetectionConfigSchema).optional(),\n\n // v2: Domain event declarations (CODEGEN-EVOLUTION-PLAN Phase 2)\n // Generates typed event classes, handlers, and queue registration\n events: z.array(EventDeclarationSchema).optional(),\n\n // EVT-7: Opt-in typed event emission. Each entry names an `EventDefinition`\n // (top-level `events/<type>.yaml` or an inline `events:` block entry) that\n // the generated use-cases should publish via `TypedEventBus.publish(...)`\n // inside a Drizzle transaction.\n //\n // emits: [contact_created, contact_updated]\n //\n // Cross-validated in `validateEntityEmits()` against the merged event\n // registry. `undefined` ⇒ fallback to untyped lifecycle-events + warning;\n // `[]` ⇒ explicit opt-out, no warning, no typed emission.\n emits: z\n .array(\n z\n .string()\n .regex(/^[a-z][a-z0-9_]*$/, 'emits entries must be snake_case event type names'),\n )\n .optional(),\n\n // v2: Analytics / semantic layer configuration\n // Cube.js measure packs, custom cube name, and metric definitions\n analytics: AnalyticsBlockSchema.optional(),\n })\n .strict()\n .refine(\n (data) => !data.eav_value_table || typeof data.eav_definition_table === 'string',\n {\n message:\n \"`eav_definition_table` is required when `eav_value_table: true` — \" +\n \"declare the singular entity name of the paired field-definitions entity \" +\n \"(e.g. `eav_definition_table: 'field_definition'`).\",\n path: ['eav_definition_table'],\n },\n )\n .superRefine((entity, ctx) => {\n if (!entity.detection) return;\n const declared = new Set(Object.keys(entity.sync?.providers ?? {}));\n for (const provider of Object.keys(entity.detection)) {\n if (!declared.has(provider)) {\n ctx.addIssue({\n code: 'custom',\n path: ['detection', provider],\n message: `Provider '${provider}' used in detection: but not declared in sync.providers. Known providers: ${[...declared].join(', ')}`,\n });\n }\n }\n });\n\nexport type EntityDefinition = z.infer<typeof EntityDefinitionSchema>;\n\n// ============================================================================\n// Validation Helpers\n// ============================================================================\n\nexport function validateEntityDefinition(data: unknown): EntityDefinition {\n return EntityDefinitionSchema.parse(data);\n}\n\nexport function safeValidateEntityDefinition(data: unknown): {\n success: boolean;\n data?: EntityDefinition;\n error?: z.ZodError;\n} {\n const result = EntityDefinitionSchema.safeParse(data);\n if (result.success) {\n return { success: true, data: result.data };\n }\n return { success: false, error: result.error };\n}\n\n// ============================================================================\n// Type Mapping Utilities (for code generation)\n// ============================================================================\n\n/**\n * Maps YAML field types to TypeScript types\n *\n * Note: 'entity_ref' is handled specially in templates as it generates\n * two fields: {field}EntityType (EntityType enum) and {field}EntityId (string)\n */\nexport const fieldTypeToTypeScript: Record<FieldType, string> = {\n string: \"string\",\n integer: \"number\",\n decimal: \"number\",\n boolean: \"boolean\",\n uuid: \"string\",\n date: \"Date\",\n datetime: \"Date\",\n json: \"unknown\",\n entity_ref: \"EntityRef\", // Placeholder - templates handle specially\n string_array: \"string[]\",\n enum: \"string\", // Actual enum type generated from choices\n};\n\n/**\n * Maps YAML field types to Drizzle column types\n *\n * Note: 'entity_ref' generates two columns: pgEnum + uuid\n * Note: 'enum' uses pgEnum with choices\n */\nexport const fieldTypeToDrizzle: Record<FieldType, string> = {\n string: \"varchar\",\n integer: \"integer\",\n decimal: \"decimal\",\n boolean: \"boolean\",\n uuid: \"uuid\",\n date: \"date\",\n datetime: \"timestamp\",\n json: \"jsonb\",\n entity_ref: \"entity_ref\", // Placeholder - templates handle specially (enum + uuid)\n string_array: \"text().array()\",\n enum: \"enum\", // Placeholder - templates generate pgEnum\n};\n\n/**\n * Maps YAML field types to Zod schema methods\n *\n * Note: 'entity_ref' generates two fields in Zod schema\n * Note: 'enum' uses z.enum() with choices\n */\nexport const fieldTypeToZod: Record<FieldType, string> = {\n string: \"z.string()\",\n integer: \"z.number().int()\",\n // Drizzle maps PG `numeric` to a JS string to preserve precision.\n // Using z.coerce.string() — not z.coerce.number() — prevents silent\n // precision loss on large decimal values. Matches clean-lite-ps (PR #42).\n decimal: \"z.coerce.string()\",\n boolean: \"z.boolean()\",\n uuid: \"z.string().uuid()\",\n date: \"z.date()\",\n datetime: \"z.date()\",\n json: \"z.unknown()\",\n entity_ref: \"entity_ref\", // Placeholder - templates handle specially\n string_array: \"z.array(z.string())\",\n enum: \"z.enum()\", // Placeholder - templates add choices\n};\n","/**\n * Sync subsystem — field-diff protocol (port)\n *\n * `IFieldDiffer<T>` is the pluggable differ seam. The default implementation\n * (`DeepEqualDiffer`, ships in SYNC-5) walks every field except an ignore\n * list; CDC-aware differs can skip comparison for fields the provider didn't\n * flag as changed.\n *\n * `FieldDiffSchema` is the structural enforcement of the `changed_fields`\n * column per ADR-0003 — enforced at write time by the recorder service so\n * consumers can rely on the shape in downstream queries.\n */\nimport { z } from 'zod';\n\n// ============================================================================\n// FieldDiff shape — the ADR-0003 contract\n// ============================================================================\n\n/**\n * Structured per-field change. Enforced shape for `sync_run_items.changed_fields`.\n *\n * `created` items set `from: null, to: <value>` for every non-null field.\n * `deleted` items set `from: <value>, to: null`.\n * `noop` items carry `{}`.\n */\nexport const FieldDiffValueSchema = z.object({\n from: z.unknown(),\n to: z.unknown(),\n});\n\nexport const FieldDiffSchema = z.record(z.string(), FieldDiffValueSchema);\n\nexport type FieldDiffValue = z.infer<typeof FieldDiffValueSchema>;\nexport type FieldDiff = z.infer<typeof FieldDiffSchema>;\n\n/** Result of comparing a new record against its existing local state. */\nexport type DiffResult = FieldDiff | 'noop';\n\n// ============================================================================\n// IFieldDiffer\n// ============================================================================\n\n/**\n * Pluggable differ. Default ships in SYNC-5 as `DeepEqualDiffer<T>` —\n * deep-equal over every field except an ignore list (`updated_at` and other\n * row metadata). CDC-aware differs restrict comparison to\n * `providerChangedFields` when supplied.\n */\nexport interface IFieldDiffer<T> {\n /**\n * @param existing — current local state, or `null` when the record is new\n * @param incoming — the canonical record coming from the adapter\n * @param providerChangedFields — optional hint from CDC-capable sources;\n * when present, differ may restrict the comparison to these fields\n */\n diff(\n existing: T | null,\n incoming: T,\n providerChangedFields?: string[],\n ): DiffResult;\n}\n","/**\n * Sync subsystem — DetectionConfig schema (#226-1)\n *\n * Canonical Zod schema for per-entity sync detection config. The schema is\n * the single source of truth for filter/mapping shape and is consumed by:\n *\n * 1. Runtime primitives — `PollChangeSource<T>`, `WebhookChangeSource<T>`\n * (#226-3, #226-4) accept a parsed `DetectionConfig` at construction.\n * 2. Codegen — `src/schema/entity-definition.schema.ts` (#226-6) imports\n * this schema so per-entity YAML `detection:` blocks validate against\n * the same shape the runtime enforces.\n *\n * Locked decisions (see ADR-033 + decision memo Q1–Q6):\n * - Filter vocabulary is flat AND of `{ field, op, value }` triples; richer\n * boolean expressions (OR / NOT / nested) are deferred per epic open Q3.\n * - Cursor strategy is a tagged union over the four shapes the three modes\n * need (`systemModstamp`, `replayId`, `timestamp`, `eventId`). Each\n * strategy types its cursor internally; the orchestrator persists what\n * the iterator last yielded (sync skill rule 2).\n * - `mode: 'poll'` may opt into `provenance: 'cdc'` so Stripe-style event\n * endpoints (mechanically a poll, semantically CDC) reuse the poll\n * primitive while emitting `Change<T>.source = 'cdc'`. Long-lived\n * streaming CDC (SFDC Pub-Sub, Debezium) is a separate primitive\n * deferred to #226-8.\n * - `webhook` mode requires `eventIdField` so `WebhookChangeSource<T>`\n * can populate `Change<T>.dedupKey` from the inbound staging row.\n */\nimport { z } from 'zod';\n\n// ============================================================================\n// Field mapping — provider field → canonical target\n// ============================================================================\n\n/**\n * Maps a single provider field onto the canonical record. `transform` is an\n * opt-in tag the adapter callback may inspect (`date-iso`, `decimal-string`,\n * etc.); the schema does not enumerate transforms — adapters interpret them.\n */\nexport const FieldMappingSchema = z.object({\n source: z.string().min(1),\n target: z.string().min(1),\n transform: z.string().min(1).optional(),\n});\n\nexport type FieldMapping = z.infer<typeof FieldMappingSchema>;\n\n// ============================================================================\n// Resolved filter — flat-AND triple\n// ============================================================================\n\n/**\n * A single resolved filter clause applied at fetch time. `value` is `unknown`\n * to admit primitives, arrays (for `in` / `nin`), and dates as ISO strings —\n * adapters interpret per provider.\n */\nexport const ResolvedFilterSchema = z.object({\n field: z.string().min(1),\n op: z.enum(['eq', 'neq', 'in', 'nin', 'gt', 'gte', 'lt', 'lte']),\n value: z.unknown(),\n});\n\nexport type ResolvedFilter = z.infer<typeof ResolvedFilterSchema>;\n\n// ============================================================================\n// Cursor strategy — tagged union over the four shapes the modes need\n// ============================================================================\n\nconst SystemModstampCursorSchema = z.object({\n kind: z.literal('systemModstamp'),\n field: z.string().min(1),\n});\n\nconst ReplayIdCursorSchema = z.object({\n kind: z.literal('replayId'),\n field: z.string().min(1),\n});\n\nconst TimestampCursorSchema = z.object({\n kind: z.literal('timestamp'),\n field: z.string().min(1),\n});\n\nconst EventIdCursorSchema = z.object({\n kind: z.literal('eventId'),\n field: z.string().min(1),\n});\n\nexport const CursorStrategySchema = z.discriminatedUnion('kind', [\n SystemModstampCursorSchema,\n ReplayIdCursorSchema,\n TimestampCursorSchema,\n EventIdCursorSchema,\n]);\n\nexport type CursorStrategy = z.infer<typeof CursorStrategySchema>;\n\n// ============================================================================\n// Mode-specific blocks\n// ============================================================================\n\n/**\n * Poll-mode block. `provenance: 'cdc'` opts the poll primitive into stamping\n * `Change<T>.source = 'cdc'` and populating `dedupKey` from the cursor's\n * `field` — used for Stripe-style event endpoints. Defaults to `'poll'`.\n */\nexport const PollDetectionSchema = z.object({\n cursor: CursorStrategySchema,\n provenance: z.enum(['poll', 'cdc']).optional(),\n});\n\nexport type PollDetection = z.infer<typeof PollDetectionSchema>;\n\n/**\n * Webhook-mode block. `eventIdField` names the column in the consumer-owned\n * inbound staging row that `WebhookChangeSource<T>` reads to set\n * `Change<T>.dedupKey`.\n */\nexport const WebhookDetectionSchema = z.object({\n eventIdField: z.string().min(1),\n});\n\nexport type WebhookDetection = z.infer<typeof WebhookDetectionSchema>;\n\n// ============================================================================\n// DetectionConfig — top-level discriminated union over `mode`\n// ============================================================================\n\nconst PollModeSchema = z.object({\n mode: z.literal('poll'),\n poll: PollDetectionSchema,\n mapping: z.array(FieldMappingSchema).min(1),\n filters: z.array(ResolvedFilterSchema).default([]),\n});\n\nconst WebhookModeSchema = z.object({\n mode: z.literal('webhook'),\n webhook: WebhookDetectionSchema,\n mapping: z.array(FieldMappingSchema).min(1),\n filters: z.array(ResolvedFilterSchema).default([]),\n});\n\n/**\n * Top-level detection config. Discriminated on `mode` so the relevant\n * mode-block (poll/webhook) is structurally required for that mode. CDC as a\n * long-lived streaming primitive is deferred (#226-8); CDC-as-provenance\n * (Stripe-style event endpoints) is expressed via `mode: 'poll'` with\n * `poll.provenance: 'cdc'`.\n */\nexport const DetectionConfigSchema = z.discriminatedUnion('mode', [\n PollModeSchema,\n WebhookModeSchema,\n]);\n\nexport type DetectionConfig = z.infer<typeof DetectionConfigSchema>;\n","/**\n * Sync subsystem — DI tokens\n *\n * String constants (not Symbols) so they match by value across import\n * boundaries — same convention as the events subsystem (`EVENT_BUS`). The\n * jobs subsystem uses Symbols for its analogous tokens; events and sync\n * stay internally consistent with strings.\n *\n * Usage in use cases:\n * ```ts\n * constructor(\n * @Inject(SYNC_CHANGE_SOURCE) private readonly source: IChangeSource<CanonicalOpportunity>,\n * @Inject(SYNC_CURSOR_STORE) private readonly cursors: ICursorStore,\n * @Inject(SYNC_FIELD_DIFFER) private readonly differ: IFieldDiffer<CanonicalOpportunity>,\n * @Inject(SYNC_SINK) private readonly sink: ISyncSink<CanonicalOpportunity>,\n * @Inject(SYNC_RUN_RECORDER) private readonly recorder: ISyncRunRecorder,\n * ) {}\n * ```\n *\n * Concrete bindings are registered by `SyncModule.forRoot(...)` (SYNC-6).\n */\n\nexport const SYNC_CHANGE_SOURCE = 'SYNC_CHANGE_SOURCE' as const;\nexport const SYNC_CURSOR_STORE = 'SYNC_CURSOR_STORE' as const;\nexport const SYNC_FIELD_DIFFER = 'SYNC_FIELD_DIFFER' as const;\nexport const SYNC_SINK = 'SYNC_SINK' as const;\n\n/**\n * Run-recorder token (SYNC-5). Backed by `ISyncRunRecorder`. Drizzle impl\n * lands in SYNC-4; tests provide inline fakes.\n */\nexport const SYNC_RUN_RECORDER = 'SYNC_RUN_RECORDER' as const;\n\n/**\n * Injection token for the resolved `SyncModuleOptions` object (SYNC-6).\n *\n * Backends that need to observe module configuration (e.g. `multiTenant`\n * flag, pool filters) inject via this token. Provided automatically by\n * `SyncModule.forRoot(...)` / `SyncModule.forRootAsync(...)`.\n */\nexport const SYNC_MODULE_OPTIONS = 'SYNC_MODULE_OPTIONS' as const;\n\n/**\n * Injection token for the resolved multi-tenancy flag (SYNC-6).\n *\n * Provided by `SyncModule.forRoot(...)` as `options.multiTenant ?? false`.\n * Consumed by `ExecuteSyncUseCase` to enforce the tenantId-is-required rule.\n */\nexport const SYNC_MULTI_TENANT = 'SYNC_MULTI_TENANT' as const;\n","/**\n * Typed errors + shared boundary helpers for the sync subsystem.\n *\n * Classes (not bare Error) so consumers can `instanceof` them in catch\n * blocks and exception filters can map them to HTTP codes.\n *\n * Mirrors the shape of `events-errors.ts` and `jobs-errors.ts`.\n */\n\n/**\n * Thrown by the Drizzle cursor-store / run-recorder backends AND by the\n * orchestrator entry point when `SYNC_MULTI_TENANT` is enabled but the\n * caller did not supply a non-null `tenantId`. Strict enforcement at the\n * boundary — explicit `null` still throws.\n *\n * Disable multi-tenancy on the module (`multiTenant: false`, the default)\n * to opt out of the requirement entirely.\n *\n * `operation` identifies the call site (e.g. `'cursor.put'`,\n * `'startRun'`, `'execute'`) so the stack-trace message points at the\n * specific boundary that rejected the input.\n */\nexport class MissingTenantIdError extends Error {\n override readonly name = 'MissingTenantIdError';\n constructor(operation: string) {\n super(\n `Missing tenantId for sync operation '${operation}'. SyncModule is ` +\n `configured with multiTenant: true — every call must include a ` +\n `non-null tenantId. Either pass the tenantId or disable multi-` +\n `tenancy on the module.`,\n );\n }\n}\n\n/**\n * Shared boundary guard — used at the orchestrator entry AND inside the\n * Drizzle backends. Keeping the check in one function guarantees every\n * `MissingTenantIdError` carries the same message shape regardless of the\n * site that raised it, which makes it easier for consumers to pattern-\n * match on the error in logs/metrics.\n *\n * When `multiTenant` is false, the function is a no-op — `tenantId` may\n * be anything (including `undefined`). When true, `undefined` or `null`\n * throws.\n */\nexport function assertTenantId(\n tenantId: string | null | undefined,\n options: { multiTenant: boolean; operation: string },\n): asserts tenantId is string {\n if (!options.multiTenant) return;\n if (tenantId === undefined || tenantId === null) {\n throw new MissingTenantIdError(options.operation);\n }\n}\n","/**\n * Drizzle schema for the sync subsystem audit/observability tables (SYNC-1).\n *\n * Three tables model end-to-end sync observability, keyed by the single port\n * every sync adapter implements (`IChangeSource<T>` from SYNC-2):\n *\n * - `sync_subscriptions` — owns the cursor per\n * `(integration_id, adapter, domain, external_ref)` tuple. Addressed\n * by id by `ICursorStore` (SYNC-3/SYNC-4).\n * - `sync_runs` — per-run audit log: start/complete, status,\n * cursor before/after, counts, direction (inbound|outbound),\n * action (poll|cdc|webhook|manual|writeback).\n * - `sync_run_items` — per-record change log with structured\n * `changed_fields` jsonb enforced by the Zod `FieldDiffSchema`\n * contract (ADR-0003; protocol lives in SYNC-2's\n * sync-field-diff.protocol.ts).\n *\n * Design calls (vs. issue #126 open questions):\n *\n * - `sync_subscriptions` ships in the subsystem (not consumer-owned).\n * Rationale: SYNC-4's `PostgresCursorStore` needs to read/write this\n * table directly; making it consumer-owned would require consumers to\n * hand-wire a shape the backend already knows. The row is addressable\n * by id and scoped by the uniqueness tuple; consumers can still\n * query/list it freely. Same stance as `job_run` being subsystem-\n * owned while remaining consumer-queryable.\n *\n * - `tenant_id` is always emitted on the three tables as nullable text.\n * The `SYNC_MULTI_TENANT` DI flag (SYNC-6) is what enforces the\n * non-null + cross-tenant-isolation contract at the service/orchestrator\n * boundary. This mirrors JOB-1/JOB-8's final shape — runtime guard, not\n * a scaffold-time conditional column. Keeps the schema file uniform\n * across single-tenant and multi-tenant deployments.\n *\n * - `changed_fields` on `sync_run_items` is typed via the Zod-inferred\n * `FieldDiff` shape from SYNC-2 (`{ [fieldName]: { from, to } }`). The\n * recorder service (SYNC-5) validates every write against\n * `FieldDiffSchema.parse` so consumers can rely on the shape.\n */\nimport {\n pgEnum,\n pgTable,\n uuid,\n text,\n jsonb,\n integer,\n boolean,\n timestamp,\n index,\n uniqueIndex,\n} from 'drizzle-orm/pg-core';\nimport type { InferSelectModel } from 'drizzle-orm';\n\nimport type { FieldDiff } from './sync-field-diff.protocol';\n\n// ─── Enums ──────────────────────────────────────────────────────────────────\n\n/**\n * Direction of a sync run relative to local state.\n *\n * - `inbound` — external → local (the common case: SFDC poll → local DB).\n * - `outbound` — local → external (writeback; deferred per epic but the\n * column shape is reserved so future writeback runs share the audit log).\n */\nexport const syncRunDirectionEnum = pgEnum('sync_run_direction', [\n 'inbound',\n 'outbound',\n]);\n\n/**\n * How the run detected upstream changes. Maps 1:1 to the `Change.source`\n * provenance on inbound runs; `manual` captures operator-triggered re-syncs\n * and `writeback` captures outbound runs.\n */\nexport const syncRunActionEnum = pgEnum('sync_run_action', [\n 'poll',\n 'cdc',\n 'webhook',\n 'manual',\n 'writeback',\n]);\n\n/**\n * Lifecycle status of a sync run.\n *\n * - `running` — in-flight; recorder has started but not completed.\n * - `success` — completed with at least one change processed.\n * - `no_changes` — completed cleanly, no upstream changes found.\n * - `failed` — errored before completion; `error` column carries the\n * message. `records_processed` may be non-zero (partial progress).\n */\nexport const syncRunStatusEnum = pgEnum('sync_run_status', [\n 'running',\n 'success',\n 'no_changes',\n 'failed',\n]);\n\n/**\n * Operation applied per record. Mirrors `Change<T>.operation` from SYNC-2,\n * plus the recorder's own `'noop'` for changes that matched existing state.\n */\nexport const syncRunItemOperationEnum = pgEnum('sync_run_item_operation', [\n 'created',\n 'updated',\n 'deleted',\n 'noop',\n]);\n\n/**\n * Per-record status within a run. `skipped` captures loopback-detected echoes\n * of the local system's own writes (see `ILoopbackFingerprintStore` in the\n * epic), which record the external_id but intentionally do not touch local\n * state.\n */\nexport const syncRunItemStatusEnum = pgEnum('sync_run_item_status', [\n 'success',\n 'failed',\n 'skipped',\n]);\n\n// ─── sync_subscriptions ─────────────────────────────────────────────────────\n\n/**\n * One cursor owner per (integration, adapter, domain, external_ref).\n *\n * - `integration_id` — opaque id of the connected account/instance. E.g.\n * the SFDC org id for polling strategies, the GitHub installation id\n * for webhook strategies.\n * - `adapter` — short adapter label, e.g. `'salesforce'`, `'hubspot'`.\n * - `domain` — canonical entity domain this subscription tracks,\n * e.g. `'opportunity'`, `'contact'`.\n * - `external_ref` — optional upstream scope (e.g. a filter id, a\n * webhook subscription id). NULL when the subscription covers the\n * entire domain.\n *\n * The cursor shape is opaque jsonb — strategies type it internally (poll:\n * `{ systemModstamp }`, cdc: `{ replayId }`, webhook: `{ ts }`). Overwritten\n * by `ICursorStore.put(id, cursor)`.\n */\nexport const syncSubscriptions = pgTable(\n 'sync_subscriptions',\n {\n id: uuid('id').primaryKey().defaultRandom(),\n integrationId: text('integration_id').notNull(),\n adapter: text('adapter').notNull(),\n domain: text('domain').notNull(),\n externalRef: text('external_ref'),\n enabled: boolean('enabled').notNull().default(true),\n /**\n * Per-subscription configuration bag. Strategies type it internally;\n * e.g. polling strategies stash `{ batchSize, highWatermark }` here.\n */\n config: jsonb('config').notNull().default({}).$type<Record<string, unknown>>(),\n /**\n * Opaque cursor persisted by `ICursorStore.put()`. NULL until the first\n * successful run advances it.\n */\n cursor: jsonb('cursor').$type<unknown>(),\n lastSyncAt: timestamp('last_sync_at', { withTimezone: true }),\n /** Runtime-enforced when `SYNC_MULTI_TENANT` is true; see SYNC-6. */\n tenantId: text('tenant_id'),\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),\n },\n (t) => ({\n /**\n * Composite uniqueness per the epic shape. `external_ref` is nullable;\n * Postgres treats NULLs as distinct in a UNIQUE constraint, which means\n * two rows with the same `(integration_id, adapter, domain)` and NULL\n * external_ref are allowed. That's intentional — a subscription with\n * NULL external_ref covers the full domain, and duplicates there would\n * be a consumer-layer modeling issue, not a schema concern.\n */\n uqSyncSubscriptionTuple: uniqueIndex('uq_sync_subscriptions_tuple').on(\n t.integrationId,\n t.adapter,\n t.domain,\n t.externalRef,\n ),\n /** Scheduling query: list enabled subscriptions ordered by staleness. */\n idxSyncSubscriptionsEnabledLastSync: index(\n 'idx_sync_subscriptions_enabled_last_sync',\n ).on(t.enabled, t.lastSyncAt),\n }),\n);\n\nexport type SyncSubscriptionRow = InferSelectModel<typeof syncSubscriptions>;\n\n// ─── sync_runs ──────────────────────────────────────────────────────────────\n\n/**\n * One row per invocation of `ExecuteSyncUseCase`. `started_at` is set when\n * the recorder opens the run; `completed_at`, `status`, `records_*`,\n * `cursor_after`, and `duration_ms` are filled on completion.\n *\n * `cursor_before` / `cursor_after` carry the opaque cursor snapshots so the\n * run log is fully self-describing — given a run id, an operator can reason\n * about exactly what window was scanned without cross-referencing another\n * table.\n */\nexport const syncRuns = pgTable(\n 'sync_runs',\n {\n id: uuid('id').primaryKey().defaultRandom(),\n subscriptionId: uuid('subscription_id')\n .notNull()\n .references(() => syncSubscriptions.id, { onDelete: 'cascade' }),\n direction: syncRunDirectionEnum('direction').notNull(),\n action: syncRunActionEnum('action').notNull(),\n status: syncRunStatusEnum('status').notNull().default('running'),\n recordsFound: integer('records_found').notNull().default(0),\n recordsProcessed: integer('records_processed').notNull().default(0),\n cursorBefore: jsonb('cursor_before').$type<unknown>(),\n cursorAfter: jsonb('cursor_after').$type<unknown>(),\n durationMs: integer('duration_ms'),\n error: text('error'),\n startedAt: timestamp('started_at', { withTimezone: true })\n .notNull()\n .defaultNow(),\n completedAt: timestamp('completed_at', { withTimezone: true }),\n /** Runtime-enforced when `SYNC_MULTI_TENANT` is true; see SYNC-6. */\n tenantId: text('tenant_id'),\n },\n (t) => ({\n /** Timeline read: \"most recent runs for this subscription\". */\n idxSyncRunsSubscriptionStartedAt: index(\n 'idx_sync_runs_subscription_started_at',\n ).on(t.subscriptionId, t.startedAt),\n /** Stale-run sweeper: \"runs that started > N minutes ago and are still running\". */\n idxSyncRunsStatusStartedAt: index('idx_sync_runs_status_started_at').on(\n t.status,\n t.startedAt,\n ),\n }),\n);\n\nexport type SyncRunRow = InferSelectModel<typeof syncRuns>;\n\n// ─── sync_run_items ─────────────────────────────────────────────────────────\n\n/**\n * One row per upstream change processed within a run. Captures the canonical\n * decision the orchestrator made (`operation` + `status`), the structured\n * per-field diff (`changed_fields`, ADR-0003), and the local row id\n * (`local_id`) for drill-down joins.\n *\n * `changed_fields` is validated at the recorder layer via `FieldDiffSchema`\n * (SYNC-2) — the $type<FieldDiff> annotation here only documents the shape\n * for Drizzle consumers. The runtime enforcement is non-negotiable: downstream\n * drift-detection queries rely on the `{from, to}` shape per field.\n *\n * `title` is an optional human-readable label captured at write time (e.g.\n * `\"Pinnacle opportunity\"`) so run-log UIs don't need to re-hydrate the\n * canonical record.\n */\nexport const syncRunItems = pgTable(\n 'sync_run_items',\n {\n id: uuid('id').primaryKey().defaultRandom(),\n syncRunId: uuid('sync_run_id')\n .notNull()\n .references(() => syncRuns.id, { onDelete: 'cascade' }),\n entityType: text('entity_type').notNull(),\n externalId: text('external_id').notNull(),\n localId: text('local_id'),\n operation: syncRunItemOperationEnum('operation').notNull(),\n status: syncRunItemStatusEnum('status').notNull(),\n /**\n * Structured per-field diff — ADR-0003 shape enforced by\n * `FieldDiffSchema.parse` at the recorder service layer.\n *\n * Shape: `{ [fieldName]: { from: unknown, to: unknown } }`.\n * Empty `{}` for `noop` items; `{ [field]: { from: null, to: <value> } }`\n * for created items; `{ [field]: { from: <value>, to: null } }` for\n * deleted items.\n */\n changedFields: jsonb('changed_fields').notNull().default({}).$type<FieldDiff>(),\n title: text('title'),\n error: text('error'),\n createdAt: timestamp('created_at', { withTimezone: true })\n .notNull()\n .defaultNow(),\n /** Runtime-enforced when `SYNC_MULTI_TENANT` is true; see SYNC-6. */\n tenantId: text('tenant_id'),\n },\n (t) => ({\n /** Ordered timeline within a run. */\n idxSyncRunItemsRunCreatedAt: index('idx_sync_run_items_run_created_at').on(\n t.syncRunId,\n t.createdAt,\n ),\n /** Per-record history: \"every sync that touched opportunity/$extId\". */\n idxSyncRunItemsEntityExternal: index(\n 'idx_sync_run_items_entity_external',\n ).on(t.entityType, t.externalId),\n }),\n);\n\nexport type SyncRunItemRow = InferSelectModel<typeof syncRunItems>;\n","/**\n * MemoryCursorStore — in-memory backend for `ICursorStore` (SYNC-3).\n *\n * Test double that lets consumers exercise `ExecuteSyncUseCase` (SYNC-5) and\n * other cursor-consuming code paths without Postgres. Mirrors the role of\n * `MemoryEventBus` and `MemoryJobStore`: plain keyed state, tests take a\n * direct reference for `beforeEach` resets.\n *\n * Cursor values are stored by reference — the port's `get`/`put` contract\n * treats them as opaque `unknown`. Callers that want durable value-equality\n * semantics should snapshot via JSON before `put` and reparse after `get`;\n * this is what the Drizzle backend (SYNC-4) does implicitly via jsonb\n * round-trip. The memory backend intentionally does not simulate the\n * serialize/deserialize cycle — consumers who care should test against\n * Postgres.\n *\n * ## Multi-tenancy\n *\n * `tenantId` is accepted but ignored. The memory backend's state is\n * process-local — there's no durable storage where a cross-tenant leak\n * could occur. Tests that want to assert per-tenant isolation should\n * target the Drizzle backend.\n *\n * Not shipped in dealbrain-v2; this is a subsystem-first addition for the\n * test surface. Consumed by:\n * - SYNC-5 unit tests (`ExecuteSyncUseCase` against synthetic sources)\n * - SYNC-6 module tests (`SyncModule.forRoot({ backend: 'memory' })`)\n */\nimport { Injectable } from '@nestjs/common';\nimport type {\n CursorSnapshot,\n ICursorStore,\n} from './sync-cursor-store.protocol';\nimport type { MemorySyncSubscription } from './sync-run-recorder.memory-backend';\n\n@Injectable()\nexport class MemoryCursorStore implements ICursorStore {\n /**\n * Subscription-id → last persisted cursor. Public so tests can inspect\n * or pre-seed state; production callers MUST go through `get`/`put`.\n */\n readonly cursors: Map<string, unknown> = new Map();\n\n /**\n * Seedable subscription metadata for `listAll` — the memory backend\n * stores only `subscriptionId → cursor` in its write path, so the\n * snapshot shape (`integrationId`, `adapter`, `domain`, `externalRef`,\n * timestamps) has no natural source without test seeding. Tests populate\n * this map; unseeded entries get empty-string metadata and `new Date(0)`\n * timestamps so the shape stays stable. Production paths go through the\n * Drizzle backend.\n */\n readonly subscriptions: Map<string, MemorySyncSubscription> = new Map();\n\n async get(\n subscriptionId: string,\n _tenantId?: string | null,\n ): Promise<unknown | null> {\n // `Map.get` returns `undefined` for missing keys; the port contract\n // returns `null`. Normalize here so callers can `=== null`-check.\n const value = this.cursors.get(subscriptionId);\n return value === undefined ? null : value;\n }\n\n async put(\n subscriptionId: string,\n cursor: unknown,\n _tenantId?: string | null,\n ): Promise<void> {\n // Overwrite semantics — matches the port contract and the Drizzle\n // backend's `ON CONFLICT DO UPDATE` behavior.\n this.cursors.set(subscriptionId, cursor);\n }\n\n async listAll(_tenantId?: string | null): Promise<CursorSnapshot[]> {\n // Accepts tenantId for contract symmetry but does not filter on it —\n // the memory backend never enforces tenancy (see class-level comment).\n const snapshots: CursorSnapshot[] = [];\n for (const [subscriptionId, cursor] of this.cursors.entries()) {\n const meta = this.subscriptions.get(subscriptionId);\n snapshots.push({\n subscriptionId,\n integrationId: meta?.integrationId ?? '',\n adapter: meta?.adapter ?? '',\n domain: meta?.domain ?? '',\n externalRef: meta?.externalRef ?? null,\n cursor: cursor ?? null,\n lastSyncAt: meta?.lastSyncAt ?? null,\n updatedAt: meta?.updatedAt ?? new Date(0),\n tenantId: null,\n });\n }\n return snapshots.sort(\n (a, b) => b.updatedAt.getTime() - a.updatedAt.getTime(),\n );\n }\n\n /** Reset state. Tests call this in `beforeEach`. */\n clear(): void {\n this.cursors.clear();\n this.subscriptions.clear();\n }\n}\n","/**\n * MemoryRunRecorder — in-memory backend for `ISyncRunRecorder` (SYNC-6).\n *\n * Test double so `SyncModule.forRoot({ backend: 'memory' })` is genuinely\n * end-to-end runnable without Postgres. Mirrors the role of\n * `MemoryCursorStore`: plain keyed state, `clear()` helper for\n * `beforeEach` resets, public inspection surface so tests can assert on\n * the recorded run + item timeline without scraping logs.\n *\n * Validates `changedFields` through `FieldDiffSchema.parse` on every\n * `recordItem` call — same ADR-0003 contract as the Drizzle backend. An\n * in-memory recorder that skipped the validation would be a silently\n * weaker contract than production.\n *\n * `startRun` generates a uuid via `crypto.randomUUID()` (Node 19+ / Bun).\n * We don't import `uuid` because the subsystem has no other use for it.\n *\n * ## Multi-tenancy\n *\n * `tenantId` is accepted (and recorded on the in-memory row so tests can\n * assert it) but enforcement lives at the module boundary. The memory\n * backend intentionally does not throw on missing `tenantId` — that's\n * the orchestrator's job when `multiTenant=true` (SYNC-6). A permissive\n * memory recorder lets tests exercise error paths where the orchestrator\n * short-circuits before ever reaching the recorder.\n */\nimport { Injectable } from '@nestjs/common';\nimport type {\n CompleteRunInput,\n ISyncRunRecorder,\n RecordItemInput,\n StartRunInput,\n SyncRunSummary,\n} from './sync-run-recorder.protocol';\nimport { FieldDiffSchema } from './sync-field-diff.protocol';\n\n/**\n * Optional per-subscription metadata a test can seed on the memory backend\n * so `listRecent` can surface `integrationId`. The memory recorder's write\n * path never persists subscription rows (it only stores runs + items), so\n * `listRecent` has no way to derive `integrationId` on its own. Tests that\n * care about the field should populate `subscriptions` before calling\n * `listRecent`; calls that don't seed get an empty string and a stable\n * shape (see `listRecent` below).\n */\nexport interface MemorySyncSubscription {\n integrationId: string;\n adapter: string;\n domain: string;\n externalRef: string | null;\n lastSyncAt?: Date | null;\n updatedAt: Date;\n}\n\n/**\n * Concrete run row as held in memory. Shape mirrors the interesting\n * columns on `sync_runs` so assertions read like DB queries.\n */\nexport interface MemoryRunRecord {\n id: string;\n subscriptionId: string;\n direction: 'inbound' | 'outbound';\n action: 'poll' | 'cdc' | 'webhook' | 'manual' | 'writeback';\n status: 'running' | 'success' | 'no_changes' | 'failed';\n cursorBefore: unknown | null;\n cursorAfter: unknown | null;\n recordsFound: number;\n recordsProcessed: number;\n durationMs: number | null;\n error: string | null;\n tenantId: string | null;\n startedAt: Date;\n completedAt: Date | null;\n}\n\n@Injectable()\nexport class MemoryRunRecorder implements ISyncRunRecorder {\n /**\n * All started runs keyed by id. Public so tests can inspect lifecycle\n * transitions without poking through recording methods.\n */\n readonly runs: Map<string, MemoryRunRecord> = new Map();\n\n /**\n * Items keyed by `sync_run_id`, array order matches insertion order —\n * mirrors the timeline the `(sync_run_id, created_at)` index produces\n * in Postgres.\n */\n readonly items: Map<string, RecordItemInput[]> = new Map();\n\n /**\n * Seedable subscription metadata — tests populate this to make\n * `listRecent` return meaningful `integrationId` values. The memory\n * backend doesn't track subscriptions on its own (only runs + items), so\n * this map is the intentional extension point: tests write entries for\n * the subscription ids they use, production code never touches it.\n */\n readonly subscriptions: Map<string, MemorySyncSubscription> = new Map();\n\n async startRun(input: StartRunInput): Promise<{ id: string }> {\n const id = crypto.randomUUID();\n this.runs.set(id, {\n id,\n subscriptionId: input.subscriptionId,\n direction: input.direction,\n action: input.action,\n status: 'running',\n cursorBefore: input.cursorBefore ?? null,\n cursorAfter: null,\n recordsFound: 0,\n recordsProcessed: 0,\n durationMs: null,\n error: null,\n tenantId: input.tenantId ?? null,\n startedAt: new Date(),\n completedAt: null,\n });\n this.items.set(id, []);\n return { id };\n }\n\n async recordItem(input: RecordItemInput): Promise<void> {\n // Same ADR-0003 contract as the Drizzle backend.\n FieldDiffSchema.parse(input.changedFields);\n\n const bucket = this.items.get(input.syncRunId);\n if (!bucket) {\n throw new Error(\n `MemoryRunRecorder.recordItem: no run started for id '${input.syncRunId}'. ` +\n `Call startRun(...) first.`,\n );\n }\n bucket.push(input);\n }\n\n async completeRun(runId: string, input: CompleteRunInput): Promise<void> {\n const run = this.runs.get(runId);\n if (!run) {\n throw new Error(\n `MemoryRunRecorder.completeRun: no run started for id '${runId}'.`,\n );\n }\n run.status = input.status;\n run.recordsFound = input.recordsFound;\n run.recordsProcessed = input.recordsProcessed;\n run.cursorAfter = input.cursorAfter ?? null;\n run.durationMs = input.durationMs;\n run.error = input.error ?? null;\n run.completedAt = new Date();\n }\n\n async listRecent(\n limit: number,\n subscriptionId?: string,\n _tenantId?: string | null,\n ): Promise<SyncRunSummary[]> {\n // Memory backend accepts tenantId for contract symmetry but does not\n // filter on it — state is process-local and cross-tenant isolation is\n // not meaningful here (matches MemoryCursorStore behavior).\n const all = Array.from(this.runs.values());\n const filtered =\n subscriptionId === undefined\n ? all\n : all.filter((r) => r.subscriptionId === subscriptionId);\n return filtered\n .sort((a, b) => b.startedAt.getTime() - a.startedAt.getTime())\n .slice(0, limit)\n .map((r) => ({\n id: r.id,\n subscriptionId: r.subscriptionId,\n // integrationId is only knowable if the test seeded subscriptions\n // metadata; empty string otherwise. The Drizzle backend resolves\n // it via JOIN, which is the production path.\n integrationId:\n this.subscriptions.get(r.subscriptionId)?.integrationId ?? '',\n status: r.status,\n startedAt: r.startedAt,\n completedAt: r.completedAt,\n recordsProcessed: r.recordsProcessed,\n tenantId: r.tenantId,\n }));\n }\n\n /** Reset state. Tests call this in `beforeEach`. */\n clear(): void {\n this.runs.clear();\n this.items.clear();\n this.subscriptions.clear();\n }\n\n // ─── test ergonomics ─────────────────────────────────────────────────\n\n /** All runs for a subscription, newest first. Timeline reads. */\n getRunsForSubscription(subscriptionId: string): MemoryRunRecord[] {\n return Array.from(this.runs.values())\n .filter((r) => r.subscriptionId === subscriptionId)\n .sort((a, b) => b.startedAt.getTime() - a.startedAt.getTime());\n }\n\n /** All item rows for a run, insertion-ordered. */\n getItemsForRun(runId: string): RecordItemInput[] {\n return this.items.get(runId) ?? [];\n }\n}\n","/**\n * DeepEqualDiffer — default `IFieldDiffer<T>` for the sync subsystem (SYNC-5).\n *\n * Walks every field of `incoming` against `existing`, emitting a structured\n * per-field diff (`{ from, to }`) for every field whose value changed.\n * Returns `'noop'` when the record is unchanged.\n *\n * Design decisions (extracted from dealbrain-v2 + HS-9 findings):\n *\n * 1. **Ignore list** — row metadata that sinks/services stamp unconditionally\n * so upstream cannot reasonably disagree:\n * `id`, `createdAt`, `updatedAt`, `deletedAt`, `type`,\n * `lastModifiedAt`, `fields`, `providerMetadata`\n * (`fields` is the EAV bag — it's diffed by the sink's EAV dual-write\n * path, not at the canonical-record layer.)\n *\n * 2. **`providerChangedFields` hint (CDC)** — when present, restricts the\n * comparison to the hinted field set. The hint is advisory; fields in\n * the ignore list are still filtered out even when hinted. Provider\n * hints are field-NAME-level; they don't override the ignore rules.\n *\n * 3. **Date → ISO string** — `Date` instances are normalized to\n * `toISOString()` before comparison. Sinks return `Date` from the DB\n * driver; adapters typically deliver strings. Direct `===` would\n * always say \"changed.\"\n *\n * 4. **Decimal-string vs number** — Postgres `numeric` columns return as\n * strings through Drizzle; adapters deliver numbers. When one side is a\n * number and the other is a numeric string that parses to the same\n * number, they're equal. The normalizer does NOT coerce non-numeric\n * strings, and it preserves zero-vs-null distinction.\n *\n * 5. **null-existing path** — `diff(null, incoming)` produces a full\n * created-shape diff (`{from: null, to: <value>}` for every non-ignored\n * field). Orchestrator sees this and records `operation: 'created'`.\n */\nimport { Injectable } from '@nestjs/common';\nimport type {\n DiffResult,\n FieldDiff,\n IFieldDiffer,\n} from './sync-field-diff.protocol';\n\n/**\n * Default ignore list. Keep in sync with consumer canonical-record shapes —\n * adding a row-metadata field here means no sync will ever mark it changed.\n */\nconst DEFAULT_IGNORE_FIELDS: ReadonlySet<string> = new Set([\n 'id',\n 'createdAt',\n 'updatedAt',\n 'deletedAt',\n 'type',\n 'lastModifiedAt',\n 'fields',\n 'providerMetadata',\n]);\n\nexport interface DeepEqualDifferOptions {\n /**\n * Extra field names to ignore in addition to the defaults. Consumers can\n * pass `['sync_version']` etc. to augment the base list; values here are\n * merged (not replaced) with `DEFAULT_IGNORE_FIELDS`.\n */\n readonly ignore?: readonly string[];\n}\n\n@Injectable()\nexport class DeepEqualDiffer<T extends Record<string, unknown>>\n implements IFieldDiffer<T>\n{\n private readonly ignore: ReadonlySet<string>;\n\n constructor(opts: DeepEqualDifferOptions = {}) {\n if (opts.ignore && opts.ignore.length > 0) {\n this.ignore = new Set([...DEFAULT_IGNORE_FIELDS, ...opts.ignore]);\n } else {\n this.ignore = DEFAULT_IGNORE_FIELDS;\n }\n }\n\n diff(\n existing: T | null,\n incoming: T,\n providerChangedFields?: string[],\n ): DiffResult {\n // Created-shape: every non-ignored field becomes `{from: null, to}`.\n if (existing === null) {\n const out: FieldDiff = {};\n for (const key of Object.keys(incoming)) {\n if (this.ignore.has(key)) continue;\n const value = (incoming as Record<string, unknown>)[key];\n // Skip fields that are themselves null/undefined — a created record\n // doesn't need to declare \"this field is null now\" for every\n // untouched column.\n if (value === null || value === undefined) continue;\n out[key] = { from: null, to: value };\n }\n return Object.keys(out).length === 0 ? 'noop' : out;\n }\n\n // Field set to compare. `providerChangedFields` narrows to a hint set;\n // ignored fields are filtered out regardless of hint.\n const candidates = new Set<string>();\n if (providerChangedFields && providerChangedFields.length > 0) {\n for (const key of providerChangedFields) {\n if (!this.ignore.has(key)) candidates.add(key);\n }\n } else {\n for (const key of Object.keys(incoming)) {\n if (!this.ignore.has(key)) candidates.add(key);\n }\n // Also include keys that exist on existing but not on incoming —\n // e.g. a field that was cleared. This would otherwise be missed when\n // incoming carries an undefined column we drop from the iteration.\n for (const key of Object.keys(existing)) {\n if (this.ignore.has(key)) continue;\n if (!(key in (incoming as Record<string, unknown>))) continue;\n candidates.add(key);\n }\n }\n\n const out: FieldDiff = {};\n for (const key of candidates) {\n const before = (existing as Record<string, unknown>)[key];\n const after = (incoming as Record<string, unknown>)[key];\n if (!isEqual(before, after)) {\n out[key] = { from: before ?? null, to: after ?? null };\n }\n }\n\n return Object.keys(out).length === 0 ? 'noop' : out;\n }\n}\n\n// ─── equality helpers ───────────────────────────────────────────────────────\n\n/**\n * Field-level equality with the canonical-sync normalizations:\n * - Date → toISOString (adapters deliver strings)\n * - numeric-string vs number → numeric equality when both parse\n * - deep equality for plain objects/arrays (single-level is enough for\n * canonical records; nested records travel as jsonb columns where the\n * sink already owns the comparison)\n */\nfunction isEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n\n const na = normalize(a);\n const nb = normalize(b);\n if (na === nb) return true;\n\n // After normalization: both may still be non-primitive objects.\n if (\n typeof na === 'object' &&\n typeof nb === 'object' &&\n na !== null &&\n nb !== null\n ) {\n return deepEqualObject(na as Record<string, unknown>, nb as Record<string, unknown>);\n }\n\n // Numeric string ↔ number: when one side is a number and the other is a\n // string that parses to the same finite number.\n const numericEqual = maybeNumericEqual(na, nb) || maybeNumericEqual(nb, na);\n return numericEqual;\n}\n\nfunction normalize(value: unknown): unknown {\n if (value instanceof Date) return value.toISOString();\n return value;\n}\n\nfunction maybeNumericEqual(a: unknown, b: unknown): boolean {\n // a is string-shape, b is number — parse a and compare. Only when the\n // string looks numeric AND the parse round-trips (no silent NaN pass-\n // through on non-numeric strings).\n if (typeof a !== 'string' || typeof b !== 'number') return false;\n if (a.trim() === '') return false;\n const parsed = Number(a);\n if (!Number.isFinite(parsed)) return false;\n return parsed === b;\n}\n\nfunction deepEqualObject(\n a: Record<string, unknown>,\n b: Record<string, unknown>,\n): boolean {\n if (Array.isArray(a) !== Array.isArray(b)) return false;\n const aKeys = Object.keys(a);\n const bKeys = Object.keys(b);\n if (aKeys.length !== bKeys.length) return false;\n for (const key of aKeys) {\n if (!(key in b)) return false;\n if (!isEqual(a[key], b[key])) return false;\n }\n return true;\n}\n","/**\n * ExecuteSyncUseCase — the generic sync orchestrator (SYNC-5).\n *\n * One class. Reused across every `(provider, detection-mode, canonical-entity)`\n * tuple. Parameterized over `T` so canonical records stay typed end-to-end.\n *\n * Flow per run:\n *\n * 1. `recorder.startRun(...)` — opens a `sync_runs` row in 'running'.\n * 2. for each change yielded by `source.listChanges(subscription, cursorBefore)`:\n * a. differ.diff(existing, incoming) → 'noop' short-circuits to\n * a noop audit row (no sink write).\n * b. sink.upsertByExternalId / softDeleteByExternalId → records\n * the local id on the audit row.\n * c. per-item try/catch — a failed item increments the failed\n * counter and records `status: 'failed'` with `error`, but\n * does NOT abort the run.\n * d. advance `latestCursor = change.cursor` as the iterator moves.\n * 3. `cursors.put(subscription.id, latestCursor)` when the loop completes\n * AND at least one cursor advance happened. On exceptions from the\n * source iterator (auth expiry, network error), we persist the\n * last-good cursor so the next run resumes from the last known\n * successful position.\n * 4. `finally { recorder.completeRun(...) }` — always terminates the run.\n *\n * Loopback suppression — when a consumer's writes echo back on the next\n * inbound poll/CDC/webhook — is composed into the source's middleware\n * chain via `createLoopbackMiddleware(store)` (#226-5 / ADR-033). The\n * orchestrator no longer special-cases echoes: middleware drops them\n * before they reach this loop. Consumers that don't have outbound\n * writeback paths simply omit the middleware.\n *\n * ## Generics\n *\n * - `T` = canonical record shape from the adapter side. Same `T` flows\n * through `IChangeSource<T>`, `IFieldDiffer<T>`, `ISyncSink<T>`.\n *\n * ## No CRM bleed\n *\n * Per the SYNC-5 issue's extraction notes (HS-9 finding), this orchestrator\n * is strictly provider-agnostic:\n * - `entityType` is `string` throughout; no `'opportunity' | 'account' | ...`\n * narrowing leaks into the use case\n * - dealbrain's `SyncRunRecorderService` class injection replaced with the\n * `ISyncRunRecorder` protocol (backend lands in SYNC-4)\n */\nimport { Inject, Injectable, Logger, Optional } from '@nestjs/common';\nimport type { IChangeSource, Change } from './sync-change-source.protocol';\nimport type { ICursorStore } from './sync-cursor-store.protocol';\nimport type { IFieldDiffer, FieldDiff } from './sync-field-diff.protocol';\nimport type { ISyncSink } from './sync-sink.protocol';\nimport type { ISyncRunRecorder } from './sync-run-recorder.protocol';\nimport { assertTenantId } from './sync-errors';\nimport {\n SYNC_CHANGE_SOURCE,\n SYNC_CURSOR_STORE,\n SYNC_FIELD_DIFFER,\n SYNC_MULTI_TENANT,\n SYNC_RUN_RECORDER,\n SYNC_SINK,\n} from './sync.tokens';\n\n// ============================================================================\n// Inputs + result\n// ============================================================================\n\nexport interface ExecuteSyncInput<T> {\n /** The subscription whose cursor/identity frames this run. */\n readonly subscription: {\n readonly id: string;\n readonly domain: string; // entityType — used on audit rows\n readonly externalRef?: string | null;\n };\n /** Per-run user context; threaded through sink writes. */\n readonly userId: string;\n /** Provider label persisted on saved rows, e.g. `'salesforce-crm'`. */\n readonly provider: string;\n /** Run direction — almost always `'inbound'`. Reserved for writeback. */\n readonly direction: 'inbound' | 'outbound';\n /** Detection mode — maps 1:1 to `sync_runs.action`. */\n readonly action: 'poll' | 'cdc' | 'webhook' | 'manual' | 'writeback';\n /** Multi-tenant deployments pass the tenant id through. */\n readonly tenantId?: string | null;\n /**\n * Optional override — inject a specific change source for this run when\n * the DI-bound source is not the one to use (e.g. manual backfill with\n * a custom cursor). Defaults to the DI-resolved `SYNC_CHANGE_SOURCE`.\n */\n readonly sourceOverride?: IChangeSource<T>;\n}\n\nexport interface ExecuteSyncResult {\n readonly runId: string;\n readonly status: 'success' | 'no_changes' | 'failed';\n readonly recordsFound: number;\n readonly recordsProcessed: number;\n readonly recordsFailed: number;\n readonly cursorBefore: unknown | null;\n readonly cursorAfter: unknown | null;\n readonly durationMs: number;\n readonly error?: string | null;\n}\n\n// ============================================================================\n// ExecuteSyncUseCase\n// ============================================================================\n\n@Injectable()\nexport class ExecuteSyncUseCase<T extends Record<string, unknown>> {\n private readonly logger = new Logger(ExecuteSyncUseCase.name);\n\n constructor(\n @Inject(SYNC_CHANGE_SOURCE) private readonly source: IChangeSource<T>,\n @Inject(SYNC_CURSOR_STORE) private readonly cursors: ICursorStore,\n @Inject(SYNC_FIELD_DIFFER) private readonly differ: IFieldDiffer<T>,\n @Inject(SYNC_SINK) private readonly sink: ISyncSink<T>,\n @Inject(SYNC_RUN_RECORDER) private readonly recorder: ISyncRunRecorder,\n @Optional()\n @Inject(SYNC_MULTI_TENANT)\n private readonly multiTenant: boolean = false,\n ) {}\n\n async execute(input: ExecuteSyncInput<T>): Promise<ExecuteSyncResult> {\n // Defense-in-depth tenancy guard — fire BEFORE startRun so a rejected\n // input never leaves a dangling `status=running` row. Backends also\n // enforce (SYNC-4), but failing fast at the orchestrator boundary is\n // cheaper for observability, metrics, and manual cleanup.\n assertTenantId(input.tenantId, {\n multiTenant: this.multiTenant,\n operation: 'execute',\n });\n\n const source = input.sourceOverride ?? this.source;\n const startedAt = Date.now();\n const cursorBefore = await this.cursors.get(input.subscription.id, input.tenantId);\n\n const { id: runId } = await this.recorder.startRun({\n subscriptionId: input.subscription.id,\n direction: input.direction,\n action: input.action,\n cursorBefore,\n tenantId: input.tenantId,\n });\n\n let recordsFound = 0;\n let recordsProcessed = 0;\n let recordsFailed = 0;\n let latestCursor: unknown | null = cursorBefore;\n let cursorAdvanced = false;\n let runError: string | null = null;\n let status: 'success' | 'no_changes' | 'failed' = 'no_changes';\n\n try {\n for await (const change of source.listChanges(input.subscription, cursorBefore)) {\n recordsFound++;\n latestCursor = change.cursor;\n cursorAdvanced = true;\n\n try {\n await this.processChange(runId, input, change);\n recordsProcessed++;\n } catch (err) {\n recordsFailed++;\n const message = err instanceof Error ? err.message : String(err);\n this.logger.warn(\n `sync item failed: subscription=${input.subscription.id} externalId=${change.externalId}: ${message}`,\n );\n await this.recorder.recordItem({\n syncRunId: runId,\n entityType: input.subscription.domain,\n externalId: change.externalId,\n operation: change.operation === 'deleted' ? 'deleted' : 'updated',\n status: 'failed',\n changedFields: {},\n error: message,\n tenantId: input.tenantId,\n });\n }\n }\n\n if (recordsFailed > 0 && recordsProcessed === 0 && recordsFound > 0) {\n // Every record we saw failed — call the run a failure, not a\n // success. Partial success (some processed, some failed) still\n // counts as 'success' so the cursor advances.\n status = 'failed';\n runError = `all ${recordsFailed} records failed`;\n } else if (recordsFound === 0) {\n status = 'no_changes';\n } else {\n status = 'success';\n }\n } catch (err) {\n // Source iterator itself threw — cursor DOES NOT advance past the\n // last-successful cursor. `latestCursor` still holds the last\n // `change.cursor` we observed, which is the furthest we know to\n // have delivered. Persist it (below) so next run resumes there.\n status = 'failed';\n runError = err instanceof Error ? err.message : String(err);\n this.logger.error(\n `sync source failed: subscription=${input.subscription.id}: ${runError}`,\n );\n }\n\n // Persist cursor advance only when something actually moved. Never\n // overwrite a valid cursor with `null` on a no-change run.\n if (cursorAdvanced && latestCursor !== null && latestCursor !== undefined) {\n try {\n await this.cursors.put(input.subscription.id, latestCursor, input.tenantId);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n this.logger.error(\n `cursor put failed: subscription=${input.subscription.id}: ${message}`,\n );\n if (status !== 'failed') {\n status = 'failed';\n runError = `cursor put failed: ${message}`;\n }\n }\n }\n\n const durationMs = Date.now() - startedAt;\n\n await this.recorder.completeRun(runId, {\n status,\n recordsFound,\n recordsProcessed,\n cursorAfter: cursorAdvanced ? latestCursor : cursorBefore,\n durationMs,\n error: runError,\n });\n\n return {\n runId,\n status,\n recordsFound,\n recordsProcessed,\n recordsFailed,\n cursorBefore,\n cursorAfter: cursorAdvanced ? latestCursor : cursorBefore,\n durationMs,\n error: runError,\n };\n }\n\n private async processChange(\n runId: string,\n input: ExecuteSyncInput<T>,\n change: Change<T>,\n ): Promise<void> {\n // Deletion branch — no diff, no upsert; soft-delete via sink.\n if (change.operation === 'deleted') {\n const result = await this.sink.softDeleteByExternalId(\n input.userId,\n change.externalId,\n );\n await this.recorder.recordItem({\n syncRunId: runId,\n entityType: input.subscription.domain,\n externalId: change.externalId,\n localId: result?.id ?? null,\n operation: result ? 'deleted' : 'noop',\n status: 'success',\n changedFields: {},\n tenantId: input.tenantId,\n });\n return;\n }\n\n // Create/update path — diff against local state, short-circuit on noop.\n const existing = await this.sink.findByExternalId(\n input.userId,\n change.externalId,\n );\n const diff = this.differ.diff(\n existing,\n change.record,\n change.providerChangedFields,\n );\n\n if (diff === 'noop') {\n await this.recorder.recordItem({\n syncRunId: runId,\n entityType: input.subscription.domain,\n externalId: change.externalId,\n localId: null,\n operation: 'noop',\n status: 'success',\n changedFields: {},\n tenantId: input.tenantId,\n });\n return;\n }\n\n const { id: localId } = await this.sink.upsertByExternalId(\n input.userId,\n change.record,\n input.provider,\n );\n\n await this.recorder.recordItem({\n syncRunId: runId,\n entityType: input.subscription.domain,\n externalId: change.externalId,\n localId,\n operation: existing === null ? 'created' : 'updated',\n status: 'success',\n changedFields: diff as FieldDiff,\n tenantId: input.tenantId,\n });\n }\n}\n","/**\n * PostgresCursorStore — Drizzle-backed `ICursorStore` (SYNC-4).\n *\n * Reads/writes `sync_subscriptions.cursor` directly — no service\n * composition. Consumers that want a service layer around subscriptions\n * wire it themselves; the port's contract is just cursor persistence.\n *\n * ## What `put` stamps\n *\n * `put` writes three columns in one statement: `cursor`, `last_sync_at`,\n * and `updated_at`. Rationale: SYNC-1's scheduling index\n * `(enabled, last_sync_at)` is useless if `last_sync_at` doesn't advance\n * with every cursor put. Every real consumer needs this stamped, so\n * bundling it here avoids every consumer wrapping the port in a service\n * layer just to stamp a timestamp.\n *\n * ## Multi-tenancy\n *\n * When `SYNC_MULTI_TENANT` is true (SYNC-6):\n * - every read/write is scoped by `AND tenant_id = $tenantId`\n * - a null/missing `tenantId` throws `MissingTenantIdError` via the\n * shared `assertTenantId` helper (one message shape across the\n * orchestrator + both backends, SYNC-6)\n * - explicit `null` also throws — matches JOB-8 / EVT-6 strict-enforcement\n *\n * When the flag is off, `tenantId` is ignored. Cross-tenant isolation is\n * the caller's problem in single-tenant deployments.\n */\nimport { Inject, Injectable, Optional } from '@nestjs/common';\nimport { and, desc, eq, type SQL } from 'drizzle-orm';\nimport type { DrizzleClient } from '../../types/drizzle';\nimport { DRIZZLE } from '../../constants/tokens';\nimport type {\n CursorSnapshot,\n ICursorStore,\n} from './sync-cursor-store.protocol';\nimport { syncSubscriptions } from './sync-audit.schema';\nimport { SYNC_MULTI_TENANT } from './sync.tokens';\nimport { assertTenantId } from './sync-errors';\n\n@Injectable()\nexport class PostgresCursorStore implements ICursorStore {\n private readonly multiTenant: boolean;\n\n constructor(\n @Inject(DRIZZLE) private readonly db: DrizzleClient,\n @Optional() @Inject(SYNC_MULTI_TENANT) multiTenant?: boolean,\n ) {\n this.multiTenant = multiTenant ?? false;\n }\n\n async get(\n subscriptionId: string,\n tenantId?: string | null,\n ): Promise<unknown | null> {\n const where = this.buildWhere(subscriptionId, tenantId, 'cursor.get');\n\n const rows = await this.db\n .select({ cursor: syncSubscriptions.cursor })\n .from(syncSubscriptions)\n .where(where)\n .limit(1);\n\n if (rows.length === 0) return null;\n return rows[0]?.cursor ?? null;\n }\n\n async put(\n subscriptionId: string,\n cursor: unknown,\n tenantId?: string | null,\n ): Promise<void> {\n const where = this.buildWhere(subscriptionId, tenantId, 'cursor.put');\n\n await this.db\n .update(syncSubscriptions)\n .set({\n cursor,\n lastSyncAt: new Date(),\n updatedAt: new Date(),\n })\n .where(where);\n }\n\n async listAll(tenantId?: string | null): Promise<CursorSnapshot[]> {\n assertTenantId(tenantId, {\n multiTenant: this.multiTenant,\n operation: 'cursor.listAll',\n });\n\n const where = this.multiTenant\n ? eq(syncSubscriptions.tenantId, tenantId as string)\n : undefined;\n\n const rows = await this.db\n .select({\n id: syncSubscriptions.id,\n integrationId: syncSubscriptions.integrationId,\n adapter: syncSubscriptions.adapter,\n domain: syncSubscriptions.domain,\n externalRef: syncSubscriptions.externalRef,\n cursor: syncSubscriptions.cursor,\n lastSyncAt: syncSubscriptions.lastSyncAt,\n updatedAt: syncSubscriptions.updatedAt,\n tenantId: syncSubscriptions.tenantId,\n })\n .from(syncSubscriptions)\n .where(where)\n .orderBy(desc(syncSubscriptions.updatedAt));\n\n return rows.map((row) => ({\n subscriptionId: row.id,\n integrationId: row.integrationId,\n adapter: row.adapter,\n domain: row.domain,\n externalRef: row.externalRef,\n cursor: row.cursor ?? null,\n lastSyncAt: row.lastSyncAt,\n updatedAt: row.updatedAt,\n tenantId: row.tenantId,\n }));\n }\n\n /**\n * Centralized WHERE clause — `get` and `put` share identical semantics.\n * Drift here would let a caller read under one tenancy rule and write\n * under another.\n */\n private buildWhere(\n subscriptionId: string,\n tenantId: string | null | undefined,\n operation: string,\n ): SQL | undefined {\n assertTenantId(tenantId, {\n multiTenant: this.multiTenant,\n operation,\n });\n if (this.multiTenant) {\n return and(\n eq(syncSubscriptions.id, subscriptionId),\n eq(syncSubscriptions.tenantId, tenantId as string),\n );\n }\n return eq(syncSubscriptions.id, subscriptionId);\n }\n}\n","/**\n * NestJS injection tokens\n *\n * Used with @Inject() decorator in concrete repository constructors.\n */\n\n/**\n * Injection token for the Drizzle ORM database client.\n *\n * Usage in concrete repositories:\n * ```typescript\n * constructor(@Inject(DRIZZLE) db: DrizzleClient) { super(db); }\n * ```\n */\nexport const DRIZZLE = 'DRIZZLE' as const;\n\n/**\n * Injection token for the event bus (IEventBus).\n *\n * Optional — only resolved when EventsModule.forRoot() is registered.\n * BaseService uses this with @Optional() to emit lifecycle events\n * without requiring the events subsystem to be installed.\n *\n * Usage in services/use cases:\n * ```typescript\n * @Optional() @Inject(EVENT_BUS) eventBus?: IEventBus\n * ```\n */\nexport const EVENT_BUS = 'EVENT_BUS' as const;\n","/**\n * DrizzleSyncRunRecorder — Drizzle-backed `ISyncRunRecorder` (SYNC-4).\n *\n * Generic write path only — extracted from dealbrain-v2's\n * `SyncRunRecorderService`, minus CRM-specific convenience methods. Those\n * stay consumer-owned; the subsystem ships the substrate.\n *\n * ## Responsibilities\n *\n * - `startRun` — INSERT sync_runs row in status='running', returns id.\n * - `recordItem` — validates `changedFields` via `FieldDiffSchema.parse`\n * BEFORE the INSERT; a malformed shape throws before\n * any DB call fires. Enforces the ADR-0003 contract at\n * the write boundary.\n * - `completeRun` — UPDATE sync_runs with terminal status, counts,\n * cursor_after, duration_ms, completed_at.\n *\n * ## Multi-tenancy\n *\n * When `SYNC_MULTI_TENANT` is true (SYNC-6):\n * - `startRun` and `recordItem` require non-null `tenantId` on input.\n * Enforcement goes through the shared `assertTenantId` helper so the\n * error message shape matches the orchestrator entry point + the\n * cursor-store backends.\n * - `completeRun` does NOT re-check tenancy — the run id was returned\n * by `startRun` which already enforced it, and run ids are uuids that\n * aren't guessable cross-tenant. Matches JOB-3's pattern of trusting\n * the run-id for downstream mutations.\n */\nimport { Inject, Injectable, Optional } from '@nestjs/common';\nimport { and, desc, eq, type SQL } from 'drizzle-orm';\nimport type { DrizzleClient } from '../../types/drizzle';\nimport { DRIZZLE } from '../../constants/tokens';\nimport type {\n CompleteRunInput,\n ISyncRunRecorder,\n RecordItemInput,\n StartRunInput,\n SyncRunSummary,\n} from './sync-run-recorder.protocol';\nimport { syncRuns, syncRunItems, syncSubscriptions } from './sync-audit.schema';\nimport { FieldDiffSchema } from './sync-field-diff.protocol';\nimport { SYNC_MULTI_TENANT } from './sync.tokens';\nimport { assertTenantId } from './sync-errors';\n\n@Injectable()\nexport class DrizzleSyncRunRecorder implements ISyncRunRecorder {\n private readonly multiTenant: boolean;\n\n constructor(\n @Inject(DRIZZLE) private readonly db: DrizzleClient,\n @Optional() @Inject(SYNC_MULTI_TENANT) multiTenant?: boolean,\n ) {\n this.multiTenant = multiTenant ?? false;\n }\n\n async startRun(input: StartRunInput): Promise<{ id: string }> {\n assertTenantId(input.tenantId, {\n multiTenant: this.multiTenant,\n operation: 'startRun',\n });\n\n const rows = await this.db\n .insert(syncRuns)\n .values({\n subscriptionId: input.subscriptionId,\n direction: input.direction,\n action: input.action,\n status: 'running',\n cursorBefore: input.cursorBefore ?? null,\n tenantId: input.tenantId ?? null,\n })\n .returning({ id: syncRuns.id });\n\n const id = rows[0]?.id;\n if (!id) {\n // Drizzle's insert().returning() contract: at least one row is\n // returned for every successful INSERT. A missing id would indicate\n // a driver misbehavior; throw loudly rather than return bogus data.\n throw new Error('DrizzleSyncRunRecorder: INSERT RETURNING produced no id');\n }\n return { id };\n }\n\n async recordItem(input: RecordItemInput): Promise<void> {\n assertTenantId(input.tenantId, {\n multiTenant: this.multiTenant,\n operation: 'recordItem',\n });\n\n // ADR-0003 contract enforcement — reject malformed changedFields\n // before the DB call fires. `parse` throws a ZodError; callers see\n // the validation failure, not a DB constraint error.\n FieldDiffSchema.parse(input.changedFields);\n\n await this.db.insert(syncRunItems).values({\n syncRunId: input.syncRunId,\n entityType: input.entityType,\n externalId: input.externalId,\n localId: input.localId ?? null,\n operation: input.operation,\n status: input.status,\n changedFields: input.changedFields,\n title: input.title ?? null,\n error: input.error ?? null,\n tenantId: input.tenantId ?? null,\n });\n }\n\n async listRecent(\n limit: number,\n subscriptionId?: string,\n tenantId?: string | null,\n ): Promise<SyncRunSummary[]> {\n assertTenantId(tenantId, {\n multiTenant: this.multiTenant,\n operation: 'listRecent',\n });\n\n // JOIN against sync_subscriptions to resolve `integration_id` per run.\n // `sync_runs.subscription_id` is a non-null FK so INNER JOIN is correct;\n // there should be no orphaned runs.\n const conditions: SQL[] = [];\n if (subscriptionId !== undefined) {\n conditions.push(eq(syncRuns.subscriptionId, subscriptionId));\n }\n if (this.multiTenant) {\n conditions.push(eq(syncRuns.tenantId, tenantId as string));\n }\n const where =\n conditions.length === 0\n ? undefined\n : conditions.length === 1\n ? conditions[0]\n : and(...conditions);\n\n const rows = await this.db\n .select({\n id: syncRuns.id,\n subscriptionId: syncRuns.subscriptionId,\n integrationId: syncSubscriptions.integrationId,\n status: syncRuns.status,\n startedAt: syncRuns.startedAt,\n completedAt: syncRuns.completedAt,\n recordsProcessed: syncRuns.recordsProcessed,\n tenantId: syncRuns.tenantId,\n })\n .from(syncRuns)\n .innerJoin(\n syncSubscriptions,\n eq(syncRuns.subscriptionId, syncSubscriptions.id),\n )\n .where(where)\n .orderBy(desc(syncRuns.startedAt))\n .limit(limit);\n\n return rows.map((row) => ({\n id: row.id,\n subscriptionId: row.subscriptionId,\n integrationId: row.integrationId,\n status: row.status,\n startedAt: row.startedAt,\n completedAt: row.completedAt,\n recordsProcessed: row.recordsProcessed,\n tenantId: row.tenantId,\n }));\n }\n\n async completeRun(runId: string, input: CompleteRunInput): Promise<void> {\n await this.db\n .update(syncRuns)\n .set({\n status: input.status,\n recordsFound: input.recordsFound,\n recordsProcessed: input.recordsProcessed,\n cursorAfter: input.cursorAfter ?? null,\n durationMs: input.durationMs,\n error: input.error ?? null,\n completedAt: new Date(),\n })\n .where(eq(syncRuns.id, runId));\n }\n}\n","/**\n * SyncModule — `DynamicModule.forRoot({ backend, multiTenant? })` factory\n * wiring the sync subsystem's substrate (SYNC-6, ADR-008 subsystem pattern).\n *\n * ## What this module provides\n *\n * - `SYNC_CURSOR_STORE` — Drizzle or Memory cursor store\n * - `SYNC_RUN_RECORDER` — Drizzle or Memory run recorder\n * - `SYNC_FIELD_DIFFER` — default `DeepEqualDiffer`\n * - `SYNC_MULTI_TENANT` — resolved boolean flag (defaults to false)\n * - `SYNC_MODULE_OPTIONS` — the options object itself, for backends\n * that need to inspect config at construction time\n *\n * ## What this module does NOT provide\n *\n * - `SYNC_CHANGE_SOURCE` — per-provider per-entity; consumer binds in\n * their feature module (e.g. `OpportunitySyncModule` provides a\n * `SalesforceOpportunityChangeSource`). Loopback suppression — when\n * needed — is composed into the primitive's middleware chain via\n * `createLoopbackMiddleware(store)` (#226-5 / ADR-033); the\n * orchestrator no longer accepts a fingerprint store directly.\n * - `SYNC_SINK` — per canonical entity; consumer binds in their feature\n * module.\n * - `ExecuteSyncUseCase` — registered by the feature module alongside\n * its source + sink bindings. Providing the orchestrator here would\n * force Nest to resolve SYNC_CHANGE_SOURCE + SYNC_SINK at module\n * compile time, which fails when the feature module hasn't been\n * imported yet. Consumers register `ExecuteSyncUseCase` in the same\n * `providers` array as their source + sink so resolution is local\n * to where all three are bound.\n *\n * Same shape as `EventsModule.forRoot` — the module wires the bus; you\n * bring your own handlers. Here: the module wires the substrate; you\n * bring your own source + sink.\n *\n * ## Usage\n *\n * ```ts\n * // AppModule — single source of truth for backend + multi-tenancy.\n * @Module({\n * imports: [SyncModule.forRoot({ backend: 'drizzle' })],\n * })\n * export class AppModule {}\n *\n * // Per-entity feature module — binds source + sink, gets the\n * // orchestrator for free.\n * @Module({\n * providers: [\n * { provide: SYNC_CHANGE_SOURCE, useClass: SalesforceOpportunitySource },\n * { provide: SYNC_SINK, useClass: OpportunitySyncSink },\n * ExecuteSyncUseCase,\n * ],\n * })\n * export class OpportunitySyncModule {\n * constructor(\n * private readonly execute: ExecuteSyncUseCase<CanonicalOpportunity>,\n * ) {}\n * }\n * ```\n *\n * `global: true` means feature modules do not need to re-import\n * `SyncModule` — the substrate tokens are available project-wide.\n */\nimport { Module, type DynamicModule, type Provider } from '@nestjs/common';\nimport {\n SYNC_CURSOR_STORE,\n SYNC_FIELD_DIFFER,\n SYNC_MODULE_OPTIONS,\n SYNC_MULTI_TENANT,\n SYNC_RUN_RECORDER,\n} from './sync.tokens';\nimport { MemoryCursorStore } from './sync-cursor-store.memory-backend';\nimport { MemoryRunRecorder } from './sync-run-recorder.memory-backend';\nimport { PostgresCursorStore } from './sync-cursor-store.drizzle-backend';\nimport { DrizzleSyncRunRecorder } from './sync-run-recorder.drizzle-backend';\nimport { DeepEqualDiffer } from './deep-equal.differ';\n\nexport interface SyncModuleOptions {\n /**\n * Backend selection. `drizzle` wires the Postgres cursor store +\n * run-log recorder; `memory` wires in-memory doubles suitable for\n * tests + local dev.\n */\n backend: 'drizzle' | 'memory';\n\n /**\n * Multi-tenancy opt-in (SYNC-6).\n *\n * When `true`, every call to the orchestrator + both Drizzle backends\n * must supply a non-null `tenantId`; missing values throw\n * `MissingTenantIdError`. Defense-in-depth: the orchestrator rejects\n * at entry (no dangling `status=running` rows) AND the Drizzle\n * backends reject at their write boundary (belt-and-braces for any\n * path that bypasses the orchestrator). Both sites use the shared\n * `assertTenantId` helper so error messages match.\n *\n * Memory backends accept `tenantId` unconditionally — their state is\n * process-local; cross-tenant isolation there is not meaningful.\n *\n * Defaults to `false`.\n */\n multiTenant?: boolean;\n}\n\n@Module({})\nexport class SyncModule {\n static forRoot(options: SyncModuleOptions): DynamicModule {\n const multiTenant = options.multiTenant ?? false;\n\n const sharedProviders: Provider[] = [\n { provide: SYNC_MODULE_OPTIONS, useValue: options },\n { provide: SYNC_MULTI_TENANT, useValue: multiTenant },\n // Default differ — consumers can override by binding a different\n // `IFieldDiffer<T>` to `SYNC_FIELD_DIFFER` in their feature module.\n { provide: SYNC_FIELD_DIFFER, useValue: new DeepEqualDiffer() },\n ];\n\n const backendProviders: Provider[] =\n options.backend === 'memory'\n ? [\n // Wired as singletons via `useValue` so tests can pull\n // them out via `moduleRef.get(MemoryCursorStore)` for\n // direct assertions. Matches JOB-4 / MemoryJobStore shape.\n { provide: MemoryCursorStore, useValue: new MemoryCursorStore() },\n {\n provide: SYNC_CURSOR_STORE,\n useExisting: MemoryCursorStore,\n },\n { provide: MemoryRunRecorder, useValue: new MemoryRunRecorder() },\n {\n provide: SYNC_RUN_RECORDER,\n useExisting: MemoryRunRecorder,\n },\n ]\n : [\n // Drizzle backends — injected with DRIZZLE (provided by the\n // consumer's DrizzleModule) + the SYNC_MULTI_TENANT flag\n // we bound above.\n { provide: SYNC_CURSOR_STORE, useClass: PostgresCursorStore },\n { provide: SYNC_RUN_RECORDER, useClass: DrizzleSyncRunRecorder },\n ];\n\n return {\n module: SyncModule,\n global: true,\n providers: [...sharedProviders, ...backendProviders],\n exports: [\n SYNC_MODULE_OPTIONS,\n SYNC_MULTI_TENANT,\n SYNC_FIELD_DIFFER,\n SYNC_CURSOR_STORE,\n SYNC_RUN_RECORDER,\n ],\n };\n }\n}\n","import { z } from \"zod\";\n\n/**\n * Event Definition Schema\n *\n * Describes a single `events/*.yaml` file. This is the codegen-side contract\n * for first-class event declarations (ADR-024 Phase 1, EVT-2). One file per\n * event; filename matches `type` (snake_case). Consumed by EVT-3 to emit\n * `runtime/subsystems/events/generated/` artifacts.\n *\n * Payload field types intentionally narrower than entity field types:\n * events are a wire format, not a database schema. `decimal`, `entity_ref`,\n * `string_array`, `enum` make no sense in an event payload.\n */\n\n// ============================================================================\n// Enums and constants\n// ============================================================================\n\nexport const EVENT_DIRECTIONS = [\"inbound\", \"change\", \"outbound\"] as const;\nexport type EventDirection = (typeof EVENT_DIRECTIONS)[number];\n\n/**\n * Event tiers (AUDIT-1):\n * - `domain` (default) — facts other components may react to. Bridge-eligible.\n * Carries a `direction` and routes through the corresponding\n * `events_*` pool.\n * - `audit` — observational facts about the system itself (sync ran, feature\n * used). NOT bridge-eligible. MUST have no `direction` and no `pool`.\n *\n * See `ai-docs/specs/issue-242/plan.md` for the full design and the EVT\n * skill (`.claude/skills/events/SKILL.md`) for the runtime contract.\n */\nexport const EVENT_TIERS = [\"domain\", \"audit\"] as const;\nexport type EventTier = (typeof EVENT_TIERS)[number];\n\nexport const EVENT_FIELD_TYPES = [\n\t\"uuid\",\n\t\"string\",\n\t\"number\",\n\t\"boolean\",\n\t\"date\",\n\t\"json\",\n\t\"array\",\n] as const;\nexport type EventFieldType = (typeof EVENT_FIELD_TYPES)[number];\n\n/**\n * Scalar types permitted as `items` of an `array` field. Intentionally narrower\n * than the full field-type set: nested arrays and nested objects inside a\n * payload array cross the line from \"wire format\" into \"embedded schema\" and\n * should be modelled either as a separate event or as a `json` blob.\n */\nexport const EVENT_ARRAY_ITEM_TYPES = [\n\t\"uuid\",\n\t\"string\",\n\t\"number\",\n\t\"boolean\",\n\t\"date\",\n] as const;\nexport type EventArrayItemType = (typeof EVENT_ARRAY_ITEM_TYPES)[number];\n\nexport const RESERVED_EVENT_POOLS = [\n\t\"events_inbound\",\n\t\"events_change\",\n\t\"events_outbound\",\n] as const;\nexport type EventPool = (typeof RESERVED_EVENT_POOLS)[number];\n\nexport const EVENT_BACKOFF_STRATEGIES = [\"linear\", \"exponential\"] as const;\nexport type EventBackoffStrategy = (typeof EVENT_BACKOFF_STRATEGIES)[number];\n\n/**\n * Direction → default pool derivation. Each `direction` maps to exactly one\n * reserved pool; overrides must stay within the same category.\n */\nexport const DIRECTION_TO_POOL: Record<EventDirection, EventPool> = {\n\tinbound: \"events_inbound\",\n\tchange: \"events_change\",\n\toutbound: \"events_outbound\",\n};\n\n// ============================================================================\n// Sub-schemas\n// ============================================================================\n\nconst EventDirectionSchema = z.enum(EVENT_DIRECTIONS);\nconst EventTierSchema = z.enum(EVENT_TIERS);\nconst EventFieldTypeSchema = z.enum(EVENT_FIELD_TYPES);\nconst EventArrayItemTypeSchema = z.enum(EVENT_ARRAY_ITEM_TYPES);\nconst EventPoolSchema = z.enum(RESERVED_EVENT_POOLS);\n\n/**\n * Per-payload-field metadata. `nullable: true` means the field may be `null`\n * on the wire; `description` is surfaced into the generated interface/Zod\n * schema as a JSDoc. `items` is required when `type: 'array'` and rejected\n * otherwise — enforces \"array-ness is declared, item shape is declared\"\n * without opening the door to arbitrary nesting.\n */\nconst EventPayloadFieldSchema = z\n\t.object({\n\t\ttype: EventFieldTypeSchema,\n\t\titems: EventArrayItemTypeSchema.optional(),\n\t\tnullable: z.boolean().optional().default(false),\n\t\tdescription: z.string().optional(),\n\t})\n\t.strict()\n\t.superRefine((data, ctx) => {\n\t\tif (data.type === \"array\" && data.items === undefined) {\n\t\t\tctx.addIssue({\n\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\tmessage: \"'items' is required when type is 'array'\",\n\t\t\t\tpath: [\"items\"],\n\t\t\t});\n\t\t}\n\t\tif (data.type !== \"array\" && data.items !== undefined) {\n\t\t\tctx.addIssue({\n\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\tmessage: `'items' is only valid when type is 'array' (got '${data.type}')`,\n\t\t\t\tpath: [\"items\"],\n\t\t\t});\n\t\t}\n\t});\n\nexport type EventPayloadField = z.infer<typeof EventPayloadFieldSchema>;\n\n/**\n * Retry metadata hints surfaced to the drain loop. Default applied at parent\n * level (see `EventDefinitionSchemaCore`).\n */\nconst RetrySchema = z\n\t.object({\n\t\tattempts: z.number().int().min(0).max(20),\n\t\tbackoff: z.enum(EVENT_BACKOFF_STRATEGIES),\n\t})\n\t.strict();\n\nexport type EventRetry = z.infer<typeof RetrySchema>;\n\n// ============================================================================\n// Top-level schema\n// ============================================================================\n\nconst SNAKE_CASE_RE = /^[a-z][a-z0-9_]*$/;\n\nconst EventDefinitionSchemaCore = z\n\t.object({\n\t\ttype: z\n\t\t\t.string()\n\t\t\t.regex(\n\t\t\t\tSNAKE_CASE_RE,\n\t\t\t\t\"Event type must be snake_case starting with a letter\",\n\t\t\t),\n\t\ttier: EventTierSchema.optional().default(\"domain\"),\n\t\tdirection: EventDirectionSchema.optional(),\n\t\tpool: EventPoolSchema.optional(),\n\t\taggregate: z.string().regex(SNAKE_CASE_RE).optional(),\n\t\tsource: z.string().min(1).optional(),\n\t\tdestination: z.string().min(1).optional(),\n\t\tpayload: z\n\t\t\t.record(\n\t\t\t\tz\n\t\t\t\t\t.string()\n\t\t\t\t\t.regex(SNAKE_CASE_RE, \"Payload keys must be snake_case\"),\n\t\t\t\tEventPayloadFieldSchema,\n\t\t\t)\n\t\t\t.default({}),\n\t\tretry: RetrySchema.optional().default({\n\t\t\tattempts: 3,\n\t\t\tbackoff: \"exponential\",\n\t\t}),\n\t\tversion: z.number().int().min(1).optional().default(1),\n\t\tdescription: z.string().optional(),\n\t})\n\t.strict();\n\n/**\n * Cross-field refinements (in order):\n *\n * 1. Tier invariants (AUDIT-1):\n * a. `tier: 'audit'` ⇒ `pool` MUST be omitted.\n * b. `tier: 'audit'` ⇒ `direction` MUST be omitted.\n * c. `tier: 'domain'` ⇒ `direction` is required.\n * 2. `direction: change` ⇒ `aggregate` is required.\n * 3. `source` is only valid when `direction: inbound` (strict direction gating).\n * 4. `destination` is only valid when `direction: outbound` (strict direction gating).\n * 5. An explicit `pool` must match `DIRECTION_TO_POOL[direction]`.\n *\n * Strict gating on #3/#4 is a deliberate choice: silent acceptance breeds\n * drift. The ADR defines `source` as inbound-only and `destination` as\n * outbound-only.\n *\n * Refinements #2..#5 are domain-tier-only — audit events have no\n * direction/pool/aggregate/source/destination semantics.\n */\nconst EventDefinitionSchemaRefined = EventDefinitionSchemaCore.superRefine(\n\t(data, ctx) => {\n\t\t// AUDIT-1 — tier invariants. These run first because the rest of\n\t\t// the refinements assume domain semantics (direction populated).\n\t\tif (data.tier === \"audit\") {\n\t\t\tif (data.pool !== undefined) {\n\t\t\t\tctx.addIssue({\n\t\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\t\tmessage: `Event '${data.type}' is tier:audit; pool MUST be omitted (got '${data.pool}'). Audit events have no pool. See ai-docs/specs/issue-242/plan.md §AUDIT-2.`,\n\t\t\t\t\tpath: [\"pool\"],\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (data.direction !== undefined) {\n\t\t\t\tctx.addIssue({\n\t\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\t\tmessage: `Event '${data.type}' is tier:audit; direction MUST be omitted (got '${data.direction}'). Audit events have no direction. See ai-docs/specs/issue-242/plan.md §AUDIT-2.`,\n\t\t\t\t\tpath: [\"direction\"],\n\t\t\t\t});\n\t\t\t}\n\t\t\t// Skip the domain-tier refinements below — they reference\n\t\t\t// `direction`, which is intentionally absent for audit.\n\t\t\treturn;\n\t\t}\n\n\t\t// tier === 'domain' — direction must be present.\n\t\tif (data.direction === undefined) {\n\t\t\tctx.addIssue({\n\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\tmessage: \"'direction' is required when tier is 'domain'\",\n\t\t\t\tpath: [\"direction\"],\n\t\t\t});\n\t\t\t// Bail out — the remaining refinements all read `direction`\n\t\t\t// and would otherwise produce confusing cascade errors.\n\t\t\treturn;\n\t\t}\n\n\t\tif (data.direction === \"change\" && !data.aggregate) {\n\t\t\tctx.addIssue({\n\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\tmessage: \"'aggregate' is required when direction is 'change'\",\n\t\t\t\tpath: [\"aggregate\"],\n\t\t\t});\n\t\t}\n\n\t\tif (data.source !== undefined && data.direction !== \"inbound\") {\n\t\t\tctx.addIssue({\n\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\tmessage: `'source' is only valid when direction is 'inbound' (got '${data.direction}')`,\n\t\t\t\tpath: [\"source\"],\n\t\t\t});\n\t\t}\n\n\t\tif (data.destination !== undefined && data.direction !== \"outbound\") {\n\t\t\tctx.addIssue({\n\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\tmessage: `'destination' is only valid when direction is 'outbound' (got '${data.direction}')`,\n\t\t\t\tpath: [\"destination\"],\n\t\t\t});\n\t\t}\n\n\t\tif (data.pool !== undefined) {\n\t\t\tconst expected = DIRECTION_TO_POOL[data.direction];\n\t\t\tif (data.pool !== expected) {\n\t\t\t\tctx.addIssue({\n\t\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\t\tmessage: `pool '${data.pool}' is inconsistent with direction '${data.direction}' (expected '${expected}')`,\n\t\t\t\t\tpath: [\"pool\"],\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t},\n);\n\n/**\n * Final schema: derive `pool` from `direction` when not explicitly set.\n *\n * After `parse()`:\n * - Domain events (`tier === 'domain'`): `pool` and `direction` are both\n * populated; `pool` is derived from `direction` when not explicit.\n * - Audit events (`tier === 'audit'`): `pool` and `direction` both stay\n * `undefined` — audit events have no routing fields by construction\n * (mirrors the `domain_events` CHECK constraint, AUDIT-1).\n */\nexport const EventDefinitionSchema = EventDefinitionSchemaRefined.transform(\n\t(parsed) => {\n\t\tif (parsed.tier === \"audit\") {\n\t\t\t// Audit events: no pool/direction derivation. Both stay undefined.\n\t\t\treturn parsed;\n\t\t}\n\t\t// tier === 'domain': direction is guaranteed present by the refinement.\n\t\t// Narrow the type for the lookup.\n\t\tconst direction = parsed.direction as EventDirection;\n\t\treturn {\n\t\t\t...parsed,\n\t\t\tpool: parsed.pool ?? DIRECTION_TO_POOL[direction],\n\t\t};\n\t},\n);\n\nexport type EventDefinition = z.infer<typeof EventDefinitionSchema>;\n\n// ============================================================================\n// Validation Helpers\n// ============================================================================\n\nexport function validateEventDefinition(data: unknown): EventDefinition {\n\treturn EventDefinitionSchema.parse(data);\n}\n\nexport function safeValidateEventDefinition(data: unknown): {\n\tsuccess: boolean;\n\tdata?: EventDefinition;\n\terror?: z.ZodError;\n} {\n\tconst result = EventDefinitionSchema.safeParse(data);\n\tif (result.success) {\n\t\treturn { success: true, data: result.data };\n\t}\n\treturn { success: false, error: result.error };\n}\n","import { z } from 'zod';\n\n/**\n * Relationship Definition Schema\n *\n * Defines the YAML contract for first-class relationship entities — typed,\n * temporal, sourced junction tables between core entities.\n *\n * A relationship definition generates the same artifacts as an entity\n * (Drizzle schema, repository, DTOs, NestJS module, controller) but with\n * auto-generated FK columns, type enum, temporal fields, and source tracking.\n *\n * The relationship: block replaces entity: as the top-level discriminator.\n * The fields:, queries:, and behaviors: blocks reuse entity-definition schemas.\n *\n * See: docs/codegen-evolution-data-model/03-relationship-taxonomy.md\n * See: test/fixtures/relationships/ for examples\n */\n\n// Re-use field and query schemas from entity-definition\n// These are imported to avoid duplication — fields on a relationship\n// work identically to fields on an entity.\nimport type { FieldDefinition, QueryDeclaration } from './entity-definition.schema.js';\n\n// ============================================================================\n// Relationship Type Definitions\n// ============================================================================\n\n/**\n * Direction metadata for a single relationship type.\n *\n * Required for self-referential relationships (person↔person, org↔org)\n * where direction can't be inferred from entity-type asymmetry.\n *\n * Three mutually exclusive modes:\n * - inverse: \"from→to is called X, to→from is called Y\"\n * - bidirectional: true — direction doesn't matter, query both sides\n * - directed: true — one-way, no inverse name (default if none specified)\n */\nconst TypeDirectionSchema = z\n\t.object({\n\t\t/** Name of the inverse type when viewed from the other direction */\n\t\tinverse: z.string().optional(),\n\t\t/** Both directions are equivalent — queries should check both FK columns */\n\t\tbidirectional: z.boolean().optional(),\n\t\t/** Explicitly directed, no named inverse (default behavior) */\n\t\tdirected: z.boolean().optional(),\n\t})\n\t.refine(\n\t\t(data) => {\n\t\t\tconst set = [data.inverse, data.bidirectional, data.directed].filter(\n\t\t\t\t(v) => v !== undefined,\n\t\t\t);\n\t\t\treturn set.length === 1;\n\t\t},\n\t\t{\n\t\t\tmessage:\n\t\t\t\t'Exactly one of inverse, bidirectional, or directed must be specified',\n\t\t},\n\t);\n\nexport type TypeDirection = z.infer<typeof TypeDirectionSchema>;\n\n/**\n * Relationship types can be declared in two forms:\n *\n * 1. Simple list — for cross-type relationships where direction is\n * unambiguous from entity asymmetry:\n * types: [employed_by, advises, board_member]\n *\n * 2. Object map — for self-referential or when types need direction metadata:\n * types:\n * reporting:\n * inverse: management\n * network:\n * bidirectional: true\n *\n * The simple list is sugar for \"all directed from→to, no inverses.\"\n */\nconst RelationshipTypesSchema = z.union([\n\t// Simple list: all types are directed from→to\n\tz.array(z.string().regex(/^[a-z][a-z0-9_]*$/, 'Type must be snake_case')),\n\t// Object map: each type has direction metadata\n\tz.record(\n\t\tz.string().regex(/^[a-z][a-z0-9_]*$/, 'Type key must be snake_case'),\n\t\tTypeDirectionSchema,\n\t),\n]);\n\nexport type RelationshipTypes = z.infer<typeof RelationshipTypesSchema>;\n\n// ============================================================================\n// On-Delete Semantics (ADR-021)\n// ============================================================================\n\nconst OnDeleteActionSchema = z\n\t.enum(['restrict', 'cascade', 'set_null', 'no_action'])\n\t.default('restrict');\n\nexport type OnDeleteAction = z.infer<typeof OnDeleteActionSchema>;\n\n// ============================================================================\n// Relationship Configuration Block\n// ============================================================================\n\n/**\n * The relationship: block — top-level config for a relationship definition.\n *\n * Establishes the two endpoints, type taxonomy, and behavioral flags.\n * Auto-generates FK columns, type enum, temporal fields, source tracking,\n * and timestamps based on configuration.\n */\nconst RelationshipConfigSchema = z\n\t.object({\n\t\t/** Relationship name (snake_case). Used for class/file naming. */\n\t\tname: z.string().regex(\n\t\t\t/^[a-z][a-z0-9_]*$/,\n\t\t\t'Relationship name must be snake_case',\n\t\t),\n\n\t\t/** Database table name. Defaults to {name}s if not specified. */\n\t\ttable: z\n\t\t\t.string()\n\t\t\t.regex(/^[a-z][a-z0-9_]*$/, 'Table must be snake_case')\n\t\t\t.optional(),\n\n\t\t/** The \"from\" entity — generates {entity}_id FK column (subject). */\n\t\tfrom: z.string().regex(/^[a-z][a-z0-9_]*$/, 'Entity name must be snake_case'),\n\n\t\t/** The \"to\" entity — generates {entity}_id FK column (object). */\n\t\tto: z.string().regex(/^[a-z][a-z0-9_]*$/, 'Entity name must be snake_case'),\n\n\t\t/**\n\t\t * Relationship subtypes. Optional — omit for untyped junctions.\n\t\t * When present, generates a `type` enum column on the junction table.\n\t\t *\n\t\t * Simple list: all types are directed (from→to). Use for cross-type\n\t\t * relationships where entity asymmetry makes direction obvious.\n\t\t *\n\t\t * Object map: each type declares its own direction metadata.\n\t\t * Required for self-referential relationships (from === to).\n\t\t */\n\t\ttypes: RelationshipTypesSchema.optional(),\n\n\t\t/**\n\t\t * Generate temporal validity fields: valid_from (date), valid_to (date?),\n\t\t * is_current (boolean, denormalized for query performance).\n\t\t * Default: true\n\t\t */\n\t\ttemporal: z.boolean().default(true),\n\n\t\t/**\n\t\t * Generate source tracking fields: source (enum), confidence (decimal 0-1).\n\t\t * Default: true\n\t\t */\n\t\tsourced: z.boolean().default(true),\n\n\t\t/** on_delete action for the \"from\" endpoint FK. Default: restrict */\n\t\ton_delete_from: OnDeleteActionSchema.optional(),\n\n\t\t/** on_delete action for the \"to\" endpoint FK. Default: restrict */\n\t\ton_delete_to: OnDeleteActionSchema.optional(),\n\n\t\t/**\n\t\t * Override the default unique constraint columns.\n\t\t *\n\t\t * Defaults:\n\t\t * - Typed: [from_id, to_id, type]\n\t\t * - Typed + temporal: [from_id, to_id, type, valid_from]\n\t\t * - Untyped: [from_id, to_id]\n\t\t *\n\t\t * Use this when the default doesn't fit — e.g., allowing multiple\n\t\t * relationships of the same type between the same entities at different times.\n\t\t */\n\t\tunique_on: z.array(z.string()).optional(),\n\t})\n\t.strict();\n\nexport type RelationshipConfig = z.infer<typeof RelationshipConfigSchema>;\n\n// ============================================================================\n// Query Declaration (reuse from entity-definition)\n// ============================================================================\n\n/**\n * Same query declaration syntax as entities.\n * FK field names in `by:` use the auto-generated names:\n * - Cross-type: {entity}_id (e.g., person_id, organization_id)\n * - Self-referential: from_{entity}_id, to_{entity}_id\n */\nconst RelationshipQuerySchema = z.object({\n\tby: z.array(z.string()).min(1),\n\tunique: z.boolean().optional(),\n\tselect: z.array(z.string()).optional(),\n\torder: z.string().optional(),\n\tlimit: z.boolean().optional(),\n});\n\n// ============================================================================\n// Field Definition (reuse from entity-definition)\n// ============================================================================\n\n// We import the type but need to re-reference the schema inline for Zod parsing.\n// The actual FieldDefinitionSchema is defined in entity-definition.schema.ts.\n// For now, we use z.record(z.string(), z.any()) and validate fields\n// through the shared FieldDefinitionSchema at parse time.\n//\n// TODO: Extract FieldDefinitionSchema to a shared module so both\n// entity-definition and relationship-definition can import it directly.\n\n// ============================================================================\n// Full Relationship Definition\n// ============================================================================\n\n/**\n * Complete relationship definition — the top-level shape of a relationship YAML file.\n *\n * Example (minimal):\n * relationship:\n * name: engagement_opportunity\n * from: engagement\n * to: opportunity\n *\n * Example (full):\n * relationship:\n * name: person_organization\n * table: person_organizations\n * from: person\n * to: organization\n * types: [employed_by, advises, board_member]\n * temporal: true\n * sourced: true\n * fields:\n * role_title:\n * type: string\n * nullable: true\n * queries:\n * - by: [person_id]\n */\nexport const RelationshipDefinitionSchema = z\n\t.object({\n\t\t/** Relationship configuration block */\n\t\trelationship: RelationshipConfigSchema,\n\n\t\t/**\n\t\t * Additional fields beyond auto-generated ones.\n\t\t * These describe the relationship, not either endpoint entity.\n\t\t * Uses the same field definition schema as entity fields.\n\t\t */\n\t\tfields: z.record(z.string(), z.any()).optional(),\n\n\t\t/** Declarative queries — same syntax as entity queries. */\n\t\tqueries: z.array(RelationshipQuerySchema).optional(),\n\t})\n\t.strict()\n\t.refine(\n\t\t(data) => {\n\t\t\t// Self-referential relationships with types MUST use the object map form\n\t\t\t// so that direction metadata (inverse/bidirectional/directed) is explicit.\n\t\t\tif (data.relationship.from === data.relationship.to && data.relationship.types) {\n\t\t\t\treturn !Array.isArray(data.relationship.types);\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\t\t{\n\t\t\tmessage:\n\t\t\t\t'Self-referential relationships must use the object map form for types ' +\n\t\t\t\t'(with inverse/bidirectional/directed metadata), not a simple list',\n\t\t\tpath: ['relationship', 'types'],\n\t\t},\n\t)\n\t.refine(\n\t\t(data) => {\n\t\t\t// Reject fields: keys that collide with auto-generated column names.\n\t\t\t// The reserved set is dynamic — depends on the relationship config.\n\t\t\tif (!data.fields) return true;\n\n\t\t\tconst reserved = getReservedColumnNames(data.relationship);\n\t\t\tconst collisions = Object.keys(data.fields).filter((key) =>\n\t\t\t\treserved.has(key),\n\t\t\t);\n\t\t\treturn collisions.length === 0;\n\t\t},\n\t\t{\n\t\t\tmessage:\n\t\t\t\t'fields: contains keys that collide with auto-generated columns. ' +\n\t\t\t\t'Reserved names depend on config (type, valid_from, valid_to, ' +\n\t\t\t\t'is_current, source, confidence, id, created_at, updated_at, and FK columns).',\n\t\t\tpath: ['fields'],\n\t\t},\n\t);\n\nexport type RelationshipDefinition = z.infer<\n\ttypeof RelationshipDefinitionSchema\n>;\n\n// ============================================================================\n// Validation Helpers\n// ============================================================================\n\nexport function validateRelationshipDefinition(\n\tdata: unknown,\n): RelationshipDefinition {\n\treturn RelationshipDefinitionSchema.parse(data);\n}\n\nexport function safeValidateRelationshipDefinition(data: unknown): {\n\tsuccess: boolean;\n\tdata?: RelationshipDefinition;\n\terror?: z.ZodError;\n} {\n\tconst result = RelationshipDefinitionSchema.safeParse(data);\n\tif (result.success) {\n\t\treturn { success: true, data: result.data };\n\t}\n\treturn { success: false, error: result.error };\n}\n\n// ============================================================================\n// Reserved Column Names\n// ============================================================================\n\n/**\n * Returns the set of column names that are auto-generated for a relationship\n * and therefore cannot be used as custom field names.\n *\n * The set is dynamic — it depends on the relationship config:\n * - Always: id, created_at, updated_at, and both FK columns\n * - If types: present → type\n * - If temporal: true → valid_from, valid_to, is_current\n * - If sourced: true → source, confidence\n */\nexport function getReservedColumnNames(config: RelationshipConfig): Set<string> {\n\tconst { fromColumn, toColumn } = deriveRelationshipFKColumns(config);\n\tconst reserved = new Set([\n\t\t'id',\n\t\t'created_at',\n\t\t'updated_at',\n\t\tfromColumn,\n\t\ttoColumn,\n\t]);\n\n\tif (config.types) {\n\t\treserved.add('type');\n\t}\n\tif (config.temporal) {\n\t\treserved.add('valid_from');\n\t\treserved.add('valid_to');\n\t\treserved.add('is_current');\n\t}\n\tif (config.sourced) {\n\t\treserved.add('source');\n\t\treserved.add('confidence');\n\t}\n\n\treturn reserved;\n}\n\n// ============================================================================\n// Auto-Generated Field Helpers\n// ============================================================================\n\n/**\n * Derives the FK column names for a relationship.\n *\n * Cross-type (from !== to):\n * from: person, to: organization → person_id, organization_id\n *\n * Self-referential (from === to):\n * from: person, to: person → from_person_id, to_person_id\n */\nexport function deriveRelationshipFKColumns(config: RelationshipConfig): {\n\tfromColumn: string;\n\ttoColumn: string;\n} {\n\tif (config.from === config.to) {\n\t\treturn {\n\t\t\tfromColumn: `from_${config.from}_id`,\n\t\t\ttoColumn: `to_${config.to}_id`,\n\t\t};\n\t}\n\treturn {\n\t\tfromColumn: `${config.from}_id`,\n\t\ttoColumn: `${config.to}_id`,\n\t};\n}\n\n/**\n * Derives the default table name if not explicitly specified.\n * Uses the relationship name + 's' suffix.\n */\nexport function deriveTableName(config: RelationshipConfig): string {\n\treturn config.table ?? `${config.name}s`;\n}\n\n/**\n * Collects all type names from a types declaration.\n * Handles both simple list and object map forms.\n */\nexport function collectTypeNames(\n\ttypes: RelationshipTypes | undefined,\n): string[] {\n\tif (!types) return [];\n\tif (Array.isArray(types)) return types;\n\treturn Object.keys(types);\n}\n\n/**\n * Collects all inverse type names from a types declaration.\n * Only applicable for object map form with inverse metadata.\n */\nexport function collectInverseNames(\n\ttypes: RelationshipTypes | undefined,\n): string[] {\n\tif (!types || Array.isArray(types)) return [];\n\treturn Object.values(types)\n\t\t.map((dir) => (dir as TypeDirection & { inverse?: string }).inverse)\n\t\t.filter((v): v is string => v !== undefined);\n}\n\n/**\n * Determines the default unique constraint columns.\n *\n * Logic:\n * - Typed + temporal: [from_id, to_id, type, valid_from]\n * - Typed: [from_id, to_id, type]\n * - Untyped: [from_id, to_id]\n */\nexport function deriveUniqueConstraint(config: RelationshipConfig): string[] {\n\tif (config.unique_on) return config.unique_on;\n\n\tconst { fromColumn, toColumn } = deriveRelationshipFKColumns(config);\n\tconst columns = [fromColumn, toColumn];\n\n\tif (config.types) {\n\t\tcolumns.push('type');\n\t}\n\tif (config.temporal && config.types) {\n\t\tcolumns.push('valid_from');\n\t}\n\n\treturn columns;\n}\n","/**\n * Graph Builder\n *\n * Builds a domain graph from parsed entities, including nodes and edges.\n * Tracks bidirectional connections between entities.\n */\n\nimport type {\n\tParsedEntity,\n\tParsedRelationship,\n\tParsedRelationshipDefinition,\n\tDomainGraph,\n\tRelationshipEdge,\n\tEntityNode,\n} from './types';\n\n/**\n * Infer cardinality from relationship type\n */\nfunction inferCardinality(type: string): '1:1' | '1:N' | 'N:1' | 'N:M' {\n\tswitch (type) {\n\t\tcase 'belongs_to':\n\t\t\treturn 'N:1';\n\t\tcase 'has_many':\n\t\t\treturn '1:N';\n\t\tcase 'has_one':\n\t\t\treturn '1:1';\n\t\tdefault:\n\t\t\treturn '1:N';\n\t}\n}\n\n/**\n * Check if an edge already exists in the opposite direction\n */\nfunction hasReverseEdge(\n\tedges: RelationshipEdge[],\n\tfrom: string,\n\tto: string\n): RelationshipEdge | undefined {\n\treturn edges.find((e) => e.from === to && e.to === from);\n}\n\n/**\n * Build a domain graph from parsed entities\n */\nexport function buildDomainGraph(\n\tentities: ParsedEntity[],\n\trelationshipDefinitions: ParsedRelationshipDefinition[] = [],\n): DomainGraph {\n\tconst entityMap = new Map<string, ParsedEntity>();\n\tconst relDefMap = new Map<string, ParsedRelationshipDefinition>();\n\tconst edges: RelationshipEdge[] = [];\n\n\t// Build entity map\n\tfor (const entity of entities) {\n\t\tentityMap.set(entity.name, entity);\n\t}\n\n\t// Build relationship definition map\n\tfor (const relDef of relationshipDefinitions) {\n\t\trelDefMap.set(relDef.name, relDef);\n\t}\n\n\t// Build edges from inline entity relationships (belongs_to, has_many, has_one)\n\tfor (const entity of entities) {\n\t\tfor (const [relName, rel] of entity.relationships) {\n\t\t\tif (!rel.resolved) continue;\n\n\t\t\t// Check if reverse edge already exists\n\t\t\tconst reverseEdge = hasReverseEdge(edges, entity.name, rel.target);\n\n\t\t\tconst edge: RelationshipEdge = {\n\t\t\t\tfrom: entity.name,\n\t\t\t\tto: rel.target,\n\t\t\t\trelationship: rel,\n\t\t\t\tcardinality: inferCardinality(rel.type),\n\t\t\t\tbidirectional: reverseEdge !== undefined,\n\t\t\t};\n\n\t\t\t// Mark reverse edge as bidirectional too\n\t\t\tif (reverseEdge) {\n\t\t\t\treverseEdge.bidirectional = true;\n\t\t\t}\n\n\t\t\tedges.push(edge);\n\t\t}\n\t}\n\n\t// Build edges from first-class relationship definitions (junction entities)\n\tfor (const relDef of relationshipDefinitions) {\n\t\tconst fromExists = entityMap.has(relDef.from);\n\t\tconst toExists = entityMap.has(relDef.to);\n\n\t\tif (fromExists && toExists) {\n\t\t\t// Create an N:M edge — junction tables are always many-to-many\n\t\t\tconst edge: RelationshipEdge = {\n\t\t\t\tfrom: relDef.from,\n\t\t\t\tto: relDef.to,\n\t\t\t\trelationship: {\n\t\t\t\t\tname: relDef.name,\n\t\t\t\t\ttype: 'has_many',\n\t\t\t\t\ttarget: relDef.to,\n\t\t\t\t\tforeignKey: relDef.fromColumn,\n\t\t\t\t\tresolved: true,\n\t\t\t\t},\n\t\t\t\tcardinality: 'N:M',\n\t\t\t\tbidirectional: relDef.types.some((t) => t.bidirectional),\n\t\t\t};\n\n\t\t\tedges.push(edge);\n\t\t}\n\t}\n\n\treturn { entities: entityMap, relationshipDefinitions: relDefMap, edges };\n}\n\n/**\n * Get all entities related to a given entity within a specified depth\n */\nexport function getRelatedEntities(\n\tgraph: DomainGraph,\n\tentityName: string,\n\tdepth = 1\n): Set<string> {\n\tconst related = new Set<string>();\n\tconst visited = new Set<string>();\n\tconst queue: Array<{ name: string; currentDepth: number }> = [\n\t\t{ name: entityName, currentDepth: 0 },\n\t];\n\n\twhile (queue.length > 0) {\n\t\tconst item = queue.shift();\n\t\tif (!item) continue;\n\n\t\tconst { name, currentDepth } = item;\n\t\tif (visited.has(name) || currentDepth > depth) continue;\n\t\tvisited.add(name);\n\n\t\tfor (const edge of graph.edges) {\n\t\t\tif (edge.from === name && !visited.has(edge.to)) {\n\t\t\t\trelated.add(edge.to);\n\t\t\t\tqueue.push({ name: edge.to, currentDepth: currentDepth + 1 });\n\t\t\t}\n\t\t\tif (edge.to === name && !visited.has(edge.from)) {\n\t\t\t\trelated.add(edge.from);\n\t\t\t\tqueue.push({ name: edge.from, currentDepth: currentDepth + 1 });\n\t\t\t}\n\t\t}\n\t}\n\n\treturn related;\n}\n\n/**\n * Find entities with no relationships (orphans)\n */\nexport function findOrphanEntities(graph: DomainGraph): string[] {\n\tconst orphans: string[] = [];\n\tfor (const [name] of graph.entities) {\n\t\tconst hasRelationship = graph.edges.some((e) => e.from === name || e.to === name);\n\t\tif (!hasRelationship) {\n\t\t\torphans.push(name);\n\t\t}\n\t}\n\treturn orphans;\n}\n\n/**\n * Find circular dependencies in the graph\n */\nexport function findCircularDependencies(graph: DomainGraph): string[][] {\n\tconst cycles: string[][] = [];\n\tconst visited = new Set<string>();\n\tconst recursionStack = new Set<string>();\n\n\tfunction dfs(node: string, path: string[]): void {\n\t\tvisited.add(node);\n\t\trecursionStack.add(node);\n\n\t\tconst outgoingEdges = graph.edges.filter((e) => e.from === node);\n\t\tfor (const edge of outgoingEdges) {\n\t\t\tif (!visited.has(edge.to)) {\n\t\t\t\tdfs(edge.to, [...path, edge.to]);\n\t\t\t} else if (recursionStack.has(edge.to)) {\n\t\t\t\t// Found cycle\n\t\t\t\tconst cycleStart = path.indexOf(edge.to);\n\t\t\t\tif (cycleStart !== -1) {\n\t\t\t\t\tcycles.push([...path.slice(cycleStart), edge.to]);\n\t\t\t\t} else {\n\t\t\t\t\t// The cycle starts at edge.to which is in the recursion stack\n\t\t\t\t\tcycles.push([...path, edge.to]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\trecursionStack.delete(node);\n\t}\n\n\tfor (const [name] of graph.entities) {\n\t\tif (!visited.has(name)) {\n\t\t\tdfs(name, [name]);\n\t\t}\n\t}\n\n\t// Deduplicate cycles (same cycle can be detected from different starting points)\n\tconst uniqueCycles: string[][] = [];\n\tconst seen = new Set<string>();\n\n\tfor (const cycle of cycles) {\n\t\t// Normalize cycle by rotating to start with smallest element\n\t\tconst minIndex = cycle.indexOf(\n\t\t\tcycle.reduce((min, val) => (val < min ? val : min), cycle[0])\n\t\t);\n\t\tconst normalized = [...cycle.slice(minIndex), ...cycle.slice(0, minIndex)];\n\t\tconst key = normalized.join('->');\n\n\t\tif (!seen.has(key)) {\n\t\t\tseen.add(key);\n\t\t\tuniqueCycles.push(cycle);\n\t\t}\n\t}\n\n\treturn uniqueCycles;\n}\n\n/**\n * Build entity nodes for visualization\n */\nexport function buildEntityNodes(graph: DomainGraph): EntityNode[] {\n\tconst nodes: EntityNode[] = [];\n\tfor (const [name, entity] of graph.entities) {\n\t\tnodes.push({\n\t\t\tid: name,\n\t\t\tname: entity.name,\n\t\t\tentity,\n\t\t});\n\t}\n\treturn nodes;\n}\n","/**\n * External ID Tracking Behavior\n *\n * Adds external_id, provider, and provider_metadata fields to track\n * records that are synced from external systems (e.g., Salesforce, HubSpot).\n */\n\nimport type { BehaviorDefinition } from './types';\n\nexport const externalIdTrackingBehavior: BehaviorDefinition = {\n\tname: 'external_id_tracking',\n\tdescription: 'Adds external_id, provider, and provider_metadata fields for external system sync tracking',\n\n\tfields: [\n\t\t{\n\t\t\tname: 'external_id',\n\t\t\tcamelName: 'externalId',\n\t\t\ttype: 'string',\n\t\t\ttsType: 'string | null',\n\t\t\tdrizzleType: 'varchar',\n\t\t\tdrizzleImports: ['varchar', 'index'],\n\t\t\tzodType: 'z.string().nullable()',\n\t\t\tnullable: true,\n\t\t\tui: {\n\t\t\t\tlabel: 'External ID',\n\t\t\t\ttype: 'text',\n\t\t\t\timportance: 'tertiary',\n\t\t\t\tgroup: 'metadata',\n\t\t\t\tvisible: false,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: 'provider',\n\t\t\tcamelName: 'provider',\n\t\t\ttype: 'string',\n\t\t\ttsType: 'string | null',\n\t\t\tdrizzleType: 'varchar',\n\t\t\tdrizzleImports: ['varchar'],\n\t\t\tzodType: 'z.string().nullable()',\n\t\t\tnullable: true,\n\t\t\tui: {\n\t\t\t\tlabel: 'Provider',\n\t\t\t\ttype: 'text',\n\t\t\t\timportance: 'tertiary',\n\t\t\t\tgroup: 'metadata',\n\t\t\t\tvisible: false,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: 'provider_metadata',\n\t\t\tcamelName: 'providerMetadata',\n\t\t\ttype: 'json',\n\t\t\ttsType: 'unknown | null',\n\t\t\tdrizzleType: 'jsonb',\n\t\t\tdrizzleImports: ['jsonb'],\n\t\t\tzodType: 'z.unknown().nullable()',\n\t\t\tnullable: true,\n\t\t\tui: {\n\t\t\t\tlabel: 'Provider Metadata',\n\t\t\t\ttype: 'json',\n\t\t\t\timportance: 'tertiary',\n\t\t\t\tgroup: 'metadata',\n\t\t\t\tvisible: false,\n\t\t\t},\n\t\t},\n\t],\n\n\tdrizzleImports: ['varchar', 'jsonb', 'index'],\n\n\tconfigKey: 'externalIdTracking',\n};\n","/**\n * Soft Delete Behavior\n *\n * Adds deleted_at field for soft delete functionality.\n * Records are marked as deleted instead of being removed from the database.\n * BaseRepository automatically filters soft-deleted records in queries.\n */\n\nimport type { BehaviorDefinition } from './types';\n\nexport const softDeleteBehavior: BehaviorDefinition = {\n\tname: 'soft_delete',\n\tdescription: 'Adds deleted_at field for soft delete functionality',\n\n\tfields: [\n\t\t{\n\t\t\tname: 'deleted_at',\n\t\t\tcamelName: 'deletedAt',\n\t\t\ttype: 'datetime',\n\t\t\ttsType: 'Date | null',\n\t\t\tdrizzleType: 'timestamp',\n\t\t\tdrizzleImports: ['timestamp'],\n\t\t\tzodType: 'z.coerce.date().nullable()',\n\t\t\tnullable: true,\n\t\t\tui: {\n\t\t\t\tlabel: 'Deleted At',\n\t\t\t\ttype: 'datetime',\n\t\t\t\timportance: 'tertiary',\n\t\t\t\tgroup: 'metadata',\n\t\t\t\tvisible: false,\n\t\t\t},\n\t\t},\n\t],\n\n\tdrizzleImports: ['timestamp'],\n\n\tmethods: [\n\t\t'softDelete',\n\t\t'restore',\n\t\t'findWithDeleted',\n\t\t'findOnlyDeleted',\n\t\t'baseQuery', // Modified to filter deleted records\n\t],\n\n\tconfigKey: 'softDelete',\n};\n","/**\n * Timestamps Behavior\n *\n * Adds created_at and updated_at fields to track entity lifecycle.\n * These fields are automatically managed by BaseRepository.\n */\n\nimport type { BehaviorDefinition } from './types';\n\nexport const timestampsBehavior: BehaviorDefinition = {\n\tname: 'timestamps',\n\tdescription: 'Adds created_at and updated_at timestamp fields',\n\n\tfields: [\n\t\t{\n\t\t\tname: 'created_at',\n\t\t\tcamelName: 'createdAt',\n\t\t\ttype: 'datetime',\n\t\t\ttsType: 'Date',\n\t\t\tdrizzleType: 'timestamp',\n\t\t\tdrizzleImports: ['timestamp'],\n\t\t\tzodType: 'z.coerce.date()',\n\t\t\tnullable: false,\n\t\t\tdefault: 'now()',\n\t\t\tui: {\n\t\t\t\tlabel: 'Created At',\n\t\t\t\ttype: 'datetime',\n\t\t\t\timportance: 'tertiary',\n\t\t\t\tgroup: 'metadata',\n\t\t\t\tvisible: false,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: 'updated_at',\n\t\t\tcamelName: 'updatedAt',\n\t\t\ttype: 'datetime',\n\t\t\ttsType: 'Date',\n\t\t\tdrizzleType: 'timestamp',\n\t\t\tdrizzleImports: ['timestamp'],\n\t\t\tzodType: 'z.coerce.date()',\n\t\t\tnullable: false,\n\t\t\tdefault: 'now()',\n\t\t\tui: {\n\t\t\t\tlabel: 'Updated At',\n\t\t\t\ttype: 'datetime',\n\t\t\t\timportance: 'tertiary',\n\t\t\t\tgroup: 'metadata',\n\t\t\t\tvisible: false,\n\t\t\t},\n\t\t},\n\t],\n\n\tdrizzleImports: ['timestamp'],\n\n\tmethods: ['applyTimestampsOnCreate', 'applyTimestampsOnUpdate'],\n\n\tconfigKey: 'timestamps',\n};\n","/**\n * User Tracking Behavior\n *\n * Adds created_by and updated_by fields to track which user\n * created and last modified an entity.\n * These fields are automatically managed by BaseRepository when\n * a RepositoryContext with userId is provided.\n */\n\nimport type { BehaviorDefinition } from './types';\n\nexport const userTrackingBehavior: BehaviorDefinition = {\n\tname: 'user_tracking',\n\tdescription: 'Adds created_by and updated_by user reference fields',\n\n\tfields: [\n\t\t{\n\t\t\tname: 'created_by',\n\t\t\tcamelName: 'createdBy',\n\t\t\ttype: 'uuid',\n\t\t\ttsType: 'string | null',\n\t\t\tdrizzleType: 'uuid',\n\t\t\tdrizzleImports: ['uuid'],\n\t\t\tzodType: 'z.string().uuid().nullable()',\n\t\t\tnullable: true,\n\t\t\tforeignKey: 'users.id',\n\t\t\tui: {\n\t\t\t\tlabel: 'Created By',\n\t\t\t\ttype: 'reference',\n\t\t\t\timportance: 'tertiary',\n\t\t\t\tgroup: 'metadata',\n\t\t\t\tvisible: false,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: 'updated_by',\n\t\t\tcamelName: 'updatedBy',\n\t\t\ttype: 'uuid',\n\t\t\ttsType: 'string | null',\n\t\t\tdrizzleType: 'uuid',\n\t\t\tdrizzleImports: ['uuid'],\n\t\t\tzodType: 'z.string().uuid().nullable()',\n\t\t\tnullable: true,\n\t\t\tforeignKey: 'users.id',\n\t\t\tui: {\n\t\t\t\tlabel: 'Updated By',\n\t\t\t\ttype: 'reference',\n\t\t\t\timportance: 'tertiary',\n\t\t\t\tgroup: 'metadata',\n\t\t\t\tvisible: false,\n\t\t\t},\n\t\t},\n\t],\n\n\tdrizzleImports: ['uuid'],\n\n\tmethods: ['applyUserTrackingOnCreate', 'applyUserTrackingOnUpdate'],\n\n\tconfigKey: 'userTracking',\n};\n","/**\n * Behavior Registry - Central registry for all entity behaviors\n *\n * Provides functions to:\n * - Get behavior definitions by name\n * - Validate behavior configurations\n * - Resolve fields added by behaviors\n */\n\nimport { externalIdTrackingBehavior } from './external-id-tracking';\nimport { softDeleteBehavior } from './soft-delete';\nimport { timestampsBehavior } from './timestamps';\nimport type {\n\tBehaviorConfig,\n\tBehaviorDefinition,\n\tBehaviorField,\n\tNormalizedBehaviorConfig,\n\tResolvedBehaviors,\n\tValidationResult,\n} from './types';\nimport { userTrackingBehavior } from './user-tracking';\n\n// ============================================================================\n// Behavior Registry\n// ============================================================================\n\nconst behaviorRegistry = new Map<string, BehaviorDefinition>([\n\t['timestamps', timestampsBehavior],\n\t['soft_delete', softDeleteBehavior],\n\t['user_tracking', userTrackingBehavior],\n\t['external_id_tracking', externalIdTrackingBehavior],\n]);\n\n/**\n * Get a behavior definition by name\n */\nexport function getBehavior(name: string): BehaviorDefinition | undefined {\n\treturn behaviorRegistry.get(name);\n}\n\n/**\n * Get all registered behavior names\n */\nexport function getAllBehaviorNames(): string[] {\n\treturn Array.from(behaviorRegistry.keys());\n}\n\n// ============================================================================\n// Config Normalization\n// ============================================================================\n\n/**\n * Normalize a behavior config to always have name and options\n */\nexport function normalizeBehaviorConfig(\n\tconfig: BehaviorConfig,\n): NormalizedBehaviorConfig {\n\tif (typeof config === 'string') {\n\t\treturn { name: config, options: {} };\n\t}\n\treturn { name: config.name, options: config.options ?? {} };\n}\n\n/**\n * Normalize an array of behavior configs\n */\nexport function normalizeBehaviorConfigs(\n\tconfigs: BehaviorConfig[],\n): NormalizedBehaviorConfig[] {\n\treturn configs.map(normalizeBehaviorConfig);\n}\n\n// ============================================================================\n// Validation\n// ============================================================================\n\n/**\n * Validate a set of behavior configurations\n * Checks for unknown behaviors, missing dependencies, and conflicts\n */\nexport function validateBehaviors(configs: BehaviorConfig[]): ValidationResult {\n\tconst errors: string[] = [];\n\tconst warnings: string[] = [];\n\tconst normalized = normalizeBehaviorConfigs(configs);\n\tconst enabledNames = new Set(normalized.map((c) => c.name));\n\n\tfor (const config of normalized) {\n\t\tconst behavior = getBehavior(config.name);\n\n\t\t// Check behavior exists\n\t\tif (!behavior) {\n\t\t\terrors.push(`Unknown behavior: '${config.name}'`);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Check dependencies\n\t\tif (behavior.requires) {\n\t\t\tfor (const req of behavior.requires) {\n\t\t\t\tif (!enabledNames.has(req)) {\n\t\t\t\t\terrors.push(\n\t\t\t\t\t\t`Behavior '${config.name}' requires '${req}' which is not enabled`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Check conflicts\n\t\tif (behavior.conflicts) {\n\t\t\tfor (const conflict of behavior.conflicts) {\n\t\t\t\tif (enabledNames.has(conflict)) {\n\t\t\t\t\terrors.push(\n\t\t\t\t\t\t`Behavior '${config.name}' conflicts with '${conflict}'`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\tvalid: errors.length === 0,\n\t\terrors,\n\t\twarnings,\n\t};\n}\n\n// ============================================================================\n// Field Resolution\n// ============================================================================\n\n/**\n * Get all fields added by a set of behaviors\n */\nexport function resolveBehaviorFields(\n\tconfigs: BehaviorConfig[],\n): BehaviorField[] {\n\tconst normalized = normalizeBehaviorConfigs(configs);\n\tconst fields: BehaviorField[] = [];\n\tconst addedFieldNames = new Set<string>();\n\n\tfor (const config of normalized) {\n\t\tconst behavior = getBehavior(config.name);\n\t\tif (!behavior) continue;\n\n\t\tfor (const field of behavior.fields) {\n\t\t\t// Avoid duplicate fields if multiple behaviors add the same field\n\t\t\tif (!addedFieldNames.has(field.name)) {\n\t\t\t\tfields.push(field);\n\t\t\t\taddedFieldNames.add(field.name);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn fields;\n}\n\n/**\n * Get all Drizzle imports needed by a set of behaviors\n */\nexport function resolveBehaviorDrizzleImports(\n\tconfigs: BehaviorConfig[],\n): string[] {\n\tconst normalized = normalizeBehaviorConfigs(configs);\n\tconst imports = new Set<string>();\n\n\tfor (const config of normalized) {\n\t\tconst behavior = getBehavior(config.name);\n\t\tif (!behavior) continue;\n\n\t\tfor (const imp of behavior.drizzleImports) {\n\t\t\timports.add(imp);\n\t\t}\n\t}\n\n\treturn Array.from(imports).sort();\n}\n\n// ============================================================================\n// Full Resolution\n// ============================================================================\n\n/**\n * Resolve all behavior data for templates\n */\nexport function resolveBehaviors(configs: BehaviorConfig[]): ResolvedBehaviors {\n\tconst normalized = normalizeBehaviorConfigs(configs);\n\tconst fields = resolveBehaviorFields(configs);\n\tconst drizzleImports = resolveBehaviorDrizzleImports(configs);\n\n\tconst enabledNames = new Set(normalized.map((c) => c.name));\n\n\tconst hasTimestamps = enabledNames.has('timestamps');\n\tconst hasSoftDelete = enabledNames.has('soft_delete');\n\tconst hasUserTracking = enabledNames.has('user_tracking');\n\tconst hasExternalIdTracking = enabledNames.has('external_id_tracking');\n\n\treturn {\n\t\tconfigs: normalized,\n\t\tfields,\n\t\tdrizzleImports,\n\t\trepositoryConfig: {\n\t\t\ttimestamps: hasTimestamps,\n\t\t\tsoftDelete: hasSoftDelete,\n\t\t\tuserTracking: hasUserTracking,\n\t\t\tversionable: false, // Future behavior\n\t\t},\n\t\thasBehaviors: normalized.length > 0,\n\t\thasTimestamps,\n\t\thasSoftDelete,\n\t\thasUserTracking,\n\t\thasExternalIdTracking,\n\t};\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\nexport type {\n\tBehaviorConfig,\n\tBehaviorDefinition,\n\tBehaviorField,\n\tNormalizedBehaviorConfig,\n\tResolvedBehaviors,\n\tValidationResult,\n} from './types';\n\nexport { timestampsBehavior } from './timestamps';\nexport { softDeleteBehavior } from './soft-delete';\nexport { userTrackingBehavior } from './user-tracking';\nexport { externalIdTrackingBehavior } from './external-id-tracking';\n","/**\n * Consistency Checker\n *\n * Performs various consistency checks on the domain model:\n * - Missing relationship targets\n * - Missing inverse relationships\n * - Missing indexes on filterable fields\n * - Orphan entities (no relationships)\n * - Circular dependencies\n * - Naming conventions\n * - Missing UI metadata\n */\n\nimport type { ParsedEntity, DomainGraph, AnalysisIssue } from './types';\nimport { findOrphanEntities, findCircularDependencies } from './graph-builder';\nimport { resolveBehaviorFields } from '../behaviors/index';\n\n/**\n * Run all consistency checks on the domain graph\n */\nexport function checkConsistency(graph: DomainGraph): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\n\t// Check each entity\n\tfor (const [name, entity] of graph.entities) {\n\t\tissues.push(...checkEntityConsistency(entity));\n\t\tissues.push(...checkRelationshipConsistency(entity, graph));\n\t\tissues.push(...checkNamingConventions(entity));\n\t\tissues.push(...checkMissingIndexes(entity));\n\t\tissues.push(...checkUiMetadata(entity));\n\t\tif (entity.queries !== undefined) {\n\t\t\tissues.push(...checkQueryFieldReferences(entity));\n\t\t}\n\t\tif (entity.sync !== undefined) {\n\t\t\tissues.push(...checkSyncFieldMappingReferences(entity));\n\t\t\tissues.push(...checkExternalIdTrackingCollision(entity));\n\t\t}\n\t}\n\n\t// Check graph-level issues\n\tissues.push(...checkOrphanEntities(graph));\n\tissues.push(...checkCircularReferences(graph));\n\tissues.push(...checkMissingInverses(graph));\n\n\treturn issues;\n}\n\n/**\n * Check entity-level consistency\n */\nfunction checkEntityConsistency(entity: ParsedEntity): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\n\t// Check for missing primary key\n\tif (!entity.fields.has('id')) {\n\t\tissues.push({\n\t\t\tseverity: 'info',\n\t\t\ttype: 'missing_id',\n\t\t\tentity: entity.name,\n\t\t\tmessage: 'Entity missing standard \"id\" field',\n\t\t\tsuggestion: 'Add an \"id\" field with type \"uuid\"',\n\t\t});\n\t}\n\n\t// Check for missing timestamps\n\tconst hasCreatedAt = entity.fields.has('created_at');\n\tconst hasTimestampsBehavior = entity.behaviors.includes('timestamps');\n\n\tif (!hasCreatedAt && !hasTimestampsBehavior) {\n\t\tissues.push({\n\t\t\tseverity: 'info',\n\t\t\ttype: 'missing_timestamps',\n\t\t\tentity: entity.name,\n\t\t\tmessage: 'Entity missing \"created_at\" field and \"timestamps\" behavior',\n\t\t\tsuggestion: 'Add \"timestamps\" to behaviors or add created_at/updated_at fields',\n\t\t});\n\t}\n\n\treturn issues;\n}\n\n/**\n * Check relationship consistency\n */\nfunction checkRelationshipConsistency(\n\tentity: ParsedEntity,\n\tgraph: DomainGraph\n): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\n\tfor (const [relName, rel] of entity.relationships) {\n\t\t// Check for belongs_to without matching foreign key field\n\t\tif (rel.type === 'belongs_to') {\n\t\t\tconst fkField = entity.fields.get(rel.foreignKey);\n\t\t\tif (!fkField) {\n\t\t\t\tissues.push({\n\t\t\t\t\tseverity: 'warning',\n\t\t\t\t\ttype: 'missing_fk_field',\n\t\t\t\t\tentity: entity.name,\n\t\t\t\t\tfield: relName,\n\t\t\t\t\tmessage: `Relationship \"${relName}\" references foreign key \"${rel.foreignKey}\" but field doesn't exist`,\n\t\t\t\t\tsuggestion: `Add field \"${rel.foreignKey}\" with foreign_key reference`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Check for has_many relationships - target should have the FK field\n\t\tif (rel.type === 'has_many' || rel.type === 'has_one') {\n\t\t\tconst targetEntity = graph.entities.get(rel.target);\n\t\t\tif (targetEntity) {\n\t\t\t\tconst targetFkField = targetEntity.fields.get(rel.foreignKey);\n\t\t\t\tif (!targetFkField) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tseverity: 'warning',\n\t\t\t\t\t\ttype: 'missing_target_fk',\n\t\t\t\t\t\tentity: entity.name,\n\t\t\t\t\t\tfield: relName,\n\t\t\t\t\t\tmessage: `Relationship \"${relName}\" expects foreign key \"${rel.foreignKey}\" on \"${rel.target}\" but field doesn't exist`,\n\t\t\t\t\t\tsuggestion: `Add field \"${rel.foreignKey}\" to \"${rel.target}\" entity`,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn issues;\n}\n\n/**\n * Check naming conventions\n */\nfunction checkNamingConventions(entity: ParsedEntity): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\n\t// Entity name should be lowercase snake_case\n\tif (entity.name !== entity.name.toLowerCase()) {\n\t\tissues.push({\n\t\t\tseverity: 'warning',\n\t\t\ttype: 'naming_convention',\n\t\t\tentity: entity.name,\n\t\t\tmessage: 'Entity name should be lowercase',\n\t\t\tsuggestion: `Use \"${entity.name.toLowerCase()}\"`,\n\t\t});\n\t}\n\n\t// Check field naming\n\tfor (const [fieldName] of entity.fields) {\n\t\tif (fieldName !== fieldName.toLowerCase()) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'warning',\n\t\t\t\ttype: 'naming_convention',\n\t\t\t\tentity: entity.name,\n\t\t\t\tfield: fieldName,\n\t\t\t\tmessage: 'Field name should be snake_case',\n\t\t\t\tsuggestion: `Use \"${toSnakeCase(fieldName)}\"`,\n\t\t\t});\n\t\t}\n\t}\n\n\t// Check relationship naming\n\tfor (const [relName] of entity.relationships) {\n\t\tif (relName !== relName.toLowerCase()) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'warning',\n\t\t\t\ttype: 'naming_convention',\n\t\t\t\tentity: entity.name,\n\t\t\t\tfield: relName,\n\t\t\t\tmessage: 'Relationship name should be snake_case',\n\t\t\t\tsuggestion: `Use \"${toSnakeCase(relName)}\"`,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn issues;\n}\n\n/**\n * Check for missing indexes on filterable fields\n */\nfunction checkMissingIndexes(entity: ParsedEntity): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\n\tfor (const [fieldName, field] of entity.fields) {\n\t\t// Check if field is marked as filterable but has no index\n\t\tif (field.ui.filterable && !field.index && !field.unique) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'warning',\n\t\t\t\ttype: 'missing_index',\n\t\t\t\tentity: entity.name,\n\t\t\t\tfield: fieldName,\n\t\t\t\tmessage: `Field \"${fieldName}\" is filterable but has no index`,\n\t\t\t\tsuggestion: 'Add \"index: true\" to improve query performance',\n\t\t\t});\n\t\t}\n\n\t\t// Foreign key fields should typically have an index\n\t\tif (field.foreignKey && !field.index && !field.unique) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'info',\n\t\t\t\ttype: 'missing_fk_index',\n\t\t\t\tentity: entity.name,\n\t\t\t\tfield: fieldName,\n\t\t\t\tmessage: `Foreign key field \"${fieldName}\" has no index`,\n\t\t\t\tsuggestion: 'Add \"index: true\" for better join performance',\n\t\t\t});\n\t\t}\n\t}\n\n\treturn issues;\n}\n\n/**\n * Check for missing UI metadata\n */\nfunction checkUiMetadata(entity: ParsedEntity): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\n\t// System fields that don't need UI metadata\n\tconst systemFields = new Set(['id', 'created_at', 'updated_at', 'deleted_at', 'tenant_id']);\n\n\tfor (const [fieldName, field] of entity.fields) {\n\t\tif (systemFields.has(fieldName)) continue;\n\n\t\tconst hasAnyUiMeta =\n\t\t\tfield.ui.label !== undefined ||\n\t\t\tfield.ui.type !== undefined ||\n\t\t\tfield.ui.group !== undefined;\n\n\t\tif (!hasAnyUiMeta) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'info',\n\t\t\t\ttype: 'missing_ui_metadata',\n\t\t\t\tentity: entity.name,\n\t\t\t\tfield: fieldName,\n\t\t\t\tmessage: `Field \"${fieldName}\" has no UI metadata`,\n\t\t\t\tsuggestion: 'Add ui_label, ui_type, ui_group for better admin panel display',\n\t\t\t});\n\t\t}\n\t}\n\n\treturn issues;\n}\n\n/**\n * Check for orphan entities\n */\nfunction checkOrphanEntities(graph: DomainGraph): AnalysisIssue[] {\n\tconst orphans = findOrphanEntities(graph);\n\treturn orphans.map((name) => ({\n\t\tseverity: 'info' as const,\n\t\ttype: 'orphan_entity',\n\t\tentity: name,\n\t\tmessage: `Entity \"${name}\" has no relationships to other entities`,\n\t\tsuggestion: 'Consider if this entity should be related to others',\n\t}));\n}\n\n/**\n * Check for circular references\n */\nfunction checkCircularReferences(graph: DomainGraph): AnalysisIssue[] {\n\tconst cycles = findCircularDependencies(graph);\n\treturn cycles.map((cycle) => ({\n\t\tseverity: 'info' as const,\n\t\ttype: 'circular_dependency',\n\t\tentity: cycle[0],\n\t\tmessage: `Circular reference detected: ${cycle.join(' -> ')}`,\n\t\tsuggestion: 'Verify this is intentional (e.g., self-referential hierarchy)',\n\t}));\n}\n\n/**\n * Check for missing inverse relationships\n */\nfunction checkMissingInverses(graph: DomainGraph): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\n\tfor (const edge of graph.edges) {\n\t\tconst { from, to, relationship } = edge;\n\t\tconst targetEntity = graph.entities.get(to);\n\t\tif (!targetEntity) continue;\n\n\t\t// Check if target has an inverse relationship back to source\n\t\tconst hasInverse = Array.from(targetEntity.relationships.values()).some(\n\t\t\t(rel) => rel.target === from\n\t\t);\n\n\t\t// belongs_to relationships typically don't need explicit inverses\n\t\t// (the has_many on the other side serves as the inverse)\n\t\tif (!hasInverse && relationship.type !== 'belongs_to') {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'info',\n\t\t\t\ttype: 'missing_inverse',\n\t\t\t\tentity: from,\n\t\t\t\tfield: relationship.name,\n\t\t\t\tmessage: `Relationship \"${relationship.name}\" to \"${to}\" has no inverse defined on target`,\n\t\t\t\tsuggestion: `Add inverse relationship on \"${to}\" pointing back to \"${from}\"`,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn issues;\n}\n\n/**\n * Get the set of all valid field names for an entity, including behavior-added fields\n * and belongs_to foreign key fields (which the template emits as columns even when\n * not explicitly declared under `fields:`).\n */\nfunction getAvailableFieldNames(entity: ParsedEntity): string[] {\n\tconst entityFieldNames = Array.from(entity.fields.keys());\n\tconst behaviorFields = resolveBehaviorFields(entity.behaviors);\n\tconst behaviorFieldNames = behaviorFields.map((f) => f.name);\n\tconst belongsToFkNames: string[] = [];\n\tfor (const rel of entity.relationships.values()) {\n\t\tif (rel.type === 'belongs_to' && rel.foreignKey) {\n\t\t\tbelongsToFkNames.push(rel.foreignKey);\n\t\t}\n\t}\n\treturn [...new Set([...entityFieldNames, ...behaviorFieldNames, ...belongsToFkNames])];\n}\n\n/**\n * Check that query.by and query.select fields reference existing entity fields\n */\nfunction checkQueryFieldReferences(entity: ParsedEntity): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\tconst availableFields = getAvailableFieldNames(entity);\n\tconst availableSet = new Set(availableFields);\n\n\tfor (const query of entity.queries ?? []) {\n\t\t// Skip by-field validation when via is specified — those fields come from the junction table\n\t\tif (!query.via) {\n\t\t\tfor (const fieldName of query.by) {\n\t\t\t\tif (!availableSet.has(fieldName)) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tseverity: 'error',\n\t\t\t\t\t\ttype: 'unknown_query_field',\n\t\t\t\t\t\tentity: entity.name,\n\t\t\t\t\t\tfield: fieldName,\n\t\t\t\t\t\tmessage: `Query references unknown field \"${fieldName}\" in entity \"${entity.name}\". Available fields: ${availableFields.join(', ')}`,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (const fieldName of query.select ?? []) {\n\t\t\tif (!availableSet.has(fieldName)) {\n\t\t\t\tissues.push({\n\t\t\t\t\tseverity: 'error',\n\t\t\t\t\ttype: 'unknown_query_field',\n\t\t\t\t\tentity: entity.name,\n\t\t\t\t\tfield: fieldName,\n\t\t\t\t\tmessage: `Query references unknown field \"${fieldName}\" in entity \"${entity.name}\". Available fields: ${availableFields.join(', ')}`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn issues;\n}\n\n/**\n * Check that sync field_mapping keys and read_only_fields reference existing entity fields\n */\nfunction checkSyncFieldMappingReferences(entity: ParsedEntity): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\tconst availableFields = getAvailableFieldNames(entity);\n\tconst availableSet = new Set(availableFields);\n\n\tfor (const [providerName, provider] of Object.entries(entity.sync?.providers ?? {})) {\n\t\tfor (const fieldName of Object.keys(provider.fieldMapping ?? {})) {\n\t\t\tif (!availableSet.has(fieldName)) {\n\t\t\t\tissues.push({\n\t\t\t\t\tseverity: 'warning',\n\t\t\t\t\ttype: 'unknown_sync_field_mapping',\n\t\t\t\t\tentity: entity.name,\n\t\t\t\t\tfield: fieldName,\n\t\t\t\t\tmessage: `Sync field mapping references unknown field \"${fieldName}\" for provider \"${providerName}\" in entity \"${entity.name}\"`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tfor (const fieldName of provider.readOnlyFields ?? []) {\n\t\t\tif (!availableSet.has(fieldName)) {\n\t\t\t\tissues.push({\n\t\t\t\t\tseverity: 'warning',\n\t\t\t\t\ttype: 'unknown_sync_field_mapping',\n\t\t\t\t\tentity: entity.name,\n\t\t\t\t\tfield: fieldName,\n\t\t\t\t\tmessage: `Sync field mapping references unknown field \"${fieldName}\" for provider \"${providerName}\" in entity \"${entity.name}\"`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn issues;\n}\n\n/**\n * Check for potential collision between external_id_tracking behavior and sync field_mapping\n */\nfunction checkExternalIdTrackingCollision(entity: ParsedEntity): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\n\tconst hasExternalIdTracking = entity.behaviors.includes('external_id_tracking');\n\tif (!hasExternalIdTracking) return issues;\n\n\tfor (const [providerName, provider] of Object.entries(entity.sync?.providers ?? {})) {\n\t\tif (provider.fieldMapping && 'external_id' in provider.fieldMapping) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'warning',\n\t\t\t\ttype: 'external_id_tracking_collision',\n\t\t\t\tentity: entity.name,\n\t\t\t\tfield: 'external_id',\n\t\t\t\tmessage: `Entity \"${entity.name}\" has external_id_tracking behavior and also maps \"external_id\" in sync field_mapping for provider \"${providerName}\". The behavior-added field may collide with the mapped field.`,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn issues;\n}\n\n/**\n * Convert string to snake_case\n */\nfunction toSnakeCase(str: string): string {\n\treturn str\n\t\t.replace(/([A-Z])/g, '_$1')\n\t\t.toLowerCase()\n\t\t.replace(/^_/, '');\n}\n","/**\n * Statistics\n *\n * Computes statistics about the domain model:\n * - Entity counts\n * - Field counts and type distribution\n * - Relationship counts and type distribution\n */\n\nimport type { ParsedEntity, DomainGraph, DomainStatistics } from './types';\n\n/**\n * Compute domain statistics from the graph\n */\nexport function computeStatistics(graph: DomainGraph): DomainStatistics {\n\tconst entities = Array.from(graph.entities.values());\n\n\tconst fieldsByType: Record<string, number> = {};\n\tconst relationshipsByType: Record<string, number> = {};\n\tlet totalFields = 0;\n\tlet totalRelationships = 0;\n\tlet entitiesWithBehaviors = 0;\n\n\tfor (const entity of entities) {\n\t\ttotalFields += entity.fields.size;\n\t\ttotalRelationships += entity.relationships.size;\n\n\t\tif (entity.behaviors.length > 0) {\n\t\t\tentitiesWithBehaviors++;\n\t\t}\n\n\t\t// Count fields by type\n\t\tfor (const field of entity.fields.values()) {\n\t\t\tfieldsByType[field.type] = (fieldsByType[field.type] ?? 0) + 1;\n\t\t}\n\n\t\t// Count relationships by type\n\t\tfor (const rel of entity.relationships.values()) {\n\t\t\trelationshipsByType[rel.type] = (relationshipsByType[rel.type] ?? 0) + 1;\n\t\t}\n\t}\n\n\treturn {\n\t\ttotalEntities: entities.length,\n\t\ttotalFields,\n\t\ttotalRelationships,\n\t\tfieldsByType,\n\t\trelationshipsByType,\n\t\tentitiesWithBehaviors,\n\t\taverageFieldsPerEntity: entities.length > 0 ? totalFields / entities.length : 0,\n\t};\n}\n\n/**\n * Get a breakdown of field properties\n */\nexport function getFieldBreakdown(graph: DomainGraph): {\n\trequired: number;\n\tnullable: number;\n\tindexed: number;\n\tunique: number;\n\twithForeignKey: number;\n\twithConstraints: number;\n} {\n\tlet required = 0;\n\tlet nullable = 0;\n\tlet indexed = 0;\n\tlet unique = 0;\n\tlet withForeignKey = 0;\n\tlet withConstraints = 0;\n\n\tfor (const entity of graph.entities.values()) {\n\t\tfor (const field of entity.fields.values()) {\n\t\t\tif (field.required) required++;\n\t\t\tif (field.nullable) nullable++;\n\t\t\tif (field.index) indexed++;\n\t\t\tif (field.unique) unique++;\n\t\t\tif (field.foreignKey) withForeignKey++;\n\n\t\t\tconst hasConstraints =\n\t\t\t\tfield.constraints.minLength !== undefined ||\n\t\t\t\tfield.constraints.maxLength !== undefined ||\n\t\t\t\tfield.constraints.min !== undefined ||\n\t\t\t\tfield.constraints.max !== undefined;\n\t\t\tif (hasConstraints) withConstraints++;\n\t\t}\n\t}\n\n\treturn { required, nullable, indexed, unique, withForeignKey, withConstraints };\n}\n\n/**\n * Get UI metadata coverage statistics\n */\nexport function getUiMetadataCoverage(graph: DomainGraph): {\n\twithLabel: number;\n\twithType: number;\n\twithGroup: number;\n\twithImportance: number;\n\ttotal: number;\n} {\n\tlet withLabel = 0;\n\tlet withType = 0;\n\tlet withGroup = 0;\n\tlet withImportance = 0;\n\tlet total = 0;\n\n\tfor (const entity of graph.entities.values()) {\n\t\tfor (const field of entity.fields.values()) {\n\t\t\ttotal++;\n\t\t\tif (field.ui.label) withLabel++;\n\t\t\tif (field.ui.type) withType++;\n\t\t\tif (field.ui.group) withGroup++;\n\t\t\tif (field.ui.importance) withImportance++;\n\t\t}\n\t}\n\n\treturn { withLabel, withType, withGroup, withImportance, total };\n}\n","/**\n * Pattern Registry — library + app pattern storage and discovery.\n *\n * Three stores keyed by pattern name:\n * - `LIBRARY_PATTERNS` — seeded by the codegen package itself when the\n * `src/patterns/library/*` barrel imports execute. Consumers never\n * list these in `codegen.config.yaml patterns:`. Domain only.\n * - `APP_PATTERNS` — populated by `loadAppPatterns()` from a\n * consumer-supplied glob set (default `src/patterns/*.pattern.ts`).\n * Domain only.\n * - `ORCHESTRATION_APP_PATTERNS` — populated by the same loader,\n * routed by `kind: 'orchestration'` (ADR-032). No library\n * orchestration patterns ship in Phase 3-1.\n *\n * `getPattern()` checks app patterns first so a consumer could, in\n * principle, shadow a library pattern by using the same `name`. That's\n * not a documented feature, but nothing in the API prevents it.\n *\n * The Hygen subprocess (`src/cli/shared/hygen.ts:64`) reloads this module\n * independently — it has no shared memory with the CLI process. Both\n * loads are deterministic, side-effect-free reads of the same files, so\n * the registry contents are identical across processes. The registry\n * test suite asserts this determinism explicitly.\n *\n * See `docs/adrs/ADR-031-app-defined-patterns.md` §\"Decision 5\" and\n * `docs/specs/app-defined-patterns-implementation.md` §3.\n */\n\nimport { glob } from 'glob';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport {\n\tisOrchestrationPattern,\n\tisPatternDefinition,\n\ttype AnyPatternDefinition,\n\ttype OrchestrationPatternDefinition,\n\ttype PatternDefinition,\n} from './pattern-definition.js';\n\n// ============================================================================\n// Stores\n// ============================================================================\n\nconst LIBRARY_PATTERNS: Map<string, PatternDefinition> = new Map();\nconst APP_PATTERNS: Map<string, PatternDefinition> = new Map();\n\n/**\n * Orchestration patterns (ADR-032). Library never ships orchestration\n * patterns in Phase 3-1 — only the app-pattern map exists for this kind.\n * If a library-shipped orchestration pattern ever lands, add a parallel\n * `LIBRARY_ORCHESTRATION_PATTERNS` map; for now keep storage minimal.\n */\nconst ORCHESTRATION_APP_PATTERNS: Map<string, OrchestrationPatternDefinition> =\n\tnew Map();\n\n/**\n * Every pattern must contribute *something* — either at least one column\n * or at least one of the two class references. A pattern that contributes\n * nothing would generate no useful output and almost certainly indicates\n * a typo or an unfinished definition.\n */\nfunction assertHasContribution(def: PatternDefinition): void {\n\tconst hasColumns = Array.isArray(def.columns) && def.columns.length > 0;\n\tconst hasRepo =\n\t\ttypeof def.repositoryClass === 'string' && def.repositoryClass.length > 0;\n\tconst hasService =\n\t\ttypeof def.serviceClass === 'string' && def.serviceClass.length > 0;\n\n\tif (!hasColumns && !hasRepo && !hasService) {\n\t\tthrow new Error(\n\t\t\t`Pattern '${def.name}' contributes nothing — at least one of ` +\n\t\t\t\t'`columns`, `repositoryClass`, or `serviceClass` is required.',\n\t\t);\n\t}\n}\n\n/**\n * Orchestration counterpart to `assertHasContribution`. An orchestration\n * pattern's minimum contribution is one registry with at least one entry —\n * a registry with zero entries would emit a token + module that nothing\n * resolves to, almost certainly a typo. Detailed entry validation\n * (duplicate keys, malformed entries, co-keyed mismatches) lives in the\n * project-level validator so loader behaviour stays symmetrical with the\n * domain side: load is non-throwing for content-level issues, validator\n * is the single authoritative reporter.\n */\nfunction assertOrchestrationContribution(\n\tdef: OrchestrationPatternDefinition,\n): void {\n\tif (!def.registry || typeof def.registry !== 'object') {\n\t\tthrow new Error(\n\t\t\t`Orchestration pattern '${def.name}' is missing a 'registry' field.`,\n\t\t);\n\t}\n\tif (\n\t\ttypeof def.registry.keyType !== 'string' ||\n\t\tdef.registry.keyType.length === 0\n\t) {\n\t\tthrow new Error(\n\t\t\t`Orchestration pattern '${def.name}' registry.keyType must be a non-empty string.`,\n\t\t);\n\t}\n\tif (\n\t\ttypeof def.registry.valueType !== 'string' ||\n\t\tdef.registry.valueType.length === 0\n\t) {\n\t\tthrow new Error(\n\t\t\t`Orchestration pattern '${def.name}' registry.valueType must be a non-empty string.`,\n\t\t);\n\t}\n\tif (\n\t\t!Array.isArray(def.registry.entries) ||\n\t\tdef.registry.entries.length === 0\n\t) {\n\t\tthrow new Error(\n\t\t\t`Orchestration pattern '${def.name}' registry.entries must contain at least one entry.`,\n\t\t);\n\t}\n}\n\n// ============================================================================\n// Library pattern registration\n// ============================================================================\n\n/**\n * Insert a library pattern into the registry. Called once by each\n * `src/patterns/library/*.pattern.ts` file via the barrel. Re-registering\n * the same name overwrites the previous value silently; this is\n * intentional for hot-reload scenarios but should not happen in normal\n * use.\n */\nexport function registerLibraryPattern(def: PatternDefinition): void {\n\tassertHasContribution(def);\n\tLIBRARY_PATTERNS.set(def.name, def);\n}\n\n// ============================================================================\n// Lookup\n// ============================================================================\n\n/**\n * Resolve a **domain** pattern by name. App patterns shadow library\n * patterns with the same name — useful in principle but not a documented\n * feature.\n *\n * Orchestration patterns live in a disjoint store; use\n * `getOrchestrationPattern()` to look those up. The two surfaces are\n * intentionally separate (ADR-032 Decision 8) so callers don't have to\n * narrow the result on every callsite.\n */\nexport function getPattern(name: string): PatternDefinition | undefined {\n\treturn APP_PATTERNS.get(name) ?? LIBRARY_PATTERNS.get(name);\n}\n\n/**\n * Return every registered domain pattern name (library + app), sorted for\n * deterministic output. The two-process determinism test relies on this\n * ordering being stable across processes. Orchestration names are NOT\n * included — see `getOrchestrationPatternNames()`.\n */\nexport function getAllPatternNames(): string[] {\n\tconst set = new Set<string>([\n\t\t...LIBRARY_PATTERNS.keys(),\n\t\t...APP_PATTERNS.keys(),\n\t]);\n\treturn [...set].sort();\n}\n\n/** Library-only view — mainly for debugging and tests. */\nexport function getLibraryPatternNames(): string[] {\n\treturn [...LIBRARY_PATTERNS.keys()].sort();\n}\n\n/** App-only view — mainly for debugging and tests. */\nexport function getAppPatternNames(): string[] {\n\treturn [...APP_PATTERNS.keys()].sort();\n}\n\n// ============================================================================\n// Orchestration accessors (ADR-032)\n// ============================================================================\n\n/** Resolve an orchestration pattern by name. */\nexport function getOrchestrationPattern(\n\tname: string,\n): OrchestrationPatternDefinition | undefined {\n\treturn ORCHESTRATION_APP_PATTERNS.get(name);\n}\n\n/** Sorted list of orchestration pattern names. */\nexport function getOrchestrationPatternNames(): string[] {\n\treturn [...ORCHESTRATION_APP_PATTERNS.keys()].sort();\n}\n\n/**\n * Every registered orchestration pattern, sorted by name. The\n * project-level validator iterates this list in one place so issue\n * ordering is stable across processes.\n */\nexport function getAllOrchestrationPatterns(): OrchestrationPatternDefinition[] {\n\treturn getOrchestrationPatternNames().map(\n\t\t(n) => ORCHESTRATION_APP_PATTERNS.get(n)!,\n\t);\n}\n\n// ============================================================================\n// App pattern discovery\n// ============================================================================\n\nexport interface LoadAppPatternsResult {\n\t/** Pattern names that were successfully registered, sorted */\n\tloaded: string[];\n\t/** One human-readable error per failed file import */\n\terrors: string[];\n}\n\n/**\n * Expand every glob in `manifestPaths` relative to `cwd`, dynamic-import\n * each matching file, and register every exported value that passes\n * `isPatternDefinition()`. Exports whose name ends in `Pattern` and\n * pass the shape check are registered; other exports are ignored so\n * that files can export helper values alongside their pattern.\n *\n * Import failures are non-fatal — the error is collected and returned\n * so the CLI can surface it without breaking generation of unrelated\n * entities. A pattern that fails the \"at-least-one-contribution\" check\n * surfaces here as an error too.\n *\n * Idempotent: calling twice with the same arguments leaves `APP_PATTERNS`\n * in the same state as calling once.\n */\nexport async function loadAppPatterns(\n\tmanifestPaths: string[],\n\tcwd: string,\n): Promise<LoadAppPatternsResult> {\n\tconst loaded = new Set<string>();\n\tconst errors: string[] = [];\n\n\t// Collect + dedupe absolute file paths across every glob pattern so\n\t// a file matched by two globs is imported once.\n\tconst files = new Set<string>();\n\tfor (const raw of manifestPaths) {\n\t\ttry {\n\t\t\tconst expanded = await glob(raw, { cwd, absolute: true, nodir: true });\n\t\t\tfor (const filePath of expanded) {\n\t\t\t\tfiles.add(filePath);\n\t\t\t}\n\t\t} catch (err) {\n\t\t\terrors.push(\n\t\t\t\t`Failed to expand pattern glob '${raw}': ${stringifyError(err)}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// Sort so dynamic-import order is deterministic across processes —\n\t// the Hygen subprocess relies on this to produce the same registry\n\t// as the CLI.\n\tconst sortedFiles = [...files].sort();\n\n\tfor (const filePath of sortedFiles) {\n\t\ttry {\n\t\t\t// `pathToFileURL` is required for absolute-path dynamic imports on\n\t\t\t// Windows and makes the behavior identical on macOS/Linux.\n\t\t\tconst mod = (await import(pathToFileURL(filePath).href)) as Record<\n\t\t\t\tstring,\n\t\t\t\tunknown\n\t\t\t>;\n\t\t\tfor (const [key, val] of Object.entries(mod)) {\n\t\t\t\tif (!key.endsWith('Pattern')) continue;\n\t\t\t\tif (!isPatternDefinition(val)) continue;\n\n\t\t\t\t// Route on `kind`. Domain (default) and orchestration land in\n\t\t\t\t// disjoint maps; same-name collisions within either map are\n\t\t\t\t// load-time errors (silent overwrite was wrong by CLAUDE.md\n\t\t\t\t// \"architectural correctness\" — see ADR-032 §Composition rules\n\t\t\t\t// row 1).\n\t\t\t\tif (isOrchestrationPattern(val as unknown as AnyPatternDefinition)) {\n\t\t\t\t\tconst orch = val as unknown as OrchestrationPatternDefinition;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tassertOrchestrationContribution(orch);\n\t\t\t\t\t} catch (assertErr) {\n\t\t\t\t\t\terrors.push(\n\t\t\t\t\t\t\t`Orchestration pattern '${orch.name}' in ${relPath(filePath, cwd)} is invalid: ${stringifyError(assertErr)}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tconst existingOrch = ORCHESTRATION_APP_PATTERNS.get(orch.name);\n\t\t\t\t\tif (existingOrch && existingOrch !== orch) {\n\t\t\t\t\t\terrors.push(\n\t\t\t\t\t\t\t`Orchestration pattern '${orch.name}' in ${relPath(filePath, cwd)} duplicates a previously loaded orchestration pattern. Pattern names must be unique.`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tORCHESTRATION_APP_PATTERNS.set(orch.name, orch);\n\t\t\t\t\tloaded.add(orch.name);\n\t\t\t\t} else {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tassertHasContribution(val);\n\t\t\t\t\t} catch (assertErr) {\n\t\t\t\t\t\terrors.push(\n\t\t\t\t\t\t\t`Pattern '${val.name}' in ${relPath(filePath, cwd)} is invalid: ${stringifyError(assertErr)}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tconst existingDom = APP_PATTERNS.get(val.name);\n\t\t\t\t\tif (existingDom && existingDom !== val) {\n\t\t\t\t\t\terrors.push(\n\t\t\t\t\t\t\t`Pattern '${val.name}' in ${relPath(filePath, cwd)} duplicates a previously loaded app pattern. Pattern names must be unique.`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tAPP_PATTERNS.set(val.name, val);\n\t\t\t\t\tloaded.add(val.name);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (err) {\n\t\t\terrors.push(\n\t\t\t\t`Failed to load pattern file '${relPath(filePath, cwd)}': ${stringifyError(err)}`,\n\t\t\t);\n\t\t}\n\t}\n\n\treturn {\n\t\tloaded: [...loaded].sort(),\n\t\terrors,\n\t};\n}\n\n// ============================================================================\n// Test-only reset\n// ============================================================================\n\n/**\n * Clear every registered app pattern and, optionally, library patterns too.\n *\n * Intended for unit tests that build isolated scenarios on top of a clean\n * registry. Not exported from the barrel — tests import it directly from\n * `./registry.js`.\n */\nexport function _resetRegistryForTests(\n\topts: { includeLibrary?: boolean } = {},\n): void {\n\tAPP_PATTERNS.clear();\n\tORCHESTRATION_APP_PATTERNS.clear();\n\tif (opts.includeLibrary) {\n\t\tLIBRARY_PATTERNS.clear();\n\t}\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction stringifyError(err: unknown): string {\n\tif (err instanceof Error) return err.message;\n\treturn String(err);\n}\n\nfunction relPath(abs: string, cwd: string): string {\n\ttry {\n\t\treturn path.relative(cwd, abs) || abs;\n\t} catch {\n\t\treturn abs;\n\t}\n}\n","/**\n * Pattern Definition — pure metadata record returned by an identity function.\n *\n * `definePattern()` is the registration artifact for both library-shipped and\n * app-defined patterns. It carries only names + import paths for the classes\n * a generated entity should extend — never the class constructors themselves.\n * This keeps the codegen pipeline free of TS class-evaluation cost and avoids\n * `reflect-metadata`, which lets the Hygen subprocess cheaply rebuild the\n * registry (see `src/cli/shared/hygen.ts` — the registry loads twice per\n * `entity new` invocation).\n *\n * Two pattern kinds share this surface:\n * - **domain** (default; ADR-031) — `PatternDefinition`. Contributes\n * repository/service base classes, columns, behaviors to entities that\n * declare `pattern:`/`patterns:` in YAML.\n * - **orchestration** (ADR-032) — `OrchestrationPatternDefinition`. Declares\n * a DI registry + optional dispatcher scaffold. Not entity-attached;\n * codegen emits a NestJS module under `src/orchestration/` instead.\n *\n * See `docs/adrs/ADR-031-app-defined-patterns.md` §\"Decision 1\" for the\n * domain binding surface and `docs/adrs/ADR-032-orchestration-patterns.md`\n * for the orchestration kind.\n */\n\nimport type { ZodSchema } from 'zod';\n\n/**\n * A column a pattern contributes to every entity that declares it.\n *\n * Column-level conflicts between patterns, between a pattern and an\n * entity-declared field, or between a pattern and a behavior-contributed\n * field are codegen-time hard errors; see\n * `src/patterns/validate-composition.ts`.\n */\nexport interface PatternColumnContribution {\n\t/** snake_case column name — matches the database column */\n\tname: string;\n\t/** Drizzle column type string, e.g. \"varchar(255)\" or \"text\" */\n\ttype: string;\n}\n\n/**\n * Discriminator for the two pattern shapes. Default is `\"domain\"` to preserve\n * Phase 1 (ADR-031) behaviour — every existing PatternDefinition without a\n * `kind` field continues to register as a domain pattern.\n */\nexport type PatternKind = 'domain' | 'orchestration';\n\n/**\n * The full pattern metadata record. Every `definePattern({...})` call\n * returns a value of this shape; the library and consumer registries\n * store these and look them up by `name`.\n */\nexport interface PatternDefinition<TConfig = unknown> {\n\t/** Unique name used in YAML — e.g. `pattern: Synced` */\n\tname: string;\n\n\t/**\n\t * ADR-032: defaults to `\"domain\"`. Phase 3 adds `\"orchestration\"` as a\n\t * disjoint shape (see `OrchestrationPatternDefinition`). Domain\n\t * `PatternDefinition` instances must omit this field or set it to\n\t * `\"domain\"`; the loader routes orchestration values to a separate map.\n\t */\n\tkind?: 'domain';\n\n\t/**\n\t * Built-in patterns this extends, by name. Phase 1 supports single-depth\n\t * chains only — a pattern may `extends: ['Synced']` but the transitive\n\t * chain is not yet resolved. Multi-depth inheritance is deferred until\n\t * a real consumer asks.\n\t */\n\textends?: string[];\n\n\t/** Constructor name codegen emits in the generated repo's `extends` clause */\n\trepositoryClass?: string;\n\t/** Constructor name codegen emits in the generated service's `extends` clause */\n\tserviceClass?: string;\n\n\t/**\n\t * Fully-qualified TypeScript path alias the consumer's tsconfig resolves.\n\t * Library patterns use the consumer-installed runtime base class path\n\t * (e.g. `@shared/base-classes/synced-entity-repository`); app patterns\n\t * use whatever alias the consumer has configured (e.g. `@/patterns/...`).\n\t */\n\trepositoryImport?: string;\n\t/** Same as `repositoryImport` but for the service base class */\n\tserviceImport?: string;\n\n\t/**\n\t * Documentation-only method-signature strings emitted as comments in the\n\t * generated repo. Exist purely so app authors reading the generated file\n\t * see what their concrete class inherits without jumping to the base.\n\t */\n\trepositoryInheritedMethods?: string[];\n\t/** Same as `repositoryInheritedMethods` but for the service base class */\n\tserviceInheritedMethods?: string[];\n\n\t/**\n\t * Columns this pattern adds to every entity that declares it. Used by\n\t * the composition validator to detect column-name collisions.\n\t */\n\tcolumns?: PatternColumnContribution[];\n\n\t/**\n\t * Behaviors this pattern implicitly enables. Entity YAML need not\n\t * re-declare them; duplicates across patterns are silent-deduped.\n\t */\n\timpliedBehaviors?: string[];\n\n\t/**\n\t * Zod schema that validates the per-entity `config:` block for this\n\t * pattern at parse time. When absent, entities may not supply a `config:`\n\t * entry for this pattern and codegen emits no `patternConfig` property.\n\t */\n\tconfigSchema?: ZodSchema<TConfig>;\n\n\t/** One-line description for codegen help output and error messages */\n\tdescription?: string;\n}\n\n/**\n * Identity function that returns its argument unchanged. The body is trivial\n * on purpose — the whole point is to give TypeScript a hook for generic\n * inference on `TConfig` while leaving the runtime value a plain object\n * registered by the codegen loader.\n */\nexport function definePattern<TConfig = unknown>(\n\tdef: PatternDefinition<TConfig>,\n): PatternDefinition<TConfig> {\n\treturn def;\n}\n\n/**\n * Shape check for values produced by `import()`ing an app pattern file.\n * The registry loader runs this on every exported value it finds; only\n * values that pass are registered.\n *\n * We keep this deliberately loose — a `name` string is the whole\n * requirement — because a pattern that contributes neither columns nor\n * class references is still a *valid* identity pattern (e.g. `BasePattern`\n * exists to anchor the `extends` chain without contributing anything).\n * Stricter shape rules belong in the registry's \"at-least-one-contribution\"\n * check, not here.\n *\n * This function is intentionally **kind-agnostic** — both\n * `PatternDefinition` (domain) and `OrchestrationPatternDefinition`\n * (orchestration) pass. The discriminator routing happens in the loader\n * via `isOrchestrationPattern()`/`isDomainPattern()`.\n */\nexport function isPatternDefinition(val: unknown): val is PatternDefinition {\n\treturn (\n\t\ttypeof val === 'object' &&\n\t\tval !== null &&\n\t\t'name' in val &&\n\t\ttypeof (val as { name: unknown }).name === 'string'\n\t);\n}\n\n// ============================================================================\n// Orchestration kind (ADR-032)\n// ============================================================================\n\n/**\n * One registry's declarative shape. ADR-032 §\"The Proposal\".\n *\n * Phase 3-1 records this; Phase 3-2 codegen reads it to emit token files,\n * provider blocks, and dispatcher overload signatures. Phase 3-1 validates\n * only what is statically checkable from this record alone — see\n * `validate-orchestration.ts` for the rules and their deferral notes.\n */\nexport interface OrchestrationRegistrySpec {\n\t/**\n\t * Identifier for co-keyed sibling registries (ADR-032 Phase 3-2/3, O-1).\n\t *\n\t * The PRIMARY registry never carries a `name` — its tokens / methods are\n\t * derived from the pattern name alone (`${PATTERN_CONST}_REGISTRY`,\n\t * `select(...)`). Each co-keyed sibling MUST carry an explicit `name`\n\t * which the emitter uppercases for the token suffix and PascalCases for\n\t * the dispatcher method suffix:\n\t *\n\t * `coKeyedRegistries: [{ name: 'auth', valueType: 'IAuthStrategy' ... }]`\n\t * ⇒ `CRM_PORTS_AUTH_REGISTRY` token + `selectAuth(...)` method.\n\t *\n\t * No auto-stripping of \"I\" prefix or \"Strategy/Port/Adapter/Provider\"\n\t * suffixes — authors pick what reads right.\n\t */\n\tname?: string;\n\t/**\n\t * Type alias the consumer's tsconfig resolves (e.g. `\"CrmAdapterDomain\"`).\n\t * Phase 3-1 stores this string verbatim. Resolution that the path actually\n\t * imports a concrete TS enum is deferred to Phase 3-2 emission, where\n\t * codegen will need to read the consumer's source tree.\n\t */\n\tkeyType: string;\n\t/**\n\t * Module specifier the emitter writes into `import type { keyType } from\n\t * '<keyTypeImport>'`. Required at Phase 3-2 emission; the generator emits\n\t * `pattern_missing_import_path` if absent. (ADR-032 Phase 3-2 §3.4 / O-3.)\n\t */\n\tkeyTypeImport?: string;\n\t/** Same shape as `keyType` — the registry's value-type interface ref. */\n\tvalueType: string;\n\t/** Module specifier for `valueType` import. See `keyTypeImport`. */\n\tvalueTypeImport?: string;\n\tentries: ReadonlyArray<{\n\t\t/** Stable string key — must be unique within this registry. */\n\t\tkey: string;\n\t\t/**\n\t\t * Concrete provider class name (NOT a DI token string). Codegen will\n\t\t * import this and use it as the constructor injectable.\n\t\t * Phase 3-1 records it; Phase 3-2 verifies it resolves.\n\t\t */\n\t\tprovider: string;\n\t\t/** Module specifier for `provider` import. See `keyTypeImport`. */\n\t\tproviderImport?: string;\n\t}>;\n}\n\n/**\n * Orchestration pattern — declarative DI registry + optional dispatcher\n * scaffold. ADR-032 §\"The Proposal\" + Decisions 1-8.\n *\n * Disjoint from `PatternDefinition` (domain): no columns, no\n * repository/service base class, no entity-level patternConfig. Composition\n * with domain patterns happens only at the DI layer in the consumer's\n * generated code, not in entity YAML.\n */\nexport interface OrchestrationPatternDefinition {\n\tname: string;\n\tkind: 'orchestration';\n\t/** Primary registry (always present). */\n\tregistry: OrchestrationRegistrySpec;\n\t/**\n\t * Sibling registries that share the primary registry's key space.\n\t * ADR-032 Decision 2 — co-keyed groups are a first-class field.\n\t * Validator enforces matching `keyType` across the group.\n\t */\n\tcoKeyedRegistries?: ReadonlyArray<OrchestrationRegistrySpec>;\n\t/** Optional dispatcher scaffold spec (ADR-032 Decision 4 + 5). */\n\tdispatcher?: {\n\t\t/** Class name to emit (e.g. `\"CrmPortsDispatcher\"`). */\n\t\tclassName: string;\n\t\t/**\n\t\t * Method name the consumer overrides in their subclass to fill the\n\t\t * assembly body (ADR-032 Decision 5).\n\t\t */\n\t\tassemblySlot: string;\n\t};\n\t/** One-line description for help output and error messages. */\n\tdescription?: string;\n}\n\n/** Union for callers that need to handle both shapes. */\nexport type AnyPatternDefinition =\n\t| PatternDefinition\n\t| OrchestrationPatternDefinition;\n\nexport function isOrchestrationPattern(\n\tdef: AnyPatternDefinition,\n): def is OrchestrationPatternDefinition {\n\treturn (def as { kind?: PatternKind }).kind === 'orchestration';\n}\n\nexport function isDomainPattern(\n\tdef: AnyPatternDefinition,\n): def is PatternDefinition {\n\treturn !isOrchestrationPattern(def);\n}\n\n/**\n * Identity function that returns its argument unchanged — orchestration\n * counterpart to `definePattern()`. The body is trivial on purpose; the\n * point is to give TypeScript a hook so consumer fixtures get full\n * compile-time checking against `OrchestrationPatternDefinition`.\n */\nexport function defineOrchestrationPattern(\n\tdef: OrchestrationPatternDefinition,\n): OrchestrationPatternDefinition {\n\treturn def;\n}\n","/**\n * Pattern Composition Validator\n *\n * Enforces the ADR-031 composition rules against parsed entities:\n *\n * | Case | Result |\n * |------------------------------------------------------------|------------------------|\n * | Column conflict between two patterns | error |\n * | Column conflict with entity field | error |\n * | Column conflict with a behavior field | error |\n * | Method-name conflict between patterns | (TS compile error) |\n * | Same implied behavior across patterns | silent dedup |\n * | Pattern referenced in YAML but not in the registry | error |\n * | `config:` key for a pattern the entity is not using | warning |\n * | Pattern config fails its Zod schema | error |\n *\n * Method-name conflicts are explicitly **not** checked here — they surface as\n * TypeScript compile errors at the consumer when the generated concrete\n * class extends the base. Adding a codegen check would duplicate work\n * the type system already does, so we stay silent on that row per ADR-031.\n *\n * Project-level validation (`validatePatternProject`) covers plan Risk 4:\n * entities declaring `pattern:` while `generate.architecture: clean` is\n * selected get a warning since the `clean` pipeline does not yet consume\n * patterns. Additive Phase 3+ work per ADR.\n *\n * The shape mirrors `src/behaviors/index.ts:81–124` (`validateBehaviors`):\n * a single pass that returns structured issues for `analyzeDomain()` to\n * aggregate.\n */\n\nimport type { AnalysisIssue, ParsedEntity } from '../analyzer/types.js';\nimport { resolveBehaviorFields } from '../behaviors/index.js';\nimport { getPattern } from './registry.js';\n\n// ============================================================================\n// Per-entity validation\n// ============================================================================\n\n/**\n * Validate pattern composition for a single entity. Returns an array of\n * `AnalysisIssue` values suitable for concatenation into `analyzeDomain`'s\n * aggregated issue list.\n *\n * Entities with no `pattern:` or `patterns:` declared return an empty\n * array — pattern-free entities are a valid use case (plain `BaseRepository`\n * fallback) and nothing below applies to them.\n */\nexport function validatePatternComposition(\n\tentity: ParsedEntity,\n): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\n\t// Normalise `pattern:` (single) and `patterns:` (multi) into one list,\n\t// preserving declaration order. `pattern` + `patterns` mutual exclusion\n\t// is a schema-level check — by the time we get here, at most one shape\n\t// is set.\n\tconst patternNames: string[] = entity.patterns ?? (entity.pattern ? [entity.pattern] : []);\n\tif (patternNames.length === 0) return issues;\n\n\t// Column-source tracker: maps column name → human-readable origin.\n\t// Populated in priority order (entity fields > behavior fields >\n\t// pattern contributions) so conflict messages name the *existing*\n\t// contributor correctly.\n\tconst columnSources = new Map<string, string>();\n\n\tfor (const [name] of entity.fields) {\n\t\tcolumnSources.set(name, `entity field '${name}'`);\n\t}\n\n\t// Behavior fields participate in conflict detection. Behaviors the\n\t// entity has NOT already declared but that a pattern implies will be\n\t// added below (silent dedup); conflicts against those show up when\n\t// the pattern's columns are checked.\n\tconst behaviorFields = resolveBehaviorFields(entity.behaviors);\n\tfor (const bf of behaviorFields) {\n\t\tconst existing = columnSources.get(bf.name);\n\t\tif (existing) {\n\t\t\t// A behavior field colliding with an entity-declared field\n\t\t\t// was already a codegen problem before patterns existed. We\n\t\t\t// surface it here too so the composition check is the single\n\t\t\t// authoritative pass for \"column conflicts on this entity.\"\n\t\t\tissues.push({\n\t\t\t\tseverity: 'error',\n\t\t\t\ttype: 'pattern_column_conflict',\n\t\t\t\tentity: entity.name,\n\t\t\t\tmessage:\n\t\t\t\t\t`Behavior-contributed field '${bf.name}' conflicts with ${existing}.`,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tcolumnSources.set(bf.name, `behavior field '${bf.name}'`);\n\t}\n\n\t// Track implied behaviors across all declared patterns so we can\n\t// assert silent dedup rather than repeat issues — this also lets us\n\t// return the deduped list for callers that want to thread it into\n\t// template-locals later without re-walking.\n\tconst impliedBehaviors = new Set<string>(entity.behaviors);\n\n\tfor (const patternName of patternNames) {\n\t\tconst def = getPattern(patternName);\n\n\t\t// Rule: pattern referenced in YAML but not in the registry\n\t\tif (!def) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'error',\n\t\t\t\ttype: 'pattern_unknown',\n\t\t\t\tentity: entity.name,\n\t\t\t\tmessage:\n\t\t\t\t\t`Unknown pattern '${patternName}'. ` +\n\t\t\t\t\t`Library patterns are pre-registered; app patterns are loaded from ` +\n\t\t\t\t\t`globs in codegen.config.yaml 'patterns:' (default 'src/patterns/*.pattern.ts').`,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Rule: pattern config must match the pattern's Zod schema\n\t\tif (def.configSchema) {\n\t\t\tconst rawConfig = entity.patternConfig?.[patternName];\n\t\t\tconst result = def.configSchema.safeParse(rawConfig ?? {});\n\t\t\tif (!result.success) {\n\t\t\t\tconst detail = result.error.issues\n\t\t\t\t\t.map((i) => `${i.path.join('.') || '<root>'}: ${i.message}`)\n\t\t\t\t\t.join(', ');\n\t\t\t\tissues.push({\n\t\t\t\t\tseverity: 'error',\n\t\t\t\t\ttype: 'pattern_config_invalid',\n\t\t\t\t\tentity: entity.name,\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t`Pattern '${patternName}' config failed validation: ${detail}`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Rule: column contributions conflict with anything already in the\n\t\t// column-sources table. The first column to claim a name wins; the\n\t\t// second one reports the conflict naming both contributors.\n\t\tfor (const col of def.columns ?? []) {\n\t\t\tconst existing = columnSources.get(col.name);\n\t\t\tif (existing) {\n\t\t\t\tissues.push({\n\t\t\t\t\tseverity: 'error',\n\t\t\t\t\ttype: 'pattern_column_conflict',\n\t\t\t\t\tentity: entity.name,\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t`Pattern '${patternName}' contributes column '${col.name}' ` +\n\t\t\t\t\t\t`which conflicts with ${existing}.`,\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tcolumnSources.set(col.name, `pattern '${patternName}'`);\n\t\t}\n\n\t\t// Silent dedup on implied behaviors — a pattern declaring a\n\t\t// behavior the entity already has (or another pattern already\n\t\t// contributed) is a no-op, not an error.\n\t\tfor (const b of def.impliedBehaviors ?? []) {\n\t\t\timpliedBehaviors.add(b);\n\t\t}\n\t}\n\n\t// Rule: `config:` key for a pattern not in the declared list → warning.\n\tif (entity.patternConfig) {\n\t\tconst declared = new Set(patternNames);\n\t\tfor (const key of Object.keys(entity.patternConfig)) {\n\t\t\tif (!declared.has(key)) {\n\t\t\t\tissues.push({\n\t\t\t\t\tseverity: 'warning',\n\t\t\t\t\ttype: 'pattern_config_unused',\n\t\t\t\t\tentity: entity.name,\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t`Config block has key '${key}' but pattern '${key}' is not ` +\n\t\t\t\t\t\t`declared in 'pattern:' or 'patterns:'. Remove the entry or ` +\n\t\t\t\t\t\t`add the pattern.`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn issues;\n}\n\n// ============================================================================\n// Project-level validation — plan Risk 4\n// ============================================================================\n\nexport interface PatternProjectContext {\n\tentities: ReadonlyArray<ParsedEntity>;\n\t/**\n\t * Selected backend architecture from `codegen.config.yaml\n\t * generate.architecture`. `undefined` when the consumer is using the\n\t * library purely as an analyzer (no generation config loaded).\n\t */\n\tarchitecture?: string;\n}\n\n/**\n * Validate project-level invariants for patterns. Runs after\n * `validatePatternComposition` has visited every entity, so we can\n * assume per-entity errors have been surfaced.\n *\n * Today this only covers plan Risk 4: warn when patterns are declared\n * but the selected architecture is `clean`, which does not yet consume\n * them. A `clean` consumer with `pattern: Synced` is not broken — the\n * `clean` pipeline ignores the key — but they see no effect, which is\n * confusing without the warning.\n */\nexport function validatePatternProject(\n\tctx: PatternProjectContext,\n): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\n\tif (ctx.architecture === 'clean') {\n\t\tconst withPatterns = ctx.entities.filter(\n\t\t\t(e) => (e.patterns && e.patterns.length > 0) || !!e.pattern,\n\t\t);\n\t\tfor (const e of withPatterns) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'warning',\n\t\t\t\ttype: 'pattern_clean_pipeline_noop',\n\t\t\t\tentity: e.name,\n\t\t\t\tmessage:\n\t\t\t\t\t`'pattern:' is declared but 'generate.architecture: clean' does not ` +\n\t\t\t\t\t`yet consume patterns. This declaration is a no-op. Patterns are ` +\n\t\t\t\t\t`consumed by 'clean-lite-ps' today; 'clean' integration is Phase 3+ ` +\n\t\t\t\t\t`additive work (ADR-031).`,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn issues;\n}\n","/**\n * Orchestration Pattern Validator (ADR-032)\n *\n * Project-level only — orchestration patterns are not entity-attached, so\n * there is no per-entity pass. Mirrors `validatePatternProject`'s shape:\n * one pure function consuming a context object and returning structured\n * `AnalysisIssue[]` for `analyzeDomain()` to aggregate.\n *\n * Enforces ADR-032 §\"Composition rules\" to the extent statically checkable\n * from a `OrchestrationPatternDefinition` alone:\n *\n * | Rule | Issue type |\n * |------------------------------------------------------------|-------------------------------------|\n * | Domain ↔ orchestration pattern share a name | pattern_name_collision |\n * | Registry has zero entries | pattern_entries_empty |\n * | Entry missing/non-string `key` or `provider` | pattern_entry_malformed |\n * | Two entries in the same registry share a `key` | pattern_entry_key_duplicate |\n * | Co-keyed registry's `keyType` diverges from the primary | pattern_cokeyed_keytype_mismatch |\n *\n * Two ADR-032 conflicts are NOT enforced here — they need consumer source\n * access that Phase 3-1 cannot do:\n * - `keyType`/`valueType` resolution (row 2): deferred to Phase 3-2 emission.\n * - Provider not exported by any known module (row 3): deferred to Phase 3-2\n * + DI runtime.\n *\n * Orchestration ↔ orchestration name duplicates ARE enforced — but at LOAD\n * time inside `loadAppPatterns()`, not here, because by the time the\n * validator runs the duplicate has already been deduped by `Map.set()`\n * keying on name. The loader emits a `LoadAppPatternsResult.errors` entry.\n */\n\nimport type { AnalysisIssue } from '../analyzer/types.js';\nimport type { OrchestrationPatternDefinition } from './pattern-definition.js';\n\n// Sentinel used for the `entity` field on project-level orchestration\n// issues. The orchestration kind is not entity-attached, so there is no\n// real entity name to point at. Existing console + markdown formatters\n// treat `issue.entity` as an opaque truthy string used only in display\n// (`${issue.entity}${issue.field ? '.' + issue.field : ''}`), so a\n// non-entity sentinel is safe — the formatters never look it up against\n// the parsed entity map.\nconst PROJECT_SENTINEL = '<project>';\n\nexport interface OrchestrationProjectContext {\n\t/** All orchestration patterns currently registered. */\n\torchestrationPatterns: ReadonlyArray<OrchestrationPatternDefinition>;\n\t/** All domain pattern names currently registered (library + app). */\n\tdomainPatternNames: ReadonlyArray<string>;\n}\n\nexport function validateOrchestrationProject(\n\tctx: OrchestrationProjectContext,\n): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\n\t// Rule 1: orchestration ↔ domain name collision (ADR-032 row 4).\n\tconst domainNameSet = new Set(ctx.domainPatternNames);\n\tfor (const orch of ctx.orchestrationPatterns) {\n\t\tif (domainNameSet.has(orch.name)) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'error',\n\t\t\t\ttype: 'pattern_name_collision',\n\t\t\t\tentity: PROJECT_SENTINEL,\n\t\t\t\tmessage:\n\t\t\t\t\t`Orchestration pattern '${orch.name}' shares a name with a domain ` +\n\t\t\t\t\t`pattern. Pattern names are globally unique across kinds (ADR-032 §Composition rules).`,\n\t\t\t});\n\t\t}\n\t}\n\n\t// Rules 2-4: per-pattern checks (entries shape + co-keyed keyType).\n\tfor (const orch of ctx.orchestrationPatterns) {\n\t\tconst allRegistries = [\n\t\t\torch.registry,\n\t\t\t...(orch.coKeyedRegistries ?? []),\n\t\t];\n\n\t\tfor (const reg of allRegistries) {\n\t\t\t// Rule 2: entries[] non-empty (defensive — loader already enforced\n\t\t\t// this for the primary registry, but co-keyed sibling registries\n\t\t\t// don't go through `assertOrchestrationContribution` and could be\n\t\t\t// authored as `entries: []`).\n\t\t\tif (!Array.isArray(reg.entries) || reg.entries.length === 0) {\n\t\t\t\tissues.push({\n\t\t\t\t\tseverity: 'error',\n\t\t\t\t\ttype: 'pattern_entries_empty',\n\t\t\t\t\tentity: PROJECT_SENTINEL,\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t`Orchestration pattern '${orch.name}' declares a registry with ` +\n\t\t\t\t\t\t`no entries. Provide at least one { key, provider } pair.`,\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Rules 3a + 3b: per-entry well-formedness + key uniqueness.\n\t\t\tconst seen = new Set<string>();\n\t\t\tfor (const entry of reg.entries) {\n\t\t\t\tif (typeof entry.key !== 'string' || entry.key.length === 0) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tseverity: 'error',\n\t\t\t\t\t\ttype: 'pattern_entry_malformed',\n\t\t\t\t\t\tentity: PROJECT_SENTINEL,\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t`Orchestration pattern '${orch.name}' has an entry with a ` +\n\t\t\t\t\t\t\t`missing or non-string 'key'.`,\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\ttypeof entry.provider !== 'string' ||\n\t\t\t\t\tentry.provider.length === 0\n\t\t\t\t) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tseverity: 'error',\n\t\t\t\t\t\ttype: 'pattern_entry_malformed',\n\t\t\t\t\t\tentity: PROJECT_SENTINEL,\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t`Orchestration pattern '${orch.name}' entry '${entry.key}' has ` +\n\t\t\t\t\t\t\t`a missing or non-string 'provider'.`,\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (seen.has(entry.key)) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tseverity: 'error',\n\t\t\t\t\t\ttype: 'pattern_entry_key_duplicate',\n\t\t\t\t\t\tentity: PROJECT_SENTINEL,\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t`Orchestration pattern '${orch.name}' has duplicate entry key ` +\n\t\t\t\t\t\t\t`'${entry.key}'. Keys must be unique within a registry.`,\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tseen.add(entry.key);\n\t\t\t}\n\t\t}\n\n\t\t// Rule 4: co-keyed registry keyType consistency (ADR-032 Decision 2).\n\t\tif (orch.coKeyedRegistries && orch.coKeyedRegistries.length > 0) {\n\t\t\tconst primaryKeyType = orch.registry.keyType;\n\t\t\tfor (const reg of orch.coKeyedRegistries) {\n\t\t\t\tif (reg.keyType !== primaryKeyType) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tseverity: 'error',\n\t\t\t\t\t\ttype: 'pattern_cokeyed_keytype_mismatch',\n\t\t\t\t\t\tentity: PROJECT_SENTINEL,\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t`Orchestration pattern '${orch.name}' co-keyed registry has ` +\n\t\t\t\t\t\t\t`keyType '${reg.keyType}', expected '${primaryKeyType}'. ` +\n\t\t\t\t\t\t\t`Co-keyed registries must share the primary registry's key space (ADR-032 Decision 2).`,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn issues;\n}\n","/**\n * Console Formatter\n *\n * Pretty terminal output with colors for the domain analysis results.\n */\n\nimport type { AnalysisResult, AnalysisIssue, Severity } from '../analyzer/types';\n\n// ANSI color codes\nconst colors = {\n\treset: '\\x1b[0m',\n\tbold: '\\x1b[1m',\n\tdim: '\\x1b[2m',\n\n\tred: '\\x1b[31m',\n\tgreen: '\\x1b[32m',\n\tyellow: '\\x1b[33m',\n\tblue: '\\x1b[34m',\n\tmagenta: '\\x1b[35m',\n\tcyan: '\\x1b[36m',\n\twhite: '\\x1b[37m',\n\n\tbgRed: '\\x1b[41m',\n\tbgGreen: '\\x1b[42m',\n\tbgYellow: '\\x1b[43m',\n};\n\nfunction color(text: string, ...styles: string[]): string {\n\treturn `${styles.join('')}${text}${colors.reset}`;\n}\n\nfunction severityColor(severity: Severity): string {\n\tswitch (severity) {\n\t\tcase 'error':\n\t\t\treturn colors.red;\n\t\tcase 'warning':\n\t\t\treturn colors.yellow;\n\t\tcase 'info':\n\t\t\treturn colors.cyan;\n\t}\n}\n\nfunction severityIcon(severity: Severity): string {\n\tswitch (severity) {\n\t\tcase 'error':\n\t\t\treturn 'X';\n\t\tcase 'warning':\n\t\t\treturn '!';\n\t\tcase 'info':\n\t\t\treturn 'i';\n\t}\n}\n\n/**\n * Format analysis result for console output\n */\nexport function formatConsole(result: AnalysisResult): string {\n\tconst lines: string[] = [];\n\n\t// Header\n\tlines.push('');\n\tlines.push(color('='.repeat(60), colors.dim));\n\tlines.push(color(' Domain Analysis Report', colors.bold, colors.cyan));\n\tlines.push(color('='.repeat(60), colors.dim));\n\tlines.push('');\n\n\t// Statistics\n\tlines.push(...formatStatistics(result));\n\n\t// Entity summary\n\tlines.push(...formatEntities(result));\n\n\t// Relationships\n\tlines.push(...formatRelationships(result));\n\n\t// Issues\n\tif (result.issues.length > 0) {\n\t\tlines.push(...formatIssues(result.issues));\n\t}\n\n\t// Final status\n\tlines.push('');\n\tlines.push(color('-'.repeat(60), colors.dim));\n\n\tconst errors = result.issues.filter((i) => i.severity === 'error');\n\tconst warnings = result.issues.filter((i) => i.severity === 'warning');\n\tconst infos = result.issues.filter((i) => i.severity === 'info');\n\n\tif (result.isValid) {\n\t\tlines.push(\n\t\t\tcolor(\n\t\t\t\t`[OK] Domain is valid (${warnings.length} warnings, ${infos.length} info)`,\n\t\t\t\tcolors.green\n\t\t\t)\n\t\t);\n\t} else {\n\t\tlines.push(color(`[FAIL] Domain has ${errors.length} errors`, colors.red));\n\t}\n\n\tlines.push(color('-'.repeat(60), colors.dim));\n\tlines.push('');\n\n\treturn lines.join('\\n');\n}\n\nfunction formatStatistics(result: AnalysisResult): string[] {\n\tconst lines: string[] = [];\n\tconst stats = result.statistics;\n\n\tlines.push(color('Statistics:', colors.bold));\n\tlines.push('');\n\tlines.push(` Entities: ${stats.totalEntities}`);\n\tlines.push(\n\t\t` Fields: ${stats.totalFields} (avg ${stats.averageFieldsPerEntity.toFixed(1)}/entity)`\n\t);\n\tlines.push(` Relationships: ${stats.totalRelationships}`);\n\tlines.push(` With behaviors: ${stats.entitiesWithBehaviors}`);\n\tlines.push('');\n\n\t// Field types breakdown\n\tlines.push(' Field types:');\n\tconst sortedTypes = Object.entries(stats.fieldsByType).sort((a, b) => b[1] - a[1]);\n\tfor (const [type, count] of sortedTypes) {\n\t\tconst bar = color('|'.repeat(Math.min(count, 20)), colors.blue);\n\t\tlines.push(` ${type.padEnd(12)} ${bar} ${count}`);\n\t}\n\tlines.push('');\n\n\t// Relationship types breakdown\n\tif (stats.totalRelationships > 0) {\n\t\tlines.push(' Relationship types:');\n\t\tconst sortedRels = Object.entries(stats.relationshipsByType).sort((a, b) => b[1] - a[1]);\n\t\tfor (const [type, count] of sortedRels) {\n\t\t\tconst bar = color('|'.repeat(Math.min(count, 20)), colors.magenta);\n\t\t\tlines.push(` ${type.padEnd(12)} ${bar} ${count}`);\n\t\t}\n\t\tlines.push('');\n\t}\n\n\treturn lines;\n}\n\nfunction formatEntities(result: AnalysisResult): string[] {\n\tconst lines: string[] = [];\n\n\tlines.push(color('Entities:', colors.bold));\n\tlines.push('');\n\n\tfor (const entity of result.entities) {\n\t\tconst fieldCount = entity.fields.size;\n\t\tconst relCount = entity.relationships.size;\n\t\tlines.push(\n\t\t\t` ${color(entity.name, colors.cyan)} (${fieldCount} fields, ${relCount} relationships)`\n\t\t);\n\t\tif (entity.behaviors.length > 0) {\n\t\t\tlines.push(color(` behaviors: ${entity.behaviors.join(', ')}`, colors.dim));\n\t\t}\n\t}\n\tlines.push('');\n\n\treturn lines;\n}\n\nfunction formatRelationships(result: AnalysisResult): string[] {\n\tconst lines: string[] = [];\n\n\tif (result.graph.edges.length === 0) {\n\t\treturn lines;\n\t}\n\n\tlines.push(color('Relationships:', colors.bold));\n\tlines.push('');\n\n\tfor (const edge of result.graph.edges) {\n\t\tconst arrow = getCardinalityArrow(edge.cardinality);\n\t\tconst bidir = edge.bidirectional ? color(' (bidirectional)', colors.dim) : '';\n\t\tlines.push(\n\t\t\t` ${edge.from.padEnd(20)} ${arrow} ${edge.to} ${color(`(${edge.relationship.type})`, colors.dim)}${bidir}`\n\t\t);\n\t}\n\tlines.push('');\n\n\treturn lines;\n}\n\nfunction getCardinalityArrow(cardinality: string): string {\n\tswitch (cardinality) {\n\t\tcase '1:N':\n\t\t\treturn color('--<', colors.magenta);\n\t\tcase 'N:1':\n\t\t\treturn color('>--', colors.magenta);\n\t\tcase '1:1':\n\t\t\treturn color('---', colors.magenta);\n\t\tcase 'N:M':\n\t\t\treturn color('>-<', colors.magenta);\n\t\tdefault:\n\t\t\treturn color('-->', colors.magenta);\n\t}\n}\n\nfunction formatIssues(issues: AnalysisIssue[]): string[] {\n\tconst lines: string[] = [];\n\n\t// Group by severity\n\tconst errors = issues.filter((i) => i.severity === 'error');\n\tconst warnings = issues.filter((i) => i.severity === 'warning');\n\tconst infos = issues.filter((i) => i.severity === 'info');\n\n\tif (errors.length > 0) {\n\t\tlines.push(color(`Errors (${errors.length}):`, colors.bold, colors.red));\n\t\tlines.push('');\n\t\tlines.push(...formatIssueList(errors, 'error'));\n\t\tlines.push('');\n\t}\n\n\tif (warnings.length > 0) {\n\t\tlines.push(color(`Warnings (${warnings.length}):`, colors.bold, colors.yellow));\n\t\tlines.push('');\n\t\tlines.push(...formatIssueList(warnings, 'warning'));\n\t\tlines.push('');\n\t}\n\n\tif (infos.length > 0) {\n\t\tlines.push(color(`Info (${infos.length}):`, colors.bold, colors.cyan));\n\t\tlines.push('');\n\t\tlines.push(...formatIssueList(infos, 'info', 5)); // Only show first 5 info messages\n\t\tlines.push('');\n\t}\n\n\treturn lines;\n}\n\nfunction formatIssueList(\n\tissues: AnalysisIssue[],\n\tseverity: Severity,\n\tlimit?: number\n): string[] {\n\tconst lines: string[] = [];\n\tconst displayIssues = limit ? issues.slice(0, limit) : issues;\n\n\t// Group by type\n\tconst byType = new Map<string, AnalysisIssue[]>();\n\tfor (const issue of displayIssues) {\n\t\tconst list = byType.get(issue.type) ?? [];\n\t\tlist.push(issue);\n\t\tbyType.set(issue.type, list);\n\t}\n\n\tfor (const [type, typeIssues] of byType) {\n\t\tlines.push(color(` ${type} (${typeIssues.length}):`, colors.dim));\n\n\t\tfor (const issue of typeIssues.slice(0, 5)) {\n\t\t\tconst location = issue.entity\n\t\t\t\t? `${issue.entity}${issue.field ? '.' + issue.field : ''}`\n\t\t\t\t: issue.path ?? 'unknown';\n\n\t\t\tconst icon = color(`[${severityIcon(severity)}]`, severityColor(severity));\n\t\t\tlines.push(` ${icon} ${color(location, colors.bold)}: ${issue.message}`);\n\n\t\t\tif (issue.suggestion) {\n\t\t\t\tlines.push(color(` -> ${issue.suggestion}`, colors.dim));\n\t\t\t}\n\t\t}\n\n\t\tif (typeIssues.length > 5) {\n\t\t\tlines.push(color(` ... and ${typeIssues.length - 5} more`, colors.dim));\n\t\t}\n\t}\n\n\tif (limit && issues.length > limit) {\n\t\tlines.push(color(` ... and ${issues.length - limit} more info messages`, colors.dim));\n\t}\n\n\treturn lines;\n}\n","/**\n * JSON Formatter\n *\n * Machine-readable JSON output for the domain analysis results.\n */\n\nimport type { AnalysisResult, ParsedEntity, DomainGraph } from '../analyzer/types';\n\n/**\n * Helper to convert Maps to plain objects for JSON serialization\n */\nfunction mapToObject<K extends string, V>(map: Map<K, V>): Record<K, V> {\n\tconst obj = {} as Record<K, V>;\n\tfor (const [key, value] of map) {\n\t\tobj[key] = value;\n\t}\n\treturn obj;\n}\n\n/**\n * Convert ParsedEntity to a JSON-serializable format\n */\nfunction serializeEntity(entity: ParsedEntity): Record<string, unknown> {\n\treturn {\n\t\tname: entity.name,\n\t\tplural: entity.plural,\n\t\ttable: entity.table,\n\t\tfolderStructure: entity.folderStructure,\n\t\tfields: mapToObject(entity.fields),\n\t\trelationships: mapToObject(entity.relationships),\n\t\tbehaviors: entity.behaviors,\n\t\tsourcePath: entity.sourcePath,\n\t};\n}\n\n/**\n * Convert DomainGraph to a JSON-serializable format\n */\nfunction serializeGraph(graph: DomainGraph): Record<string, unknown> {\n\tconst entities: Record<string, unknown> = {};\n\tfor (const [name, entity] of graph.entities) {\n\t\tentities[name] = serializeEntity(entity);\n\t}\n\n\treturn {\n\t\tentities,\n\t\tedges: graph.edges,\n\t};\n}\n\n/**\n * Format analysis result as JSON string\n */\nexport function formatJson(result: AnalysisResult, pretty = true): string {\n\tconst output = {\n\t\tisValid: result.isValid,\n\t\tsummary: {\n\t\t\tentities: result.statistics.totalEntities,\n\t\t\tfields: result.statistics.totalFields,\n\t\t\trelationships: result.statistics.totalRelationships,\n\t\t\terrors: result.issues.filter((i) => i.severity === 'error').length,\n\t\t\twarnings: result.issues.filter((i) => i.severity === 'warning').length,\n\t\t\tinfo: result.issues.filter((i) => i.severity === 'info').length,\n\t\t},\n\t\tentities: result.entities.map(serializeEntity),\n\t\tgraph: serializeGraph(result.graph),\n\t\tissues: result.issues,\n\t\tstatistics: result.statistics,\n\t\ttimestamp: new Date().toISOString(),\n\t};\n\n\treturn pretty ? JSON.stringify(output, null, 2) : JSON.stringify(output);\n}\n\n/**\n * Format only statistics as JSON\n */\nexport function formatStatsJson(result: AnalysisResult, pretty = true): string {\n\tconst output = {\n\t\tstatistics: result.statistics,\n\t\tisValid: result.isValid,\n\t\tissueCount: {\n\t\t\terrors: result.issues.filter((i) => i.severity === 'error').length,\n\t\t\twarnings: result.issues.filter((i) => i.severity === 'warning').length,\n\t\t\tinfo: result.issues.filter((i) => i.severity === 'info').length,\n\t\t},\n\t\ttimestamp: new Date().toISOString(),\n\t};\n\n\treturn pretty ? JSON.stringify(output, null, 2) : JSON.stringify(output);\n}\n\n/**\n * Format only issues as JSON\n */\nexport function formatIssuesJson(result: AnalysisResult, pretty = true): string {\n\tconst output = {\n\t\tisValid: result.isValid,\n\t\tissues: result.issues,\n\t\ttimestamp: new Date().toISOString(),\n\t};\n\n\treturn pretty ? JSON.stringify(output, null, 2) : JSON.stringify(output);\n}\n","/**\n * Markdown Formatter\n *\n * Documentation output with Mermaid diagrams for the domain analysis results.\n */\n\nimport type { AnalysisResult, ParsedEntity, RelationshipEdge } from '../analyzer/types';\n\n/**\n * Format analysis result as Markdown documentation\n */\nexport function formatMarkdown(result: AnalysisResult): string {\n\tconst lines: string[] = [];\n\n\t// Title\n\tlines.push('# Domain Model Documentation');\n\tlines.push('');\n\tlines.push(`Generated: ${new Date().toISOString()}`);\n\tlines.push('');\n\n\t// Overview statistics\n\tlines.push('## Overview');\n\tlines.push('');\n\tlines.push('| Metric | Value |');\n\tlines.push('|--------|-------|');\n\tlines.push(`| Entities | ${result.statistics.totalEntities} |`);\n\tlines.push(`| Total Fields | ${result.statistics.totalFields} |`);\n\tlines.push(`| Total Relationships | ${result.statistics.totalRelationships} |`);\n\tlines.push(\n\t\t`| Avg Fields/Entity | ${result.statistics.averageFieldsPerEntity.toFixed(1)} |`\n\t);\n\tlines.push('');\n\n\t// Field type distribution\n\tlines.push('### Field Type Distribution');\n\tlines.push('');\n\tlines.push('| Type | Count |');\n\tlines.push('|------|-------|');\n\tconst sortedTypes = Object.entries(result.statistics.fieldsByType).sort(\n\t\t(a, b) => b[1] - a[1]\n\t);\n\tfor (const [type, count] of sortedTypes) {\n\t\tlines.push(`| ${type} | ${count} |`);\n\t}\n\tlines.push('');\n\n\t// Relationship type distribution\n\tif (result.statistics.totalRelationships > 0) {\n\t\tlines.push('### Relationship Type Distribution');\n\t\tlines.push('');\n\t\tlines.push('| Type | Count |');\n\t\tlines.push('|------|-------|');\n\t\tconst sortedRels = Object.entries(result.statistics.relationshipsByType).sort(\n\t\t\t(a, b) => b[1] - a[1]\n\t\t);\n\t\tfor (const [type, count] of sortedRels) {\n\t\t\tlines.push(`| ${type} | ${count} |`);\n\t\t}\n\t\tlines.push('');\n\t}\n\n\t// Entity Relationship Diagram\n\tlines.push('## Entity Relationship Diagram');\n\tlines.push('');\n\tlines.push('```mermaid');\n\tlines.push(...generateMermaidErDiagram(result));\n\tlines.push('```');\n\tlines.push('');\n\n\t// Entities\n\tlines.push('## Entities');\n\tlines.push('');\n\n\tfor (const entity of result.entities) {\n\t\tlines.push(...formatEntitySection(entity));\n\t}\n\n\t// Issues\n\tconst errors = result.issues.filter((i) => i.severity === 'error');\n\tconst warnings = result.issues.filter((i) => i.severity === 'warning');\n\tconst infos = result.issues.filter((i) => i.severity === 'info');\n\n\tif (result.issues.length > 0) {\n\t\tlines.push('## Analysis Issues');\n\t\tlines.push('');\n\n\t\tif (errors.length > 0) {\n\t\t\tlines.push('### Errors');\n\t\t\tlines.push('');\n\t\t\tfor (const issue of errors) {\n\t\t\t\tconst location = issue.entity\n\t\t\t\t\t? `**${issue.entity}${issue.field ? '.' + issue.field : ''}**`\n\t\t\t\t\t: issue.path ?? 'unknown';\n\t\t\t\tlines.push(`- [${issue.type}] ${location}: ${issue.message}`);\n\t\t\t\tif (issue.suggestion) {\n\t\t\t\t\tlines.push(` - Suggestion: ${issue.suggestion}`);\n\t\t\t\t}\n\t\t\t}\n\t\t\tlines.push('');\n\t\t}\n\n\t\tif (warnings.length > 0) {\n\t\t\tlines.push('### Warnings');\n\t\t\tlines.push('');\n\t\t\tfor (const issue of warnings) {\n\t\t\t\tconst location = issue.entity\n\t\t\t\t\t? `**${issue.entity}${issue.field ? '.' + issue.field : ''}**`\n\t\t\t\t\t: issue.path ?? 'unknown';\n\t\t\t\tlines.push(`- [${issue.type}] ${location}: ${issue.message}`);\n\t\t\t\tif (issue.suggestion) {\n\t\t\t\t\tlines.push(` - Suggestion: ${issue.suggestion}`);\n\t\t\t\t}\n\t\t\t}\n\t\t\tlines.push('');\n\t\t}\n\n\t\tif (infos.length > 0) {\n\t\t\tlines.push('### Info');\n\t\t\tlines.push('');\n\t\t\tlines.push('<details>');\n\t\t\tlines.push('<summary>Show info messages</summary>');\n\t\t\tlines.push('');\n\t\t\tfor (const issue of infos) {\n\t\t\t\tconst location = issue.entity\n\t\t\t\t\t? `**${issue.entity}${issue.field ? '.' + issue.field : ''}**`\n\t\t\t\t\t: issue.path ?? 'unknown';\n\t\t\t\tlines.push(`- [${issue.type}] ${location}: ${issue.message}`);\n\t\t\t}\n\t\t\tlines.push('');\n\t\t\tlines.push('</details>');\n\t\t\tlines.push('');\n\t\t}\n\t}\n\n\treturn lines.join('\\n');\n}\n\n/**\n * Format a single entity section\n */\nfunction formatEntitySection(entity: ParsedEntity): string[] {\n\tconst lines: string[] = [];\n\n\tlines.push(`### ${entity.name}`);\n\tlines.push('');\n\tlines.push(`**Table:** \\`${entity.table}\\``);\n\tlines.push(`**Plural:** ${entity.plural}`);\n\tif (entity.behaviors.length > 0) {\n\t\tlines.push(`**Behaviors:** ${entity.behaviors.join(', ')}`);\n\t}\n\tlines.push('');\n\n\t// Fields table\n\tlines.push('#### Fields');\n\tlines.push('');\n\tlines.push('| Name | Type | Required | Nullable | Index | Foreign Key |');\n\tlines.push('|------|------|----------|----------|-------|-------------|');\n\n\tfor (const [name, field] of entity.fields) {\n\t\tconst required = field.required ? 'Yes' : '';\n\t\tconst nullable = field.nullable ? 'Yes' : '';\n\t\tconst index = field.index ? 'Yes' : field.unique ? 'Unique' : '';\n\t\tconst fk = field.foreignKey ? `${field.foreignKey.table}.${field.foreignKey.column}` : '';\n\t\tlines.push(`| ${name} | ${field.type} | ${required} | ${nullable} | ${index} | ${fk} |`);\n\t}\n\tlines.push('');\n\n\t// Relationships\n\tif (entity.relationships.size > 0) {\n\t\tlines.push('#### Relationships');\n\t\tlines.push('');\n\t\tlines.push('| Name | Type | Target | Foreign Key |');\n\t\tlines.push('|------|------|--------|-------------|');\n\n\t\tfor (const [name, rel] of entity.relationships) {\n\t\t\tlines.push(`| ${name} | ${rel.type} | ${rel.target} | ${rel.foreignKey} |`);\n\t\t}\n\t\tlines.push('');\n\t}\n\n\treturn lines;\n}\n\n/**\n * Generate Mermaid ER diagram\n */\nfunction generateMermaidErDiagram(result: AnalysisResult): string[] {\n\tconst lines: string[] = [];\n\n\tlines.push('erDiagram');\n\n\t// Define entities with their fields\n\tfor (const entity of result.entities) {\n\t\tconst entityName = entity.name.toUpperCase();\n\t\tlines.push(` ${entityName} {`);\n\n\t\t// Show key fields only (to keep diagram readable)\n\t\tconst keyFields = Array.from(entity.fields.entries())\n\t\t\t.filter(\n\t\t\t\t([name, field]) =>\n\t\t\t\t\tfield.foreignKey || field.unique || field.index || name === 'id' || name === 'name'\n\t\t\t)\n\t\t\t.slice(0, 6); // Limit to 6 fields\n\n\t\tfor (const [name, field] of keyFields) {\n\t\t\tconst typeStr = field.type;\n\t\t\tconst pk = name === 'id' ? 'PK' : '';\n\t\t\tconst fk = field.foreignKey ? 'FK' : '';\n\t\t\tconst marker = pk || fk ? ` \"${pk}${fk}\"` : '';\n\t\t\tlines.push(` ${typeStr} ${name}${marker}`);\n\t\t}\n\n\t\tif (entity.fields.size > keyFields.length) {\n\t\t\tlines.push(` string _more_fields`);\n\t\t}\n\n\t\tlines.push(' }');\n\t}\n\n\t// Add relationships\n\tfor (const edge of result.graph.edges) {\n\t\tconst from = edge.from.toUpperCase();\n\t\tconst to = edge.to.toUpperCase();\n\t\tconst cardinalitySymbol = getCardinalitySymbol(edge.cardinality);\n\t\tconst label = edge.relationship.name;\n\n\t\tlines.push(` ${from} ${cardinalitySymbol} ${to} : \"${label}\"`);\n\t}\n\n\treturn lines;\n}\n\n/**\n * Get Mermaid cardinality symbol\n */\nfunction getCardinalitySymbol(cardinality: string): string {\n\tswitch (cardinality) {\n\t\tcase '1:N':\n\t\t\treturn '||--o{';\n\t\tcase 'N:1':\n\t\t\treturn '}o--||';\n\t\tcase '1:1':\n\t\t\treturn '||--||';\n\t\tcase 'N:M':\n\t\t\treturn '}o--o{';\n\t\tdefault:\n\t\t\treturn '||--o{';\n\t}\n}\n\n/**\n * Generate a simple relationship graph in Mermaid\n */\nexport function formatMermaidGraph(result: AnalysisResult): string {\n\tconst lines: string[] = [];\n\n\tlines.push('```mermaid');\n\tlines.push('graph LR');\n\n\t// Style definitions\n\tlines.push(' classDef entity fill:#e1f5fe,stroke:#01579b');\n\n\t// Add entities as nodes\n\tfor (const entity of result.entities) {\n\t\tlines.push(` ${entity.name}[\"${entity.name}\\\\n(${entity.fields.size} fields)\"]`);\n\t}\n\n\t// Add relationships as edges\n\tfor (const edge of result.graph.edges) {\n\t\tconst style = edge.bidirectional ? '<-->' : '-->';\n\t\tlines.push(` ${edge.from} ${style}|${edge.relationship.type}| ${edge.to}`);\n\t}\n\n\t// Apply styles\n\tconst entityList = result.entities.map((e) => e.name).join(',');\n\tif (entityList) {\n\t\tlines.push(` class ${entityList} entity`);\n\t}\n\n\tlines.push('```');\n\n\treturn lines.join('\\n');\n}\n","/**\n * ActivityPattern — replaces `family: activity`.\n *\n * Activity entities represent time-bounded interactions (calls, meetings,\n * emails). The base repository/service expose date-range + opportunity +\n * user-scoped lookups on top of the standard CRUD methods.\n *\n * Class names, import paths, and inherited-method strings match the\n * legacy `FAMILY_MAP` entry verbatim so PATTERN-5's template swap produces\n * byte-identical output.\n */\n\nimport { definePattern } from '../pattern-definition.js';\n\nexport const ActivityPattern = definePattern({\n\tname: 'Activity',\n\textends: ['Base'],\n\trepositoryClass: 'ActivityEntityRepository',\n\tserviceClass: 'ActivityEntityService',\n\trepositoryImport: '@shared/base-classes/activity-entity-repository',\n\tserviceImport: '@shared/base-classes/activity-entity-service',\n\trepositoryInheritedMethods: [\n\t\t'findById, findByIds, list, count, exists, create, update, delete, upsertMany',\n\t\t'findByDateRange, findByUserId, findByOpportunityId, findRecentByOpportunityId',\n\t],\n\tserviceInheritedMethods: [\n\t\t'findById, findByIds, list, count, exists, create, update, delete',\n\t\t'findByDateRange, findByUserId, findByOpportunityId, findRecentByOpportunityId',\n\t],\n\tdescription:\n\t\t'Time-bounded interaction entities — date-range + opportunity scoped lookups',\n});\n","/**\n * BasePattern — identity pattern for the `extends` chain.\n *\n * Contributes no columns, no implied behaviors, and no config. Its only\n * purpose is to anchor the inheritance hierarchy so every other pattern\n * can declare `extends: ['Base']` and codegen can resolve that to a\n * concrete `BaseRepository` / `BaseService` reference.\n *\n * Matches the existing `family: base` entry in\n * `templates/entity/new/clean-lite-ps/prompt-extension.js` verbatim.\n */\n\nimport { definePattern } from '../pattern-definition.js';\n\nexport const BasePattern = definePattern({\n\tname: 'Base',\n\trepositoryClass: 'BaseRepository',\n\tserviceClass: 'BaseService',\n\trepositoryImport: '@shared/base-classes/base-repository',\n\tserviceImport: '@shared/base-classes/base-service',\n\trepositoryInheritedMethods: [\n\t\t'findById, findByIds, list, count, exists, create, update, delete, upsertMany',\n\t],\n\tserviceInheritedMethods: [\n\t\t'findById, findByIds, list, count, exists, create, update, delete',\n\t],\n\tdescription: 'Identity pattern — base CRUD, no extra columns or methods',\n});\n","/**\n * KnowledgePattern — replaces `family: knowledge`.\n *\n * Knowledge entities hold long-form content with a workflow status and\n * semantic-search support (vectors, pending/approved states). The base\n * classes expose `semanticSearch`, pending-by-opportunity lookups, and\n * batch status updates.\n *\n * Class names, import paths, and inherited-method strings match the\n * legacy `FAMILY_MAP` entry verbatim.\n */\n\nimport { definePattern } from '../pattern-definition.js';\n\nexport const KnowledgePattern = definePattern({\n\tname: 'Knowledge',\n\textends: ['Base'],\n\trepositoryClass: 'KnowledgeEntityRepository',\n\tserviceClass: 'KnowledgeEntityService',\n\trepositoryImport: '@shared/base-classes/knowledge-entity-repository',\n\tserviceImport: '@shared/base-classes/knowledge-entity-service',\n\trepositoryInheritedMethods: [\n\t\t'findById, findByIds, list, count, exists, create, update, delete, upsertMany',\n\t\t'semanticSearch, findPendingByOpportunityId, updateStatus, updateStatusBatch',\n\t],\n\tserviceInheritedMethods: [\n\t\t'findById, findByIds, list, count, exists, create, update, delete',\n\t\t'semanticSearch, findPendingByOpportunityId, updateStatus, updateStatusBatch',\n\t],\n\tdescription: 'Knowledge entities — semantic search + workflow status',\n});\n","/**\n * MetadataPattern — replaces `family: metadata`.\n *\n * Metadata entities represent history-tracked auxiliary rows attached to a\n * parent entity (audit trails, custom-field values, change logs). The base\n * classes expose entity-id + type scoped lookups and history listing.\n *\n * Class names, import paths, and inherited-method strings match the\n * legacy `FAMILY_MAP` entry verbatim.\n */\n\nimport { definePattern } from '../pattern-definition.js';\n\nexport const MetadataPattern = definePattern({\n\tname: 'Metadata',\n\textends: ['Base'],\n\trepositoryClass: 'MetadataEntityRepository',\n\tserviceClass: 'MetadataEntityService',\n\trepositoryImport: '@shared/base-classes/metadata-entity-repository',\n\tserviceImport: '@shared/base-classes/metadata-entity-service',\n\trepositoryInheritedMethods: [\n\t\t'findById, findByIds, list, count, exists, create, update, delete, upsertMany',\n\t\t'findByEntityIdAndType, listByEntityId, listHistoryByEntityId',\n\t],\n\tserviceInheritedMethods: [\n\t\t'findById, findByIds, list, count, exists, create, update, delete',\n\t\t'findByEntityIdAndType, listByEntityId, listHistoryByEntityId',\n\t],\n\tdescription:\n\t\t'History-tracked metadata rows — entity-id + type scoped lookups',\n});\n","/**\n * SyncedPattern — adds external-system sync columns and methods.\n *\n * Replaces the legacy `family: synced` entry in\n * `templates/entity/new/clean-lite-ps/prompt-extension.js`. Class names,\n * import paths, and inherited-method comment lines are preserved verbatim\n * so PATTERN-5's template swap produces byte-identical output for\n * pre-existing `family: synced` fixtures.\n *\n * Implies `external_id_tracking` — the behavior that contributes the\n * `external_id`, `provider`, and `provider_metadata` columns to the table.\n * An entity declaring `pattern: Synced` need not re-declare the behavior.\n */\n\nimport { definePattern } from '../pattern-definition.js';\n\nexport const SyncedPattern = definePattern({\n\tname: 'Synced',\n\textends: ['Base'],\n\trepositoryClass: 'SyncedEntityRepository',\n\tserviceClass: 'SyncedEntityService',\n\trepositoryImport: '@shared/base-classes/synced-entity-repository',\n\tserviceImport: '@shared/base-classes/synced-entity-service',\n\trepositoryInheritedMethods: [\n\t\t'findById, findByIds, list, count, exists, create, update, delete, upsertMany',\n\t\t'findByExternalId, findAllByUserId, findVisibleByUserId, syncUpsert',\n\t],\n\tserviceInheritedMethods: [\n\t\t'findById, findByIds, list, count, exists, create, update, delete',\n\t\t'findByExternalId, findAllByUserId, findVisibleByUserId',\n\t],\n\timpliedBehaviors: ['external_id_tracking'],\n\tdescription: 'External CRM/system sync columns and syncUpsert methods',\n});\n","/**\n * Library pattern bootstrap — imports every shipped pattern and registers\n * it with the shared library registry. Side-effect-only module: importing\n * this barrel is what pre-registers `Base`, `Synced`, `Activity`,\n * `Knowledge`, and `Metadata`.\n *\n * Adding a new library pattern is two edits: create the `*.pattern.ts`\n * file and add the import+register pair below.\n */\n\nimport { registerLibraryPattern } from '../registry.js';\nimport { ActivityPattern } from './activity.pattern.js';\nimport { BasePattern } from './base.pattern.js';\nimport { KnowledgePattern } from './knowledge.pattern.js';\nimport { MetadataPattern } from './metadata.pattern.js';\nimport { SyncedPattern } from './synced.pattern.js';\n\nregisterLibraryPattern(BasePattern);\nregisterLibraryPattern(SyncedPattern);\nregisterLibraryPattern(ActivityPattern);\nregisterLibraryPattern(KnowledgePattern);\nregisterLibraryPattern(MetadataPattern);\n\nexport {\n\tActivityPattern,\n\tBasePattern,\n\tKnowledgePattern,\n\tMetadataPattern,\n\tSyncedPattern,\n};\n","/**\n * Entity Codegen & Domain Analyzer\n *\n * A validation and analysis tool for entity YAML definitions.\n * Parses entities, builds a relationship graph, and detects issues.\n */\n\nimport { loadEntities, loadRelationships, resolveReferences, resolveRelationshipReferences } from './parser';\nimport { buildDomainGraph, checkConsistency, computeStatistics } from './analyzer';\nimport {\n\tvalidatePatternComposition,\n\tvalidatePatternProject,\n} from './patterns/validate-composition.js';\nimport { validateOrchestrationProject } from './patterns/validate-orchestration.js';\nimport {\n\tgetAllOrchestrationPatterns,\n\tgetAllPatternNames,\n} from './patterns/registry.js';\nimport type { AnalysisResult, OutputFormat } from './analyzer/types';\n\n/**\n * Options for `analyzeDomain`. All fields are optional and additive — omitting\n * them keeps the analyzer's behavior identical to pre-PATTERN-4 callers.\n */\nexport interface AnalyzeDomainOptions {\n\t/**\n\t * Path to the relationships directory. Equivalent to the legacy second\n\t * positional argument — preserved for call-site compatibility.\n\t */\n\trelationshipsDir?: string;\n\t/**\n\t * Selected backend architecture from `codegen.config.yaml\n\t * generate.architecture`. When provided, enables the PATTERN-4 project-level\n\t * check (plan Risk 4) that warns when `pattern:` is declared but the\n\t * selected architecture does not yet consume patterns (e.g. `clean`).\n\t */\n\tarchitecture?: string;\n}\n\n/**\n * Analyze a domain from entity and relationship YAML files.\n *\n * The signature accepts either the legacy `(entitiesDir, relationshipsDir)`\n * shape or the newer `(entitiesDir, options)` object form. Existing callers\n * keep working unchanged; pattern-aware callers pass\n * `{ architecture, relationshipsDir }` to opt into the Risk-4 project-level\n * warning surface.\n */\nexport async function analyzeDomain(\n\tentitiesDir: string,\n\trelationshipsOrOptions?: string | AnalyzeDomainOptions,\n): Promise<AnalysisResult> {\n\tconst opts: AnalyzeDomainOptions =\n\t\ttypeof relationshipsOrOptions === 'string'\n\t\t\t? { relationshipsDir: relationshipsOrOptions }\n\t\t\t: relationshipsOrOptions ?? {};\n\tconst relationshipsDir = opts.relationshipsDir;\n\n\t// Load and parse all entity files\n\tconst { entities, issues: loadIssues } = loadEntities(entitiesDir);\n\n\t// Load relationship definitions (optional — directory may not exist)\n\tconst { relationships: relationshipDefinitions, issues: relLoadIssues } =\n\t\trelationshipsDir\n\t\t\t? loadRelationships(relationshipsDir)\n\t\t\t: { relationships: [], issues: [] };\n\n\t// Resolve cross-entity references\n\tconst resolveIssues = resolveReferences(entities);\n\n\t// Resolve relationship endpoint references\n\tconst relResolveIssues = resolveRelationshipReferences(\n\t\trelationshipDefinitions,\n\t\tentities,\n\t);\n\n\t// Build relationship graph (includes both inline and first-class relationships)\n\tconst graph = buildDomainGraph(entities, relationshipDefinitions);\n\n\t// Check consistency\n\tconst consistencyIssues = checkConsistency(graph);\n\n\t// PATTERN-4 — pattern composition check. Runs AFTER resolveReferences()\n\t// (per ADR-031 §3) so entity fields + behaviors are known; the\n\t// per-entity validator detects column conflicts, unknown patterns, and\n\t// config-schema failures, and the project-level validator covers plan\n\t// Risk 4 (warn when `pattern:` is declared under an architecture that\n\t// does not yet consume patterns).\n\tconst patternIssues = entities.flatMap((e) => validatePatternComposition(e));\n\tconst patternProjectIssues = validatePatternProject({\n\t\tentities,\n\t\tarchitecture: opts.architecture,\n\t});\n\n\t// ADR-032 Phase 3-1 — orchestration pattern project-level validator.\n\t// Compares orchestration names against the domain name set (cross-kind\n\t// collision is a hard error), and walks each orchestration pattern's\n\t// registry shape for malformed entries, duplicate keys, and co-keyed\n\t// keyType drift.\n\tconst orchestrationProjectIssues = validateOrchestrationProject({\n\t\torchestrationPatterns: getAllOrchestrationPatterns(),\n\t\tdomainPatternNames: getAllPatternNames(),\n\t});\n\n\t// Compute statistics\n\tconst statistics = computeStatistics(graph);\n\n\t// Combine all issues\n\tconst allIssues = [\n\t\t...loadIssues,\n\t\t...relLoadIssues,\n\t\t...resolveIssues,\n\t\t...relResolveIssues,\n\t\t...consistencyIssues,\n\t\t...patternIssues,\n\t\t...patternProjectIssues,\n\t\t...orchestrationProjectIssues,\n\t];\n\n\t// Determine validity (only errors make it invalid)\n\tconst hasErrors = allIssues.some((i) => i.severity === 'error');\n\n\treturn {\n\t\tisValid: !hasErrors,\n\t\tentities,\n\t\trelationshipDefinitions,\n\t\tgraph,\n\t\tissues: allIssues,\n\t\tstatistics,\n\t};\n}\n\n/**\n * Validate entity files without full analysis\n * Returns true if all files parse successfully\n */\nexport function validateEntities(entitiesDir: string): {\n\tvalid: boolean;\n\terrors: string[];\n} {\n\tconst { entities, issues } = loadEntities(entitiesDir);\n\tconst errors = issues\n\t\t.filter((i) => i.severity === 'error')\n\t\t.map((i) => i.message);\n\n\treturn {\n\t\tvalid: errors.length === 0,\n\t\terrors,\n\t};\n}\n\n// Re-export types\nexport * from './analyzer/types';\n\n// Re-export parser utilities\nexport { loadEntities, loadRelationships, loadEntityFromYaml, loadRelationshipFromYaml } from './parser';\n\n// Re-export analyzer utilities\nexport {\n\tbuildDomainGraph,\n\tgetRelatedEntities,\n\tfindOrphanEntities,\n\tfindCircularDependencies,\n\tcheckConsistency,\n\tcomputeStatistics,\n} from './analyzer';\n\n// Re-export formatters\nexport {\n\tformatConsole,\n\tformatJson,\n\tformatMarkdown,\n\tformatMermaidGraph,\n} from './formatters';\n\n\n// Re-export patterns surface (definePattern + library patterns + registry).\n// Importing this barrel has the side effect of pre-registering the five\n// library-shipped patterns (Base / Synced / Activity / Knowledge / Metadata).\nexport * from './patterns';\n"],"mappings":"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","names":["z","z","Injectable","Injectable","Injectable","out","Injectable","Injectable","Injectable","Inject","Injectable","Optional","Injectable","Inject","Optional","Inject","Injectable","Optional","and","desc","eq","eq","and","desc","Injectable","Inject","Optional","z","z","z","path","path","text","index"]}
|
|
1
|
+
{"version":3,"sources":["../../src/parser/load-entities.ts","../../src/utils/yaml-loader.ts","../../src/schema/entity-definition.schema.ts","../../runtime/subsystems/sync/sync-field-diff.protocol.ts","../../runtime/subsystems/sync/detection-config.schema.ts","../../runtime/subsystems/sync/sync.tokens.ts","../../runtime/subsystems/sync/sync-errors.ts","../../runtime/subsystems/sync/sync-audit.schema.ts","../../runtime/subsystems/sync/sync-cursor-store.memory-backend.ts","../../runtime/subsystems/sync/sync-run-recorder.memory-backend.ts","../../runtime/subsystems/sync/deep-equal.differ.ts","../../runtime/subsystems/sync/execute-sync.use-case.ts","../../runtime/subsystems/sync/sync-cursor-store.drizzle-backend.ts","../../runtime/constants/tokens.ts","../../runtime/subsystems/sync/sync-run-recorder.drizzle-backend.ts","../../runtime/subsystems/sync/sync.module.ts","../../src/schema/event-definition.schema.ts","../../src/schema/relationship-definition.schema.ts","../../src/analyzer/graph-builder.ts","../../src/behaviors/external-id-tracking.ts","../../src/behaviors/soft-delete.ts","../../src/behaviors/timestamps.ts","../../src/behaviors/user-tracking.ts","../../src/behaviors/index.ts","../../src/analyzer/consistency-checker.ts","../../src/analyzer/statistics.ts","../../src/patterns/registry.ts","../../src/patterns/pattern-definition.ts","../../src/patterns/validate-composition.ts","../../src/patterns/validate-orchestration.ts","../../src/formatters/console-formatter.ts","../../src/formatters/json-formatter.ts","../../src/formatters/markdown-formatter.ts","../../src/patterns/library/activity.pattern.ts","../../src/patterns/library/base.pattern.ts","../../src/patterns/library/knowledge.pattern.ts","../../src/patterns/library/metadata.pattern.ts","../../src/patterns/library/synced.pattern.ts","../../src/patterns/library/index.ts","../../src/index.ts"],"sourcesContent":["/**\n * Entity Loader\n *\n * Loads and parses all YAML entity files from a directory.\n * Reuses existing yaml-loader and entity-definition schema from codegen.\n */\n\nimport { readdirSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport {\n\tloadEntityFromYaml,\n\tloadRelationshipFromYaml,\n\ttype LoadResult,\n\ttype LoadError,\n\ttype RelationshipLoadResult,\n\ttype RelationshipLoadError,\n} from '../utils/yaml-loader';\nimport type {\n\tParsedEntity,\n\tParsedEvent,\n\tParsedField,\n\tParsedProviderSync,\n\tParsedQuery,\n\tParsedRelationship,\n\tParsedRelationshipDefinition,\n\tParsedSync,\n\tParsedTypeDirection,\n\tAnalysisIssue,\n} from '../analyzer/types';\nimport {\n\tderiveRelationshipFKColumns,\n\tderiveTableName,\n\tderiveUniqueConstraint,\n\tcollectTypeNames,\n\ttype RelationshipDefinition,\n\ttype RelationshipTypes,\n} from '../schema/relationship-definition.schema';\n\nexport interface LoadEntitiesResult {\n\tentities: ParsedEntity[];\n\tissues: AnalysisIssue[];\n}\n\n/**\n * Transform a loaded entity definition into a ParsedEntity\n */\nfunction transformToEntity(result: LoadResult): ParsedEntity {\n\tconst { definition, filePath } = result;\n\n\t// Search queries use a different shape (name/filters/search/paginate) and\n\t// are consumed directly by the codegen templates, not by the analyzer.\n\t// Narrow to the by-column variant here for ParsedQuery mapping.\n\tconst queries: ParsedQuery[] | undefined = definition.queries\n\t\t?.filter((q): q is Extract<typeof q, { by: unknown }> => 'by' in q)\n\t\t.map((q) => ({\n\t\t\tby: q.by,\n\t\t\tunique: q.unique,\n\t\t\tselect: q.select,\n\t\t\torder: q.order,\n\t\t\tlimit: q.limit,\n\t\t\tvia: q.via,\n\t\t}));\n\n\tconst entity: ParsedEntity = {\n\t\tname: definition.entity.name,\n\t\tplural: definition.entity.plural,\n\t\ttable: definition.entity.table,\n\t\tpattern: definition.entity.pattern,\n\t\tpatterns: definition.entity.patterns,\n\t\tpatternConfig: definition.entity.config,\n\t\tscopeable: definition.entity.scopeable ?? false,\n\t\tfolderStructure: definition.entity.folder_structure ?? 'nested',\n\t\tfields: new Map(),\n\t\trelationships: new Map(),\n\t\tbehaviors: definition.behaviors.map((b) => (typeof b === 'string' ? b : b.name)),\n\t\tqueries,\n\t\tsourcePath: filePath,\n\t};\n\n\t// Parse fields\n\tfor (const [name, fieldDef] of Object.entries(definition.fields)) {\n\t\tconst field: ParsedField = {\n\t\t\tname,\n\t\t\ttype: fieldDef.type,\n\t\t\trequired: fieldDef.required ?? false,\n\t\t\tnullable: fieldDef.nullable ?? false,\n\t\t\tunique: fieldDef.unique ?? false,\n\t\t\tindex: fieldDef.index ?? false,\n\t\t\tforeignKey: fieldDef.foreign_key ? parseForeignKey(fieldDef.foreign_key) : undefined,\n\t\t\tchoices: fieldDef.choices,\n\t\t\tconstraints: {\n\t\t\t\tminLength: fieldDef.min_length,\n\t\t\t\tmaxLength: fieldDef.max_length,\n\t\t\t\tmin: fieldDef.min,\n\t\t\t\tmax: fieldDef.max,\n\t\t\t},\n\t\t\tui: {\n\t\t\t\tlabel: fieldDef.ui_label,\n\t\t\t\ttype: fieldDef.ui_type,\n\t\t\t\timportance: fieldDef.ui_importance,\n\t\t\t\tgroup: fieldDef.ui_group,\n\t\t\t\tsortable: fieldDef.ui_sortable,\n\t\t\t\tfilterable: fieldDef.ui_filterable,\n\t\t\t\tvisible: fieldDef.ui_visible,\n\t\t\t},\n\t\t};\n\t\tentity.fields.set(name, field);\n\t}\n\n\t// Parse relationships\n\tif (definition.relationships) {\n\t\tfor (const [name, relDef] of Object.entries(definition.relationships)) {\n\t\t\tconst relationship: ParsedRelationship = {\n\t\t\t\tname,\n\t\t\t\ttype: relDef.type,\n\t\t\t\ttarget: relDef.target,\n\t\t\t\tforeignKey: relDef.foreign_key,\n\t\t\t\tinverse: relDef.inverse,\n\t\t\t\tthrough: relDef.through,\n\t\t\t\tresolved: false,\n\t\t\t};\n\t\t\tentity.relationships.set(name, relationship);\n\t\t}\n\t}\n\n\t// Parse sync configuration\n\tif (definition.sync) {\n\t\tconst syncDef = definition.sync;\n\t\tconst parsedSync: ParsedSync = {\n\t\t\telectric: syncDef.electric ?? false,\n\t\t};\n\n\t\tif (syncDef.providers) {\n\t\t\tparsedSync.providers = {};\n\t\t\tfor (const [providerName, providerDef] of Object.entries(syncDef.providers)) {\n\t\t\t\tconst parsedProvider: ParsedProviderSync = {\n\t\t\t\t\tremoteEntity: providerDef.remote_entity,\n\t\t\t\t\tdirection: providerDef.direction,\n\t\t\t\t\tcdc: providerDef.cdc ?? false,\n\t\t\t\t};\n\t\t\t\tif (providerDef.field_mapping) {\n\t\t\t\t\tparsedProvider.fieldMapping = providerDef.field_mapping;\n\t\t\t\t}\n\t\t\t\tif (providerDef.read_only_fields) {\n\t\t\t\t\tparsedProvider.readOnlyFields = providerDef.read_only_fields;\n\t\t\t\t}\n\t\t\t\tparsedSync.providers[providerName] = parsedProvider;\n\t\t\t}\n\t\t}\n\n\t\tentity.sync = parsedSync;\n\t}\n\n\t// Parse events\n\tif (definition.events) {\n\t\tentity.events = definition.events.map((ev): ParsedEvent => ({\n\t\t\tname: ev.name,\n\t\t\tqueue: ev.queue,\n\t\t\tbody: ev.body,\n\t\t\tgenerateHandler: ev.generate_handler,\n\t\t}));\n\t}\n\n\t// Parse emits (EVT-7). Preserve `undefined` vs `[]` distinction — the\n\t// validator treats absence as a warning and explicit empty as opt-out.\n\tif (definition.emits !== undefined) {\n\t\tentity.emits = definition.emits;\n\t}\n\n\treturn entity;\n}\n\n/**\n * Parse a foreign key string (e.g., \"accounts.id\") into table and column\n */\nfunction parseForeignKey(fk: string): { table: string; column: string } {\n\tconst [table, column] = fk.split('.');\n\treturn { table, column: column ?? 'id' };\n}\n\n/**\n * Convert a load error to an analysis issue\n */\nfunction loadErrorToIssue(error: LoadError): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\n\tissues.push({\n\t\tseverity: 'error',\n\t\ttype: 'parse_error',\n\t\tmessage: error.error,\n\t\tpath: error.filePath,\n\t});\n\n\tif (error.details) {\n\t\tfor (const detail of error.details) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'error',\n\t\t\t\ttype: 'schema_error',\n\t\t\t\tmessage: detail,\n\t\t\t\tpath: error.filePath,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn issues;\n}\n\n/**\n * Load all entity YAML files from a directory\n */\nexport function loadEntities(entitiesDir: string): LoadEntitiesResult {\n\tconst entities: ParsedEntity[] = [];\n\tconst issues: AnalysisIssue[] = [];\n\n\tconst resolvedDir = resolve(entitiesDir);\n\n\t// Get all YAML files\n\tlet files: string[];\n\ttry {\n\t\tfiles = readdirSync(resolvedDir)\n\t\t\t.filter((f) => f.endsWith('.yaml') || f.endsWith('.yml'))\n\t\t\t.map((f) => join(resolvedDir, f));\n\t} catch (err) {\n\t\tissues.push({\n\t\t\tseverity: 'error',\n\t\t\ttype: 'parse_error',\n\t\t\tmessage: `Failed to read directory: ${resolvedDir}`,\n\t\t\tpath: resolvedDir,\n\t\t});\n\t\treturn { entities, issues };\n\t}\n\n\tif (files.length === 0) {\n\t\tissues.push({\n\t\t\tseverity: 'warning',\n\t\t\ttype: 'no_files',\n\t\t\tmessage: `No YAML files found in directory: ${resolvedDir}`,\n\t\t\tpath: resolvedDir,\n\t\t});\n\t\treturn { entities, issues };\n\t}\n\n\t// Load each file\n\tfor (const filePath of files) {\n\t\tconst result = loadEntityFromYaml(filePath);\n\n\t\tif (result.success) {\n\t\t\tentities.push(transformToEntity(result));\n\t\t} else {\n\t\t\tissues.push(...loadErrorToIssue(result));\n\t\t}\n\t}\n\n\treturn { entities, issues };\n}\n\n/**\n * Resolve cross-entity references\n */\nexport function resolveReferences(entities: ParsedEntity[]): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\tconst entityMap = new Map<string, ParsedEntity>();\n\n\t// Build entity map by name\n\tfor (const entity of entities) {\n\t\tif (entityMap.has(entity.name)) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'error',\n\t\t\t\ttype: 'duplicate_entity',\n\t\t\t\tentity: entity.name,\n\t\t\t\tmessage: `Duplicate entity name: ${entity.name}`,\n\t\t\t\tpath: entity.sourcePath,\n\t\t\t});\n\t\t}\n\t\tentityMap.set(entity.name, entity);\n\t}\n\n\t// Resolve relationships\n\tfor (const entity of entities) {\n\t\tfor (const [relName, rel] of entity.relationships) {\n\t\t\tconst targetEntity = entityMap.get(rel.target);\n\t\t\tif (targetEntity) {\n\t\t\t\trel.resolved = true;\n\t\t\t} else {\n\t\t\t\tissues.push({\n\t\t\t\t\tseverity: 'error',\n\t\t\t\t\ttype: 'missing_target',\n\t\t\t\t\tentity: entity.name,\n\t\t\t\t\tfield: relName,\n\t\t\t\t\tmessage: `Relationship '${relName}' references unknown entity '${rel.target}'`,\n\t\t\t\t\tpath: entity.sourcePath,\n\t\t\t\t\tsuggestion: `Define entity '${rel.target}' or fix the target name`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Check foreign key references\n\t\tfor (const [fieldName, field] of entity.fields) {\n\t\t\tif (field.foreignKey) {\n\t\t\t\tconst targetTable = field.foreignKey.table;\n\t\t\t\tconst targetEntity = Array.from(entityMap.values()).find(\n\t\t\t\t\t(e) => e.table === targetTable\n\t\t\t\t);\n\t\t\t\tif (!targetEntity) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tseverity: 'warning',\n\t\t\t\t\t\ttype: 'missing_fk_target',\n\t\t\t\t\t\tentity: entity.name,\n\t\t\t\t\t\tfield: fieldName,\n\t\t\t\t\t\tmessage: `Foreign key references unknown table '${targetTable}'`,\n\t\t\t\t\t\tpath: entity.sourcePath,\n\t\t\t\t\t\tsuggestion: `Define entity with table '${targetTable}' or fix the foreign_key reference`,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn issues;\n}\n\n// ============================================================================\n// Relationship Loading\n// ============================================================================\n\nexport interface LoadRelationshipsResult {\n\trelationships: ParsedRelationshipDefinition[];\n\tissues: AnalysisIssue[];\n}\n\n/**\n * Transform a loaded relationship definition into a ParsedRelationshipDefinition.\n *\n * This resolves all auto-generated fields: FK columns, type directions,\n * temporal/sourced fields, unique constraints.\n */\nfunction transformToRelationshipDefinition(\n\tresult: RelationshipLoadResult,\n): ParsedRelationshipDefinition {\n\tconst { definition, filePath } = result;\n\tconst config = definition.relationship;\n\n\tconst { fromColumn, toColumn } = deriveRelationshipFKColumns(config);\n\tconst table = deriveTableName(config);\n\tconst uniqueOn = deriveUniqueConstraint(config);\n\n\t// Resolve type directions\n\tconst types = resolveTypeDirections(config.types);\n\n\t// Parse custom fields\n\tconst fields = new Map<string, ParsedField>();\n\tif (definition.fields) {\n\t\tfor (const [name, fieldDef] of Object.entries(definition.fields)) {\n\t\t\tconst field: ParsedField = {\n\t\t\t\tname,\n\t\t\t\ttype: fieldDef.type,\n\t\t\t\trequired: fieldDef.required ?? false,\n\t\t\t\tnullable: fieldDef.nullable ?? false,\n\t\t\t\tunique: fieldDef.unique ?? false,\n\t\t\t\tindex: fieldDef.index ?? false,\n\t\t\t\tforeignKey: fieldDef.foreign_key\n\t\t\t\t\t? parseForeignKey(fieldDef.foreign_key)\n\t\t\t\t\t: undefined,\n\t\t\t\tchoices: fieldDef.choices,\n\t\t\t\tconstraints: {\n\t\t\t\t\tminLength: fieldDef.min_length,\n\t\t\t\t\tmaxLength: fieldDef.max_length,\n\t\t\t\t\tmin: fieldDef.min,\n\t\t\t\t\tmax: fieldDef.max,\n\t\t\t\t},\n\t\t\t\tui: {\n\t\t\t\t\tlabel: fieldDef.ui_label,\n\t\t\t\t\ttype: fieldDef.ui_type,\n\t\t\t\t\timportance: fieldDef.ui_importance,\n\t\t\t\t\tgroup: fieldDef.ui_group,\n\t\t\t\t\tsortable: fieldDef.ui_sortable,\n\t\t\t\t\tfilterable: fieldDef.ui_filterable,\n\t\t\t\t\tvisible: fieldDef.ui_visible,\n\t\t\t\t},\n\t\t\t};\n\t\t\tfields.set(name, field);\n\t\t}\n\t}\n\n\t// Parse queries\n\t// Relationship queries here: same filtering rationale as entity queries.\n\tconst queries: ParsedQuery[] | undefined = definition.queries\n\t\t?.filter((q): q is Extract<typeof q, { by: unknown }> => 'by' in q)\n\t\t.map((q) => ({\n\t\t\tby: q.by,\n\t\t\tunique: q.unique,\n\t\t\tselect: q.select,\n\t\t\torder: q.order,\n\t\t\tlimit: q.limit,\n\t\t}));\n\n\treturn {\n\t\tname: config.name,\n\t\ttable,\n\t\tfrom: config.from,\n\t\tto: config.to,\n\t\tselfReferential: config.from === config.to,\n\t\tfromColumn,\n\t\ttoColumn,\n\t\ttypes,\n\t\thasTypes: types.length > 0,\n\t\ttemporal: config.temporal,\n\t\tsourced: config.sourced,\n\t\tonDeleteFrom: config.on_delete_from ?? 'restrict',\n\t\tonDeleteTo: config.on_delete_to ?? 'restrict',\n\t\tuniqueOn,\n\t\tfields,\n\t\tqueries,\n\t\tsourcePath: filePath,\n\t};\n}\n\n/**\n * Resolve type directions from the YAML types: block.\n *\n * Simple list → all directed, no inverses.\n * Object map → each type has explicit direction metadata.\n */\nfunction resolveTypeDirections(\n\ttypes: RelationshipTypes | undefined,\n): ParsedTypeDirection[] {\n\tif (!types) return [];\n\n\tif (Array.isArray(types)) {\n\t\t// Simple list: all directed from→to\n\t\treturn types.map((name) => ({\n\t\t\tname,\n\t\t\tbidirectional: false,\n\t\t\tdirected: true,\n\t\t}));\n\t}\n\n\t// Object map: resolve each type's direction\n\treturn Object.entries(types).map(([name, dir]) => {\n\t\tconst direction = dir as { inverse?: string; bidirectional?: boolean; directed?: boolean };\n\t\treturn {\n\t\t\tname,\n\t\t\tinverse: direction.inverse,\n\t\t\tbidirectional: direction.bidirectional ?? false,\n\t\t\tdirected: direction.directed ?? (!direction.bidirectional && !direction.inverse),\n\t\t};\n\t});\n}\n\n/**\n * Load all relationship YAML files from a directory\n */\nexport function loadRelationships(\n\trelationshipsDir: string,\n): LoadRelationshipsResult {\n\tconst relationships: ParsedRelationshipDefinition[] = [];\n\tconst issues: AnalysisIssue[] = [];\n\n\tconst resolvedDir = resolve(relationshipsDir);\n\n\tlet files: string[];\n\ttry {\n\t\tfiles = readdirSync(resolvedDir)\n\t\t\t.filter((f) => f.endsWith('.yaml') || f.endsWith('.yml'))\n\t\t\t.map((f) => join(resolvedDir, f));\n\t} catch {\n\t\t// Directory doesn't exist — not an error, relationships are optional\n\t\treturn { relationships, issues };\n\t}\n\n\tif (files.length === 0) {\n\t\treturn { relationships, issues };\n\t}\n\n\tfor (const filePath of files) {\n\t\tconst result = loadRelationshipFromYaml(filePath);\n\n\t\tif (result.success) {\n\t\t\trelationships.push(transformToRelationshipDefinition(result));\n\t\t} else {\n\t\t\tissues.push(...loadErrorToIssue(result as unknown as LoadError));\n\t\t}\n\t}\n\n\treturn { relationships, issues };\n}\n\n/**\n * Resolve cross-references between relationship definitions and entities.\n * Validates that from/to entities exist.\n */\nexport function resolveRelationshipReferences(\n\trelationshipDefs: ParsedRelationshipDefinition[],\n\tentities: ParsedEntity[],\n): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\tconst entityNames = new Set(entities.map((e) => e.name));\n\n\tfor (const relDef of relationshipDefs) {\n\t\tif (!entityNames.has(relDef.from)) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'warning',\n\t\t\t\ttype: 'missing_relationship_endpoint',\n\t\t\t\tentity: relDef.name,\n\t\t\t\tmessage: `Relationship '${relDef.name}' references unknown 'from' entity '${relDef.from}'`,\n\t\t\t\tpath: relDef.sourcePath,\n\t\t\t\tsuggestion: `Define entity '${relDef.from}' or fix the 'from' value`,\n\t\t\t});\n\t\t}\n\n\t\tif (!entityNames.has(relDef.to)) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'warning',\n\t\t\t\ttype: 'missing_relationship_endpoint',\n\t\t\t\tentity: relDef.name,\n\t\t\t\tmessage: `Relationship '${relDef.name}' references unknown 'to' entity '${relDef.to}'`,\n\t\t\t\tpath: relDef.sourcePath,\n\t\t\t\tsuggestion: `Define entity '${relDef.to}' or fix the 'to' value`,\n\t\t\t});\n\t\t}\n\n\t\t// Check for duplicate relationship names\n\t\tconst dupes = relationshipDefs.filter((r) => r.name === relDef.name);\n\t\tif (dupes.length > 1) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'error',\n\t\t\t\ttype: 'duplicate_relationship',\n\t\t\t\tentity: relDef.name,\n\t\t\t\tmessage: `Duplicate relationship name: ${relDef.name}`,\n\t\t\t\tpath: relDef.sourcePath,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn issues;\n}\n\nexport { loadEntityFromYaml } from '../utils/yaml-loader';\nexport { loadRelationshipFromYaml } from '../utils/yaml-loader';\n","import { readFileSync, existsSync } from 'node:fs';\nimport { parse as parseYaml } from 'yaml';\nimport { ZodError } from 'zod';\nimport {\n\ttype EntityDefinition,\n\tEntityDefinitionSchema,\n} from '../schema/entity-definition.schema';\nimport {\n\ttype EventDefinition,\n\tEventDefinitionSchema,\n} from '../schema/event-definition.schema';\nimport {\n\ttype RelationshipDefinition,\n\tRelationshipDefinitionSchema,\n} from '../schema/relationship-definition.schema';\n\nexport interface LoadResult {\n\tsuccess: true;\n\tdefinition: EntityDefinition;\n\tfilePath: string;\n}\n\nexport interface LoadError {\n\tsuccess: false;\n\terror: string;\n\tdetails?: string[];\n\tfilePath: string;\n}\n\nexport type LoadEntityResult = LoadResult | LoadError;\n\n/**\n * Load and validate an entity definition from a YAML file\n */\nexport function loadEntityFromYaml(filePath: string): LoadEntityResult {\n\t// Check file exists\n\tif (!existsSync(filePath)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: `File not found: ${filePath}`,\n\t\t\tfilePath,\n\t\t};\n\t}\n\n\t// Read file\n\tlet content: string;\n\ttry {\n\t\tcontent = readFileSync(filePath, 'utf-8');\n\t} catch (err) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: `Failed to read file: ${filePath}`,\n\t\t\tdetails: [err instanceof Error ? err.message : String(err)],\n\t\t\tfilePath,\n\t\t};\n\t}\n\n\t// Parse YAML\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = parseYaml(content);\n\t} catch (err) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: `Invalid YAML syntax in ${filePath}`,\n\t\t\tdetails: [err instanceof Error ? err.message : String(err)],\n\t\t\tfilePath,\n\t\t};\n\t}\n\n\t// Validate against schema\n\tconst result = EntityDefinitionSchema.safeParse(parsed);\n\tif (!result.success) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: `Validation failed for ${filePath}`,\n\t\t\tdetails: formatZodErrors(result.error),\n\t\t\tfilePath,\n\t\t};\n\t}\n\n\treturn {\n\t\tsuccess: true,\n\t\tdefinition: result.data,\n\t\tfilePath,\n\t};\n}\n\n/**\n * Format Zod errors into human-readable messages\n */\nfunction formatZodErrors(error: ZodError): string[] {\n\treturn error.errors.map((err) => {\n\t\tconst path = err.path.join('.');\n\t\tconst location = path ? `at '${path}'` : 'at root';\n\t\treturn `${err.message} ${location}`;\n\t});\n}\n\n/**\n * Pretty-print a load error for CLI output\n */\nexport function formatLoadError(result: LoadError): string {\n\tconst lines = [`❌ ${result.error}`];\n\tif (result.details && result.details.length > 0) {\n\t\tlines.push('');\n\t\tfor (const detail of result.details) {\n\t\t\tlines.push(` • ${detail}`);\n\t\t}\n\t}\n\treturn lines.join('\\n');\n}\n\n/**\n * Load multiple entity files\n */\nexport function loadEntitiesFromYaml(filePaths: string[]): {\n\tsuccesses: LoadResult[];\n\tfailures: LoadError[];\n} {\n\tconst successes: LoadResult[] = [];\n\tconst failures: LoadError[] = [];\n\n\tfor (const filePath of filePaths) {\n\t\tconst result = loadEntityFromYaml(filePath);\n\t\tif (result.success) {\n\t\t\tsuccesses.push(result);\n\t\t} else {\n\t\t\tfailures.push(result);\n\t\t}\n\t}\n\n\treturn { successes, failures };\n}\n\n// ============================================================================\n// Relationship YAML Loading\n// ============================================================================\n\nexport interface RelationshipLoadResult {\n\tsuccess: true;\n\tdefinition: RelationshipDefinition;\n\tfilePath: string;\n}\n\nexport interface RelationshipLoadError {\n\tsuccess: false;\n\terror: string;\n\tdetails?: string[];\n\tfilePath: string;\n}\n\nexport type LoadRelationshipResult =\n\t| RelationshipLoadResult\n\t| RelationshipLoadError;\n\n/**\n * Load and validate a relationship definition from a YAML file\n */\nexport function loadRelationshipFromYaml(\n\tfilePath: string,\n): LoadRelationshipResult {\n\tif (!existsSync(filePath)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: `File not found: ${filePath}`,\n\t\t\tfilePath,\n\t\t};\n\t}\n\n\tlet content: string;\n\ttry {\n\t\tcontent = readFileSync(filePath, 'utf-8');\n\t} catch (err) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: `Failed to read file: ${filePath}`,\n\t\t\tdetails: [err instanceof Error ? err.message : String(err)],\n\t\t\tfilePath,\n\t\t};\n\t}\n\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = parseYaml(content);\n\t} catch (err) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: `Invalid YAML syntax in ${filePath}`,\n\t\t\tdetails: [err instanceof Error ? err.message : String(err)],\n\t\t\tfilePath,\n\t\t};\n\t}\n\n\tconst result = RelationshipDefinitionSchema.safeParse(parsed);\n\tif (!result.success) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: `Validation failed for ${filePath}`,\n\t\t\tdetails: formatZodErrors(result.error),\n\t\t\tfilePath,\n\t\t};\n\t}\n\n\treturn {\n\t\tsuccess: true,\n\t\tdefinition: result.data,\n\t\tfilePath,\n\t};\n}\n\n/**\n * Load multiple relationship files\n */\nexport function loadRelationshipsFromYaml(filePaths: string[]): {\n\tsuccesses: RelationshipLoadResult[];\n\tfailures: RelationshipLoadError[];\n} {\n\tconst successes: RelationshipLoadResult[] = [];\n\tconst failures: RelationshipLoadError[] = [];\n\n\tfor (const filePath of filePaths) {\n\t\tconst result = loadRelationshipFromYaml(filePath);\n\t\tif (result.success) {\n\t\t\tsuccesses.push(result);\n\t\t} else {\n\t\t\tfailures.push(result);\n\t\t}\n\t}\n\n\treturn { successes, failures };\n}\n\n// ============================================================================\n// Event YAML Loading\n// ============================================================================\n\nexport interface EventLoadResult {\n\tsuccess: true;\n\tdefinition: EventDefinition;\n\tfilePath: string;\n}\n\nexport interface EventLoadError {\n\tsuccess: false;\n\terror: string;\n\tdetails?: string[];\n\tfilePath: string;\n}\n\nexport type LoadEventResult = EventLoadResult | EventLoadError;\n\n/**\n * Load and validate a single event definition from a YAML file.\n *\n * Mirrors {@link loadEntityFromYaml}: existence check → readFileSync →\n * parseYaml → `EventDefinitionSchema.safeParse`. Returns a discriminated\n * result; callers are expected to aggregate into `AnalysisIssue`s rather\n * than throw.\n */\nexport function loadEventFromYaml(filePath: string): LoadEventResult {\n\tif (!existsSync(filePath)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: `File not found: ${filePath}`,\n\t\t\tfilePath,\n\t\t};\n\t}\n\n\tlet content: string;\n\ttry {\n\t\tcontent = readFileSync(filePath, 'utf-8');\n\t} catch (err) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: `Failed to read file: ${filePath}`,\n\t\t\tdetails: [err instanceof Error ? err.message : String(err)],\n\t\t\tfilePath,\n\t\t};\n\t}\n\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = parseYaml(content);\n\t} catch (err) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: `Invalid YAML syntax in ${filePath}`,\n\t\t\tdetails: [err instanceof Error ? err.message : String(err)],\n\t\t\tfilePath,\n\t\t};\n\t}\n\n\tconst result = EventDefinitionSchema.safeParse(parsed);\n\tif (!result.success) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: `Validation failed for ${filePath}`,\n\t\t\tdetails: formatZodErrors(result.error),\n\t\t\tfilePath,\n\t\t};\n\t}\n\n\treturn {\n\t\tsuccess: true,\n\t\tdefinition: result.data,\n\t\tfilePath,\n\t};\n}\n\n/**\n * Detect whether a YAML file is an entity or relationship definition.\n * Checks for the top-level discriminator key.\n */\nexport function detectYamlType(\n\tfilePath: string,\n): 'entity' | 'relationship' | 'unknown' {\n\tif (!existsSync(filePath)) return 'unknown';\n\n\ttry {\n\t\tconst content = readFileSync(filePath, 'utf-8');\n\t\tconst parsed = parseYaml(content) as Record<string, unknown>;\n\t\tif (parsed && typeof parsed === 'object') {\n\t\t\tif ('entity' in parsed) return 'entity';\n\t\t\tif ('relationship' in parsed) return 'relationship';\n\t\t}\n\t} catch {\n\t\t// Fall through\n\t}\n\treturn 'unknown';\n}\n","import { z } from \"zod\";\nimport { DetectionConfigSchema } from \"../../runtime/subsystems/sync\";\n\n/**\n * Entity Definition Schema\n *\n * Generates backend code:\n * - Domain entity + repository interface\n * - Application DTOs, use-cases, queries\n * - Infrastructure Drizzle schema + repository\n * - Presentation controller\n * - NestJS module wiring\n * - Shared Zod schema in packages/db\n *\n * Generates frontend code:\n * - Entity metadata for automatic admin panels\n * - UI type, importance, grouping for fields\n */\n\n// ============================================================================\n// Field Types\n// ============================================================================\n\nconst FieldTypeSchema = z.enum([\n \"string\",\n \"integer\",\n \"decimal\",\n \"boolean\",\n \"uuid\",\n \"date\",\n \"datetime\",\n \"json\",\n \"entity_ref\", // Polymorphic reference: generates {field}EntityType + {field}EntityId columns\n \"string_array\", // Array of strings: generates text[] column\n \"enum\", // Enum type with choices or choices_from\n]);\n\nexport type FieldType = z.infer<typeof FieldTypeSchema>;\n\n// ============================================================================\n// UI Metadata Types\n// ============================================================================\n\nconst UiTypeSchema = z.enum([\n \"text\",\n \"textarea\",\n \"number\",\n \"money\",\n \"percentage\",\n \"email\",\n \"url\",\n \"date\",\n \"datetime\",\n \"boolean\",\n \"enum\",\n \"reference\",\n \"json\",\n \"badge\",\n \"password\",\n]);\n\nexport type UiType = z.infer<typeof UiTypeSchema>;\n\nconst UiImportanceSchema = z.enum([\"primary\", \"secondary\", \"tertiary\"]);\n\nexport type UiImportance = z.infer<typeof UiImportanceSchema>;\n\n/**\n * UI Metadata Schema - Optional field-level UI properties\n *\n * All properties are optional and will be inferred at generation time\n * if not explicitly specified in the YAML definition.\n */\n// ============================================================================\n// Semantic / Analytics Metadata Types\n// ============================================================================\n\nconst AnalyticsAggregationSchema = z.enum([\n 'sum',\n 'min',\n 'max',\n 'count',\n 'count_distinct',\n 'average',\n 'median',\n 'percentile',\n 'sum_boolean',\n]);\n\nconst AnalyticsDimensionTypeSchema = z.enum(['categorical', 'time']);\n\nconst AnalyticsEntityTypeSchema = z.enum(['primary', 'unique', 'foreign', 'natural']);\n\nconst AnalyticsTimeGranularitySchema = z.enum(['day', 'week', 'month', 'quarter', 'year']);\n\nconst AnalyticsVisibilitySchema = z.enum(['internal', 'agent', 'public']);\n\nconst NonAdditiveDimensionSchema = z.union([\n z.string(),\n z.object({\n name: z.string(),\n window_choice: z.string().optional(),\n window_groupings: z.array(z.string()).optional(),\n }),\n]);\n\n/**\n * Semantic Metadata Schema - Optional field-level analytics properties\n *\n * Controls how a field is exposed to the cube.js semantic layer:\n * measures, dimensions, entities, and their configuration.\n */\nconst SemanticMetadataSchema = z.object({\n measure: z.boolean().optional(),\n analytics_aggregation: AnalyticsAggregationSchema.optional(),\n agg_time_dimension: z.string().optional(),\n non_additive_dimension: NonAdditiveDimensionSchema.optional(),\n dimension: z.boolean().optional(),\n dimension_type: AnalyticsDimensionTypeSchema.optional(),\n time_granularity: AnalyticsTimeGranularitySchema.optional(),\n is_partition: z.boolean().optional(),\n entity: z.boolean().optional(),\n entity_type: AnalyticsEntityTypeSchema.optional(),\n entity_role: z.string().optional(),\n analytics_visibility: AnalyticsVisibilitySchema.optional(),\n semantic_expr: z.string().optional(),\n semantic_label: z.string().optional(),\n});\n\nconst UiMetadataSchema = z.object({\n ui_label: z.string().optional(),\n ui_type: UiTypeSchema.optional(),\n ui_importance: UiImportanceSchema.optional(),\n ui_group: z.string().optional(),\n ui_sortable: z.boolean().optional(),\n ui_filterable: z.boolean().optional(),\n ui_visible: z.boolean().optional(),\n ui_placeholder: z.string().optional(),\n ui_help: z.string().optional(),\n ui_format: z.record(z.unknown()).optional(),\n});\n\n// ============================================================================\n// Field Definition\n// ============================================================================\n\n/**\n * Field Definition Schema\n *\n * Semantics:\n * - `required: true` → Field must be provided on CREATE (DTO validation)\n * - `required: false` → Field is optional on CREATE (DTO validation)\n * - `nullable: true` → Database column allows NULL\n * - `nullable: false` (default) → Database column is NOT NULL\n *\n * Common patterns:\n * - `required: true` (nullable defaults to false) → Must provide, cannot be null\n * - `required: false, nullable: true` → Optional field, can be null\n * - `required: true, nullable: true` → INVALID (rejected by validator)\n * - `required: false, nullable: false` → Has default value in DB\n */\n/**\n * Base Field Schema - Core database/type properties\n */\nconst BaseFieldSchema = z.object({\n type: FieldTypeSchema,\n required: z.boolean().optional().default(false),\n nullable: z.boolean().optional().default(false),\n\n // String constraints\n max_length: z.number().int().positive().optional(),\n min_length: z.number().int().nonnegative().optional(),\n\n // Numeric constraints\n min: z.number().optional(),\n max: z.number().optional(),\n\n // Enum/choices (inline definition)\n choices: z.array(z.string()).optional(),\n\n // Enum/choices from external file (e.g., \"relationship_types.yaml\")\n // Mutually exclusive with choices - parser loads file and extracts keys\n choices_from: z.string().optional(),\n\n // Entity reference: allowed entity types for polymorphic refs\n // Required when type is 'entity_ref'\n allowed_types: z.array(z.string()).optional(),\n\n // Default value\n default: z.unknown().optional(),\n\n // Indexing\n index: z.boolean().optional(),\n unique: z.boolean().optional(),\n\n // Foreign key reference (e.g., \"accounts.id\")\n foreign_key: z.string().optional(),\n});\n\n/**\n * Field Definition Schema - Combines base fields with optional UI metadata\n */\nconst FieldDefinitionSchema = BaseFieldSchema.merge(UiMetadataSchema).merge(SemanticMetadataSchema)\n .refine((data) => !(data.required === true && data.nullable === true), {\n message:\n \"'required: true' and 'nullable: true' cannot both be set. A required field cannot be null.\",\n path: [\"required\"],\n })\n .refine(\n (data) => {\n if (data.min_length !== undefined && data.type !== \"string\") {\n return false;\n }\n return true;\n },\n {\n message: \"'min_length' can only be used with type 'string'\",\n path: [\"min_length\"],\n },\n )\n .refine(\n (data) => {\n if (data.max_length !== undefined && data.type !== \"string\") {\n return false;\n }\n return true;\n },\n {\n message: \"'max_length' can only be used with type 'string'\",\n path: [\"max_length\"],\n },\n )\n .refine(\n (data) => {\n if (\n data.min !== undefined &&\n ![\"integer\", \"decimal\"].includes(data.type)\n ) {\n return false;\n }\n return true;\n },\n {\n message: \"'min' can only be used with numeric types\",\n path: [\"min\"],\n },\n )\n .refine(\n (data) => {\n if (\n data.max !== undefined &&\n ![\"integer\", \"decimal\"].includes(data.type)\n ) {\n return false;\n }\n return true;\n },\n {\n message: \"'max' can only be used with numeric types\",\n path: [\"max\"],\n },\n )\n .refine(\n (data) => {\n // entity_ref requires allowed_types\n if (data.type === \"entity_ref\" && !data.allowed_types?.length) {\n return false;\n }\n return true;\n },\n {\n message: \"'entity_ref' type requires 'allowed_types' to be specified\",\n path: [\"allowed_types\"],\n },\n )\n .refine(\n (data) => {\n // allowed_types only valid for entity_ref\n if (data.allowed_types !== undefined && data.type !== \"entity_ref\") {\n return false;\n }\n return true;\n },\n {\n message: \"'allowed_types' can only be used with type 'entity_ref'\",\n path: [\"allowed_types\"],\n },\n )\n .refine(\n (data) => {\n // choices and choices_from are mutually exclusive\n if (data.choices !== undefined && data.choices_from !== undefined) {\n return false;\n }\n return true;\n },\n {\n message: \"'choices' and 'choices_from' cannot both be specified\",\n path: [\"choices_from\"],\n },\n )\n .refine(\n (data) => {\n // enum type requires either choices or choices_from\n if (data.type === \"enum\" && !data.choices?.length && !data.choices_from) {\n return false;\n }\n return true;\n },\n {\n message: \"'enum' type requires either 'choices' or 'choices_from'\",\n path: [\"choices\"],\n },\n )\n .refine(\n (data) => {\n // If measure is true, analytics_aggregation must be present\n if (data.measure === true && !data.analytics_aggregation) {\n return false;\n }\n return true;\n },\n {\n message:\n \"When 'measure' is true, 'analytics_aggregation' must be specified\",\n path: [\"analytics_aggregation\"],\n },\n );\n\nexport type FieldDefinition = z.infer<typeof FieldDefinitionSchema>;\n\n// ============================================================================\n// Relationship Definition\n// ============================================================================\n\nconst RelationshipTypeSchema = z.enum([\"belongs_to\", \"has_many\", \"has_one\"]);\n\n/**\n * on_delete — governs database-level FK cascade behaviour for hard-deletes.\n *\n * Applies only to belongs_to relations; ignored on has_many / has_one.\n * Per ADR-021, this has NO effect under soft-delete: BaseService.delete()\n * issues an UPDATE (sets deleted_at), never a DELETE, so Postgres cascade\n * rules never fire for a soft-deleted parent.\n *\n * | Value | Emitted Drizzle | Postgres behaviour |\n * |-------------|------------------------------|---------------------------------------|\n * | restrict | { onDelete: 'restrict' } | Parent DELETE fails if children exist. DEFAULT. |\n * | cascade | { onDelete: 'cascade' } | Parent DELETE removes children. |\n * | set_null | { onDelete: 'set null' } | Parent DELETE nulls FK on children. Requires nullable: true. |\n * | no_action | { onDelete: 'no action' } | Deferred check (equivalent to restrict in single-statement txns). |\n *\n * See docs/adrs/ADR-021-on-delete-semantics.md for the full decision.\n */\nexport const OnDeleteSchema = z.enum([\"restrict\", \"cascade\", \"set_null\", \"no_action\"]);\n\nexport type OnDelete = z.infer<typeof OnDeleteSchema>;\n\nconst RelationshipSchema = z\n .object({\n type: RelationshipTypeSchema,\n target: z.string(), // Target entity name (e.g., \"account\")\n foreign_key: z.string(), // FK field name (e.g., \"account_id\")\n through: z.string().optional(), // For transitive: \"owned_opportunities.updates\"\n inverse: z.string().optional(), // Name of inverse relationship on target entity\n nullable: z.boolean().optional(), // Whether the FK column allows NULL\n on_delete: OnDeleteSchema.optional().default(\"restrict\"), // FK cascade action (belongs_to only; hard-delete only)\n })\n .strict()\n .refine(\n (data) => {\n // set_null requires nullable: true — Postgres cannot null a NOT NULL column\n if (data.on_delete === \"set_null\" && data.nullable !== true) {\n return false;\n }\n return true;\n },\n {\n message:\n \"'on_delete: set_null' requires 'nullable: true' — Postgres cannot null a NOT NULL FK column.\",\n path: [\"on_delete\"],\n },\n );\n\nexport type Relationship = z.infer<typeof RelationshipSchema>;\n\n// ============================================================================\n// Behavior Configuration\n// ============================================================================\n\n/**\n * Behavior configuration can be:\n * - A simple string: \"timestamps\"\n * - An object with options: { name: \"sluggable\", options: { source: \"title\" } }\n *\n * Built-in behaviors:\n * - timestamps: Adds created_at, updated_at fields\n * - soft_delete: Adds deleted_at field, filters deleted records\n * - user_tracking: Adds created_by, updated_by fields\n * - temporal_validity: Adds valid_from, valid_to, is_active fields\n * with deactivate() method and validity-aware query filtering\n */\nconst BehaviorConfigSchema = z.union([\n z.string(),\n z.object({\n name: z.string(),\n options: z.record(z.unknown()).optional(),\n }),\n]);\n\nexport type BehaviorConfig = z.infer<typeof BehaviorConfigSchema>;\n\n/**\n * Behavior strategy for repository code generation\n * - base_class: Extend BaseRepository (DRY, recommended)\n * - inline: Generate all code directly (WET, full transparency)\n */\nconst BehaviorStrategySchema = z.enum([\"base_class\", \"inline\"]);\n\nexport type BehaviorStrategy = z.infer<typeof BehaviorStrategySchema>;\n\n// ============================================================================\n// Entity Configuration\n// ============================================================================\n\n/**\n * Layout: Folder structure - controls directory nesting\n * - nested: domain/opportunity/opportunity.entity.ts\n * - flat: domain/opportunity.entity.ts\n */\nconst FolderStructureSchema = z.enum([\"nested\", \"flat\"]).default(\"nested\");\n\n/**\n * Layout: File grouping - controls how related code is organized\n * - separate: Each concern in its own file (entity.ts, repository.interface.ts)\n * - grouped: Related concerns combined into index.ts\n *\n * This is orthogonal to folder_structure:\n * | folder_structure | file_grouping | Result |\n * |-----------------|---------------|--------|\n * | nested | separate | domain/opportunity/opportunity.entity.ts |\n * | nested | grouped | domain/opportunity/index.ts (combined) |\n * | flat | separate | domain/opportunity.entity.ts |\n * | flat | grouped | domain/opportunity.ts (combined) |\n */\nconst FileGroupingSchema = z.enum([\"separate\", \"grouped\"]).default(\"separate\");\n\n/**\n * Expose configuration - which layers to generate for this entity\n * - repository: Always generated (domain entity, repository interface/impl)\n * - rest: Generate REST controller\n * - trpc: Generate tRPC module\n * - electric: Generate Electric SQL migration (REPLICA IDENTITY + publication)\n *\n * Default: ['repository', 'rest', 'trpc'] (all layers)\n */\nconst ExposeLayerSchema = z.enum([\"repository\", \"rest\", \"trpc\", \"electric\"]);\nexport type ExposeLayer = z.infer<typeof ExposeLayerSchema>;\n\nconst EntityConfigSchema = z\n .object({\n name: z\n .string()\n .regex(\n /^[a-z][a-z0-9_]*$/,\n \"Entity name must be lowercase with underscores (e.g., 'opportunity')\",\n ),\n plural: z.string().regex(/^[a-z][a-z0-9_]*$/, \"Plural must be lowercase\"),\n table: z.string().regex(/^[a-z][a-z0-9_]*$/, \"Table must be lowercase\"),\n\n // Layout options (orthogonal concerns)\n // folder_structure: controls directory nesting\n // file_grouping: controls file organization\n folder_structure: FolderStructureSchema.optional(),\n file_grouping: FileGroupingSchema.optional(),\n\n // Per-entity behavior strategy override (overrides codegen.config.yaml)\n behavior_strategy: BehaviorStrategySchema.optional(),\n // Which layers to generate (default: all)\n expose: z\n .array(ExposeLayerSchema)\n .optional()\n .default([\"repository\", \"rest\", \"trpc\"]),\n\n // App-defined patterns (ADR-031, supersedes ADR-005 family:).\n // `pattern:` and `patterns:` are mutually exclusive — use `pattern:`\n // for a single pattern and `patterns:` for multi-pattern composition.\n // Pattern names resolve against the registry at codegen time.\n pattern: z.string().optional(),\n patterns: z.array(z.string()).optional(),\n // Per-pattern config, keyed by pattern name. Each value is validated\n // against the pattern's `configSchema` in composition validation\n // (src/patterns/validate-composition.ts — PATTERN-4).\n config: z.record(z.string(), z.unknown()).optional(),\n\n // JOB-7: marks this entity as a valid scope target for job scoping.\n // Drives the generated ScopeEntityType union in\n // runtime/subsystems/jobs/generated/scope-entity-type.ts.\n scopeable: z.boolean().optional(),\n })\n .strict()\n .refine((d) => !(d.pattern && d.patterns), {\n message: \"'pattern' and 'patterns' are mutually exclusive\",\n });\n\nexport type EntityConfig = z.infer<typeof EntityConfigSchema>;\n\n// ============================================================================\n// Query Declaration\n// ============================================================================\n\n/**\n * Query Declaration Schema - Declarative query generation (ADR-005)\n *\n * Each declaration generates repository + service + use case methods.\n *\n * Examples:\n * { by: [\"user_id\"] }\n * { by: [\"email\"], unique: true }\n * { by: [\"account_id\"], order: \"created_at desc\", limit: true }\n * { by: [\"opportunity_id\"], select: [\"email\"], via: \"opportunity_contact_link\" }\n */\nconst QueryDeclarationSchema = z.object({\n by: z.array(z.string()).min(1),\n unique: z.boolean().optional(),\n select: z.array(z.string()).optional(),\n order: z.string().optional(),\n limit: z.boolean().optional(),\n via: z.string().optional(),\n});\n\nexport type QueryDeclaration = z.infer<typeof QueryDeclarationSchema>;\n\n/**\n * Search Query Declaration — filtered search with pagination.\n *\n * Emits:\n * - `searchXs(input): Promise<Page<Entity>>` on the service\n * - `GET /xs/search` controller route with Zod filter schema\n * - `SearchXsUseCase` with filter-AND + count-for-total semantics\n *\n * Example:\n * - name: search\n * filters: [user_id, provider, is_visible, canonical_state, is_closed]\n * search: name # optional ilike on a single text column\n * paginate: true # defaults to limit 50, max 200, offset 0\n *\n * Consumer contract: `@shared/http/pagination` must export\n * `PaginationSchema` (z.object with limit+offset defaults) and a\n * `Page<T>` interface with `{ items, total, limit, offset }`.\n */\nconst SearchQueryDeclarationSchema = z.object({\n name: z.literal('search'),\n filters: z.array(z.string()).min(1),\n search: z.string().optional(),\n paginate: z.boolean().optional().default(true),\n order: z.string().optional(),\n});\n\nexport type SearchQueryDeclaration = z.infer<typeof SearchQueryDeclarationSchema>;\n\n/**\n * Discriminated union: query declarations can be either the legacy\n * by-column findByX form or the named-search form. The two shapes are\n * disjoint (no `name` vs required `name: 'search'`), so consumers can\n * mix them in the same `queries:` block.\n */\nconst AnyQueryDeclarationSchema = z.union([\n SearchQueryDeclarationSchema,\n QueryDeclarationSchema,\n]);\n\n// ============================================================================\n// Sync Configuration\n// ============================================================================\n\n/**\n * Direction of sync with an external provider\n */\nexport const SyncDirectionSchema = z.enum([\n 'inbound',\n 'outbound',\n 'bidirectional',\n]);\n\nexport type SyncDirection = z.infer<typeof SyncDirectionSchema>;\n\n/**\n * Per-provider sync configuration\n */\nexport const ProviderSyncSchema = z.object({\n remote_entity: z.string(),\n direction: SyncDirectionSchema,\n cdc: z.boolean().optional().default(false),\n field_mapping: z.record(z.string(), z.string()).optional(),\n read_only_fields: z.array(z.string()).optional(),\n});\n\nexport type ProviderSync = z.infer<typeof ProviderSyncSchema>;\n\n/**\n * Top-level sync block: Electric SQL + named provider configs\n */\nexport const SyncConfigSchema = z.object({\n electric: z.boolean().optional().default(false),\n providers: z.record(z.string(), ProviderSyncSchema).optional(),\n});\n\nexport type SyncConfig = z.infer<typeof SyncConfigSchema>;\n\n// ============================================================================\n// Event Declaration\n// ============================================================================\n\n/**\n * Event Declaration Schema - Domain event declarations (CODEGEN-EVOLUTION-PLAN Phase 2)\n *\n * Each declaration generates typed event classes, handlers, and queue registration.\n *\n * Example:\n * name: opportunity_stage_changed\n * queue: domain-events\n * body:\n * opportunity_id: uuid\n * old_stage: string\n * generate_handler: true\n */\nconst EventDeclarationSchema = z.object({\n name: z\n .string()\n .regex(/^[a-z][a-z0-9_]*$/, \"Event name must be snake_case\"),\n queue: z.string(),\n body: z.record(z.string(), z.string()),\n generate_handler: z.boolean().optional().default(false),\n});\n\nexport type EventDeclaration = z.infer<typeof EventDeclarationSchema>;\n\n// ============================================================================\n// Analytics Block (entity-level)\n// ============================================================================\n\n/**\n * Simple metric in a YAML metric definition\n */\nconst SimpleMetricSchema = z.object({\n type: z.literal('simple'),\n measure: z.string(),\n agg: AnalyticsAggregationSchema.optional(),\n filter: z.string().optional(),\n description: z.string().optional(),\n label: z.string().optional(),\n});\n\n/**\n * Derived metric — expression combining other metrics\n */\nconst DerivedMetricSchema = z.object({\n type: z.literal('derived'),\n expr: z.string(),\n metrics: z.array(z.string()),\n description: z.string().optional(),\n label: z.string().optional(),\n});\n\n/**\n * Ratio metric — numerator / denominator\n */\nconst RatioMetricSchema = z.object({\n type: z.literal('ratio'),\n numerator: z.union([z.string(), SimpleMetricSchema]),\n denominator: z.union([z.string(), SimpleMetricSchema]),\n filter: z.string().optional(),\n description: z.string().optional(),\n label: z.string().optional(),\n});\n\n/**\n * Cumulative metric — time-series accumulation\n */\nconst CumulativeMetricSchema = z.object({\n type: z.literal('cumulative'),\n measure: z.string(),\n window: z.string().optional(),\n grain_to_date: AnalyticsTimeGranularitySchema.optional(),\n description: z.string().optional(),\n label: z.string().optional(),\n});\n\n/**\n * Discriminated union of all four metric types\n */\nconst MetricDefinitionSchema = z.discriminatedUnion('type', [\n SimpleMetricSchema,\n DerivedMetricSchema,\n RatioMetricSchema,\n CumulativeMetricSchema,\n]);\n\nexport type MetricDefinition = z.infer<typeof MetricDefinitionSchema>;\n\n/**\n * Entity-level analytics block\n *\n * Declared in the YAML under `analytics:` alongside fields and relationships.\n */\nconst AnalyticsBlockSchema = z.object({\n measure_packs: z.array(z.string()).optional(),\n cube_name: z.string().optional(),\n metrics: z.record(z.string(), MetricDefinitionSchema).optional(),\n});\n\nexport type AnalyticsBlock = z.infer<typeof AnalyticsBlockSchema>;\n\n// ============================================================================\n// Full Entity Definition\n// ============================================================================\n\n// ============================================================================\n// Generation Toggles\n// ============================================================================\n\n/**\n * Per-entity opt-outs for code generation.\n *\n * - `writes`: when `false`, suppresses create/update/delete use cases,\n * matching controller routes, and module providers. Defaults to `true`.\n */\nconst GenerateConfigSchema = z\n .object({\n writes: z.boolean().optional().default(true),\n })\n .strict();\n\nexport type GenerateConfig = z.infer<typeof GenerateConfigSchema>;\n\nexport const EntityDefinitionSchema = z\n .object({\n entity: EntityConfigSchema,\n fields: z.record(z.string(), FieldDefinitionSchema),\n relationships: z.record(z.string(), RelationshipSchema).optional(),\n // Behaviors add cross-cutting concerns (timestamps, soft_delete, user_tracking, etc.)\n behaviors: z.array(BehaviorConfigSchema).optional().default([]),\n\n // Per-entity generation toggles (e.g. disable write-side emission)\n generate: GenerateConfigSchema.optional(),\n\n // EAV (entity-attribute-value) dual-write + paired reads (ADR-13).\n // When `true`, codegen emits:\n // - FindXWithFieldsUseCase + ListXWithFieldsUseCase (paired reads)\n // - CreateX / UpdateX use cases in transactional compound-write shape\n // (composes entity service + FieldValueService in one db.transaction,\n // splits `{ fields, ...core }` from the DTO)\n // - GET /:id/with-fields + GET /with-fields controller routes\n // - Service with injected FieldValueRepository + findByIdWithFields /\n // listWithFields paired read methods\n //\n // Consumer contract (must be in place before regen):\n // - BaseService.create/update/delete accept optional `tx` parameter\n // - `@shared/eav-helpers` exports `toEavRows(entityId, entityType, fields)`\n // and `mergeEavRows(rows)`\n // - FieldValueService exposes `upsertMany(rows, tx?)` (inherited from\n // MetadataEntityService)\n // - DRIZZLE_DB injection token available via `@shared/constants/tokens`\n //\n // Defaults to `false` — opt in per entity that needs dynamic/custom fields.\n eav: z.boolean().optional().default(false),\n\n // Declare this entity IS an EAV value table. When `true`, codegen emits\n // the compound EAV methods (upsertFieldsTransactional, findMergedByEntity)\n // on the service and the upsertCurrentValues method on the repository —\n // no hand extension required. Companion flag `eav_definition_table`\n // identifies the sibling entity that stores the field-key ↔ id lookup.\n //\n // Mutually exclusive with `eav: true` in practice — a value table holds\n // OTHER entities' dynamic fields, it isn't itself an EAV-opt-in entity.\n //\n // Assumption (v1): value tables have a `user_id` column. Future\n // `eav_user_scoped: false` flag will relax this for audit/system EAV.\n eav_value_table: z.boolean().optional().default(false),\n\n // Singular entity name of the field-definitions entity that pairs with\n // this value table (matches the `target:` convention in relationship\n // YAMLs). Required when `eav_value_table: true`; ignored otherwise.\n eav_definition_table: z.string().optional(),\n\n\n // v2: Declarative query generation (ADR-005)\n // Generates repository + service + use case methods from declarations\n queries: z.array(AnyQueryDeclarationSchema).optional(),\n\n // v2: Integration sync configuration (CODEGEN-EVOLUTION-PLAN Phase 2)\n // Electric SQL + provider sync (Salesforce, HubSpot, etc.)\n sync: SyncConfigSchema.optional(),\n\n // ADR-033.1: Provider-keyed change-source detection.\n //\n // Map of provider name → DetectionConfig. Single-provider entities use\n // a one-key map; multi-provider entities list each provider as a\n // separate key. Each value is an independent `DetectionConfig` (its\n // own mode/cursor/mapping/filters) sourced from the canonical schema\n // in `runtime/subsystems/sync` so this validator and the runtime\n // parser stay in lockstep.\n //\n // Within-file cross-check (ADR-033.1 §6): every key here must also\n // appear in `sync.providers` — see the superRefine on\n // `EntityDefinitionSchema` below.\n detection: z.record(z.string(), DetectionConfigSchema).optional(),\n\n // v2: Domain event declarations (CODEGEN-EVOLUTION-PLAN Phase 2)\n // Generates typed event classes, handlers, and queue registration\n events: z.array(EventDeclarationSchema).optional(),\n\n // EVT-7: Opt-in typed event emission. Each entry names an `EventDefinition`\n // (top-level `events/<type>.yaml` or an inline `events:` block entry) that\n // the generated use-cases should publish via `TypedEventBus.publish(...)`\n // inside a Drizzle transaction.\n //\n // emits: [contact_created, contact_updated]\n //\n // Cross-validated in `validateEntityEmits()` against the merged event\n // registry. `undefined` ⇒ fallback to untyped lifecycle-events + warning;\n // `[]` ⇒ explicit opt-out, no warning, no typed emission.\n emits: z\n .array(\n z\n .string()\n .regex(/^[a-z][a-z0-9_]*$/, 'emits entries must be snake_case event type names'),\n )\n .optional(),\n\n // v2: Analytics / semantic layer configuration\n // Cube.js measure packs, custom cube name, and metric definitions\n analytics: AnalyticsBlockSchema.optional(),\n })\n .strict()\n .refine(\n (data) => !data.eav_value_table || typeof data.eav_definition_table === 'string',\n {\n message:\n \"`eav_definition_table` is required when `eav_value_table: true` — \" +\n \"declare the singular entity name of the paired field-definitions entity \" +\n \"(e.g. `eav_definition_table: 'field_definition'`).\",\n path: ['eav_definition_table'],\n },\n )\n .superRefine((entity, ctx) => {\n if (!entity.detection) return;\n const declared = new Set(Object.keys(entity.sync?.providers ?? {}));\n for (const provider of Object.keys(entity.detection)) {\n if (!declared.has(provider)) {\n ctx.addIssue({\n code: 'custom',\n path: ['detection', provider],\n message: `Provider '${provider}' used in detection: but not declared in sync.providers. Known providers: ${[...declared].join(', ')}`,\n });\n }\n }\n });\n\nexport type EntityDefinition = z.infer<typeof EntityDefinitionSchema>;\n\n// ============================================================================\n// Validation Helpers\n// ============================================================================\n\nexport function validateEntityDefinition(data: unknown): EntityDefinition {\n return EntityDefinitionSchema.parse(data);\n}\n\nexport function safeValidateEntityDefinition(data: unknown): {\n success: boolean;\n data?: EntityDefinition;\n error?: z.ZodError;\n} {\n const result = EntityDefinitionSchema.safeParse(data);\n if (result.success) {\n return { success: true, data: result.data };\n }\n return { success: false, error: result.error };\n}\n\n// ============================================================================\n// Type Mapping Utilities (for code generation)\n// ============================================================================\n\n/**\n * Maps YAML field types to TypeScript types\n *\n * Note: 'entity_ref' is handled specially in templates as it generates\n * two fields: {field}EntityType (EntityType enum) and {field}EntityId (string)\n */\nexport const fieldTypeToTypeScript: Record<FieldType, string> = {\n string: \"string\",\n integer: \"number\",\n decimal: \"number\",\n boolean: \"boolean\",\n uuid: \"string\",\n date: \"Date\",\n datetime: \"Date\",\n json: \"unknown\",\n entity_ref: \"EntityRef\", // Placeholder - templates handle specially\n string_array: \"string[]\",\n enum: \"string\", // Actual enum type generated from choices\n};\n\n/**\n * Maps YAML field types to Drizzle column types\n *\n * Note: 'entity_ref' generates two columns: pgEnum + uuid\n * Note: 'enum' uses pgEnum with choices\n */\nexport const fieldTypeToDrizzle: Record<FieldType, string> = {\n string: \"varchar\",\n integer: \"integer\",\n decimal: \"decimal\",\n boolean: \"boolean\",\n uuid: \"uuid\",\n date: \"date\",\n datetime: \"timestamp\",\n json: \"jsonb\",\n entity_ref: \"entity_ref\", // Placeholder - templates handle specially (enum + uuid)\n string_array: \"text().array()\",\n enum: \"enum\", // Placeholder - templates generate pgEnum\n};\n\n/**\n * Maps YAML field types to Zod schema methods\n *\n * Note: 'entity_ref' generates two fields in Zod schema\n * Note: 'enum' uses z.enum() with choices\n */\nexport const fieldTypeToZod: Record<FieldType, string> = {\n string: \"z.string()\",\n integer: \"z.number().int()\",\n // Drizzle maps PG `numeric` to a JS string to preserve precision.\n // Using z.coerce.string() — not z.coerce.number() — prevents silent\n // precision loss on large decimal values. Matches clean-lite-ps (PR #42).\n decimal: \"z.coerce.string()\",\n boolean: \"z.boolean()\",\n uuid: \"z.string().uuid()\",\n date: \"z.date()\",\n datetime: \"z.date()\",\n json: \"z.unknown()\",\n entity_ref: \"entity_ref\", // Placeholder - templates handle specially\n string_array: \"z.array(z.string())\",\n enum: \"z.enum()\", // Placeholder - templates add choices\n};\n","/**\n * Sync subsystem — field-diff protocol (port)\n *\n * `IFieldDiffer<T>` is the pluggable differ seam. The default implementation\n * (`DeepEqualDiffer`, ships in SYNC-5) walks every field except an ignore\n * list; CDC-aware differs can skip comparison for fields the provider didn't\n * flag as changed.\n *\n * `FieldDiffSchema` is the structural enforcement of the `changed_fields`\n * column per ADR-0003 — enforced at write time by the recorder service so\n * consumers can rely on the shape in downstream queries.\n */\nimport { z } from 'zod';\n\n// ============================================================================\n// FieldDiff shape — the ADR-0003 contract\n// ============================================================================\n\n/**\n * Structured per-field change. Enforced shape for `sync_run_items.changed_fields`.\n *\n * `created` items set `from: null, to: <value>` for every non-null field.\n * `deleted` items set `from: <value>, to: null`.\n * `noop` items carry `{}`.\n */\nexport const FieldDiffValueSchema = z.object({\n from: z.unknown(),\n to: z.unknown(),\n});\n\nexport const FieldDiffSchema = z.record(z.string(), FieldDiffValueSchema);\n\nexport type FieldDiffValue = z.infer<typeof FieldDiffValueSchema>;\nexport type FieldDiff = z.infer<typeof FieldDiffSchema>;\n\n/** Result of comparing a new record against its existing local state. */\nexport type DiffResult = FieldDiff | 'noop';\n\n// ============================================================================\n// IFieldDiffer\n// ============================================================================\n\n/**\n * Pluggable differ. Default ships in SYNC-5 as `DeepEqualDiffer<T>` —\n * deep-equal over every field except an ignore list (`updated_at` and other\n * row metadata). CDC-aware differs restrict comparison to\n * `providerChangedFields` when supplied.\n */\nexport interface IFieldDiffer<T> {\n /**\n * @param existing — current local state, or `null` when the record is new\n * @param incoming — the canonical record coming from the adapter\n * @param providerChangedFields — optional hint from CDC-capable sources;\n * when present, differ may restrict the comparison to these fields\n */\n diff(\n existing: T | null,\n incoming: T,\n providerChangedFields?: string[],\n ): DiffResult;\n}\n","/**\n * Sync subsystem — DetectionConfig schema (#226-1)\n *\n * Canonical Zod schema for per-entity sync detection config. The schema is\n * the single source of truth for filter/mapping shape and is consumed by:\n *\n * 1. Runtime primitives — `PollChangeSource<T>`, `WebhookChangeSource<T>`\n * (#226-3, #226-4) accept a parsed `DetectionConfig` at construction.\n * 2. Codegen — `src/schema/entity-definition.schema.ts` (#226-6) imports\n * this schema so per-entity YAML `detection:` blocks validate against\n * the same shape the runtime enforces.\n *\n * Locked decisions (see ADR-033 + decision memo Q1–Q6):\n * - Filter vocabulary is flat AND of `{ field, op, value }` triples; richer\n * boolean expressions (OR / NOT / nested) are deferred per epic open Q3.\n * - Cursor strategy is a tagged union over the four shapes the three modes\n * need (`systemModstamp`, `replayId`, `timestamp`, `eventId`). Each\n * strategy types its cursor internally; the orchestrator persists what\n * the iterator last yielded (sync skill rule 2).\n * - `mode: 'poll'` may opt into `provenance: 'cdc'` so Stripe-style event\n * endpoints (mechanically a poll, semantically CDC) reuse the poll\n * primitive while emitting `Change<T>.source = 'cdc'`. Long-lived\n * streaming CDC (SFDC Pub-Sub, Debezium) is a separate primitive\n * deferred to #226-8.\n * - `webhook` mode requires `eventIdField` so `WebhookChangeSource<T>`\n * can populate `Change<T>.dedupKey` from the inbound staging row.\n */\nimport { z } from 'zod';\n\n// ============================================================================\n// Field mapping — provider field → canonical target\n// ============================================================================\n\n/**\n * Maps a single provider field onto the canonical record. `transform` is an\n * opt-in tag the adapter callback may inspect (`date-iso`, `decimal-string`,\n * etc.); the schema does not enumerate transforms — adapters interpret them.\n */\nexport const FieldMappingSchema = z.object({\n source: z.string().min(1),\n target: z.string().min(1),\n transform: z.string().min(1).optional(),\n});\n\nexport type FieldMapping = z.infer<typeof FieldMappingSchema>;\n\n// ============================================================================\n// Resolved filter — flat-AND triple\n// ============================================================================\n\n/**\n * A single resolved filter clause applied at fetch time. `value` is `unknown`\n * to admit primitives, arrays (for `in` / `nin`), and dates as ISO strings —\n * adapters interpret per provider.\n */\nexport const ResolvedFilterSchema = z.object({\n field: z.string().min(1),\n op: z.enum(['eq', 'neq', 'in', 'nin', 'gt', 'gte', 'lt', 'lte']),\n value: z.unknown(),\n});\n\nexport type ResolvedFilter = z.infer<typeof ResolvedFilterSchema>;\n\n// ============================================================================\n// Cursor strategy — tagged union over the four shapes the modes need\n// ============================================================================\n\nconst SystemModstampCursorSchema = z.object({\n kind: z.literal('systemModstamp'),\n field: z.string().min(1),\n});\n\nconst ReplayIdCursorSchema = z.object({\n kind: z.literal('replayId'),\n field: z.string().min(1),\n});\n\nconst TimestampCursorSchema = z.object({\n kind: z.literal('timestamp'),\n field: z.string().min(1),\n});\n\nconst EventIdCursorSchema = z.object({\n kind: z.literal('eventId'),\n field: z.string().min(1),\n});\n\nexport const CursorStrategySchema = z.discriminatedUnion('kind', [\n SystemModstampCursorSchema,\n ReplayIdCursorSchema,\n TimestampCursorSchema,\n EventIdCursorSchema,\n]);\n\nexport type CursorStrategy = z.infer<typeof CursorStrategySchema>;\n\n// ============================================================================\n// Mode-specific blocks\n// ============================================================================\n\n/**\n * Poll-mode block. `provenance: 'cdc'` opts the poll primitive into stamping\n * `Change<T>.source = 'cdc'` and populating `dedupKey` from the cursor's\n * `field` — used for Stripe-style event endpoints. Defaults to `'poll'`.\n */\nexport const PollDetectionSchema = z.object({\n cursor: CursorStrategySchema,\n provenance: z.enum(['poll', 'cdc']).optional(),\n});\n\nexport type PollDetection = z.infer<typeof PollDetectionSchema>;\n\n/**\n * Webhook-mode block. `eventIdField` names the column in the consumer-owned\n * inbound staging row that `WebhookChangeSource<T>` reads to set\n * `Change<T>.dedupKey`.\n */\nexport const WebhookDetectionSchema = z.object({\n eventIdField: z.string().min(1),\n});\n\nexport type WebhookDetection = z.infer<typeof WebhookDetectionSchema>;\n\n// ============================================================================\n// DetectionConfig — top-level discriminated union over `mode`\n// ============================================================================\n\nconst PollModeSchema = z.object({\n mode: z.literal('poll'),\n poll: PollDetectionSchema,\n mapping: z.array(FieldMappingSchema).min(1),\n filters: z.array(ResolvedFilterSchema).default([]),\n});\n\nconst WebhookModeSchema = z.object({\n mode: z.literal('webhook'),\n webhook: WebhookDetectionSchema,\n mapping: z.array(FieldMappingSchema).min(1),\n filters: z.array(ResolvedFilterSchema).default([]),\n});\n\n/**\n * Top-level detection config. Discriminated on `mode` so the relevant\n * mode-block (poll/webhook) is structurally required for that mode. CDC as a\n * long-lived streaming primitive is deferred (#226-8); CDC-as-provenance\n * (Stripe-style event endpoints) is expressed via `mode: 'poll'` with\n * `poll.provenance: 'cdc'`.\n */\nexport const DetectionConfigSchema = z.discriminatedUnion('mode', [\n PollModeSchema,\n WebhookModeSchema,\n]);\n\nexport type DetectionConfig = z.infer<typeof DetectionConfigSchema>;\n","/**\n * Sync subsystem — DI tokens\n *\n * String constants (not Symbols) so they match by value across import\n * boundaries — same convention as the events subsystem (`EVENT_BUS`). The\n * jobs subsystem uses Symbols for its analogous tokens; events and sync\n * stay internally consistent with strings.\n *\n * Usage in use cases:\n * ```ts\n * constructor(\n * @Inject(SYNC_CHANGE_SOURCE) private readonly source: IChangeSource<CanonicalOpportunity>,\n * @Inject(SYNC_CURSOR_STORE) private readonly cursors: ICursorStore,\n * @Inject(SYNC_FIELD_DIFFER) private readonly differ: IFieldDiffer<CanonicalOpportunity>,\n * @Inject(SYNC_SINK) private readonly sink: ISyncSink<CanonicalOpportunity>,\n * @Inject(SYNC_RUN_RECORDER) private readonly recorder: ISyncRunRecorder,\n * ) {}\n * ```\n *\n * Concrete bindings are registered by `SyncModule.forRoot(...)` (SYNC-6).\n */\n\nexport const SYNC_CHANGE_SOURCE = 'SYNC_CHANGE_SOURCE' as const;\nexport const SYNC_CURSOR_STORE = 'SYNC_CURSOR_STORE' as const;\nexport const SYNC_FIELD_DIFFER = 'SYNC_FIELD_DIFFER' as const;\nexport const SYNC_SINK = 'SYNC_SINK' as const;\n\n/**\n * Run-recorder token (SYNC-5). Backed by `ISyncRunRecorder`. Drizzle impl\n * lands in SYNC-4; tests provide inline fakes.\n */\nexport const SYNC_RUN_RECORDER = 'SYNC_RUN_RECORDER' as const;\n\n/**\n * Injection token for the resolved `SyncModuleOptions` object (SYNC-6).\n *\n * Backends that need to observe module configuration (e.g. `multiTenant`\n * flag, pool filters) inject via this token. Provided automatically by\n * `SyncModule.forRoot(...)` / `SyncModule.forRootAsync(...)`.\n */\nexport const SYNC_MODULE_OPTIONS = 'SYNC_MODULE_OPTIONS' as const;\n\n/**\n * Injection token for the resolved multi-tenancy flag (SYNC-6).\n *\n * Provided by `SyncModule.forRoot(...)` as `options.multiTenant ?? false`.\n * Consumed by `ExecuteSyncUseCase` to enforce the tenantId-is-required rule.\n */\nexport const SYNC_MULTI_TENANT = 'SYNC_MULTI_TENANT' as const;\n","/**\n * Typed errors + shared boundary helpers for the sync subsystem.\n *\n * Classes (not bare Error) so consumers can `instanceof` them in catch\n * blocks and exception filters can map them to HTTP codes.\n *\n * Mirrors the shape of `events-errors.ts` and `jobs-errors.ts`.\n */\n\n/**\n * Thrown by the Drizzle cursor-store / run-recorder backends AND by the\n * orchestrator entry point when `SYNC_MULTI_TENANT` is enabled but the\n * caller did not supply a non-null `tenantId`. Strict enforcement at the\n * boundary — explicit `null` still throws.\n *\n * Disable multi-tenancy on the module (`multiTenant: false`, the default)\n * to opt out of the requirement entirely.\n *\n * `operation` identifies the call site (e.g. `'cursor.put'`,\n * `'startRun'`, `'execute'`) so the stack-trace message points at the\n * specific boundary that rejected the input.\n */\nexport class MissingTenantIdError extends Error {\n override readonly name = 'MissingTenantIdError';\n constructor(operation: string) {\n super(\n `Missing tenantId for sync operation '${operation}'. SyncModule is ` +\n `configured with multiTenant: true — every call must include a ` +\n `non-null tenantId. Either pass the tenantId or disable multi-` +\n `tenancy on the module.`,\n );\n }\n}\n\n/**\n * Shared boundary guard — used at the orchestrator entry AND inside the\n * Drizzle backends. Keeping the check in one function guarantees every\n * `MissingTenantIdError` carries the same message shape regardless of the\n * site that raised it, which makes it easier for consumers to pattern-\n * match on the error in logs/metrics.\n *\n * When `multiTenant` is false, the function is a no-op — `tenantId` may\n * be anything (including `undefined`). When true, `undefined` or `null`\n * throws.\n */\nexport function assertTenantId(\n tenantId: string | null | undefined,\n options: { multiTenant: boolean; operation: string },\n): asserts tenantId is string {\n if (!options.multiTenant) return;\n if (tenantId === undefined || tenantId === null) {\n throw new MissingTenantIdError(options.operation);\n }\n}\n","/**\n * Drizzle schema for the sync subsystem audit/observability tables (SYNC-1).\n *\n * Three tables model end-to-end sync observability, keyed by the single port\n * every sync adapter implements (`IChangeSource<T>` from SYNC-2):\n *\n * - `sync_subscriptions` — owns the cursor per\n * `(integration_id, adapter, domain, external_ref)` tuple. Addressed\n * by id by `ICursorStore` (SYNC-3/SYNC-4).\n * - `sync_runs` — per-run audit log: start/complete, status,\n * cursor before/after, counts, direction (inbound|outbound),\n * action (poll|cdc|webhook|manual|writeback).\n * - `sync_run_items` — per-record change log with structured\n * `changed_fields` jsonb enforced by the Zod `FieldDiffSchema`\n * contract (ADR-0003; protocol lives in SYNC-2's\n * sync-field-diff.protocol.ts).\n *\n * Design calls (vs. issue #126 open questions):\n *\n * - `sync_subscriptions` ships in the subsystem (not consumer-owned).\n * Rationale: SYNC-4's `PostgresCursorStore` needs to read/write this\n * table directly; making it consumer-owned would require consumers to\n * hand-wire a shape the backend already knows. The row is addressable\n * by id and scoped by the uniqueness tuple; consumers can still\n * query/list it freely. Same stance as `job_run` being subsystem-\n * owned while remaining consumer-queryable.\n *\n * - `tenant_id` is always emitted on the three tables as nullable text.\n * The `SYNC_MULTI_TENANT` DI flag (SYNC-6) is what enforces the\n * non-null + cross-tenant-isolation contract at the service/orchestrator\n * boundary. This mirrors JOB-1/JOB-8's final shape — runtime guard, not\n * a scaffold-time conditional column. Keeps the schema file uniform\n * across single-tenant and multi-tenant deployments.\n *\n * - `changed_fields` on `sync_run_items` is typed via the Zod-inferred\n * `FieldDiff` shape from SYNC-2 (`{ [fieldName]: { from, to } }`). The\n * recorder service (SYNC-5) validates every write against\n * `FieldDiffSchema.parse` so consumers can rely on the shape.\n */\nimport {\n pgEnum,\n pgTable,\n uuid,\n text,\n jsonb,\n integer,\n boolean,\n timestamp,\n index,\n uniqueIndex,\n} from 'drizzle-orm/pg-core';\nimport type { InferSelectModel } from 'drizzle-orm';\n\nimport type { FieldDiff } from './sync-field-diff.protocol';\n\n// ─── Enums ──────────────────────────────────────────────────────────────────\n\n/**\n * Direction of a sync run relative to local state.\n *\n * - `inbound` — external → local (the common case: SFDC poll → local DB).\n * - `outbound` — local → external (writeback; deferred per epic but the\n * column shape is reserved so future writeback runs share the audit log).\n */\nexport const syncRunDirectionEnum = pgEnum('sync_run_direction', [\n 'inbound',\n 'outbound',\n]);\n\n/**\n * How the run detected upstream changes. Maps 1:1 to the `Change.source`\n * provenance on inbound runs; `manual` captures operator-triggered re-syncs\n * and `writeback` captures outbound runs.\n */\nexport const syncRunActionEnum = pgEnum('sync_run_action', [\n 'poll',\n 'cdc',\n 'webhook',\n 'manual',\n 'writeback',\n]);\n\n/**\n * Lifecycle status of a sync run.\n *\n * - `running` — in-flight; recorder has started but not completed.\n * - `success` — completed with at least one change processed.\n * - `no_changes` — completed cleanly, no upstream changes found.\n * - `failed` — errored before completion; `error` column carries the\n * message. `records_processed` may be non-zero (partial progress).\n */\nexport const syncRunStatusEnum = pgEnum('sync_run_status', [\n 'running',\n 'success',\n 'no_changes',\n 'failed',\n]);\n\n/**\n * Operation applied per record. Mirrors `Change<T>.operation` from SYNC-2,\n * plus the recorder's own `'noop'` for changes that matched existing state.\n */\nexport const syncRunItemOperationEnum = pgEnum('sync_run_item_operation', [\n 'created',\n 'updated',\n 'deleted',\n 'noop',\n]);\n\n/**\n * Per-record status within a run. `skipped` captures loopback-detected echoes\n * of the local system's own writes (see `ILoopbackFingerprintStore` in the\n * epic), which record the external_id but intentionally do not touch local\n * state.\n */\nexport const syncRunItemStatusEnum = pgEnum('sync_run_item_status', [\n 'success',\n 'failed',\n 'skipped',\n]);\n\n// ─── sync_subscriptions ─────────────────────────────────────────────────────\n\n/**\n * One cursor owner per (integration, adapter, domain, external_ref).\n *\n * - `integration_id` — opaque id of the connected account/instance. E.g.\n * the SFDC org id for polling strategies, the GitHub installation id\n * for webhook strategies.\n * - `adapter` — short adapter label, e.g. `'salesforce'`, `'hubspot'`.\n * - `domain` — canonical entity domain this subscription tracks,\n * e.g. `'opportunity'`, `'contact'`.\n * - `external_ref` — optional upstream scope (e.g. a filter id, a\n * webhook subscription id). NULL when the subscription covers the\n * entire domain.\n *\n * The cursor shape is opaque jsonb — strategies type it internally (poll:\n * `{ systemModstamp }`, cdc: `{ replayId }`, webhook: `{ ts }`). Overwritten\n * by `ICursorStore.put(id, cursor)`.\n */\nexport const syncSubscriptions = pgTable(\n 'sync_subscriptions',\n {\n id: uuid('id').primaryKey().defaultRandom(),\n integrationId: text('integration_id').notNull(),\n adapter: text('adapter').notNull(),\n domain: text('domain').notNull(),\n externalRef: text('external_ref'),\n enabled: boolean('enabled').notNull().default(true),\n /**\n * Per-subscription configuration bag. Strategies type it internally;\n * e.g. polling strategies stash `{ batchSize, highWatermark }` here.\n */\n config: jsonb('config').notNull().default({}).$type<Record<string, unknown>>(),\n /**\n * Opaque cursor persisted by `ICursorStore.put()`. NULL until the first\n * successful run advances it.\n */\n cursor: jsonb('cursor').$type<unknown>(),\n lastSyncAt: timestamp('last_sync_at', { withTimezone: true }),\n /** Runtime-enforced when `SYNC_MULTI_TENANT` is true; see SYNC-6. */\n tenantId: text('tenant_id'),\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),\n },\n (t) => ({\n /**\n * Composite uniqueness per the epic shape. `external_ref` is nullable;\n * Postgres treats NULLs as distinct in a UNIQUE constraint, which means\n * two rows with the same `(integration_id, adapter, domain)` and NULL\n * external_ref are allowed. That's intentional — a subscription with\n * NULL external_ref covers the full domain, and duplicates there would\n * be a consumer-layer modeling issue, not a schema concern.\n */\n uqSyncSubscriptionTuple: uniqueIndex('uq_sync_subscriptions_tuple').on(\n t.integrationId,\n t.adapter,\n t.domain,\n t.externalRef,\n ),\n /** Scheduling query: list enabled subscriptions ordered by staleness. */\n idxSyncSubscriptionsEnabledLastSync: index(\n 'idx_sync_subscriptions_enabled_last_sync',\n ).on(t.enabled, t.lastSyncAt),\n }),\n);\n\nexport type SyncSubscriptionRow = InferSelectModel<typeof syncSubscriptions>;\n\n// ─── sync_runs ──────────────────────────────────────────────────────────────\n\n/**\n * One row per invocation of `ExecuteSyncUseCase`. `started_at` is set when\n * the recorder opens the run; `completed_at`, `status`, `records_*`,\n * `cursor_after`, and `duration_ms` are filled on completion.\n *\n * `cursor_before` / `cursor_after` carry the opaque cursor snapshots so the\n * run log is fully self-describing — given a run id, an operator can reason\n * about exactly what window was scanned without cross-referencing another\n * table.\n */\nexport const syncRuns = pgTable(\n 'sync_runs',\n {\n id: uuid('id').primaryKey().defaultRandom(),\n subscriptionId: uuid('subscription_id')\n .notNull()\n .references(() => syncSubscriptions.id, { onDelete: 'cascade' }),\n direction: syncRunDirectionEnum('direction').notNull(),\n action: syncRunActionEnum('action').notNull(),\n status: syncRunStatusEnum('status').notNull().default('running'),\n recordsFound: integer('records_found').notNull().default(0),\n recordsProcessed: integer('records_processed').notNull().default(0),\n cursorBefore: jsonb('cursor_before').$type<unknown>(),\n cursorAfter: jsonb('cursor_after').$type<unknown>(),\n durationMs: integer('duration_ms'),\n error: text('error'),\n startedAt: timestamp('started_at', { withTimezone: true })\n .notNull()\n .defaultNow(),\n completedAt: timestamp('completed_at', { withTimezone: true }),\n /** Runtime-enforced when `SYNC_MULTI_TENANT` is true; see SYNC-6. */\n tenantId: text('tenant_id'),\n },\n (t) => ({\n /** Timeline read: \"most recent runs for this subscription\". */\n idxSyncRunsSubscriptionStartedAt: index(\n 'idx_sync_runs_subscription_started_at',\n ).on(t.subscriptionId, t.startedAt),\n /** Stale-run sweeper: \"runs that started > N minutes ago and are still running\". */\n idxSyncRunsStatusStartedAt: index('idx_sync_runs_status_started_at').on(\n t.status,\n t.startedAt,\n ),\n }),\n);\n\nexport type SyncRunRow = InferSelectModel<typeof syncRuns>;\n\n// ─── sync_run_items ─────────────────────────────────────────────────────────\n\n/**\n * One row per upstream change processed within a run. Captures the canonical\n * decision the orchestrator made (`operation` + `status`), the structured\n * per-field diff (`changed_fields`, ADR-0003), and the local row id\n * (`local_id`) for drill-down joins.\n *\n * `changed_fields` is validated at the recorder layer via `FieldDiffSchema`\n * (SYNC-2) — the $type<FieldDiff> annotation here only documents the shape\n * for Drizzle consumers. The runtime enforcement is non-negotiable: downstream\n * drift-detection queries rely on the `{from, to}` shape per field.\n *\n * `title` is an optional human-readable label captured at write time (e.g.\n * `\"Pinnacle opportunity\"`) so run-log UIs don't need to re-hydrate the\n * canonical record.\n */\nexport const syncRunItems = pgTable(\n 'sync_run_items',\n {\n id: uuid('id').primaryKey().defaultRandom(),\n syncRunId: uuid('sync_run_id')\n .notNull()\n .references(() => syncRuns.id, { onDelete: 'cascade' }),\n entityType: text('entity_type').notNull(),\n externalId: text('external_id').notNull(),\n localId: text('local_id'),\n operation: syncRunItemOperationEnum('operation').notNull(),\n status: syncRunItemStatusEnum('status').notNull(),\n /**\n * Structured per-field diff — ADR-0003 shape enforced by\n * `FieldDiffSchema.parse` at the recorder service layer.\n *\n * Shape: `{ [fieldName]: { from: unknown, to: unknown } }`.\n * Empty `{}` for `noop` items; `{ [field]: { from: null, to: <value> } }`\n * for created items; `{ [field]: { from: <value>, to: null } }` for\n * deleted items.\n */\n changedFields: jsonb('changed_fields').notNull().default({}).$type<FieldDiff>(),\n title: text('title'),\n error: text('error'),\n createdAt: timestamp('created_at', { withTimezone: true })\n .notNull()\n .defaultNow(),\n /** Runtime-enforced when `SYNC_MULTI_TENANT` is true; see SYNC-6. */\n tenantId: text('tenant_id'),\n },\n (t) => ({\n /** Ordered timeline within a run. */\n idxSyncRunItemsRunCreatedAt: index('idx_sync_run_items_run_created_at').on(\n t.syncRunId,\n t.createdAt,\n ),\n /** Per-record history: \"every sync that touched opportunity/$extId\". */\n idxSyncRunItemsEntityExternal: index(\n 'idx_sync_run_items_entity_external',\n ).on(t.entityType, t.externalId),\n }),\n);\n\nexport type SyncRunItemRow = InferSelectModel<typeof syncRunItems>;\n","/**\n * MemoryCursorStore — in-memory backend for `ICursorStore` (SYNC-3).\n *\n * Test double that lets consumers exercise `ExecuteSyncUseCase` (SYNC-5) and\n * other cursor-consuming code paths without Postgres. Mirrors the role of\n * `MemoryEventBus` and `MemoryJobStore`: plain keyed state, tests take a\n * direct reference for `beforeEach` resets.\n *\n * Cursor values are stored by reference — the port's `get`/`put` contract\n * treats them as opaque `unknown`. Callers that want durable value-equality\n * semantics should snapshot via JSON before `put` and reparse after `get`;\n * this is what the Drizzle backend (SYNC-4) does implicitly via jsonb\n * round-trip. The memory backend intentionally does not simulate the\n * serialize/deserialize cycle — consumers who care should test against\n * Postgres.\n *\n * ## Multi-tenancy\n *\n * `tenantId` is accepted but ignored. The memory backend's state is\n * process-local — there's no durable storage where a cross-tenant leak\n * could occur. Tests that want to assert per-tenant isolation should\n * target the Drizzle backend.\n *\n * Not shipped in the upstream consumer; this is a subsystem-first addition for the\n * test surface. Consumed by:\n * - SYNC-5 unit tests (`ExecuteSyncUseCase` against synthetic sources)\n * - SYNC-6 module tests (`SyncModule.forRoot({ backend: 'memory' })`)\n */\nimport { Injectable } from '@nestjs/common';\nimport type {\n CursorSnapshot,\n ICursorStore,\n} from './sync-cursor-store.protocol';\nimport type { MemorySyncSubscription } from './sync-run-recorder.memory-backend';\n\n@Injectable()\nexport class MemoryCursorStore implements ICursorStore {\n /**\n * Subscription-id → last persisted cursor. Public so tests can inspect\n * or pre-seed state; production callers MUST go through `get`/`put`.\n */\n readonly cursors: Map<string, unknown> = new Map();\n\n /**\n * Seedable subscription metadata for `listAll` — the memory backend\n * stores only `subscriptionId → cursor` in its write path, so the\n * snapshot shape (`integrationId`, `adapter`, `domain`, `externalRef`,\n * timestamps) has no natural source without test seeding. Tests populate\n * this map; unseeded entries get empty-string metadata and `new Date(0)`\n * timestamps so the shape stays stable. Production paths go through the\n * Drizzle backend.\n */\n readonly subscriptions: Map<string, MemorySyncSubscription> = new Map();\n\n async get(\n subscriptionId: string,\n _tenantId?: string | null,\n ): Promise<unknown | null> {\n // `Map.get` returns `undefined` for missing keys; the port contract\n // returns `null`. Normalize here so callers can `=== null`-check.\n const value = this.cursors.get(subscriptionId);\n return value === undefined ? null : value;\n }\n\n async put(\n subscriptionId: string,\n cursor: unknown,\n _tenantId?: string | null,\n ): Promise<void> {\n // Overwrite semantics — matches the port contract and the Drizzle\n // backend's `ON CONFLICT DO UPDATE` behavior.\n this.cursors.set(subscriptionId, cursor);\n }\n\n async listAll(_tenantId?: string | null): Promise<CursorSnapshot[]> {\n // Accepts tenantId for contract symmetry but does not filter on it —\n // the memory backend never enforces tenancy (see class-level comment).\n const snapshots: CursorSnapshot[] = [];\n for (const [subscriptionId, cursor] of this.cursors.entries()) {\n const meta = this.subscriptions.get(subscriptionId);\n snapshots.push({\n subscriptionId,\n integrationId: meta?.integrationId ?? '',\n adapter: meta?.adapter ?? '',\n domain: meta?.domain ?? '',\n externalRef: meta?.externalRef ?? null,\n cursor: cursor ?? null,\n lastSyncAt: meta?.lastSyncAt ?? null,\n updatedAt: meta?.updatedAt ?? new Date(0),\n tenantId: null,\n });\n }\n return snapshots.sort(\n (a, b) => b.updatedAt.getTime() - a.updatedAt.getTime(),\n );\n }\n\n /** Reset state. Tests call this in `beforeEach`. */\n clear(): void {\n this.cursors.clear();\n this.subscriptions.clear();\n }\n}\n","/**\n * MemoryRunRecorder — in-memory backend for `ISyncRunRecorder` (SYNC-6).\n *\n * Test double so `SyncModule.forRoot({ backend: 'memory' })` is genuinely\n * end-to-end runnable without Postgres. Mirrors the role of\n * `MemoryCursorStore`: plain keyed state, `clear()` helper for\n * `beforeEach` resets, public inspection surface so tests can assert on\n * the recorded run + item timeline without scraping logs.\n *\n * Validates `changedFields` through `FieldDiffSchema.parse` on every\n * `recordItem` call — same ADR-0003 contract as the Drizzle backend. An\n * in-memory recorder that skipped the validation would be a silently\n * weaker contract than production.\n *\n * `startRun` generates a uuid via `crypto.randomUUID()` (Node 19+ / Bun).\n * We don't import `uuid` because the subsystem has no other use for it.\n *\n * ## Multi-tenancy\n *\n * `tenantId` is accepted (and recorded on the in-memory row so tests can\n * assert it) but enforcement lives at the module boundary. The memory\n * backend intentionally does not throw on missing `tenantId` — that's\n * the orchestrator's job when `multiTenant=true` (SYNC-6). A permissive\n * memory recorder lets tests exercise error paths where the orchestrator\n * short-circuits before ever reaching the recorder.\n */\nimport { Injectable } from '@nestjs/common';\nimport type {\n CompleteRunInput,\n ISyncRunRecorder,\n RecordItemInput,\n StartRunInput,\n SyncRunSummary,\n} from './sync-run-recorder.protocol';\nimport { FieldDiffSchema } from './sync-field-diff.protocol';\n\n/**\n * Optional per-subscription metadata a test can seed on the memory backend\n * so `listRecent` can surface `integrationId`. The memory recorder's write\n * path never persists subscription rows (it only stores runs + items), so\n * `listRecent` has no way to derive `integrationId` on its own. Tests that\n * care about the field should populate `subscriptions` before calling\n * `listRecent`; calls that don't seed get an empty string and a stable\n * shape (see `listRecent` below).\n */\nexport interface MemorySyncSubscription {\n integrationId: string;\n adapter: string;\n domain: string;\n externalRef: string | null;\n lastSyncAt?: Date | null;\n updatedAt: Date;\n}\n\n/**\n * Concrete run row as held in memory. Shape mirrors the interesting\n * columns on `sync_runs` so assertions read like DB queries.\n */\nexport interface MemoryRunRecord {\n id: string;\n subscriptionId: string;\n direction: 'inbound' | 'outbound';\n action: 'poll' | 'cdc' | 'webhook' | 'manual' | 'writeback';\n status: 'running' | 'success' | 'no_changes' | 'failed';\n cursorBefore: unknown | null;\n cursorAfter: unknown | null;\n recordsFound: number;\n recordsProcessed: number;\n durationMs: number | null;\n error: string | null;\n tenantId: string | null;\n startedAt: Date;\n completedAt: Date | null;\n}\n\n@Injectable()\nexport class MemoryRunRecorder implements ISyncRunRecorder {\n /**\n * All started runs keyed by id. Public so tests can inspect lifecycle\n * transitions without poking through recording methods.\n */\n readonly runs: Map<string, MemoryRunRecord> = new Map();\n\n /**\n * Items keyed by `sync_run_id`, array order matches insertion order —\n * mirrors the timeline the `(sync_run_id, created_at)` index produces\n * in Postgres.\n */\n readonly items: Map<string, RecordItemInput[]> = new Map();\n\n /**\n * Seedable subscription metadata — tests populate this to make\n * `listRecent` return meaningful `integrationId` values. The memory\n * backend doesn't track subscriptions on its own (only runs + items), so\n * this map is the intentional extension point: tests write entries for\n * the subscription ids they use, production code never touches it.\n */\n readonly subscriptions: Map<string, MemorySyncSubscription> = new Map();\n\n async startRun(input: StartRunInput): Promise<{ id: string }> {\n const id = crypto.randomUUID();\n this.runs.set(id, {\n id,\n subscriptionId: input.subscriptionId,\n direction: input.direction,\n action: input.action,\n status: 'running',\n cursorBefore: input.cursorBefore ?? null,\n cursorAfter: null,\n recordsFound: 0,\n recordsProcessed: 0,\n durationMs: null,\n error: null,\n tenantId: input.tenantId ?? null,\n startedAt: new Date(),\n completedAt: null,\n });\n this.items.set(id, []);\n return { id };\n }\n\n async recordItem(input: RecordItemInput): Promise<void> {\n // Same ADR-0003 contract as the Drizzle backend.\n FieldDiffSchema.parse(input.changedFields);\n\n const bucket = this.items.get(input.syncRunId);\n if (!bucket) {\n throw new Error(\n `MemoryRunRecorder.recordItem: no run started for id '${input.syncRunId}'. ` +\n `Call startRun(...) first.`,\n );\n }\n bucket.push(input);\n }\n\n async completeRun(runId: string, input: CompleteRunInput): Promise<void> {\n const run = this.runs.get(runId);\n if (!run) {\n throw new Error(\n `MemoryRunRecorder.completeRun: no run started for id '${runId}'.`,\n );\n }\n run.status = input.status;\n run.recordsFound = input.recordsFound;\n run.recordsProcessed = input.recordsProcessed;\n run.cursorAfter = input.cursorAfter ?? null;\n run.durationMs = input.durationMs;\n run.error = input.error ?? null;\n run.completedAt = new Date();\n }\n\n async listRecent(\n limit: number,\n subscriptionId?: string,\n _tenantId?: string | null,\n ): Promise<SyncRunSummary[]> {\n // Memory backend accepts tenantId for contract symmetry but does not\n // filter on it — state is process-local and cross-tenant isolation is\n // not meaningful here (matches MemoryCursorStore behavior).\n const all = Array.from(this.runs.values());\n const filtered =\n subscriptionId === undefined\n ? all\n : all.filter((r) => r.subscriptionId === subscriptionId);\n return filtered\n .sort((a, b) => b.startedAt.getTime() - a.startedAt.getTime())\n .slice(0, limit)\n .map((r) => ({\n id: r.id,\n subscriptionId: r.subscriptionId,\n // integrationId is only knowable if the test seeded subscriptions\n // metadata; empty string otherwise. The Drizzle backend resolves\n // it via JOIN, which is the production path.\n integrationId:\n this.subscriptions.get(r.subscriptionId)?.integrationId ?? '',\n status: r.status,\n startedAt: r.startedAt,\n completedAt: r.completedAt,\n recordsProcessed: r.recordsProcessed,\n tenantId: r.tenantId,\n }));\n }\n\n /** Reset state. Tests call this in `beforeEach`. */\n clear(): void {\n this.runs.clear();\n this.items.clear();\n this.subscriptions.clear();\n }\n\n // ─── test ergonomics ─────────────────────────────────────────────────\n\n /** All runs for a subscription, newest first. Timeline reads. */\n getRunsForSubscription(subscriptionId: string): MemoryRunRecord[] {\n return Array.from(this.runs.values())\n .filter((r) => r.subscriptionId === subscriptionId)\n .sort((a, b) => b.startedAt.getTime() - a.startedAt.getTime());\n }\n\n /** All item rows for a run, insertion-ordered. */\n getItemsForRun(runId: string): RecordItemInput[] {\n return this.items.get(runId) ?? [];\n }\n}\n","/**\n * DeepEqualDiffer — default `IFieldDiffer<T>` for the sync subsystem (SYNC-5).\n *\n * Walks every field of `incoming` against `existing`, emitting a structured\n * per-field diff (`{ from, to }`) for every field whose value changed.\n * Returns `'noop'` when the record is unchanged.\n *\n * Design decisions (extracted from the upstream consumer + HS-9 findings):\n *\n * 1. **Ignore list** — row metadata that sinks/services stamp unconditionally\n * so upstream cannot reasonably disagree:\n * `id`, `createdAt`, `updatedAt`, `deletedAt`, `type`,\n * `lastModifiedAt`, `fields`, `providerMetadata`\n * (`fields` is the EAV bag — it's diffed by the sink's EAV dual-write\n * path, not at the canonical-record layer.)\n *\n * 2. **`providerChangedFields` hint (CDC)** — when present, restricts the\n * comparison to the hinted field set. The hint is advisory; fields in\n * the ignore list are still filtered out even when hinted. Provider\n * hints are field-NAME-level; they don't override the ignore rules.\n *\n * 3. **Date → ISO string** — `Date` instances are normalized to\n * `toISOString()` before comparison. Sinks return `Date` from the DB\n * driver; adapters typically deliver strings. Direct `===` would\n * always say \"changed.\"\n *\n * 4. **Decimal-string vs number** — Postgres `numeric` columns return as\n * strings through Drizzle; adapters deliver numbers. When one side is a\n * number and the other is a numeric string that parses to the same\n * number, they're equal. The normalizer does NOT coerce non-numeric\n * strings, and it preserves zero-vs-null distinction.\n *\n * 5. **null-existing path** — `diff(null, incoming)` produces a full\n * created-shape diff (`{from: null, to: <value>}` for every non-ignored\n * field). Orchestrator sees this and records `operation: 'created'`.\n */\nimport { Injectable } from '@nestjs/common';\nimport type {\n DiffResult,\n FieldDiff,\n IFieldDiffer,\n} from './sync-field-diff.protocol';\n\n/**\n * Default ignore list. Keep in sync with consumer canonical-record shapes —\n * adding a row-metadata field here means no sync will ever mark it changed.\n */\nconst DEFAULT_IGNORE_FIELDS: ReadonlySet<string> = new Set([\n 'id',\n 'createdAt',\n 'updatedAt',\n 'deletedAt',\n 'type',\n 'lastModifiedAt',\n 'fields',\n 'providerMetadata',\n]);\n\nexport interface DeepEqualDifferOptions {\n /**\n * Extra field names to ignore in addition to the defaults. Consumers can\n * pass `['sync_version']` etc. to augment the base list; values here are\n * merged (not replaced) with `DEFAULT_IGNORE_FIELDS`.\n */\n readonly ignore?: readonly string[];\n}\n\n@Injectable()\nexport class DeepEqualDiffer<T extends Record<string, unknown>>\n implements IFieldDiffer<T>\n{\n private readonly ignore: ReadonlySet<string>;\n\n constructor(opts: DeepEqualDifferOptions = {}) {\n if (opts.ignore && opts.ignore.length > 0) {\n this.ignore = new Set([...DEFAULT_IGNORE_FIELDS, ...opts.ignore]);\n } else {\n this.ignore = DEFAULT_IGNORE_FIELDS;\n }\n }\n\n diff(\n existing: T | null,\n incoming: T,\n providerChangedFields?: string[],\n ): DiffResult {\n // Created-shape: every non-ignored field becomes `{from: null, to}`.\n if (existing === null) {\n const out: FieldDiff = {};\n for (const key of Object.keys(incoming)) {\n if (this.ignore.has(key)) continue;\n const value = (incoming as Record<string, unknown>)[key];\n // Skip fields that are themselves null/undefined — a created record\n // doesn't need to declare \"this field is null now\" for every\n // untouched column.\n if (value === null || value === undefined) continue;\n out[key] = { from: null, to: value };\n }\n return Object.keys(out).length === 0 ? 'noop' : out;\n }\n\n // Field set to compare. `providerChangedFields` narrows to a hint set;\n // ignored fields are filtered out regardless of hint.\n const candidates = new Set<string>();\n if (providerChangedFields && providerChangedFields.length > 0) {\n for (const key of providerChangedFields) {\n if (!this.ignore.has(key)) candidates.add(key);\n }\n } else {\n for (const key of Object.keys(incoming)) {\n if (!this.ignore.has(key)) candidates.add(key);\n }\n // Also include keys that exist on existing but not on incoming —\n // e.g. a field that was cleared. This would otherwise be missed when\n // incoming carries an undefined column we drop from the iteration.\n for (const key of Object.keys(existing)) {\n if (this.ignore.has(key)) continue;\n if (!(key in (incoming as Record<string, unknown>))) continue;\n candidates.add(key);\n }\n }\n\n const out: FieldDiff = {};\n for (const key of candidates) {\n const before = (existing as Record<string, unknown>)[key];\n const after = (incoming as Record<string, unknown>)[key];\n if (!isEqual(before, after)) {\n out[key] = { from: before ?? null, to: after ?? null };\n }\n }\n\n return Object.keys(out).length === 0 ? 'noop' : out;\n }\n}\n\n// ─── equality helpers ───────────────────────────────────────────────────────\n\n/**\n * Field-level equality with the canonical-sync normalizations:\n * - Date → toISOString (adapters deliver strings)\n * - numeric-string vs number → numeric equality when both parse\n * - deep equality for plain objects/arrays (single-level is enough for\n * canonical records; nested records travel as jsonb columns where the\n * sink already owns the comparison)\n */\nfunction isEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n\n const na = normalize(a);\n const nb = normalize(b);\n if (na === nb) return true;\n\n // After normalization: both may still be non-primitive objects.\n if (\n typeof na === 'object' &&\n typeof nb === 'object' &&\n na !== null &&\n nb !== null\n ) {\n return deepEqualObject(na as Record<string, unknown>, nb as Record<string, unknown>);\n }\n\n // Numeric string ↔ number: when one side is a number and the other is a\n // string that parses to the same finite number.\n const numericEqual = maybeNumericEqual(na, nb) || maybeNumericEqual(nb, na);\n return numericEqual;\n}\n\nfunction normalize(value: unknown): unknown {\n if (value instanceof Date) return value.toISOString();\n return value;\n}\n\nfunction maybeNumericEqual(a: unknown, b: unknown): boolean {\n // a is string-shape, b is number — parse a and compare. Only when the\n // string looks numeric AND the parse round-trips (no silent NaN pass-\n // through on non-numeric strings).\n if (typeof a !== 'string' || typeof b !== 'number') return false;\n if (a.trim() === '') return false;\n const parsed = Number(a);\n if (!Number.isFinite(parsed)) return false;\n return parsed === b;\n}\n\nfunction deepEqualObject(\n a: Record<string, unknown>,\n b: Record<string, unknown>,\n): boolean {\n if (Array.isArray(a) !== Array.isArray(b)) return false;\n const aKeys = Object.keys(a);\n const bKeys = Object.keys(b);\n if (aKeys.length !== bKeys.length) return false;\n for (const key of aKeys) {\n if (!(key in b)) return false;\n if (!isEqual(a[key], b[key])) return false;\n }\n return true;\n}\n","/**\n * ExecuteSyncUseCase — the generic sync orchestrator (SYNC-5).\n *\n * One class. Reused across every `(provider, detection-mode, canonical-entity)`\n * tuple. Parameterized over `T` so canonical records stay typed end-to-end.\n *\n * Flow per run:\n *\n * 1. `recorder.startRun(...)` — opens a `sync_runs` row in 'running'.\n * 2. for each change yielded by `source.listChanges(subscription, cursorBefore)`:\n * a. differ.diff(existing, incoming) → 'noop' short-circuits to\n * a noop audit row (no sink write).\n * b. sink.upsertByExternalId / softDeleteByExternalId → records\n * the local id on the audit row.\n * c. per-item try/catch — a failed item increments the failed\n * counter and records `status: 'failed'` with `error`, but\n * does NOT abort the run.\n * d. advance `latestCursor = change.cursor` as the iterator moves.\n * 3. `cursors.put(subscription.id, latestCursor)` when the loop completes\n * AND at least one cursor advance happened. On exceptions from the\n * source iterator (auth expiry, network error), we persist the\n * last-good cursor so the next run resumes from the last known\n * successful position.\n * 4. `finally { recorder.completeRun(...) }` — always terminates the run.\n *\n * Loopback suppression — when a consumer's writes echo back on the next\n * inbound poll/CDC/webhook — is composed into the source's middleware\n * chain via `createLoopbackMiddleware(store)` (#226-5 / ADR-033). The\n * orchestrator no longer special-cases echoes: middleware drops them\n * before they reach this loop. Consumers that don't have outbound\n * writeback paths simply omit the middleware.\n *\n * ## Generics\n *\n * - `T` = canonical record shape from the adapter side. Same `T` flows\n * through `IChangeSource<T>`, `IFieldDiffer<T>`, `ISyncSink<T>`.\n *\n * ## No CRM bleed\n *\n * Per the SYNC-5 issue's extraction notes (HS-9 finding), this orchestrator\n * is strictly provider-agnostic:\n * - `entityType` is `string` throughout; no `'opportunity' | 'account' | ...`\n * narrowing leaks into the use case\n * - the upstream consumer's `SyncRunRecorderService` class injection replaced with the\n * `ISyncRunRecorder` protocol (backend lands in SYNC-4)\n */\nimport { Inject, Injectable, Logger, Optional } from '@nestjs/common';\nimport type { IChangeSource, Change } from './sync-change-source.protocol';\nimport type { ICursorStore } from './sync-cursor-store.protocol';\nimport type { IFieldDiffer, FieldDiff } from './sync-field-diff.protocol';\nimport type { ISyncSink } from './sync-sink.protocol';\nimport type { ISyncRunRecorder } from './sync-run-recorder.protocol';\nimport { assertTenantId } from './sync-errors';\nimport {\n SYNC_CHANGE_SOURCE,\n SYNC_CURSOR_STORE,\n SYNC_FIELD_DIFFER,\n SYNC_MULTI_TENANT,\n SYNC_RUN_RECORDER,\n SYNC_SINK,\n} from './sync.tokens';\n\n// ============================================================================\n// Inputs + result\n// ============================================================================\n\nexport interface ExecuteSyncInput<T> {\n /** The subscription whose cursor/identity frames this run. */\n readonly subscription: {\n readonly id: string;\n readonly domain: string; // entityType — used on audit rows\n readonly externalRef?: string | null;\n };\n /** Per-run user context; threaded through sink writes. */\n readonly userId: string;\n /** Provider label persisted on saved rows, e.g. `'salesforce-crm'`. */\n readonly provider: string;\n /** Run direction — almost always `'inbound'`. Reserved for writeback. */\n readonly direction: 'inbound' | 'outbound';\n /** Detection mode — maps 1:1 to `sync_runs.action`. */\n readonly action: 'poll' | 'cdc' | 'webhook' | 'manual' | 'writeback';\n /** Multi-tenant deployments pass the tenant id through. */\n readonly tenantId?: string | null;\n /**\n * Optional override — inject a specific change source for this run when\n * the DI-bound source is not the one to use (e.g. manual backfill with\n * a custom cursor). Defaults to the DI-resolved `SYNC_CHANGE_SOURCE`.\n */\n readonly sourceOverride?: IChangeSource<T>;\n}\n\nexport interface ExecuteSyncResult {\n readonly runId: string;\n readonly status: 'success' | 'no_changes' | 'failed';\n readonly recordsFound: number;\n readonly recordsProcessed: number;\n readonly recordsFailed: number;\n readonly cursorBefore: unknown | null;\n readonly cursorAfter: unknown | null;\n readonly durationMs: number;\n readonly error?: string | null;\n}\n\n// ============================================================================\n// ExecuteSyncUseCase\n// ============================================================================\n\n@Injectable()\nexport class ExecuteSyncUseCase<T extends Record<string, unknown>> {\n private readonly logger = new Logger(ExecuteSyncUseCase.name);\n\n constructor(\n @Inject(SYNC_CHANGE_SOURCE) private readonly source: IChangeSource<T>,\n @Inject(SYNC_CURSOR_STORE) private readonly cursors: ICursorStore,\n @Inject(SYNC_FIELD_DIFFER) private readonly differ: IFieldDiffer<T>,\n @Inject(SYNC_SINK) private readonly sink: ISyncSink<T>,\n @Inject(SYNC_RUN_RECORDER) private readonly recorder: ISyncRunRecorder,\n @Optional()\n @Inject(SYNC_MULTI_TENANT)\n private readonly multiTenant: boolean = false,\n ) {}\n\n async execute(input: ExecuteSyncInput<T>): Promise<ExecuteSyncResult> {\n // Defense-in-depth tenancy guard — fire BEFORE startRun so a rejected\n // input never leaves a dangling `status=running` row. Backends also\n // enforce (SYNC-4), but failing fast at the orchestrator boundary is\n // cheaper for observability, metrics, and manual cleanup.\n assertTenantId(input.tenantId, {\n multiTenant: this.multiTenant,\n operation: 'execute',\n });\n\n const source = input.sourceOverride ?? this.source;\n const startedAt = Date.now();\n const cursorBefore = await this.cursors.get(input.subscription.id, input.tenantId);\n\n const { id: runId } = await this.recorder.startRun({\n subscriptionId: input.subscription.id,\n direction: input.direction,\n action: input.action,\n cursorBefore,\n tenantId: input.tenantId,\n });\n\n let recordsFound = 0;\n let recordsProcessed = 0;\n let recordsFailed = 0;\n let latestCursor: unknown | null = cursorBefore;\n let cursorAdvanced = false;\n let runError: string | null = null;\n let status: 'success' | 'no_changes' | 'failed' = 'no_changes';\n\n try {\n for await (const change of source.listChanges(input.subscription, cursorBefore)) {\n recordsFound++;\n latestCursor = change.cursor;\n cursorAdvanced = true;\n\n try {\n await this.processChange(runId, input, change);\n recordsProcessed++;\n } catch (err) {\n recordsFailed++;\n const message = err instanceof Error ? err.message : String(err);\n this.logger.warn(\n `sync item failed: subscription=${input.subscription.id} externalId=${change.externalId}: ${message}`,\n );\n await this.recorder.recordItem({\n syncRunId: runId,\n entityType: input.subscription.domain,\n externalId: change.externalId,\n operation: change.operation === 'deleted' ? 'deleted' : 'updated',\n status: 'failed',\n changedFields: {},\n error: message,\n tenantId: input.tenantId,\n });\n }\n }\n\n if (recordsFailed > 0 && recordsProcessed === 0 && recordsFound > 0) {\n // Every record we saw failed — call the run a failure, not a\n // success. Partial success (some processed, some failed) still\n // counts as 'success' so the cursor advances.\n status = 'failed';\n runError = `all ${recordsFailed} records failed`;\n } else if (recordsFound === 0) {\n status = 'no_changes';\n } else {\n status = 'success';\n }\n } catch (err) {\n // Source iterator itself threw — cursor DOES NOT advance past the\n // last-successful cursor. `latestCursor` still holds the last\n // `change.cursor` we observed, which is the furthest we know to\n // have delivered. Persist it (below) so next run resumes there.\n status = 'failed';\n runError = err instanceof Error ? err.message : String(err);\n this.logger.error(\n `sync source failed: subscription=${input.subscription.id}: ${runError}`,\n );\n }\n\n // Persist cursor advance only when something actually moved. Never\n // overwrite a valid cursor with `null` on a no-change run.\n if (cursorAdvanced && latestCursor !== null && latestCursor !== undefined) {\n try {\n await this.cursors.put(input.subscription.id, latestCursor, input.tenantId);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n this.logger.error(\n `cursor put failed: subscription=${input.subscription.id}: ${message}`,\n );\n if (status !== 'failed') {\n status = 'failed';\n runError = `cursor put failed: ${message}`;\n }\n }\n }\n\n const durationMs = Date.now() - startedAt;\n\n await this.recorder.completeRun(runId, {\n status,\n recordsFound,\n recordsProcessed,\n cursorAfter: cursorAdvanced ? latestCursor : cursorBefore,\n durationMs,\n error: runError,\n });\n\n return {\n runId,\n status,\n recordsFound,\n recordsProcessed,\n recordsFailed,\n cursorBefore,\n cursorAfter: cursorAdvanced ? latestCursor : cursorBefore,\n durationMs,\n error: runError,\n };\n }\n\n private async processChange(\n runId: string,\n input: ExecuteSyncInput<T>,\n change: Change<T>,\n ): Promise<void> {\n // Deletion branch — no diff, no upsert; soft-delete via sink.\n if (change.operation === 'deleted') {\n const result = await this.sink.softDeleteByExternalId(\n input.userId,\n change.externalId,\n );\n await this.recorder.recordItem({\n syncRunId: runId,\n entityType: input.subscription.domain,\n externalId: change.externalId,\n localId: result?.id ?? null,\n operation: result ? 'deleted' : 'noop',\n status: 'success',\n changedFields: {},\n tenantId: input.tenantId,\n });\n return;\n }\n\n // Create/update path — diff against local state, short-circuit on noop.\n const existing = await this.sink.findByExternalId(\n input.userId,\n change.externalId,\n );\n const diff = this.differ.diff(\n existing,\n change.record,\n change.providerChangedFields,\n );\n\n if (diff === 'noop') {\n await this.recorder.recordItem({\n syncRunId: runId,\n entityType: input.subscription.domain,\n externalId: change.externalId,\n localId: null,\n operation: 'noop',\n status: 'success',\n changedFields: {},\n tenantId: input.tenantId,\n });\n return;\n }\n\n const { id: localId } = await this.sink.upsertByExternalId(\n input.userId,\n change.record,\n input.provider,\n );\n\n await this.recorder.recordItem({\n syncRunId: runId,\n entityType: input.subscription.domain,\n externalId: change.externalId,\n localId,\n operation: existing === null ? 'created' : 'updated',\n status: 'success',\n changedFields: diff as FieldDiff,\n tenantId: input.tenantId,\n });\n }\n}\n","/**\n * PostgresCursorStore — Drizzle-backed `ICursorStore` (SYNC-4).\n *\n * Reads/writes `sync_subscriptions.cursor` directly — no service\n * composition. Consumers that want a service layer around subscriptions\n * wire it themselves; the port's contract is just cursor persistence.\n *\n * ## What `put` stamps\n *\n * `put` writes three columns in one statement: `cursor`, `last_sync_at`,\n * and `updated_at`. Rationale: SYNC-1's scheduling index\n * `(enabled, last_sync_at)` is useless if `last_sync_at` doesn't advance\n * with every cursor put. Every real consumer needs this stamped, so\n * bundling it here avoids every consumer wrapping the port in a service\n * layer just to stamp a timestamp.\n *\n * ## Multi-tenancy\n *\n * When `SYNC_MULTI_TENANT` is true (SYNC-6):\n * - every read/write is scoped by `AND tenant_id = $tenantId`\n * - a null/missing `tenantId` throws `MissingTenantIdError` via the\n * shared `assertTenantId` helper (one message shape across the\n * orchestrator + both backends, SYNC-6)\n * - explicit `null` also throws — matches JOB-8 / EVT-6 strict-enforcement\n *\n * When the flag is off, `tenantId` is ignored. Cross-tenant isolation is\n * the caller's problem in single-tenant deployments.\n */\nimport { Inject, Injectable, Optional } from '@nestjs/common';\nimport { and, desc, eq, type SQL } from 'drizzle-orm';\nimport type { DrizzleClient } from '../../types/drizzle';\nimport { DRIZZLE } from '../../constants/tokens';\nimport type {\n CursorSnapshot,\n ICursorStore,\n} from './sync-cursor-store.protocol';\nimport { syncSubscriptions } from './sync-audit.schema';\nimport { SYNC_MULTI_TENANT } from './sync.tokens';\nimport { assertTenantId } from './sync-errors';\n\n@Injectable()\nexport class PostgresCursorStore implements ICursorStore {\n private readonly multiTenant: boolean;\n\n constructor(\n @Inject(DRIZZLE) private readonly db: DrizzleClient,\n @Optional() @Inject(SYNC_MULTI_TENANT) multiTenant?: boolean,\n ) {\n this.multiTenant = multiTenant ?? false;\n }\n\n async get(\n subscriptionId: string,\n tenantId?: string | null,\n ): Promise<unknown | null> {\n const where = this.buildWhere(subscriptionId, tenantId, 'cursor.get');\n\n const rows = await this.db\n .select({ cursor: syncSubscriptions.cursor })\n .from(syncSubscriptions)\n .where(where)\n .limit(1);\n\n if (rows.length === 0) return null;\n return rows[0]?.cursor ?? null;\n }\n\n async put(\n subscriptionId: string,\n cursor: unknown,\n tenantId?: string | null,\n ): Promise<void> {\n const where = this.buildWhere(subscriptionId, tenantId, 'cursor.put');\n\n await this.db\n .update(syncSubscriptions)\n .set({\n cursor,\n lastSyncAt: new Date(),\n updatedAt: new Date(),\n })\n .where(where);\n }\n\n async listAll(tenantId?: string | null): Promise<CursorSnapshot[]> {\n assertTenantId(tenantId, {\n multiTenant: this.multiTenant,\n operation: 'cursor.listAll',\n });\n\n const where = this.multiTenant\n ? eq(syncSubscriptions.tenantId, tenantId as string)\n : undefined;\n\n const rows = await this.db\n .select({\n id: syncSubscriptions.id,\n integrationId: syncSubscriptions.integrationId,\n adapter: syncSubscriptions.adapter,\n domain: syncSubscriptions.domain,\n externalRef: syncSubscriptions.externalRef,\n cursor: syncSubscriptions.cursor,\n lastSyncAt: syncSubscriptions.lastSyncAt,\n updatedAt: syncSubscriptions.updatedAt,\n tenantId: syncSubscriptions.tenantId,\n })\n .from(syncSubscriptions)\n .where(where)\n .orderBy(desc(syncSubscriptions.updatedAt));\n\n return rows.map((row) => ({\n subscriptionId: row.id,\n integrationId: row.integrationId,\n adapter: row.adapter,\n domain: row.domain,\n externalRef: row.externalRef,\n cursor: row.cursor ?? null,\n lastSyncAt: row.lastSyncAt,\n updatedAt: row.updatedAt,\n tenantId: row.tenantId,\n }));\n }\n\n /**\n * Centralized WHERE clause — `get` and `put` share identical semantics.\n * Drift here would let a caller read under one tenancy rule and write\n * under another.\n */\n private buildWhere(\n subscriptionId: string,\n tenantId: string | null | undefined,\n operation: string,\n ): SQL | undefined {\n assertTenantId(tenantId, {\n multiTenant: this.multiTenant,\n operation,\n });\n if (this.multiTenant) {\n return and(\n eq(syncSubscriptions.id, subscriptionId),\n eq(syncSubscriptions.tenantId, tenantId as string),\n );\n }\n return eq(syncSubscriptions.id, subscriptionId);\n }\n}\n","/**\n * NestJS injection tokens\n *\n * Used with @Inject() decorator in concrete repository constructors.\n */\n\n/**\n * Injection token for the Drizzle ORM database client.\n *\n * Usage in concrete repositories:\n * ```typescript\n * constructor(@Inject(DRIZZLE) db: DrizzleClient) { super(db); }\n * ```\n */\nexport const DRIZZLE = 'DRIZZLE' as const;\n\n/**\n * Injection token for the event bus (IEventBus).\n *\n * Optional — only resolved when EventsModule.forRoot() is registered.\n * BaseService uses this with @Optional() to emit lifecycle events\n * without requiring the events subsystem to be installed.\n *\n * Usage in services/use cases:\n * ```typescript\n * @Optional() @Inject(EVENT_BUS) eventBus?: IEventBus\n * ```\n */\nexport const EVENT_BUS = 'EVENT_BUS' as const;\n","/**\n * DrizzleSyncRunRecorder — Drizzle-backed `ISyncRunRecorder` (SYNC-4).\n *\n * Generic write path only — extracted from the source app's\n * `SyncRunRecorderService`, minus CRM-specific convenience methods. Those\n * stay consumer-owned; the subsystem ships the substrate.\n *\n * ## Responsibilities\n *\n * - `startRun` — INSERT sync_runs row in status='running', returns id.\n * - `recordItem` — validates `changedFields` via `FieldDiffSchema.parse`\n * BEFORE the INSERT; a malformed shape throws before\n * any DB call fires. Enforces the ADR-0003 contract at\n * the write boundary.\n * - `completeRun` — UPDATE sync_runs with terminal status, counts,\n * cursor_after, duration_ms, completed_at.\n *\n * ## Multi-tenancy\n *\n * When `SYNC_MULTI_TENANT` is true (SYNC-6):\n * - `startRun` and `recordItem` require non-null `tenantId` on input.\n * Enforcement goes through the shared `assertTenantId` helper so the\n * error message shape matches the orchestrator entry point + the\n * cursor-store backends.\n * - `completeRun` does NOT re-check tenancy — the run id was returned\n * by `startRun` which already enforced it, and run ids are uuids that\n * aren't guessable cross-tenant. Matches JOB-3's pattern of trusting\n * the run-id for downstream mutations.\n */\nimport { Inject, Injectable, Optional } from '@nestjs/common';\nimport { and, desc, eq, type SQL } from 'drizzle-orm';\nimport type { DrizzleClient } from '../../types/drizzle';\nimport { DRIZZLE } from '../../constants/tokens';\nimport type {\n CompleteRunInput,\n ISyncRunRecorder,\n RecordItemInput,\n StartRunInput,\n SyncRunSummary,\n} from './sync-run-recorder.protocol';\nimport { syncRuns, syncRunItems, syncSubscriptions } from './sync-audit.schema';\nimport { FieldDiffSchema } from './sync-field-diff.protocol';\nimport { SYNC_MULTI_TENANT } from './sync.tokens';\nimport { assertTenantId } from './sync-errors';\n\n@Injectable()\nexport class DrizzleSyncRunRecorder implements ISyncRunRecorder {\n private readonly multiTenant: boolean;\n\n constructor(\n @Inject(DRIZZLE) private readonly db: DrizzleClient,\n @Optional() @Inject(SYNC_MULTI_TENANT) multiTenant?: boolean,\n ) {\n this.multiTenant = multiTenant ?? false;\n }\n\n async startRun(input: StartRunInput): Promise<{ id: string }> {\n assertTenantId(input.tenantId, {\n multiTenant: this.multiTenant,\n operation: 'startRun',\n });\n\n const rows = await this.db\n .insert(syncRuns)\n .values({\n subscriptionId: input.subscriptionId,\n direction: input.direction,\n action: input.action,\n status: 'running',\n cursorBefore: input.cursorBefore ?? null,\n tenantId: input.tenantId ?? null,\n })\n .returning({ id: syncRuns.id });\n\n const id = rows[0]?.id;\n if (!id) {\n // Drizzle's insert().returning() contract: at least one row is\n // returned for every successful INSERT. A missing id would indicate\n // a driver misbehavior; throw loudly rather than return bogus data.\n throw new Error('DrizzleSyncRunRecorder: INSERT RETURNING produced no id');\n }\n return { id };\n }\n\n async recordItem(input: RecordItemInput): Promise<void> {\n assertTenantId(input.tenantId, {\n multiTenant: this.multiTenant,\n operation: 'recordItem',\n });\n\n // ADR-0003 contract enforcement — reject malformed changedFields\n // before the DB call fires. `parse` throws a ZodError; callers see\n // the validation failure, not a DB constraint error.\n FieldDiffSchema.parse(input.changedFields);\n\n await this.db.insert(syncRunItems).values({\n syncRunId: input.syncRunId,\n entityType: input.entityType,\n externalId: input.externalId,\n localId: input.localId ?? null,\n operation: input.operation,\n status: input.status,\n changedFields: input.changedFields,\n title: input.title ?? null,\n error: input.error ?? null,\n tenantId: input.tenantId ?? null,\n });\n }\n\n async listRecent(\n limit: number,\n subscriptionId?: string,\n tenantId?: string | null,\n ): Promise<SyncRunSummary[]> {\n assertTenantId(tenantId, {\n multiTenant: this.multiTenant,\n operation: 'listRecent',\n });\n\n // JOIN against sync_subscriptions to resolve `integration_id` per run.\n // `sync_runs.subscription_id` is a non-null FK so INNER JOIN is correct;\n // there should be no orphaned runs.\n const conditions: SQL[] = [];\n if (subscriptionId !== undefined) {\n conditions.push(eq(syncRuns.subscriptionId, subscriptionId));\n }\n if (this.multiTenant) {\n conditions.push(eq(syncRuns.tenantId, tenantId as string));\n }\n const where =\n conditions.length === 0\n ? undefined\n : conditions.length === 1\n ? conditions[0]\n : and(...conditions);\n\n const rows = await this.db\n .select({\n id: syncRuns.id,\n subscriptionId: syncRuns.subscriptionId,\n integrationId: syncSubscriptions.integrationId,\n status: syncRuns.status,\n startedAt: syncRuns.startedAt,\n completedAt: syncRuns.completedAt,\n recordsProcessed: syncRuns.recordsProcessed,\n tenantId: syncRuns.tenantId,\n })\n .from(syncRuns)\n .innerJoin(\n syncSubscriptions,\n eq(syncRuns.subscriptionId, syncSubscriptions.id),\n )\n .where(where)\n .orderBy(desc(syncRuns.startedAt))\n .limit(limit);\n\n return rows.map((row) => ({\n id: row.id,\n subscriptionId: row.subscriptionId,\n integrationId: row.integrationId,\n status: row.status,\n startedAt: row.startedAt,\n completedAt: row.completedAt,\n recordsProcessed: row.recordsProcessed,\n tenantId: row.tenantId,\n }));\n }\n\n async completeRun(runId: string, input: CompleteRunInput): Promise<void> {\n await this.db\n .update(syncRuns)\n .set({\n status: input.status,\n recordsFound: input.recordsFound,\n recordsProcessed: input.recordsProcessed,\n cursorAfter: input.cursorAfter ?? null,\n durationMs: input.durationMs,\n error: input.error ?? null,\n completedAt: new Date(),\n })\n .where(eq(syncRuns.id, runId));\n }\n}\n","/**\n * SyncModule — `DynamicModule.forRoot({ backend, multiTenant? })` factory\n * wiring the sync subsystem's substrate (SYNC-6, ADR-008 subsystem pattern).\n *\n * ## What this module provides\n *\n * - `SYNC_CURSOR_STORE` — Drizzle or Memory cursor store\n * - `SYNC_RUN_RECORDER` — Drizzle or Memory run recorder\n * - `SYNC_FIELD_DIFFER` — default `DeepEqualDiffer`\n * - `SYNC_MULTI_TENANT` — resolved boolean flag (defaults to false)\n * - `SYNC_MODULE_OPTIONS` — the options object itself, for backends\n * that need to inspect config at construction time\n *\n * ## What this module does NOT provide\n *\n * - `SYNC_CHANGE_SOURCE` — per-provider per-entity; consumer binds in\n * their feature module (e.g. `OpportunitySyncModule` provides a\n * `SalesforceOpportunityChangeSource`). Loopback suppression — when\n * needed — is composed into the primitive's middleware chain via\n * `createLoopbackMiddleware(store)` (#226-5 / ADR-033); the\n * orchestrator no longer accepts a fingerprint store directly.\n * - `SYNC_SINK` — per canonical entity; consumer binds in their feature\n * module.\n * - `ExecuteSyncUseCase` — registered by the feature module alongside\n * its source + sink bindings. Providing the orchestrator here would\n * force Nest to resolve SYNC_CHANGE_SOURCE + SYNC_SINK at module\n * compile time, which fails when the feature module hasn't been\n * imported yet. Consumers register `ExecuteSyncUseCase` in the same\n * `providers` array as their source + sink so resolution is local\n * to where all three are bound.\n *\n * Same shape as `EventsModule.forRoot` — the module wires the bus; you\n * bring your own handlers. Here: the module wires the substrate; you\n * bring your own source + sink.\n *\n * ## Usage\n *\n * ```ts\n * // AppModule — single source of truth for backend + multi-tenancy.\n * @Module({\n * imports: [SyncModule.forRoot({ backend: 'drizzle' })],\n * })\n * export class AppModule {}\n *\n * // Per-entity feature module — binds source + sink, gets the\n * // orchestrator for free.\n * @Module({\n * providers: [\n * { provide: SYNC_CHANGE_SOURCE, useClass: SalesforceOpportunitySource },\n * { provide: SYNC_SINK, useClass: OpportunitySyncSink },\n * ExecuteSyncUseCase,\n * ],\n * })\n * export class OpportunitySyncModule {\n * constructor(\n * private readonly execute: ExecuteSyncUseCase<CanonicalOpportunity>,\n * ) {}\n * }\n * ```\n *\n * `global: true` means feature modules do not need to re-import\n * `SyncModule` — the substrate tokens are available project-wide.\n */\nimport { Module, type DynamicModule, type Provider } from '@nestjs/common';\nimport {\n SYNC_CURSOR_STORE,\n SYNC_FIELD_DIFFER,\n SYNC_MODULE_OPTIONS,\n SYNC_MULTI_TENANT,\n SYNC_RUN_RECORDER,\n} from './sync.tokens';\nimport { MemoryCursorStore } from './sync-cursor-store.memory-backend';\nimport { MemoryRunRecorder } from './sync-run-recorder.memory-backend';\nimport { PostgresCursorStore } from './sync-cursor-store.drizzle-backend';\nimport { DrizzleSyncRunRecorder } from './sync-run-recorder.drizzle-backend';\nimport { DeepEqualDiffer } from './deep-equal.differ';\n\nexport interface SyncModuleOptions {\n /**\n * Backend selection. `drizzle` wires the Postgres cursor store +\n * run-log recorder; `memory` wires in-memory doubles suitable for\n * tests + local dev.\n */\n backend: 'drizzle' | 'memory';\n\n /**\n * Multi-tenancy opt-in (SYNC-6).\n *\n * When `true`, every call to the orchestrator + both Drizzle backends\n * must supply a non-null `tenantId`; missing values throw\n * `MissingTenantIdError`. Defense-in-depth: the orchestrator rejects\n * at entry (no dangling `status=running` rows) AND the Drizzle\n * backends reject at their write boundary (belt-and-braces for any\n * path that bypasses the orchestrator). Both sites use the shared\n * `assertTenantId` helper so error messages match.\n *\n * Memory backends accept `tenantId` unconditionally — their state is\n * process-local; cross-tenant isolation there is not meaningful.\n *\n * Defaults to `false`.\n */\n multiTenant?: boolean;\n}\n\n@Module({})\nexport class SyncModule {\n static forRoot(options: SyncModuleOptions): DynamicModule {\n const multiTenant = options.multiTenant ?? false;\n\n const sharedProviders: Provider[] = [\n { provide: SYNC_MODULE_OPTIONS, useValue: options },\n { provide: SYNC_MULTI_TENANT, useValue: multiTenant },\n // Default differ — consumers can override by binding a different\n // `IFieldDiffer<T>` to `SYNC_FIELD_DIFFER` in their feature module.\n { provide: SYNC_FIELD_DIFFER, useValue: new DeepEqualDiffer() },\n ];\n\n const backendProviders: Provider[] =\n options.backend === 'memory'\n ? [\n // Wired as singletons via `useValue` so tests can pull\n // them out via `moduleRef.get(MemoryCursorStore)` for\n // direct assertions. Matches JOB-4 / MemoryJobStore shape.\n { provide: MemoryCursorStore, useValue: new MemoryCursorStore() },\n {\n provide: SYNC_CURSOR_STORE,\n useExisting: MemoryCursorStore,\n },\n { provide: MemoryRunRecorder, useValue: new MemoryRunRecorder() },\n {\n provide: SYNC_RUN_RECORDER,\n useExisting: MemoryRunRecorder,\n },\n ]\n : [\n // Drizzle backends — injected with DRIZZLE (provided by the\n // consumer's DrizzleModule) + the SYNC_MULTI_TENANT flag\n // we bound above.\n { provide: SYNC_CURSOR_STORE, useClass: PostgresCursorStore },\n { provide: SYNC_RUN_RECORDER, useClass: DrizzleSyncRunRecorder },\n ];\n\n return {\n module: SyncModule,\n global: true,\n providers: [...sharedProviders, ...backendProviders],\n exports: [\n SYNC_MODULE_OPTIONS,\n SYNC_MULTI_TENANT,\n SYNC_FIELD_DIFFER,\n SYNC_CURSOR_STORE,\n SYNC_RUN_RECORDER,\n ],\n };\n }\n}\n","import { z } from \"zod\";\n\n/**\n * Event Definition Schema\n *\n * Describes a single `events/*.yaml` file. This is the codegen-side contract\n * for first-class event declarations (ADR-024 Phase 1, EVT-2). One file per\n * event; filename matches `type` (snake_case). Consumed by EVT-3 to emit\n * `runtime/subsystems/events/generated/` artifacts.\n *\n * Payload field types intentionally narrower than entity field types:\n * events are a wire format, not a database schema. `decimal`, `entity_ref`,\n * `string_array`, `enum` make no sense in an event payload.\n */\n\n// ============================================================================\n// Enums and constants\n// ============================================================================\n\nexport const EVENT_DIRECTIONS = [\"inbound\", \"change\", \"outbound\"] as const;\nexport type EventDirection = (typeof EVENT_DIRECTIONS)[number];\n\n/**\n * Event tiers (AUDIT-1):\n * - `domain` (default) — facts other components may react to. Bridge-eligible.\n * Carries a `direction` and routes through the corresponding\n * `events_*` pool.\n * - `audit` — observational facts about the system itself (sync ran, feature\n * used). NOT bridge-eligible. MUST have no `direction` and no `pool`.\n *\n * See `ai-docs/specs/issue-242/plan.md` for the full design and the EVT\n * skill (`.claude/skills/events/SKILL.md`) for the runtime contract.\n */\nexport const EVENT_TIERS = [\"domain\", \"audit\"] as const;\nexport type EventTier = (typeof EVENT_TIERS)[number];\n\nexport const EVENT_FIELD_TYPES = [\n\t\"uuid\",\n\t\"string\",\n\t\"number\",\n\t\"boolean\",\n\t\"date\",\n\t\"json\",\n\t\"array\",\n] as const;\nexport type EventFieldType = (typeof EVENT_FIELD_TYPES)[number];\n\n/**\n * Scalar types permitted as `items` of an `array` field. Intentionally narrower\n * than the full field-type set: nested arrays and nested objects inside a\n * payload array cross the line from \"wire format\" into \"embedded schema\" and\n * should be modelled either as a separate event or as a `json` blob.\n */\nexport const EVENT_ARRAY_ITEM_TYPES = [\n\t\"uuid\",\n\t\"string\",\n\t\"number\",\n\t\"boolean\",\n\t\"date\",\n] as const;\nexport type EventArrayItemType = (typeof EVENT_ARRAY_ITEM_TYPES)[number];\n\nexport const RESERVED_EVENT_POOLS = [\n\t\"events_inbound\",\n\t\"events_change\",\n\t\"events_outbound\",\n] as const;\nexport type EventPool = (typeof RESERVED_EVENT_POOLS)[number];\n\nexport const EVENT_BACKOFF_STRATEGIES = [\"linear\", \"exponential\"] as const;\nexport type EventBackoffStrategy = (typeof EVENT_BACKOFF_STRATEGIES)[number];\n\n/**\n * Direction → default pool derivation. Each `direction` maps to exactly one\n * reserved pool; overrides must stay within the same category.\n */\nexport const DIRECTION_TO_POOL: Record<EventDirection, EventPool> = {\n\tinbound: \"events_inbound\",\n\tchange: \"events_change\",\n\toutbound: \"events_outbound\",\n};\n\n// ============================================================================\n// Sub-schemas\n// ============================================================================\n\nconst EventDirectionSchema = z.enum(EVENT_DIRECTIONS);\nconst EventTierSchema = z.enum(EVENT_TIERS);\nconst EventFieldTypeSchema = z.enum(EVENT_FIELD_TYPES);\nconst EventArrayItemTypeSchema = z.enum(EVENT_ARRAY_ITEM_TYPES);\nconst EventPoolSchema = z.enum(RESERVED_EVENT_POOLS);\n\n/**\n * Per-payload-field metadata. `nullable: true` means the field may be `null`\n * on the wire; `description` is surfaced into the generated interface/Zod\n * schema as a JSDoc. `items` is required when `type: 'array'` and rejected\n * otherwise — enforces \"array-ness is declared, item shape is declared\"\n * without opening the door to arbitrary nesting.\n */\nconst EventPayloadFieldSchema = z\n\t.object({\n\t\ttype: EventFieldTypeSchema,\n\t\titems: EventArrayItemTypeSchema.optional(),\n\t\tnullable: z.boolean().optional().default(false),\n\t\tdescription: z.string().optional(),\n\t})\n\t.strict()\n\t.superRefine((data, ctx) => {\n\t\tif (data.type === \"array\" && data.items === undefined) {\n\t\t\tctx.addIssue({\n\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\tmessage: \"'items' is required when type is 'array'\",\n\t\t\t\tpath: [\"items\"],\n\t\t\t});\n\t\t}\n\t\tif (data.type !== \"array\" && data.items !== undefined) {\n\t\t\tctx.addIssue({\n\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\tmessage: `'items' is only valid when type is 'array' (got '${data.type}')`,\n\t\t\t\tpath: [\"items\"],\n\t\t\t});\n\t\t}\n\t});\n\nexport type EventPayloadField = z.infer<typeof EventPayloadFieldSchema>;\n\n/**\n * Retry metadata hints surfaced to the drain loop. Default applied at parent\n * level (see `EventDefinitionSchemaCore`).\n */\nconst RetrySchema = z\n\t.object({\n\t\tattempts: z.number().int().min(0).max(20),\n\t\tbackoff: z.enum(EVENT_BACKOFF_STRATEGIES),\n\t})\n\t.strict();\n\nexport type EventRetry = z.infer<typeof RetrySchema>;\n\n// ============================================================================\n// Top-level schema\n// ============================================================================\n\nconst SNAKE_CASE_RE = /^[a-z][a-z0-9_]*$/;\n\nconst EventDefinitionSchemaCore = z\n\t.object({\n\t\ttype: z\n\t\t\t.string()\n\t\t\t.regex(\n\t\t\t\tSNAKE_CASE_RE,\n\t\t\t\t\"Event type must be snake_case starting with a letter\",\n\t\t\t),\n\t\ttier: EventTierSchema.optional().default(\"domain\"),\n\t\tdirection: EventDirectionSchema.optional(),\n\t\tpool: EventPoolSchema.optional(),\n\t\taggregate: z.string().regex(SNAKE_CASE_RE).optional(),\n\t\tsource: z.string().min(1).optional(),\n\t\tdestination: z.string().min(1).optional(),\n\t\tpayload: z\n\t\t\t.record(\n\t\t\t\tz\n\t\t\t\t\t.string()\n\t\t\t\t\t.regex(SNAKE_CASE_RE, \"Payload keys must be snake_case\"),\n\t\t\t\tEventPayloadFieldSchema,\n\t\t\t)\n\t\t\t.default({}),\n\t\tretry: RetrySchema.optional().default({\n\t\t\tattempts: 3,\n\t\t\tbackoff: \"exponential\",\n\t\t}),\n\t\tversion: z.number().int().min(1).optional().default(1),\n\t\tdescription: z.string().optional(),\n\t})\n\t.strict();\n\n/**\n * Cross-field refinements (in order):\n *\n * 1. Tier invariants (AUDIT-1):\n * a. `tier: 'audit'` ⇒ `pool` MUST be omitted.\n * b. `tier: 'audit'` ⇒ `direction` MUST be omitted.\n * c. `tier: 'domain'` ⇒ `direction` is required.\n * 2. `direction: change` ⇒ `aggregate` is required.\n * 3. `source` is only valid when `direction: inbound` (strict direction gating).\n * 4. `destination` is only valid when `direction: outbound` (strict direction gating).\n * 5. An explicit `pool` must match `DIRECTION_TO_POOL[direction]`.\n *\n * Strict gating on #3/#4 is a deliberate choice: silent acceptance breeds\n * drift. The ADR defines `source` as inbound-only and `destination` as\n * outbound-only.\n *\n * Refinements #2..#5 are domain-tier-only — audit events have no\n * direction/pool/aggregate/source/destination semantics.\n */\nconst EventDefinitionSchemaRefined = EventDefinitionSchemaCore.superRefine(\n\t(data, ctx) => {\n\t\t// AUDIT-1 — tier invariants. These run first because the rest of\n\t\t// the refinements assume domain semantics (direction populated).\n\t\tif (data.tier === \"audit\") {\n\t\t\tif (data.pool !== undefined) {\n\t\t\t\tctx.addIssue({\n\t\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\t\tmessage: `Event '${data.type}' is tier:audit; pool MUST be omitted (got '${data.pool}'). Audit events have no pool. See ai-docs/specs/issue-242/plan.md §AUDIT-2.`,\n\t\t\t\t\tpath: [\"pool\"],\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (data.direction !== undefined) {\n\t\t\t\tctx.addIssue({\n\t\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\t\tmessage: `Event '${data.type}' is tier:audit; direction MUST be omitted (got '${data.direction}'). Audit events have no direction. See ai-docs/specs/issue-242/plan.md §AUDIT-2.`,\n\t\t\t\t\tpath: [\"direction\"],\n\t\t\t\t});\n\t\t\t}\n\t\t\t// Skip the domain-tier refinements below — they reference\n\t\t\t// `direction`, which is intentionally absent for audit.\n\t\t\treturn;\n\t\t}\n\n\t\t// tier === 'domain' — direction must be present.\n\t\tif (data.direction === undefined) {\n\t\t\tctx.addIssue({\n\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\tmessage: \"'direction' is required when tier is 'domain'\",\n\t\t\t\tpath: [\"direction\"],\n\t\t\t});\n\t\t\t// Bail out — the remaining refinements all read `direction`\n\t\t\t// and would otherwise produce confusing cascade errors.\n\t\t\treturn;\n\t\t}\n\n\t\tif (data.direction === \"change\" && !data.aggregate) {\n\t\t\tctx.addIssue({\n\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\tmessage: \"'aggregate' is required when direction is 'change'\",\n\t\t\t\tpath: [\"aggregate\"],\n\t\t\t});\n\t\t}\n\n\t\tif (data.source !== undefined && data.direction !== \"inbound\") {\n\t\t\tctx.addIssue({\n\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\tmessage: `'source' is only valid when direction is 'inbound' (got '${data.direction}')`,\n\t\t\t\tpath: [\"source\"],\n\t\t\t});\n\t\t}\n\n\t\tif (data.destination !== undefined && data.direction !== \"outbound\") {\n\t\t\tctx.addIssue({\n\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\tmessage: `'destination' is only valid when direction is 'outbound' (got '${data.direction}')`,\n\t\t\t\tpath: [\"destination\"],\n\t\t\t});\n\t\t}\n\n\t\tif (data.pool !== undefined) {\n\t\t\tconst expected = DIRECTION_TO_POOL[data.direction];\n\t\t\tif (data.pool !== expected) {\n\t\t\t\tctx.addIssue({\n\t\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\t\tmessage: `pool '${data.pool}' is inconsistent with direction '${data.direction}' (expected '${expected}')`,\n\t\t\t\t\tpath: [\"pool\"],\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t},\n);\n\n/**\n * Final schema: derive `pool` from `direction` when not explicitly set.\n *\n * After `parse()`:\n * - Domain events (`tier === 'domain'`): `pool` and `direction` are both\n * populated; `pool` is derived from `direction` when not explicit.\n * - Audit events (`tier === 'audit'`): `pool` and `direction` both stay\n * `undefined` — audit events have no routing fields by construction\n * (mirrors the `domain_events` CHECK constraint, AUDIT-1).\n */\nexport const EventDefinitionSchema = EventDefinitionSchemaRefined.transform(\n\t(parsed) => {\n\t\tif (parsed.tier === \"audit\") {\n\t\t\t// Audit events: no pool/direction derivation. Both stay undefined.\n\t\t\treturn parsed;\n\t\t}\n\t\t// tier === 'domain': direction is guaranteed present by the refinement.\n\t\t// Narrow the type for the lookup.\n\t\tconst direction = parsed.direction as EventDirection;\n\t\treturn {\n\t\t\t...parsed,\n\t\t\tpool: parsed.pool ?? DIRECTION_TO_POOL[direction],\n\t\t};\n\t},\n);\n\nexport type EventDefinition = z.infer<typeof EventDefinitionSchema>;\n\n// ============================================================================\n// Validation Helpers\n// ============================================================================\n\nexport function validateEventDefinition(data: unknown): EventDefinition {\n\treturn EventDefinitionSchema.parse(data);\n}\n\nexport function safeValidateEventDefinition(data: unknown): {\n\tsuccess: boolean;\n\tdata?: EventDefinition;\n\terror?: z.ZodError;\n} {\n\tconst result = EventDefinitionSchema.safeParse(data);\n\tif (result.success) {\n\t\treturn { success: true, data: result.data };\n\t}\n\treturn { success: false, error: result.error };\n}\n","import { z } from 'zod';\n\n/**\n * Relationship Definition Schema\n *\n * Defines the YAML contract for first-class relationship entities — typed,\n * temporal, sourced junction tables between core entities.\n *\n * A relationship definition generates the same artifacts as an entity\n * (Drizzle schema, repository, DTOs, NestJS module, controller) but with\n * auto-generated FK columns, type enum, temporal fields, and source tracking.\n *\n * The relationship: block replaces entity: as the top-level discriminator.\n * The fields:, queries:, and behaviors: blocks reuse entity-definition schemas.\n *\n * See: docs/codegen-evolution-data-model/03-relationship-taxonomy.md\n * See: test/fixtures/relationships/ for examples\n */\n\n// Re-use field and query schemas from entity-definition\n// These are imported to avoid duplication — fields on a relationship\n// work identically to fields on an entity.\nimport type { FieldDefinition, QueryDeclaration } from './entity-definition.schema.js';\n\n// ============================================================================\n// Relationship Type Definitions\n// ============================================================================\n\n/**\n * Direction metadata for a single relationship type.\n *\n * Required for self-referential relationships (person↔person, org↔org)\n * where direction can't be inferred from entity-type asymmetry.\n *\n * Three mutually exclusive modes:\n * - inverse: \"from→to is called X, to→from is called Y\"\n * - bidirectional: true — direction doesn't matter, query both sides\n * - directed: true — one-way, no inverse name (default if none specified)\n */\nconst TypeDirectionSchema = z\n\t.object({\n\t\t/** Name of the inverse type when viewed from the other direction */\n\t\tinverse: z.string().optional(),\n\t\t/** Both directions are equivalent — queries should check both FK columns */\n\t\tbidirectional: z.boolean().optional(),\n\t\t/** Explicitly directed, no named inverse (default behavior) */\n\t\tdirected: z.boolean().optional(),\n\t})\n\t.refine(\n\t\t(data) => {\n\t\t\tconst set = [data.inverse, data.bidirectional, data.directed].filter(\n\t\t\t\t(v) => v !== undefined,\n\t\t\t);\n\t\t\treturn set.length === 1;\n\t\t},\n\t\t{\n\t\t\tmessage:\n\t\t\t\t'Exactly one of inverse, bidirectional, or directed must be specified',\n\t\t},\n\t);\n\nexport type TypeDirection = z.infer<typeof TypeDirectionSchema>;\n\n/**\n * Relationship types can be declared in two forms:\n *\n * 1. Simple list — for cross-type relationships where direction is\n * unambiguous from entity asymmetry:\n * types: [employed_by, advises, board_member]\n *\n * 2. Object map — for self-referential or when types need direction metadata:\n * types:\n * reporting:\n * inverse: management\n * network:\n * bidirectional: true\n *\n * The simple list is sugar for \"all directed from→to, no inverses.\"\n */\nconst RelationshipTypesSchema = z.union([\n\t// Simple list: all types are directed from→to\n\tz.array(z.string().regex(/^[a-z][a-z0-9_]*$/, 'Type must be snake_case')),\n\t// Object map: each type has direction metadata\n\tz.record(\n\t\tz.string().regex(/^[a-z][a-z0-9_]*$/, 'Type key must be snake_case'),\n\t\tTypeDirectionSchema,\n\t),\n]);\n\nexport type RelationshipTypes = z.infer<typeof RelationshipTypesSchema>;\n\n// ============================================================================\n// On-Delete Semantics (ADR-021)\n// ============================================================================\n\nconst OnDeleteActionSchema = z\n\t.enum(['restrict', 'cascade', 'set_null', 'no_action'])\n\t.default('restrict');\n\nexport type OnDeleteAction = z.infer<typeof OnDeleteActionSchema>;\n\n// ============================================================================\n// Relationship Configuration Block\n// ============================================================================\n\n/**\n * The relationship: block — top-level config for a relationship definition.\n *\n * Establishes the two endpoints, type taxonomy, and behavioral flags.\n * Auto-generates FK columns, type enum, temporal fields, source tracking,\n * and timestamps based on configuration.\n */\nconst RelationshipConfigSchema = z\n\t.object({\n\t\t/** Relationship name (snake_case). Used for class/file naming. */\n\t\tname: z.string().regex(\n\t\t\t/^[a-z][a-z0-9_]*$/,\n\t\t\t'Relationship name must be snake_case',\n\t\t),\n\n\t\t/** Database table name. Defaults to {name}s if not specified. */\n\t\ttable: z\n\t\t\t.string()\n\t\t\t.regex(/^[a-z][a-z0-9_]*$/, 'Table must be snake_case')\n\t\t\t.optional(),\n\n\t\t/** The \"from\" entity — generates {entity}_id FK column (subject). */\n\t\tfrom: z.string().regex(/^[a-z][a-z0-9_]*$/, 'Entity name must be snake_case'),\n\n\t\t/** The \"to\" entity — generates {entity}_id FK column (object). */\n\t\tto: z.string().regex(/^[a-z][a-z0-9_]*$/, 'Entity name must be snake_case'),\n\n\t\t/**\n\t\t * Relationship subtypes. Optional — omit for untyped junctions.\n\t\t * When present, generates a `type` enum column on the junction table.\n\t\t *\n\t\t * Simple list: all types are directed (from→to). Use for cross-type\n\t\t * relationships where entity asymmetry makes direction obvious.\n\t\t *\n\t\t * Object map: each type declares its own direction metadata.\n\t\t * Required for self-referential relationships (from === to).\n\t\t */\n\t\ttypes: RelationshipTypesSchema.optional(),\n\n\t\t/**\n\t\t * Generate temporal validity fields: valid_from (date), valid_to (date?),\n\t\t * is_current (boolean, denormalized for query performance).\n\t\t * Default: true\n\t\t */\n\t\ttemporal: z.boolean().default(true),\n\n\t\t/**\n\t\t * Generate source tracking fields: source (enum), confidence (decimal 0-1).\n\t\t * Default: true\n\t\t */\n\t\tsourced: z.boolean().default(true),\n\n\t\t/** on_delete action for the \"from\" endpoint FK. Default: restrict */\n\t\ton_delete_from: OnDeleteActionSchema.optional(),\n\n\t\t/** on_delete action for the \"to\" endpoint FK. Default: restrict */\n\t\ton_delete_to: OnDeleteActionSchema.optional(),\n\n\t\t/**\n\t\t * Override the default unique constraint columns.\n\t\t *\n\t\t * Defaults:\n\t\t * - Typed: [from_id, to_id, type]\n\t\t * - Typed + temporal: [from_id, to_id, type, valid_from]\n\t\t * - Untyped: [from_id, to_id]\n\t\t *\n\t\t * Use this when the default doesn't fit — e.g., allowing multiple\n\t\t * relationships of the same type between the same entities at different times.\n\t\t */\n\t\tunique_on: z.array(z.string()).optional(),\n\t})\n\t.strict();\n\nexport type RelationshipConfig = z.infer<typeof RelationshipConfigSchema>;\n\n// ============================================================================\n// Query Declaration (reuse from entity-definition)\n// ============================================================================\n\n/**\n * Same query declaration syntax as entities.\n * FK field names in `by:` use the auto-generated names:\n * - Cross-type: {entity}_id (e.g., person_id, organization_id)\n * - Self-referential: from_{entity}_id, to_{entity}_id\n */\nconst RelationshipQuerySchema = z.object({\n\tby: z.array(z.string()).min(1),\n\tunique: z.boolean().optional(),\n\tselect: z.array(z.string()).optional(),\n\torder: z.string().optional(),\n\tlimit: z.boolean().optional(),\n});\n\n// ============================================================================\n// Field Definition (reuse from entity-definition)\n// ============================================================================\n\n// We import the type but need to re-reference the schema inline for Zod parsing.\n// The actual FieldDefinitionSchema is defined in entity-definition.schema.ts.\n// For now, we use z.record(z.string(), z.any()) and validate fields\n// through the shared FieldDefinitionSchema at parse time.\n//\n// TODO: Extract FieldDefinitionSchema to a shared module so both\n// entity-definition and relationship-definition can import it directly.\n\n// ============================================================================\n// Full Relationship Definition\n// ============================================================================\n\n/**\n * Complete relationship definition — the top-level shape of a relationship YAML file.\n *\n * Example (minimal):\n * relationship:\n * name: engagement_opportunity\n * from: engagement\n * to: opportunity\n *\n * Example (full):\n * relationship:\n * name: person_organization\n * table: person_organizations\n * from: person\n * to: organization\n * types: [employed_by, advises, board_member]\n * temporal: true\n * sourced: true\n * fields:\n * role_title:\n * type: string\n * nullable: true\n * queries:\n * - by: [person_id]\n */\nexport const RelationshipDefinitionSchema = z\n\t.object({\n\t\t/** Relationship configuration block */\n\t\trelationship: RelationshipConfigSchema,\n\n\t\t/**\n\t\t * Additional fields beyond auto-generated ones.\n\t\t * These describe the relationship, not either endpoint entity.\n\t\t * Uses the same field definition schema as entity fields.\n\t\t */\n\t\tfields: z.record(z.string(), z.any()).optional(),\n\n\t\t/** Declarative queries — same syntax as entity queries. */\n\t\tqueries: z.array(RelationshipQuerySchema).optional(),\n\t})\n\t.strict()\n\t.refine(\n\t\t(data) => {\n\t\t\t// Self-referential relationships with types MUST use the object map form\n\t\t\t// so that direction metadata (inverse/bidirectional/directed) is explicit.\n\t\t\tif (data.relationship.from === data.relationship.to && data.relationship.types) {\n\t\t\t\treturn !Array.isArray(data.relationship.types);\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\t\t{\n\t\t\tmessage:\n\t\t\t\t'Self-referential relationships must use the object map form for types ' +\n\t\t\t\t'(with inverse/bidirectional/directed metadata), not a simple list',\n\t\t\tpath: ['relationship', 'types'],\n\t\t},\n\t)\n\t.refine(\n\t\t(data) => {\n\t\t\t// Reject fields: keys that collide with auto-generated column names.\n\t\t\t// The reserved set is dynamic — depends on the relationship config.\n\t\t\tif (!data.fields) return true;\n\n\t\t\tconst reserved = getReservedColumnNames(data.relationship);\n\t\t\tconst collisions = Object.keys(data.fields).filter((key) =>\n\t\t\t\treserved.has(key),\n\t\t\t);\n\t\t\treturn collisions.length === 0;\n\t\t},\n\t\t{\n\t\t\tmessage:\n\t\t\t\t'fields: contains keys that collide with auto-generated columns. ' +\n\t\t\t\t'Reserved names depend on config (type, valid_from, valid_to, ' +\n\t\t\t\t'is_current, source, confidence, id, created_at, updated_at, and FK columns).',\n\t\t\tpath: ['fields'],\n\t\t},\n\t);\n\nexport type RelationshipDefinition = z.infer<\n\ttypeof RelationshipDefinitionSchema\n>;\n\n// ============================================================================\n// Validation Helpers\n// ============================================================================\n\nexport function validateRelationshipDefinition(\n\tdata: unknown,\n): RelationshipDefinition {\n\treturn RelationshipDefinitionSchema.parse(data);\n}\n\nexport function safeValidateRelationshipDefinition(data: unknown): {\n\tsuccess: boolean;\n\tdata?: RelationshipDefinition;\n\terror?: z.ZodError;\n} {\n\tconst result = RelationshipDefinitionSchema.safeParse(data);\n\tif (result.success) {\n\t\treturn { success: true, data: result.data };\n\t}\n\treturn { success: false, error: result.error };\n}\n\n// ============================================================================\n// Reserved Column Names\n// ============================================================================\n\n/**\n * Returns the set of column names that are auto-generated for a relationship\n * and therefore cannot be used as custom field names.\n *\n * The set is dynamic — it depends on the relationship config:\n * - Always: id, created_at, updated_at, and both FK columns\n * - If types: present → type\n * - If temporal: true → valid_from, valid_to, is_current\n * - If sourced: true → source, confidence\n */\nexport function getReservedColumnNames(config: RelationshipConfig): Set<string> {\n\tconst { fromColumn, toColumn } = deriveRelationshipFKColumns(config);\n\tconst reserved = new Set([\n\t\t'id',\n\t\t'created_at',\n\t\t'updated_at',\n\t\tfromColumn,\n\t\ttoColumn,\n\t]);\n\n\tif (config.types) {\n\t\treserved.add('type');\n\t}\n\tif (config.temporal) {\n\t\treserved.add('valid_from');\n\t\treserved.add('valid_to');\n\t\treserved.add('is_current');\n\t}\n\tif (config.sourced) {\n\t\treserved.add('source');\n\t\treserved.add('confidence');\n\t}\n\n\treturn reserved;\n}\n\n// ============================================================================\n// Auto-Generated Field Helpers\n// ============================================================================\n\n/**\n * Derives the FK column names for a relationship.\n *\n * Cross-type (from !== to):\n * from: person, to: organization → person_id, organization_id\n *\n * Self-referential (from === to):\n * from: person, to: person → from_person_id, to_person_id\n */\nexport function deriveRelationshipFKColumns(config: RelationshipConfig): {\n\tfromColumn: string;\n\ttoColumn: string;\n} {\n\tif (config.from === config.to) {\n\t\treturn {\n\t\t\tfromColumn: `from_${config.from}_id`,\n\t\t\ttoColumn: `to_${config.to}_id`,\n\t\t};\n\t}\n\treturn {\n\t\tfromColumn: `${config.from}_id`,\n\t\ttoColumn: `${config.to}_id`,\n\t};\n}\n\n/**\n * Derives the default table name if not explicitly specified.\n * Uses the relationship name + 's' suffix.\n */\nexport function deriveTableName(config: RelationshipConfig): string {\n\treturn config.table ?? `${config.name}s`;\n}\n\n/**\n * Collects all type names from a types declaration.\n * Handles both simple list and object map forms.\n */\nexport function collectTypeNames(\n\ttypes: RelationshipTypes | undefined,\n): string[] {\n\tif (!types) return [];\n\tif (Array.isArray(types)) return types;\n\treturn Object.keys(types);\n}\n\n/**\n * Collects all inverse type names from a types declaration.\n * Only applicable for object map form with inverse metadata.\n */\nexport function collectInverseNames(\n\ttypes: RelationshipTypes | undefined,\n): string[] {\n\tif (!types || Array.isArray(types)) return [];\n\treturn Object.values(types)\n\t\t.map((dir) => (dir as TypeDirection & { inverse?: string }).inverse)\n\t\t.filter((v): v is string => v !== undefined);\n}\n\n/**\n * Determines the default unique constraint columns.\n *\n * Logic:\n * - Typed + temporal: [from_id, to_id, type, valid_from]\n * - Typed: [from_id, to_id, type]\n * - Untyped: [from_id, to_id]\n */\nexport function deriveUniqueConstraint(config: RelationshipConfig): string[] {\n\tif (config.unique_on) return config.unique_on;\n\n\tconst { fromColumn, toColumn } = deriveRelationshipFKColumns(config);\n\tconst columns = [fromColumn, toColumn];\n\n\tif (config.types) {\n\t\tcolumns.push('type');\n\t}\n\tif (config.temporal && config.types) {\n\t\tcolumns.push('valid_from');\n\t}\n\n\treturn columns;\n}\n","/**\n * Graph Builder\n *\n * Builds a domain graph from parsed entities, including nodes and edges.\n * Tracks bidirectional connections between entities.\n */\n\nimport type {\n\tParsedEntity,\n\tParsedRelationship,\n\tParsedRelationshipDefinition,\n\tDomainGraph,\n\tRelationshipEdge,\n\tEntityNode,\n} from './types';\n\n/**\n * Infer cardinality from relationship type\n */\nfunction inferCardinality(type: string): '1:1' | '1:N' | 'N:1' | 'N:M' {\n\tswitch (type) {\n\t\tcase 'belongs_to':\n\t\t\treturn 'N:1';\n\t\tcase 'has_many':\n\t\t\treturn '1:N';\n\t\tcase 'has_one':\n\t\t\treturn '1:1';\n\t\tdefault:\n\t\t\treturn '1:N';\n\t}\n}\n\n/**\n * Check if an edge already exists in the opposite direction\n */\nfunction hasReverseEdge(\n\tedges: RelationshipEdge[],\n\tfrom: string,\n\tto: string\n): RelationshipEdge | undefined {\n\treturn edges.find((e) => e.from === to && e.to === from);\n}\n\n/**\n * Build a domain graph from parsed entities\n */\nexport function buildDomainGraph(\n\tentities: ParsedEntity[],\n\trelationshipDefinitions: ParsedRelationshipDefinition[] = [],\n): DomainGraph {\n\tconst entityMap = new Map<string, ParsedEntity>();\n\tconst relDefMap = new Map<string, ParsedRelationshipDefinition>();\n\tconst edges: RelationshipEdge[] = [];\n\n\t// Build entity map\n\tfor (const entity of entities) {\n\t\tentityMap.set(entity.name, entity);\n\t}\n\n\t// Build relationship definition map\n\tfor (const relDef of relationshipDefinitions) {\n\t\trelDefMap.set(relDef.name, relDef);\n\t}\n\n\t// Build edges from inline entity relationships (belongs_to, has_many, has_one)\n\tfor (const entity of entities) {\n\t\tfor (const [relName, rel] of entity.relationships) {\n\t\t\tif (!rel.resolved) continue;\n\n\t\t\t// Check if reverse edge already exists\n\t\t\tconst reverseEdge = hasReverseEdge(edges, entity.name, rel.target);\n\n\t\t\tconst edge: RelationshipEdge = {\n\t\t\t\tfrom: entity.name,\n\t\t\t\tto: rel.target,\n\t\t\t\trelationship: rel,\n\t\t\t\tcardinality: inferCardinality(rel.type),\n\t\t\t\tbidirectional: reverseEdge !== undefined,\n\t\t\t};\n\n\t\t\t// Mark reverse edge as bidirectional too\n\t\t\tif (reverseEdge) {\n\t\t\t\treverseEdge.bidirectional = true;\n\t\t\t}\n\n\t\t\tedges.push(edge);\n\t\t}\n\t}\n\n\t// Build edges from first-class relationship definitions (junction entities)\n\tfor (const relDef of relationshipDefinitions) {\n\t\tconst fromExists = entityMap.has(relDef.from);\n\t\tconst toExists = entityMap.has(relDef.to);\n\n\t\tif (fromExists && toExists) {\n\t\t\t// Create an N:M edge — junction tables are always many-to-many\n\t\t\tconst edge: RelationshipEdge = {\n\t\t\t\tfrom: relDef.from,\n\t\t\t\tto: relDef.to,\n\t\t\t\trelationship: {\n\t\t\t\t\tname: relDef.name,\n\t\t\t\t\ttype: 'has_many',\n\t\t\t\t\ttarget: relDef.to,\n\t\t\t\t\tforeignKey: relDef.fromColumn,\n\t\t\t\t\tresolved: true,\n\t\t\t\t},\n\t\t\t\tcardinality: 'N:M',\n\t\t\t\tbidirectional: relDef.types.some((t) => t.bidirectional),\n\t\t\t};\n\n\t\t\tedges.push(edge);\n\t\t}\n\t}\n\n\treturn { entities: entityMap, relationshipDefinitions: relDefMap, edges };\n}\n\n/**\n * Get all entities related to a given entity within a specified depth\n */\nexport function getRelatedEntities(\n\tgraph: DomainGraph,\n\tentityName: string,\n\tdepth = 1\n): Set<string> {\n\tconst related = new Set<string>();\n\tconst visited = new Set<string>();\n\tconst queue: Array<{ name: string; currentDepth: number }> = [\n\t\t{ name: entityName, currentDepth: 0 },\n\t];\n\n\twhile (queue.length > 0) {\n\t\tconst item = queue.shift();\n\t\tif (!item) continue;\n\n\t\tconst { name, currentDepth } = item;\n\t\tif (visited.has(name) || currentDepth > depth) continue;\n\t\tvisited.add(name);\n\n\t\tfor (const edge of graph.edges) {\n\t\t\tif (edge.from === name && !visited.has(edge.to)) {\n\t\t\t\trelated.add(edge.to);\n\t\t\t\tqueue.push({ name: edge.to, currentDepth: currentDepth + 1 });\n\t\t\t}\n\t\t\tif (edge.to === name && !visited.has(edge.from)) {\n\t\t\t\trelated.add(edge.from);\n\t\t\t\tqueue.push({ name: edge.from, currentDepth: currentDepth + 1 });\n\t\t\t}\n\t\t}\n\t}\n\n\treturn related;\n}\n\n/**\n * Find entities with no relationships (orphans)\n */\nexport function findOrphanEntities(graph: DomainGraph): string[] {\n\tconst orphans: string[] = [];\n\tfor (const [name] of graph.entities) {\n\t\tconst hasRelationship = graph.edges.some((e) => e.from === name || e.to === name);\n\t\tif (!hasRelationship) {\n\t\t\torphans.push(name);\n\t\t}\n\t}\n\treturn orphans;\n}\n\n/**\n * Find circular dependencies in the graph\n */\nexport function findCircularDependencies(graph: DomainGraph): string[][] {\n\tconst cycles: string[][] = [];\n\tconst visited = new Set<string>();\n\tconst recursionStack = new Set<string>();\n\n\tfunction dfs(node: string, path: string[]): void {\n\t\tvisited.add(node);\n\t\trecursionStack.add(node);\n\n\t\tconst outgoingEdges = graph.edges.filter((e) => e.from === node);\n\t\tfor (const edge of outgoingEdges) {\n\t\t\tif (!visited.has(edge.to)) {\n\t\t\t\tdfs(edge.to, [...path, edge.to]);\n\t\t\t} else if (recursionStack.has(edge.to)) {\n\t\t\t\t// Found cycle\n\t\t\t\tconst cycleStart = path.indexOf(edge.to);\n\t\t\t\tif (cycleStart !== -1) {\n\t\t\t\t\tcycles.push([...path.slice(cycleStart), edge.to]);\n\t\t\t\t} else {\n\t\t\t\t\t// The cycle starts at edge.to which is in the recursion stack\n\t\t\t\t\tcycles.push([...path, edge.to]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\trecursionStack.delete(node);\n\t}\n\n\tfor (const [name] of graph.entities) {\n\t\tif (!visited.has(name)) {\n\t\t\tdfs(name, [name]);\n\t\t}\n\t}\n\n\t// Deduplicate cycles (same cycle can be detected from different starting points)\n\tconst uniqueCycles: string[][] = [];\n\tconst seen = new Set<string>();\n\n\tfor (const cycle of cycles) {\n\t\t// Normalize cycle by rotating to start with smallest element\n\t\tconst minIndex = cycle.indexOf(\n\t\t\tcycle.reduce((min, val) => (val < min ? val : min), cycle[0])\n\t\t);\n\t\tconst normalized = [...cycle.slice(minIndex), ...cycle.slice(0, minIndex)];\n\t\tconst key = normalized.join('->');\n\n\t\tif (!seen.has(key)) {\n\t\t\tseen.add(key);\n\t\t\tuniqueCycles.push(cycle);\n\t\t}\n\t}\n\n\treturn uniqueCycles;\n}\n\n/**\n * Build entity nodes for visualization\n */\nexport function buildEntityNodes(graph: DomainGraph): EntityNode[] {\n\tconst nodes: EntityNode[] = [];\n\tfor (const [name, entity] of graph.entities) {\n\t\tnodes.push({\n\t\t\tid: name,\n\t\t\tname: entity.name,\n\t\t\tentity,\n\t\t});\n\t}\n\treturn nodes;\n}\n","/**\n * External ID Tracking Behavior\n *\n * Adds external_id, provider, and provider_metadata fields to track\n * records that are synced from external systems (e.g., Salesforce, HubSpot).\n */\n\nimport type { BehaviorDefinition } from './types';\n\nexport const externalIdTrackingBehavior: BehaviorDefinition = {\n\tname: 'external_id_tracking',\n\tdescription: 'Adds external_id, provider, and provider_metadata fields for external system sync tracking',\n\n\tfields: [\n\t\t{\n\t\t\tname: 'external_id',\n\t\t\tcamelName: 'externalId',\n\t\t\ttype: 'string',\n\t\t\ttsType: 'string | null',\n\t\t\tdrizzleType: 'varchar',\n\t\t\tdrizzleImports: ['varchar', 'index'],\n\t\t\tzodType: 'z.string().nullable()',\n\t\t\tnullable: true,\n\t\t\tui: {\n\t\t\t\tlabel: 'External ID',\n\t\t\t\ttype: 'text',\n\t\t\t\timportance: 'tertiary',\n\t\t\t\tgroup: 'metadata',\n\t\t\t\tvisible: false,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: 'provider',\n\t\t\tcamelName: 'provider',\n\t\t\ttype: 'string',\n\t\t\ttsType: 'string | null',\n\t\t\tdrizzleType: 'varchar',\n\t\t\tdrizzleImports: ['varchar'],\n\t\t\tzodType: 'z.string().nullable()',\n\t\t\tnullable: true,\n\t\t\tui: {\n\t\t\t\tlabel: 'Provider',\n\t\t\t\ttype: 'text',\n\t\t\t\timportance: 'tertiary',\n\t\t\t\tgroup: 'metadata',\n\t\t\t\tvisible: false,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: 'provider_metadata',\n\t\t\tcamelName: 'providerMetadata',\n\t\t\ttype: 'json',\n\t\t\ttsType: 'unknown | null',\n\t\t\tdrizzleType: 'jsonb',\n\t\t\tdrizzleImports: ['jsonb'],\n\t\t\tzodType: 'z.unknown().nullable()',\n\t\t\tnullable: true,\n\t\t\tui: {\n\t\t\t\tlabel: 'Provider Metadata',\n\t\t\t\ttype: 'json',\n\t\t\t\timportance: 'tertiary',\n\t\t\t\tgroup: 'metadata',\n\t\t\t\tvisible: false,\n\t\t\t},\n\t\t},\n\t],\n\n\tdrizzleImports: ['varchar', 'jsonb', 'index'],\n\n\tconfigKey: 'externalIdTracking',\n};\n","/**\n * Soft Delete Behavior\n *\n * Adds deleted_at field for soft delete functionality.\n * Records are marked as deleted instead of being removed from the database.\n * BaseRepository automatically filters soft-deleted records in queries.\n */\n\nimport type { BehaviorDefinition } from './types';\n\nexport const softDeleteBehavior: BehaviorDefinition = {\n\tname: 'soft_delete',\n\tdescription: 'Adds deleted_at field for soft delete functionality',\n\n\tfields: [\n\t\t{\n\t\t\tname: 'deleted_at',\n\t\t\tcamelName: 'deletedAt',\n\t\t\ttype: 'datetime',\n\t\t\ttsType: 'Date | null',\n\t\t\tdrizzleType: 'timestamp',\n\t\t\tdrizzleImports: ['timestamp'],\n\t\t\tzodType: 'z.coerce.date().nullable()',\n\t\t\tnullable: true,\n\t\t\tui: {\n\t\t\t\tlabel: 'Deleted At',\n\t\t\t\ttype: 'datetime',\n\t\t\t\timportance: 'tertiary',\n\t\t\t\tgroup: 'metadata',\n\t\t\t\tvisible: false,\n\t\t\t},\n\t\t},\n\t],\n\n\tdrizzleImports: ['timestamp'],\n\n\tmethods: [\n\t\t'softDelete',\n\t\t'restore',\n\t\t'findWithDeleted',\n\t\t'findOnlyDeleted',\n\t\t'baseQuery', // Modified to filter deleted records\n\t],\n\n\tconfigKey: 'softDelete',\n};\n","/**\n * Timestamps Behavior\n *\n * Adds created_at and updated_at fields to track entity lifecycle.\n * These fields are automatically managed by BaseRepository.\n */\n\nimport type { BehaviorDefinition } from './types';\n\nexport const timestampsBehavior: BehaviorDefinition = {\n\tname: 'timestamps',\n\tdescription: 'Adds created_at and updated_at timestamp fields',\n\n\tfields: [\n\t\t{\n\t\t\tname: 'created_at',\n\t\t\tcamelName: 'createdAt',\n\t\t\ttype: 'datetime',\n\t\t\ttsType: 'Date',\n\t\t\tdrizzleType: 'timestamp',\n\t\t\tdrizzleImports: ['timestamp'],\n\t\t\tzodType: 'z.coerce.date()',\n\t\t\tnullable: false,\n\t\t\tdefault: 'now()',\n\t\t\tui: {\n\t\t\t\tlabel: 'Created At',\n\t\t\t\ttype: 'datetime',\n\t\t\t\timportance: 'tertiary',\n\t\t\t\tgroup: 'metadata',\n\t\t\t\tvisible: false,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: 'updated_at',\n\t\t\tcamelName: 'updatedAt',\n\t\t\ttype: 'datetime',\n\t\t\ttsType: 'Date',\n\t\t\tdrizzleType: 'timestamp',\n\t\t\tdrizzleImports: ['timestamp'],\n\t\t\tzodType: 'z.coerce.date()',\n\t\t\tnullable: false,\n\t\t\tdefault: 'now()',\n\t\t\tui: {\n\t\t\t\tlabel: 'Updated At',\n\t\t\t\ttype: 'datetime',\n\t\t\t\timportance: 'tertiary',\n\t\t\t\tgroup: 'metadata',\n\t\t\t\tvisible: false,\n\t\t\t},\n\t\t},\n\t],\n\n\tdrizzleImports: ['timestamp'],\n\n\tmethods: ['applyTimestampsOnCreate', 'applyTimestampsOnUpdate'],\n\n\tconfigKey: 'timestamps',\n};\n","/**\n * User Tracking Behavior\n *\n * Adds created_by and updated_by fields to track which user\n * created and last modified an entity.\n * These fields are automatically managed by BaseRepository when\n * a RepositoryContext with userId is provided.\n */\n\nimport type { BehaviorDefinition } from './types';\n\nexport const userTrackingBehavior: BehaviorDefinition = {\n\tname: 'user_tracking',\n\tdescription: 'Adds created_by and updated_by user reference fields',\n\n\tfields: [\n\t\t{\n\t\t\tname: 'created_by',\n\t\t\tcamelName: 'createdBy',\n\t\t\ttype: 'uuid',\n\t\t\ttsType: 'string | null',\n\t\t\tdrizzleType: 'uuid',\n\t\t\tdrizzleImports: ['uuid'],\n\t\t\tzodType: 'z.string().uuid().nullable()',\n\t\t\tnullable: true,\n\t\t\tforeignKey: 'users.id',\n\t\t\tui: {\n\t\t\t\tlabel: 'Created By',\n\t\t\t\ttype: 'reference',\n\t\t\t\timportance: 'tertiary',\n\t\t\t\tgroup: 'metadata',\n\t\t\t\tvisible: false,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: 'updated_by',\n\t\t\tcamelName: 'updatedBy',\n\t\t\ttype: 'uuid',\n\t\t\ttsType: 'string | null',\n\t\t\tdrizzleType: 'uuid',\n\t\t\tdrizzleImports: ['uuid'],\n\t\t\tzodType: 'z.string().uuid().nullable()',\n\t\t\tnullable: true,\n\t\t\tforeignKey: 'users.id',\n\t\t\tui: {\n\t\t\t\tlabel: 'Updated By',\n\t\t\t\ttype: 'reference',\n\t\t\t\timportance: 'tertiary',\n\t\t\t\tgroup: 'metadata',\n\t\t\t\tvisible: false,\n\t\t\t},\n\t\t},\n\t],\n\n\tdrizzleImports: ['uuid'],\n\n\tmethods: ['applyUserTrackingOnCreate', 'applyUserTrackingOnUpdate'],\n\n\tconfigKey: 'userTracking',\n};\n","/**\n * Behavior Registry - Central registry for all entity behaviors\n *\n * Provides functions to:\n * - Get behavior definitions by name\n * - Validate behavior configurations\n * - Resolve fields added by behaviors\n */\n\nimport { externalIdTrackingBehavior } from './external-id-tracking';\nimport { softDeleteBehavior } from './soft-delete';\nimport { timestampsBehavior } from './timestamps';\nimport type {\n\tBehaviorConfig,\n\tBehaviorDefinition,\n\tBehaviorField,\n\tNormalizedBehaviorConfig,\n\tResolvedBehaviors,\n\tValidationResult,\n} from './types';\nimport { userTrackingBehavior } from './user-tracking';\n\n// ============================================================================\n// Behavior Registry\n// ============================================================================\n\nconst behaviorRegistry = new Map<string, BehaviorDefinition>([\n\t['timestamps', timestampsBehavior],\n\t['soft_delete', softDeleteBehavior],\n\t['user_tracking', userTrackingBehavior],\n\t['external_id_tracking', externalIdTrackingBehavior],\n]);\n\n/**\n * Get a behavior definition by name\n */\nexport function getBehavior(name: string): BehaviorDefinition | undefined {\n\treturn behaviorRegistry.get(name);\n}\n\n/**\n * Get all registered behavior names\n */\nexport function getAllBehaviorNames(): string[] {\n\treturn Array.from(behaviorRegistry.keys());\n}\n\n// ============================================================================\n// Config Normalization\n// ============================================================================\n\n/**\n * Normalize a behavior config to always have name and options\n */\nexport function normalizeBehaviorConfig(\n\tconfig: BehaviorConfig,\n): NormalizedBehaviorConfig {\n\tif (typeof config === 'string') {\n\t\treturn { name: config, options: {} };\n\t}\n\treturn { name: config.name, options: config.options ?? {} };\n}\n\n/**\n * Normalize an array of behavior configs\n */\nexport function normalizeBehaviorConfigs(\n\tconfigs: BehaviorConfig[],\n): NormalizedBehaviorConfig[] {\n\treturn configs.map(normalizeBehaviorConfig);\n}\n\n// ============================================================================\n// Validation\n// ============================================================================\n\n/**\n * Validate a set of behavior configurations\n * Checks for unknown behaviors, missing dependencies, and conflicts\n */\nexport function validateBehaviors(configs: BehaviorConfig[]): ValidationResult {\n\tconst errors: string[] = [];\n\tconst warnings: string[] = [];\n\tconst normalized = normalizeBehaviorConfigs(configs);\n\tconst enabledNames = new Set(normalized.map((c) => c.name));\n\n\tfor (const config of normalized) {\n\t\tconst behavior = getBehavior(config.name);\n\n\t\t// Check behavior exists\n\t\tif (!behavior) {\n\t\t\terrors.push(`Unknown behavior: '${config.name}'`);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Check dependencies\n\t\tif (behavior.requires) {\n\t\t\tfor (const req of behavior.requires) {\n\t\t\t\tif (!enabledNames.has(req)) {\n\t\t\t\t\terrors.push(\n\t\t\t\t\t\t`Behavior '${config.name}' requires '${req}' which is not enabled`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Check conflicts\n\t\tif (behavior.conflicts) {\n\t\t\tfor (const conflict of behavior.conflicts) {\n\t\t\t\tif (enabledNames.has(conflict)) {\n\t\t\t\t\terrors.push(\n\t\t\t\t\t\t`Behavior '${config.name}' conflicts with '${conflict}'`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\tvalid: errors.length === 0,\n\t\terrors,\n\t\twarnings,\n\t};\n}\n\n// ============================================================================\n// Field Resolution\n// ============================================================================\n\n/**\n * Get all fields added by a set of behaviors\n */\nexport function resolveBehaviorFields(\n\tconfigs: BehaviorConfig[],\n): BehaviorField[] {\n\tconst normalized = normalizeBehaviorConfigs(configs);\n\tconst fields: BehaviorField[] = [];\n\tconst addedFieldNames = new Set<string>();\n\n\tfor (const config of normalized) {\n\t\tconst behavior = getBehavior(config.name);\n\t\tif (!behavior) continue;\n\n\t\tfor (const field of behavior.fields) {\n\t\t\t// Avoid duplicate fields if multiple behaviors add the same field\n\t\t\tif (!addedFieldNames.has(field.name)) {\n\t\t\t\tfields.push(field);\n\t\t\t\taddedFieldNames.add(field.name);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn fields;\n}\n\n/**\n * Get all Drizzle imports needed by a set of behaviors\n */\nexport function resolveBehaviorDrizzleImports(\n\tconfigs: BehaviorConfig[],\n): string[] {\n\tconst normalized = normalizeBehaviorConfigs(configs);\n\tconst imports = new Set<string>();\n\n\tfor (const config of normalized) {\n\t\tconst behavior = getBehavior(config.name);\n\t\tif (!behavior) continue;\n\n\t\tfor (const imp of behavior.drizzleImports) {\n\t\t\timports.add(imp);\n\t\t}\n\t}\n\n\treturn Array.from(imports).sort();\n}\n\n// ============================================================================\n// Full Resolution\n// ============================================================================\n\n/**\n * Resolve all behavior data for templates\n */\nexport function resolveBehaviors(configs: BehaviorConfig[]): ResolvedBehaviors {\n\tconst normalized = normalizeBehaviorConfigs(configs);\n\tconst fields = resolveBehaviorFields(configs);\n\tconst drizzleImports = resolveBehaviorDrizzleImports(configs);\n\n\tconst enabledNames = new Set(normalized.map((c) => c.name));\n\n\tconst hasTimestamps = enabledNames.has('timestamps');\n\tconst hasSoftDelete = enabledNames.has('soft_delete');\n\tconst hasUserTracking = enabledNames.has('user_tracking');\n\tconst hasExternalIdTracking = enabledNames.has('external_id_tracking');\n\n\treturn {\n\t\tconfigs: normalized,\n\t\tfields,\n\t\tdrizzleImports,\n\t\trepositoryConfig: {\n\t\t\ttimestamps: hasTimestamps,\n\t\t\tsoftDelete: hasSoftDelete,\n\t\t\tuserTracking: hasUserTracking,\n\t\t\tversionable: false, // Future behavior\n\t\t},\n\t\thasBehaviors: normalized.length > 0,\n\t\thasTimestamps,\n\t\thasSoftDelete,\n\t\thasUserTracking,\n\t\thasExternalIdTracking,\n\t};\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\nexport type {\n\tBehaviorConfig,\n\tBehaviorDefinition,\n\tBehaviorField,\n\tNormalizedBehaviorConfig,\n\tResolvedBehaviors,\n\tValidationResult,\n} from './types';\n\nexport { timestampsBehavior } from './timestamps';\nexport { softDeleteBehavior } from './soft-delete';\nexport { userTrackingBehavior } from './user-tracking';\nexport { externalIdTrackingBehavior } from './external-id-tracking';\n","/**\n * Consistency Checker\n *\n * Performs various consistency checks on the domain model:\n * - Missing relationship targets\n * - Missing inverse relationships\n * - Missing indexes on filterable fields\n * - Orphan entities (no relationships)\n * - Circular dependencies\n * - Naming conventions\n * - Missing UI metadata\n */\n\nimport type { ParsedEntity, DomainGraph, AnalysisIssue } from './types';\nimport { findOrphanEntities, findCircularDependencies } from './graph-builder';\nimport { resolveBehaviorFields } from '../behaviors/index';\n\n/**\n * Run all consistency checks on the domain graph\n */\nexport function checkConsistency(graph: DomainGraph): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\n\t// Check each entity\n\tfor (const [name, entity] of graph.entities) {\n\t\tissues.push(...checkEntityConsistency(entity));\n\t\tissues.push(...checkRelationshipConsistency(entity, graph));\n\t\tissues.push(...checkNamingConventions(entity));\n\t\tissues.push(...checkMissingIndexes(entity));\n\t\tissues.push(...checkUiMetadata(entity));\n\t\tif (entity.queries !== undefined) {\n\t\t\tissues.push(...checkQueryFieldReferences(entity));\n\t\t}\n\t\tif (entity.sync !== undefined) {\n\t\t\tissues.push(...checkSyncFieldMappingReferences(entity));\n\t\t\tissues.push(...checkExternalIdTrackingCollision(entity));\n\t\t}\n\t}\n\n\t// Check graph-level issues\n\tissues.push(...checkOrphanEntities(graph));\n\tissues.push(...checkCircularReferences(graph));\n\tissues.push(...checkMissingInverses(graph));\n\n\treturn issues;\n}\n\n/**\n * Check entity-level consistency\n */\nfunction checkEntityConsistency(entity: ParsedEntity): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\n\t// Check for missing primary key\n\tif (!entity.fields.has('id')) {\n\t\tissues.push({\n\t\t\tseverity: 'info',\n\t\t\ttype: 'missing_id',\n\t\t\tentity: entity.name,\n\t\t\tmessage: 'Entity missing standard \"id\" field',\n\t\t\tsuggestion: 'Add an \"id\" field with type \"uuid\"',\n\t\t});\n\t}\n\n\t// Check for missing timestamps\n\tconst hasCreatedAt = entity.fields.has('created_at');\n\tconst hasTimestampsBehavior = entity.behaviors.includes('timestamps');\n\n\tif (!hasCreatedAt && !hasTimestampsBehavior) {\n\t\tissues.push({\n\t\t\tseverity: 'info',\n\t\t\ttype: 'missing_timestamps',\n\t\t\tentity: entity.name,\n\t\t\tmessage: 'Entity missing \"created_at\" field and \"timestamps\" behavior',\n\t\t\tsuggestion: 'Add \"timestamps\" to behaviors or add created_at/updated_at fields',\n\t\t});\n\t}\n\n\treturn issues;\n}\n\n/**\n * Check relationship consistency\n */\nfunction checkRelationshipConsistency(\n\tentity: ParsedEntity,\n\tgraph: DomainGraph\n): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\n\tfor (const [relName, rel] of entity.relationships) {\n\t\t// Check for belongs_to without matching foreign key field\n\t\tif (rel.type === 'belongs_to') {\n\t\t\tconst fkField = entity.fields.get(rel.foreignKey);\n\t\t\tif (!fkField) {\n\t\t\t\tissues.push({\n\t\t\t\t\tseverity: 'warning',\n\t\t\t\t\ttype: 'missing_fk_field',\n\t\t\t\t\tentity: entity.name,\n\t\t\t\t\tfield: relName,\n\t\t\t\t\tmessage: `Relationship \"${relName}\" references foreign key \"${rel.foreignKey}\" but field doesn't exist`,\n\t\t\t\t\tsuggestion: `Add field \"${rel.foreignKey}\" with foreign_key reference`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Check for has_many relationships - target should have the FK field\n\t\tif (rel.type === 'has_many' || rel.type === 'has_one') {\n\t\t\tconst targetEntity = graph.entities.get(rel.target);\n\t\t\tif (targetEntity) {\n\t\t\t\tconst targetFkField = targetEntity.fields.get(rel.foreignKey);\n\t\t\t\tif (!targetFkField) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tseverity: 'warning',\n\t\t\t\t\t\ttype: 'missing_target_fk',\n\t\t\t\t\t\tentity: entity.name,\n\t\t\t\t\t\tfield: relName,\n\t\t\t\t\t\tmessage: `Relationship \"${relName}\" expects foreign key \"${rel.foreignKey}\" on \"${rel.target}\" but field doesn't exist`,\n\t\t\t\t\t\tsuggestion: `Add field \"${rel.foreignKey}\" to \"${rel.target}\" entity`,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn issues;\n}\n\n/**\n * Check naming conventions\n */\nfunction checkNamingConventions(entity: ParsedEntity): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\n\t// Entity name should be lowercase snake_case\n\tif (entity.name !== entity.name.toLowerCase()) {\n\t\tissues.push({\n\t\t\tseverity: 'warning',\n\t\t\ttype: 'naming_convention',\n\t\t\tentity: entity.name,\n\t\t\tmessage: 'Entity name should be lowercase',\n\t\t\tsuggestion: `Use \"${entity.name.toLowerCase()}\"`,\n\t\t});\n\t}\n\n\t// Check field naming\n\tfor (const [fieldName] of entity.fields) {\n\t\tif (fieldName !== fieldName.toLowerCase()) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'warning',\n\t\t\t\ttype: 'naming_convention',\n\t\t\t\tentity: entity.name,\n\t\t\t\tfield: fieldName,\n\t\t\t\tmessage: 'Field name should be snake_case',\n\t\t\t\tsuggestion: `Use \"${toSnakeCase(fieldName)}\"`,\n\t\t\t});\n\t\t}\n\t}\n\n\t// Check relationship naming\n\tfor (const [relName] of entity.relationships) {\n\t\tif (relName !== relName.toLowerCase()) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'warning',\n\t\t\t\ttype: 'naming_convention',\n\t\t\t\tentity: entity.name,\n\t\t\t\tfield: relName,\n\t\t\t\tmessage: 'Relationship name should be snake_case',\n\t\t\t\tsuggestion: `Use \"${toSnakeCase(relName)}\"`,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn issues;\n}\n\n/**\n * Check for missing indexes on filterable fields\n */\nfunction checkMissingIndexes(entity: ParsedEntity): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\n\tfor (const [fieldName, field] of entity.fields) {\n\t\t// Check if field is marked as filterable but has no index\n\t\tif (field.ui.filterable && !field.index && !field.unique) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'warning',\n\t\t\t\ttype: 'missing_index',\n\t\t\t\tentity: entity.name,\n\t\t\t\tfield: fieldName,\n\t\t\t\tmessage: `Field \"${fieldName}\" is filterable but has no index`,\n\t\t\t\tsuggestion: 'Add \"index: true\" to improve query performance',\n\t\t\t});\n\t\t}\n\n\t\t// Foreign key fields should typically have an index\n\t\tif (field.foreignKey && !field.index && !field.unique) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'info',\n\t\t\t\ttype: 'missing_fk_index',\n\t\t\t\tentity: entity.name,\n\t\t\t\tfield: fieldName,\n\t\t\t\tmessage: `Foreign key field \"${fieldName}\" has no index`,\n\t\t\t\tsuggestion: 'Add \"index: true\" for better join performance',\n\t\t\t});\n\t\t}\n\t}\n\n\treturn issues;\n}\n\n/**\n * Check for missing UI metadata\n */\nfunction checkUiMetadata(entity: ParsedEntity): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\n\t// System fields that don't need UI metadata\n\tconst systemFields = new Set(['id', 'created_at', 'updated_at', 'deleted_at', 'tenant_id']);\n\n\tfor (const [fieldName, field] of entity.fields) {\n\t\tif (systemFields.has(fieldName)) continue;\n\n\t\tconst hasAnyUiMeta =\n\t\t\tfield.ui.label !== undefined ||\n\t\t\tfield.ui.type !== undefined ||\n\t\t\tfield.ui.group !== undefined;\n\n\t\tif (!hasAnyUiMeta) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'info',\n\t\t\t\ttype: 'missing_ui_metadata',\n\t\t\t\tentity: entity.name,\n\t\t\t\tfield: fieldName,\n\t\t\t\tmessage: `Field \"${fieldName}\" has no UI metadata`,\n\t\t\t\tsuggestion: 'Add ui_label, ui_type, ui_group for better admin panel display',\n\t\t\t});\n\t\t}\n\t}\n\n\treturn issues;\n}\n\n/**\n * Check for orphan entities\n */\nfunction checkOrphanEntities(graph: DomainGraph): AnalysisIssue[] {\n\tconst orphans = findOrphanEntities(graph);\n\treturn orphans.map((name) => ({\n\t\tseverity: 'info' as const,\n\t\ttype: 'orphan_entity',\n\t\tentity: name,\n\t\tmessage: `Entity \"${name}\" has no relationships to other entities`,\n\t\tsuggestion: 'Consider if this entity should be related to others',\n\t}));\n}\n\n/**\n * Check for circular references\n */\nfunction checkCircularReferences(graph: DomainGraph): AnalysisIssue[] {\n\tconst cycles = findCircularDependencies(graph);\n\treturn cycles.map((cycle) => ({\n\t\tseverity: 'info' as const,\n\t\ttype: 'circular_dependency',\n\t\tentity: cycle[0],\n\t\tmessage: `Circular reference detected: ${cycle.join(' -> ')}`,\n\t\tsuggestion: 'Verify this is intentional (e.g., self-referential hierarchy)',\n\t}));\n}\n\n/**\n * Check for missing inverse relationships\n */\nfunction checkMissingInverses(graph: DomainGraph): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\n\tfor (const edge of graph.edges) {\n\t\tconst { from, to, relationship } = edge;\n\t\tconst targetEntity = graph.entities.get(to);\n\t\tif (!targetEntity) continue;\n\n\t\t// Check if target has an inverse relationship back to source\n\t\tconst hasInverse = Array.from(targetEntity.relationships.values()).some(\n\t\t\t(rel) => rel.target === from\n\t\t);\n\n\t\t// belongs_to relationships typically don't need explicit inverses\n\t\t// (the has_many on the other side serves as the inverse)\n\t\tif (!hasInverse && relationship.type !== 'belongs_to') {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'info',\n\t\t\t\ttype: 'missing_inverse',\n\t\t\t\tentity: from,\n\t\t\t\tfield: relationship.name,\n\t\t\t\tmessage: `Relationship \"${relationship.name}\" to \"${to}\" has no inverse defined on target`,\n\t\t\t\tsuggestion: `Add inverse relationship on \"${to}\" pointing back to \"${from}\"`,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn issues;\n}\n\n/**\n * Get the set of all valid field names for an entity, including behavior-added fields\n * and belongs_to foreign key fields (which the template emits as columns even when\n * not explicitly declared under `fields:`).\n */\nfunction getAvailableFieldNames(entity: ParsedEntity): string[] {\n\tconst entityFieldNames = Array.from(entity.fields.keys());\n\tconst behaviorFields = resolveBehaviorFields(entity.behaviors);\n\tconst behaviorFieldNames = behaviorFields.map((f) => f.name);\n\tconst belongsToFkNames: string[] = [];\n\tfor (const rel of entity.relationships.values()) {\n\t\tif (rel.type === 'belongs_to' && rel.foreignKey) {\n\t\t\tbelongsToFkNames.push(rel.foreignKey);\n\t\t}\n\t}\n\treturn [...new Set([...entityFieldNames, ...behaviorFieldNames, ...belongsToFkNames])];\n}\n\n/**\n * Check that query.by and query.select fields reference existing entity fields\n */\nfunction checkQueryFieldReferences(entity: ParsedEntity): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\tconst availableFields = getAvailableFieldNames(entity);\n\tconst availableSet = new Set(availableFields);\n\n\tfor (const query of entity.queries ?? []) {\n\t\t// Skip by-field validation when via is specified — those fields come from the junction table\n\t\tif (!query.via) {\n\t\t\tfor (const fieldName of query.by) {\n\t\t\t\tif (!availableSet.has(fieldName)) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tseverity: 'error',\n\t\t\t\t\t\ttype: 'unknown_query_field',\n\t\t\t\t\t\tentity: entity.name,\n\t\t\t\t\t\tfield: fieldName,\n\t\t\t\t\t\tmessage: `Query references unknown field \"${fieldName}\" in entity \"${entity.name}\". Available fields: ${availableFields.join(', ')}`,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (const fieldName of query.select ?? []) {\n\t\t\tif (!availableSet.has(fieldName)) {\n\t\t\t\tissues.push({\n\t\t\t\t\tseverity: 'error',\n\t\t\t\t\ttype: 'unknown_query_field',\n\t\t\t\t\tentity: entity.name,\n\t\t\t\t\tfield: fieldName,\n\t\t\t\t\tmessage: `Query references unknown field \"${fieldName}\" in entity \"${entity.name}\". Available fields: ${availableFields.join(', ')}`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn issues;\n}\n\n/**\n * Check that sync field_mapping keys and read_only_fields reference existing entity fields\n */\nfunction checkSyncFieldMappingReferences(entity: ParsedEntity): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\tconst availableFields = getAvailableFieldNames(entity);\n\tconst availableSet = new Set(availableFields);\n\n\tfor (const [providerName, provider] of Object.entries(entity.sync?.providers ?? {})) {\n\t\tfor (const fieldName of Object.keys(provider.fieldMapping ?? {})) {\n\t\t\tif (!availableSet.has(fieldName)) {\n\t\t\t\tissues.push({\n\t\t\t\t\tseverity: 'warning',\n\t\t\t\t\ttype: 'unknown_sync_field_mapping',\n\t\t\t\t\tentity: entity.name,\n\t\t\t\t\tfield: fieldName,\n\t\t\t\t\tmessage: `Sync field mapping references unknown field \"${fieldName}\" for provider \"${providerName}\" in entity \"${entity.name}\"`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tfor (const fieldName of provider.readOnlyFields ?? []) {\n\t\t\tif (!availableSet.has(fieldName)) {\n\t\t\t\tissues.push({\n\t\t\t\t\tseverity: 'warning',\n\t\t\t\t\ttype: 'unknown_sync_field_mapping',\n\t\t\t\t\tentity: entity.name,\n\t\t\t\t\tfield: fieldName,\n\t\t\t\t\tmessage: `Sync field mapping references unknown field \"${fieldName}\" for provider \"${providerName}\" in entity \"${entity.name}\"`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn issues;\n}\n\n/**\n * Check for potential collision between external_id_tracking behavior and sync field_mapping\n */\nfunction checkExternalIdTrackingCollision(entity: ParsedEntity): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\n\tconst hasExternalIdTracking = entity.behaviors.includes('external_id_tracking');\n\tif (!hasExternalIdTracking) return issues;\n\n\tfor (const [providerName, provider] of Object.entries(entity.sync?.providers ?? {})) {\n\t\tif (provider.fieldMapping && 'external_id' in provider.fieldMapping) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'warning',\n\t\t\t\ttype: 'external_id_tracking_collision',\n\t\t\t\tentity: entity.name,\n\t\t\t\tfield: 'external_id',\n\t\t\t\tmessage: `Entity \"${entity.name}\" has external_id_tracking behavior and also maps \"external_id\" in sync field_mapping for provider \"${providerName}\". The behavior-added field may collide with the mapped field.`,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn issues;\n}\n\n/**\n * Convert string to snake_case\n */\nfunction toSnakeCase(str: string): string {\n\treturn str\n\t\t.replace(/([A-Z])/g, '_$1')\n\t\t.toLowerCase()\n\t\t.replace(/^_/, '');\n}\n","/**\n * Statistics\n *\n * Computes statistics about the domain model:\n * - Entity counts\n * - Field counts and type distribution\n * - Relationship counts and type distribution\n */\n\nimport type { ParsedEntity, DomainGraph, DomainStatistics } from './types';\n\n/**\n * Compute domain statistics from the graph\n */\nexport function computeStatistics(graph: DomainGraph): DomainStatistics {\n\tconst entities = Array.from(graph.entities.values());\n\n\tconst fieldsByType: Record<string, number> = {};\n\tconst relationshipsByType: Record<string, number> = {};\n\tlet totalFields = 0;\n\tlet totalRelationships = 0;\n\tlet entitiesWithBehaviors = 0;\n\n\tfor (const entity of entities) {\n\t\ttotalFields += entity.fields.size;\n\t\ttotalRelationships += entity.relationships.size;\n\n\t\tif (entity.behaviors.length > 0) {\n\t\t\tentitiesWithBehaviors++;\n\t\t}\n\n\t\t// Count fields by type\n\t\tfor (const field of entity.fields.values()) {\n\t\t\tfieldsByType[field.type] = (fieldsByType[field.type] ?? 0) + 1;\n\t\t}\n\n\t\t// Count relationships by type\n\t\tfor (const rel of entity.relationships.values()) {\n\t\t\trelationshipsByType[rel.type] = (relationshipsByType[rel.type] ?? 0) + 1;\n\t\t}\n\t}\n\n\treturn {\n\t\ttotalEntities: entities.length,\n\t\ttotalFields,\n\t\ttotalRelationships,\n\t\tfieldsByType,\n\t\trelationshipsByType,\n\t\tentitiesWithBehaviors,\n\t\taverageFieldsPerEntity: entities.length > 0 ? totalFields / entities.length : 0,\n\t};\n}\n\n/**\n * Get a breakdown of field properties\n */\nexport function getFieldBreakdown(graph: DomainGraph): {\n\trequired: number;\n\tnullable: number;\n\tindexed: number;\n\tunique: number;\n\twithForeignKey: number;\n\twithConstraints: number;\n} {\n\tlet required = 0;\n\tlet nullable = 0;\n\tlet indexed = 0;\n\tlet unique = 0;\n\tlet withForeignKey = 0;\n\tlet withConstraints = 0;\n\n\tfor (const entity of graph.entities.values()) {\n\t\tfor (const field of entity.fields.values()) {\n\t\t\tif (field.required) required++;\n\t\t\tif (field.nullable) nullable++;\n\t\t\tif (field.index) indexed++;\n\t\t\tif (field.unique) unique++;\n\t\t\tif (field.foreignKey) withForeignKey++;\n\n\t\t\tconst hasConstraints =\n\t\t\t\tfield.constraints.minLength !== undefined ||\n\t\t\t\tfield.constraints.maxLength !== undefined ||\n\t\t\t\tfield.constraints.min !== undefined ||\n\t\t\t\tfield.constraints.max !== undefined;\n\t\t\tif (hasConstraints) withConstraints++;\n\t\t}\n\t}\n\n\treturn { required, nullable, indexed, unique, withForeignKey, withConstraints };\n}\n\n/**\n * Get UI metadata coverage statistics\n */\nexport function getUiMetadataCoverage(graph: DomainGraph): {\n\twithLabel: number;\n\twithType: number;\n\twithGroup: number;\n\twithImportance: number;\n\ttotal: number;\n} {\n\tlet withLabel = 0;\n\tlet withType = 0;\n\tlet withGroup = 0;\n\tlet withImportance = 0;\n\tlet total = 0;\n\n\tfor (const entity of graph.entities.values()) {\n\t\tfor (const field of entity.fields.values()) {\n\t\t\ttotal++;\n\t\t\tif (field.ui.label) withLabel++;\n\t\t\tif (field.ui.type) withType++;\n\t\t\tif (field.ui.group) withGroup++;\n\t\t\tif (field.ui.importance) withImportance++;\n\t\t}\n\t}\n\n\treturn { withLabel, withType, withGroup, withImportance, total };\n}\n","/**\n * Pattern Registry — library + app pattern storage and discovery.\n *\n * Three stores keyed by pattern name:\n * - `LIBRARY_PATTERNS` — seeded by the codegen package itself when the\n * `src/patterns/library/*` barrel imports execute. Consumers never\n * list these in `codegen.config.yaml patterns:`. Domain only.\n * - `APP_PATTERNS` — populated by `loadAppPatterns()` from a\n * consumer-supplied glob set (default `src/patterns/*.pattern.ts`).\n * Domain only.\n * - `ORCHESTRATION_APP_PATTERNS` — populated by the same loader,\n * routed by `kind: 'orchestration'` (ADR-032). No library\n * orchestration patterns ship in Phase 3-1.\n *\n * `getPattern()` checks app patterns first so a consumer could, in\n * principle, shadow a library pattern by using the same `name`. That's\n * not a documented feature, but nothing in the API prevents it.\n *\n * The Hygen subprocess (`src/cli/shared/hygen.ts:64`) reloads this module\n * independently — it has no shared memory with the CLI process. Both\n * loads are deterministic, side-effect-free reads of the same files, so\n * the registry contents are identical across processes. The registry\n * test suite asserts this determinism explicitly.\n *\n * See `docs/adrs/ADR-031-app-defined-patterns.md` §\"Decision 5\" and\n * `docs/specs/app-defined-patterns-implementation.md` §3.\n */\n\nimport { glob } from 'glob';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport {\n\tisOrchestrationPattern,\n\tisPatternDefinition,\n\ttype AnyPatternDefinition,\n\ttype OrchestrationPatternDefinition,\n\ttype PatternDefinition,\n} from './pattern-definition.js';\n\n// ============================================================================\n// Stores\n// ============================================================================\n\nconst LIBRARY_PATTERNS: Map<string, PatternDefinition> = new Map();\nconst APP_PATTERNS: Map<string, PatternDefinition> = new Map();\n\n/**\n * Orchestration patterns (ADR-032). Library never ships orchestration\n * patterns in Phase 3-1 — only the app-pattern map exists for this kind.\n * If a library-shipped orchestration pattern ever lands, add a parallel\n * `LIBRARY_ORCHESTRATION_PATTERNS` map; for now keep storage minimal.\n */\nconst ORCHESTRATION_APP_PATTERNS: Map<string, OrchestrationPatternDefinition> =\n\tnew Map();\n\n/**\n * Every pattern must contribute *something* — either at least one column\n * or at least one of the two class references. A pattern that contributes\n * nothing would generate no useful output and almost certainly indicates\n * a typo or an unfinished definition.\n */\nfunction assertHasContribution(def: PatternDefinition): void {\n\tconst hasColumns = Array.isArray(def.columns) && def.columns.length > 0;\n\tconst hasRepo =\n\t\ttypeof def.repositoryClass === 'string' && def.repositoryClass.length > 0;\n\tconst hasService =\n\t\ttypeof def.serviceClass === 'string' && def.serviceClass.length > 0;\n\n\tif (!hasColumns && !hasRepo && !hasService) {\n\t\tthrow new Error(\n\t\t\t`Pattern '${def.name}' contributes nothing — at least one of ` +\n\t\t\t\t'`columns`, `repositoryClass`, or `serviceClass` is required.',\n\t\t);\n\t}\n}\n\n/**\n * Orchestration counterpart to `assertHasContribution`. An orchestration\n * pattern's minimum contribution is one registry with at least one entry —\n * a registry with zero entries would emit a token + module that nothing\n * resolves to, almost certainly a typo. Detailed entry validation\n * (duplicate keys, malformed entries, co-keyed mismatches) lives in the\n * project-level validator so loader behaviour stays symmetrical with the\n * domain side: load is non-throwing for content-level issues, validator\n * is the single authoritative reporter.\n */\nfunction assertOrchestrationContribution(\n\tdef: OrchestrationPatternDefinition,\n): void {\n\tif (!def.registry || typeof def.registry !== 'object') {\n\t\tthrow new Error(\n\t\t\t`Orchestration pattern '${def.name}' is missing a 'registry' field.`,\n\t\t);\n\t}\n\tif (\n\t\ttypeof def.registry.keyType !== 'string' ||\n\t\tdef.registry.keyType.length === 0\n\t) {\n\t\tthrow new Error(\n\t\t\t`Orchestration pattern '${def.name}' registry.keyType must be a non-empty string.`,\n\t\t);\n\t}\n\tif (\n\t\ttypeof def.registry.valueType !== 'string' ||\n\t\tdef.registry.valueType.length === 0\n\t) {\n\t\tthrow new Error(\n\t\t\t`Orchestration pattern '${def.name}' registry.valueType must be a non-empty string.`,\n\t\t);\n\t}\n\tif (\n\t\t!Array.isArray(def.registry.entries) ||\n\t\tdef.registry.entries.length === 0\n\t) {\n\t\tthrow new Error(\n\t\t\t`Orchestration pattern '${def.name}' registry.entries must contain at least one entry.`,\n\t\t);\n\t}\n}\n\n// ============================================================================\n// Library pattern registration\n// ============================================================================\n\n/**\n * Insert a library pattern into the registry. Called once by each\n * `src/patterns/library/*.pattern.ts` file via the barrel. Re-registering\n * the same name overwrites the previous value silently; this is\n * intentional for hot-reload scenarios but should not happen in normal\n * use.\n */\nexport function registerLibraryPattern(def: PatternDefinition): void {\n\tassertHasContribution(def);\n\tLIBRARY_PATTERNS.set(def.name, def);\n}\n\n// ============================================================================\n// Lookup\n// ============================================================================\n\n/**\n * Resolve a **domain** pattern by name. App patterns shadow library\n * patterns with the same name — useful in principle but not a documented\n * feature.\n *\n * Orchestration patterns live in a disjoint store; use\n * `getOrchestrationPattern()` to look those up. The two surfaces are\n * intentionally separate (ADR-032 Decision 8) so callers don't have to\n * narrow the result on every callsite.\n */\nexport function getPattern(name: string): PatternDefinition | undefined {\n\treturn APP_PATTERNS.get(name) ?? LIBRARY_PATTERNS.get(name);\n}\n\n/**\n * Return every registered domain pattern name (library + app), sorted for\n * deterministic output. The two-process determinism test relies on this\n * ordering being stable across processes. Orchestration names are NOT\n * included — see `getOrchestrationPatternNames()`.\n */\nexport function getAllPatternNames(): string[] {\n\tconst set = new Set<string>([\n\t\t...LIBRARY_PATTERNS.keys(),\n\t\t...APP_PATTERNS.keys(),\n\t]);\n\treturn [...set].sort();\n}\n\n/** Library-only view — mainly for debugging and tests. */\nexport function getLibraryPatternNames(): string[] {\n\treturn [...LIBRARY_PATTERNS.keys()].sort();\n}\n\n/** App-only view — mainly for debugging and tests. */\nexport function getAppPatternNames(): string[] {\n\treturn [...APP_PATTERNS.keys()].sort();\n}\n\n// ============================================================================\n// Orchestration accessors (ADR-032)\n// ============================================================================\n\n/** Resolve an orchestration pattern by name. */\nexport function getOrchestrationPattern(\n\tname: string,\n): OrchestrationPatternDefinition | undefined {\n\treturn ORCHESTRATION_APP_PATTERNS.get(name);\n}\n\n/** Sorted list of orchestration pattern names. */\nexport function getOrchestrationPatternNames(): string[] {\n\treturn [...ORCHESTRATION_APP_PATTERNS.keys()].sort();\n}\n\n/**\n * Every registered orchestration pattern, sorted by name. The\n * project-level validator iterates this list in one place so issue\n * ordering is stable across processes.\n */\nexport function getAllOrchestrationPatterns(): OrchestrationPatternDefinition[] {\n\treturn getOrchestrationPatternNames().map(\n\t\t(n) => ORCHESTRATION_APP_PATTERNS.get(n)!,\n\t);\n}\n\n// ============================================================================\n// App pattern discovery\n// ============================================================================\n\nexport interface LoadAppPatternsResult {\n\t/** Pattern names that were successfully registered, sorted */\n\tloaded: string[];\n\t/** One human-readable error per failed file import */\n\terrors: string[];\n}\n\n/**\n * Expand every glob in `manifestPaths` relative to `cwd`, dynamic-import\n * each matching file, and register every exported value that passes\n * `isPatternDefinition()`. Exports whose name ends in `Pattern` and\n * pass the shape check are registered; other exports are ignored so\n * that files can export helper values alongside their pattern.\n *\n * Import failures are non-fatal — the error is collected and returned\n * so the CLI can surface it without breaking generation of unrelated\n * entities. A pattern that fails the \"at-least-one-contribution\" check\n * surfaces here as an error too.\n *\n * Idempotent: calling twice with the same arguments leaves `APP_PATTERNS`\n * in the same state as calling once.\n */\nexport async function loadAppPatterns(\n\tmanifestPaths: string[],\n\tcwd: string,\n): Promise<LoadAppPatternsResult> {\n\tconst loaded = new Set<string>();\n\tconst errors: string[] = [];\n\n\t// Collect + dedupe absolute file paths across every glob pattern so\n\t// a file matched by two globs is imported once.\n\tconst files = new Set<string>();\n\tfor (const raw of manifestPaths) {\n\t\ttry {\n\t\t\tconst expanded = await glob(raw, { cwd, absolute: true, nodir: true });\n\t\t\tfor (const filePath of expanded) {\n\t\t\t\tfiles.add(filePath);\n\t\t\t}\n\t\t} catch (err) {\n\t\t\terrors.push(\n\t\t\t\t`Failed to expand pattern glob '${raw}': ${stringifyError(err)}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// Sort so dynamic-import order is deterministic across processes —\n\t// the Hygen subprocess relies on this to produce the same registry\n\t// as the CLI.\n\tconst sortedFiles = [...files].sort();\n\n\tfor (const filePath of sortedFiles) {\n\t\ttry {\n\t\t\t// `pathToFileURL` is required for absolute-path dynamic imports on\n\t\t\t// Windows and makes the behavior identical on macOS/Linux.\n\t\t\tconst mod = (await import(pathToFileURL(filePath).href)) as Record<\n\t\t\t\tstring,\n\t\t\t\tunknown\n\t\t\t>;\n\t\t\tfor (const [key, val] of Object.entries(mod)) {\n\t\t\t\tif (!key.endsWith('Pattern')) continue;\n\t\t\t\tif (!isPatternDefinition(val)) continue;\n\n\t\t\t\t// Route on `kind`. Domain (default) and orchestration land in\n\t\t\t\t// disjoint maps; same-name collisions within either map are\n\t\t\t\t// load-time errors (silent overwrite was wrong by CLAUDE.md\n\t\t\t\t// \"architectural correctness\" — see ADR-032 §Composition rules\n\t\t\t\t// row 1).\n\t\t\t\tif (isOrchestrationPattern(val as unknown as AnyPatternDefinition)) {\n\t\t\t\t\tconst orch = val as unknown as OrchestrationPatternDefinition;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tassertOrchestrationContribution(orch);\n\t\t\t\t\t} catch (assertErr) {\n\t\t\t\t\t\terrors.push(\n\t\t\t\t\t\t\t`Orchestration pattern '${orch.name}' in ${relPath(filePath, cwd)} is invalid: ${stringifyError(assertErr)}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tconst existingOrch = ORCHESTRATION_APP_PATTERNS.get(orch.name);\n\t\t\t\t\tif (existingOrch && existingOrch !== orch) {\n\t\t\t\t\t\terrors.push(\n\t\t\t\t\t\t\t`Orchestration pattern '${orch.name}' in ${relPath(filePath, cwd)} duplicates a previously loaded orchestration pattern. Pattern names must be unique.`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tORCHESTRATION_APP_PATTERNS.set(orch.name, orch);\n\t\t\t\t\tloaded.add(orch.name);\n\t\t\t\t} else {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tassertHasContribution(val);\n\t\t\t\t\t} catch (assertErr) {\n\t\t\t\t\t\terrors.push(\n\t\t\t\t\t\t\t`Pattern '${val.name}' in ${relPath(filePath, cwd)} is invalid: ${stringifyError(assertErr)}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tconst existingDom = APP_PATTERNS.get(val.name);\n\t\t\t\t\tif (existingDom && existingDom !== val) {\n\t\t\t\t\t\terrors.push(\n\t\t\t\t\t\t\t`Pattern '${val.name}' in ${relPath(filePath, cwd)} duplicates a previously loaded app pattern. Pattern names must be unique.`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tAPP_PATTERNS.set(val.name, val);\n\t\t\t\t\tloaded.add(val.name);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (err) {\n\t\t\terrors.push(\n\t\t\t\t`Failed to load pattern file '${relPath(filePath, cwd)}': ${stringifyError(err)}`,\n\t\t\t);\n\t\t}\n\t}\n\n\treturn {\n\t\tloaded: [...loaded].sort(),\n\t\terrors,\n\t};\n}\n\n// ============================================================================\n// Test-only reset\n// ============================================================================\n\n/**\n * Clear every registered app pattern and, optionally, library patterns too.\n *\n * Intended for unit tests that build isolated scenarios on top of a clean\n * registry. Not exported from the barrel — tests import it directly from\n * `./registry.js`.\n */\nexport function _resetRegistryForTests(\n\topts: { includeLibrary?: boolean } = {},\n): void {\n\tAPP_PATTERNS.clear();\n\tORCHESTRATION_APP_PATTERNS.clear();\n\tif (opts.includeLibrary) {\n\t\tLIBRARY_PATTERNS.clear();\n\t}\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction stringifyError(err: unknown): string {\n\tif (err instanceof Error) return err.message;\n\treturn String(err);\n}\n\nfunction relPath(abs: string, cwd: string): string {\n\ttry {\n\t\treturn path.relative(cwd, abs) || abs;\n\t} catch {\n\t\treturn abs;\n\t}\n}\n","/**\n * Pattern Definition — pure metadata record returned by an identity function.\n *\n * `definePattern()` is the registration artifact for both library-shipped and\n * app-defined patterns. It carries only names + import paths for the classes\n * a generated entity should extend — never the class constructors themselves.\n * This keeps the codegen pipeline free of TS class-evaluation cost and avoids\n * `reflect-metadata`, which lets the Hygen subprocess cheaply rebuild the\n * registry (see `src/cli/shared/hygen.ts` — the registry loads twice per\n * `entity new` invocation).\n *\n * Two pattern kinds share this surface:\n * - **domain** (default; ADR-031) — `PatternDefinition`. Contributes\n * repository/service base classes, columns, behaviors to entities that\n * declare `pattern:`/`patterns:` in YAML.\n * - **orchestration** (ADR-032) — `OrchestrationPatternDefinition`. Declares\n * a DI registry + optional dispatcher scaffold. Not entity-attached;\n * codegen emits a NestJS module under `src/orchestration/` instead.\n *\n * See `docs/adrs/ADR-031-app-defined-patterns.md` §\"Decision 1\" for the\n * domain binding surface and `docs/adrs/ADR-032-orchestration-patterns.md`\n * for the orchestration kind.\n */\n\nimport type { ZodSchema } from 'zod';\n\n/**\n * A column a pattern contributes to every entity that declares it.\n *\n * Column-level conflicts between patterns, between a pattern and an\n * entity-declared field, or between a pattern and a behavior-contributed\n * field are codegen-time hard errors; see\n * `src/patterns/validate-composition.ts`.\n */\nexport interface PatternColumnContribution {\n\t/** snake_case column name — matches the database column */\n\tname: string;\n\t/** Drizzle column type string, e.g. \"varchar(255)\" or \"text\" */\n\ttype: string;\n}\n\n/**\n * Discriminator for the two pattern shapes. Default is `\"domain\"` to preserve\n * Phase 1 (ADR-031) behaviour — every existing PatternDefinition without a\n * `kind` field continues to register as a domain pattern.\n */\nexport type PatternKind = 'domain' | 'orchestration';\n\n/**\n * The full pattern metadata record. Every `definePattern({...})` call\n * returns a value of this shape; the library and consumer registries\n * store these and look them up by `name`.\n */\nexport interface PatternDefinition<TConfig = unknown> {\n\t/** Unique name used in YAML — e.g. `pattern: Synced` */\n\tname: string;\n\n\t/**\n\t * ADR-032: defaults to `\"domain\"`. Phase 3 adds `\"orchestration\"` as a\n\t * disjoint shape (see `OrchestrationPatternDefinition`). Domain\n\t * `PatternDefinition` instances must omit this field or set it to\n\t * `\"domain\"`; the loader routes orchestration values to a separate map.\n\t */\n\tkind?: 'domain';\n\n\t/**\n\t * Built-in patterns this extends, by name. Phase 1 supports single-depth\n\t * chains only — a pattern may `extends: ['Synced']` but the transitive\n\t * chain is not yet resolved. Multi-depth inheritance is deferred until\n\t * a real consumer asks.\n\t */\n\textends?: string[];\n\n\t/** Constructor name codegen emits in the generated repo's `extends` clause */\n\trepositoryClass?: string;\n\t/** Constructor name codegen emits in the generated service's `extends` clause */\n\tserviceClass?: string;\n\n\t/**\n\t * Fully-qualified TypeScript path alias the consumer's tsconfig resolves.\n\t * Library patterns use the consumer-installed runtime base class path\n\t * (e.g. `@shared/base-classes/synced-entity-repository`); app patterns\n\t * use whatever alias the consumer has configured (e.g. `@/patterns/...`).\n\t */\n\trepositoryImport?: string;\n\t/** Same as `repositoryImport` but for the service base class */\n\tserviceImport?: string;\n\n\t/**\n\t * Documentation-only method-signature strings emitted as comments in the\n\t * generated repo. Exist purely so app authors reading the generated file\n\t * see what their concrete class inherits without jumping to the base.\n\t */\n\trepositoryInheritedMethods?: string[];\n\t/** Same as `repositoryInheritedMethods` but for the service base class */\n\tserviceInheritedMethods?: string[];\n\n\t/**\n\t * Columns this pattern adds to every entity that declares it. Used by\n\t * the composition validator to detect column-name collisions.\n\t */\n\tcolumns?: PatternColumnContribution[];\n\n\t/**\n\t * Behaviors this pattern implicitly enables. Entity YAML need not\n\t * re-declare them; duplicates across patterns are silent-deduped.\n\t */\n\timpliedBehaviors?: string[];\n\n\t/**\n\t * Zod schema that validates the per-entity `config:` block for this\n\t * pattern at parse time. When absent, entities may not supply a `config:`\n\t * entry for this pattern and codegen emits no `patternConfig` property.\n\t */\n\tconfigSchema?: ZodSchema<TConfig>;\n\n\t/** One-line description for codegen help output and error messages */\n\tdescription?: string;\n}\n\n/**\n * Identity function that returns its argument unchanged. The body is trivial\n * on purpose — the whole point is to give TypeScript a hook for generic\n * inference on `TConfig` while leaving the runtime value a plain object\n * registered by the codegen loader.\n */\nexport function definePattern<TConfig = unknown>(\n\tdef: PatternDefinition<TConfig>,\n): PatternDefinition<TConfig> {\n\treturn def;\n}\n\n/**\n * Shape check for values produced by `import()`ing an app pattern file.\n * The registry loader runs this on every exported value it finds; only\n * values that pass are registered.\n *\n * We keep this deliberately loose — a `name` string is the whole\n * requirement — because a pattern that contributes neither columns nor\n * class references is still a *valid* identity pattern (e.g. `BasePattern`\n * exists to anchor the `extends` chain without contributing anything).\n * Stricter shape rules belong in the registry's \"at-least-one-contribution\"\n * check, not here.\n *\n * This function is intentionally **kind-agnostic** — both\n * `PatternDefinition` (domain) and `OrchestrationPatternDefinition`\n * (orchestration) pass. The discriminator routing happens in the loader\n * via `isOrchestrationPattern()`/`isDomainPattern()`.\n */\nexport function isPatternDefinition(val: unknown): val is PatternDefinition {\n\treturn (\n\t\ttypeof val === 'object' &&\n\t\tval !== null &&\n\t\t'name' in val &&\n\t\ttypeof (val as { name: unknown }).name === 'string'\n\t);\n}\n\n// ============================================================================\n// Orchestration kind (ADR-032)\n// ============================================================================\n\n/**\n * One registry's declarative shape. ADR-032 §\"The Proposal\".\n *\n * Phase 3-1 records this; Phase 3-2 codegen reads it to emit token files,\n * provider blocks, and dispatcher overload signatures. Phase 3-1 validates\n * only what is statically checkable from this record alone — see\n * `validate-orchestration.ts` for the rules and their deferral notes.\n */\nexport interface OrchestrationRegistrySpec {\n\t/**\n\t * Identifier for co-keyed sibling registries (ADR-032 Phase 3-2/3, O-1).\n\t *\n\t * The PRIMARY registry never carries a `name` — its tokens / methods are\n\t * derived from the pattern name alone (`${PATTERN_CONST}_REGISTRY`,\n\t * `select(...)`). Each co-keyed sibling MUST carry an explicit `name`\n\t * which the emitter uppercases for the token suffix and PascalCases for\n\t * the dispatcher method suffix:\n\t *\n\t * `coKeyedRegistries: [{ name: 'auth', valueType: 'IAuthStrategy' ... }]`\n\t * ⇒ `CRM_PORTS_AUTH_REGISTRY` token + `selectAuth(...)` method.\n\t *\n\t * No auto-stripping of \"I\" prefix or \"Strategy/Port/Adapter/Provider\"\n\t * suffixes — authors pick what reads right.\n\t */\n\tname?: string;\n\t/**\n\t * Type alias the consumer's tsconfig resolves (e.g. `\"CrmAdapterDomain\"`).\n\t * Phase 3-1 stores this string verbatim. Resolution that the path actually\n\t * imports a concrete TS enum is deferred to Phase 3-2 emission, where\n\t * codegen will need to read the consumer's source tree.\n\t */\n\tkeyType: string;\n\t/**\n\t * Module specifier the emitter writes into `import type { keyType } from\n\t * '<keyTypeImport>'`. Required at Phase 3-2 emission; the generator emits\n\t * `pattern_missing_import_path` if absent. (ADR-032 Phase 3-2 §3.4 / O-3.)\n\t */\n\tkeyTypeImport?: string;\n\t/** Same shape as `keyType` — the registry's value-type interface ref. */\n\tvalueType: string;\n\t/** Module specifier for `valueType` import. See `keyTypeImport`. */\n\tvalueTypeImport?: string;\n\tentries: ReadonlyArray<{\n\t\t/** Stable string key — must be unique within this registry. */\n\t\tkey: string;\n\t\t/**\n\t\t * Concrete provider class name (NOT a DI token string). Codegen will\n\t\t * import this and use it as the constructor injectable.\n\t\t * Phase 3-1 records it; Phase 3-2 verifies it resolves.\n\t\t */\n\t\tprovider: string;\n\t\t/** Module specifier for `provider` import. See `keyTypeImport`. */\n\t\tproviderImport?: string;\n\t}>;\n}\n\n/**\n * Orchestration pattern — declarative DI registry + optional dispatcher\n * scaffold. ADR-032 §\"The Proposal\" + Decisions 1-8.\n *\n * Disjoint from `PatternDefinition` (domain): no columns, no\n * repository/service base class, no entity-level patternConfig. Composition\n * with domain patterns happens only at the DI layer in the consumer's\n * generated code, not in entity YAML.\n */\nexport interface OrchestrationPatternDefinition {\n\tname: string;\n\tkind: 'orchestration';\n\t/** Primary registry (always present). */\n\tregistry: OrchestrationRegistrySpec;\n\t/**\n\t * Sibling registries that share the primary registry's key space.\n\t * ADR-032 Decision 2 — co-keyed groups are a first-class field.\n\t * Validator enforces matching `keyType` across the group.\n\t */\n\tcoKeyedRegistries?: ReadonlyArray<OrchestrationRegistrySpec>;\n\t/** Optional dispatcher scaffold spec (ADR-032 Decision 4 + 5). */\n\tdispatcher?: {\n\t\t/** Class name to emit (e.g. `\"CrmPortsDispatcher\"`). */\n\t\tclassName: string;\n\t\t/**\n\t\t * Method name the consumer overrides in their subclass to fill the\n\t\t * assembly body (ADR-032 Decision 5).\n\t\t */\n\t\tassemblySlot: string;\n\t};\n\t/** One-line description for help output and error messages. */\n\tdescription?: string;\n}\n\n/** Union for callers that need to handle both shapes. */\nexport type AnyPatternDefinition =\n\t| PatternDefinition\n\t| OrchestrationPatternDefinition;\n\nexport function isOrchestrationPattern(\n\tdef: AnyPatternDefinition,\n): def is OrchestrationPatternDefinition {\n\treturn (def as { kind?: PatternKind }).kind === 'orchestration';\n}\n\nexport function isDomainPattern(\n\tdef: AnyPatternDefinition,\n): def is PatternDefinition {\n\treturn !isOrchestrationPattern(def);\n}\n\n/**\n * Identity function that returns its argument unchanged — orchestration\n * counterpart to `definePattern()`. The body is trivial on purpose; the\n * point is to give TypeScript a hook so consumer fixtures get full\n * compile-time checking against `OrchestrationPatternDefinition`.\n */\nexport function defineOrchestrationPattern(\n\tdef: OrchestrationPatternDefinition,\n): OrchestrationPatternDefinition {\n\treturn def;\n}\n","/**\n * Pattern Composition Validator\n *\n * Enforces the ADR-031 composition rules against parsed entities:\n *\n * | Case | Result |\n * |------------------------------------------------------------|------------------------|\n * | Column conflict between two patterns | error |\n * | Column conflict with entity field | error |\n * | Column conflict with a behavior field | error |\n * | Method-name conflict between patterns | (TS compile error) |\n * | Same implied behavior across patterns | silent dedup |\n * | Pattern referenced in YAML but not in the registry | error |\n * | `config:` key for a pattern the entity is not using | warning |\n * | Pattern config fails its Zod schema | error |\n *\n * Method-name conflicts are explicitly **not** checked here — they surface as\n * TypeScript compile errors at the consumer when the generated concrete\n * class extends the base. Adding a codegen check would duplicate work\n * the type system already does, so we stay silent on that row per ADR-031.\n *\n * Project-level validation (`validatePatternProject`) covers plan Risk 4:\n * entities declaring `pattern:` while `generate.architecture: clean` is\n * selected get a warning since the `clean` pipeline does not yet consume\n * patterns. Additive Phase 3+ work per ADR.\n *\n * The shape mirrors `src/behaviors/index.ts:81–124` (`validateBehaviors`):\n * a single pass that returns structured issues for `analyzeDomain()` to\n * aggregate.\n */\n\nimport type { AnalysisIssue, ParsedEntity } from '../analyzer/types.js';\nimport { resolveBehaviorFields } from '../behaviors/index.js';\nimport { getPattern } from './registry.js';\n\n// ============================================================================\n// Per-entity validation\n// ============================================================================\n\n/**\n * Validate pattern composition for a single entity. Returns an array of\n * `AnalysisIssue` values suitable for concatenation into `analyzeDomain`'s\n * aggregated issue list.\n *\n * Entities with no `pattern:` or `patterns:` declared return an empty\n * array — pattern-free entities are a valid use case (plain `BaseRepository`\n * fallback) and nothing below applies to them.\n */\nexport function validatePatternComposition(\n\tentity: ParsedEntity,\n): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\n\t// Normalise `pattern:` (single) and `patterns:` (multi) into one list,\n\t// preserving declaration order. `pattern` + `patterns` mutual exclusion\n\t// is a schema-level check — by the time we get here, at most one shape\n\t// is set.\n\tconst patternNames: string[] = entity.patterns ?? (entity.pattern ? [entity.pattern] : []);\n\tif (patternNames.length === 0) return issues;\n\n\t// Column-source tracker: maps column name → human-readable origin.\n\t// Populated in priority order (entity fields > behavior fields >\n\t// pattern contributions) so conflict messages name the *existing*\n\t// contributor correctly.\n\tconst columnSources = new Map<string, string>();\n\n\tfor (const [name] of entity.fields) {\n\t\tcolumnSources.set(name, `entity field '${name}'`);\n\t}\n\n\t// Behavior fields participate in conflict detection. Behaviors the\n\t// entity has NOT already declared but that a pattern implies will be\n\t// added below (silent dedup); conflicts against those show up when\n\t// the pattern's columns are checked.\n\tconst behaviorFields = resolveBehaviorFields(entity.behaviors);\n\tfor (const bf of behaviorFields) {\n\t\tconst existing = columnSources.get(bf.name);\n\t\tif (existing) {\n\t\t\t// A behavior field colliding with an entity-declared field\n\t\t\t// was already a codegen problem before patterns existed. We\n\t\t\t// surface it here too so the composition check is the single\n\t\t\t// authoritative pass for \"column conflicts on this entity.\"\n\t\t\tissues.push({\n\t\t\t\tseverity: 'error',\n\t\t\t\ttype: 'pattern_column_conflict',\n\t\t\t\tentity: entity.name,\n\t\t\t\tmessage:\n\t\t\t\t\t`Behavior-contributed field '${bf.name}' conflicts with ${existing}.`,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tcolumnSources.set(bf.name, `behavior field '${bf.name}'`);\n\t}\n\n\t// Track implied behaviors across all declared patterns so we can\n\t// assert silent dedup rather than repeat issues — this also lets us\n\t// return the deduped list for callers that want to thread it into\n\t// template-locals later without re-walking.\n\tconst impliedBehaviors = new Set<string>(entity.behaviors);\n\n\tfor (const patternName of patternNames) {\n\t\tconst def = getPattern(patternName);\n\n\t\t// Rule: pattern referenced in YAML but not in the registry\n\t\tif (!def) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'error',\n\t\t\t\ttype: 'pattern_unknown',\n\t\t\t\tentity: entity.name,\n\t\t\t\tmessage:\n\t\t\t\t\t`Unknown pattern '${patternName}'. ` +\n\t\t\t\t\t`Library patterns are pre-registered; app patterns are loaded from ` +\n\t\t\t\t\t`globs in codegen.config.yaml 'patterns:' (default 'src/patterns/*.pattern.ts').`,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Rule: pattern config must match the pattern's Zod schema\n\t\tif (def.configSchema) {\n\t\t\tconst rawConfig = entity.patternConfig?.[patternName];\n\t\t\tconst result = def.configSchema.safeParse(rawConfig ?? {});\n\t\t\tif (!result.success) {\n\t\t\t\tconst detail = result.error.issues\n\t\t\t\t\t.map((i) => `${i.path.join('.') || '<root>'}: ${i.message}`)\n\t\t\t\t\t.join(', ');\n\t\t\t\tissues.push({\n\t\t\t\t\tseverity: 'error',\n\t\t\t\t\ttype: 'pattern_config_invalid',\n\t\t\t\t\tentity: entity.name,\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t`Pattern '${patternName}' config failed validation: ${detail}`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Rule: column contributions conflict with anything already in the\n\t\t// column-sources table. The first column to claim a name wins; the\n\t\t// second one reports the conflict naming both contributors.\n\t\tfor (const col of def.columns ?? []) {\n\t\t\tconst existing = columnSources.get(col.name);\n\t\t\tif (existing) {\n\t\t\t\tissues.push({\n\t\t\t\t\tseverity: 'error',\n\t\t\t\t\ttype: 'pattern_column_conflict',\n\t\t\t\t\tentity: entity.name,\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t`Pattern '${patternName}' contributes column '${col.name}' ` +\n\t\t\t\t\t\t`which conflicts with ${existing}.`,\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tcolumnSources.set(col.name, `pattern '${patternName}'`);\n\t\t}\n\n\t\t// Silent dedup on implied behaviors — a pattern declaring a\n\t\t// behavior the entity already has (or another pattern already\n\t\t// contributed) is a no-op, not an error.\n\t\tfor (const b of def.impliedBehaviors ?? []) {\n\t\t\timpliedBehaviors.add(b);\n\t\t}\n\t}\n\n\t// Rule: `config:` key for a pattern not in the declared list → warning.\n\tif (entity.patternConfig) {\n\t\tconst declared = new Set(patternNames);\n\t\tfor (const key of Object.keys(entity.patternConfig)) {\n\t\t\tif (!declared.has(key)) {\n\t\t\t\tissues.push({\n\t\t\t\t\tseverity: 'warning',\n\t\t\t\t\ttype: 'pattern_config_unused',\n\t\t\t\t\tentity: entity.name,\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t`Config block has key '${key}' but pattern '${key}' is not ` +\n\t\t\t\t\t\t`declared in 'pattern:' or 'patterns:'. Remove the entry or ` +\n\t\t\t\t\t\t`add the pattern.`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn issues;\n}\n\n// ============================================================================\n// Project-level validation — plan Risk 4\n// ============================================================================\n\nexport interface PatternProjectContext {\n\tentities: ReadonlyArray<ParsedEntity>;\n\t/**\n\t * Selected backend architecture from `codegen.config.yaml\n\t * generate.architecture`. `undefined` when the consumer is using the\n\t * library purely as an analyzer (no generation config loaded).\n\t */\n\tarchitecture?: string;\n}\n\n/**\n * Validate project-level invariants for patterns. Runs after\n * `validatePatternComposition` has visited every entity, so we can\n * assume per-entity errors have been surfaced.\n *\n * Today this only covers plan Risk 4: warn when patterns are declared\n * but the selected architecture is `clean`, which does not yet consume\n * them. A `clean` consumer with `pattern: Synced` is not broken — the\n * `clean` pipeline ignores the key — but they see no effect, which is\n * confusing without the warning.\n */\nexport function validatePatternProject(\n\tctx: PatternProjectContext,\n): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\n\tif (ctx.architecture === 'clean') {\n\t\tconst withPatterns = ctx.entities.filter(\n\t\t\t(e) => (e.patterns && e.patterns.length > 0) || !!e.pattern,\n\t\t);\n\t\tfor (const e of withPatterns) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'warning',\n\t\t\t\ttype: 'pattern_clean_pipeline_noop',\n\t\t\t\tentity: e.name,\n\t\t\t\tmessage:\n\t\t\t\t\t`'pattern:' is declared but 'generate.architecture: clean' does not ` +\n\t\t\t\t\t`yet consume patterns. This declaration is a no-op. Patterns are ` +\n\t\t\t\t\t`consumed by 'clean-lite-ps' today; 'clean' integration is Phase 3+ ` +\n\t\t\t\t\t`additive work (ADR-031).`,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn issues;\n}\n","/**\n * Orchestration Pattern Validator (ADR-032)\n *\n * Project-level only — orchestration patterns are not entity-attached, so\n * there is no per-entity pass. Mirrors `validatePatternProject`'s shape:\n * one pure function consuming a context object and returning structured\n * `AnalysisIssue[]` for `analyzeDomain()` to aggregate.\n *\n * Enforces ADR-032 §\"Composition rules\" to the extent statically checkable\n * from a `OrchestrationPatternDefinition` alone:\n *\n * | Rule | Issue type |\n * |------------------------------------------------------------|-------------------------------------|\n * | Domain ↔ orchestration pattern share a name | pattern_name_collision |\n * | Registry has zero entries | pattern_entries_empty |\n * | Entry missing/non-string `key` or `provider` | pattern_entry_malformed |\n * | Two entries in the same registry share a `key` | pattern_entry_key_duplicate |\n * | Co-keyed registry's `keyType` diverges from the primary | pattern_cokeyed_keytype_mismatch |\n *\n * Two ADR-032 conflicts are NOT enforced here — they need consumer source\n * access that Phase 3-1 cannot do:\n * - `keyType`/`valueType` resolution (row 2): deferred to Phase 3-2 emission.\n * - Provider not exported by any known module (row 3): deferred to Phase 3-2\n * + DI runtime.\n *\n * Orchestration ↔ orchestration name duplicates ARE enforced — but at LOAD\n * time inside `loadAppPatterns()`, not here, because by the time the\n * validator runs the duplicate has already been deduped by `Map.set()`\n * keying on name. The loader emits a `LoadAppPatternsResult.errors` entry.\n */\n\nimport type { AnalysisIssue } from '../analyzer/types.js';\nimport type { OrchestrationPatternDefinition } from './pattern-definition.js';\n\n// Sentinel used for the `entity` field on project-level orchestration\n// issues. The orchestration kind is not entity-attached, so there is no\n// real entity name to point at. Existing console + markdown formatters\n// treat `issue.entity` as an opaque truthy string used only in display\n// (`${issue.entity}${issue.field ? '.' + issue.field : ''}`), so a\n// non-entity sentinel is safe — the formatters never look it up against\n// the parsed entity map.\nconst PROJECT_SENTINEL = '<project>';\n\nexport interface OrchestrationProjectContext {\n\t/** All orchestration patterns currently registered. */\n\torchestrationPatterns: ReadonlyArray<OrchestrationPatternDefinition>;\n\t/** All domain pattern names currently registered (library + app). */\n\tdomainPatternNames: ReadonlyArray<string>;\n}\n\nexport function validateOrchestrationProject(\n\tctx: OrchestrationProjectContext,\n): AnalysisIssue[] {\n\tconst issues: AnalysisIssue[] = [];\n\n\t// Rule 1: orchestration ↔ domain name collision (ADR-032 row 4).\n\tconst domainNameSet = new Set(ctx.domainPatternNames);\n\tfor (const orch of ctx.orchestrationPatterns) {\n\t\tif (domainNameSet.has(orch.name)) {\n\t\t\tissues.push({\n\t\t\t\tseverity: 'error',\n\t\t\t\ttype: 'pattern_name_collision',\n\t\t\t\tentity: PROJECT_SENTINEL,\n\t\t\t\tmessage:\n\t\t\t\t\t`Orchestration pattern '${orch.name}' shares a name with a domain ` +\n\t\t\t\t\t`pattern. Pattern names are globally unique across kinds (ADR-032 §Composition rules).`,\n\t\t\t});\n\t\t}\n\t}\n\n\t// Rules 2-4: per-pattern checks (entries shape + co-keyed keyType).\n\tfor (const orch of ctx.orchestrationPatterns) {\n\t\tconst allRegistries = [\n\t\t\torch.registry,\n\t\t\t...(orch.coKeyedRegistries ?? []),\n\t\t];\n\n\t\tfor (const reg of allRegistries) {\n\t\t\t// Rule 2: entries[] non-empty (defensive — loader already enforced\n\t\t\t// this for the primary registry, but co-keyed sibling registries\n\t\t\t// don't go through `assertOrchestrationContribution` and could be\n\t\t\t// authored as `entries: []`).\n\t\t\tif (!Array.isArray(reg.entries) || reg.entries.length === 0) {\n\t\t\t\tissues.push({\n\t\t\t\t\tseverity: 'error',\n\t\t\t\t\ttype: 'pattern_entries_empty',\n\t\t\t\t\tentity: PROJECT_SENTINEL,\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t`Orchestration pattern '${orch.name}' declares a registry with ` +\n\t\t\t\t\t\t`no entries. Provide at least one { key, provider } pair.`,\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Rules 3a + 3b: per-entry well-formedness + key uniqueness.\n\t\t\tconst seen = new Set<string>();\n\t\t\tfor (const entry of reg.entries) {\n\t\t\t\tif (typeof entry.key !== 'string' || entry.key.length === 0) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tseverity: 'error',\n\t\t\t\t\t\ttype: 'pattern_entry_malformed',\n\t\t\t\t\t\tentity: PROJECT_SENTINEL,\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t`Orchestration pattern '${orch.name}' has an entry with a ` +\n\t\t\t\t\t\t\t`missing or non-string 'key'.`,\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\ttypeof entry.provider !== 'string' ||\n\t\t\t\t\tentry.provider.length === 0\n\t\t\t\t) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tseverity: 'error',\n\t\t\t\t\t\ttype: 'pattern_entry_malformed',\n\t\t\t\t\t\tentity: PROJECT_SENTINEL,\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t`Orchestration pattern '${orch.name}' entry '${entry.key}' has ` +\n\t\t\t\t\t\t\t`a missing or non-string 'provider'.`,\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (seen.has(entry.key)) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tseverity: 'error',\n\t\t\t\t\t\ttype: 'pattern_entry_key_duplicate',\n\t\t\t\t\t\tentity: PROJECT_SENTINEL,\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t`Orchestration pattern '${orch.name}' has duplicate entry key ` +\n\t\t\t\t\t\t\t`'${entry.key}'. Keys must be unique within a registry.`,\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tseen.add(entry.key);\n\t\t\t}\n\t\t}\n\n\t\t// Rule 4: co-keyed registry keyType consistency (ADR-032 Decision 2).\n\t\tif (orch.coKeyedRegistries && orch.coKeyedRegistries.length > 0) {\n\t\t\tconst primaryKeyType = orch.registry.keyType;\n\t\t\tfor (const reg of orch.coKeyedRegistries) {\n\t\t\t\tif (reg.keyType !== primaryKeyType) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tseverity: 'error',\n\t\t\t\t\t\ttype: 'pattern_cokeyed_keytype_mismatch',\n\t\t\t\t\t\tentity: PROJECT_SENTINEL,\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t`Orchestration pattern '${orch.name}' co-keyed registry has ` +\n\t\t\t\t\t\t\t`keyType '${reg.keyType}', expected '${primaryKeyType}'. ` +\n\t\t\t\t\t\t\t`Co-keyed registries must share the primary registry's key space (ADR-032 Decision 2).`,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn issues;\n}\n","/**\n * Console Formatter\n *\n * Pretty terminal output with colors for the domain analysis results.\n */\n\nimport type { AnalysisResult, AnalysisIssue, Severity } from '../analyzer/types';\n\n// ANSI color codes\nconst colors = {\n\treset: '\\x1b[0m',\n\tbold: '\\x1b[1m',\n\tdim: '\\x1b[2m',\n\n\tred: '\\x1b[31m',\n\tgreen: '\\x1b[32m',\n\tyellow: '\\x1b[33m',\n\tblue: '\\x1b[34m',\n\tmagenta: '\\x1b[35m',\n\tcyan: '\\x1b[36m',\n\twhite: '\\x1b[37m',\n\n\tbgRed: '\\x1b[41m',\n\tbgGreen: '\\x1b[42m',\n\tbgYellow: '\\x1b[43m',\n};\n\nfunction color(text: string, ...styles: string[]): string {\n\treturn `${styles.join('')}${text}${colors.reset}`;\n}\n\nfunction severityColor(severity: Severity): string {\n\tswitch (severity) {\n\t\tcase 'error':\n\t\t\treturn colors.red;\n\t\tcase 'warning':\n\t\t\treturn colors.yellow;\n\t\tcase 'info':\n\t\t\treturn colors.cyan;\n\t}\n}\n\nfunction severityIcon(severity: Severity): string {\n\tswitch (severity) {\n\t\tcase 'error':\n\t\t\treturn 'X';\n\t\tcase 'warning':\n\t\t\treturn '!';\n\t\tcase 'info':\n\t\t\treturn 'i';\n\t}\n}\n\n/**\n * Format analysis result for console output\n */\nexport function formatConsole(result: AnalysisResult): string {\n\tconst lines: string[] = [];\n\n\t// Header\n\tlines.push('');\n\tlines.push(color('='.repeat(60), colors.dim));\n\tlines.push(color(' Domain Analysis Report', colors.bold, colors.cyan));\n\tlines.push(color('='.repeat(60), colors.dim));\n\tlines.push('');\n\n\t// Statistics\n\tlines.push(...formatStatistics(result));\n\n\t// Entity summary\n\tlines.push(...formatEntities(result));\n\n\t// Relationships\n\tlines.push(...formatRelationships(result));\n\n\t// Issues\n\tif (result.issues.length > 0) {\n\t\tlines.push(...formatIssues(result.issues));\n\t}\n\n\t// Final status\n\tlines.push('');\n\tlines.push(color('-'.repeat(60), colors.dim));\n\n\tconst errors = result.issues.filter((i) => i.severity === 'error');\n\tconst warnings = result.issues.filter((i) => i.severity === 'warning');\n\tconst infos = result.issues.filter((i) => i.severity === 'info');\n\n\tif (result.isValid) {\n\t\tlines.push(\n\t\t\tcolor(\n\t\t\t\t`[OK] Domain is valid (${warnings.length} warnings, ${infos.length} info)`,\n\t\t\t\tcolors.green\n\t\t\t)\n\t\t);\n\t} else {\n\t\tlines.push(color(`[FAIL] Domain has ${errors.length} errors`, colors.red));\n\t}\n\n\tlines.push(color('-'.repeat(60), colors.dim));\n\tlines.push('');\n\n\treturn lines.join('\\n');\n}\n\nfunction formatStatistics(result: AnalysisResult): string[] {\n\tconst lines: string[] = [];\n\tconst stats = result.statistics;\n\n\tlines.push(color('Statistics:', colors.bold));\n\tlines.push('');\n\tlines.push(` Entities: ${stats.totalEntities}`);\n\tlines.push(\n\t\t` Fields: ${stats.totalFields} (avg ${stats.averageFieldsPerEntity.toFixed(1)}/entity)`\n\t);\n\tlines.push(` Relationships: ${stats.totalRelationships}`);\n\tlines.push(` With behaviors: ${stats.entitiesWithBehaviors}`);\n\tlines.push('');\n\n\t// Field types breakdown\n\tlines.push(' Field types:');\n\tconst sortedTypes = Object.entries(stats.fieldsByType).sort((a, b) => b[1] - a[1]);\n\tfor (const [type, count] of sortedTypes) {\n\t\tconst bar = color('|'.repeat(Math.min(count, 20)), colors.blue);\n\t\tlines.push(` ${type.padEnd(12)} ${bar} ${count}`);\n\t}\n\tlines.push('');\n\n\t// Relationship types breakdown\n\tif (stats.totalRelationships > 0) {\n\t\tlines.push(' Relationship types:');\n\t\tconst sortedRels = Object.entries(stats.relationshipsByType).sort((a, b) => b[1] - a[1]);\n\t\tfor (const [type, count] of sortedRels) {\n\t\t\tconst bar = color('|'.repeat(Math.min(count, 20)), colors.magenta);\n\t\t\tlines.push(` ${type.padEnd(12)} ${bar} ${count}`);\n\t\t}\n\t\tlines.push('');\n\t}\n\n\treturn lines;\n}\n\nfunction formatEntities(result: AnalysisResult): string[] {\n\tconst lines: string[] = [];\n\n\tlines.push(color('Entities:', colors.bold));\n\tlines.push('');\n\n\tfor (const entity of result.entities) {\n\t\tconst fieldCount = entity.fields.size;\n\t\tconst relCount = entity.relationships.size;\n\t\tlines.push(\n\t\t\t` ${color(entity.name, colors.cyan)} (${fieldCount} fields, ${relCount} relationships)`\n\t\t);\n\t\tif (entity.behaviors.length > 0) {\n\t\t\tlines.push(color(` behaviors: ${entity.behaviors.join(', ')}`, colors.dim));\n\t\t}\n\t}\n\tlines.push('');\n\n\treturn lines;\n}\n\nfunction formatRelationships(result: AnalysisResult): string[] {\n\tconst lines: string[] = [];\n\n\tif (result.graph.edges.length === 0) {\n\t\treturn lines;\n\t}\n\n\tlines.push(color('Relationships:', colors.bold));\n\tlines.push('');\n\n\tfor (const edge of result.graph.edges) {\n\t\tconst arrow = getCardinalityArrow(edge.cardinality);\n\t\tconst bidir = edge.bidirectional ? color(' (bidirectional)', colors.dim) : '';\n\t\tlines.push(\n\t\t\t` ${edge.from.padEnd(20)} ${arrow} ${edge.to} ${color(`(${edge.relationship.type})`, colors.dim)}${bidir}`\n\t\t);\n\t}\n\tlines.push('');\n\n\treturn lines;\n}\n\nfunction getCardinalityArrow(cardinality: string): string {\n\tswitch (cardinality) {\n\t\tcase '1:N':\n\t\t\treturn color('--<', colors.magenta);\n\t\tcase 'N:1':\n\t\t\treturn color('>--', colors.magenta);\n\t\tcase '1:1':\n\t\t\treturn color('---', colors.magenta);\n\t\tcase 'N:M':\n\t\t\treturn color('>-<', colors.magenta);\n\t\tdefault:\n\t\t\treturn color('-->', colors.magenta);\n\t}\n}\n\nfunction formatIssues(issues: AnalysisIssue[]): string[] {\n\tconst lines: string[] = [];\n\n\t// Group by severity\n\tconst errors = issues.filter((i) => i.severity === 'error');\n\tconst warnings = issues.filter((i) => i.severity === 'warning');\n\tconst infos = issues.filter((i) => i.severity === 'info');\n\n\tif (errors.length > 0) {\n\t\tlines.push(color(`Errors (${errors.length}):`, colors.bold, colors.red));\n\t\tlines.push('');\n\t\tlines.push(...formatIssueList(errors, 'error'));\n\t\tlines.push('');\n\t}\n\n\tif (warnings.length > 0) {\n\t\tlines.push(color(`Warnings (${warnings.length}):`, colors.bold, colors.yellow));\n\t\tlines.push('');\n\t\tlines.push(...formatIssueList(warnings, 'warning'));\n\t\tlines.push('');\n\t}\n\n\tif (infos.length > 0) {\n\t\tlines.push(color(`Info (${infos.length}):`, colors.bold, colors.cyan));\n\t\tlines.push('');\n\t\tlines.push(...formatIssueList(infos, 'info', 5)); // Only show first 5 info messages\n\t\tlines.push('');\n\t}\n\n\treturn lines;\n}\n\nfunction formatIssueList(\n\tissues: AnalysisIssue[],\n\tseverity: Severity,\n\tlimit?: number\n): string[] {\n\tconst lines: string[] = [];\n\tconst displayIssues = limit ? issues.slice(0, limit) : issues;\n\n\t// Group by type\n\tconst byType = new Map<string, AnalysisIssue[]>();\n\tfor (const issue of displayIssues) {\n\t\tconst list = byType.get(issue.type) ?? [];\n\t\tlist.push(issue);\n\t\tbyType.set(issue.type, list);\n\t}\n\n\tfor (const [type, typeIssues] of byType) {\n\t\tlines.push(color(` ${type} (${typeIssues.length}):`, colors.dim));\n\n\t\tfor (const issue of typeIssues.slice(0, 5)) {\n\t\t\tconst location = issue.entity\n\t\t\t\t? `${issue.entity}${issue.field ? '.' + issue.field : ''}`\n\t\t\t\t: issue.path ?? 'unknown';\n\n\t\t\tconst icon = color(`[${severityIcon(severity)}]`, severityColor(severity));\n\t\t\tlines.push(` ${icon} ${color(location, colors.bold)}: ${issue.message}`);\n\n\t\t\tif (issue.suggestion) {\n\t\t\t\tlines.push(color(` -> ${issue.suggestion}`, colors.dim));\n\t\t\t}\n\t\t}\n\n\t\tif (typeIssues.length > 5) {\n\t\t\tlines.push(color(` ... and ${typeIssues.length - 5} more`, colors.dim));\n\t\t}\n\t}\n\n\tif (limit && issues.length > limit) {\n\t\tlines.push(color(` ... and ${issues.length - limit} more info messages`, colors.dim));\n\t}\n\n\treturn lines;\n}\n","/**\n * JSON Formatter\n *\n * Machine-readable JSON output for the domain analysis results.\n */\n\nimport type { AnalysisResult, ParsedEntity, DomainGraph } from '../analyzer/types';\n\n/**\n * Helper to convert Maps to plain objects for JSON serialization\n */\nfunction mapToObject<K extends string, V>(map: Map<K, V>): Record<K, V> {\n\tconst obj = {} as Record<K, V>;\n\tfor (const [key, value] of map) {\n\t\tobj[key] = value;\n\t}\n\treturn obj;\n}\n\n/**\n * Convert ParsedEntity to a JSON-serializable format\n */\nfunction serializeEntity(entity: ParsedEntity): Record<string, unknown> {\n\treturn {\n\t\tname: entity.name,\n\t\tplural: entity.plural,\n\t\ttable: entity.table,\n\t\tfolderStructure: entity.folderStructure,\n\t\tfields: mapToObject(entity.fields),\n\t\trelationships: mapToObject(entity.relationships),\n\t\tbehaviors: entity.behaviors,\n\t\tsourcePath: entity.sourcePath,\n\t};\n}\n\n/**\n * Convert DomainGraph to a JSON-serializable format\n */\nfunction serializeGraph(graph: DomainGraph): Record<string, unknown> {\n\tconst entities: Record<string, unknown> = {};\n\tfor (const [name, entity] of graph.entities) {\n\t\tentities[name] = serializeEntity(entity);\n\t}\n\n\treturn {\n\t\tentities,\n\t\tedges: graph.edges,\n\t};\n}\n\n/**\n * Format analysis result as JSON string\n */\nexport function formatJson(result: AnalysisResult, pretty = true): string {\n\tconst output = {\n\t\tisValid: result.isValid,\n\t\tsummary: {\n\t\t\tentities: result.statistics.totalEntities,\n\t\t\tfields: result.statistics.totalFields,\n\t\t\trelationships: result.statistics.totalRelationships,\n\t\t\terrors: result.issues.filter((i) => i.severity === 'error').length,\n\t\t\twarnings: result.issues.filter((i) => i.severity === 'warning').length,\n\t\t\tinfo: result.issues.filter((i) => i.severity === 'info').length,\n\t\t},\n\t\tentities: result.entities.map(serializeEntity),\n\t\tgraph: serializeGraph(result.graph),\n\t\tissues: result.issues,\n\t\tstatistics: result.statistics,\n\t\ttimestamp: new Date().toISOString(),\n\t};\n\n\treturn pretty ? JSON.stringify(output, null, 2) : JSON.stringify(output);\n}\n\n/**\n * Format only statistics as JSON\n */\nexport function formatStatsJson(result: AnalysisResult, pretty = true): string {\n\tconst output = {\n\t\tstatistics: result.statistics,\n\t\tisValid: result.isValid,\n\t\tissueCount: {\n\t\t\terrors: result.issues.filter((i) => i.severity === 'error').length,\n\t\t\twarnings: result.issues.filter((i) => i.severity === 'warning').length,\n\t\t\tinfo: result.issues.filter((i) => i.severity === 'info').length,\n\t\t},\n\t\ttimestamp: new Date().toISOString(),\n\t};\n\n\treturn pretty ? JSON.stringify(output, null, 2) : JSON.stringify(output);\n}\n\n/**\n * Format only issues as JSON\n */\nexport function formatIssuesJson(result: AnalysisResult, pretty = true): string {\n\tconst output = {\n\t\tisValid: result.isValid,\n\t\tissues: result.issues,\n\t\ttimestamp: new Date().toISOString(),\n\t};\n\n\treturn pretty ? JSON.stringify(output, null, 2) : JSON.stringify(output);\n}\n","/**\n * Markdown Formatter\n *\n * Documentation output with Mermaid diagrams for the domain analysis results.\n */\n\nimport type { AnalysisResult, ParsedEntity, RelationshipEdge } from '../analyzer/types';\n\n/**\n * Format analysis result as Markdown documentation\n */\nexport function formatMarkdown(result: AnalysisResult): string {\n\tconst lines: string[] = [];\n\n\t// Title\n\tlines.push('# Domain Model Documentation');\n\tlines.push('');\n\tlines.push(`Generated: ${new Date().toISOString()}`);\n\tlines.push('');\n\n\t// Overview statistics\n\tlines.push('## Overview');\n\tlines.push('');\n\tlines.push('| Metric | Value |');\n\tlines.push('|--------|-------|');\n\tlines.push(`| Entities | ${result.statistics.totalEntities} |`);\n\tlines.push(`| Total Fields | ${result.statistics.totalFields} |`);\n\tlines.push(`| Total Relationships | ${result.statistics.totalRelationships} |`);\n\tlines.push(\n\t\t`| Avg Fields/Entity | ${result.statistics.averageFieldsPerEntity.toFixed(1)} |`\n\t);\n\tlines.push('');\n\n\t// Field type distribution\n\tlines.push('### Field Type Distribution');\n\tlines.push('');\n\tlines.push('| Type | Count |');\n\tlines.push('|------|-------|');\n\tconst sortedTypes = Object.entries(result.statistics.fieldsByType).sort(\n\t\t(a, b) => b[1] - a[1]\n\t);\n\tfor (const [type, count] of sortedTypes) {\n\t\tlines.push(`| ${type} | ${count} |`);\n\t}\n\tlines.push('');\n\n\t// Relationship type distribution\n\tif (result.statistics.totalRelationships > 0) {\n\t\tlines.push('### Relationship Type Distribution');\n\t\tlines.push('');\n\t\tlines.push('| Type | Count |');\n\t\tlines.push('|------|-------|');\n\t\tconst sortedRels = Object.entries(result.statistics.relationshipsByType).sort(\n\t\t\t(a, b) => b[1] - a[1]\n\t\t);\n\t\tfor (const [type, count] of sortedRels) {\n\t\t\tlines.push(`| ${type} | ${count} |`);\n\t\t}\n\t\tlines.push('');\n\t}\n\n\t// Entity Relationship Diagram\n\tlines.push('## Entity Relationship Diagram');\n\tlines.push('');\n\tlines.push('```mermaid');\n\tlines.push(...generateMermaidErDiagram(result));\n\tlines.push('```');\n\tlines.push('');\n\n\t// Entities\n\tlines.push('## Entities');\n\tlines.push('');\n\n\tfor (const entity of result.entities) {\n\t\tlines.push(...formatEntitySection(entity));\n\t}\n\n\t// Issues\n\tconst errors = result.issues.filter((i) => i.severity === 'error');\n\tconst warnings = result.issues.filter((i) => i.severity === 'warning');\n\tconst infos = result.issues.filter((i) => i.severity === 'info');\n\n\tif (result.issues.length > 0) {\n\t\tlines.push('## Analysis Issues');\n\t\tlines.push('');\n\n\t\tif (errors.length > 0) {\n\t\t\tlines.push('### Errors');\n\t\t\tlines.push('');\n\t\t\tfor (const issue of errors) {\n\t\t\t\tconst location = issue.entity\n\t\t\t\t\t? `**${issue.entity}${issue.field ? '.' + issue.field : ''}**`\n\t\t\t\t\t: issue.path ?? 'unknown';\n\t\t\t\tlines.push(`- [${issue.type}] ${location}: ${issue.message}`);\n\t\t\t\tif (issue.suggestion) {\n\t\t\t\t\tlines.push(` - Suggestion: ${issue.suggestion}`);\n\t\t\t\t}\n\t\t\t}\n\t\t\tlines.push('');\n\t\t}\n\n\t\tif (warnings.length > 0) {\n\t\t\tlines.push('### Warnings');\n\t\t\tlines.push('');\n\t\t\tfor (const issue of warnings) {\n\t\t\t\tconst location = issue.entity\n\t\t\t\t\t? `**${issue.entity}${issue.field ? '.' + issue.field : ''}**`\n\t\t\t\t\t: issue.path ?? 'unknown';\n\t\t\t\tlines.push(`- [${issue.type}] ${location}: ${issue.message}`);\n\t\t\t\tif (issue.suggestion) {\n\t\t\t\t\tlines.push(` - Suggestion: ${issue.suggestion}`);\n\t\t\t\t}\n\t\t\t}\n\t\t\tlines.push('');\n\t\t}\n\n\t\tif (infos.length > 0) {\n\t\t\tlines.push('### Info');\n\t\t\tlines.push('');\n\t\t\tlines.push('<details>');\n\t\t\tlines.push('<summary>Show info messages</summary>');\n\t\t\tlines.push('');\n\t\t\tfor (const issue of infos) {\n\t\t\t\tconst location = issue.entity\n\t\t\t\t\t? `**${issue.entity}${issue.field ? '.' + issue.field : ''}**`\n\t\t\t\t\t: issue.path ?? 'unknown';\n\t\t\t\tlines.push(`- [${issue.type}] ${location}: ${issue.message}`);\n\t\t\t}\n\t\t\tlines.push('');\n\t\t\tlines.push('</details>');\n\t\t\tlines.push('');\n\t\t}\n\t}\n\n\treturn lines.join('\\n');\n}\n\n/**\n * Format a single entity section\n */\nfunction formatEntitySection(entity: ParsedEntity): string[] {\n\tconst lines: string[] = [];\n\n\tlines.push(`### ${entity.name}`);\n\tlines.push('');\n\tlines.push(`**Table:** \\`${entity.table}\\``);\n\tlines.push(`**Plural:** ${entity.plural}`);\n\tif (entity.behaviors.length > 0) {\n\t\tlines.push(`**Behaviors:** ${entity.behaviors.join(', ')}`);\n\t}\n\tlines.push('');\n\n\t// Fields table\n\tlines.push('#### Fields');\n\tlines.push('');\n\tlines.push('| Name | Type | Required | Nullable | Index | Foreign Key |');\n\tlines.push('|------|------|----------|----------|-------|-------------|');\n\n\tfor (const [name, field] of entity.fields) {\n\t\tconst required = field.required ? 'Yes' : '';\n\t\tconst nullable = field.nullable ? 'Yes' : '';\n\t\tconst index = field.index ? 'Yes' : field.unique ? 'Unique' : '';\n\t\tconst fk = field.foreignKey ? `${field.foreignKey.table}.${field.foreignKey.column}` : '';\n\t\tlines.push(`| ${name} | ${field.type} | ${required} | ${nullable} | ${index} | ${fk} |`);\n\t}\n\tlines.push('');\n\n\t// Relationships\n\tif (entity.relationships.size > 0) {\n\t\tlines.push('#### Relationships');\n\t\tlines.push('');\n\t\tlines.push('| Name | Type | Target | Foreign Key |');\n\t\tlines.push('|------|------|--------|-------------|');\n\n\t\tfor (const [name, rel] of entity.relationships) {\n\t\t\tlines.push(`| ${name} | ${rel.type} | ${rel.target} | ${rel.foreignKey} |`);\n\t\t}\n\t\tlines.push('');\n\t}\n\n\treturn lines;\n}\n\n/**\n * Generate Mermaid ER diagram\n */\nfunction generateMermaidErDiagram(result: AnalysisResult): string[] {\n\tconst lines: string[] = [];\n\n\tlines.push('erDiagram');\n\n\t// Define entities with their fields\n\tfor (const entity of result.entities) {\n\t\tconst entityName = entity.name.toUpperCase();\n\t\tlines.push(` ${entityName} {`);\n\n\t\t// Show key fields only (to keep diagram readable)\n\t\tconst keyFields = Array.from(entity.fields.entries())\n\t\t\t.filter(\n\t\t\t\t([name, field]) =>\n\t\t\t\t\tfield.foreignKey || field.unique || field.index || name === 'id' || name === 'name'\n\t\t\t)\n\t\t\t.slice(0, 6); // Limit to 6 fields\n\n\t\tfor (const [name, field] of keyFields) {\n\t\t\tconst typeStr = field.type;\n\t\t\tconst pk = name === 'id' ? 'PK' : '';\n\t\t\tconst fk = field.foreignKey ? 'FK' : '';\n\t\t\tconst marker = pk || fk ? ` \"${pk}${fk}\"` : '';\n\t\t\tlines.push(` ${typeStr} ${name}${marker}`);\n\t\t}\n\n\t\tif (entity.fields.size > keyFields.length) {\n\t\t\tlines.push(` string _more_fields`);\n\t\t}\n\n\t\tlines.push(' }');\n\t}\n\n\t// Add relationships\n\tfor (const edge of result.graph.edges) {\n\t\tconst from = edge.from.toUpperCase();\n\t\tconst to = edge.to.toUpperCase();\n\t\tconst cardinalitySymbol = getCardinalitySymbol(edge.cardinality);\n\t\tconst label = edge.relationship.name;\n\n\t\tlines.push(` ${from} ${cardinalitySymbol} ${to} : \"${label}\"`);\n\t}\n\n\treturn lines;\n}\n\n/**\n * Get Mermaid cardinality symbol\n */\nfunction getCardinalitySymbol(cardinality: string): string {\n\tswitch (cardinality) {\n\t\tcase '1:N':\n\t\t\treturn '||--o{';\n\t\tcase 'N:1':\n\t\t\treturn '}o--||';\n\t\tcase '1:1':\n\t\t\treturn '||--||';\n\t\tcase 'N:M':\n\t\t\treturn '}o--o{';\n\t\tdefault:\n\t\t\treturn '||--o{';\n\t}\n}\n\n/**\n * Generate a simple relationship graph in Mermaid\n */\nexport function formatMermaidGraph(result: AnalysisResult): string {\n\tconst lines: string[] = [];\n\n\tlines.push('```mermaid');\n\tlines.push('graph LR');\n\n\t// Style definitions\n\tlines.push(' classDef entity fill:#e1f5fe,stroke:#01579b');\n\n\t// Add entities as nodes\n\tfor (const entity of result.entities) {\n\t\tlines.push(` ${entity.name}[\"${entity.name}\\\\n(${entity.fields.size} fields)\"]`);\n\t}\n\n\t// Add relationships as edges\n\tfor (const edge of result.graph.edges) {\n\t\tconst style = edge.bidirectional ? '<-->' : '-->';\n\t\tlines.push(` ${edge.from} ${style}|${edge.relationship.type}| ${edge.to}`);\n\t}\n\n\t// Apply styles\n\tconst entityList = result.entities.map((e) => e.name).join(',');\n\tif (entityList) {\n\t\tlines.push(` class ${entityList} entity`);\n\t}\n\n\tlines.push('```');\n\n\treturn lines.join('\\n');\n}\n","/**\n * ActivityPattern — replaces `family: activity`.\n *\n * Activity entities represent time-bounded interactions (calls, meetings,\n * emails). The base repository/service expose date-range + opportunity +\n * user-scoped lookups on top of the standard CRUD methods.\n *\n * Class names, import paths, and inherited-method strings match the\n * legacy `FAMILY_MAP` entry verbatim so PATTERN-5's template swap produces\n * byte-identical output.\n */\n\nimport { definePattern } from '../pattern-definition.js';\n\nexport const ActivityPattern = definePattern({\n\tname: 'Activity',\n\textends: ['Base'],\n\trepositoryClass: 'ActivityEntityRepository',\n\tserviceClass: 'ActivityEntityService',\n\trepositoryImport: '@shared/base-classes/activity-entity-repository',\n\tserviceImport: '@shared/base-classes/activity-entity-service',\n\trepositoryInheritedMethods: [\n\t\t'findById, findByIds, list, count, exists, create, update, delete, upsertMany',\n\t\t'findByDateRange, findByUserId, findByOpportunityId, findRecentByOpportunityId',\n\t],\n\tserviceInheritedMethods: [\n\t\t'findById, findByIds, list, count, exists, create, update, delete',\n\t\t'findByDateRange, findByUserId, findByOpportunityId, findRecentByOpportunityId',\n\t],\n\tdescription:\n\t\t'Time-bounded interaction entities — date-range + opportunity scoped lookups',\n});\n","/**\n * BasePattern — identity pattern for the `extends` chain.\n *\n * Contributes no columns, no implied behaviors, and no config. Its only\n * purpose is to anchor the inheritance hierarchy so every other pattern\n * can declare `extends: ['Base']` and codegen can resolve that to a\n * concrete `BaseRepository` / `BaseService` reference.\n *\n * Matches the existing `family: base` entry in\n * `templates/entity/new/clean-lite-ps/prompt-extension.js` verbatim.\n */\n\nimport { definePattern } from '../pattern-definition.js';\n\nexport const BasePattern = definePattern({\n\tname: 'Base',\n\trepositoryClass: 'BaseRepository',\n\tserviceClass: 'BaseService',\n\trepositoryImport: '@shared/base-classes/base-repository',\n\tserviceImport: '@shared/base-classes/base-service',\n\trepositoryInheritedMethods: [\n\t\t'findById, findByIds, list, count, exists, create, update, delete, upsertMany',\n\t],\n\tserviceInheritedMethods: [\n\t\t'findById, findByIds, list, count, exists, create, update, delete',\n\t],\n\tdescription: 'Identity pattern — base CRUD, no extra columns or methods',\n});\n","/**\n * KnowledgePattern — replaces `family: knowledge`.\n *\n * Knowledge entities hold long-form content with a workflow status and\n * semantic-search support (vectors, pending/approved states). The base\n * classes expose `semanticSearch`, pending-by-opportunity lookups, and\n * batch status updates.\n *\n * Class names, import paths, and inherited-method strings match the\n * legacy `FAMILY_MAP` entry verbatim.\n */\n\nimport { definePattern } from '../pattern-definition.js';\n\nexport const KnowledgePattern = definePattern({\n\tname: 'Knowledge',\n\textends: ['Base'],\n\trepositoryClass: 'KnowledgeEntityRepository',\n\tserviceClass: 'KnowledgeEntityService',\n\trepositoryImport: '@shared/base-classes/knowledge-entity-repository',\n\tserviceImport: '@shared/base-classes/knowledge-entity-service',\n\trepositoryInheritedMethods: [\n\t\t'findById, findByIds, list, count, exists, create, update, delete, upsertMany',\n\t\t'semanticSearch, findPendingByOpportunityId, updateStatus, updateStatusBatch',\n\t],\n\tserviceInheritedMethods: [\n\t\t'findById, findByIds, list, count, exists, create, update, delete',\n\t\t'semanticSearch, findPendingByOpportunityId, updateStatus, updateStatusBatch',\n\t],\n\tdescription: 'Knowledge entities — semantic search + workflow status',\n});\n","/**\n * MetadataPattern — replaces `family: metadata`.\n *\n * Metadata entities represent history-tracked auxiliary rows attached to a\n * parent entity (audit trails, custom-field values, change logs). The base\n * classes expose entity-id + type scoped lookups and history listing.\n *\n * Class names, import paths, and inherited-method strings match the\n * legacy `FAMILY_MAP` entry verbatim.\n */\n\nimport { definePattern } from '../pattern-definition.js';\n\nexport const MetadataPattern = definePattern({\n\tname: 'Metadata',\n\textends: ['Base'],\n\trepositoryClass: 'MetadataEntityRepository',\n\tserviceClass: 'MetadataEntityService',\n\trepositoryImport: '@shared/base-classes/metadata-entity-repository',\n\tserviceImport: '@shared/base-classes/metadata-entity-service',\n\trepositoryInheritedMethods: [\n\t\t'findById, findByIds, list, count, exists, create, update, delete, upsertMany',\n\t\t'findByEntityIdAndType, listByEntityId, listHistoryByEntityId',\n\t],\n\tserviceInheritedMethods: [\n\t\t'findById, findByIds, list, count, exists, create, update, delete',\n\t\t'findByEntityIdAndType, listByEntityId, listHistoryByEntityId',\n\t],\n\tdescription:\n\t\t'History-tracked metadata rows — entity-id + type scoped lookups',\n});\n","/**\n * SyncedPattern — adds external-system sync columns and methods.\n *\n * Replaces the legacy `family: synced` entry in\n * `templates/entity/new/clean-lite-ps/prompt-extension.js`. Class names,\n * import paths, and inherited-method comment lines are preserved verbatim\n * so PATTERN-5's template swap produces byte-identical output for\n * pre-existing `family: synced` fixtures.\n *\n * Implies `external_id_tracking` — the behavior that contributes the\n * `external_id`, `provider`, and `provider_metadata` columns to the table.\n * An entity declaring `pattern: Synced` need not re-declare the behavior.\n */\n\nimport { definePattern } from '../pattern-definition.js';\n\nexport const SyncedPattern = definePattern({\n\tname: 'Synced',\n\textends: ['Base'],\n\trepositoryClass: 'SyncedEntityRepository',\n\tserviceClass: 'SyncedEntityService',\n\trepositoryImport: '@shared/base-classes/synced-entity-repository',\n\tserviceImport: '@shared/base-classes/synced-entity-service',\n\trepositoryInheritedMethods: [\n\t\t'findById, findByIds, list, count, exists, create, update, delete, upsertMany',\n\t\t'findByExternalId, findAllByUserId, findVisibleByUserId, syncUpsert',\n\t],\n\tserviceInheritedMethods: [\n\t\t'findById, findByIds, list, count, exists, create, update, delete',\n\t\t'findByExternalId, findAllByUserId, findVisibleByUserId',\n\t],\n\timpliedBehaviors: ['external_id_tracking'],\n\tdescription: 'External CRM/system sync columns and syncUpsert methods',\n});\n","/**\n * Library pattern bootstrap — imports every shipped pattern and registers\n * it with the shared library registry. Side-effect-only module: importing\n * this barrel is what pre-registers `Base`, `Synced`, `Activity`,\n * `Knowledge`, and `Metadata`.\n *\n * Adding a new library pattern is two edits: create the `*.pattern.ts`\n * file and add the import+register pair below.\n */\n\nimport { registerLibraryPattern } from '../registry.js';\nimport { ActivityPattern } from './activity.pattern.js';\nimport { BasePattern } from './base.pattern.js';\nimport { KnowledgePattern } from './knowledge.pattern.js';\nimport { MetadataPattern } from './metadata.pattern.js';\nimport { SyncedPattern } from './synced.pattern.js';\n\nregisterLibraryPattern(BasePattern);\nregisterLibraryPattern(SyncedPattern);\nregisterLibraryPattern(ActivityPattern);\nregisterLibraryPattern(KnowledgePattern);\nregisterLibraryPattern(MetadataPattern);\n\nexport {\n\tActivityPattern,\n\tBasePattern,\n\tKnowledgePattern,\n\tMetadataPattern,\n\tSyncedPattern,\n};\n","/**\n * Entity Codegen & Domain Analyzer\n *\n * A validation and analysis tool for entity YAML definitions.\n * Parses entities, builds a relationship graph, and detects issues.\n */\n\nimport { loadEntities, loadRelationships, resolveReferences, resolveRelationshipReferences } from './parser';\nimport { buildDomainGraph, checkConsistency, computeStatistics } from './analyzer';\nimport {\n\tvalidatePatternComposition,\n\tvalidatePatternProject,\n} from './patterns/validate-composition.js';\nimport { validateOrchestrationProject } from './patterns/validate-orchestration.js';\nimport {\n\tgetAllOrchestrationPatterns,\n\tgetAllPatternNames,\n} from './patterns/registry.js';\nimport type { AnalysisResult, OutputFormat } from './analyzer/types';\n\n/**\n * Options for `analyzeDomain`. All fields are optional and additive — omitting\n * them keeps the analyzer's behavior identical to pre-PATTERN-4 callers.\n */\nexport interface AnalyzeDomainOptions {\n\t/**\n\t * Path to the relationships directory. Equivalent to the legacy second\n\t * positional argument — preserved for call-site compatibility.\n\t */\n\trelationshipsDir?: string;\n\t/**\n\t * Selected backend architecture from `codegen.config.yaml\n\t * generate.architecture`. When provided, enables the PATTERN-4 project-level\n\t * check (plan Risk 4) that warns when `pattern:` is declared but the\n\t * selected architecture does not yet consume patterns (e.g. `clean`).\n\t */\n\tarchitecture?: string;\n}\n\n/**\n * Analyze a domain from entity and relationship YAML files.\n *\n * The signature accepts either the legacy `(entitiesDir, relationshipsDir)`\n * shape or the newer `(entitiesDir, options)` object form. Existing callers\n * keep working unchanged; pattern-aware callers pass\n * `{ architecture, relationshipsDir }` to opt into the Risk-4 project-level\n * warning surface.\n */\nexport async function analyzeDomain(\n\tentitiesDir: string,\n\trelationshipsOrOptions?: string | AnalyzeDomainOptions,\n): Promise<AnalysisResult> {\n\tconst opts: AnalyzeDomainOptions =\n\t\ttypeof relationshipsOrOptions === 'string'\n\t\t\t? { relationshipsDir: relationshipsOrOptions }\n\t\t\t: relationshipsOrOptions ?? {};\n\tconst relationshipsDir = opts.relationshipsDir;\n\n\t// Load and parse all entity files\n\tconst { entities, issues: loadIssues } = loadEntities(entitiesDir);\n\n\t// Load relationship definitions (optional — directory may not exist)\n\tconst { relationships: relationshipDefinitions, issues: relLoadIssues } =\n\t\trelationshipsDir\n\t\t\t? loadRelationships(relationshipsDir)\n\t\t\t: { relationships: [], issues: [] };\n\n\t// Resolve cross-entity references\n\tconst resolveIssues = resolveReferences(entities);\n\n\t// Resolve relationship endpoint references\n\tconst relResolveIssues = resolveRelationshipReferences(\n\t\trelationshipDefinitions,\n\t\tentities,\n\t);\n\n\t// Build relationship graph (includes both inline and first-class relationships)\n\tconst graph = buildDomainGraph(entities, relationshipDefinitions);\n\n\t// Check consistency\n\tconst consistencyIssues = checkConsistency(graph);\n\n\t// PATTERN-4 — pattern composition check. Runs AFTER resolveReferences()\n\t// (per ADR-031 §3) so entity fields + behaviors are known; the\n\t// per-entity validator detects column conflicts, unknown patterns, and\n\t// config-schema failures, and the project-level validator covers plan\n\t// Risk 4 (warn when `pattern:` is declared under an architecture that\n\t// does not yet consume patterns).\n\tconst patternIssues = entities.flatMap((e) => validatePatternComposition(e));\n\tconst patternProjectIssues = validatePatternProject({\n\t\tentities,\n\t\tarchitecture: opts.architecture,\n\t});\n\n\t// ADR-032 Phase 3-1 — orchestration pattern project-level validator.\n\t// Compares orchestration names against the domain name set (cross-kind\n\t// collision is a hard error), and walks each orchestration pattern's\n\t// registry shape for malformed entries, duplicate keys, and co-keyed\n\t// keyType drift.\n\tconst orchestrationProjectIssues = validateOrchestrationProject({\n\t\torchestrationPatterns: getAllOrchestrationPatterns(),\n\t\tdomainPatternNames: getAllPatternNames(),\n\t});\n\n\t// Compute statistics\n\tconst statistics = computeStatistics(graph);\n\n\t// Combine all issues\n\tconst allIssues = [\n\t\t...loadIssues,\n\t\t...relLoadIssues,\n\t\t...resolveIssues,\n\t\t...relResolveIssues,\n\t\t...consistencyIssues,\n\t\t...patternIssues,\n\t\t...patternProjectIssues,\n\t\t...orchestrationProjectIssues,\n\t];\n\n\t// Determine validity (only errors make it invalid)\n\tconst hasErrors = allIssues.some((i) => i.severity === 'error');\n\n\treturn {\n\t\tisValid: !hasErrors,\n\t\tentities,\n\t\trelationshipDefinitions,\n\t\tgraph,\n\t\tissues: allIssues,\n\t\tstatistics,\n\t};\n}\n\n/**\n * Validate entity files without full analysis\n * Returns true if all files parse successfully\n */\nexport function validateEntities(entitiesDir: string): {\n\tvalid: boolean;\n\terrors: string[];\n} {\n\tconst { entities, issues } = loadEntities(entitiesDir);\n\tconst errors = issues\n\t\t.filter((i) => i.severity === 'error')\n\t\t.map((i) => i.message);\n\n\treturn {\n\t\tvalid: errors.length === 0,\n\t\terrors,\n\t};\n}\n\n// Re-export types\nexport * from './analyzer/types';\n\n// Re-export parser utilities\nexport { loadEntities, loadRelationships, loadEntityFromYaml, loadRelationshipFromYaml } from './parser';\n\n// Re-export analyzer utilities\nexport {\n\tbuildDomainGraph,\n\tgetRelatedEntities,\n\tfindOrphanEntities,\n\tfindCircularDependencies,\n\tcheckConsistency,\n\tcomputeStatistics,\n} from './analyzer';\n\n// Re-export formatters\nexport {\n\tformatConsole,\n\tformatJson,\n\tformatMarkdown,\n\tformatMermaidGraph,\n} from './formatters';\n\n\n// Re-export patterns surface (definePattern + library patterns + registry).\n// Importing this barrel has the side effect of pre-registering the five\n// library-shipped patterns (Base / Synced / Activity / Knowledge / Metadata).\nexport * from './patterns';\n"],"mappings":"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","names":["z","z","Injectable","Injectable","Injectable","out","Injectable","Injectable","Injectable","Inject","Injectable","Optional","Injectable","Inject","Optional","Inject","Injectable","Optional","and","desc","eq","eq","and","desc","Injectable","Inject","Optional","z","z","z","path","path","text","index"]}
|