@documentation-robotics/cli 0.3.0 → 0.4.0

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.
Files changed (182) hide show
  1. package/README.md +10 -14
  2. package/dist/analyzers/active-analyzer.js +62 -0
  3. package/dist/analyzers/active-analyzer.js.map +7 -0
  4. package/dist/analyzers/cards/build.js +21 -1
  5. package/dist/analyzers/cards/build.js.map +2 -2
  6. package/dist/analyzers/cards/extract.js +138 -0
  7. package/dist/analyzers/cards/extract.js.map +7 -0
  8. package/dist/analyzers/cards/routes.js +96 -0
  9. package/dist/analyzers/cards/routes.js.map +7 -0
  10. package/dist/analyzers/cbm-analyzer.js +76 -4
  11. package/dist/analyzers/cbm-analyzer.js.map +2 -2
  12. package/dist/analyzers/cbm-responses.js +12 -6
  13. package/dist/analyzers/cbm-responses.js.map +2 -2
  14. package/dist/analyzers/code-changes.js +159 -0
  15. package/dist/analyzers/code-changes.js.map +7 -0
  16. package/dist/analyzers/edge-relationships.js +6 -2
  17. package/dist/analyzers/edge-relationships.js.map +2 -2
  18. package/dist/analyzers/extraction-plan.js +541 -0
  19. package/dist/analyzers/extraction-plan.js.map +7 -0
  20. package/dist/analyzers/index-job.js +229 -0
  21. package/dist/analyzers/index-job.js.map +7 -0
  22. package/dist/cli.js +12 -10
  23. package/dist/cli.js.map +2 -2
  24. package/dist/coding-agents/drbot-mcp.js +120 -18
  25. package/dist/coding-agents/drbot-mcp.js.map +2 -2
  26. package/dist/commands/add.js +4 -2
  27. package/dist/commands/add.js.map +2 -2
  28. package/dist/commands/analyzer.js +35 -35
  29. package/dist/commands/analyzer.js.map +2 -2
  30. package/dist/commands/changeset-verify.js +16 -8
  31. package/dist/commands/changeset-verify.js.map +2 -2
  32. package/dist/commands/changeset.js +41 -11
  33. package/dist/commands/changeset.js.map +2 -2
  34. package/dist/commands/init.js +9 -26
  35. package/dist/commands/init.js.map +2 -2
  36. package/dist/commands/mcp.js +35 -31
  37. package/dist/commands/mcp.js.map +3 -3
  38. package/dist/commands/relationship.js +2 -12
  39. package/dist/commands/relationship.js.map +2 -2
  40. package/dist/commands/reports.js +3 -3
  41. package/dist/commands/reports.js.map +2 -2
  42. package/dist/commands/update.js +14 -13
  43. package/dist/commands/update.js.map +2 -2
  44. package/dist/commands/upgrade.js +28 -120
  45. package/dist/commands/upgrade.js.map +2 -2
  46. package/dist/commands/validate.js +19 -3
  47. package/dist/commands/validate.js.map +2 -2
  48. package/dist/commands/version.js +1 -1
  49. package/dist/commands/visualize.js +30 -12
  50. package/dist/commands/visualize.js.map +2 -2
  51. package/dist/core/annotation-store.js +15 -5
  52. package/dist/core/annotation-store.js.map +2 -2
  53. package/dist/core/catalog-migration.js +2 -1
  54. package/dist/core/catalog-migration.js.map +2 -2
  55. package/dist/core/changeset-base-index.js +7 -0
  56. package/dist/core/changeset-base-index.js.map +2 -2
  57. package/dist/core/changeset-brief-compact.js +256 -0
  58. package/dist/core/changeset-brief-compact.js.map +7 -0
  59. package/dist/core/changeset-verify.js +356 -26
  60. package/dist/core/changeset-verify.js.map +3 -3
  61. package/dist/core/extraction-observability.js +161 -0
  62. package/dist/core/extraction-observability.js.map +7 -0
  63. package/dist/core/migration-registry.js +13 -1
  64. package/dist/core/migration-registry.js.map +2 -2
  65. package/dist/core/project-init.js +53 -0
  66. package/dist/core/project-init.js.map +7 -0
  67. package/dist/core/relationship-staging.js +94 -1
  68. package/dist/core/relationship-staging.js.map +2 -2
  69. package/dist/core/staged-changeset-storage.js +83 -3
  70. package/dist/core/staged-changeset-storage.js.map +2 -2
  71. package/dist/core/staging-area.js +85 -8
  72. package/dist/core/staging-area.js.map +2 -2
  73. package/dist/core/upgrade-plan.js +117 -0
  74. package/dist/core/upgrade-plan.js.map +7 -0
  75. package/dist/generated/relationship-index.js +124 -15
  76. package/dist/generated/relationship-index.js.map +2 -2
  77. package/dist/integrations/claude_code/.claude-plugin/plugin.json +24 -0
  78. package/dist/integrations/claude_code/agents/dr-architect.md +19 -5
  79. package/dist/integrations/claude_code/agents/dr-extractor.md +7 -1
  80. package/dist/integrations/claude_code/commands/dr-changeset.md +2 -1
  81. package/dist/integrations/claude_code/commands/dr-map.md +7 -1
  82. package/dist/integrations/claude_code/commands/dr-plan.md +42 -16
  83. package/dist/integrations/claude_code/docs/MCP_SERVER.md +28 -31
  84. package/dist/integrations/claude_code/docs/README.md +20 -1
  85. package/dist/integrations/claude_code/plugin-agents/dr-advisor.md +255 -0
  86. package/dist/integrations/claude_code/plugin-agents/dr-architect.md +306 -0
  87. package/dist/integrations/claude_code/skills/dr_13_testing_layer/SKILL.md +3 -0
  88. package/dist/integrations/claude_code/skills/dr_change_planning/SKILL.md +90 -31
  89. package/dist/integrations/claude_code/skills/dr_changeset_reviewer/SKILL.md +5 -0
  90. package/dist/integrations/claude_code/skills/dr_engineering_guide/SKILL.md +5 -0
  91. package/dist/integrations/github_copilot/agents/dr-architect.md +2 -0
  92. package/dist/integrations/github_copilot/skills/dr_13_testing_layer/SKILL.md +3 -0
  93. package/dist/integrations/github_copilot/skills/dr_change_planning/SKILL.md +88 -30
  94. package/dist/mcp/changeset-only.js +14 -3
  95. package/dist/mcp/changeset-only.js.map +2 -2
  96. package/dist/mcp/project-root.js +85 -0
  97. package/dist/mcp/project-root.js.map +7 -0
  98. package/dist/mcp/server-instructions.js +27 -0
  99. package/dist/mcp/server-instructions.js.map +7 -0
  100. package/dist/mcp/strict-schema.js +52 -0
  101. package/dist/mcp/strict-schema.js.map +7 -0
  102. package/dist/mcp/tool-registry.js +39 -5
  103. package/dist/mcp/tool-registry.js.map +2 -2
  104. package/dist/mcp/tools/changeset-analysis-tools.js +25 -5
  105. package/dist/mcp/tools/changeset-analysis-tools.js.map +3 -3
  106. package/dist/mcp/tools/changeset-commit.js +224 -0
  107. package/dist/mcp/tools/changeset-commit.js.map +7 -0
  108. package/dist/mcp/tools/changeset-editing.js +133 -57
  109. package/dist/mcp/tools/changeset-editing.js.map +3 -3
  110. package/dist/mcp/tools/changeset-lifecycle.js +1 -1
  111. package/dist/mcp/tools/changeset-lifecycle.js.map +2 -2
  112. package/dist/mcp/tools/changeset-verify.js +12 -6
  113. package/dist/mcp/tools/changeset-verify.js.map +2 -2
  114. package/dist/mcp/tools/codebase-extract.js +836 -0
  115. package/dist/mcp/tools/codebase-extract.js.map +7 -0
  116. package/dist/mcp/tools/codebase-index.js +125 -0
  117. package/dist/mcp/tools/codebase-index.js.map +7 -0
  118. package/dist/mcp/tools/codebase-shared.js +265 -0
  119. package/dist/mcp/tools/codebase-shared.js.map +7 -0
  120. package/dist/mcp/tools/codebase-verify.js +48 -0
  121. package/dist/mcp/tools/codebase-verify.js.map +7 -0
  122. package/dist/mcp/tools/index.js +15 -0
  123. package/dist/mcp/tools/index.js.map +2 -2
  124. package/dist/mcp/tools/model-add.js +189 -73
  125. package/dist/mcp/tools/model-add.js.map +2 -2
  126. package/dist/mcp/tools/model-update.js +16 -12
  127. package/dist/mcp/tools/model-update.js.map +2 -2
  128. package/dist/mcp/tools/model-validate.js +46 -4
  129. package/dist/mcp/tools/model-validate.js.map +2 -2
  130. package/dist/mcp/tools/project-status-collectors.js +381 -0
  131. package/dist/mcp/tools/project-status-collectors.js.map +7 -0
  132. package/dist/mcp/tools/project-status.js +237 -0
  133. package/dist/mcp/tools/project-status.js.map +7 -0
  134. package/dist/mcp/tools/project-tools.js +505 -0
  135. package/dist/mcp/tools/project-tools.js.map +7 -0
  136. package/dist/mcp/tools/relationship-tools.js +89 -20
  137. package/dist/mcp/tools/relationship-tools.js.map +2 -2
  138. package/dist/mcp/tools/review-open.js +210 -0
  139. package/dist/mcp/tools/review-open.js.map +7 -0
  140. package/dist/mcp/tools/shared.js +10 -2
  141. package/dist/mcp/tools/shared.js.map +2 -2
  142. package/dist/reports/model-report-orchestrator.js +31 -2
  143. package/dist/reports/model-report-orchestrator.js.map +2 -2
  144. package/dist/schemas/bundled/analyzers/cbm.json +22 -10
  145. package/dist/schemas/bundled/analyzers/manifest.json +2 -2
  146. package/dist/schemas/bundled/api.json +1 -1
  147. package/dist/schemas/bundled/apm.json +1 -1
  148. package/dist/schemas/bundled/application.json +1 -1
  149. package/dist/schemas/bundled/base.json +1 -1
  150. package/dist/schemas/bundled/business.json +1 -1
  151. package/dist/schemas/bundled/data-model.json +1 -1
  152. package/dist/schemas/bundled/data-store.json +1 -1
  153. package/dist/schemas/bundled/manifest.json +3 -3
  154. package/dist/schemas/bundled/motivation.json +1 -1
  155. package/dist/schemas/bundled/navigation.json +1 -1
  156. package/dist/schemas/bundled/product.json +1 -1
  157. package/dist/schemas/bundled/security.json +1 -1
  158. package/dist/schemas/bundled/technology.json +1 -1
  159. package/dist/schemas/bundled/testing.json +145 -1
  160. package/dist/schemas/bundled/ux.json +1 -1
  161. package/dist/server/server.js +508 -237
  162. package/dist/server/server.js.map +3 -3
  163. package/dist/server/viewer-registry.js +264 -0
  164. package/dist/server/viewer-registry.js.map +7 -0
  165. package/dist/telemetry/index.js +1 -1
  166. package/dist/utils/id-generator.js +5 -2
  167. package/dist/utils/id-generator.js.map +2 -2
  168. package/dist/utils/source-reference.js +58 -27
  169. package/dist/utils/source-reference.js.map +2 -2
  170. package/dist/utils/spec-version.js +2 -2
  171. package/dist/utils/spec-version.js.map +1 -1
  172. package/dist/validators/model-warnings.js +28 -0
  173. package/dist/validators/model-warnings.js.map +7 -0
  174. package/dist/viewer/README.md +6 -6
  175. package/dist/viewer/assets/main-CUOQGGRA.css +1 -0
  176. package/dist/viewer/assets/main-DvH3gYrI.js +84 -0
  177. package/dist/viewer/index.html +2 -2
  178. package/dist/viewer/manifest.json +10 -10
  179. package/dist/viewer/version.json +1 -1
  180. package/package.json +1 -1
  181. package/dist/viewer/assets/main-CxzcuU_o.js +0 -84
  182. package/dist/viewer/assets/main-j-7ULYpm.css +0 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/core/changeset-verify.ts"],
4
- "sourcesContent": ["/**\n * Changeset verify \u2014 compare what a change PLANNED (a staged changeset) with what was BUILT.\n *\n * The planned side is always a changeset: its net changes (adds, updates and deletes of elements and\n * relationships, replayed in sequence order). The built side is a `BuiltSide`, which can come from:\n *\n * - another changeset (`builtFromGraph`): an as-built changeset written by hand or, later, by the\n * extraction cascade. The built world is the base model with that changeset applied, and what the\n * build changed is known, so unplanned changes are reported in full.\n * - the base model (`builtFromBase`): e.g. after an as-built changeset was committed on the branch.\n * What the build changed is not known, so unplanned changes are limited to relationships the build\n * gave the elements the plan adds.\n * - a plain snapshot of elements and relationships (`builtFromSnapshot`), the shape an extraction\n * cascade can produce without writing a changeset first.\n *\n * Matching is tolerant of renames. Elements match by id first, then by layer + type + normalized\n * name, then by layer + normalized name with a different type, then (optionally) by layer + type +\n * shared source file. Anything other than an id match is reported as a probable match with its\n * reason, never as exact. Relationships match by (source, predicate, target) after mapping the\n * planned endpoints through the element matches, so a relationship between renamed elements still\n * matches (probably).\n *\n * See docs/CHANGE_MODELING.md (Verify).\n */\n\nimport { Changeset, type StagedChange } from \"./changeset.js\";\nimport { ChangesetGraph, type GraphElement, type GraphRelationship } from \"./changeset-graph.js\";\nimport type { Model } from \"./model.js\";\nimport type { SourceReference } from \"../types/source-reference.js\";\nimport { tryReadBaseIndex } from \"./changeset-base-index.js\";\nimport { stagedSourceReference } from \"./staged-source-reference.js\";\n\n/**\n * Attribute fields whose expected progress is not a divergence: a plan says `status: planned`, the\n * build says `delivered`. Only a move to a later stage of LIFECYCLE_STAGES counts; a move back, or\n * to a value outside them, stays a divergence.\n */\nexport const LIFECYCLE_FIELDS: readonly string[] = [\"attributes.status\"];\n\n/**\n * The stages of the spec's status enums, in order (values in one stage are alternatives from\n * different types: goals, product items, milestones, test cases). Off-ramps such as `deprecated`,\n * `abandoned`, `cancelled` and `at-risk` are not stages, so moving to one is reported as a divergence.\n */\nexport const LIFECYCLE_STAGES: readonly (readonly string[])[] = [\n [\"proposed\", \"draft\"],\n [\"planned\", \"under-review\"],\n [\"approved\", \"in-progress\", \"developing\", \"active\"],\n [\"implemented\", \"delivered\", \"achieved\", \"completed\"],\n [\"automated\"],\n];\n\nfunction lifecycleStage(value: unknown): number {\n if (typeof value !== \"string\") return -1;\n const v = value.trim().toLowerCase();\n return LIFECYCLE_STAGES.findIndex((stage) => stage.includes(v));\n}\n\n/** Whether a field difference is the build moving a lifecycle field to a later stage. */\nexport function isLifecycleMove(difference: FieldDifference): boolean {\n if (!LIFECYCLE_FIELDS.includes(difference.field)) return false;\n const from = lifecycleStage(difference.planned);\n const to = lifecycleStage(difference.built);\n return from >= 0 && to > from;\n}\n\n// ---------------------------------------------------------------------------\n// Shapes\n// ---------------------------------------------------------------------------\n\nexport interface VerifyElement {\n /** Dotted path (`layer.type.name`). */\n id: string;\n layer: string;\n type: string;\n name: string;\n description?: string;\n attributes: Record<string, unknown>;\n sourceReference?: SourceReference;\n}\n\nexport interface VerifyRelationship {\n source: string;\n predicate: string;\n target: string;\n}\n\nexport interface PlannedElementChange extends VerifyElement {\n op: \"add\" | \"update\" | \"delete\";\n /** For updates: the fields the plan changes (`description`, `attributes.priority`, ...). */\n changedFields?: string[];\n /** For updates: each changed field's value before the plan, to tell a build that left it alone from one that changed it differently. */\n baseValues?: Record<string, unknown>;\n}\n\nexport interface PlannedRelationshipChange extends VerifyRelationship {\n op: \"add\" | \"delete\";\n}\n\nexport interface Plan {\n label: string;\n elements: PlannedElementChange[];\n relationships: PlannedRelationshipChange[];\n /** Changes that could not be read, and anything else worth knowing about the plan. */\n notes: string[];\n /**\n * Ids of the elements the base model had when the plan was created (its base index). Such an\n * element cannot be the built form of a planned add. Undefined when no index was recorded.\n */\n baseElementIds?: string[];\n}\n\nexport type BuiltChange = \"added\" | \"updated\" | \"deleted\";\n\nexport interface BuiltElement extends VerifyElement {\n change?: BuiltChange;\n}\n\nexport interface BuiltRelationship extends VerifyRelationship {\n change?: Exclude<BuiltChange, \"updated\">;\n}\n\nexport interface BuiltSide {\n label: string;\n kind: \"changeset\" | \"base\" | \"snapshot\";\n /** Elements that exist in the built world. */\n elements: BuiltElement[];\n /** Relationships that exist in the built world. */\n relationships: BuiltRelationship[];\n /**\n * What the build changed, deletions included. Undefined when it is not known (the base model);\n * unplanned changes are then limited to the neighbourhood of the plan's additions.\n */\n changedElements?: BuiltElement[];\n changedRelationships?: BuiltRelationship[];\n notes: string[];\n}\n\nexport type MatchKind = \"exact\" | \"probable\";\n\nexport interface FieldDifference {\n field: string;\n planned: unknown;\n built: unknown;\n}\n\nexport interface ElementMatch {\n planned: string;\n built: string;\n op: PlannedElementChange[\"op\"];\n match: MatchKind;\n /** Why a probable match was made. */\n reason?: string;\n /** Expected lifecycle progress (see LIFECYCLE_FIELDS): reported, not counted as divergence. */\n lifecycle?: FieldDifference[];\n}\n\nexport interface DivergentElement extends ElementMatch {\n fields: FieldDifference[];\n}\n\nexport interface MissingElement {\n planned: string;\n layer: string;\n type: string;\n name: string;\n op: PlannedElementChange[\"op\"];\n reason: string;\n /** Built elements that could be it, when matching was ambiguous. */\n candidates?: string[];\n /** For a planned update that the build does not carry: the fields it would have changed. */\n fields?: FieldDifference[];\n}\n\nexport interface UnplannedElement {\n id: string;\n layer: string;\n type: string;\n name: string;\n change: BuiltChange | \"present\";\n}\n\nexport interface DeletionNotDone {\n planned: string;\n built: string;\n}\n\nexport interface RelationshipMatch {\n planned: VerifyRelationship;\n built: VerifyRelationship;\n op: PlannedRelationshipChange[\"op\"];\n match: MatchKind;\n reason?: string;\n}\n\nexport interface DivergentRelationship extends RelationshipMatch {\n fields: FieldDifference[];\n}\n\nexport interface MissingRelationship {\n planned: VerifyRelationship;\n reason: string;\n /** Relationships between the same elements that may predate the change (built side without changes). */\n candidates?: VerifyRelationship[];\n}\n\nexport interface UnplannedRelationship extends VerifyRelationship {\n change: Exclude<BuiltChange, \"updated\"> | \"present\";\n}\n\nexport interface RelationshipDeletionNotDone {\n planned: VerifyRelationship;\n built: VerifyRelationship;\n}\n\nexport interface CategoryCounts {\n planned: number;\n /** Planned changes found in the build, divergent ones included (`divergent` is the subset that differs). */\n matched: number;\n probable: number;\n missing: number;\n divergent: number;\n unplanned: number;\n deletionsNotDone: number;\n}\n\nexport type Verdict = \"match\" | \"probable-match\" | \"diverges\" | \"incomplete\" | \"empty-plan\";\n\nexport interface VerifyReport {\n planned: { label: string; elements: number; relationships: number };\n against: { label: string; kind: BuiltSide[\"kind\"] };\n verdict: Verdict;\n verdictText: string;\n summary: { elements: CategoryCounts; relationships: CategoryCounts };\n elements: {\n matched: ElementMatch[];\n divergent: DivergentElement[];\n missing: MissingElement[];\n unplanned: UnplannedElement[];\n deletionsNotDone: DeletionNotDone[];\n };\n relationships: {\n matched: RelationshipMatch[];\n divergent: DivergentRelationship[];\n missing: MissingRelationship[];\n unplanned: UnplannedRelationship[];\n deletionsNotDone: RelationshipDeletionNotDone[];\n };\n notes: string[];\n}\n\nexport interface VerifyOptions {\n /** Match elements of the same layer and type that share a source file (default true). */\n matchBySource?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Planned side\n// ---------------------------------------------------------------------------\n\n/**\n * The net changes of a changeset, replayed in sequence order: an add later updated is an add, an\n * add later deleted is nothing, a relationship added and then removed is nothing.\n *\n * `resolve` maps UUIDs to dotted paths (pass `graph.resolve` from the changeset's own graph);\n * `lookup` supplies an element's record when a delete carries no `before` snapshot.\n */\nexport function planFromChangeset(\n changeset: Changeset,\n context: { resolve?: (id: string) => string; lookup?: (id: string) => GraphElement | undefined } = {}\n): Plan {\n const resolve = context.resolve ?? ((id: string) => id);\n const notes: string[] = [];\n const elements = new Map<string, PlannedElementChange & { before?: VerifyElement }>();\n const relationships = new Map<string, PlannedRelationshipChange>();\n\n const changes = [...(changeset.changes as StagedChange[])]\n .map((change, index) => ({ change, index }))\n .sort((a, b) => (a.change.sequenceNumber ?? a.index) - (b.change.sequenceNumber ?? b.index));\n\n for (const { change, index } of changes) {\n const where = `change #${change.sequenceNumber ?? index} (${change.type} ${change.elementId})`;\n\n if (change.type === \"relationship-add\" || change.type === \"relationship-delete\") {\n const rel = readRelationship(change, resolve);\n if (!rel) {\n notes.push(`Skipped ${where}: it does not name a source, predicate and target.`);\n continue;\n }\n const key = relKey(rel);\n const previous = relationships.get(key);\n if (change.type === \"relationship-add\") {\n // Re-adding a relationship this changeset removed restores it: no net change.\n if (previous?.op === \"delete\") relationships.delete(key);\n else relationships.set(key, { ...rel, op: \"add\" });\n } else {\n if (previous?.op === \"add\") relationships.delete(key);\n else relationships.set(key, { ...rel, op: \"delete\" });\n }\n continue;\n }\n\n const id = resolve(change.elementId);\n const previous = elements.get(id);\n\n if (change.type === \"add\" || change.type === \"update\") {\n if (!change.after) {\n notes.push(`Skipped ${where}: it has no element data.`);\n continue;\n }\n const record = toVerifyElement(change.after, change.layerName, id);\n if (change.type === \"add\" && previous?.op !== \"delete\") {\n elements.set(id, { ...record, op: \"add\" });\n } else if (previous?.op === \"add\") {\n elements.set(id, { ...record, op: \"add\" });\n } else {\n const before =\n previous?.before ??\n (change.before ? toVerifyElement(change.before, change.layerName, id) : undefined);\n const fields = before ? changedFields(before, record) : undefined;\n elements.set(id, {\n ...record,\n op: \"update\",\n ...(before && fields\n ? { before, changedFields: fields, baseValues: Object.fromEntries(fields.map((f) => [f, fieldValue(before, f)])) }\n : {}),\n });\n }\n continue;\n }\n\n if (change.type === \"delete\") {\n if (previous?.op === \"add\") {\n elements.delete(id);\n continue;\n }\n const known = context.lookup?.(id);\n const before =\n previous?.before ??\n (change.before\n ? toVerifyElement(change.before, change.layerName, id)\n : known\n ? fromGraphElement(known)\n : fromId(id, change.layerName));\n elements.set(id, { ...before, id, op: \"delete\", before });\n continue;\n }\n\n notes.push(`Skipped ${where}: unknown change type.`);\n }\n\n return {\n label: changeset.name,\n elements: [...elements.values()].map(({ before: _before, ...rest }) => rest),\n relationships: [...relationships.values()],\n notes,\n };\n}\n\n/** The planned side of a changeset, read through its projected graph over the model. */\nexport async function planFromModel(model: Model, changeset: Changeset): Promise<Plan> {\n const graph = await ChangesetGraph.build(model, changeset);\n return planFromChangeset(changeset, {\n resolve: (id) => graph.resolve(id),\n lookup: (id) => graph.getElement(id),\n });\n}\n\n// ---------------------------------------------------------------------------\n// Built side\n// ---------------------------------------------------------------------------\n\n/** The built world of an as-built changeset: base + its changes, with what it changed. */\nexport function builtFromGraph(graph: ChangesetGraph, label = graph.changeset.name): BuiltSide {\n const elements: BuiltElement[] = [];\n const changedElements: BuiltElement[] = [];\n for (const element of graph.elements.values()) {\n const built: BuiltElement = {\n ...fromGraphElement(element),\n ...(element.status !== \"unchanged\" ? { change: element.status } : {}),\n };\n if (element.status !== \"deleted\") elements.push(built);\n if (element.status !== \"unchanged\") changedElements.push(built);\n }\n\n const relationships: BuiltRelationship[] = [];\n const changedRelationships: BuiltRelationship[] = [];\n for (const rel of graph.relationships()) {\n const built: BuiltRelationship = {\n source: rel.source,\n predicate: rel.predicate,\n target: rel.target,\n ...(rel.status !== \"unchanged\" ? { change: rel.status } : {}),\n };\n if (rel.status !== \"deleted\") relationships.push(built);\n if (rel.status !== \"unchanged\") changedRelationships.push(built);\n }\n\n return { label, kind: \"changeset\", elements, relationships, changedElements, changedRelationships, notes: [] };\n}\n\n/** The base model as the built world. What the build changed is not known. */\nexport async function builtFromBase(model: Model): Promise<BuiltSide> {\n const now = new Date().toISOString();\n const empty = new Changeset({\n id: \"base\",\n name: \"base model\",\n created: now,\n modified: now,\n status: \"committed\",\n baseSnapshot: \"\",\n changes: [],\n });\n const graph = await ChangesetGraph.build(model, empty);\n const side = builtFromGraph(graph, \"base model\");\n return {\n label: \"base model\",\n kind: \"base\",\n elements: side.elements,\n relationships: side.relationships,\n notes: [\n \"Compared with the base model: what the build changed is not recorded, so unplanned changes are limited \" +\n \"to relationships the build gave the elements this plan adds. Compare with an as-built changeset for \" +\n \"a full list.\",\n ],\n };\n}\n\n/**\n * A built side from plain elements and relationships, e.g. the output of an extraction pass.\n * With `allChanged`, every element and relationship given counts as a change of the build (an\n * extraction scoped to the branch's diff); otherwise they are the built world only.\n */\nexport function builtFromSnapshot(snapshot: {\n label: string;\n elements: BuiltElement[];\n relationships: BuiltRelationship[];\n allChanged?: boolean;\n notes?: string[];\n}): BuiltSide {\n const elements = snapshot.elements.filter((e) => e.change !== \"deleted\");\n const relationships = snapshot.relationships.filter((r) => r.change !== \"deleted\");\n return {\n label: snapshot.label,\n kind: \"snapshot\",\n elements,\n relationships,\n ...(snapshot.allChanged\n ? {\n changedElements: snapshot.elements.map((e) => ({ ...e, change: e.change ?? \"added\" })),\n changedRelationships: snapshot.relationships.map((r) => ({ ...r, change: r.change ?? \"added\" })),\n }\n : {}),\n notes: snapshot.notes ?? [],\n };\n}\n\n// ---------------------------------------------------------------------------\n// Verify\n// ---------------------------------------------------------------------------\n\nexport function verifyChangeset(plan: Plan, built: BuiltSide, options: VerifyOptions = {}): VerifyReport {\n const matchBySource = options.matchBySource ?? true;\n const notes = [...plan.notes, ...built.notes];\n\n const builtById = new Map(built.elements.map((e) => [e.id, e]));\n const changedIds = new Set((built.changedElements ?? []).map((e) => e.id));\n const claimed = new Set<string>();\n /** planned id \u2192 built id, with how it matched. */\n const elementMap = new Map<string, { built: string; match: MatchKind; reason?: string }>();\n\n const report: VerifyReport = {\n planned: { label: plan.label, elements: plan.elements.length, relationships: plan.relationships.length },\n against: { label: built.label, kind: built.kind },\n verdict: \"match\",\n verdictText: \"\",\n summary: { elements: emptyCounts(), relationships: emptyCounts() },\n elements: { matched: [], divergent: [], missing: [], unplanned: [], deletionsNotDone: [] },\n relationships: { matched: [], divergent: [], missing: [], unplanned: [], deletionsNotDone: [] },\n notes,\n };\n\n // --- Elements: exact ids first, so a fuzzy match never takes an element another plan entry names.\n const live = plan.elements.filter((e) => e.op !== \"delete\");\n const deletions = plan.elements.filter((e) => e.op === \"delete\");\n\n for (const planned of live) {\n if (builtById.has(planned.id)) {\n claimed.add(planned.id);\n elementMap.set(planned.id, { built: planned.id, match: \"exact\" });\n }\n }\n\n const pending = live.filter((e) => !elementMap.has(e.id));\n const ambiguous = new Map<string, string[]>();\n const tiers: Array<{\n test: (planned: VerifyElement, candidate: VerifyElement) => boolean;\n reason: (planned: VerifyElement, candidate: VerifyElement) => string;\n }> = [\n {\n test: (p, c) => p.layer === c.layer && sameType(p, c) && namesMatch(p, c),\n reason: (p, c) =>\n `same layer and type, name matches ignoring case and separators (\"${p.name}\" ~ \"${c.name}\")`,\n },\n {\n test: (p, c) => p.layer === c.layer && !sameType(p, c) && namesMatch(p, c),\n reason: (p, c) => `same layer and name, but built as ${c.type} instead of ${p.type}`,\n },\n ];\n if (matchBySource) {\n tiers.push({\n test: (p, c) => p.layer === c.layer && sameType(p, c) && sharesSourceFile(p, c),\n reason: (p, c) => `same layer and type, shares source file ${sharedSourceFiles(p, c).join(\", \")}`,\n });\n }\n\n // A planned add cannot have been built as an element that existed before the plan. With the plan's\n // base index that is exact; without one, an unchanged element with no relationship to the plan's\n // elements is taken to predate it.\n const baseIds = plan.baseElementIds ? new Set(plan.baseElementIds) : undefined;\n const builtNeighbors = new Map<string, Set<string>>();\n for (const rel of built.relationships) {\n for (const [a, b] of [\n [rel.source, rel.target],\n [rel.target, rel.source],\n ]) {\n const set = builtNeighbors.get(a) ?? new Set<string>();\n set.add(b);\n builtNeighbors.set(a, set);\n }\n }\n const planTouched = new Set<string>([\n ...plan.elements.map((e) => e.id),\n ...plan.relationships.flatMap((r) => [r.source, r.target]),\n ]);\n const neighborCache = new Map<string, Set<string>>();\n const plannedNeighbors = (id: string): Set<string> => {\n const cached = neighborCache.get(id);\n if (cached) return cached;\n const own = plan.relationships\n .filter((r) => r.op === \"add\" && (r.source === id || r.target === id))\n .map((r) => (r.source === id ? r.target : r.source));\n const ids = own.length > 0 ? own : [...planTouched].filter((other) => other !== id);\n const near = new Set(ids.flatMap((other) => [other, elementMap.get(other)?.built ?? other]));\n neighborCache.set(id, near);\n return near;\n };\n let fellBack = false;\n const canBeBuildOf = (planned: PlannedElementChange, candidate: VerifyElement): boolean => {\n if (planned.op !== \"add\") return true;\n if (baseIds) return !baseIds.has(candidate.id);\n if (changedIds.has(candidate.id)) return true;\n fellBack = true;\n const near = plannedNeighbors(planned.id);\n for (const other of builtNeighbors.get(candidate.id) ?? []) if (near.has(other)) return true;\n return false;\n };\n\n for (const tier of tiers) {\n for (const planned of pending) {\n if (elementMap.has(planned.id)) continue;\n const candidates = built.elements.filter(\n (c) => !claimed.has(c.id) && tier.test(planned, c) && canBeBuildOf(planned, c)\n );\n if (candidates.length === 0) continue;\n let chosen = candidates;\n if (chosen.length > 1 && changedIds.size > 0) {\n const changed = chosen.filter((c) => changedIds.has(c.id));\n if (changed.length > 0) chosen = changed;\n }\n if (chosen.length === 1) {\n const candidate = chosen[0];\n claimed.add(candidate.id);\n elementMap.set(planned.id, { built: candidate.id, match: \"probable\", reason: tier.reason(planned, candidate) });\n ambiguous.delete(planned.id);\n } else if (!ambiguous.has(planned.id)) {\n ambiguous.set(\n planned.id,\n chosen.map((c) => c.id)\n );\n }\n }\n }\n\n if (fellBack) {\n notes.push(\n `No base index was recorded for ${plan.label}, so the elements that existed before it are not known exactly: ` +\n \"unchanged elements with no relationship to the plan's elements were not considered as the built form of \" +\n \"a planned add.\"\n );\n }\n\n const lifecycleMoves: string[] = [];\n for (const planned of live) {\n const mapping = elementMap.get(planned.id);\n if (!mapping) {\n const candidates = ambiguous.get(planned.id);\n report.elements.missing.push({\n planned: planned.id,\n layer: planned.layer,\n type: planned.type,\n name: planned.name,\n op: planned.op,\n reason: candidates\n ? `several built elements could be it (${candidates.length}); none matched uniquely`\n : planned.op === \"update\"\n ? \"the element the plan updates does not exist in the build\"\n : \"not found in the build by id, name or source file\",\n ...(candidates ? { candidates } : {}),\n });\n continue;\n }\n\n const builtElement = builtById.get(mapping.built)!;\n const fields = compareElements(planned, builtElement, planned.op === \"update\" ? planned.changedFields : undefined);\n const match: ElementMatch = {\n planned: planned.id,\n built: mapping.built,\n op: planned.op,\n match: mapping.match,\n ...(mapping.reason ? { reason: mapping.reason } : {}),\n };\n\n if (planned.op === \"update\" && planned.changedFields && planned.changedFields.length > 0) {\n const unmet = fields.filter((f) => planned.changedFields!.includes(f.field));\n // Missing only when the build left every field the plan changes alone. A field the build changed\n // to something else is a divergence, reported below with both values.\n const touched = unmet.some((f) => buildTouched(planned, builtElement, f.field));\n if (unmet.length === planned.changedFields.length && !touched) {\n report.elements.missing.push({\n planned: planned.id,\n layer: planned.layer,\n type: planned.type,\n name: planned.name,\n op: planned.op,\n reason: \"the element exists but the build does not carry the planned update\",\n fields: unmet,\n });\n continue;\n }\n }\n\n const lifecycle = fields.filter(isLifecycleMove);\n const differences = fields.filter((f) => !isLifecycleMove(f));\n if (lifecycle.length > 0) {\n match.lifecycle = lifecycle;\n for (const f of lifecycle) {\n lifecycleMoves.push(`${planned.id} ${f.field} ${String(f.planned)} \u2192 ${String(f.built)}`);\n }\n }\n if (differences.length > 0) report.elements.divergent.push({ ...match, fields: differences });\n else report.elements.matched.push(match);\n }\n\n if (lifecycleMoves.length > 0) {\n notes.push(\n `Lifecycle progress, not counted as divergence (${LIFECYCLE_FIELDS.join(\", \")} moving to a later stage of ` +\n `${LIFECYCLE_STAGES.map((stage) => stage.join(\"/\")).join(\" \u2192 \")}): ${lifecycleMoves.join(\"; \")}.`\n );\n }\n\n for (const planned of deletions) {\n const still = builtById.get(planned.id);\n if (still) {\n claimed.add(still.id);\n report.elements.deletionsNotDone.push({ planned: planned.id, built: still.id });\n } else {\n claimed.add(planned.id);\n report.elements.matched.push({ planned: planned.id, built: planned.id, op: \"delete\", match: \"exact\" });\n }\n }\n\n if (built.changedElements) {\n for (const element of built.changedElements) {\n if (claimed.has(element.id)) continue;\n report.elements.unplanned.push({\n id: element.id,\n layer: element.layer,\n type: element.type,\n name: element.name,\n change: element.change ?? \"added\",\n });\n }\n }\n\n // --- Relationships, through the element matches.\n const builtRels = new Map(built.relationships.map((r) => [relKey(r), r]));\n const claimedRels = new Set<string>();\n const mapId = (id: string) => elementMap.get(id)?.built ?? id;\n const probableEndpoints = (rel: VerifyRelationship): string[] =>\n [rel.source, rel.target]\n .filter((id, i, all) => all.indexOf(id) === i)\n .filter((id) => elementMap.get(id)?.match === \"probable\")\n .map((id) => `${id} \u2192 ${elementMap.get(id)!.built}`);\n const missingEndpoints = new Set(report.elements.missing.map((m) => m.planned));\n\n const mapRel = (planned: PlannedRelationshipChange): VerifyRelationship => ({\n source: mapId(planned.source),\n predicate: planned.predicate,\n target: mapId(planned.target),\n });\n const matchInfoFor = (planned: PlannedRelationshipChange) => {\n const probable = probableEndpoints(planned);\n return probable.length > 0\n ? { match: \"probable\" as const, reason: `through probable element match: ${probable.join(\"; \")}` }\n : { match: \"exact\" as const };\n };\n\n // Pass 1: exact (source, predicate, target) hits, so the fallback below can never take a built\n // relationship that another planned relationship matches exactly.\n const unresolved: PlannedRelationshipChange[] = [];\n for (const planned of plan.relationships) {\n const mapped = mapRel(planned);\n const found = builtRels.get(relKey(mapped));\n if (!found || claimedRels.has(relKey(found))) {\n unresolved.push(planned);\n continue;\n }\n claimedRels.add(relKey(found));\n const plannedRef = strip(planned);\n if (planned.op === \"delete\") {\n report.relationships.deletionsNotDone.push({ planned: plannedRef, built: strip(found) });\n } else {\n report.relationships.matched.push({ planned: plannedRef, built: strip(found), op: \"add\", ...matchInfoFor(planned) });\n }\n }\n\n // Elements the plan adds, as built: a relationship touching one cannot predate the change.\n const addedBuiltIds = new Set(\n live.filter((e) => e.op === \"add\" && elementMap.has(e.id)).map((e) => elementMap.get(e.id)!.built)\n );\n\n // Pass 2: everything without an exact hit.\n for (const planned of unresolved) {\n const mapped = mapRel(planned);\n const plannedRef = strip(planned);\n const matchInfo = matchInfoFor(planned);\n\n if (planned.op === \"delete\") {\n claimedRels.add(relKey(mapped));\n report.relationships.matched.push({ planned: plannedRef, built: mapped, op: \"delete\", ...matchInfo });\n continue;\n }\n\n // Same endpoints, another predicate; or the same predicate the other way round.\n // Prefer what the build changed: an untouched base relationship is not the build's version of this one.\n const isAlternative = (r: VerifyRelationship) =>\n !claimedRels.has(relKey(r)) &&\n ((r.source === mapped.source && r.target === mapped.target && r.predicate !== mapped.predicate) ||\n (r.source === mapped.target && r.target === mapped.source && r.predicate === mapped.predicate));\n const alternative = built.changedRelationships\n ? built.changedRelationships.filter((r) => r.change !== \"deleted\").find(isAlternative)\n : // What the build changed is not known: only a relationship touching an element the plan adds\n // can be the build's version; one between pre-existing elements may simply predate the change.\n built.relationships.find(\n (r) => isAlternative(r) && (addedBuiltIds.has(r.source) || addedBuiltIds.has(r.target))\n );\n if (alternative) {\n claimedRels.add(relKey(alternative));\n const fields: FieldDifference[] =\n alternative.predicate !== mapped.predicate\n ? [{ field: \"predicate\", planned: mapped.predicate, built: alternative.predicate }]\n : [\n {\n field: \"direction\",\n planned: `${mapped.source} \u2192 ${mapped.target}`,\n built: `${alternative.source} \u2192 ${alternative.target}`,\n },\n ];\n report.relationships.divergent.push({\n planned: plannedRef,\n built: strip(alternative),\n op: \"add\",\n ...matchInfo,\n fields,\n });\n continue;\n }\n\n // Near matches that may predate the change: listed, not claimed.\n const candidates = built.changedRelationships ? [] : built.relationships.filter(isAlternative).map(strip);\n const absent = [planned.source, planned.target].filter(\n (id) => missingEndpoints.has(id) || (!elementMap.has(id) && !builtById.has(id))\n );\n report.relationships.missing.push({\n planned: plannedRef,\n reason:\n absent.length > 0\n ? `not built; endpoint${absent.length > 1 ? \"s\" : \"\"} ${absent.join(\", \")} not found in the build`\n : candidates.length > 0\n ? \"not found in the build; a relationship between the same elements exists, but it may predate the change\"\n : \"not found in the build\",\n ...(candidates.length > 0 ? { candidates } : {}),\n });\n }\n\n if (built.changedRelationships) {\n for (const rel of built.changedRelationships) {\n if (claimedRels.has(relKey(rel))) continue;\n report.relationships.unplanned.push({ ...strip(rel), change: rel.change ?? \"added\" });\n }\n } else {\n // Base model: relationships the build gave the elements this plan adds, beyond the plan's own.\n for (const rel of built.relationships) {\n if (claimedRels.has(relKey(rel))) continue;\n if (addedBuiltIds.has(rel.source) || addedBuiltIds.has(rel.target)) {\n report.relationships.unplanned.push({ ...strip(rel), change: \"present\" });\n }\n }\n }\n\n report.summary.elements = countCategories(plan.elements.length, report.elements);\n report.summary.relationships = countCategories(plan.relationships.length, report.relationships);\n const { verdict, text } = decideVerdict(report);\n report.verdict = verdict;\n report.verdictText = text;\n return report;\n}\n\n/**\n * Verifies a planned changeset against an as-built changeset or the base model of `model`.\n * Used by the `changeset_verify` MCP tool and `dr changeset verify`.\n */\nexport async function verifyChangesetInModel(\n model: Model,\n options: {\n planned: Changeset;\n against: { changeset: Changeset } | { base: true };\n matchBySource?: boolean;\n }\n): Promise<VerifyReport & { plannedChangeset: { id: string; name: string } }> {\n const { planned } = options;\n const plan = await planFromModel(model, planned);\n const notes: string[] = [];\n const baseIndex = await tryReadBaseIndex(model.rootPath, planned.id);\n if (baseIndex.index) plan.baseElementIds = Object.keys(baseIndex.index.elements);\n if (baseIndex.warning) notes.push(baseIndex.warning);\n\n let built: BuiltSide;\n if (\"changeset\" in options.against) {\n const asBuilt = options.against.changeset;\n if (asBuilt.id === planned.id) {\n notes.push(\"The planned and as-built changesets are the same changeset, so everything matches by definition.\");\n }\n built = builtFromGraph(await ChangesetGraph.build(model, asBuilt), `${asBuilt.name} (${asBuilt.id})`);\n } else {\n built = await builtFromBase(model);\n if (planned.status === \"staged\") {\n notes.push(\n \"The planned changeset is still staged, so its own changes are not in the base model: anything \" +\n \"reported missing is missing from what was committed to the base (e.g. an as-built changeset).\"\n );\n }\n }\n\n const report = verifyChangeset(plan, built, { matchBySource: options.matchBySource });\n report.notes.push(...notes);\n return { plannedChangeset: { id: planned.id, name: planned.name }, ...report };\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Lowercase with every non-alphanumeric removed: \"Export Orders\", \"export-orders\", \"exportOrders\" \u2192 \"exportorders\". */\nexport function normalizeName(name: string): string {\n return name.toLowerCase().replace(/[^a-z0-9]/g, \"\");\n}\n\nfunction nameKeys(element: VerifyElement): Set<string> {\n const keys = new Set<string>();\n if (element.name) keys.add(normalizeName(element.name));\n const segment = idNameSegment(element.id);\n if (segment) keys.add(normalizeName(segment));\n keys.delete(\"\");\n return keys;\n}\n\nfunction namesMatch(a: VerifyElement, b: VerifyElement): boolean {\n const keys = nameKeys(b);\n for (const key of nameKeys(a)) if (keys.has(key)) return true;\n return false;\n}\n\nfunction sameType(a: VerifyElement, b: VerifyElement): boolean {\n return normalizeName(a.type) === normalizeName(b.type);\n}\n\nfunction sourceFiles(element: VerifyElement): string[] {\n return (element.sourceReference?.locations ?? [])\n .map((l) => (typeof l?.file === \"string\" ? l.file.replace(/^\\.\\//, \"\").replace(/\\\\/g, \"/\") : \"\"))\n .filter((f) => f.length > 0);\n}\n\nfunction sharedSourceFiles(a: VerifyElement, b: VerifyElement): string[] {\n const files = new Set(sourceFiles(b));\n return sourceFiles(a).filter((f) => files.has(f));\n}\n\nfunction sharesSourceFile(a: VerifyElement, b: VerifyElement): boolean {\n return sharedSourceFiles(a, b).length > 0;\n}\n\n/**\n * Fields where the built element differs from what the plan states. Only what the plan states is\n * compared: a description or attribute the build adds beyond the plan is not a divergence. The\n * exception is `removedBy`: fields a planned update changes that the planned record no longer has\n * (an attribute removed, a description cleared). The build must not have them either.\n */\nfunction compareElements(planned: VerifyElement, built: VerifyElement, removedBy?: string[]): FieldDifference[] {\n const fields: FieldDifference[] = [];\n if (planned.type && !sameType(planned, built)) {\n fields.push({ field: \"type\", planned: planned.type, built: built.type });\n }\n if (planned.name && normalizeName(planned.name) !== normalizeName(built.name)) {\n fields.push({ field: \"name\", planned: planned.name, built: built.name });\n }\n if (planned.description !== undefined && planned.description.trim() !== (built.description ?? \"\").trim()) {\n fields.push({ field: \"description\", planned: planned.description, built: built.description });\n }\n for (const [key, value] of Object.entries(planned.attributes ?? {})) {\n const builtValue = built.attributes?.[key];\n if (!sameValue(value, builtValue)) {\n fields.push({ field: `attributes.${key}`, planned: value, built: builtValue });\n }\n }\n for (const field of removedBy ?? []) {\n if (field === \"description\") {\n if (planned.description === undefined && (built.description ?? \"\").trim() !== \"\") {\n fields.push({ field, planned: undefined, built: built.description });\n }\n } else if (field.startsWith(\"attributes.\")) {\n const key = field.slice(\"attributes.\".length);\n const plannedHas = planned.attributes !== undefined && Object.hasOwn(planned.attributes, key);\n if (!plannedHas && built.attributes?.[key] !== undefined) {\n fields.push({ field, planned: undefined, built: built.attributes[key] });\n }\n }\n }\n return fields;\n}\n\n/** A field's value on an element, by the names `compareElements` and `changedFields` use. */\nfunction fieldValue(element: VerifyElement, field: string): unknown {\n if (field === \"type\") return element.type;\n if (field === \"name\") return element.name;\n if (field === \"description\") return element.description;\n if (field.startsWith(\"attributes.\")) return element.attributes?.[field.slice(\"attributes.\".length)];\n return undefined;\n}\n\nfunction sameFieldValue(field: string, a: unknown, b: unknown): boolean {\n if (field === \"type\" || field === \"name\") {\n return normalizeName(String(a ?? \"\")) === normalizeName(String(b ?? \"\"));\n }\n if (field === \"description\") return String(a ?? \"\").trim() === String(b ?? \"\").trim();\n return sameValue(a, b);\n}\n\n/**\n * Whether the build changed `field` from what it was before the plan. Uses the plan's recorded base\n * value; without one, falls back to whether the build changed the element at all (unknown against\n * the base model, where it counts as untouched).\n */\nfunction buildTouched(planned: PlannedElementChange, built: BuiltElement, field: string): boolean {\n if (planned.baseValues && Object.hasOwn(planned.baseValues, field)) {\n return !sameFieldValue(field, fieldValue(built, field), planned.baseValues[field]);\n }\n return built.change === \"updated\" || built.change === \"added\";\n}\n\nfunction changedFields(before: VerifyElement, after: VerifyElement): string[] {\n const fields: string[] = [];\n if (before.type !== after.type) fields.push(\"type\");\n if (before.name !== after.name) fields.push(\"name\");\n if ((before.description ?? \"\") !== (after.description ?? \"\")) fields.push(\"description\");\n const keys = new Set([...Object.keys(before.attributes ?? {}), ...Object.keys(after.attributes ?? {})]);\n for (const key of keys) {\n if (!sameValue(before.attributes?.[key], after.attributes?.[key])) fields.push(`attributes.${key}`);\n }\n return fields;\n}\n\nfunction sameValue(a: unknown, b: unknown): boolean {\n return stableStringify(a) === stableStringify(b);\n}\n\nfunction stableStringify(value: unknown): string {\n if (value === undefined) return \"undefined\";\n if (value === null || typeof value !== \"object\") return JSON.stringify(value);\n if (Array.isArray(value)) return `[${value.map(stableStringify).join(\",\")}]`;\n const entries = Object.keys(value as Record<string, unknown>)\n .sort()\n .map((k) => `${JSON.stringify(k)}:${stableStringify((value as Record<string, unknown>)[k])}`);\n return `{${entries.join(\",\")}}`;\n}\n\nfunction relKey(rel: VerifyRelationship): string {\n return `${rel.source}::${rel.predicate}::${rel.target}`;\n}\n\nfunction strip(rel: VerifyRelationship): VerifyRelationship {\n return { source: rel.source, predicate: rel.predicate, target: rel.target };\n}\n\nfunction readRelationship(change: StagedChange, resolve: (id: string) => string): VerifyRelationship | null {\n const data = (change.type === \"relationship-delete\" ? (change.before ?? change.after) : change.after) as\n | Partial<GraphRelationship>\n | undefined;\n const [source, predicate, target] =\n data?.source && data.predicate && data.target\n ? [data.source, data.predicate, data.target]\n : change.elementId.split(\"::\");\n if (!source || !predicate || !target) return null;\n return { source: resolve(source), predicate, target: resolve(target) };\n}\n\nfunction idNameSegment(id: string): string | undefined {\n const parts = id.split(\".\");\n return parts.length >= 3 ? parts.slice(2).join(\".\") : undefined;\n}\n\nfunction fromId(id: string, layerName: string): VerifyElement {\n const parts = id.split(\".\");\n return {\n id,\n layer: parts.length >= 3 ? parts[0] : layerName,\n type: parts.length >= 3 ? parts[1] : \"\",\n name: idNameSegment(id) ?? id,\n attributes: {},\n };\n}\n\nfunction fromGraphElement(element: GraphElement): VerifyElement {\n return {\n id: element.id,\n layer: element.layer,\n type: element.type,\n name: element.name,\n ...(element.description !== undefined ? { description: element.description } : {}),\n attributes: element.attributes ?? {},\n ...(element.sourceReference ? { sourceReference: element.sourceReference } : {}),\n };\n}\n\nfunction toVerifyElement(record: Record<string, unknown>, layerName: string, id: string): VerifyElement {\n const str = (value: unknown): string | undefined =>\n typeof value === \"string\" && value.length > 0 ? value : undefined;\n const fallback = fromId(id, layerName);\n return {\n id,\n layer: str(record.layer_id) ?? str(record.layer) ?? fallback.layer,\n type: str(record.type) ?? fallback.type,\n name: str(record.name) ?? fallback.name,\n ...(str(record.description) !== undefined ? { description: str(record.description) } : {}),\n attributes:\n record.attributes && typeof record.attributes === \"object\"\n ? (record.attributes as Record<string, unknown>)\n : {},\n ...(stagedSourceReference(record) ? { sourceReference: stagedSourceReference(record) } : {}),\n };\n}\n\nfunction emptyCounts(): CategoryCounts {\n return { planned: 0, matched: 0, probable: 0, missing: 0, divergent: 0, unplanned: 0, deletionsNotDone: 0 };\n}\n\nfunction countCategories(\n planned: number,\n section: {\n matched: Array<{ match: MatchKind }>;\n divergent: Array<{ match: MatchKind }>;\n missing: unknown[];\n unplanned: unknown[];\n deletionsNotDone: unknown[];\n }\n): CategoryCounts {\n return {\n planned,\n matched: section.matched.length + section.divergent.length,\n probable: [...section.matched, ...section.divergent].filter((m) => m.match === \"probable\").length,\n missing: section.missing.length,\n divergent: section.divergent.length,\n unplanned: section.unplanned.length,\n deletionsNotDone: section.deletionsNotDone.length,\n };\n}\n\nfunction decideVerdict(report: VerifyReport): { verdict: Verdict; text: string } {\n const e = report.summary.elements;\n const r = report.summary.relationships;\n if (e.planned === 0 && r.planned === 0) {\n return { verdict: \"empty-plan\", text: \"The plan has no changes to verify.\" };\n }\n\n const parts: string[] = [];\n const say = (n: number, what: string) => {\n if (n > 0) parts.push(`${n} ${what}`);\n };\n say(e.missing, plural(e.missing, \"planned element\", \"planned elements\") + \" missing\");\n say(r.missing, plural(r.missing, \"planned relationship\", \"planned relationships\") + \" missing\");\n say(e.deletionsNotDone + r.deletionsNotDone, \"planned deletion(s) not done\");\n say(e.divergent, plural(e.divergent, \"element differs\", \"elements differ\"));\n say(r.divergent, plural(r.divergent, \"relationship differs\", \"relationships differ\"));\n say(e.unplanned, plural(e.unplanned, \"unplanned element change\", \"unplanned element changes\"));\n say(r.unplanned, plural(r.unplanned, \"unplanned relationship\", \"unplanned relationships\"));\n\n const probable = e.probable + r.probable;\n const probableText = probable > 0 ? ` ${probable} match(es) are probable, not exact; confirm them.` : \"\";\n\n if (e.missing + r.missing + e.deletionsNotDone + r.deletionsNotDone > 0) {\n return { verdict: \"incomplete\", text: `The build is incomplete: ${parts.join(\", \")}.${probableText}` };\n }\n if (e.divergent + r.divergent + e.unplanned + r.unplanned > 0) {\n return { verdict: \"diverges\", text: `The build diverges from the plan: ${parts.join(\", \")}.${probableText}` };\n }\n if (probable > 0) {\n return { verdict: \"probable-match\", text: `Everything planned was found.${probableText}` };\n }\n return { verdict: \"match\", text: \"The build matches the plan.\" };\n}\n\nfunction plural(n: number, one: string, many: string): string {\n return n === 1 ? one : many;\n}\n"],
5
- "mappings": "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",
6
- "names": ["previous"]
4
+ "sourcesContent": ["/**\n * Changeset verify \u2014 compare what a change PLANNED (a staged changeset) with what was BUILT.\n *\n * The planned side is always a changeset: its net changes (adds, updates and deletes of elements and\n * relationships, replayed in sequence order). The built side is a `BuiltSide`, which can come from:\n *\n * - another changeset (`builtFromGraph`): an as-built changeset, normally written by\n * `codebase_extract`. The built world is the base model with that changeset applied, and what the\n * build changed is known, so unplanned changes are reported in full. When it came from extraction,\n * planned changes extraction can't produce are unverifiable, not missing (see\n * `extraction-observability.ts`).\n * - the base model (`builtFromBase`): e.g. after an as-built changeset was committed on the branch.\n * What the build changed is not known, so unplanned changes are limited to relationships the build\n * gave the elements the plan adds.\n * - a plain snapshot of elements and relationships (`builtFromSnapshot`), the shape an extraction\n * cascade can produce without writing a changeset first.\n *\n * Matching is tolerant of renames. Elements match by id first, then by layer + type + normalized\n * name, then by layer + normalized name with a different type, then (optionally) by layer + type +\n * shared source file. Anything other than an id match is reported as a probable match with its\n * reason, never as exact. Relationships match by (source, predicate, target) after mapping the\n * planned endpoints through the element matches, so a relationship between renamed elements still\n * matches (probably).\n *\n * Descriptions are not compared (prose against a docstring differs without the build being wrong):\n * a difference is a note on the match. A planned update that changes the description still has it\n * checked.\n *\n * See docs/CHANGE_MODELING.md (Verify).\n */\n\nimport { Changeset, type StagedChange } from \"./changeset.js\";\nimport { ChangesetGraph, type GraphElement, type GraphRelationship } from \"./changeset-graph.js\";\nimport type { Model } from \"./model.js\";\nimport type { SourceReference } from \"../types/source-reference.js\";\nimport { tryReadBaseIndex } from \"./changeset-base-index.js\";\nimport { stagedSourceReference } from \"./staged-source-reference.js\";\nimport { loadExtractionCoverage, type ExtractionCoverage } from \"./extraction-observability.js\";\nimport { currentGitHead, resolveAnalyzerName } from \"../analyzers/active-analyzer.js\";\nimport { decisionKey } from \"../analyzers/extraction-plan.js\";\nimport { readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\n/**\n * Attribute fields whose expected progress is not a divergence: a plan says `status: planned`, the\n * build says `delivered`. Only a move to a later stage of LIFECYCLE_STAGES counts; a move back, or\n * to a value outside them, stays a divergence.\n */\nexport const LIFECYCLE_FIELDS: readonly string[] = [\"attributes.status\"];\n\n/**\n * The stages of the spec's status enums, in order (values in one stage are alternatives from\n * different types: goals, product items, milestones, test cases). Off-ramps such as `deprecated`,\n * `abandoned`, `cancelled` and `at-risk` are not stages, so moving to one is reported as a divergence.\n */\nexport const LIFECYCLE_STAGES: readonly (readonly string[])[] = [\n [\"proposed\", \"draft\"],\n [\"planned\", \"under-review\"],\n [\"approved\", \"in-progress\", \"developing\", \"active\"],\n [\"implemented\", \"delivered\", \"achieved\", \"completed\"],\n [\"automated\"],\n];\n\nfunction lifecycleStage(value: unknown): number {\n if (typeof value !== \"string\") return -1;\n const v = value.trim().toLowerCase();\n return LIFECYCLE_STAGES.findIndex((stage) => stage.includes(v));\n}\n\n/** Whether a field difference is the build moving a lifecycle field to a later stage. */\nexport function isLifecycleMove(difference: FieldDifference): boolean {\n if (!LIFECYCLE_FIELDS.includes(difference.field)) return false;\n const from = lifecycleStage(difference.planned);\n const to = lifecycleStage(difference.built);\n return from >= 0 && to > from;\n}\n\n// ---------------------------------------------------------------------------\n// Shapes\n// ---------------------------------------------------------------------------\n\nexport interface VerifyElement {\n /** Dotted path (`layer.type.name`). */\n id: string;\n layer: string;\n type: string;\n name: string;\n description?: string;\n attributes: Record<string, unknown>;\n sourceReference?: SourceReference;\n}\n\nexport interface VerifyRelationship {\n source: string;\n predicate: string;\n target: string;\n}\n\nexport interface PlannedElementChange extends VerifyElement {\n op: \"add\" | \"update\" | \"delete\";\n /** For updates: the fields the plan changes (`description`, `attributes.priority`, ...). */\n changedFields?: string[];\n /** For updates: each changed field's value before the plan, to tell a build that left it alone from one that changed it differently. */\n baseValues?: Record<string, unknown>;\n}\n\nexport interface PlannedRelationshipChange extends VerifyRelationship {\n op: \"add\" | \"delete\";\n}\n\nexport interface Plan {\n label: string;\n elements: PlannedElementChange[];\n relationships: PlannedRelationshipChange[];\n /** Changes that could not be read, and anything else worth knowing about the plan. */\n notes: string[];\n /**\n * Ids of the elements the base model had when the plan was created (its base index). Such an\n * element cannot be the built form of a planned add. Undefined when no index was recorded.\n */\n baseElementIds?: string[];\n}\n\nexport type BuiltChange = \"added\" | \"updated\" | \"deleted\";\n\nexport interface BuiltElement extends VerifyElement {\n change?: BuiltChange;\n /**\n * The source provenance the as-built changeset itself staged: an add's, or an update's when the\n * update changed the source reference. Undefined when the change kept the base's source reference\n * (a hand update of an extracted base element is not extraction output).\n */\n stagedProvenance?: string;\n /**\n * For an update: the fields it changes from the base (`name`, `description`, `attributes.x`,\n * `source_reference`), each with its base value.\n */\n updatedFrom?: Record<string, unknown>;\n}\n\nexport interface BuiltRelationship extends VerifyRelationship {\n change?: Exclude<BuiltChange, \"updated\">;\n}\n\nexport interface BuiltSide {\n label: string;\n kind: \"changeset\" | \"base\" | \"snapshot\";\n /** Elements that exist in the built world. */\n elements: BuiltElement[];\n /** Relationships that exist in the built world. */\n relationships: BuiltRelationship[];\n /**\n * What the build changed, deletions included. Undefined when it is not known (the base model);\n * unplanned changes are then limited to the neighbourhood of the plan's additions.\n */\n changedElements?: BuiltElement[];\n changedRelationships?: BuiltRelationship[];\n notes: string[];\n}\n\nexport type MatchKind = \"exact\" | \"probable\";\n\nexport interface FieldDifference {\n field: string;\n planned: unknown;\n built: unknown;\n}\n\nexport interface ElementMatch {\n planned: string;\n built: string;\n op: PlannedElementChange[\"op\"];\n match: MatchKind;\n /** Why a probable match was made. */\n reason?: string;\n /** Expected lifecycle progress (see LIFECYCLE_FIELDS): reported, not counted as divergence. */\n lifecycle?: FieldDifference[];\n /**\n * Differences reported for information only, not divergence: the description (prose against a\n * docstring, or extraction's placeholder text). A planned update that changes the description\n * still has it checked.\n */\n notes?: FieldDifference[];\n /**\n * Against extraction: planned fields extraction never writes (the description, attributes the\n * node mapping doesn't fill) that the build left as they were. Not compared.\n */\n unverifiableFields?: FieldDifference[];\n /** The built element was not staged by extraction (see AsBuiltShare.agentAdded): no evidence about the code. */\n builtByAgent?: true;\n /** The built element was extracted, then its name or attributes were changed: the edits. */\n editedAfterExtraction?: ExtractionEdit[];\n}\n\nexport interface DivergentElement extends ElementMatch {\n fields: FieldDifference[];\n}\n\nexport interface MissingElement {\n planned: string;\n layer: string;\n type: string;\n name: string;\n op: PlannedElementChange[\"op\"];\n reason: string;\n /** Built elements that could be it, when matching was ambiguous. */\n candidates?: string[];\n /** For a planned update that the build does not carry: the fields it would have changed. */\n fields?: FieldDifference[];\n}\n\n/** A planned element the build can't show either way: extraction never produces it. */\nexport interface UnverifiableElement {\n planned: string;\n layer: string;\n type: string;\n name: string;\n op: PlannedElementChange[\"op\"];\n reason: string;\n /** For a planned update of a found element: the fields extraction doesn't write. */\n fields?: FieldDifference[];\n}\n\nexport interface UnplannedElement {\n id: string;\n layer: string;\n type: string;\n name: string;\n change: BuiltChange | \"present\";\n}\n\nexport interface DeletionNotDone {\n planned: string;\n built: string;\n}\n\nexport interface RelationshipMatch {\n planned: VerifyRelationship;\n built: VerifyRelationship;\n op: PlannedRelationshipChange[\"op\"];\n match: MatchKind;\n reason?: string;\n}\n\nexport interface DivergentRelationship extends RelationshipMatch {\n fields: FieldDifference[];\n}\n\nexport interface MissingRelationship {\n planned: VerifyRelationship;\n reason: string;\n /** Relationships between the same elements that may predate the change (built side without changes). */\n candidates?: VerifyRelationship[];\n}\n\n/** A planned relationship extraction can't produce: an end it can't see, or no code edge maps to it. */\nexport interface UnverifiableRelationship {\n planned: VerifyRelationship;\n op: PlannedRelationshipChange[\"op\"];\n reason: string;\n}\n\nexport interface UnplannedRelationship extends VerifyRelationship {\n change: Exclude<BuiltChange, \"updated\"> | \"present\";\n}\n\nexport interface RelationshipDeletionNotDone {\n planned: VerifyRelationship;\n built: VerifyRelationship;\n}\n\nexport interface CategoryCounts {\n planned: number;\n /** Planned changes found in the build, divergent ones included (`divergent` is the subset that differs). */\n matched: number;\n probable: number;\n missing: number;\n divergent: number;\n unplanned: number;\n deletionsNotDone: number;\n /** Planned changes extraction can't see; not part of the verdict. */\n unverifiable: number;\n}\n\nexport type Verdict = \"match\" | \"probable-match\" | \"diverges\" | \"incomplete\" | \"unverifiable\" | \"empty-plan\";\n\n/** How much of the as-built side came from extraction, and how much was added by hand. */\nexport interface AsBuiltShare {\n elements: {\n /** Elements the as-built changeset adds, updates or deletes. */\n total: number;\n /**\n * By the source provenance the changeset staged (`extracted`, `manual`, `inferred`, `generated`,\n * `none`), `sourceUnchanged` for updates that kept the base element's source reference, and\n * `deleted` for deletes. This is what was declared; `fromExtraction` is what extraction's own\n * record confirms.\n */\n byProvenance: Record<string, number>;\n /**\n * Confirmed by extraction's record (`.dr/analyzers/extract/<id>.json`): adds it staged, or the\n * agent staged from one of its cards; updates it staged (`updated`); deletes of its candidate\n * deletes.\n */\n fromExtraction: number;\n /** The rest: added, changed or deleted by the agent, whatever provenance they declare (see `agentAdded`). */\n agentAdded: number;\n };\n relationships: {\n /** Relationships the as-built changeset adds. */\n total: number;\n /** Between two elements confirmed from extraction (relationships record no provenance of their own). */\n betweenExtracted: number;\n /** Touching an element that did not come from extraction. */\n other: number;\n };\n /**\n * Whether codebase_extract's record of this changeset was found: its own (`found`), or the record\n * of a run that staged nothing, for the changeset of that name at the current commit (`pending`).\n * Without it nothing is confirmed.\n */\n record: \"found\" | \"pending\" | \"not-found\";\n /** Each element not confirmed from extraction: its declared provenance and why it doesn't count. */\n agentAdded?: Array<{ id: string; declared: string; reason: string }>;\n /**\n * Extracted elements changed after extraction staged them: an add whose name or attributes\n * differ from what it staged, or an update that changes a field extraction didn't, or holds a\n * value extraction didn't write. They count toward `fromExtraction` (coverage), but not as\n * evidence: their matches are marked `builtByAgent` with the edits, and they count toward the\n * warning.\n */\n editedAfterExtraction?: Array<{ id: string; edits: ExtractionEdit[] }>;\n /**\n * As-built elements, not from extraction, whose id the plan also adds: likely copied from the\n * plan, so their match says nothing about the code.\n */\n copiedFromPlan?: string[];\n}\n\n/** A field of an extracted element changed after extraction staged it. */\nexport interface ExtractionEdit {\n field: string;\n extracted: unknown;\n now: unknown;\n}\n\n/** A symbol extraction offered: a card, an earlier card, or a symbol it staged. */\nexport interface OfferedSymbol {\n file: string | null;\n symbol: string;\n label?: string;\n name?: string;\n candidates?: string[];\n hint?: string;\n proposed?: { id?: string; name?: string };\n}\n\n/**\n * What `codebase_extract` recorded about an as-built changeset (`.dr/analyzers/extract/<id>.json`,\n * or `pending.json` for a run that staged nothing): the elements it staged (with the name and\n * attributes it gave them, when recorded), the updates it staged, its candidate deletes, and the\n * cards of its runs. Only the fields verify reads.\n */\nexport interface ExtractionRecord {\n source: \"changeset\" | \"pending\";\n /** For a pending record read at another commit: the commit it was read at. */\n readAt?: string;\n staged: Array<OfferedSymbol & { id: string; attributes?: Record<string, unknown> }>;\n cards: OfferedSymbol[];\n /** Cards earlier runs returned that the agent has since modelled. */\n earlierCards: OfferedSymbol[];\n /**\n * Updates extraction itself staged, with the fields when recorded (`description`,\n * `attributes.http_path`, `source_reference`), an update folded into an add included.\n */\n updated: Array<{\n id: string;\n fields?: string[];\n /** The value extraction wrote for each field, keyed like `fields`, when recorded. */\n values?: Record<string, unknown>;\n }>;\n candidateDeletes: string[];\n}\n\nfunction readList<T>(value: unknown, keep: (entry: any) => boolean): T[] {\n return Array.isArray(value) ? (value.filter((e) => e && typeof e === \"object\" && keep(e)) as T[]) : [];\n}\n\nasync function readRecordFile(file: string): Promise<Record<string, unknown> | null> {\n try {\n const parsed = JSON.parse(await readFile(file, \"utf-8\"));\n return parsed && typeof parsed === \"object\" ? (parsed as Record<string, unknown>) : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Reads codebase_extract's record of a changeset; null when there is none. Without a record of its\n * own, the record of a run that staged nothing (`pending.json`) counts when it names this changeset.\n * When it was read at another commit than `gitHead` (the agent committed in between), `readAt` says\n * which, for a note.\n */\nexport async function readExtractionRecord(\n rootPath: string,\n changeset: { id: string; name: string },\n gitHead?: string | null\n): Promise<ExtractionRecord | null> {\n const dir = path.join(rootPath, \".dr\", \"analyzers\", \"extract\");\n let raw = await readRecordFile(path.join(dir, `${changeset.id.replace(/[^\\w.-]/g, \"_\")}.json`));\n let source: ExtractionRecord[\"source\"] = \"changeset\";\n if (raw && (raw.pending || (raw.changesetId !== undefined && raw.changesetId !== changeset.id))) raw = null;\n if (!raw) {\n const pending = await readRecordFile(path.join(dir, \"pending.json\"));\n if (pending?.pending && pending.changesetName === changeset.name) {\n raw = pending;\n source = \"pending\";\n }\n }\n if (!raw) return null;\n const symbol = (e: any) => typeof e.symbol === \"string\";\n const readAt = source === \"pending\" && typeof raw.gitHead === \"string\" && raw.gitHead !== gitHead ? raw.gitHead : undefined;\n return {\n source,\n ...(readAt ? { readAt } : {}),\n staged: readList(raw.staged, (e) => typeof e.id === \"string\"),\n cards: readList(raw.cards, symbol),\n earlierCards: readList(raw.earlierCards, symbol),\n updated: readList(raw.updated, (e) => typeof e.id === \"string\"),\n candidateDeletes: Array.isArray(raw.candidateDeletes) ? raw.candidateDeletes.filter((d): d is string => typeof d === \"string\") : [],\n };\n}\n\nexport interface VerifyExtraction {\n /** Whether extraction's blind spots were taken into account (the built side came from extraction). */\n applied: boolean;\n /** Why or why not. */\n reason: string;\n analyzer?: string;\n /** Element types the analyzer's extraction can produce. */\n observableTypes?: string[];\n asBuilt?: AsBuiltShare;\n}\n\n/** What extraction can see; given when the built side came from extraction. */\nexport interface ObservabilityCheck {\n /** `unlocated`: unobservable only for want of a method, path or source reference (see ObservabilityVerdict). */\n element(element: VerifyElement): { observable: boolean; reason?: string; unlocated?: true };\n relationship(source: VerifyElement, predicate: string, target: VerifyElement): { observable: boolean; reason?: string };\n /** Whether extraction writes this field (`description`, `attributes.x`, ...) of such an element. */\n field?(element: VerifyElement, field: string): boolean;\n}\n\nexport interface VerifyReport {\n planned: { label: string; elements: number; relationships: number };\n against: { label: string; kind: BuiltSide[\"kind\"] };\n verdict: Verdict;\n verdictText: string;\n summary: { elements: CategoryCounts; relationships: CategoryCounts };\n elements: {\n matched: ElementMatch[];\n divergent: DivergentElement[];\n missing: MissingElement[];\n unverifiable: UnverifiableElement[];\n unplanned: UnplannedElement[];\n deletionsNotDone: DeletionNotDone[];\n };\n relationships: {\n matched: RelationshipMatch[];\n divergent: DivergentRelationship[];\n missing: MissingRelationship[];\n unverifiable: UnverifiableRelationship[];\n unplanned: UnplannedRelationship[];\n deletionsNotDone: RelationshipDeletionNotDone[];\n };\n /** Whether extraction's blind spots were taken into account, and where the as-built side came from. */\n extraction?: VerifyExtraction;\n /**\n * Set when the comparison says little about the code: more than half of the as-built side was not\n * staged by extraction (added by the agent, or copied from the plan).\n */\n warning?: string;\n notes: string[];\n}\n\nexport interface VerifyOptions {\n /** Match elements of the same layer and type that share a source file (default true). */\n matchBySource?: boolean;\n /**\n * When the built side came from extraction: what extraction can see. A planned change it can't\n * see that the build lacks is reported as unverifiable, not missing, and left out of the verdict.\n */\n observability?: ObservabilityCheck;\n}\n\n// ---------------------------------------------------------------------------\n// Planned side\n// ---------------------------------------------------------------------------\n\n/**\n * The net changes of a changeset, replayed in sequence order: an add later updated is an add, an\n * add later deleted is nothing, a relationship added and then removed is nothing.\n *\n * `resolve` maps UUIDs to dotted paths (pass `graph.resolve` from the changeset's own graph);\n * `lookup` supplies an element's record when a delete carries no `before` snapshot.\n */\nexport function planFromChangeset(\n changeset: Changeset,\n context: { resolve?: (id: string) => string; lookup?: (id: string) => GraphElement | undefined } = {}\n): Plan {\n const resolve = context.resolve ?? ((id: string) => id);\n const notes: string[] = [];\n const elements = new Map<string, PlannedElementChange & { before?: VerifyElement }>();\n const relationships = new Map<string, PlannedRelationshipChange>();\n\n const changes = [...(changeset.changes as StagedChange[])]\n .map((change, index) => ({ change, index }))\n .sort((a, b) => (a.change.sequenceNumber ?? a.index) - (b.change.sequenceNumber ?? b.index));\n\n for (const { change, index } of changes) {\n const where = `change #${change.sequenceNumber ?? index} (${change.type} ${change.elementId})`;\n\n if (change.type === \"relationship-add\" || change.type === \"relationship-delete\") {\n const rel = readRelationship(change, resolve);\n if (!rel) {\n notes.push(`Skipped ${where}: it does not name a source, predicate and target.`);\n continue;\n }\n const key = relKey(rel);\n const previous = relationships.get(key);\n if (change.type === \"relationship-add\") {\n // Re-adding a relationship this changeset removed restores it: no net change.\n if (previous?.op === \"delete\") relationships.delete(key);\n else relationships.set(key, { ...rel, op: \"add\" });\n } else {\n if (previous?.op === \"add\") relationships.delete(key);\n else relationships.set(key, { ...rel, op: \"delete\" });\n }\n continue;\n }\n\n const id = resolve(change.elementId);\n const previous = elements.get(id);\n\n if (change.type === \"add\" || change.type === \"update\") {\n if (!change.after) {\n notes.push(`Skipped ${where}: it has no element data.`);\n continue;\n }\n const record = toVerifyElement(change.after, change.layerName, id);\n if (change.type === \"add\" && previous?.op !== \"delete\") {\n elements.set(id, { ...record, op: \"add\" });\n } else if (previous?.op === \"add\") {\n elements.set(id, { ...record, op: \"add\" });\n } else {\n const before =\n previous?.before ??\n (change.before ? toVerifyElement(change.before, change.layerName, id) : undefined);\n const fields = before ? changedFields(before, record) : undefined;\n elements.set(id, {\n ...record,\n op: \"update\",\n ...(before && fields\n ? { before, changedFields: fields, baseValues: Object.fromEntries(fields.map((f) => [f, fieldValue(before, f)])) }\n : {}),\n });\n }\n continue;\n }\n\n if (change.type === \"delete\") {\n if (previous?.op === \"add\") {\n elements.delete(id);\n continue;\n }\n const known = context.lookup?.(id);\n const before =\n previous?.before ??\n (change.before\n ? toVerifyElement(change.before, change.layerName, id)\n : known\n ? fromGraphElement(known)\n : fromId(id, change.layerName));\n elements.set(id, { ...before, id, op: \"delete\", before });\n continue;\n }\n\n notes.push(`Skipped ${where}: unknown change type.`);\n }\n\n return {\n label: changeset.name,\n elements: [...elements.values()].map(({ before: _before, ...rest }) => rest),\n relationships: [...relationships.values()],\n notes,\n };\n}\n\n/** The planned side of a changeset, read through its projected graph over the model. */\nexport async function planFromModel(model: Model, changeset: Changeset): Promise<Plan> {\n const graph = await ChangesetGraph.build(model, changeset);\n return planFromChangeset(changeset, {\n resolve: (id) => graph.resolve(id),\n lookup: (id) => graph.getElement(id),\n });\n}\n\n// ---------------------------------------------------------------------------\n// Built side\n// ---------------------------------------------------------------------------\n\n/** The built world of an as-built changeset: base + its changes, with what it changed. */\nexport function builtFromGraph(graph: ChangesetGraph, label = graph.changeset.name): BuiltSide {\n const elements: BuiltElement[] = [];\n const changedElements: BuiltElement[] = [];\n for (const element of graph.elements.values()) {\n const staged =\n element.status === \"added\" ||\n (element.status === \"updated\" &&\n !sameValue(element.sourceReference ?? null, (element.before && stagedSourceReference(element.before)) ?? null));\n const current = fromGraphElement(element);\n let updatedFrom: Record<string, unknown> | undefined;\n if (element.status === \"updated\" && element.before) {\n const before = toVerifyElement(element.before, element.layer, element.id);\n updatedFrom = Object.fromEntries(changedFields(before, current).map((f) => [f, fieldValue(before, f)]));\n if (!sameValue(current.sourceReference ?? null, before.sourceReference ?? null)) updatedFrom.source_reference = before.sourceReference ?? null;\n }\n const built: BuiltElement = {\n ...current,\n ...(element.status !== \"unchanged\" ? { change: element.status } : {}),\n ...(staged ? { stagedProvenance: element.sourceReference?.provenance ?? \"none\" } : {}),\n ...(updatedFrom ? { updatedFrom } : {}),\n };\n if (element.status !== \"deleted\") elements.push(built);\n if (element.status !== \"unchanged\") changedElements.push(built);\n }\n\n const relationships: BuiltRelationship[] = [];\n const changedRelationships: BuiltRelationship[] = [];\n for (const rel of graph.relationships()) {\n const built: BuiltRelationship = {\n source: rel.source,\n predicate: rel.predicate,\n target: rel.target,\n ...(rel.status !== \"unchanged\" ? { change: rel.status } : {}),\n };\n if (rel.status !== \"deleted\") relationships.push(built);\n if (rel.status !== \"unchanged\") changedRelationships.push(built);\n }\n\n return { label, kind: \"changeset\", elements, relationships, changedElements, changedRelationships, notes: [] };\n}\n\n/** The base model as the built world. What the build changed is not known. */\nexport async function builtFromBase(model: Model): Promise<BuiltSide> {\n const now = new Date().toISOString();\n const empty = new Changeset({\n id: \"base\",\n name: \"base model\",\n created: now,\n modified: now,\n status: \"committed\",\n baseSnapshot: \"\",\n changes: [],\n });\n const graph = await ChangesetGraph.build(model, empty);\n const side = builtFromGraph(graph, \"base model\");\n return {\n label: \"base model\",\n kind: \"base\",\n elements: side.elements,\n relationships: side.relationships,\n notes: [\n \"Compared with the base model: what the build changed is not recorded, so unplanned changes are limited \" +\n \"to relationships the build gave the elements this plan adds. Compare with an as-built changeset for \" +\n \"a full list.\",\n ],\n };\n}\n\n/**\n * A built side from plain elements and relationships, e.g. the output of an extraction pass.\n * With `allChanged`, every element and relationship given counts as a change of the build (an\n * extraction scoped to the branch's diff); otherwise they are the built world only.\n */\nexport function builtFromSnapshot(snapshot: {\n label: string;\n elements: BuiltElement[];\n relationships: BuiltRelationship[];\n allChanged?: boolean;\n notes?: string[];\n}): BuiltSide {\n const elements = snapshot.elements.filter((e) => e.change !== \"deleted\");\n const relationships = snapshot.relationships.filter((r) => r.change !== \"deleted\");\n return {\n label: snapshot.label,\n kind: \"snapshot\",\n elements,\n relationships,\n ...(snapshot.allChanged\n ? {\n changedElements: snapshot.elements.map((e) => ({ ...e, change: e.change ?? \"added\" })),\n changedRelationships: snapshot.relationships.map((r) => ({ ...r, change: r.change ?? \"added\" })),\n }\n : {}),\n notes: snapshot.notes ?? [],\n };\n}\n\n// ---------------------------------------------------------------------------\n// Verify\n// ---------------------------------------------------------------------------\n\nexport function verifyChangeset(plan: Plan, built: BuiltSide, options: VerifyOptions = {}): VerifyReport {\n const matchBySource = options.matchBySource ?? true;\n const notes = [...plan.notes, ...built.notes];\n\n const builtById = new Map(built.elements.map((e) => [e.id, e]));\n const changedIds = new Set((built.changedElements ?? []).map((e) => e.id));\n const claimed = new Set<string>();\n /** planned id \u2192 built id, with how it matched. */\n const elementMap = new Map<string, { built: string; match: MatchKind; reason?: string }>();\n\n const report: VerifyReport = {\n planned: { label: plan.label, elements: plan.elements.length, relationships: plan.relationships.length },\n against: { label: built.label, kind: built.kind },\n verdict: \"match\",\n verdictText: \"\",\n summary: { elements: emptyCounts(), relationships: emptyCounts() },\n elements: { matched: [], divergent: [], missing: [], unverifiable: [], unplanned: [], deletionsNotDone: [] },\n relationships: { matched: [], divergent: [], missing: [], unverifiable: [], unplanned: [], deletionsNotDone: [] },\n notes,\n };\n\n // Extraction's blind spots: a planned element it can't produce, that the build lacks, is unverifiable.\n const observability = options.observability;\n const unverifiableIds = new Map<string, string>();\n /** Why a planned element that could be unverifiable is reported missing instead. */\n const missingHints = new Map<string, string>();\n const markUnverifiable = (planned: PlannedElementChange): boolean => {\n if (!observability) return false;\n const verdict = observability.element(planned);\n if (verdict.observable) return false;\n if (verdict.unlocated) {\n // Nothing to find it by, but the build changed elements of its type the plan doesn't name: one\n // of them may be it, so it stays missing, with how to tell.\n const others = (built.changedElements ?? []).filter(\n (e) => e.change !== \"deleted\" && e.layer === planned.layer && sameType(e, planned) && !claimed.has(e.id)\n );\n if (others.length > 0) {\n missingHints.set(\n planned.id,\n `not found in the build by id or name, and it has no method, path or source reference to find it by; the build has ` +\n `${others.length} unplanned ${planned.layer}.${planned.type} element(s) (${others.slice(0, 5).map((e) => e.id).join(\", \")}` +\n `${others.length > 5 ? \", ...\" : \"\"}). If one of them is this one, give the plan's element its http_method and ` +\n \"http_path, or its sourceFile and sourceSymbol, and verify again\"\n );\n return false;\n }\n }\n const reason = verdict.reason ?? \"extraction can't produce it\";\n unverifiableIds.set(planned.id, reason);\n report.elements.unverifiable.push({\n planned: planned.id,\n layer: planned.layer,\n type: planned.type,\n name: planned.name,\n op: planned.op,\n reason,\n });\n return true;\n };\n\n // --- Elements: exact ids first, so a fuzzy match never takes an element another plan entry names.\n const live = plan.elements.filter((e) => e.op !== \"delete\");\n const deletions = plan.elements.filter((e) => e.op === \"delete\");\n\n for (const planned of live) {\n if (builtById.has(planned.id)) {\n claimed.add(planned.id);\n elementMap.set(planned.id, { built: planned.id, match: \"exact\" });\n }\n }\n\n const pending = live.filter((e) => !elementMap.has(e.id));\n const ambiguous = new Map<string, string[]>();\n const tiers: Array<{\n test: (planned: VerifyElement, candidate: VerifyElement) => boolean;\n reason: (planned: VerifyElement, candidate: VerifyElement) => string;\n }> = [\n {\n test: (p, c) => p.layer === c.layer && sameType(p, c) && namesMatch(p, c),\n reason: (p, c) =>\n `same layer and type, name matches ignoring case and separators (\"${p.name}\" ~ \"${c.name}\")`,\n },\n {\n test: (p, c) => p.layer === c.layer && !sameType(p, c) && namesMatch(p, c),\n reason: (p, c) => `same layer and name, but built as ${c.type} instead of ${p.type}`,\n },\n ];\n if (matchBySource) {\n tiers.push({\n test: (p, c) => p.layer === c.layer && sameType(p, c) && sharesSourceFile(p, c),\n reason: (p, c) => `same layer and type, shares source file ${sharedSourceFiles(p, c).join(\", \")}`,\n });\n }\n\n // A planned add cannot have been built as an element that existed before the plan. With the plan's\n // base index that is exact; without one, an unchanged element with no relationship to the plan's\n // elements is taken to predate it.\n const baseIds = plan.baseElementIds ? new Set(plan.baseElementIds) : undefined;\n const builtNeighbors = new Map<string, Set<string>>();\n for (const rel of built.relationships) {\n for (const [a, b] of [\n [rel.source, rel.target],\n [rel.target, rel.source],\n ]) {\n const set = builtNeighbors.get(a) ?? new Set<string>();\n set.add(b);\n builtNeighbors.set(a, set);\n }\n }\n const planTouched = new Set<string>([\n ...plan.elements.map((e) => e.id),\n ...plan.relationships.flatMap((r) => [r.source, r.target]),\n ]);\n const neighborCache = new Map<string, Set<string>>();\n const plannedNeighbors = (id: string): Set<string> => {\n const cached = neighborCache.get(id);\n if (cached) return cached;\n const own = plan.relationships\n .filter((r) => r.op === \"add\" && (r.source === id || r.target === id))\n .map((r) => (r.source === id ? r.target : r.source));\n const ids = own.length > 0 ? own : [...planTouched].filter((other) => other !== id);\n const near = new Set(ids.flatMap((other) => [other, elementMap.get(other)?.built ?? other]));\n neighborCache.set(id, near);\n return near;\n };\n let fellBack = false;\n const canBeBuildOf = (planned: PlannedElementChange, candidate: VerifyElement): boolean => {\n if (planned.op !== \"add\") return true;\n if (baseIds) return !baseIds.has(candidate.id);\n if (changedIds.has(candidate.id)) return true;\n fellBack = true;\n const near = plannedNeighbors(planned.id);\n for (const other of builtNeighbors.get(candidate.id) ?? []) if (near.has(other)) return true;\n return false;\n };\n\n for (const tier of tiers) {\n for (const planned of pending) {\n if (elementMap.has(planned.id)) continue;\n const candidates = built.elements.filter(\n (c) => !claimed.has(c.id) && tier.test(planned, c) && canBeBuildOf(planned, c)\n );\n if (candidates.length === 0) continue;\n let chosen = candidates;\n if (chosen.length > 1 && changedIds.size > 0) {\n const changed = chosen.filter((c) => changedIds.has(c.id));\n if (changed.length > 0) chosen = changed;\n }\n if (chosen.length === 1) {\n const candidate = chosen[0];\n claimed.add(candidate.id);\n elementMap.set(planned.id, { built: candidate.id, match: \"probable\", reason: tier.reason(planned, candidate) });\n ambiguous.delete(planned.id);\n } else if (!ambiguous.has(planned.id)) {\n ambiguous.set(\n planned.id,\n chosen.map((c) => c.id)\n );\n }\n }\n }\n\n if (fellBack) {\n notes.push(\n `No base index was recorded for ${plan.label}, so the elements that existed before it are not known exactly: ` +\n \"unchanged elements with no relationship to the plan's elements were not considered as the built form of \" +\n \"a planned add.\"\n );\n }\n\n const lifecycleMoves: string[] = [];\n for (const planned of live) {\n const mapping = elementMap.get(planned.id);\n if (!mapping) {\n if (markUnverifiable(planned)) continue;\n const candidates = ambiguous.get(planned.id);\n report.elements.missing.push({\n planned: planned.id,\n layer: planned.layer,\n type: planned.type,\n name: planned.name,\n op: planned.op,\n reason: candidates\n ? `several built elements could be it (${candidates.length}); none matched uniquely`\n : planned.op === \"update\"\n ? \"the element the plan updates does not exist in the build\"\n : (missingHints.get(planned.id) ?? \"not found in the build by id, name or source file\"),\n ...(candidates ? { candidates } : {}),\n });\n continue;\n }\n\n const builtElement = builtById.get(mapping.built)!;\n let fields = compareElements(planned, builtElement, planned.op === \"update\" ? planned.changedFields : undefined);\n const match: ElementMatch = {\n planned: planned.id,\n built: mapping.built,\n op: planned.op,\n match: mapping.match,\n ...(mapping.reason ? { reason: mapping.reason } : {}),\n };\n\n // Fields extraction never writes, that the build left as they were (or doesn't have): it can't\n // show them either way.\n const unverifiableFields = observability?.field\n ? fields.filter((f) => !observability.field!(planned, f.field) && buildLeft(planned, builtElement, f))\n : [];\n if (unverifiableFields.length > 0) {\n match.unverifiableFields = unverifiableFields;\n fields = fields.filter((f) => !unverifiableFields.includes(f));\n }\n\n if (planned.op === \"update\" && planned.changedFields && planned.changedFields.length > 0) {\n const checkable = planned.changedFields.filter((field) => !unverifiableFields.some((u) => u.field === field));\n if (checkable.length === 0) {\n // The element itself was found: only the update can't be shown, so its relationships still count.\n const reason = `extraction doesn't write ${unverifiableFields.map((f) => f.field).join(\", \")}`;\n report.elements.unverifiable.push({\n planned: planned.id,\n layer: planned.layer,\n type: planned.type,\n name: planned.name,\n op: planned.op,\n reason,\n fields: unverifiableFields,\n });\n continue;\n }\n const unmet = fields.filter((f) => checkable.includes(f.field));\n // Missing only when the build left every field the plan changes alone. A field the build changed\n // to something else is a divergence, reported below with both values.\n const touched = unmet.some((f) => buildTouched(planned, builtElement, f.field));\n if (unmet.length === checkable.length && !touched) {\n if (markUnverifiable(planned)) continue;\n report.elements.missing.push({\n planned: planned.id,\n layer: planned.layer,\n type: planned.type,\n name: planned.name,\n op: planned.op,\n reason: \"the element exists but the build does not carry the planned update\",\n fields: unmet,\n });\n continue;\n }\n }\n\n const lifecycle = fields.filter(isLifecycleMove);\n // A description is prose: it differs from a docstring or extraction's placeholder without the\n // build being wrong. Only a planned update that changes it has it checked.\n const descriptionChecked = planned.op === \"update\" && (planned.changedFields ?? []).includes(\"description\");\n const informational = fields.filter((f) => f.field === \"description\" && !descriptionChecked);\n const differences = fields.filter((f) => !isLifecycleMove(f) && !informational.includes(f));\n if (lifecycle.length > 0) {\n match.lifecycle = lifecycle;\n for (const f of lifecycle) {\n lifecycleMoves.push(`${planned.id} ${f.field} ${String(f.planned)} \u2192 ${String(f.built)}`);\n }\n }\n if (informational.length > 0) match.notes = informational;\n if (differences.length > 0) report.elements.divergent.push({ ...match, fields: differences });\n else report.elements.matched.push(match);\n }\n\n if (lifecycleMoves.length > 0) {\n notes.push(\n `Lifecycle progress, not counted as divergence (${LIFECYCLE_FIELDS.join(\", \")} moving to a later stage of ` +\n `${LIFECYCLE_STAGES.map((stage) => stage.join(\"/\")).join(\" \u2192 \")}): ${lifecycleMoves.join(\"; \")}.`\n );\n }\n\n const described = [...report.elements.matched, ...report.elements.divergent].filter((m) => m.notes);\n if (described.length > 0) {\n notes.push(\n `${described.length} matched element${described.length === 1 ? \" has a description that differs\" : \"s have descriptions that differ\"} ` +\n \"from the plan's (under notes on each match). Descriptions are not compared: no need to edit the plan to \" +\n \"match the build's text.\"\n );\n }\n const unwritten = [...report.elements.matched, ...report.elements.divergent].filter((m) => m.unverifiableFields);\n if (unwritten.length > 0) {\n notes.push(\n `${unwritten.length} matched element${unwritten.length === 1 ? \" has\" : \"s have\"} planned fields extraction ` +\n \"doesn't write (under unverifiableFields on each match): check them in the code or the review.\"\n );\n }\n\n for (const planned of deletions) {\n const still = builtById.get(planned.id);\n if (still) {\n claimed.add(still.id);\n if (markUnverifiable(planned)) continue;\n report.elements.deletionsNotDone.push({ planned: planned.id, built: still.id });\n } else {\n claimed.add(planned.id);\n report.elements.matched.push({ planned: planned.id, built: planned.id, op: \"delete\", match: \"exact\" });\n }\n }\n\n if (built.changedElements) {\n for (const element of built.changedElements) {\n if (claimed.has(element.id)) continue;\n report.elements.unplanned.push({\n id: element.id,\n layer: element.layer,\n type: element.type,\n name: element.name,\n change: element.change ?? \"added\",\n });\n }\n }\n\n // --- Relationships, through the element matches.\n const builtRels = new Map(built.relationships.map((r) => [relKey(r), r]));\n const claimedRels = new Set<string>();\n const mapId = (id: string) => elementMap.get(id)?.built ?? id;\n const probableEndpoints = (rel: VerifyRelationship): string[] =>\n [rel.source, rel.target]\n .filter((id, i, all) => all.indexOf(id) === i)\n .filter((id) => elementMap.get(id)?.match === \"probable\")\n .map((id) => `${id} \u2192 ${elementMap.get(id)!.built}`);\n const missingEndpoints = new Set(report.elements.missing.map((m) => m.planned));\n\n // A planned relationship extraction can't produce: an end it can't see, or no mapped code edge.\n const plannedById = new Map(plan.elements.map((e) => [e.id, e]));\n // The element as built when it was found (extraction's source symbols), else as planned.\n const elementOf = (id: string): VerifyElement =>\n builtById.get(elementMap.get(id)?.built ?? \"\") ?? plannedById.get(id) ?? builtById.get(id) ?? fromId(id, \"\");\n const unverifiableReason = (rel: VerifyRelationship): string | undefined => {\n if (!observability) return undefined;\n for (const end of [rel.source, rel.target]) {\n const known = unverifiableIds.get(end);\n if (known !== undefined) return `${end} is unverifiable (${known})`;\n if (missingHints.has(end)) continue; // reported missing: its relationships are too\n const verdict = observability.element(elementOf(end));\n if (!verdict.observable) return `extraction can't see ${end}: ${verdict.reason ?? \"no rule produces it\"}`;\n }\n const verdict = observability.relationship(elementOf(rel.source), rel.predicate, elementOf(rel.target));\n return verdict.observable ? undefined : (verdict.reason ?? \"no mapped code edge produces it\");\n };\n const pushUnverifiable = (planned: PlannedRelationshipChange): boolean => {\n const reason = unverifiableReason(planned);\n if (reason === undefined) return false;\n report.relationships.unverifiable.push({ planned: strip(planned), op: planned.op, reason });\n return true;\n };\n\n const mapRel = (planned: PlannedRelationshipChange): VerifyRelationship => ({\n source: mapId(planned.source),\n predicate: planned.predicate,\n target: mapId(planned.target),\n });\n const matchInfoFor = (planned: PlannedRelationshipChange) => {\n const probable = probableEndpoints(planned);\n return probable.length > 0\n ? { match: \"probable\" as const, reason: `through probable element match: ${probable.join(\"; \")}` }\n : { match: \"exact\" as const };\n };\n\n // Pass 1: exact (source, predicate, target) hits, so the fallback below can never take a built\n // relationship that another planned relationship matches exactly.\n const unresolved: PlannedRelationshipChange[] = [];\n for (const planned of plan.relationships) {\n const mapped = mapRel(planned);\n const found = builtRels.get(relKey(mapped));\n if (!found || claimedRels.has(relKey(found))) {\n unresolved.push(planned);\n continue;\n }\n claimedRels.add(relKey(found));\n const plannedRef = strip(planned);\n if (planned.op === \"delete\") {\n if (pushUnverifiable(planned)) continue;\n report.relationships.deletionsNotDone.push({ planned: plannedRef, built: strip(found) });\n } else {\n report.relationships.matched.push({ planned: plannedRef, built: strip(found), op: \"add\", ...matchInfoFor(planned) });\n }\n }\n\n // Elements the plan adds, as built: a relationship touching one cannot predate the change.\n const addedBuiltIds = new Set(\n live.filter((e) => e.op === \"add\" && elementMap.has(e.id)).map((e) => elementMap.get(e.id)!.built)\n );\n\n // Pass 2: everything without an exact hit.\n for (const planned of unresolved) {\n const mapped = mapRel(planned);\n const plannedRef = strip(planned);\n const matchInfo = matchInfoFor(planned);\n\n if (planned.op === \"delete\") {\n claimedRels.add(relKey(mapped));\n report.relationships.matched.push({ planned: plannedRef, built: mapped, op: \"delete\", ...matchInfo });\n continue;\n }\n\n // Same endpoints, another predicate; or the same predicate the other way round.\n // Prefer what the build changed: an untouched base relationship is not the build's version of this one.\n const isAlternative = (r: VerifyRelationship) =>\n !claimedRels.has(relKey(r)) &&\n ((r.source === mapped.source && r.target === mapped.target && r.predicate !== mapped.predicate) ||\n (r.source === mapped.target && r.target === mapped.source && r.predicate === mapped.predicate));\n const alternative = built.changedRelationships\n ? built.changedRelationships.filter((r) => r.change !== \"deleted\").find(isAlternative)\n : // What the build changed is not known: only a relationship touching an element the plan adds\n // can be the build's version; one between pre-existing elements may simply predate the change.\n built.relationships.find(\n (r) => isAlternative(r) && (addedBuiltIds.has(r.source) || addedBuiltIds.has(r.target))\n );\n if (alternative) {\n claimedRels.add(relKey(alternative));\n const fields: FieldDifference[] =\n alternative.predicate !== mapped.predicate\n ? [{ field: \"predicate\", planned: mapped.predicate, built: alternative.predicate }]\n : [\n {\n field: \"direction\",\n planned: `${mapped.source} \u2192 ${mapped.target}`,\n built: `${alternative.source} \u2192 ${alternative.target}`,\n },\n ];\n report.relationships.divergent.push({\n planned: plannedRef,\n built: strip(alternative),\n op: \"add\",\n ...matchInfo,\n fields,\n });\n continue;\n }\n\n if (pushUnverifiable(planned)) continue;\n\n // Near matches that may predate the change: listed, not claimed.\n const candidates = built.changedRelationships ? [] : built.relationships.filter(isAlternative).map(strip);\n const absent = [planned.source, planned.target].filter(\n (id) => missingEndpoints.has(id) || (!elementMap.has(id) && !builtById.has(id))\n );\n report.relationships.missing.push({\n planned: plannedRef,\n reason:\n absent.length > 0\n ? `not built; endpoint${absent.length > 1 ? \"s\" : \"\"} ${absent.join(\", \")} not found in the build`\n : candidates.length > 0\n ? \"not found in the build; a relationship between the same elements exists, but it may predate the change\"\n : \"not found in the build\",\n ...(candidates.length > 0 ? { candidates } : {}),\n });\n }\n\n if (built.changedRelationships) {\n for (const rel of built.changedRelationships) {\n if (claimedRels.has(relKey(rel))) continue;\n report.relationships.unplanned.push({ ...strip(rel), change: rel.change ?? \"added\" });\n }\n } else {\n // Base model: relationships the build gave the elements this plan adds, beyond the plan's own.\n for (const rel of built.relationships) {\n if (claimedRels.has(relKey(rel))) continue;\n if (addedBuiltIds.has(rel.source) || addedBuiltIds.has(rel.target)) {\n report.relationships.unplanned.push({ ...strip(rel), change: \"present\" });\n }\n }\n }\n\n report.summary.elements = countCategories(plan.elements.length, report.elements);\n report.summary.relationships = countCategories(plan.relationships.length, report.relationships);\n const { verdict, text } = decideVerdict(report);\n report.verdict = verdict;\n report.verdictText = text;\n return report;\n}\n\n/**\n * Verifies a planned changeset against an as-built changeset or the base model of `model`.\n * Used by the `changeset_verify` MCP tool and `dr changeset verify`.\n */\nexport async function verifyChangesetInModel(\n model: Model,\n options: {\n planned: Changeset;\n /** With `extracted`, the base holds a landed extraction of the build: apply the extraction rule. */\n against: { changeset: Changeset } | { base: true; extracted?: boolean };\n matchBySource?: boolean;\n /** The analyzer whose extraction wrote the as-built side (default: the project's, else cbm). */\n analyzer?: string;\n /** For tests: the extraction coverage to use instead of the analyzer's bundled mapping. */\n coverage?: ExtractionCoverage | null;\n }\n): Promise<VerifyReport & { plannedChangeset: { id: string; name: string } }> {\n const { planned } = options;\n const plan = await planFromModel(model, planned);\n const notes: string[] = [];\n const baseIndex = await tryReadBaseIndex(model.rootPath, planned.id);\n if (baseIndex.index) plan.baseElementIds = Object.keys(baseIndex.index.elements);\n if (baseIndex.warning) notes.push(baseIndex.warning);\n\n let built: BuiltSide;\n let extraction: VerifyExtraction;\n let observability: ObservabilityCheck | undefined;\n let warning: string | undefined;\n if (\"changeset\" in options.against) {\n const asBuilt = options.against.changeset;\n if (asBuilt.id === planned.id) {\n notes.push(\"The planned and as-built changesets are the same changeset, so everything matches by definition.\");\n }\n built = builtFromGraph(await ChangesetGraph.build(model, asBuilt), `${asBuilt.name} (${asBuilt.id})`);\n // Where the as-built side came from is read from codebase_extract's own record of the\n // changeset, never from the provenance its elements declare or its description.\n const record = await readExtractionRecord(model.rootPath, { id: asBuilt.id!, name: asBuilt.name }, currentGitHead(model.codebaseRoot));\n if (!record) {\n extraction = {\n applied: false,\n reason:\n \"codebase_extract has no record of the as-built changeset (.dr/analyzers/extract/), so it is not taken as \" +\n \"extraction output: every planned change is checked, and its elements count as added by hand, whatever \" +\n \"provenance they declare.\",\n asBuilt: asBuiltShare(built, plan, { record: null }),\n };\n if (EXTRACTION_MARKER.test(asBuilt.description ?? \"\")) {\n notes.push(\n \"The as-built changeset's description says codebase_extract staged it, but its record is gone. Run \" +\n \"codebase_extract on it again (with the same since) to record what it stages, then verify again.\"\n );\n }\n } else {\n const codeFiles = [...new Set((built.changedElements ?? []).flatMap((e) => sourceFiles(e)))];\n const rule = await extractionRule(model, options, codeFiles, \"The as-built changeset came from codebase_extract\");\n ({ extraction, observability } = rule);\n const share = asBuiltShare(built, plan, { record, ...(observability ? { observe: (e) => observability!.element(e) } : {}) });\n extraction.asBuilt = share;\n if (record.readAt) {\n notes.push(\n `The extraction record is from a run that staged nothing, at ${record.readAt.slice(0, 7)}; the code has moved ` +\n \"since (a commit after the extract). Its cards still name what extraction offered then; run codebase_extract \" +\n \"on this changeset again if the code changed since.\"\n );\n }\n if (share.copiedFromPlan?.length) {\n notes.push(\n `${share.copiedFromPlan.length} as-built element(s) share an id with the plan's adds but did not come from ` +\n `extraction (${share.copiedFromPlan.join(\", \")}). If they were copied from the plan, their match says ` +\n \"nothing about the code; extract again with codebase_extract and leave them out.\"\n );\n }\n }\n warning = asBuiltWarning(extraction.asBuilt!, extraction.applied);\n } else {\n built = await builtFromBase(model);\n if (planned.status === \"staged\") {\n notes.push(\n \"The planned changeset is still staged, so its own changes are not in the base model: anything \" +\n \"reported missing is missing from what was committed to the base (e.g. an as-built changeset).\"\n );\n }\n if (options.against.extracted) {\n ({ extraction, observability } = await extractionRule(\n model,\n options,\n [],\n \"Compared with the base model, which holds a landed extraction (extracted: true)\"\n ));\n } else {\n extraction = {\n applied: false,\n reason:\n \"Compared with the base model: every planned change is checked. Pass extracted: true when the base holds \" +\n \"a landed extraction of the build.\",\n };\n }\n }\n\n const report = verifyChangeset(plan, built, { matchBySource: options.matchBySource, observability });\n report.extraction = extraction;\n report.notes.push(...notes);\n const share = extraction.asBuilt;\n if (share) {\n // Matches against elements extraction didn't stage are no evidence; ones it staged and the agent\n // then edited carry the edits.\n const agentIds = new Set((share.agentAdded ?? []).map((a) => a.id));\n const edits = new Map((share.editedAfterExtraction ?? []).map((e) => [e.id, e.edits]));\n const matches = [...report.elements.matched, ...report.elements.divergent];\n // An element edited after extraction is no evidence either: treated as the agent's.\n const onEdited = matches.filter((m) => edits.has(m.built));\n for (const m of onEdited) m.editedAfterExtraction = edits.get(m.built);\n const onAgent = matches.filter((m) => agentIds.has(m.built) || edits.has(m.built));\n for (const m of onAgent) m.builtByAgent = true;\n if (onEdited.length > 0) {\n report.notes.push(\n `${onEdited.length} match(es) are against extracted elements changed after extraction staged them ` +\n \"(editedAfterExtraction on each): the match shows the edit, not the code.\"\n );\n }\n if (warning) {\n report.warning = warning;\n report.verdictText += ` But ${warning.charAt(0).toLowerCase()}${warning.slice(1)}`;\n }\n if (onAgent.length > 0 && share.record !== \"not-found\") {\n // Against extraction, a match that rests on elements it didn't stage, or that were edited after\n // it, is not clean. (Without a record the comparison isn't against extraction at all: the\n // extraction note and the warning say so.)\n if (report.verdict === \"match\") report.verdict = \"probable-match\";\n report.verdictText +=\n ` ${onAgent.length} of the matches ${onAgent.length === 1 ? \"rests\" : \"rest\"} on elements extraction didn't stage` +\n (onEdited.length > 0 ? ` or that were edited after it (${onEdited.length})` : \"\") +\n \" (builtByAgent): confirm them in the code.\";\n }\n }\n return { plannedChangeset: { id: planned.id, name: planned.name }, ...report };\n}\n\n/** The extraction rule for a built side that came from extraction, from the analyzer's mapping. */\nasync function extractionRule(\n model: Model,\n options: { analyzer?: string; coverage?: ExtractionCoverage | null },\n codeFiles: string[],\n why: string\n): Promise<{ extraction: VerifyExtraction; observability?: ObservabilityCheck }> {\n const analyzer = options.analyzer ?? (await resolveAnalyzerName(model.rootPath).catch(() => \"cbm\"));\n const coverage = options.coverage !== undefined ? options.coverage : await loadExtractionCoverage(analyzer);\n if (!coverage) {\n return {\n extraction: {\n applied: false,\n reason: `${why}, but the ${analyzer} mapping could not be read, so extraction's blind spots are not known: every planned change is checked.`,\n analyzer,\n },\n };\n }\n return {\n observability: {\n element: (element) => coverage.element(element, codeFiles),\n relationship: (source, predicate, target) => coverage.relationship(source, predicate, target),\n field: (element, field) => coverage.field(element, field),\n },\n extraction: {\n applied: true,\n reason:\n `${why}: planned changes extraction can't produce (intent, types or files no rule covers, relationships no ` +\n \"code edge maps to, fields it doesn't write) are unverifiable, not missing.\",\n analyzer: coverage.analyzer,\n observableTypes: coverage.observableTypes(),\n },\n };\n}\n\n/** The description codebase_extract gives the changesets it creates. */\nconst EXTRACTION_MARKER = /Staged by codebase_extract/;\n\n/**\n * Where an as-built changeset's elements and relationships came from (see AsBuiltShare).\n *\n * Only extraction's record counts, never the provenance an element declares:\n * - an add, when extraction staged its id, or its file and symbol are one of the run's staged\n * symbols, cards or earlier cards, and extraction can produce it there (the card's candidates, or\n * for an open card the file-aware coverage check). One that would match a planned add by id or\n * name must also be named after its symbol, not after the plan's element. An extracted add whose\n * name or attributes differ from what extraction staged is listed in `editedAfterExtraction`;\n * - an update, when the record's `updated` lists its id;\n * - a delete, when it is one of the record's candidate deletes.\n * Without a record, nothing counts.\n */\nexport function asBuiltShare(\n built: BuiltSide,\n plan?: Plan,\n context: {\n record?: ExtractionRecord | null;\n /** What extraction can produce, for elements of open cards (file-aware). */\n observe?: (element: VerifyElement) => { observable: boolean; reason?: string };\n } = {}\n): AsBuiltShare {\n const record = context.record ?? null;\n const changed = built.changedElements ?? [];\n const planAdds = (plan?.elements ?? []).filter((e) => e.op === \"add\");\n const plannedAdds = new Set(planAdds.map((e) => e.id));\n const plannedNames = new Set(planAdds.flatMap((e) => [...nameKeys(e)]));\n const stagedById = new Map((record?.staged ?? []).map((e) => [e.id, e]));\n const updatedById = new Map((record?.updated ?? []).map((u) => [u.id, u]));\n const candidateDeletes = new Set(record?.candidateDeletes ?? []);\n // Each symbol extraction offered (staged, or as a card now or earlier), by file and symbol.\n const offered = new Map<string, OfferedSymbol[]>();\n for (const entry of [...(record?.staged ?? []), ...(record?.cards ?? []), ...(record?.earlierCards ?? [])]) {\n const key = decisionKey(entry.file, entry.symbol);\n offered.set(key, [...(offered.get(key) ?? []), entry]);\n }\n\n const notFromExtraction = (e: BuiltElement): string | undefined => {\n if (!record) return \"no codebase_extract record of this changeset confirms it\";\n if (e.change === \"deleted\") return candidateDeletes.has(e.id) ? undefined : \"a delete that is not one of extraction's candidate deletes\";\n if (e.change === \"updated\") return updatedById.has(e.id) ? undefined : \"an update extraction did not stage\";\n const type = `${e.layer}.${e.type}`;\n // Where an element could be taken for the plan's, its name must come from the code.\n const looksPlanned = plannedAdds.has(e.id) || [...nameKeys(e)].some((k) => plannedNames.has(k));\n const staged = stagedById.get(e.id);\n const located = (e.sourceReference?.locations ?? []).filter((l) => typeof l?.symbol === \"string\" && l.symbol.length > 0);\n const cards = located.flatMap((l) => offered.get(decisionKey(normalizeFile(l.file), l.symbol!)) ?? []);\n if (!staged && cards.length === 0) {\n const verdict = context.observe?.(e);\n if (verdict && !verdict.observable) return `extraction can't produce it: ${verdict.reason ?? type}`;\n return located.length === 0\n ? \"extraction did not stage it, and it names no source symbol\"\n : \"extraction did not stage it, and no card of its runs has its file and symbol\";\n }\n // The type: one its card allows. A card with no candidates is open, and one recorded without\n // them (an older record's earlier card) is unknown: either way only the file-aware check of\n // what extraction can produce there applies, as it does to a staged element.\n const producible = context.observe ? context.observe(e) : { observable: true };\n const allowed = (c: OfferedSymbol): boolean =>\n c.candidates?.length ? c.candidates.some((t) => t === type || t === `${e.layer}.*`) : producible.observable;\n const fitting = cards.filter(allowed);\n const withCandidates = cards.filter((c) => c.candidates?.length);\n if (withCandidates.length > 0 && !withCandidates.some(allowed)) {\n return `its card allows ${[...new Set(withCandidates.flatMap((c) => c.candidates!))].join(\", \")}, not ${type}`;\n }\n if (!producible.observable && withCandidates.length === 0) {\n return `extraction can't produce it ${staged ? \"there\" : \"from its card\"}: ${producible.reason ?? type}`;\n }\n if (!looksPlanned) return undefined;\n if ((staged && namedAfterCard(e, staged)) || fitting.some((c) => namedAfterCard(e, c))) return undefined;\n return staged ? \"named after the plan's element, not after the symbol extraction staged it from\" : \"named after the plan's element, not after its card\";\n };\n\n const byProvenance: Record<string, number> = {};\n const extracted = new Set<string>();\n const agentAdded: NonNullable<AsBuiltShare[\"agentAdded\"]> = [];\n const edited: NonNullable<AsBuiltShare[\"editedAfterExtraction\"]> = [];\n for (const e of changed) {\n // What the changeset staged, not the merged element: an update that kept the base's source\n // reference is counted apart, whatever that reference says.\n const declared =\n e.change === \"deleted\"\n ? \"deleted\"\n : (e.stagedProvenance ?? (e.change === \"updated\" ? \"sourceUnchanged\" : (e.sourceReference?.provenance ?? \"none\")));\n byProvenance[declared] = (byProvenance[declared] ?? 0) + 1;\n const reason = notFromExtraction(e);\n if (reason !== undefined) {\n agentAdded.push({ id: e.id, declared, reason });\n continue;\n }\n extracted.add(e.id);\n const edits = editsAfterExtraction(e, stagedById.get(e.id), updatedById.get(e.id));\n if (edits.length > 0) edited.push({ id: e.id, edits });\n }\n\n const relationships = (built.changedRelationships ?? []).filter((r) => r.change !== \"deleted\");\n const betweenExtracted = relationships.filter((r) => extracted.has(r.source) && extracted.has(r.target)).length;\n const addedIds = new Set(changed.filter((e) => e.change === \"added\").map((e) => e.id));\n const copied = agentAdded.filter((a) => plannedAdds.has(a.id) && addedIds.has(a.id)).map((a) => a.id);\n return {\n elements: { total: changed.length, byProvenance, fromExtraction: extracted.size, agentAdded: agentAdded.length },\n relationships: { total: relationships.length, betweenExtracted, other: relationships.length - betweenExtracted },\n record: record ? (record.source === \"pending\" ? \"pending\" : \"found\") : \"not-found\",\n ...(agentAdded.length > 0 ? { agentAdded } : {}),\n ...(edited.length > 0 ? { editedAfterExtraction: edited } : {}),\n ...(copied.length > 0 ? { copiedFromPlan: copied } : {}),\n };\n}\n\n/** A field's value as the record keys it: verify's names, plus `source_reference`. */\nfunction recordFieldValue(element: VerifyElement, field: string): unknown {\n return field === \"source_reference\" ? (element.sourceReference ?? null) : fieldValue(element, field);\n}\n\nfunction sameRecordValue(field: string, a: unknown, b: unknown): boolean {\n if (field !== \"source_reference\") return sameFieldValue(field, a, b);\n // By where it points (file and symbol), whatever else either shape carries.\n const where = (v: unknown): string[] => {\n const locations = (v as { locations?: Array<{ file?: unknown; symbol?: unknown }> } | null)?.locations;\n return Array.isArray(locations) ? locations.map((l) => `${String(l?.file ?? \"\")}#${String(l?.symbol ?? \"\")}`).sort() : [];\n };\n return sameValue(where(a), where(b));\n}\n\n/**\n * What changed in an extracted element after extraction staged it.\n *\n * - An update: each field it changes from the base that the record's `updated` entry doesn't list\n * (extraction didn't change it), and each listed field whose value differs from the one extraction\n * wrote (`values`, when recorded).\n * - An add: the name and attributes against what extraction staged; a field extraction later\n * updated on it (folded into the add) against the value it wrote, when recorded.\n */\nfunction editsAfterExtraction(\n e: BuiltElement,\n staged: { name?: string; attributes?: Record<string, unknown> } | undefined,\n own: ExtractionRecord[\"updated\"][number] | undefined\n): ExtractionEdit[] {\n const edits: ExtractionEdit[] = [];\n const values = own?.values && typeof own.values === \"object\" ? own.values : undefined;\n const byValue = (field: string): ExtractionEdit | undefined => {\n if (!values || !Object.hasOwn(values, field)) return undefined;\n const now = recordFieldValue(e, field);\n return sameRecordValue(field, values[field], now) ? undefined : { field, extracted: values[field] ?? null, now: now ?? null };\n };\n if (e.change === \"updated\") {\n if (!own) return edits;\n for (const [field, was] of Object.entries(e.updatedFrom ?? {})) {\n if (own.fields && !own.fields.includes(field)) edits.push({ field, extracted: was ?? null, now: recordFieldValue(e, field) ?? null });\n }\n for (const field of own.fields ?? []) {\n const edit = byValue(field);\n if (edit) edits.push(edit);\n }\n return edits;\n }\n if (e.change !== \"added\") return edits;\n const folded = new Set(own?.fields ?? []);\n if (staged) {\n // Fields extraction itself updated on this add are checked against what it wrote instead.\n edits.push(...editsSinceExtraction(e, staged).filter((d) => !folded.has(d.field) && !(own && !own.fields)));\n }\n for (const field of folded) {\n const edit = byValue(field);\n if (edit) edits.push(edit);\n }\n return edits;\n}\n\n/**\n * The name and attributes of an extracted add that differ from what extraction staged. A record\n * entry with a name leaves `attributes` out when there were none; one without a name (an older\n * record) says nothing about either.\n */\nfunction editsSinceExtraction(element: VerifyElement, staged: { name?: string; attributes?: Record<string, unknown> }): ExtractionEdit[] {\n const edits: ExtractionEdit[] = [];\n if (typeof staged.name !== \"string\") return edits;\n if (staged.name !== element.name) edits.push({ field: \"name\", extracted: staged.name, now: element.name });\n const stagedAttributes = staged.attributes && typeof staged.attributes === \"object\" ? staged.attributes : {};\n {\n const keys = new Set([...Object.keys(stagedAttributes), ...Object.keys(element.attributes ?? {})]);\n for (const key of [...keys].sort()) {\n const was = stagedAttributes[key];\n const now = element.attributes?.[key];\n if (!sameValue(was, now)) edits.push({ field: `attributes.${key}`, extracted: was ?? null, now: now ?? null });\n }\n }\n return edits;\n}\n\n/**\n * Whether an element is named after a card or staged symbol: the symbol (with or without its class\n * or module path), the card's name or proposal, a module's file, or for a route the same method and\n * path whatever its parameters are called (`GET /owners/{}` is `GET /owners/{ownerId}`).\n */\nfunction namedAfterCard(element: VerifyElement, card: OfferedSymbol): boolean {\n if (card.proposed?.id && card.proposed.id === element.id) return true;\n const route = routeKey(card.symbol) ?? (card.name ? routeKey(card.name) : undefined);\n if (route && routeKey(element.name) === route) return true;\n const keys = nameKeys(element);\n const parts = card.symbol.split(/[.#/\\s]+/).filter(Boolean);\n const file = card.file ?? \"\";\n const names = [card.symbol, card.name, card.proposed?.name, parts[parts.length - 1], file, file.replace(/\\.[^./]+$/, \"\")];\n return names.some((n) => typeof n === \"string\" && n.length > 0 && keys.has(normalizeName(n)));\n}\n\nfunction normalizeFile(file: string | undefined): string | null {\n return typeof file === \"string\" && file.length > 0 ? file.replace(/\\\\/g, \"/\").replace(/^\\.\\//, \"\") : null;\n}\n\n/** The warning for an as-built side mostly not from extraction: more than half its elements. */\nexport function asBuiltWarning(share: AsBuiltShare, blindSpotsApplied = true): string | undefined {\n const { total, agentAdded } = share.elements;\n const edited = share.editedAfterExtraction?.length ?? 0;\n if (total === 0 || (agentAdded + edited) * 2 <= total) return undefined;\n const copied = share.copiedFromPlan?.length ?? 0;\n return (\n `${agentAdded + edited} of the ${total} as-built elements were not staged by extraction` +\n (edited > 0 ? ` or were edited after it (${edited})` : \"\") +\n (copied > 0 ? ` (${copied} share an id with the plan's adds)` : \"\") +\n \", so this comparison says little about the code.\" +\n (blindSpotsApplied\n ? \" Extraction's blind spots were still applied.\"\n : share.record === \"not-found\"\n ? \" No extraction record covers this changeset, so extraction's blind spots were not applied.\"\n : \" Extraction's blind spots were not applied.\") +\n \" To verify the \" +\n \"code, discard this changeset and stage the build with codebase_extract: from its cards, named after them \" +\n \"(see extraction.asBuilt.agentAdded for why each one doesn't count).\"\n );\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Lowercase with every non-alphanumeric removed: \"Export Orders\", \"export-orders\", \"exportOrders\" \u2192 \"exportorders\". */\nexport function normalizeName(name: string): string {\n return name.toLowerCase().replace(/[^a-z0-9]/g, \"\");\n}\n\nfunction nameKeys(element: VerifyElement): Set<string> {\n const keys = new Set<string>();\n if (element.name) keys.add(normalizeName(element.name));\n const segment = idNameSegment(element.id);\n if (segment) keys.add(normalizeName(segment));\n keys.delete(\"\");\n return keys;\n}\n\nfunction namesMatch(a: VerifyElement, b: VerifyElement): boolean {\n const keys = nameKeys(b);\n for (const key of nameKeys(a)) if (keys.has(key)) return true;\n return false;\n}\n\nfunction sameType(a: VerifyElement, b: VerifyElement): boolean {\n return normalizeName(a.type) === normalizeName(b.type);\n}\n\nfunction sourceFiles(element: VerifyElement): string[] {\n return (element.sourceReference?.locations ?? [])\n .map((l) => (typeof l?.file === \"string\" ? l.file.replace(/^\\.\\//, \"\").replace(/\\\\/g, \"/\") : \"\"))\n .filter((f) => f.length > 0);\n}\n\nfunction sharedSourceFiles(a: VerifyElement, b: VerifyElement): string[] {\n const files = new Set(sourceFiles(b));\n return sourceFiles(a).filter((f) => files.has(f));\n}\n\nfunction sharesSourceFile(a: VerifyElement, b: VerifyElement): boolean {\n return sharedSourceFiles(a, b).length > 0;\n}\n\n/**\n * Fields where the built element differs from what the plan states. Only what the plan states is\n * compared: a description or attribute the build adds beyond the plan is not a divergence. The\n * exception is `removedBy`: fields a planned update changes that the planned record no longer has\n * (an attribute removed, a description cleared). The build must not have them either.\n */\nfunction compareElements(planned: VerifyElement, built: VerifyElement, removedBy?: string[]): FieldDifference[] {\n const fields: FieldDifference[] = [];\n if (planned.type && !sameType(planned, built)) {\n fields.push({ field: \"type\", planned: planned.type, built: built.type });\n }\n if (planned.name && normalizeName(planned.name) !== normalizeName(built.name)) {\n fields.push({ field: \"name\", planned: planned.name, built: built.name });\n }\n if (planned.description !== undefined && planned.description.trim() !== (built.description ?? \"\").trim()) {\n fields.push({ field: \"description\", planned: planned.description, built: built.description });\n }\n for (const [key, value] of Object.entries(planned.attributes ?? {})) {\n const builtValue = built.attributes?.[key];\n if (!sameAttribute(key, value, builtValue)) {\n fields.push({ field: `attributes.${key}`, planned: value, built: builtValue });\n }\n }\n for (const field of removedBy ?? []) {\n if (field === \"description\") {\n if (planned.description === undefined && (built.description ?? \"\").trim() !== \"\") {\n fields.push({ field, planned: undefined, built: built.description });\n }\n } else if (field.startsWith(\"attributes.\")) {\n const key = field.slice(\"attributes.\".length);\n const plannedHas = planned.attributes !== undefined && Object.hasOwn(planned.attributes, key);\n if (!plannedHas && built.attributes?.[key] !== undefined) {\n fields.push({ field, planned: undefined, built: built.attributes[key] });\n }\n }\n }\n // Both sides always, null where a side has no value, so \"absent\" reads differently from \"same\".\n return fields.map((f) => ({ field: f.field, planned: f.planned ?? null, built: f.built ?? null }));\n}\n\n/** A field's value on an element, by the names `compareElements` and `changedFields` use. */\nfunction fieldValue(element: VerifyElement, field: string): unknown {\n if (field === \"type\") return element.type;\n if (field === \"name\") return element.name;\n if (field === \"description\") return element.description;\n if (field.startsWith(\"attributes.\")) return element.attributes?.[field.slice(\"attributes.\".length)];\n return undefined;\n}\n\nfunction sameFieldValue(field: string, a: unknown, b: unknown): boolean {\n if (field === \"type\" || field === \"name\") {\n return normalizeName(String(a ?? \"\")) === normalizeName(String(b ?? \"\"));\n }\n if (field === \"description\") return String(a ?? \"\").trim() === String(b ?? \"\").trim();\n if (field.startsWith(\"attributes.\")) return sameAttribute(field.slice(\"attributes.\".length), a, b);\n return sameValue(a, b);\n}\n\n/** A path with its parameters as `{}` (`{ownerId}`, `:ownerId`, `{}`) and no trailing slash. */\nfunction normalizeHttpPath(p: string): string {\n return p.replace(/\\{[^}]*\\}|:[A-Za-z_]\\w*/g, \"{}\").replace(/\\/+$/, \"\") || \"/\";\n}\n\n/**\n * A route's method and normalized path, from `GET /owners/{ownerId}` or CBM's\n * `__route__GET__/owners/{ownerId}`; undefined for anything else.\n */\nfunction routeKey(text: string): string | undefined {\n const m = /^__route__([A-Z]+)__(\\/\\S*)$/.exec(text.trim()) ?? /^([A-Z]+)\\s+(\\/\\S*)$/.exec(text.trim());\n return m ? `${m[1]} ${normalizeHttpPath(m[2])}` : undefined;\n}\n\n/**\n * Attribute equality. An operation's path matches whatever its parameters are named, and its\n * method ignores case, as extraction compares them (`sameFact` in extraction-plan.ts).\n */\nfunction sameAttribute(key: string, a: unknown, b: unknown): boolean {\n if (typeof a === \"string\" && typeof b === \"string\") {\n if (key === \"http_path\") return normalizeHttpPath(a) === normalizeHttpPath(b);\n if (key === \"http_method\") return a.toUpperCase() === b.toUpperCase();\n }\n return sameValue(a, b);\n}\n\n/**\n * Whether the build left a differing field as it was before the plan, or doesn't have it: what a\n * build from extraction looks like for a field extraction never writes.\n */\nfunction buildLeft(planned: PlannedElementChange, built: BuiltElement, difference: FieldDifference): boolean {\n if (difference.built === null) return true;\n if (planned.op !== \"update\") return false;\n if (planned.baseValues && Object.hasOwn(planned.baseValues, difference.field)) {\n return sameFieldValue(difference.field, fieldValue(built, difference.field), planned.baseValues[difference.field]);\n }\n return built.change !== \"updated\" && built.change !== \"added\";\n}\n\n/**\n * Whether the build changed `field` from what it was before the plan. Uses the plan's recorded base\n * value; without one, falls back to whether the build changed the element at all (unknown against\n * the base model, where it counts as untouched).\n */\nfunction buildTouched(planned: PlannedElementChange, built: BuiltElement, field: string): boolean {\n if (planned.baseValues && Object.hasOwn(planned.baseValues, field)) {\n return !sameFieldValue(field, fieldValue(built, field), planned.baseValues[field]);\n }\n return built.change === \"updated\" || built.change === \"added\";\n}\n\nfunction changedFields(before: VerifyElement, after: VerifyElement): string[] {\n const fields: string[] = [];\n if (before.type !== after.type) fields.push(\"type\");\n if (before.name !== after.name) fields.push(\"name\");\n if ((before.description ?? \"\") !== (after.description ?? \"\")) fields.push(\"description\");\n const keys = new Set([...Object.keys(before.attributes ?? {}), ...Object.keys(after.attributes ?? {})]);\n for (const key of keys) {\n if (!sameValue(before.attributes?.[key], after.attributes?.[key])) fields.push(`attributes.${key}`);\n }\n return fields;\n}\n\nfunction sameValue(a: unknown, b: unknown): boolean {\n return stableStringify(a) === stableStringify(b);\n}\n\nfunction stableStringify(value: unknown): string {\n if (value === undefined) return \"undefined\";\n if (value === null || typeof value !== \"object\") return JSON.stringify(value);\n if (Array.isArray(value)) return `[${value.map(stableStringify).join(\",\")}]`;\n const entries = Object.keys(value as Record<string, unknown>)\n .sort()\n .map((k) => `${JSON.stringify(k)}:${stableStringify((value as Record<string, unknown>)[k])}`);\n return `{${entries.join(\",\")}}`;\n}\n\nfunction relKey(rel: VerifyRelationship): string {\n return `${rel.source}::${rel.predicate}::${rel.target}`;\n}\n\nfunction strip(rel: VerifyRelationship): VerifyRelationship {\n return { source: rel.source, predicate: rel.predicate, target: rel.target };\n}\n\nfunction readRelationship(change: StagedChange, resolve: (id: string) => string): VerifyRelationship | null {\n const data = (change.type === \"relationship-delete\" ? (change.before ?? change.after) : change.after) as\n | Partial<GraphRelationship>\n | undefined;\n const [source, predicate, target] =\n data?.source && data.predicate && data.target\n ? [data.source, data.predicate, data.target]\n : change.elementId.split(\"::\");\n if (!source || !predicate || !target) return null;\n return { source: resolve(source), predicate, target: resolve(target) };\n}\n\nfunction idNameSegment(id: string): string | undefined {\n const parts = id.split(\".\");\n return parts.length >= 3 ? parts.slice(2).join(\".\") : undefined;\n}\n\nfunction fromId(id: string, layerName: string): VerifyElement {\n const parts = id.split(\".\");\n return {\n id,\n layer: parts.length >= 3 ? parts[0] : layerName,\n type: parts.length >= 3 ? parts[1] : \"\",\n name: idNameSegment(id) ?? id,\n attributes: {},\n };\n}\n\nfunction fromGraphElement(element: GraphElement): VerifyElement {\n return {\n id: element.id,\n layer: element.layer,\n type: element.type,\n name: element.name,\n ...(element.description !== undefined ? { description: element.description } : {}),\n attributes: element.attributes ?? {},\n ...(element.sourceReference ? { sourceReference: element.sourceReference } : {}),\n };\n}\n\nfunction toVerifyElement(record: Record<string, unknown>, layerName: string, id: string): VerifyElement {\n const str = (value: unknown): string | undefined =>\n typeof value === \"string\" && value.length > 0 ? value : undefined;\n const fallback = fromId(id, layerName);\n return {\n id,\n layer: str(record.layer_id) ?? str(record.layer) ?? fallback.layer,\n type: str(record.type) ?? fallback.type,\n name: str(record.name) ?? fallback.name,\n ...(str(record.description) !== undefined ? { description: str(record.description) } : {}),\n attributes:\n record.attributes && typeof record.attributes === \"object\"\n ? (record.attributes as Record<string, unknown>)\n : {},\n ...(stagedSourceReference(record) ? { sourceReference: stagedSourceReference(record) } : {}),\n };\n}\n\nfunction emptyCounts(): CategoryCounts {\n return { planned: 0, matched: 0, probable: 0, missing: 0, divergent: 0, unplanned: 0, deletionsNotDone: 0, unverifiable: 0 };\n}\n\nfunction countCategories(\n planned: number,\n section: {\n matched: Array<{ match: MatchKind }>;\n divergent: Array<{ match: MatchKind }>;\n missing: unknown[];\n unverifiable: unknown[];\n unplanned: unknown[];\n deletionsNotDone: unknown[];\n }\n): CategoryCounts {\n return {\n planned,\n matched: section.matched.length + section.divergent.length,\n probable: [...section.matched, ...section.divergent].filter((m) => m.match === \"probable\").length,\n missing: section.missing.length,\n divergent: section.divergent.length,\n unplanned: section.unplanned.length,\n deletionsNotDone: section.deletionsNotDone.length,\n unverifiable: section.unverifiable.length,\n };\n}\n\nfunction decideVerdict(report: VerifyReport): { verdict: Verdict; text: string } {\n const e = report.summary.elements;\n const r = report.summary.relationships;\n if (e.planned === 0 && r.planned === 0) {\n return { verdict: \"empty-plan\", text: \"The plan has no changes to verify.\" };\n }\n\n const parts: string[] = [];\n const say = (n: number, what: string) => {\n if (n > 0) parts.push(`${n} ${what}`);\n };\n say(e.missing, plural(e.missing, \"planned element\", \"planned elements\") + \" missing\");\n say(r.missing, plural(r.missing, \"planned relationship\", \"planned relationships\") + \" missing\");\n say(e.deletionsNotDone + r.deletionsNotDone, \"planned deletion(s) not done\");\n say(e.divergent, plural(e.divergent, \"element differs\", \"elements differ\"));\n say(r.divergent, plural(r.divergent, \"relationship differs\", \"relationships differ\"));\n say(e.unplanned, plural(e.unplanned, \"unplanned element change\", \"unplanned element changes\"));\n say(r.unplanned, plural(r.unplanned, \"unplanned relationship\", \"unplanned relationships\"));\n\n const probable = e.probable + r.probable;\n const probableText = probable > 0 ? ` ${probable} match(es) are probable, not exact; confirm them.` : \"\";\n const unverifiable = e.unverifiable + r.unverifiable;\n const unverifiableText =\n unverifiable > 0\n ? ` ${[\n e.unverifiable > 0 ? `${e.unverifiable} planned ${plural(e.unverifiable, \"element\", \"elements\")}` : \"\",\n r.unverifiable > 0 ? `${r.unverifiable} planned ${plural(r.unverifiable, \"relationship\", \"relationships\")}` : \"\",\n ]\n .filter(Boolean)\n .join(\" and \")} can't be seen by extraction (unverifiable, not counted): check them in the code or the review.`\n : \"\";\n\n if (e.planned + r.planned === unverifiable && e.unplanned + r.unplanned === 0) {\n return {\n verdict: \"unverifiable\",\n text: `Nothing in the plan can be checked against extracted code.${unverifiableText}`,\n };\n }\n if (e.missing + r.missing + e.deletionsNotDone + r.deletionsNotDone > 0) {\n return { verdict: \"incomplete\", text: `The build is incomplete: ${parts.join(\", \")}.${probableText}${unverifiableText}` };\n }\n if (e.divergent + r.divergent + e.unplanned + r.unplanned > 0) {\n return { verdict: \"diverges\", text: `The build diverges from the plan: ${parts.join(\", \")}.${probableText}${unverifiableText}` };\n }\n const scope = unverifiable > 0 ? \"Everything extraction can see was found.\" : \"Everything planned was found.\";\n if (probable > 0) {\n return { verdict: \"probable-match\", text: `${scope}${probableText}${unverifiableText}` };\n }\n return {\n verdict: \"match\",\n text: unverifiable > 0 ? `The build matches what extraction can see of the plan.${unverifiableText}` : \"The build matches the plan.\",\n };\n}\n\nfunction plural(n: number, one: string, many: string): string {\n return n === 1 ? one : many;\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["previous", "verdict", "share"]
7
7
  }