@stacksjs/defaults 0.75.361 → 0.75.362

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 (208) hide show
  1. package/ai/skills/stacks-ai/SKILL.md +22 -0
  2. package/ai/skills/stacks-native/CATALOG.md +2 -2
  3. package/ai/skills/stacks-technical-diagrams/LICENSE +202 -22
  4. package/ai/skills/stacks-technical-diagrams/LICENSE-MIT +22 -0
  5. package/ai/skills/stacks-technical-diagrams/NOTICE +26 -0
  6. package/ai/skills/stacks-technical-diagrams/SKILL.md +106 -266
  7. package/ai/skills/stacks-technical-diagrams/THIRD_PARTY_NOTICES.md +11 -2
  8. package/ai/skills/stacks-technical-diagrams/UPSTREAM.json +12 -0
  9. package/ai/skills/stacks-technical-diagrams/agents/openai.yaml +2 -2
  10. package/ai/skills/stacks-technical-diagrams/assets/template.html +3655 -3798
  11. package/ai/skills/stacks-technical-diagrams/bin/archify.mjs +7290 -0
  12. package/ai/skills/stacks-technical-diagrams/bin/delivery-update.mjs +7 -0
  13. package/ai/skills/stacks-technical-diagrams/bin/diagrams +1 -0
  14. package/ai/skills/stacks-technical-diagrams/bin/finalize.mjs +1056 -0
  15. package/ai/skills/stacks-technical-diagrams/bin/open-artifact.mjs +72 -12
  16. package/ai/skills/stacks-technical-diagrams/bin/preview.mjs +348 -31
  17. package/ai/skills/stacks-technical-diagrams/bin/recover-output.mjs +41 -0
  18. package/ai/skills/stacks-technical-diagrams/bin/technical-diagrams.mjs +3 -2097
  19. package/ai/skills/stacks-technical-diagrams/bin/visual-check.mjs +2142 -157
  20. package/ai/skills/stacks-technical-diagrams/brand-marks/README.md +3 -3
  21. package/ai/skills/stacks-technical-diagrams/delta/architecture-delta.mjs +130 -33
  22. package/ai/skills/stacks-technical-diagrams/examples/agent-run.lifecycle.json +25 -30
  23. package/ai/skills/stacks-technical-diagrams/examples/agent-tool-call.workflow.json +0 -20
  24. package/ai/skills/stacks-technical-diagrams/examples/archify-dev-activity.timeline.json +176 -0
  25. package/ai/skills/stacks-technical-diagrams/examples/archify-repository.tree.json +197 -0
  26. package/ai/skills/stacks-technical-diagrams/examples/async-job-roundtrip.sequence.json +1 -6
  27. package/ai/skills/stacks-technical-diagrams/examples/brand-aware-delivery.architecture.json +3 -16
  28. package/ai/skills/stacks-technical-diagrams/examples/cache-miss-request.sequence.json +2 -7
  29. package/ai/skills/stacks-technical-diagrams/examples/checkout-platform.base.architecture.json +2 -1
  30. package/ai/skills/stacks-technical-diagrams/examples/checkout-platform.head.architecture.json +2 -1
  31. package/ai/skills/stacks-technical-diagrams/examples/checkout-request.waterfall.json +20 -0
  32. package/ai/skills/stacks-technical-diagrams/examples/class-payment-processors-rendered.html +14987 -0
  33. package/ai/skills/stacks-technical-diagrams/examples/class-payments-rendered.html +14787 -0
  34. package/ai/skills/stacks-technical-diagrams/examples/dataflow-product-analytics.html +14880 -0
  35. package/ai/skills/stacks-technical-diagrams/examples/delivery.explainer.json +155 -0
  36. package/ai/skills/stacks-technical-diagrams/examples/deployment-release.lifecycle.json +57 -34
  37. package/ai/skills/stacks-technical-diagrams/examples/erd-orders-rendered.html +15112 -0
  38. package/ai/skills/stacks-technical-diagrams/examples/event-stream.dataflow.json +1 -6
  39. package/ai/skills/stacks-technical-diagrams/examples/example-rebuild.waterfall.json +212 -0
  40. package/ai/skills/stacks-technical-diagrams/examples/holiday-planning.workflow.json +143 -0
  41. package/ai/skills/stacks-technical-diagrams/examples/incident-response.workflow.json +1 -6
  42. package/ai/skills/stacks-technical-diagrams/examples/lifecycle-agent-run.html +14892 -0
  43. package/ai/skills/stacks-technical-diagrams/examples/locales/de.json +463 -0
  44. package/ai/skills/stacks-technical-diagrams/examples/locales/fr.json +463 -0
  45. package/ai/skills/stacks-technical-diagrams/examples/locales/fr.partial.json +22 -0
  46. package/ai/skills/stacks-technical-diagrams/examples/locales/it.json +463 -0
  47. package/ai/skills/stacks-technical-diagrams/examples/locales/ja.json +463 -0
  48. package/ai/skills/stacks-technical-diagrams/examples/locales/pt.json +463 -0
  49. package/ai/skills/stacks-technical-diagrams/examples/locales/ru.json +463 -0
  50. package/ai/skills/stacks-technical-diagrams/examples/orders.erd.json +337 -0
  51. package/ai/skills/stacks-technical-diagrams/examples/payment-incident.timeline.json +24 -0
  52. package/ai/skills/stacks-technical-diagrams/examples/payment-platform.tree.json +22 -0
  53. package/ai/skills/stacks-technical-diagrams/examples/payment-processors.class.json +177 -0
  54. package/ai/skills/stacks-technical-diagrams/examples/payments.class.json +85 -0
  55. package/ai/skills/stacks-technical-diagrams/examples/product-analytics.dataflow.json +1 -6
  56. package/ai/skills/stacks-technical-diagrams/examples/production-deployment.architecture.json +3 -23
  57. package/ai/skills/stacks-technical-diagrams/examples/release-delivery.workflow.json +1 -6
  58. package/ai/skills/stacks-technical-diagrams/examples/sequence-cache-miss-request.html +14895 -0
  59. package/ai/skills/stacks-technical-diagrams/examples/subscription-billing-rendered.html +15369 -0
  60. package/ai/skills/stacks-technical-diagrams/examples/subscription-billing.erd.json +548 -0
  61. package/ai/skills/stacks-technical-diagrams/examples/timeline-archify-dev-activity-rendered.html +15002 -0
  62. package/ai/skills/stacks-technical-diagrams/examples/timeline-payment-incident-rendered.html +14772 -0
  63. package/ai/skills/stacks-technical-diagrams/examples/tree-archify-repository-rendered.html +15071 -0
  64. package/ai/skills/stacks-technical-diagrams/examples/tree-payment-platform-rendered.html +14810 -0
  65. package/ai/skills/stacks-technical-diagrams/examples/waterfall-checkout-request-rendered.html +14754 -0
  66. package/ai/skills/stacks-technical-diagrams/examples/waterfall-example-rebuild-rendered.html +14940 -0
  67. package/ai/skills/stacks-technical-diagrams/examples/web-app-rendered.html +14889 -0
  68. package/ai/skills/stacks-technical-diagrams/examples/web-app.architecture.json +1 -6
  69. package/ai/skills/stacks-technical-diagrams/examples/workflow-agent-tool-call-rendered.html +14907 -0
  70. package/ai/skills/stacks-technical-diagrams/explainer/browser-check.mjs +208 -0
  71. package/ai/skills/stacks-technical-diagrams/explainer/charts.mjs +70 -0
  72. package/ai/skills/stacks-technical-diagrams/explainer/check.mjs +168 -0
  73. package/ai/skills/stacks-technical-diagrams/explainer/diagrams.mjs +518 -0
  74. package/ai/skills/stacks-technical-diagrams/explainer/diff.mjs +124 -0
  75. package/ai/skills/stacks-technical-diagrams/explainer/inline.mjs +155 -0
  76. package/ai/skills/stacks-technical-diagrams/explainer/layout.mjs +35 -0
  77. package/ai/skills/stacks-technical-diagrams/explainer/page-bundle.mjs +16 -0
  78. package/ai/skills/stacks-technical-diagrams/explainer/parse.mjs +300 -0
  79. package/ai/skills/stacks-technical-diagrams/explainer/patch.mjs +117 -0
  80. package/ai/skills/stacks-technical-diagrams/explainer/prepare.mjs +131 -0
  81. package/ai/skills/stacks-technical-diagrams/explainer/reader.css +472 -0
  82. package/ai/skills/stacks-technical-diagrams/explainer/reader.js +667 -0
  83. package/ai/skills/stacks-technical-diagrams/explainer/render.mjs +224 -0
  84. package/ai/skills/stacks-technical-diagrams/explainer/revision.mjs +20 -0
  85. package/ai/skills/stacks-technical-diagrams/explainer/sources.mjs +318 -0
  86. package/ai/skills/stacks-technical-diagrams/explainer/validate.mjs +138 -0
  87. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/LICENSE +40 -0
  88. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/README.md +5 -0
  89. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/3DKXF73K.js +4 -0
  90. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/42UTT654.js +3 -0
  91. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/DKTLEL5E.js +1 -0
  92. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/EEIX5ZYH.js +2 -0
  93. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/EJ5KOXYD.js +25 -0
  94. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/GUJTEFZK.js +1 -0
  95. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/IZOKQ2GT.js +4 -0
  96. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/L4LY553T.js +3 -0
  97. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/MSKIJHB2.js +2 -0
  98. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/RVARI57O.js +1 -0
  99. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/UKSIWDDN.js +2 -0
  100. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/UPTXNAXN.js +2 -0
  101. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/XTDUIGUI.js +9 -0
  102. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/YAYTP6L5.js +9 -0
  103. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/core.js +1 -0
  104. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/diagrams/pie.js +1 -0
  105. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/diagrams/quadrantChart.js +1 -0
  106. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/diagrams/radar.js +1 -0
  107. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/diagrams/sankey.js +1 -0
  108. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/diagrams/venn.js +1 -0
  109. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/diagrams/xychart.js +1 -0
  110. package/ai/skills/stacks-technical-diagrams/explainer/writing.mjs +139 -0
  111. package/ai/skills/stacks-technical-diagrams/locales/README.md +40 -0
  112. package/ai/skills/stacks-technical-diagrams/locales/ar.json +488 -0
  113. package/ai/skills/stacks-technical-diagrams/locales/en.json +488 -0
  114. package/ai/skills/stacks-technical-diagrams/locales/es.json +488 -0
  115. package/ai/skills/stacks-technical-diagrams/locales/ko.json +488 -0
  116. package/ai/skills/stacks-technical-diagrams/locales/manifest.json +10 -0
  117. package/ai/skills/stacks-technical-diagrams/locales/zh-CN.json +488 -0
  118. package/ai/skills/stacks-technical-diagrams/locales/zh-TW.json +488 -0
  119. package/ai/skills/stacks-technical-diagrams/migrations/workflow-v2.mjs +1 -0
  120. package/ai/skills/stacks-technical-diagrams/recipes/scenarios.mjs +115 -51
  121. package/ai/skills/stacks-technical-diagrams/references/architecture-layout-repair.md +18 -0
  122. package/ai/skills/stacks-technical-diagrams/references/authoring-contract.md +453 -51
  123. package/ai/skills/stacks-technical-diagrams/references/authoring-defaults.md +57 -0
  124. package/ai/skills/stacks-technical-diagrams/references/brand-marks.md +57 -3
  125. package/ai/skills/stacks-technical-diagrams/references/delivery-contract.md +603 -58
  126. package/ai/skills/stacks-technical-diagrams/references/explainer-authoring.md +274 -0
  127. package/ai/skills/stacks-technical-diagrams/references/repository-authoring.md +126 -0
  128. package/ai/skills/stacks-technical-diagrams/references/update-awareness.md +13 -0
  129. package/ai/skills/stacks-technical-diagrams/references/viewer-runtime.md +18 -11
  130. package/ai/skills/stacks-technical-diagrams/renderers/architecture/grid.mjs +1 -1
  131. package/ai/skills/stacks-technical-diagrams/renderers/architecture/labels.mjs +2 -0
  132. package/ai/skills/stacks-technical-diagrams/renderers/architecture/render-architecture.mjs +550 -424
  133. package/ai/skills/stacks-technical-diagrams/renderers/architecture/routing.mjs +1469 -0
  134. package/ai/skills/stacks-technical-diagrams/renderers/class/README.md +129 -0
  135. package/ai/skills/stacks-technical-diagrams/renderers/class/render-class.mjs +1095 -0
  136. package/ai/skills/stacks-technical-diagrams/renderers/dataflow/README.md +89 -17
  137. package/ai/skills/stacks-technical-diagrams/renderers/dataflow/dataflow-compiler.mjs +1605 -0
  138. package/ai/skills/stacks-technical-diagrams/renderers/dataflow/joint-label-routing.mjs +165 -0
  139. package/ai/skills/stacks-technical-diagrams/renderers/dataflow/label-capacity.mjs +81 -0
  140. package/ai/skills/stacks-technical-diagrams/renderers/dataflow/render-dataflow.mjs +14 -474
  141. package/ai/skills/stacks-technical-diagrams/renderers/erd/README.md +246 -0
  142. package/ai/skills/stacks-technical-diagrams/renderers/erd/grid.mjs +150 -0
  143. package/ai/skills/stacks-technical-diagrams/renderers/erd/render-erd.mjs +1588 -0
  144. package/ai/skills/stacks-technical-diagrams/renderers/explainer/render-explainer.mjs +42 -0
  145. package/ai/skills/stacks-technical-diagrams/renderers/lifecycle/README.md +83 -94
  146. package/ai/skills/stacks-technical-diagrams/renderers/lifecycle/render-lifecycle.mjs +990 -417
  147. package/ai/skills/stacks-technical-diagrams/renderers/sequence/README.md +49 -17
  148. package/ai/skills/stacks-technical-diagrams/renderers/sequence/render-sequence.mjs +735 -94
  149. package/ai/skills/stacks-technical-diagrams/renderers/shared/atomic-output.mjs +1982 -0
  150. package/ai/skills/stacks-technical-diagrams/renderers/shared/automatic-labels.mjs +290 -0
  151. package/ai/skills/stacks-technical-diagrams/renderers/shared/brand-marks.mjs +169 -26
  152. package/ai/skills/stacks-technical-diagrams/renderers/shared/cli.mjs +266 -54
  153. package/ai/skills/stacks-technical-diagrams/renderers/shared/desktop-readability.mjs +106 -0
  154. package/ai/skills/stacks-technical-diagrams/renderers/shared/diagnostics.mjs +0 -0
  155. package/ai/skills/stacks-technical-diagrams/renderers/shared/generated-validators.mjs +268 -2
  156. package/ai/skills/stacks-technical-diagrams/renderers/shared/geometry.mjs +774 -124
  157. package/ai/skills/stacks-technical-diagrams/renderers/shared/i18n.mjs +289 -556
  158. package/ai/skills/stacks-technical-diagrams/renderers/shared/layout-report.mjs +18 -1
  159. package/ai/skills/stacks-technical-diagrams/renderers/shared/legend.mjs +16 -6
  160. package/ai/skills/stacks-technical-diagrams/renderers/shared/node-card-style.mjs +32 -0
  161. package/ai/skills/stacks-technical-diagrams/renderers/shared/output-path.mjs +329 -229
  162. package/ai/skills/stacks-technical-diagrams/renderers/shared/owned-temp-directory.mjs +82 -0
  163. package/ai/skills/stacks-technical-diagrams/renderers/shared/path-semantics.mjs +1017 -0
  164. package/ai/skills/stacks-technical-diagrams/renderers/shared/portable-path.mjs +408 -0
  165. package/ai/skills/stacks-technical-diagrams/renderers/shared/repository-evidence.mjs +235 -79
  166. package/ai/skills/stacks-technical-diagrams/renderers/shared/repository-location.mjs +17 -4
  167. package/ai/skills/stacks-technical-diagrams/renderers/shared/route-quality.mjs +670 -0
  168. package/ai/skills/stacks-technical-diagrams/renderers/shared/sidecar-path.mjs +38 -0
  169. package/ai/skills/stacks-technical-diagrams/renderers/shared/software-notices.mjs +6 -0
  170. package/ai/skills/stacks-technical-diagrams/renderers/shared/spatial-grid.mjs +66 -0
  171. package/ai/skills/stacks-technical-diagrams/renderers/shared/svg-path-analysis.mjs +135 -0
  172. package/ai/skills/stacks-technical-diagrams/renderers/shared/text-fit.mjs +59 -3
  173. package/ai/skills/stacks-technical-diagrams/renderers/shared/utils.mjs +63 -35
  174. package/ai/skills/stacks-technical-diagrams/renderers/shared/validator.mjs +2 -5
  175. package/ai/skills/stacks-technical-diagrams/renderers/timeline/README.md +76 -0
  176. package/ai/skills/stacks-technical-diagrams/renderers/timeline/render-timeline.mjs +576 -0
  177. package/ai/skills/stacks-technical-diagrams/renderers/tree/README.md +96 -0
  178. package/ai/skills/stacks-technical-diagrams/renderers/tree/render-tree.mjs +573 -0
  179. package/ai/skills/stacks-technical-diagrams/renderers/waterfall/README.md +73 -0
  180. package/ai/skills/stacks-technical-diagrams/renderers/waterfall/render-waterfall.mjs +413 -0
  181. package/ai/skills/stacks-technical-diagrams/renderers/workflow/README.md +137 -23
  182. package/ai/skills/stacks-technical-diagrams/renderers/workflow/render-workflow.mjs +18 -6
  183. package/ai/skills/stacks-technical-diagrams/renderers/workflow/workflow-compiler.mjs +2230 -710
  184. package/ai/skills/stacks-technical-diagrams/renderers/workflow/workflow-migration-geometry.mjs +17 -0
  185. package/ai/skills/stacks-technical-diagrams/renderers/workflow/workflow-placement-repair.mjs +94 -0
  186. package/ai/skills/stacks-technical-diagrams/schemas/README.md +87 -40
  187. package/ai/skills/stacks-technical-diagrams/schemas/architecture.schema.json +7 -33
  188. package/ai/skills/stacks-technical-diagrams/schemas/class.schema.json +345 -0
  189. package/ai/skills/stacks-technical-diagrams/schemas/common.schema.json +68 -2
  190. package/ai/skills/stacks-technical-diagrams/schemas/dataflow.schema.json +14 -3
  191. package/ai/skills/stacks-technical-diagrams/schemas/erd.schema.json +381 -0
  192. package/ai/skills/stacks-technical-diagrams/schemas/explainer.schema.json +927 -0
  193. package/ai/skills/stacks-technical-diagrams/schemas/lifecycle.schema.json +23 -110
  194. package/ai/skills/stacks-technical-diagrams/schemas/sequence.schema.json +15 -4
  195. package/ai/skills/stacks-technical-diagrams/schemas/timeline.schema.json +160 -0
  196. package/ai/skills/stacks-technical-diagrams/schemas/tree.schema.json +141 -0
  197. package/ai/skills/stacks-technical-diagrams/schemas/waterfall.schema.json +147 -0
  198. package/ai/skills/stacks-technical-diagrams/schemas/workflow.schema.json +14 -3
  199. package/ai/skills/stacks-technical-diagrams/scripts/check-render-output.mjs +876 -243
  200. package/ai/skills/stacks-technical-diagrams/scripts/check-update.mjs +1717 -0
  201. package/ai/skills/stacks-technical-diagrams/scripts/delivery-update-child.mjs +26 -0
  202. package/ai/skills/stacks-technical-diagrams/scripts/generate-brand-marks.mjs +141 -0
  203. package/ai/skills/stacks-technical-diagrams/scripts/generate-validators.mjs +105 -0
  204. package/ai/skills/stacks-technical-diagrams/scripts/render-examples.mjs +11 -1
  205. package/ai/skills/stacks-technical-diagrams/scripts/update-contract.mjs +187 -0
  206. package/ai/skills/stacks-technical-diagrams/skill-release.json +10 -0
  207. package/ide/vscode/package.json +1 -1
  208. package/package.json +2 -2
@@ -1,12 +1,12 @@
1
1
  # Built-in brand marks
2
2
 
3
- This skill ships a bounded catalogue of 107 commonly used brands for architecture,
3
+ Archify ships a bounded catalogue of 107 commonly used brands for architecture,
4
4
  workflow, sequence, data-flow, and lifecycle nodes. The mark is optional authored
5
5
  identity: it never replaces the node's semantic `type`, color, label, or
6
6
  relationships.
7
7
 
8
8
  Unknown sites are handled by an explicit two-stage workflow. Run
9
- `.claude/skills/stacks-technical-diagrams/bin/diagrams brands capture <url> --json`, then author the returned
9
+ `node bin/archify.mjs brands capture <url> --json`, then author the returned
10
10
  digest-pinned `brand` value. Normal render and validate commands do not perform
11
11
  an unpinned capture, and changed or unavailable content fails closed.
12
12
 
@@ -18,7 +18,7 @@ metadata in `renderers/shared/generated-brand-marks.mjs`.
18
18
  Brand names and logos may be trademarks of their respective owners. Simple
19
19
  Icons' CC0 license covers its collection work, not every underlying trademark or
20
20
  artwork. Contributors must review the recorded source, current brand guidelines,
21
- and intended referential use before adding or updating a mark. This skill does not
21
+ and intended referential use before adding or updating a mark. Archify does not
22
22
  imply sponsorship, endorsement, or partnership.
23
23
 
24
24
  Edit `catalog.json`, then regenerate the committed zero-runtime-dependency bundle:
@@ -1,3 +1,4 @@
1
+ import { softwareNoticesHtml } from '../renderers/shared/software-notices.mjs';
1
2
  import { parseRepositoryRemote } from '../renderers/shared/repository-location.mjs';
2
3
 
3
4
  const COMPARATOR_VERSION = 1;
@@ -35,16 +36,42 @@ function sortedBy(values, keyFor) {
35
36
 
36
37
  function normalizeRepository(repository) {
37
38
  if (!repository) return undefined;
38
- const location = parseRepositoryRemote(repository.url, { authored: true });
39
+ const location = parseRepositoryRemote(repository.url, { authored: true, provider: repository.provider });
39
40
  const url = location?.url || String(repository.url || '');
40
41
  return {
41
- url: location?.provider === 'github' ? url.toLowerCase() : url,
42
+ url: location?.provider === 'github' || location?.provider === 'gitlab' ? url.toLowerCase() : url,
42
43
  revision: String(repository.revision || '').toLowerCase(),
43
44
  ...(repository.provider !== undefined ? { provider: repository.provider } : {}),
44
45
  ...(repository.link_mode !== undefined ? { link_mode: repository.link_mode } : {}),
45
46
  };
46
47
  }
47
48
 
49
+ const PROVENANCE_FIELDS = ['url', 'revision', 'provider', 'link_mode'];
50
+
51
+ function provenanceSide(repository) {
52
+ if (!repository) return null;
53
+ return {
54
+ revision: repository.revision,
55
+ ...(repository.provider !== undefined ? { provider: repository.provider } : {}),
56
+ ...(repository.link_mode !== undefined ? { linkMode: repository.link_mode } : {}),
57
+ };
58
+ }
59
+
60
+ function provenanceChange(base, head) {
61
+ if (equal(base, head)) return undefined;
62
+ const changedFields = !base || !head
63
+ ? ['/repository']
64
+ : PROVENANCE_FIELDS
65
+ .filter((field) => !equal(base[field], head[field]))
66
+ .map((field) => `/${field}`)
67
+ .sort(codepointOrder);
68
+ return {
69
+ changedFields,
70
+ base: provenanceSide(base),
71
+ head: provenanceSide(head),
72
+ };
73
+ }
74
+
48
75
  function normalizeComponent(component) {
49
76
  return {
50
77
  ...component,
@@ -155,7 +182,7 @@ function fieldChanges(before, after, groups) {
155
182
  }
156
183
 
157
184
  const COMPONENT_FIELDS = {
158
- semantic: ['type', 'label', 'sublabel', 'tag'],
185
+ semantic: ['type', 'label', 'sublabel', 'tag', 'brand', 'icon'],
159
186
  evidence: ['sources'],
160
187
  geometry: ['row', 'col', 'pos', 'size'],
161
188
  };
@@ -202,26 +229,26 @@ function summaryFor(changes, shape) {
202
229
  function presentationChanged(base, head) {
203
230
  const basePresentation = {
204
231
  title: base.meta?.title,
232
+ locale: base.meta?.locale,
205
233
  subtitle: base.meta?.subtitle,
206
234
  animation: base.meta?.animation,
207
235
  visual_preset: base.meta?.visual_preset,
208
236
  quality_profile: base.meta?.quality_profile,
209
237
  engineering_profile: base.meta?.engineering_profile,
210
238
  legend: base.meta?.legend,
211
- views: base.meta?.views,
212
239
  viewBox: base.meta?.viewBox,
213
240
  layout: base.layout,
214
241
  cards: base.cards,
215
242
  };
216
243
  const headPresentation = {
217
244
  title: head.meta?.title,
245
+ locale: head.meta?.locale,
218
246
  subtitle: head.meta?.subtitle,
219
247
  animation: head.meta?.animation,
220
248
  visual_preset: head.meta?.visual_preset,
221
249
  quality_profile: head.meta?.quality_profile,
222
250
  engineering_profile: head.meta?.engineering_profile,
223
251
  legend: head.meta?.legend,
224
- views: head.meta?.views,
225
252
  viewBox: head.meta?.viewBox,
226
253
  layout: head.layout,
227
254
  cards: head.cards,
@@ -236,7 +263,7 @@ export function compareArchitecture(base, head, evidence = {}) {
236
263
  const headComponents = stableIndex(head.components, 'components', 'head');
237
264
  const shared = sorted([...baseComponents.keys()].filter((id) => headComponents.has(id)));
238
265
  if (!shared.length) {
239
- fail('delta/no-shared-component-id', 'The snapshots share no component id, so the comparison cannot prove that they describe the same system.', {
266
+ fail('delta/no-shared-component-id', 'The snapshots share no component id, so Archify cannot prove that they describe the same system.', {
240
267
  supportedFixes: ['preserve at least one authored component id across snapshots'],
241
268
  });
242
269
  }
@@ -248,7 +275,7 @@ export function compareArchitecture(base, head, evidence = {}) {
248
275
 
249
276
  const baseRepository = normalizeRepository(base.meta?.repository);
250
277
  const headRepository = normalizeRepository(head.meta?.repository);
251
- const identity = (repository) => parseRepositoryRemote(repository.url, { authored: true })?.identity || repository.url;
278
+ const identity = (repository) => parseRepositoryRemote(repository.url, { authored: true, provider: repository.provider })?.identity || repository.url;
252
279
  if (baseRepository && headRepository && identity(baseRepository) !== identity(headRepository)) {
253
280
  fail('delta/repository-mismatch', 'The snapshots name different repositories.', {
254
281
  baseRepository: baseRepository.url,
@@ -278,7 +305,8 @@ export function compareArchitecture(base, head, evidence = {}) {
278
305
  kind: (after || before).kind,
279
306
  label: (after || before).label,
280
307
  }));
281
- const provenanceChanged = !equal(baseRepository, headRepository);
308
+ const provenance = provenanceChange(baseRepository, headRepository);
309
+ const provenanceChanged = Boolean(provenance);
282
310
 
283
311
  return {
284
312
  schemaVersion: 1,
@@ -311,6 +339,7 @@ export function compareArchitecture(base, head, evidence = {}) {
311
339
  provenanceChanged,
312
340
  },
313
341
  changes: { components, connections, boundaries },
342
+ ...(provenance ? { provenance } : {}),
314
343
  identity: {
315
344
  components: 'components[].id',
316
345
  connections: 'connections[].id (required)',
@@ -462,11 +491,11 @@ export function annotateArchitectureSideSvg(svg, receipt, side) {
462
491
  if (!change) return markup;
463
492
  if (part === 'frame') {
464
493
  return addState(markup, change, side)
465
- .replace(/\/>$/, ` data-delta-boundary-key="${esc(change.key)}"/>`);
494
+ .replace(/\/>$/, () => ` data-delta-boundary-key="${esc(change.key)}"/>`);
466
495
  }
467
496
  return markup.replace(
468
497
  /<text[^>]*>/,
469
- (tag) => tag.replace(/>$/, ` data-delta-state="${change.status}" data-delta-boundary-state="${change.status}" data-delta-boundary-key="${esc(change.key)}">`),
498
+ (tag) => tag.replace(/>$/, () => ` data-delta-state="${change.status}" data-delta-boundary-state="${change.status}" data-delta-boundary-key="${esc(change.key)}">`),
470
499
  );
471
500
  });
472
501
  result = transformNodeGroups(result, (group, id) => {
@@ -519,13 +548,13 @@ function boundaryMarkupParts(markup) {
519
548
 
520
549
  function forceBoundaryState(markup, state, key, classifications = []) {
521
550
  return markup
522
- .replace(/^<rect[^>]+\/>/, (tag) => addState(tag, { classifications }, 'delta', state).replace(/\/>$/, ` data-delta-boundary-key="${esc(key)}"/>`))
551
+ .replace(/^<rect[^>]+\/>/, (tag) => addState(tag, { classifications }, 'delta', state).replace(/\/>$/, () => ` data-delta-boundary-key="${esc(key)}"/>`))
523
552
  .replace(
524
553
  /<rect data-graph-role="structural-frame-label-mask"[^>]*\/>/,
525
554
  (tag) => addState(tag, { classifications }, 'delta', state)
526
- .replace(/\/>$/, ` data-delta-boundary-state="${state}" data-delta-boundary-mask-key="${esc(key)}"/>`),
555
+ .replace(/\/>$/, () => ` data-delta-boundary-state="${state}" data-delta-boundary-mask-key="${esc(key)}"/>`),
527
556
  )
528
- .replace(/<text[^>]*>/, (tag) => tag.replace(/>$/, ` data-delta-state="${state}" data-delta-boundary-state="${state}" data-delta-boundary-key="${esc(key)}">`));
557
+ .replace(/<text[^>]*>/, (tag) => tag.replace(/>$/, () => ` data-delta-state="${state}" data-delta-boundary-state="${state}" data-delta-boundary-key="${esc(key)}">`));
529
558
  }
530
559
 
531
560
  function viewBoxSize(svg) {
@@ -553,6 +582,9 @@ function boundarySymbolMarkup(markup, state) {
553
582
  export function buildDeltaSvg(baseSvg, headSvg, receipt) {
554
583
  const [baseW, baseH] = viewBoxSize(baseSvg);
555
584
  const [headW, headH] = viewBoxSize(headSvg);
585
+ // Baseline paths and their definitions must travel together in a namespace
586
+ // distinct from the current snapshot before the final Delta prefix is added.
587
+ const baseRelationshipsSvg = prefixSvgIds(baseSvg, 'base');
556
588
  const nodes = changeMap(receipt.changes.components);
557
589
  const edges = changeMap(receipt.changes.connections);
558
590
  const boundaries = boundaryChangeMap(receipt.changes.boundaries);
@@ -569,11 +601,11 @@ export function buildDeltaSvg(baseSvg, headSvg, receipt) {
569
601
  }
570
602
  for (const change of edges.values()) {
571
603
  if (change.status === 'removed' || change.classifications.includes('topology')) {
572
- const phantom = forceElementState(elementById(baseSvg, 'edge', change.id), 'removed', change.classifications);
604
+ const phantom = forceElementState(elementById(baseRelationshipsSvg, 'edge', change.id), 'removed', change.classifications);
573
605
  baseEdgePhantoms.push(phantom);
574
606
  edgeMarkers.push(edgeSymbolMarkup(phantom, 'removed'));
575
607
  } else if (change.classifications.includes('geometry')) {
576
- const phantom = forceElementState(elementById(baseSvg, 'edge', change.id), 'moved-from', change.classifications);
608
+ const phantom = forceElementState(elementById(baseRelationshipsSvg, 'edge', change.id), 'moved-from', change.classifications);
577
609
  baseEdgePhantoms.push(phantom);
578
610
  edgeMarkers.push(edgeSymbolMarkup(phantom, 'moved-from'));
579
611
  }
@@ -595,11 +627,17 @@ export function buildDeltaSvg(baseSvg, headSvg, receipt) {
595
627
  }
596
628
  }
597
629
 
630
+ // Insert generated markup literally: authored labels can contain replacement
631
+ // tokens such as $$, $&, and $` that string replacements would interpret.
598
632
  let delta = annotateArchitectureSideSvg(headSvg, receipt, 'head');
633
+ if (baseEdgePhantoms.length) {
634
+ const baseDefinitions = baseRelationshipsSvg.match(/<defs>([\s\S]*?)<\/defs>/)?.[1] || '';
635
+ delta = delta.replace('</defs>', () => `${baseDefinitions}</defs>`);
636
+ }
599
637
  delta = delta.replace(/^<svg[^>]+>/, (tag) => tag.replace(/viewBox="[^"]+"/, `viewBox="0 0 ${Math.max(baseW, headW) + 24} ${Math.max(baseH, headH) + 24}"`));
600
- delta = delta.replace(' <!-- Boundaries (behind everything) -->', ` <!-- Baseline boundary frame phantoms -->\n${baseBoundaryFramePhantoms.filter(Boolean).join('\n')}\n\n <!-- Boundaries (behind everything) -->`);
601
- delta = delta.replace(' <!-- Connection paths (before components for correct z-order) -->', ` <!-- Baseline relationship phantoms -->\n${baseEdgePhantoms.join('\n')}\n\n <!-- Connection paths (before components for correct z-order) -->`);
602
- delta = delta.replace(' <!-- Components -->', ` <!-- Baseline boundary label phantoms (below current components) -->\n${baseBoundaryLabelPhantoms.filter(Boolean).join('\n')}\n\n <!-- Baseline removed and move-from component phantoms -->\n${baseNodePhantoms.join('\n')}\n\n <!-- Components -->`);
638
+ delta = delta.replace(' <!-- Boundaries (behind everything) -->', () => ` <!-- Baseline boundary frame phantoms -->\n${baseBoundaryFramePhantoms.filter(Boolean).join('\n')}\n\n <!-- Boundaries (behind everything) -->`);
639
+ delta = delta.replace(' <!-- Connection paths (before components for correct z-order) -->', () => ` <!-- Baseline relationship phantoms -->\n${baseEdgePhantoms.join('\n')}\n\n <!-- Connection paths (before components for correct z-order) -->`);
640
+ delta = delta.replace(' <!-- Components -->', () => ` <!-- Baseline boundary label phantoms (below current components) -->\n${baseBoundaryLabelPhantoms.filter(Boolean).join('\n')}\n\n <!-- Baseline removed and move-from component phantoms -->\n${baseNodePhantoms.join('\n')}\n\n <!-- Components -->`);
603
641
 
604
642
  for (const change of edges.values()) {
605
643
  if (change.status === 'added' || change.status === 'changed' || change.status === 'rerouted') {
@@ -612,7 +650,7 @@ export function buildDeltaSvg(baseSvg, headSvg, receipt) {
612
650
  const renderedKey = `${change.kind}:${esc(change.label)}`;
613
651
  boundaryMarkers.push(boundarySymbolMarkup(boundaryMarkupByKey(delta, renderedKey), change.status));
614
652
  }
615
- delta = delta.replace(' <!-- Legend -->', ` <!-- Delta relationship symbols -->\n${edgeMarkers.filter(Boolean).join('\n')}\n\n <!-- Delta boundary symbols -->\n${boundaryMarkers.filter(Boolean).join('\n')}\n\n <!-- Legend -->`);
653
+ delta = delta.replace(' <!-- Legend -->', () => ` <!-- Delta relationship symbols -->\n${edgeMarkers.filter(Boolean).join('\n')}\n\n <!-- Delta boundary symbols -->\n${boundaryMarkers.filter(Boolean).join('\n')}\n\n <!-- Legend -->`);
616
654
  return prefixSvgIds(staticize(delta), 'delta');
617
655
  }
618
656
 
@@ -694,15 +732,39 @@ function expectedReviewTargetSignature(row) {
694
732
 
695
733
  const total = (summary, key) => summary.components[key] + summary.connections[key] + summary.boundaries[key];
696
734
 
735
+ function provenanceDetail(provenance) {
736
+ if (provenance === undefined) return 'Repository metadata changed; field details are unavailable in this receipt.';
737
+ const value = (side, field) => {
738
+ if (!side) return 'undeclared';
739
+ if (field === '/revision') return side.revision?.slice(0, 8) || 'none';
740
+ if (field === '/provider') return side.provider ?? 'automatic';
741
+ if (field === '/link_mode') return side.linkMode ?? 'default';
742
+ if (field === '/repository') return 'declared';
743
+ return 'changed';
744
+ };
745
+ return provenance.changedFields.map((field) => {
746
+ if (field === '/url') return '/url: repository location changed';
747
+ return `${field}: ${value(provenance.base, field)} → ${value(provenance.head, field)}`;
748
+ }).join(' · ');
749
+ }
750
+
697
751
  export function renderArchitectureDeltaHtml({ receipt, baseSvg, deltaSvg, headSvg, baseHtml = '', headHtml = '', artifactCss }) {
698
752
  const rows = architectureDeltaChangeRows(receipt);
699
753
  const changed = total(receipt.summary, 'changed');
700
754
  const proof = receipt.proofLevel === 'revision-pinned' ? 'REVISION-PINNED INPUTS' : 'AUTHORED SNAPSHOTS';
755
+ const provenanceChanged = receipt.summary.provenanceChanged === true;
756
+ const provenanceFields = receipt.provenance?.changedFields?.join(', ') || 'repository metadata';
757
+ const provenanceDescription = provenanceChanged ? provenanceDetail(receipt.provenance) : '';
758
+ const provenanceNotice = provenanceChanged
759
+ ? `<aside class="provenance-change" data-provenance-changed="true" data-provenance-fields="${esc(provenanceFields)}"><strong>Repository provenance changed</strong><span>${esc(provenanceDescription)}</span></aside>`
760
+ : '';
701
761
  const rowHtml = rows.length ? rows.map((row, index) => {
702
762
  const label = row.headLabel || row.baseLabel || row.head?.label || row.base?.label || row.label || row.id;
703
763
  const targetSignature = expectedReviewTargetSignature(row);
704
764
  return `<li data-change-status="${esc(row.status)}"><button class="change-row" type="button" data-change-index="${index}" data-change-key="${esc(row.key)}" data-change-kind="${esc(row.kindKey)}" data-change-id="${esc(row.id)}" data-change-label="${esc(label)}" data-change-status="${esc(row.status)}" data-change-classifications="${esc(row.classifications.join(', '))}" data-change-target-signature="${esc(targetSignature)}"><span class="token">${esc(markerFor(row.status) || '~')}</span><span>${esc(row.kind)}</span><strong>${esc(label)}</strong><code>${esc(row.id)}</code><span>${esc(row.classifications.join(', '))}</span><span>${esc(row.changedFields.join(', ') || 'identity')}</span></button></li>`;
705
- }).join('\n') : '<li class="empty">No authored architecture changes.</li>';
765
+ }).join('\n') : provenanceChanged
766
+ ? '<li class="empty">No component, relationship, or boundary changes; repository provenance changed.</li>'
767
+ : '<li class="empty">No authored architecture changes.</li>';
706
768
  const baseView = baseHtml
707
769
  ? `<iframe class="snapshot-frame" title="Before architecture explorer" srcdoc="${esc(baseHtml)}"></iframe>`
708
770
  : baseSvg;
@@ -711,23 +773,24 @@ export function renderArchitectureDeltaHtml({ receipt, baseSvg, deltaSvg, headSv
711
773
  : headSvg;
712
774
  const html = `<!doctype html>
713
775
  <html lang="en" data-theme="dark" data-preset="${esc(receipt.view.visualPreset)}">
714
- <head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>${esc(receipt.head.title)} Architecture Delta</title>
776
+ <head><meta charset="utf-8">${softwareNoticesHtml}<meta name="viewport" content="width=device-width,initial-scale=1"><title>${esc(receipt.head.title)} Architecture Delta</title>
715
777
  <style>
716
778
  ${artifactCss}
717
779
  :root{color-scheme:dark;--d-add:#34d399;--d-remove:#fb7185;--d-change:#fbbf24;--d-move:#7dd3fc;--d-focus:#7dd3fc;--d-ink:#e6edf5;--d-muted:#8aa0b5;--d-line:#25384a}
718
780
  *{box-sizing:border-box}body{margin:0;overflow-x:hidden;background:#071019;color:var(--d-ink);font-family:"JetBrains Mono",ui-monospace,SFMono-Regular,Menlo,monospace}.proof-page{width:min(1600px,calc(100vw - 64px));margin:auto;padding:30px 0 42px}.proof-head{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:28px;align-items:end;padding-bottom:20px;border-bottom:1px solid var(--d-line)}.eyebrow{margin:0 0 8px;color:#7dd3fc;font:700 11px/1.2 ui-monospace,SFMono-Regular,Menlo,monospace;letter-spacing:.14em}.proof-head h1{margin:0;font-size:clamp(32px,4vw,56px);line-height:.96;letter-spacing:-.04em}.subtitle{margin:12px 0 0;color:var(--d-muted);font-size:14px}.metrics{display:flex;gap:9px}.metric{min-width:86px;padding:11px 13px;border:1px solid var(--d-line);border-radius:8px;background:#0b1722}.metric strong{display:block;font:700 23px/1 ui-monospace,SFMono-Regular,Menlo,monospace}.metric span{display:block;margin-top:6px;color:var(--d-muted);font:700 9px/1 ui-monospace,SFMono-Regular,Menlo,monospace;letter-spacing:.1em}.add strong{color:var(--d-add)}.remove strong{color:var(--d-remove)}.change strong{color:var(--d-change)}
719
781
  .proof-tools{display:flex;align-items:center;justify-content:space-between;gap:20px;margin:16px 0 10px}.view-switch{display:inline-flex;padding:3px;border:1px solid var(--d-line);border-radius:8px;background:#0a141e}.view-switch button,.utility,.review-step{border:0;border-radius:6px;background:transparent;color:var(--d-muted);padding:8px 14px;font:700 11px/1 ui-monospace,SFMono-Regular,Menlo,monospace;cursor:pointer}.view-switch button[aria-selected="true"]{background:#173047;color:#fff}.utility{border:1px solid var(--d-line)}.view-switch button:focus-visible,.utility:focus-visible,.review-step:focus-visible,.change-row:focus-visible{outline:2px solid var(--d-focus);outline-offset:2px}.utility:disabled,.review-step:disabled{cursor:not-allowed;opacity:.45}.legend{display:flex;gap:16px;color:var(--d-muted);font:650 10px/1 ui-monospace,SFMono-Regular,Menlo,monospace}.legend span{display:inline-flex;align-items:center;gap:6px}.legend i{width:22px;border-top:3px solid currentColor}.legend .add{color:var(--d-add)}.legend .remove{color:var(--d-remove)}.legend .remove i{border-top-style:dashed}.legend .change{color:var(--d-change)}.legend .change i{border-top-style:dotted}.legend .move{color:var(--d-move)}.legend .move i{border-top-style:double}
782
+ .provenance-change{display:flex;align-items:center;gap:12px;margin:14px 0 0;padding:10px 13px;border:1px solid rgba(125,211,252,.45);border-radius:8px;background:rgba(125,211,252,.07);color:var(--d-muted);font:650 11px/1.35 ui-monospace,SFMono-Regular,Menlo,monospace}.provenance-change strong{color:var(--d-focus)}.provenance-change span{margin-left:auto;color:var(--d-muted)}
720
783
  .review-strip{display:grid;grid-template-columns:auto auto auto auto minmax(0,1fr);align-items:center;gap:5px;margin:0 0 10px;padding:7px 8px;border-block:1px solid var(--d-line);font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.review-step{min-height:34px;border:1px solid var(--d-line);padding-inline:11px}.review-step[aria-pressed="true"]{border-color:var(--d-focus);color:var(--d-ink)}.review-status{min-width:0;padding-left:9px;color:var(--d-muted);font-size:10px;line-height:1.3;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.review-status strong{color:var(--d-ink);font-weight:750}.review-status[data-state="unavailable"]{color:var(--d-remove)}
721
784
  .canvas{overflow:hidden;border:1px solid var(--d-line);border-radius:10px;background:#09141e;padding:12px;min-height:520px}.canvas svg{display:block;width:100%;height:auto;max-height:72vh}.canvas[hidden]{display:none}.snapshot-frame{display:block;width:100%;height:min(76vh,920px);min-height:620px;border:0;border-radius:6px;background:#071019}.canvas[data-view="base"],.canvas[data-view="head"]{padding:0}.canvas[data-view="delta"] [data-delta-state="same"]{opacity:.38}.canvas[data-delta-review-active]{--review-same-opacity:.14;--review-change-opacity:.28}.canvas[data-delta-review-active] [data-delta-state="same"]{opacity:var(--review-same-opacity)!important}.canvas[data-delta-review-active] [data-delta-state]:not([data-delta-state="same"]):not([data-delta-review-current]){opacity:var(--review-change-opacity)!important}.canvas[data-delta-review-active] [data-delta-review-current]{opacity:1!important;transition:opacity .16s ease-out}g[data-node-id][data-delta-state="added"]>rect:last-of-type{stroke:var(--d-add)!important;stroke-width:3!important}g[data-node-id][data-delta-state="removed"]>rect:last-of-type{stroke:var(--d-remove)!important;stroke-width:3!important;stroke-dasharray:7 5}g[data-node-id][data-delta-state="changed"]>rect:last-of-type{stroke:var(--d-change)!important;stroke-width:3!important;stroke-dasharray:2 3}g[data-node-id][data-delta-state="moved"]>rect:last-of-type,g[data-node-id][data-delta-state="moved-from"]>rect:last-of-type{stroke:var(--d-move)!important;stroke-width:3!important;stroke-dasharray:8 3 2 3}g[data-node-id][data-delta-state="moved-from"],path[data-delta-state="moved-from"]{opacity:.42}path[data-delta-state="added"]{stroke:var(--d-add)!important;stroke-width:3!important}path[data-delta-state="removed"]{stroke:var(--d-remove)!important;stroke-width:3!important;stroke-dasharray:7 5!important}path[data-delta-state="changed"]{stroke:var(--d-change)!important;stroke-width:3!important;stroke-dasharray:2 3!important}path[data-delta-state="rerouted"],path[data-delta-state="moved-from"]{stroke:var(--d-move)!important;stroke-width:2.5!important;stroke-dasharray:8 3 2 3!important}.delta-node-marker circle{fill:#071019;stroke:currentColor;stroke-width:1.5}.delta-node-marker text,.delta-edge-marker,.delta-boundary-marker{fill:currentColor;font:800 9px ui-monospace,SFMono-Regular,Menlo,monospace}[data-delta-state="added"] .delta-node-marker,.delta-edge-marker[data-delta-state="added"],.delta-boundary-marker[data-delta-state="added"]{color:var(--d-add)}[data-delta-state="removed"] .delta-node-marker,.delta-edge-marker[data-delta-state="removed"],.delta-boundary-marker[data-delta-state="removed"]{color:var(--d-remove)}[data-delta-state="changed"] .delta-node-marker,.delta-edge-marker[data-delta-state="changed"],.delta-boundary-marker[data-delta-state="changed"]{color:var(--d-change)}[data-delta-state="moved"] .delta-node-marker,[data-delta-state="moved-from"] .delta-node-marker,.delta-edge-marker[data-delta-state="moved-from"],.delta-edge-marker[data-delta-state="rerouted"],.delta-boundary-marker[data-delta-state="geometry-changed"]{color:var(--d-move)}.delta-edge-marker,.delta-boundary-marker{paint-order:stroke;stroke:#071019;stroke-width:3px}
722
785
  rect[data-graph-role="structural-frame"][data-delta-state="added"]{stroke:var(--d-add)!important;stroke-width:2.5!important}rect[data-graph-role="structural-frame"][data-delta-state="removed"]{stroke:var(--d-remove)!important;stroke-width:2.5!important;stroke-dasharray:7 5!important}rect[data-graph-role="structural-frame"][data-delta-state="changed"]{stroke:var(--d-change)!important;stroke-width:2.5!important;stroke-dasharray:2 3!important}rect[data-graph-role="structural-frame"][data-delta-state="moved-from"]{stroke:var(--d-move)!important;stroke-width:2!important;stroke-dasharray:8 3 2 3!important;opacity:.42}text[data-delta-boundary-state="added"]{fill:var(--d-add)!important}text[data-delta-boundary-state="removed"]{fill:var(--d-remove)!important}text[data-delta-boundary-state="changed"]{fill:var(--d-change)!important}text[data-delta-boundary-state="moved-from"]{fill:var(--d-move)!important;opacity:.55}
723
786
  details{margin-top:12px;border:1px solid var(--d-line);border-radius:9px;background:#0a141e}summary{padding:13px 15px;cursor:pointer;font-weight:700}.changes{list-style:none;margin:0;padding:0 8px 8px}.changes li{border-top:1px solid rgba(138,160,181,.16)}.change-row{display:grid;grid-template-columns:30px 90px minmax(140px,1fr) minmax(100px,.7fr) minmax(120px,.8fr) minmax(140px,1.2fr);gap:10px;width:100%;margin:0;padding:9px 7px;border:0;border-radius:5px;background:transparent;color:inherit;font:inherit;font-size:11px;text-align:left;align-items:baseline;cursor:pointer}.change-row:hover{background:rgba(125,211,252,.06)}.change-row[aria-current="step"]{background:rgba(125,211,252,.1);box-shadow:inset 0 0 0 1px var(--d-focus)}.change-row:disabled{cursor:default}.token{font:800 13px/1 ui-monospace,SFMono-Regular,Menlo,monospace}.changes code,.change-row>span:last-child{color:var(--d-muted)}.proof-foot{display:flex;justify-content:space-between;gap:24px;margin-top:14px;color:var(--d-muted);font:650 10px/1.4 ui-monospace,SFMono-Regular,Menlo,monospace}
724
787
  html[data-theme="dark"] body{background:#071019!important;background-image:none!important}html[data-theme="light"]{color-scheme:light;--d-ink:#10283c;--d-muted:#587187;--d-line:#c8d6e2;--d-focus:#006b8f}html[data-theme="light"] body{background:#eef3f7!important;background-image:none!important;color:var(--d-ink)}html[data-theme="light"] .metric,html[data-theme="light"] .view-switch,html[data-theme="light"] details{background:#fff}html[data-theme="light"] .canvas{background:#f8fbfd}html[data-theme="light"] .view-switch button[aria-selected="true"]{background:#dbeaf5;color:#10283c}html[data-theme="light"] .delta-node-marker circle{fill:#fff}html[data-preset="blueprint"] body{background-image:none!important}
725
- @media(max-width:760px){.proof-page{width:100%;padding:12px}.proof-head{grid-template-columns:1fr;gap:14px;align-items:start}.proof-head h1{font-size:32px}.metrics{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));width:100%}.metric{min-width:0}.proof-tools{align-items:stretch;flex-wrap:wrap;gap:8px}.view-switch{display:flex;flex:1 1 100%}.view-switch button{flex:1;padding-inline:8px}.legend{flex-wrap:wrap;gap:8px}.proof-tools>div:last-child{margin-left:auto}.review-strip{grid-template-columns:auto auto auto auto}.review-status{grid-column:1/-1;padding:4px 2px 0}.canvas{min-height:0;padding:6px;overflow:auto}.canvas svg{min-width:720px;max-height:none}.snapshot-frame{min-width:720px}.changes{overflow-x:auto}.change-row{min-width:820px}.proof-foot{flex-direction:column;gap:4px}}
788
+ @media(max-width:760px){.proof-page{width:100%;padding:12px}.proof-head{grid-template-columns:1fr;gap:14px;align-items:start}.proof-head h1{font-size:32px}.metrics{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));width:100%}.metric{min-width:0}.provenance-change{align-items:flex-start;flex-wrap:wrap}.provenance-change span{width:100%;margin-left:0}.proof-tools{align-items:stretch;flex-wrap:wrap;gap:8px}.view-switch{display:flex;flex:1 1 100%}.view-switch button{flex:1;padding-inline:8px}.legend{flex-wrap:wrap;gap:8px}.proof-tools>div:last-child{margin-left:auto}.review-strip{grid-template-columns:auto auto auto auto}.review-status{grid-column:1/-1;padding:4px 2px 0}.canvas{min-height:0;padding:6px;overflow:auto}.canvas svg{min-width:720px;max-height:none}.snapshot-frame{min-width:720px}.changes{overflow-x:auto}.change-row{min-width:820px}.proof-foot{flex-direction:column;gap:4px}}
726
789
  @media(prefers-reduced-motion:reduce){*{scroll-behavior:auto!important}.canvas[data-delta-review-active] [data-delta-review-current]{transition:none!important}}@media print{body{min-width:0;background:#fff;color:#111}.proof-page{width:100%;padding:0}.proof-tools,.review-strip,details{display:none!important}.canvas{display:none!important}.canvas[data-view="delta"]{display:block!important;border:0}.canvas[data-view="delta"] [data-delta-state="same"]{opacity:1!important;transition:none!important}.canvas[data-delta-review-active]{--review-same-opacity:1;--review-change-opacity:1}.canvas[data-delta-review-active] [data-delta-review-current]{opacity:1!important;transition:none!important}.proof-foot{color:#444}}
727
790
  </style></head>
728
- <body><main class="proof-page"><header class="proof-head"><div><p class="eyebrow">ARCHITECTURE DELTA · ${proof}</p><h1>See what changed<br>before you merge.</h1><p class="subtitle">${esc(receipt.base.title)} → ${esc(receipt.head.title)}</p></div><div class="metrics"><div class="metric add"><strong>${total(receipt.summary, 'added')}</strong><span>ADDED</span></div><div class="metric remove"><strong>${total(receipt.summary, 'removed')}</strong><span>REMOVED</span></div><div class="metric change"><strong>${changed}</strong><span>CHANGED</span></div></div></header>
791
+ <body><main class="proof-page"><header class="proof-head"><div><p class="eyebrow">ARCHITECTURE DELTA · ${proof}</p><h1>See what changed<br>before you merge.</h1><p class="subtitle">${esc(receipt.base.title)} → ${esc(receipt.head.title)}</p></div><div class="metrics"><div class="metric add"><strong>${total(receipt.summary, 'added')}</strong><span>ADDED</span></div><div class="metric remove"><strong>${total(receipt.summary, 'removed')}</strong><span>REMOVED</span></div><div class="metric change"><strong>${changed}</strong><span>CHANGED</span></div></div></header>${provenanceNotice}
729
792
  <div class="proof-tools"><div class="view-switch" role="tablist" aria-label="Architecture snapshot"><button role="tab" data-target="base" aria-selected="false">Before</button><button role="tab" data-target="delta" aria-selected="true">Delta</button><button role="tab" data-target="head" aria-selected="false">After</button></div><div class="legend"><span class="add"><i></i>+ ADD</span><span class="remove"><i></i>− DEL</span><span class="change"><i></i>~ MOD</span><span class="move"><i></i>↔ MOVE</span></div><div><button class="utility" id="export-svg" type="button">Export SVG</button> <button class="utility" id="share-card" type="button">Share Card</button> <button class="utility" id="preset" type="button">Preset</button> <button class="utility" id="theme" type="button">Theme</button></div></div>
730
- <nav class="review-strip" aria-label="Authored change review"><button class="review-step" id="review-overview" type="button" disabled>Overview</button><button class="review-step" id="review-previous" type="button" aria-label="Previous authored change" disabled>←</button><button class="review-step" id="review-play" type="button" aria-pressed="false"${rows.length ? '' : ' disabled'}>Review</button><button class="review-step" id="review-next" type="button" aria-label="Next authored change" disabled>→</button><div class="review-status" id="review-status" role="status" aria-live="polite">Overview · ${rows.length} authored changes</div></nav>
793
+ <nav class="review-strip" aria-label="Authored change review"><button class="review-step" id="review-overview" type="button" disabled>Overview</button><button class="review-step" id="review-previous" type="button" aria-label="Previous authored change" disabled>←</button><button class="review-step" id="review-play" type="button" aria-pressed="false"${rows.length ? '' : ' disabled'}>Review</button><button class="review-step" id="review-next" type="button" aria-label="Next authored change" disabled>→</button><div class="review-status" id="review-status" role="status" aria-live="polite">Overview · ${rows.length} authored ${provenanceChanged ? 'graph changes · provenance changed' : 'changes'}</div></nav>
731
794
  <section class="canvas" data-view="base" hidden>${baseView}</section><section class="canvas" data-view="delta">${deltaSvg}</section><section class="canvas" data-view="head" hidden>${headView}</section>
732
795
  <details${rows.length <= 10 ? ' open' : ''}><summary>Exact authored changes · ${rows.length}</summary><ul class="changes">${rowHtml}</ul></details>
733
796
  <footer class="proof-foot"><span>Stable IDs only · completeness: complete · ${proof}</span><span>Authored IR only · no risk or mergeability inference</span></footer></main>
@@ -937,6 +1000,10 @@ html[data-theme="dark"] body{background:#071019!important;background-image:none!
937
1000
  const source = deltaCanvas?.querySelector(':scope > svg');
938
1001
  if (!source) throw new Error('Canonical Delta SVG is unavailable.');
939
1002
  const clone = source.cloneNode(true);
1003
+ const metadata = document.createElementNS('http://www.w3.org/2000/svg', 'metadata');
1004
+ metadata.setAttribute('id', 'archify-software-notices');
1005
+ metadata.textContent = JSON.parse(document.getElementById('archify-software-notices').textContent);
1006
+ clone.insertBefore(metadata, clone.firstChild);
940
1007
  clone.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
941
1008
  clone.removeAttribute('style');
942
1009
  clone.querySelectorAll('[data-delta-review-current]').forEach((element) => element.removeAttribute('data-delta-review-current'));
@@ -957,7 +1024,9 @@ html[data-theme="dark"] body{background:#071019!important;background-image:none!
957
1024
  'text[data-delta-boundary-state="added"]{fill:#34d399!important}text[data-delta-boundary-state="removed"]{fill:#fb7185!important}text[data-delta-boundary-state="changed"]{fill:#fbbf24!important}text[data-delta-boundary-state="moved-from"]{fill:#7dd3fc!important;opacity:.55}' +
958
1025
  '.delta-node-marker circle{fill:#071019;stroke:currentColor;stroke-width:1.5}.delta-node-marker text,.delta-edge-marker,.delta-boundary-marker{fill:currentColor;font:800 9px ui-monospace,SFMono-Regular,Menlo,monospace}';
959
1026
  clone.insertBefore(style, clone.firstChild);
960
- return new XMLSerializer().serializeToString(clone);
1027
+ // The XML declaration pins UTF-8: without it, consumers that guess an
1028
+ // encoding instead of defaulting to UTF-8 mangle non-ASCII text.
1029
+ return '<?xml version="1.0" encoding="UTF-8"?>\\n' + new XMLSerializer().serializeToString(clone);
961
1030
  }
962
1031
 
963
1032
  function artifactName(suffix) {
@@ -1041,18 +1110,31 @@ html[data-theme="dark"] body{background:#071019!important;background-image:none!
1041
1110
  ctx.fillText(connectionLine, 420, 151);
1042
1111
  ctx.fillText(boundaryLine, 786, 151);
1043
1112
  ctx.font = '650 14px ui-monospace, SFMono-Regular, Menlo, monospace';
1044
- const authoredChanges = ['components', 'connections', 'boundaries'].reduce((sum, collection) => {
1045
- const summary = receipt.summary[collection];
1046
- return sum + summary.added + summary.changed + summary.removed;
1047
- }, 0);
1113
+ const graphChanges = ['components', 'connections', 'boundaries'].reduce((sum, collection) => sum + (receipt.changes[collection] || []).length, 0);
1114
+ const provenanceSummary = ${safeJson(provenanceChanged ? `provenance changed · ${provenanceFields}` : '')};
1048
1115
  const movementSummary = '↔ moved ' + receipt.summary.components.moved + ' · rerouted ' + receipt.summary.connections.rerouted + ' · presentation ' + (receipt.summary.presentationChanged ? 'changed' : 'unchanged');
1049
- const secondary = authoredChanges === 0
1050
- ? 'No authored architecture changes · ' + movementSummary
1051
- : movementSummary;
1052
- ctx.fillText(secondary, 66, 181);
1116
+ const secondary = graphChanges === 0
1117
+ ? receipt.summary.provenanceChanged
1118
+ ? 'No graph changes · ' + provenanceSummary
1119
+ : 'No authored architecture changes · ' + movementSummary
1120
+ : movementSummary + (provenanceSummary ? ' · ' + provenanceSummary : '');
1053
1121
  const proofLine = receipt.proofLevel === 'revision-pinned'
1054
1122
  ? 'REV ' + String(receipt.base.revision).slice(0, 8) + ' → ' + String(receipt.head.revision).slice(0, 8) + ' · REVISION-PINNED INPUTS'
1055
1123
  : 'AUTHORED SNAPSHOTS';
1124
+ function fitCanvasLine(text, maxWidth) {
1125
+ if (ctx.measureText(text).width <= maxWidth) return text;
1126
+ let low = 0;
1127
+ let high = text.length;
1128
+ while (low < high) {
1129
+ const middle = Math.ceil((low + high) / 2);
1130
+ if (ctx.measureText(text.slice(0, middle) + '…').width <= maxWidth) low = middle;
1131
+ else high = middle - 1;
1132
+ }
1133
+ return text.slice(0, low).trimEnd() + '…';
1134
+ }
1135
+ const proofWidth = ctx.measureText(proofLine).width;
1136
+ const secondaryWidth = Math.max(0, 1044 - proofWidth);
1137
+ ctx.fillText(fitCanvasLine(secondary, secondaryWidth), 66, 181);
1056
1138
  ctx.textAlign = 'right';
1057
1139
  ctx.fillText(proofLine, 1134, 181);
1058
1140
  ctx.textAlign = 'left';
@@ -1185,6 +1267,21 @@ export function validateArchitectureDeltaHtml(html, receipt) {
1185
1267
  }
1186
1268
  if (!svgBalanced || svgDepth !== 0 || svgRoots !== 1 || deltaMarkup.slice(0, rootStart).trim() || deltaMarkup.slice(rootEnd).trim()) failures.push('expected exactly one root SVG in the Delta canvas');
1187
1269
  if ((html.match(/id="archify-compare-receipt"/g) || []).length !== 1) failures.push('expected exactly one embedded compare receipt');
1270
+ const provenanceChanged = receipt.summary?.provenanceChanged === true;
1271
+ const provenanceNotices = (html.match(/data-provenance-changed="true"/g) || []).length;
1272
+ const provenanceFields = receipt.provenance?.changedFields;
1273
+ const legacyProvenance = receipt.provenance === undefined;
1274
+ const validProvenanceFields = Array.isArray(provenanceFields) && provenanceFields.length > 0;
1275
+ const provenanceDescription = provenanceChanged && (legacyProvenance || validProvenanceFields) ? provenanceDetail(receipt.provenance) : '';
1276
+ const provenanceFieldLabel = legacyProvenance ? 'repository metadata' : validProvenanceFields ? provenanceFields.join(', ') : '';
1277
+ if (provenanceNotices !== (provenanceChanged ? 1 : 0)
1278
+ || (!provenanceChanged && !legacyProvenance)
1279
+ || (provenanceChanged && !legacyProvenance && !validProvenanceFields)
1280
+ || (provenanceChanged && !html.includes(`data-provenance-fields="${esc(provenanceFieldLabel)}"`))
1281
+ || (provenanceChanged && !html.includes(`<span>${esc(provenanceDescription)}</span>`))) {
1282
+ failures.push('provenance change notice does not match the receipt');
1283
+ }
1284
+ if (provenanceChanged && rows.length === 0 && html.includes('No authored architecture changes.')) failures.push('provenance-only delta claims no authored changes');
1188
1285
  if (!html.includes('aria-label="Authored change review"')) failures.push('missing exact-ID change navigator');
1189
1286
  if ((html.match(/class="change-row"/g) || []).length !== rows.length) failures.push('change navigator row count does not match the receipt');
1190
1287
  if (!html.includes('id="export-svg"') || !html.includes('id="share-card"')
@@ -1,43 +1,38 @@
1
1
  {
2
- "schema_version": 1,
2
+ "schema_version": 3,
3
3
  "diagram_type": "lifecycle",
4
4
  "meta": {
5
5
  "title": "Agent Run Lifecycle",
6
6
  "output": "examples/lifecycle-agent-run.html",
7
- "viewBox": [1030, 630],
8
7
  "animation": "trace",
9
- "quality_profile": "showcase",
10
- "views": [
11
- { "id": "main-lifecycle", "label": "Main lifecycle", "focus": ["queued", "planning", "executing", "reviewing", "completed"], "note": "Follow the ordered phases from accepted request to completed response." },
12
- { "id": "human-waits", "label": "Human and input waits", "focus": ["executing", "approval", "reviewing", "blocked"], "note": "See where the run pauses without becoming terminal." },
13
- { "id": "recovery-and-exits", "label": "Recovery and terminal exits", "focus": ["executing", "failed", "blocked", "cancelled", "expired"], "note": "Separate retryable failure from cancellation and expiry." }
14
- ]
8
+ "quality_profile": "showcase"
15
9
  },
16
- "lanes": [
17
- { "id": "main", "label": "Lifecycle phases" },
18
- { "id": "waiting", "label": "Interruptions" },
19
- { "id": "exceptions", "label": "Recovery loop" },
20
- { "id": "terminal", "label": "Terminal exits" }
21
- ],
10
+ "mainPath": ["queued", "planning", "executing", "reviewing", "completed"],
22
11
  "states": [
23
- { "id": "queued", "type": "start", "label": "Queued", "sublabel": "request accepted", "lane": "main", "col": 0, "step": "01", "tag": "entry" },
24
- { "id": "planning", "type": "active", "label": "Planning", "sublabel": "build task graph", "lane": "main", "col": 1, "step": "02", "tag": "model" },
25
- { "id": "executing", "type": "active", "label": "Executing", "sublabel": "tool calls", "lane": "main", "col": 2, "step": "03", "tag": "work" },
26
- { "id": "reviewing", "type": "decision", "label": "Reviewing", "sublabel": "quality gate", "lane": "main", "col": 3, "step": "04", "tag": "check" },
27
- { "id": "completed", "type": "success", "label": "Completed", "sublabel": "final response", "lane": "main", "col": 4, "step": "05", "tag": "done" },
28
- { "id": "approval", "type": "waiting", "label": "Needs Approval", "sublabel": "human gate", "lane": "waiting", "col": 0, "tag": "pause" },
29
- { "id": "blocked", "type": "waiting", "label": "Blocked", "sublabel": "missing input", "lane": "waiting", "col": 1, "tag": "wait" },
30
- { "id": "failed", "type": "failure", "label": "Failed", "sublabel": "recoverable error", "lane": "exceptions", "col": 0, "yOffset": 78, "tag": "retryable" },
31
- { "id": "cancelled", "type": "failure", "label": "Cancelled", "sublabel": "user stopped", "lane": "terminal", "col": 0, "tag": "terminal" },
32
- { "id": "expired", "type": "failure", "label": "Expired", "sublabel": "timeout", "lane": "terminal", "col": 1, "tag": "terminal" }
12
+ { "id": "queued", "type": "start", "label": "Queued", "sublabel": "request accepted", "tag": "entry", "step": "01" },
13
+ { "id": "planning", "type": "active", "label": "Planning", "sublabel": "build task graph", "tag": "model", "step": "02" },
14
+ { "id": "executing", "type": "active", "label": "Executing", "sublabel": "tool calls", "tag": "work", "step": "03" },
15
+ { "id": "reviewing", "type": "decision", "label": "Reviewing", "sublabel": "quality gate", "tag": "check", "step": "04" },
16
+ { "id": "completed", "type": "success", "label": "Completed", "sublabel": "final response", "tag": "done", "step": "05" },
17
+ { "id": "approval", "type": "waiting", "label": "Needs Approval", "sublabel": "human gate", "tag": "pause" },
18
+ { "id": "failed", "type": "failure", "label": "Failed", "sublabel": "recoverable error", "tag": "retryable" },
19
+ { "id": "blocked", "type": "waiting", "label": "Blocked", "sublabel": "missing input", "tag": "wait" },
20
+ { "id": "cancelled", "type": "failure", "label": "Cancelled", "sublabel": "user stopped", "tag": "terminal" },
21
+ { "id": "expired", "type": "failure", "label": "Expired", "sublabel": "timeout", "tag": "terminal" }
33
22
  ],
34
23
  "transitions": [
35
- { "id": "approval-needed", "from": "executing", "to": "approval", "variant": "security", "fromSide": "bottom", "toSide": "top", "route": "straight" },
36
- { "id": "review-blocked", "from": "reviewing", "to": "blocked", "variant": "default", "route": "drop" },
37
- { "id": "execution-failed", "from": "executing", "to": "failed", "variant": "security", "fromSide": "left", "toSide": "left", "via": [[320, 157], [320, 385]] },
38
- { "id": "failed-retry", "from": "failed", "to": "executing", "variant": "emphasis", "fromSide": "left", "toSide": "top", "via": [[20, 385], [20, 80], [402, 80]] },
39
- { "id": "block-expired", "from": "blocked", "to": "expired", "variant": "security", "fromSide": "bottom", "toSide": "top", "route": "straight" },
40
- { "id": "approval-cancelled", "from": "approval", "to": "cancelled", "variant": "security", "fromSide": "bottom", "toSide": "top", "via": [[480, 336], [480, 432], [402, 432]] }
24
+ { "id": "queued-planning", "from": "queued", "to": "planning", "label": "start" },
25
+ { "id": "planning-executing", "from": "planning", "to": "executing", "label": "plan ready" },
26
+ { "id": "executing-reviewing", "from": "executing", "to": "reviewing", "label": "steps done" },
27
+ { "id": "reviewing-completed", "from": "reviewing", "to": "completed", "label": "pass" },
28
+ { "id": "executing-approval", "from": "executing", "to": "approval", "label": "risky tool", "variant": "security" },
29
+ { "id": "approval-executing", "from": "approval", "to": "executing", "label": "approved" },
30
+ { "id": "approval-cancelled", "from": "approval", "to": "cancelled", "label": "user denies", "variant": "security" },
31
+ { "id": "executing-failed", "from": "executing", "to": "failed", "label": "tool error", "variant": "security" },
32
+ { "id": "failed-executing", "from": "failed", "to": "executing", "label": "retry", "variant": "dashed" },
33
+ { "id": "reviewing-blocked", "from": "reviewing", "to": "blocked", "label": "needs input" },
34
+ { "id": "blocked-reviewing", "from": "blocked", "to": "reviewing", "label": "input given" },
35
+ { "id": "blocked-expired", "from": "blocked", "to": "expired", "label": "no reply 24h", "variant": "security" }
41
36
  ],
42
37
  "cards": [
43
38
  {
@@ -6,26 +6,6 @@
6
6
  "animation": "trace",
7
7
  "visual_preset": "signal-flow",
8
8
  "quality_profile": "showcase",
9
- "views": [
10
- {
11
- "id": "happy-path",
12
- "label": "Request to result",
13
- "focus": ["user", "chat", "planner", "router", "approval", "tool", "external", "final"],
14
- "note": "Follow the successful request from user intent to the final reply."
15
- },
16
- {
17
- "id": "safety-gate",
18
- "label": "Policy and recovery",
19
- "focus": ["router", "approval", "blocked", "retry"],
20
- "note": "See where risky work stops, waits for consent, or returns for revision."
21
- },
22
- {
23
- "id": "evidence-loop",
24
- "label": "Evidence and memory",
25
- "focus": ["external", "store", "trace"],
26
- "note": "Isolate the durable trace and context path behind the visible answer."
27
- }
28
- ],
29
9
  "output": "examples/workflow-agent-tool-call-rendered.html"
30
10
  },
31
11
  "lanes": [