@stacksjs/defaults 0.75.361 → 0.75.366

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 (210) hide show
  1. package/ai/skills/stacks-ai/SKILL.md +22 -0
  2. package/ai/skills/stacks-native/CATALOG.md +5 -5
  3. package/ai/skills/stacks-payments/SKILL.md +10 -0
  4. package/ai/skills/stacks-technical-diagrams/LICENSE +202 -22
  5. package/ai/skills/stacks-technical-diagrams/LICENSE-MIT +22 -0
  6. package/ai/skills/stacks-technical-diagrams/NOTICE +26 -0
  7. package/ai/skills/stacks-technical-diagrams/SKILL.md +106 -266
  8. package/ai/skills/stacks-technical-diagrams/THIRD_PARTY_NOTICES.md +11 -2
  9. package/ai/skills/stacks-technical-diagrams/UPSTREAM.json +12 -0
  10. package/ai/skills/stacks-technical-diagrams/agents/openai.yaml +2 -2
  11. package/ai/skills/stacks-technical-diagrams/assets/template.html +3655 -3798
  12. package/ai/skills/stacks-technical-diagrams/bin/archify.mjs +7290 -0
  13. package/ai/skills/stacks-technical-diagrams/bin/delivery-update.mjs +7 -0
  14. package/ai/skills/stacks-technical-diagrams/bin/diagrams +1 -0
  15. package/ai/skills/stacks-technical-diagrams/bin/finalize.mjs +1056 -0
  16. package/ai/skills/stacks-technical-diagrams/bin/open-artifact.mjs +72 -12
  17. package/ai/skills/stacks-technical-diagrams/bin/preview.mjs +348 -31
  18. package/ai/skills/stacks-technical-diagrams/bin/recover-output.mjs +41 -0
  19. package/ai/skills/stacks-technical-diagrams/bin/technical-diagrams.mjs +3 -2097
  20. package/ai/skills/stacks-technical-diagrams/bin/visual-check.mjs +2142 -157
  21. package/ai/skills/stacks-technical-diagrams/brand-marks/README.md +3 -3
  22. package/ai/skills/stacks-technical-diagrams/delta/architecture-delta.mjs +130 -33
  23. package/ai/skills/stacks-technical-diagrams/examples/agent-run.lifecycle.json +25 -30
  24. package/ai/skills/stacks-technical-diagrams/examples/agent-tool-call.workflow.json +0 -20
  25. package/ai/skills/stacks-technical-diagrams/examples/archify-dev-activity.timeline.json +176 -0
  26. package/ai/skills/stacks-technical-diagrams/examples/archify-repository.tree.json +197 -0
  27. package/ai/skills/stacks-technical-diagrams/examples/async-job-roundtrip.sequence.json +1 -6
  28. package/ai/skills/stacks-technical-diagrams/examples/brand-aware-delivery.architecture.json +3 -16
  29. package/ai/skills/stacks-technical-diagrams/examples/cache-miss-request.sequence.json +2 -7
  30. package/ai/skills/stacks-technical-diagrams/examples/checkout-platform.base.architecture.json +2 -1
  31. package/ai/skills/stacks-technical-diagrams/examples/checkout-platform.head.architecture.json +2 -1
  32. package/ai/skills/stacks-technical-diagrams/examples/checkout-request.waterfall.json +20 -0
  33. package/ai/skills/stacks-technical-diagrams/examples/class-payment-processors-rendered.html +14987 -0
  34. package/ai/skills/stacks-technical-diagrams/examples/class-payments-rendered.html +14787 -0
  35. package/ai/skills/stacks-technical-diagrams/examples/dataflow-product-analytics.html +14880 -0
  36. package/ai/skills/stacks-technical-diagrams/examples/delivery.explainer.json +155 -0
  37. package/ai/skills/stacks-technical-diagrams/examples/deployment-release.lifecycle.json +57 -34
  38. package/ai/skills/stacks-technical-diagrams/examples/erd-orders-rendered.html +15112 -0
  39. package/ai/skills/stacks-technical-diagrams/examples/event-stream.dataflow.json +1 -6
  40. package/ai/skills/stacks-technical-diagrams/examples/example-rebuild.waterfall.json +212 -0
  41. package/ai/skills/stacks-technical-diagrams/examples/holiday-planning.workflow.json +143 -0
  42. package/ai/skills/stacks-technical-diagrams/examples/incident-response.workflow.json +1 -6
  43. package/ai/skills/stacks-technical-diagrams/examples/lifecycle-agent-run.html +14892 -0
  44. package/ai/skills/stacks-technical-diagrams/examples/locales/de.json +463 -0
  45. package/ai/skills/stacks-technical-diagrams/examples/locales/fr.json +463 -0
  46. package/ai/skills/stacks-technical-diagrams/examples/locales/fr.partial.json +22 -0
  47. package/ai/skills/stacks-technical-diagrams/examples/locales/it.json +463 -0
  48. package/ai/skills/stacks-technical-diagrams/examples/locales/ja.json +463 -0
  49. package/ai/skills/stacks-technical-diagrams/examples/locales/pt.json +463 -0
  50. package/ai/skills/stacks-technical-diagrams/examples/locales/ru.json +463 -0
  51. package/ai/skills/stacks-technical-diagrams/examples/orders.erd.json +337 -0
  52. package/ai/skills/stacks-technical-diagrams/examples/payment-incident.timeline.json +24 -0
  53. package/ai/skills/stacks-technical-diagrams/examples/payment-platform.tree.json +22 -0
  54. package/ai/skills/stacks-technical-diagrams/examples/payment-processors.class.json +177 -0
  55. package/ai/skills/stacks-technical-diagrams/examples/payments.class.json +85 -0
  56. package/ai/skills/stacks-technical-diagrams/examples/product-analytics.dataflow.json +1 -6
  57. package/ai/skills/stacks-technical-diagrams/examples/production-deployment.architecture.json +3 -23
  58. package/ai/skills/stacks-technical-diagrams/examples/release-delivery.workflow.json +1 -6
  59. package/ai/skills/stacks-technical-diagrams/examples/sequence-cache-miss-request.html +14895 -0
  60. package/ai/skills/stacks-technical-diagrams/examples/subscription-billing-rendered.html +15369 -0
  61. package/ai/skills/stacks-technical-diagrams/examples/subscription-billing.erd.json +548 -0
  62. package/ai/skills/stacks-technical-diagrams/examples/timeline-archify-dev-activity-rendered.html +15002 -0
  63. package/ai/skills/stacks-technical-diagrams/examples/timeline-payment-incident-rendered.html +14772 -0
  64. package/ai/skills/stacks-technical-diagrams/examples/tree-archify-repository-rendered.html +15071 -0
  65. package/ai/skills/stacks-technical-diagrams/examples/tree-payment-platform-rendered.html +14810 -0
  66. package/ai/skills/stacks-technical-diagrams/examples/waterfall-checkout-request-rendered.html +14754 -0
  67. package/ai/skills/stacks-technical-diagrams/examples/waterfall-example-rebuild-rendered.html +14940 -0
  68. package/ai/skills/stacks-technical-diagrams/examples/web-app-rendered.html +14889 -0
  69. package/ai/skills/stacks-technical-diagrams/examples/web-app.architecture.json +1 -6
  70. package/ai/skills/stacks-technical-diagrams/examples/workflow-agent-tool-call-rendered.html +14907 -0
  71. package/ai/skills/stacks-technical-diagrams/explainer/browser-check.mjs +208 -0
  72. package/ai/skills/stacks-technical-diagrams/explainer/charts.mjs +70 -0
  73. package/ai/skills/stacks-technical-diagrams/explainer/check.mjs +168 -0
  74. package/ai/skills/stacks-technical-diagrams/explainer/diagrams.mjs +518 -0
  75. package/ai/skills/stacks-technical-diagrams/explainer/diff.mjs +124 -0
  76. package/ai/skills/stacks-technical-diagrams/explainer/inline.mjs +155 -0
  77. package/ai/skills/stacks-technical-diagrams/explainer/layout.mjs +35 -0
  78. package/ai/skills/stacks-technical-diagrams/explainer/page-bundle.mjs +16 -0
  79. package/ai/skills/stacks-technical-diagrams/explainer/parse.mjs +300 -0
  80. package/ai/skills/stacks-technical-diagrams/explainer/patch.mjs +117 -0
  81. package/ai/skills/stacks-technical-diagrams/explainer/prepare.mjs +131 -0
  82. package/ai/skills/stacks-technical-diagrams/explainer/reader.css +472 -0
  83. package/ai/skills/stacks-technical-diagrams/explainer/reader.js +667 -0
  84. package/ai/skills/stacks-technical-diagrams/explainer/render.mjs +224 -0
  85. package/ai/skills/stacks-technical-diagrams/explainer/revision.mjs +20 -0
  86. package/ai/skills/stacks-technical-diagrams/explainer/sources.mjs +318 -0
  87. package/ai/skills/stacks-technical-diagrams/explainer/validate.mjs +138 -0
  88. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/LICENSE +40 -0
  89. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/README.md +5 -0
  90. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/3DKXF73K.js +4 -0
  91. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/42UTT654.js +3 -0
  92. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/DKTLEL5E.js +1 -0
  93. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/EEIX5ZYH.js +2 -0
  94. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/EJ5KOXYD.js +25 -0
  95. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/GUJTEFZK.js +1 -0
  96. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/IZOKQ2GT.js +4 -0
  97. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/L4LY553T.js +3 -0
  98. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/MSKIJHB2.js +2 -0
  99. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/RVARI57O.js +1 -0
  100. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/UKSIWDDN.js +2 -0
  101. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/UPTXNAXN.js +2 -0
  102. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/XTDUIGUI.js +9 -0
  103. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/chunks/YAYTP6L5.js +9 -0
  104. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/core.js +1 -0
  105. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/diagrams/pie.js +1 -0
  106. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/diagrams/quadrantChart.js +1 -0
  107. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/diagrams/radar.js +1 -0
  108. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/diagrams/sankey.js +1 -0
  109. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/diagrams/venn.js +1 -0
  110. package/ai/skills/stacks-technical-diagrams/explainer/vendor/pele/diagrams/xychart.js +1 -0
  111. package/ai/skills/stacks-technical-diagrams/explainer/writing.mjs +139 -0
  112. package/ai/skills/stacks-technical-diagrams/locales/README.md +40 -0
  113. package/ai/skills/stacks-technical-diagrams/locales/ar.json +488 -0
  114. package/ai/skills/stacks-technical-diagrams/locales/en.json +488 -0
  115. package/ai/skills/stacks-technical-diagrams/locales/es.json +488 -0
  116. package/ai/skills/stacks-technical-diagrams/locales/ko.json +488 -0
  117. package/ai/skills/stacks-technical-diagrams/locales/manifest.json +10 -0
  118. package/ai/skills/stacks-technical-diagrams/locales/zh-CN.json +488 -0
  119. package/ai/skills/stacks-technical-diagrams/locales/zh-TW.json +488 -0
  120. package/ai/skills/stacks-technical-diagrams/migrations/workflow-v2.mjs +1 -0
  121. package/ai/skills/stacks-technical-diagrams/recipes/scenarios.mjs +115 -51
  122. package/ai/skills/stacks-technical-diagrams/references/architecture-layout-repair.md +18 -0
  123. package/ai/skills/stacks-technical-diagrams/references/authoring-contract.md +453 -51
  124. package/ai/skills/stacks-technical-diagrams/references/authoring-defaults.md +57 -0
  125. package/ai/skills/stacks-technical-diagrams/references/brand-marks.md +57 -3
  126. package/ai/skills/stacks-technical-diagrams/references/delivery-contract.md +603 -58
  127. package/ai/skills/stacks-technical-diagrams/references/explainer-authoring.md +274 -0
  128. package/ai/skills/stacks-technical-diagrams/references/repository-authoring.md +126 -0
  129. package/ai/skills/stacks-technical-diagrams/references/update-awareness.md +13 -0
  130. package/ai/skills/stacks-technical-diagrams/references/viewer-runtime.md +18 -11
  131. package/ai/skills/stacks-technical-diagrams/renderers/architecture/grid.mjs +1 -1
  132. package/ai/skills/stacks-technical-diagrams/renderers/architecture/labels.mjs +2 -0
  133. package/ai/skills/stacks-technical-diagrams/renderers/architecture/render-architecture.mjs +550 -424
  134. package/ai/skills/stacks-technical-diagrams/renderers/architecture/routing.mjs +1469 -0
  135. package/ai/skills/stacks-technical-diagrams/renderers/class/README.md +129 -0
  136. package/ai/skills/stacks-technical-diagrams/renderers/class/render-class.mjs +1095 -0
  137. package/ai/skills/stacks-technical-diagrams/renderers/dataflow/README.md +89 -17
  138. package/ai/skills/stacks-technical-diagrams/renderers/dataflow/dataflow-compiler.mjs +1605 -0
  139. package/ai/skills/stacks-technical-diagrams/renderers/dataflow/joint-label-routing.mjs +165 -0
  140. package/ai/skills/stacks-technical-diagrams/renderers/dataflow/label-capacity.mjs +81 -0
  141. package/ai/skills/stacks-technical-diagrams/renderers/dataflow/render-dataflow.mjs +14 -474
  142. package/ai/skills/stacks-technical-diagrams/renderers/erd/README.md +246 -0
  143. package/ai/skills/stacks-technical-diagrams/renderers/erd/grid.mjs +150 -0
  144. package/ai/skills/stacks-technical-diagrams/renderers/erd/render-erd.mjs +1588 -0
  145. package/ai/skills/stacks-technical-diagrams/renderers/explainer/render-explainer.mjs +42 -0
  146. package/ai/skills/stacks-technical-diagrams/renderers/lifecycle/README.md +83 -94
  147. package/ai/skills/stacks-technical-diagrams/renderers/lifecycle/render-lifecycle.mjs +990 -417
  148. package/ai/skills/stacks-technical-diagrams/renderers/sequence/README.md +49 -17
  149. package/ai/skills/stacks-technical-diagrams/renderers/sequence/render-sequence.mjs +735 -94
  150. package/ai/skills/stacks-technical-diagrams/renderers/shared/atomic-output.mjs +1982 -0
  151. package/ai/skills/stacks-technical-diagrams/renderers/shared/automatic-labels.mjs +290 -0
  152. package/ai/skills/stacks-technical-diagrams/renderers/shared/brand-marks.mjs +169 -26
  153. package/ai/skills/stacks-technical-diagrams/renderers/shared/cli.mjs +266 -54
  154. package/ai/skills/stacks-technical-diagrams/renderers/shared/desktop-readability.mjs +106 -0
  155. package/ai/skills/stacks-technical-diagrams/renderers/shared/diagnostics.mjs +0 -0
  156. package/ai/skills/stacks-technical-diagrams/renderers/shared/generated-validators.mjs +268 -2
  157. package/ai/skills/stacks-technical-diagrams/renderers/shared/geometry.mjs +774 -124
  158. package/ai/skills/stacks-technical-diagrams/renderers/shared/i18n.mjs +289 -556
  159. package/ai/skills/stacks-technical-diagrams/renderers/shared/layout-report.mjs +18 -1
  160. package/ai/skills/stacks-technical-diagrams/renderers/shared/legend.mjs +16 -6
  161. package/ai/skills/stacks-technical-diagrams/renderers/shared/node-card-style.mjs +32 -0
  162. package/ai/skills/stacks-technical-diagrams/renderers/shared/output-path.mjs +329 -229
  163. package/ai/skills/stacks-technical-diagrams/renderers/shared/owned-temp-directory.mjs +82 -0
  164. package/ai/skills/stacks-technical-diagrams/renderers/shared/path-semantics.mjs +1017 -0
  165. package/ai/skills/stacks-technical-diagrams/renderers/shared/portable-path.mjs +408 -0
  166. package/ai/skills/stacks-technical-diagrams/renderers/shared/repository-evidence.mjs +235 -79
  167. package/ai/skills/stacks-technical-diagrams/renderers/shared/repository-location.mjs +17 -4
  168. package/ai/skills/stacks-technical-diagrams/renderers/shared/route-quality.mjs +670 -0
  169. package/ai/skills/stacks-technical-diagrams/renderers/shared/sidecar-path.mjs +38 -0
  170. package/ai/skills/stacks-technical-diagrams/renderers/shared/software-notices.mjs +6 -0
  171. package/ai/skills/stacks-technical-diagrams/renderers/shared/spatial-grid.mjs +66 -0
  172. package/ai/skills/stacks-technical-diagrams/renderers/shared/svg-path-analysis.mjs +135 -0
  173. package/ai/skills/stacks-technical-diagrams/renderers/shared/text-fit.mjs +59 -3
  174. package/ai/skills/stacks-technical-diagrams/renderers/shared/utils.mjs +63 -35
  175. package/ai/skills/stacks-technical-diagrams/renderers/shared/validator.mjs +2 -5
  176. package/ai/skills/stacks-technical-diagrams/renderers/timeline/README.md +76 -0
  177. package/ai/skills/stacks-technical-diagrams/renderers/timeline/render-timeline.mjs +576 -0
  178. package/ai/skills/stacks-technical-diagrams/renderers/tree/README.md +96 -0
  179. package/ai/skills/stacks-technical-diagrams/renderers/tree/render-tree.mjs +573 -0
  180. package/ai/skills/stacks-technical-diagrams/renderers/waterfall/README.md +73 -0
  181. package/ai/skills/stacks-technical-diagrams/renderers/waterfall/render-waterfall.mjs +413 -0
  182. package/ai/skills/stacks-technical-diagrams/renderers/workflow/README.md +137 -23
  183. package/ai/skills/stacks-technical-diagrams/renderers/workflow/render-workflow.mjs +18 -6
  184. package/ai/skills/stacks-technical-diagrams/renderers/workflow/workflow-compiler.mjs +2230 -710
  185. package/ai/skills/stacks-technical-diagrams/renderers/workflow/workflow-migration-geometry.mjs +17 -0
  186. package/ai/skills/stacks-technical-diagrams/renderers/workflow/workflow-placement-repair.mjs +94 -0
  187. package/ai/skills/stacks-technical-diagrams/schemas/README.md +87 -40
  188. package/ai/skills/stacks-technical-diagrams/schemas/architecture.schema.json +7 -33
  189. package/ai/skills/stacks-technical-diagrams/schemas/class.schema.json +345 -0
  190. package/ai/skills/stacks-technical-diagrams/schemas/common.schema.json +68 -2
  191. package/ai/skills/stacks-technical-diagrams/schemas/dataflow.schema.json +14 -3
  192. package/ai/skills/stacks-technical-diagrams/schemas/erd.schema.json +381 -0
  193. package/ai/skills/stacks-technical-diagrams/schemas/explainer.schema.json +927 -0
  194. package/ai/skills/stacks-technical-diagrams/schemas/lifecycle.schema.json +23 -110
  195. package/ai/skills/stacks-technical-diagrams/schemas/sequence.schema.json +15 -4
  196. package/ai/skills/stacks-technical-diagrams/schemas/timeline.schema.json +160 -0
  197. package/ai/skills/stacks-technical-diagrams/schemas/tree.schema.json +141 -0
  198. package/ai/skills/stacks-technical-diagrams/schemas/waterfall.schema.json +147 -0
  199. package/ai/skills/stacks-technical-diagrams/schemas/workflow.schema.json +14 -3
  200. package/ai/skills/stacks-technical-diagrams/scripts/check-render-output.mjs +876 -243
  201. package/ai/skills/stacks-technical-diagrams/scripts/check-update.mjs +1717 -0
  202. package/ai/skills/stacks-technical-diagrams/scripts/delivery-update-child.mjs +26 -0
  203. package/ai/skills/stacks-technical-diagrams/scripts/generate-brand-marks.mjs +141 -0
  204. package/ai/skills/stacks-technical-diagrams/scripts/generate-validators.mjs +105 -0
  205. package/ai/skills/stacks-technical-diagrams/scripts/render-examples.mjs +11 -1
  206. package/ai/skills/stacks-technical-diagrams/scripts/update-contract.mjs +187 -0
  207. package/ai/skills/stacks-technical-diagrams/skill-release.json +10 -0
  208. package/ai/skills/stacks-testing/SKILL.md +8 -1
  209. package/ide/vscode/package.json +1 -1
  210. package/package.json +2 -2
@@ -2,15 +2,26 @@
2
2
 
3
3
  Read this reference only after the Fast authoring path calls for more detail. The schemas and examples remain authoritative.
4
4
 
5
+ ## Composition repair
6
+
7
+ When correcting an authored overview's abstraction, map every affected role, relationship direction, protocol, boundary, condition, and source reference to its surviving node or relationship before regrouping. A startup citation does not prove a message protocol. Preserve each claim's inspected evidence. Keep user-supplied or agreed topology fixed; fewer routes alone do not justify merging. A boundary around one node requires an explicit isolation fact and must not merely repeat its label.
8
+
9
+ ## Label repair
10
+
11
+ When a relationship label collides, move the label, adjust the route or spacing, then shorten the wording while preserving meaning. Omit wording only when both endpoints fully imply it and it conveys no protocol, action, direction, synchronous or asynchronous behavior, or cross-boundary mechanism. Spacing means clear gap rather than center distance; measured mask width takes precedence. The first-draft gap budget is in [Layout and routing](authoring-defaults.md#layout-and-routing).
12
+
13
+ For a disproportionate sublabel, keep its exact role or protocol concise and place the supplementary fact in a note or card. Preserve every required responsibility, protocol, and boundary fact. Use the first-draft node-width budget in [Layout and routing](authoring-defaults.md#layout-and-routing).
14
+
5
15
  ## Schema lookup
6
16
 
7
17
  Read both the mode schema and `schemas/common.schema.json`. The mode schemas use `$ref`, so the common file is where shared enums live.
8
18
 
9
19
  - `componentType`: `frontend`, `backend`, `database`, `cloud`, `security`, `messagebus`, `external`
20
+ - Entity-relationship documents use `entities` and `relationships`; `key` accepts `pk`, `fk`, or `uk`, and `fromCardinality`/`toCardinality` accept `one` or `many`.
10
21
  - `variant`: `default`, `emphasis`, `security`, `dashed`
11
22
  - Relationship IDs use the shared identifier pattern and must be unique in their collection.
12
23
 
13
- Do not invent fields. Use the nearest matching example for structure, then author fresh IDs, wording, facts, and layout.
24
+ Do not invent fields. Before writing any new field, enum, or constrained text, read its schema definition, including common `$ref` targets. In particular, check boundary kinds, repository identity, and source-reference shapes. An example demonstrates structure; it does not enumerate every valid value. Author fresh IDs, wording, facts, and layout.
14
25
 
15
26
  ## Workflow layout contracts
16
27
 
@@ -21,6 +32,10 @@ edge labels are never deleted as a spacing repair. Do not change only
21
32
  [migration and layout-receipt contract](../renderers/workflow/README.md#migration-and-layout-receipt).
22
33
  The complete normative invariants live in the workflow renderer's
23
34
  [layout contracts](../renderers/workflow/README.md#layout-contracts).
35
+ For sequential stages stacked in one container, use one v2 lane and group,
36
+ omit `meta.viewBox`, and center nodes around the lane content with symmetric
37
+ `yOffset` values such as `-90 / 0 / 90`. Keep semantic edge labels and act on
38
+ compiler diagnostics.
24
39
 
25
40
  ## Legend contract
26
41
 
@@ -34,10 +49,13 @@ both. `visible: true` may show an unused supported convention, while
34
49
  A label override changes reader wording only. Never infer a kind from prose or
35
50
  use the legend to compensate for missing nodes, states, messages, or flows.
36
51
  Long labels are measured and wrap into deterministic rows. Architecture's
37
- implicit automatic viewBox grows from that same measured footprint. For
38
- backwards compatibility, a legacy document with no `meta.legend` may omit an
39
- implicit auto legend that cannot fit its explicit viewBox; this never changes
40
- its typed topology. Adding `meta.legend` makes the presentation intentional and
52
+ implicit automatic viewBox grows from that same measured footprint, and an
53
+ automatic ERD canvas is sized the same way so its default legend is always in
54
+ the generated content. For backwards compatibility, a legacy document with no
55
+ `meta.legend` may omit an implicit auto legend that cannot fit its explicit
56
+ viewBox; this never changes its typed topology. An ERD that authors a
57
+ `meta.viewBox` keeps that fixed area and reports the capacity instead of
58
+ dropping the legend. Adding `meta.legend` makes the presentation intentional and
41
59
  strict: if its resolved labels cannot fit the authored viewBox, shorten or hide
42
60
  them, or widen the viewBox using the emitted diagnostic.
43
61
 
@@ -46,27 +64,56 @@ them, or widen the viewBox using the emitted diagnostic.
46
64
  Choose one primary authored language. An explicit user choice wins; otherwise
47
65
  use the language of the request, or the conversation's dominant language when
48
66
  the request itself is language-neutral. Separately choose the Viewer locale.
49
- For supported languages, always write the matching `meta.locale`: `"en"` for
50
- English or `"zh-CN"` for Simplified Chinese. The renderer consumes the authored
51
- locale without inferring language from diagram strings. Documents that omit it
52
- remain valid and default to English.
67
+ Always write the matching `meta.locale` as a well-formed language tag: `"en"`
68
+ for English, `"zh-CN"` for Simplified Chinese, `"es"` for Spanish, or any
69
+ other tag for another language. The renderer consumes the authored locale without inferring language
70
+ from diagram strings. Documents that omit it remain valid and default to
71
+ English.
53
72
 
54
73
  `meta.locale` controls only renderer-owned reader surfaces: `<html lang>`, the
55
74
  document-title suffix, default SVG description and focus labels, default legend
56
75
  labels, and fixed Viewer controls, statuses, accessibility names, and errors.
57
76
  It never translates authored content. Apply the primary language separately to
58
77
  titles, subtitles, node and relationship copy, boundaries, lanes, groups,
59
- guided views, legend label overrides, and cards. A bilingual diagram still
78
+ legend label overrides, and cards. A bilingual diagram still
60
79
  chooses one primary locale for the Viewer; follow an explicit primary-language
61
80
  request, then prompt order or conversation dominance.
62
81
 
63
- For a requested language outside `en` and `zh-CN`, do not write an unsupported
64
- locale. Keep every reader-facing authored string in the requested language,
65
- omit `meta.locale` so the renderer safely uses English, and explicitly tell the
66
- user that fixed Viewer UI and `<html lang>` remain English and the artifact is
67
- not fully localized. The fallback applies only to renderer-owned surfaces; it
68
- never permits authored copy to fall back to English. Do not silently substitute
69
- `zh-CN` for another language or Chinese locale.
82
+ Bundled Viewer catalogs are enrolled in `locales/manifest.json`: currently
83
+ `en`, `zh-CN`, `zh-TW`, `es`, `ko`, and `ar`. For these, `meta.locale` alone selects the full
84
+ catalog. Tags match case-insensitively (`zh-cn` selects `zh-CN`), but region
85
+ and script variants are distinct: `zh-Hant`, `es-MX`, or `ko-KR` select no
86
+ bundled catalog.
87
+
88
+ `meta.translations` is an optional per-key override: an object mapping the
89
+ renderer's canonical message keys (`locales/en.json`, or `catalogKeys()` in
90
+ `renderers/shared/i18n.mjs`) to translated strings whose `{placeholder}` tokens
91
+ match the English source exactly. Each message resolves as: valid
92
+ `meta.translations` value → the selected bundled catalog → English. For a
93
+ bundled locale, supply only the keys whose wording the diagram needs to change;
94
+ the rest of the language is kept. Omitting the field or supplying `{}` means no
95
+ override. For a language without a bundled catalog, supply the catalog here.
96
+ Reuse suitable translations from `examples/locales/` or a previously reviewed
97
+ catalog, translate missing keys, and use the English source to check keys and
98
+ placeholders.
99
+
100
+ An unknown key or a value with mismatched placeholders is rejected and keeps
101
+ the lower-priority message; it is reported as `i18n/invalid-translation` on
102
+ stderr and as a warning in the `validate --json`, `deliver`, and `finalize`
103
+ receipt `diagnostics[]`. Keys that still resolve to English in a
104
+ non-English locale are reported as `i18n/translation-coverage`, with the missing
105
+ keys and their English source text; add exactly those keys to repair the gap.
106
+ Coverage describes the final resolved catalog, not the size of the override.
107
+
108
+ For a requested language you cannot supply `meta.translations` for, do not
109
+ write a `meta.locale` with no bundled catalog and no translations. Keep every
110
+ reader-facing authored string in the requested language, omit `meta.locale` so
111
+ the renderer safely uses English, and explicitly tell the user that fixed
112
+ Viewer UI and `<html lang>` remain English and the artifact is not fully localized.
113
+ The fallback applies only to renderer-owned surfaces; it never
114
+ permits authored copy to fall back to English. Do not silently substitute
115
+ `zh-CN` for another language or Chinese locale, and do not machine-translate
116
+ `meta.translations` values without disclosing that they are unreviewed.
70
117
 
71
118
  Keep exact product names, code identifiers, commands, protocols, API paths, and
72
119
  environment names intact. Those terms may remain English inside localized copy,
@@ -103,16 +150,69 @@ in the generated viewer.
103
150
 
104
151
  ## Executable geometry rules
105
152
 
106
- - Node anchors start at side midpoints. `left`/`right` change the horizontal endpoint; `top`/`bottom` change the vertical endpoint. For an automatic Architecture relationship, unobstructed facing ports whose axis offset is under 16px may share one horizontal or vertical axis when both endpoints retain the 16px corner gutter. If exactly one endpoint belongs to a spread group, only its unshared counterpart moves; relationships spread at both endpoints keep their distinct ports and outside bridge.
153
+ Generate one responsive artifact for laptops and external displays, preserving the authored SVG/viewBox, proportions, semantic geometry, and normal document flow. Use meaningful content rows and the Reader-declared readable page-scroll behavior when the complete diagram needs more height; viewport fitting does not authorize alternate topology or smaller typography.
154
+
155
+ - Node anchors start at side midpoints. `left`/`right` change the horizontal endpoint; `top`/`bottom` change the vertical endpoint. For an automatic Architecture relationship, unobstructed facing ports whose axis offset is under 16px may share one horizontal or vertical axis when both endpoints retain the 16px corner gutter. If exactly one endpoint belongs to a spread group, only its unshared counterpart moves; relationships spread at both endpoints keep their distinct ports and outside bridge unless a reciprocal facing pair can jointly use separate straight lanes while preserving endpoint spacing, labels, and all surrounding route and obstacle clearances.
107
156
  - A side is a direction contract. The first and final route segment must be perpendicular and outward/inward in the named direction.
108
- - Automatic Port Spread is a default renderer behavior for architecture, workflow, data-flow, and lifecycle diagrams. Shared automatic endpoints spread deterministically and symmetrically with a 16px corner gutter. It does not apply to sequence messages, single relationships, or explicit `via`, `channelX`, `channelY`, `labelAt`, or non-`auto` routes.
157
+ - In architecture and data-flow diagrams, explicit `route: "straight"` requests one direct segment, which may be diagonal when endpoint sides are not pinned. The artifact checker preserves this intent; explicit sides, opaque-node clearance, and other quality gates still apply. `via` takes precedence and retains existing rules, including data-flow's requirement for orthogonal via segments.
158
+ - Automatic Port Spread is a default renderer behavior for architecture, workflow, and data-flow diagrams. Shared automatic endpoints spread deterministically and symmetrically with a 16px corner gutter. It does not apply to sequence messages, single relationships, or explicit `via`, `channelX`, `channelY`, `labelAt`, or non-`auto` routes.
109
159
  - Showcase route rhythm: every nonzero segment must be at least 8px; every interior segment must be at least 16px. When spread ports are nearly parallel, the router uses a 24px endpoint stub and a 16px outside bridge instead of manufacturing a tiny dogleg.
160
+ - Showcase route compactness: an explicit Architecture route fails with `composition/excessive-route-detour` when its orthogonal length is at least 2.5 times an obstacle-aware legal route, adds at least 200px, and sends a control point at least 96px beyond the content envelope. The evidence records both lengths, ratio, excess, bounds, and excursion. Remove an unnecessary `via` or move the diagnosed corridor inward instead of enlarging the canvas. Related relationships that overlap on the same outer corridor by at least 32px are treated as an intentional bus and remain valid.
110
161
  - Shared endpoint corridors are allowed only when they remain semantically unambiguous. Unrelated collinear overlap of 8px or more fails showcase.
111
162
  - Container borders are intentional pass-through geometry, but a long edge running along a structural border is not.
112
163
  - An edge crossing an unrelated opaque node is always a hard failure, independent of quality profile.
113
164
 
165
+ ### Explicit `via` coordinates
166
+
167
+ Use the resolved departure anchor `S = [sx, sy]` and arrival anchor
168
+ `T = [tx, ty]`. Anchors start at side midpoints, but automatic routing and
169
+ Port Spread can move them as described above; do not assume an anchor copied
170
+ from an automatic route is the anchor of a newly authored explicit route.
171
+ Explicit `via` routes do not receive automatic Port Spread.
172
+
173
+ For the first waypoint `F = via[0]` and last waypoint `L = via[via.length - 1]`,
174
+ use these alignments and directions (SVG y increases downward):
175
+
176
+ | Side | Departure (`fromSide`): `S` → `F` | Arrival (`toSide`): `L` → `T` |
177
+ | --- | --- | --- |
178
+ | `top` | `F[0] === sx`, `F[1] < sy` | `L[0] === tx`, `L[1] < ty` |
179
+ | `bottom` | `F[0] === sx`, `F[1] > sy` | `L[0] === tx`, `L[1] > ty` |
180
+ | `left` | `F[1] === sy`, `F[0] < sx` | `L[1] === ty`, `L[0] < tx` |
181
+ | `right` | `F[1] === sy`, `F[0] > sx` | `L[1] === ty`, `L[0] > tx` |
182
+
183
+ For example, given a bottom departure anchor `S = [180, 160]` and a left
184
+ arrival anchor `T = [360, 260]`, this relationship fragment leaves downward
185
+ and enters the target rightward:
186
+
187
+ ```json
188
+ {
189
+ "from": "source",
190
+ "to": "target",
191
+ "fromSide": "bottom",
192
+ "toSide": "left",
193
+ "via": [[180, 200], [300, 200], [300, 260]]
194
+ }
195
+ ```
196
+
197
+ The full path is `[180, 160] → [180, 200] → [300, 200] → [300, 260] → [360, 260]`.
198
+ Changing only the first waypoint to `[200, 200]` makes the departure diagonal;
199
+ changing it to `[180, 120]` keeps its x aligned but leaves upward through the
200
+ source instead of outward from its bottom. Both violate `fromSide: "bottom"`
201
+ and produce `clean-flow/endpoint-side-direction`. The example establishes
202
+ endpoint direction only: keep the full route clear of unrelated nodes and
203
+ apply the other geometry rules above.
204
+
114
205
  ### Spacing and labels
115
206
 
207
+ In showcase Architecture, an unpinned connection label keeps its default position
208
+ when clear. If it collides, the renderer tries a bounded set of nearby positions
209
+ along the existing route, avoiding nodes, boundary titles, other labels and
210
+ other routes within the resolved canvas. Explicit `labelAt`, `labelDx`, `labelDy`
211
+ or `labelSegment` (including zero) disables this fallback. Routes and topology
212
+ stay unchanged; if no nearby position is clear, validation reports the original
213
+ collision. Inspect resolved labels with `--layout-json` before adding controls.
214
+ Standard placement retains its existing behavior.
215
+
116
216
  Spacing recommendations mean clear gap between boxes, not center distance. A 200px center distance between 165px-wide nodes leaves only 35px of clear gap.
117
217
 
118
218
  For a relationship label, require:
@@ -133,71 +233,343 @@ its endpoints fully imply it, explain why the wording is redundant; this is a
133
233
  semantic authoring choice, not a spacing repair. In workflow v2, let the compiler
134
234
  allocate its measured mask before applying a diagnosed `labelAt`,
135
235
  `labelDx`/`labelDy`, or `labelSegment`. Apply one diagnosed geometry control at
136
- a time.
236
+ a time unless several edges share a constrained channel. In that case, plan the smallest coupled change from measured geometry and
237
+ validate it together. Architecture/workflow provide layout evidence through
238
+ `validate <type> <candidate.json> --layout-json`; for other types, use validation
239
+ diagnostics and the rendered SVG geometry.
240
+ Before adding manual routes, check whether unnecessary agent-added controls
241
+ disable automatic port spread; preserve user-required route intent. Use the
242
+ measured clearance rules above rather than guessing coordinates.
243
+
244
+ ### Repair evidence
245
+
246
+ For architecture, `validate architecture <input.json> --layout-json` exposes the
247
+ resolved component boxes, boundary frames, connection points, and label positions.
248
+ A measurable rejected layout also returns these fields, with `ok: false`,
249
+ `contract: "archify-architecture-layout-v1"`, diagnostics, and exit 1. This is
250
+ repair evidence, not artifact acceptance; it writes no HTML. Malformed input or
251
+ an implementation failure retains the ordinary failure receipt without layout.
252
+
253
+ Use the measured failing side for `layout/boundary-out-of-bounds`. Left/top
254
+ negative coordinates need an inward move; increasing viewBox width/height only
255
+ addresses right/bottom overflow. Boundaries may wrap members across rows. Keep
256
+ real membership intact and recheck connected routes after moving members.
257
+
258
+ Automatic architecture canvases include route points as well as nodes, frames,
259
+ and labels. An authored viewBox remains authoritative. In showcase,
260
+ `layout/route-out-of-bounds` identifies clipped route points; negative coordinates
261
+ need an inward route, while right/bottom overflow can also use a larger authored
262
+ canvas. Recheck desktop readability after enlarging a canvas.
263
+
264
+ When several crossing/corridor diagnoses involve the same nodes, consider their
265
+ placement together before adding route controls. Apply one coherent repair and
266
+ validate it; independent label nudges cannot fix a shared layout bottleneck.
267
+ Compare diagnostics by code, subject, and stage instead of total count alone.
137
268
 
138
269
  ### Repair order
139
270
 
140
271
  1. Fix missing/invalid `meta.quality_profile` and schema errors.
141
272
  2. Fix node overlap or out-of-range placement.
142
273
  3. Fix edge-through-node and endpoint-direction errors.
143
- 4. Fix crossings, ambiguous corridors, border runs, and route rhythm.
274
+ 4. Fix crossings, ambiguous corridors, border runs, excessive detours, and route rhythm.
144
275
  5. Fix label-to-node, label-to-label, then label-to-route clearance.
276
+ 6. Fix labels that leave the canvas: move the label with `labelAt`/`labelDx`/`labelDy`/`labelSegment`, or widen `meta.viewBox`. Suggested `labelDx`/`labelDy` values replace the authored field; they are not added to it.
145
277
 
146
- Run `validate` after every edit. Consume `diagnostics[]` by stable `code`, exact `subject`, measured `evidence`, and `supportedFixes`. If the diagnostic gives `labelAt`, use that point instead of estimating another offset.
278
+ After every edit, rerun the complete `finalize` as the delivery contract requires; use `validate` only for focused diagnosis between finalize runs. Consume `diagnostics[]` by stable `code`, exact `subject`, measured `evidence`, and `supportedFixes`. If the diagnostic gives `labelAt`, use that point instead of estimating another offset.
147
279
 
148
280
  ## Mode placement
149
281
 
150
282
  ### Architecture
151
283
 
152
- Use one left-to-right spine with short vertical branches. Prefer 6-12 primary components and group only real ownership, trust, process, or deployment boundaries. Boundaries do not replace relationships.
284
+ Choose overview or mechanism detail using [Composition and meaning](authoring-defaults.md#composition-and-meaning). Use one obvious primary reading path, which may step across meaningful rows when the requested topology needs room. Keep the overview readable at its chosen abstraction; expand implementation details when they answer the reader's question. Group only real ownership, trust, process, or deployment boundaries. Boundaries do not replace relationships.
153
285
 
154
- Grid placement is preferred when the schema supports it. Free positions are appropriate for a bounded exception, not for prose-level coordinate planning. Keep external actors outside the system boundary when that is factually true.
286
+ Grid placement is preferred when the schema supports it. Free positions are appropriate for a bounded exception, not for prose-level coordinate planning. Keep external actors outside the system boundary when that is factually true. A boundary is drawn as the padded box around all of its members, so place them as one compact axis-aligned cluster (no empty bay that lets a non-member sit inside the padded frame) and keep every non-member outside that box; `layout/boundary-encloses-non-member` reports a component the box swallows in showcase quality. Standard retains its existing acceptance behavior.
155
287
 
156
288
  ### Workflow
157
289
 
158
290
  Lanes express responsibility or phase. Columns `0..5` express logical
159
291
  progression. Start new workflows on `readable-v2`; retain `fixed-v1` only for
160
- legacy geometry compatibility. Keep the happy path monotonic, preserve semantic
161
- edge labels, and route retries and exception returns outside the main lane
162
- corridor.
292
+ legacy geometry compatibility. In readable-v2, nodes may share a `(lane, col)`
293
+ when distinct `yOffset` values leave room for their full rectangles, labels and
294
+ connecting routes. Keep the happy path monotonic, preserve semantic edge labels,
295
+ and route retries and exception returns outside the main lane corridor.
296
+
297
+ #### Workflow viewport repair
298
+
299
+ When `viewer/viewport-overflow` includes `workflowLanes`, inspect the tallest
300
+ rendered frames and their node span before changing the source. Measurements
301
+ are CSS pixels; space above/below nodes includes lane titles and routing, so it
302
+ is not a removable-space budget. Frame IDs identify rendered lane indices.
303
+
304
+ Run `validate workflow <source.json> --layout-json` and match those frames to
305
+ source lanes and nodes. Check whether many steps share the last logical column
306
+ and use large `yOffset` values. Readable-v2 reserves symmetric space around
307
+ offsets. With a same-column vertical stack, an implicit canvas and no absolute
308
+ route or label pins, it measures each lane independently. Other cases retain
309
+ shared-height geometry for compatibility; see the canonical
310
+ [lane measurement contract](../renderers/workflow/README.md#readable-v2).
311
+
312
+ Where the source's ownership and explicit geometry permit, redistribute steps
313
+ across logical columns and meaningful lanes, keeping the main path monotonic.
314
+ Preserve every required node, relationship, label and semantic check. If ownership
315
+ or absolute pins prevent reflow, report that constraint instead of merging lanes
316
+ or moving pins automatically. Validate the changed JSON, deliver a fresh HTML,
317
+ then rerun browser checks and inspect the first screen; a static pass alone does
318
+ not settle viewport fit. These are repair directions, not guaranteed coordinates.
163
319
 
164
320
  ### Sequence
165
321
 
166
- Participants are ordered by conversation role. Messages own their vertical order. Use return/async/security variants for meaning, not decoration; sequence does not use Automatic Port Spread.
322
+ Participants are ordered by conversation role. Messages own their vertical order. Use return/async/security variants for meaning, not decoration; sequence does not use Automatic Port Spread. A segment's `from`/`to` edges must stay at least 4px off every message arrow (`message.y`): an edge along an arrow leaves the reader unable to tell which phase the message belongs to, and showcase quality reports `sequence/segment-message-border-run`. Standard retains its existing acceptance behavior.
323
+
324
+ First-draft shape: every message needs an `id`, `from`, `to`, `label`, and integer `y` at least 160. `from` and `to` must be different participants — self-messages are unsupported (`sequence/self-message-unsupported`). Optional phase bands are `segments[]` with only `from`, `to`, and `label` (no segment `id`). Inventing `pos`/`size` on participants fails schema validation — order alone places them. Omit `meta.viewBox` so automatic height fits the timeline + legend (minimum 327px readable band) instead of a fixed 760px floor, and so 2–3 participant spreads pack below the 920px default when labels fit (4+ stay at 920px; long labels still widen).
167
325
 
168
326
  ### Dataflow
169
327
 
170
- Stages express transformation or custody. Rows separate parallel streams. Label only data contracts, classifications, or cross-boundary movement that is not obvious.
328
+ Stages express transformation or custody. Rows separate parallel streams. Give every flow a concise data-contract or movement label; choose its visual convention using the required [Dataflow authoring defaults](authoring-defaults.md#presentation-and-modes).
329
+
330
+ First-draft shape: declare `stages[]` (each a `{label}`), then place every node with integer `stage` and `row` — not `pos`/`size`. Flows are `flows[]` with required `from`, `to`, and non-empty `label`.
331
+
332
+ Omit `meta.viewBox` to fit canvas width to all stages and nodes in either quality
333
+ profile, including explicit node widths. Width uses content + 24px right padding
334
+ with a 480px minimum (five default stages still need ~1068); left-edge overflow
335
+ still needs a node repair. An authored viewBox stays fixed. Showcase node growth, readable typography, content height, port bridges
336
+ and bounded label placement apply only when the canvas and all node widths are
337
+ omitted. `--quality` overrides `meta.quality_profile`; without it, the renderer
338
+ uses `ARCHIFY_QUALITY_PROFILE` when set, otherwise the JSON profile.
339
+
340
+ ### ERD
341
+
342
+ Treat a schema ERD as a table catalogue as well as a relationship map. If the
343
+ schema has more than 8 tables or 50 fields, it is a dense full-schema map: start
344
+ with `meta.quality_profile: "standard"` so complete field visibility is not
345
+ traded away for repeated showcase route repairs. Include every physical column in
346
+ `attributes`, keep the source SQL type, and preserve the
347
+ field's Chinese comment in the type string as `SQL_TYPE|中文备注` because the
348
+ schema has no separate comment property. The default viewer shows these rows at
349
+ the `read` level; do not rely on hover/focus or cards to reveal physical fields.
350
+ Cards may explain constraints, inferred relationships, or domain rules, but never
351
+ replace a field list.
352
+
353
+ Before placing boxes, classify tables into functional domains using verified table
354
+ names, comments, module paths, and foreign-key meaning. Put the domain name in
355
+ `tag` and give each domain one solid rectangle of grid cells: a single row, a
356
+ single column, or a filled rectangular block — not an L or a diagonal — with
357
+ every cell of the rectangle holding one of its tables.
358
+ All tables with the same tag stay together; do not interleave unrelated tables
359
+ between members. A domain that fills one such rectangle is drawn as a labelled
360
+ band behind its tables, so the
361
+ grouping is visible without reading every box;
362
+ a tag whose tables do not fill one rectangle earns no band, and because the band
363
+ is the only place a domain name is drawn the renderer reports
364
+ `erd/domain-not-drawn` rather than publishing a diagram that cannot name the
365
+ domain. Absolute
366
+ coordinates have no grid cells at all, so a tagged table always needs `row`/`col`.
367
+ Order parent/core tables
368
+ toward the shared boundary and
369
+ place their direct children beside or beneath them. Columns read left to right and
370
+ rows read top to bottom, so a relationship between neighbouring columns is one
371
+ straight corridor. Never place an unrelated entity between two aligned anchors;
372
+ the router can detour around it, but the clear corridor is shorter and reads
373
+ better. A junction table has two parents: put it in a cell beside or between
374
+ both, not beneath one of them with tables stacked between it and the other,
375
+ and keep every table that shares its domain tag in one solid rectangle of cells. A relationship must connect two different entities; a self-reference such as manager_id stays as a foreign-key column (and optionally a card), not an `employees`→`employees` edge.
376
+ Use `row`/`col` for this normal grouped layout, and only use explicit
377
+ `pos`/`via` after a diagnostic identifies a concrete geometry problem.
378
+
379
+ State every key role a column carries in `key`, and the real references in
380
+ `references`. A column is often more than one at once — a junction table's
381
+ `tenant_id` is both part of the primary key and a foreign key to `tenant.id` — so
382
+ `key` takes a role or a list (`["pk", "fk"]`), and dropping a role claims less
383
+ than the schema does.
384
+ A many-to-many pair is a real fact about the model, so state it and identify the join
385
+ table when one exists. A relationship has two ends and each one declares its own
386
+ maximum, so a `many`-to-`one` foreign key needs both `fromCardinality` and
387
+ `toCardinality`; `fromOptional`/`toOptional` only lowers that same end's minimum
388
+ from one to zero (an optional `one` end reads zero-or-one, an optional `many` end
389
+ reads zero-or-many), and `identifying: false` draws the non-identifying dashed
390
+ line and owns that dash — the schema rejects a `variant` that would draw the
391
+ relationship solid beside it. The foot opens toward the entity it describes, so the
392
+ drawn glyph states the end's maximum, not a direction of travel.
393
+
394
+ A table side only has room for so many ends: the ports spread at most `(side
395
+ extent - 32) / (ends - 1)` apart, and a cardinality glyph is 14 units tall. More
396
+ relationship ends than that room allows is `layout/marker-capacity`, which names
397
+ the table, the side, and the ways out — add fields so the side is taller, spread
398
+ the relationships, or reduce the fan-in. Never fix it by hiding the cardinality.
399
+
400
+ Give the domains a column each when the model has to read completely inside a
401
+ laptop viewport. The Reader scales a wide canvas up to the reader width and
402
+ narrows a tall one until the whole page fits, so the same eleven tables cost text
403
+ size when they are stacked as four horizontal domains instead of four vertical
404
+ ones. Leave a whole tile of the grid free where a long relationship has to cross
405
+ a domain: a run that crosses an occupied cell forces a jog, and a jog below the
406
+ interior floor is a `composition/short-interior-segment` failure.
407
+
408
+ An automatic canvas is sized so the default legend is always in the generated
409
+ content, and a canvas the author fixes with `meta.viewBox` reports its legend
410
+ capacity instead of dropping the key; see
411
+ [`../renderers/erd/README.md`](../renderers/erd/README.md) for the band, port, and
412
+ reader contract.
413
+
414
+ ### Tree
415
+
416
+ A tree answers "how is this decomposed?": one root, and every other node names
417
+ exactly one `parent`. Links mean containment only; do not use a tree for calls,
418
+ data movement, or cross-branch dependencies. Nothing is inferred: a missing
419
+ parent (`tree/missing-parent`), zero or several roots (`tree/root-count`), a
420
+ parent cycle (`tree/cycle`, which also covers every node stranded beneath it),
421
+ and duplicate ids are refused. Children read in declaration order.
422
+
423
+ Use `layout.direction: "down"` (default) for a shallow, balanced breakdown and
424
+ `"right"` for a deep or leaf-heavy tree such as a repository layout; a rightward
425
+ tree aligns each parent with its first child and scrolls vertically in the
426
+ reader. Labels wrap between words. `collapsed: true` makes a branch start
427
+ collapsed in the Viewer; it never removes content from the artifact, and every
428
+ export is the complete tree. For a real codebase, ground each node in the
429
+ observed path and attach `sources`. See
430
+ [`../renderers/tree/README.md`](../renderers/tree/README.md).
431
+
432
+ ### Class
433
+
434
+ A class diagram explains the contracts inside one module: which types exist,
435
+ which members matter to the explanation, and how the types relate. Choose the
436
+ members the question needs; a type may show none. Each type states its `kind`
437
+ (`class`, `abstract`, `interface`, `enum`, `record`); every kind except `class`
438
+ draws its UML keyword, so an interface never reads as an empty class. For a real
439
+ codebase, ground every type, member, and relationship in repository evidence and
440
+ attach `sources`.
441
+
442
+ Every relationship reads `from` -> `to` and its `kind` owns the notation:
443
+ `dependency` (`from` uses `to`, dashed open arrow), `association` (`from` holds a
444
+ `to`, solid open arrow), `inheritance` (`from` extends `to`, solid hollow
445
+ triangle), `realization` (`from` implements interface `to`, dashed hollow
446
+ triangle), `composition` and `aggregation` (`from` is the whole, filled or
447
+ hollow diamond at `from`). Realization must target an interface from a
448
+ non-interface; inheritance must not cross the interface boundary; an
449
+ inheritance cycle is rejected.
450
+
451
+ Place types on the `row`/`col` grid with supertypes above their subtypes. Two
452
+ or more automatic generalizations into one supertype draw as one hierarchy bus
453
+ with a single triangle. Members never truncate: a type grows to its widest
454
+ member up to `layout.typeMaxW` and longer members wrap at parameter boundaries.
455
+ See [`../renderers/class/README.md`](../renderers/class/README.md).
456
+
457
+ First-draft shape: types use `row`/`col` (not `pos`/`size`), fields go in
458
+ `attributes[]`, operations in `methods[]` with `parameters` as one string such as
459
+ `"msg: Message"` (not an array of objects). Enum members are attributes with only
460
+ `name`. Relationships need an `id`, `from`, `to`, and `kind`.
461
+
462
+ ### Timeline
463
+
464
+ A timeline answers "when did what happen, and how far apart?". Every event
465
+ needs an ISO 8601 `at` with an explicit `Z` or `±HH:MM` offset; a timestamp
466
+ without one is rejected rather than guessed. `meta.timezone` (IANA, default
467
+ `UTC`) is the display clock for ticks and labels, and the axis caption states
468
+ it. `meta.evidence` is required: `observed` for recorded events (logs, git
469
+ history, pager records) and `illustrative` for explanatory input. Never mark
470
+ invented or approximate times as observed, and never fill gaps with events the
471
+ input does not contain.
472
+
473
+ Use `lanes` for sources or categories (release, monitoring, response); every
474
+ event then names one. Each event's visible text is `title` (not `label`). `kind`
475
+ (`default`, `change`, `alert`, `action`, `recovery`) only
476
+ colours the card; inventing values such as `milestone` fails schema validation. Events are drawn in time order whatever the authored order;
477
+ simultaneous and close events stack. By default a quiet period longer than 8×
478
+ the median gap and 10% of the span is drawn as a fixed-width break labelled
479
+ with the omitted duration; `layout.breaks: "none"` keeps one proportional axis.
480
+ See [`../renderers/timeline/README.md`](../renderers/timeline/README.md).
481
+
482
+ ### Waterfall
483
+
484
+ A waterfall answers "where did the time go?" for one request, job, or agent
485
+ run. Each span has `id`, `name`, `start`, and `end` or `duration` in
486
+ `meta.unit` (`us`, `ms`, `s`; default `ms`), plus optional `parent`, `status`,
487
+ `service`, and `detail`. Bar position and length come only from these numbers.
488
+ `meta.evidence` is required: `measured` only for recorded timing (trace export,
489
+ logs, profiler, timed run); otherwise `illustrative`. Never infer a duration
490
+ from code structure, and never present estimated numbers as measured.
491
+
492
+ A span with no recorded end must be `status: "incomplete"`; it is drawn as an
493
+ open lower bound to the last recorded instant. Contradictory end/duration,
494
+ an end before the start, a missing parent, or a parent cycle is refused.
495
+ Percentages are always "of the wall-clock total"; parent and child durations
496
+ are inclusive and never summed. Do not mark a critical path or waiting time
497
+ unless the input states the dependency. See
498
+ [`../renderers/waterfall/README.md`](../renderers/waterfall/README.md).
171
499
 
172
500
  ### Lifecycle
173
501
 
174
- Main phases use columns `0..4`; event and terminal bands use columns `0..2`.
175
- Event/terminal column `N` aligns to the same x coordinate as main column
176
- `N + 2`. A recoverable failure needs a real transition back to an active state.
177
- A card or guided view saying “retry” is not topology.
502
+ Schema v3 is the only lifecycle contract. `mainPath` lists the happy path from
503
+ the initial state; every consecutive pair needs a transition. The renderer owns
504
+ all geometry: the main path is one row, transitions back to an earlier phase
505
+ (or skipping ahead) become arcs above it, and every other state sits below the
506
+ state it branches from, one row deeper per step away from the main path.
507
+ Equivalent exits share one arrow only when their labels, notes and variants
508
+ match and exactly one group from at least two main-path phases qualifies for
509
+ that target. Consecutive phases receive a composite frame; non-consecutive
510
+ phases share a bus. Other exits stay separate, including distinct notes on
511
+ their original transitions. Do not remove or copy notes to force sharing.
512
+ There are no lanes, columns, sizes, or routing controls. Layout retries retain
513
+ the transition text's minimum gap and stop widening the main-path row when its
514
+ minimum width would exceed the original text readability budget; the final
515
+ width and label-clearance checks still apply.
516
+
517
+ Keep the main path to the phases a reader follows, at most about six states,
518
+ and keep transition labels short. A recoverable failure needs a real transition
519
+ back to an active state; a card saying “retry” is not topology.
520
+
521
+ Pick each state's `type` by what the reader should notice, since color and the
522
+ corner sigil follow it: `waiting` for a pause on a person, time, or input;
523
+ `decision` for a review or branch point; `success` or `failure` for a good or
524
+ bad outcome; `neutral` for parked states and outcomes that are neither;
525
+ `external` when an outside party holds the work; `active` otherwise. From a
526
+ Mermaid `stateDiagram`, `[*] -->` names the first `mainPath` state, a state
527
+ with `--> [*]` is an outcome (`success`, `failure`, or `neutral`; it is drawn as
528
+ final when it has no other outgoing transition), and `<<choice>>` becomes a
529
+ `decision` state. Flatten a composite `state X { ... }` into its inner states
530
+ and repeat its exit from each of them with one label; consecutive main-path
531
+ phases sharing that exit are framed automatically. Concurrent regions (`--`)
532
+ have no lifecycle form: draw one lifecycle per region.
178
533
 
179
534
  ## Repository evidence
180
535
 
181
- When an architecture diagram must reflect real code, inspect repository
182
- entrypoints, runtime boundaries, storage, transports, and deployment
183
- configuration before authoring. Record only evidence you actually verified.
184
- `--repo-root <path>` is architecture-only and is accepted by architecture
185
- `render`, `validate`, `deliver`, `preview`, and `compare`; workflow, sequence,
186
- dataflow, and lifecycle reject it. Never infer runtime causality from file
187
- proximity or naming alone.
536
+ When the diagram must reflect real code, inspect repository entrypoints,
537
+ runtime boundaries, storage, transports, and deployment configuration before
538
+ authoring. Record only evidence you actually verified. `--repo-root <path>` is
539
+ accepted by `render`, `validate`, `deliver`, and `preview` for every diagram
540
+ type, by architecture `compare`, and by workflow `migrate`; every mode verifies `meta.repository` and
541
+ node `sources` the same way. Migrating a source-backed workflow requires the same
542
+ `--repo-root` so its candidate is verified before replacing the destination.
543
+ Never infer runtime causality from file proximity
544
+ or naming alone.
188
545
 
189
546
  Declare `meta.repository.url` and one full 40-character `revision`, then attach
190
- `components[].sources` with repository-relative `path`, optional `line`,
191
- `end_line`, and `label`. Verification reads blobs at that commit, independently
192
- of working-tree edits. A matching local origin, available commit, bounded path,
547
+ `sources` to the mode's node collection (Architecture `components[]`, Workflow
548
+ and Data Flow `nodes[]`, Sequence `participants[]`, Lifecycle `states[]`) with
549
+ repository-relative `path`, optional `line`, `end_line`, and `label`.
550
+ Verification reads blobs at that commit, independently of working-tree edits.
551
+ Verification ignores local Git replacement refs, including those selected by
552
+ `GIT_REPLACE_REF_BASE`, and always reads the original objects at the pinned SHA.
553
+ It does not change repository configuration or delete replacement refs.
554
+ A matching local origin, available commit, bounded path,
193
555
  blob, and valid line range are required in every link mode. Verification is
194
556
  local and makes no remote requests; it establishes neither public availability
195
557
  nor the current reader's access rights.
196
558
 
197
- `link_mode` defaults to `web`. GitHub and Gitee HTTPS repository URLs generate
198
- revision-pinned links; their public hosts select the provider automatically.
199
- Optional `provider: "github"` or `"gitee"` must agree with the host. Existing
200
- GitHub declarations and default delivery receipt fields remain compatible.
559
+ `link_mode` defaults to `web`. GitHub, Gitee, and GitLab HTTPS repository URLs
560
+ generate revision-pinned links; the public hosts github.com, gitee.com, and
561
+ gitlab.com select the provider automatically. Optional `provider: "github"`,
562
+ `"gitee"`, or `"gitlab"` must agree with a public host. A self-managed GitLab
563
+ host declares `provider: "gitlab"`; Archify never contacts the host to detect
564
+ its forge. Existing GitHub declarations and default delivery receipt fields
565
+ remain compatible.
566
+
567
+ GitLab URLs may name nested groups (`group/subgroup/project`). Source links use
568
+ `<url>/-/blob/<revision>/<path>#L<line>-<end_line>` and the repository link
569
+ uses `<url>/-/tree/<revision>`. A Markdown source (`.md`, `.markdown`) with a
570
+ line range links to the plain view (`?plain=1`) so the cited lines are
571
+ highlighted instead of the rendered document. GitLab repository paths compare
572
+ case-insensitively, like GitHub.
201
573
 
202
574
  ```json
203
575
  {
@@ -207,6 +579,14 @@ GitHub declarations and default delivery receipt fields remain compatible.
207
579
  }
208
580
  ```
209
581
 
582
+ ```json
583
+ {
584
+ "url": "https://git.example.com/platform/payments/service",
585
+ "revision": "0123456789abcdef0123456789abcdef01234567",
586
+ "provider": "gitlab"
587
+ }
588
+ ```
589
+
210
590
  For an internal or unsupported forge, select `link_mode: "local-only"`. The
211
591
  Viewer retains SRC markers, searchable file paths, line ranges, and revision
212
592
  labels without repository or source hyperlinks. The evidence receipt adds
@@ -226,18 +606,40 @@ Local-only accepts HTTP(S), `git@host:path`, and `ssh://git@host[:port]/path`
226
606
  addresses, including nested namespaces. Declare a credential-free address;
227
607
  HTTP(S) credentials on the checkout's origin are ignored for identity and
228
608
  redacted from diagnostics. Hostnames compare case-insensitively; repository
229
- paths retain case except for the existing GitHub behavior. A trailing slash
230
- normalizes away. Only GitHub and Gitee normalize a terminal `.git` and match
231
- standard HTTPS/443 with Git SSH/22. For other hosts, use the actual clone address:
609
+ paths retain case except for GitHub and GitLab. A trailing slash
610
+ normalizes away. Only GitHub, Gitee, and GitLab (gitlab.com, or a host declared
611
+ with `provider: "gitlab"`) normalize a terminal `.git` and match standard
612
+ HTTPS/443 with Git SSH/22 on the same host; a GitLab SSH endpoint on another host
613
+ or port is not inferred. For other hosts, use the actual clone address:
232
614
  transport, port, `.git` suffix, and remote-relative versus absolute paths must
233
615
  match. For example, `git@host:Team/repo` differs from
234
616
  `ssh://git@host/Team/repo`; `git@host:/Team/repo` matches the latter. SCP-style
235
617
  paths preserve literal percent escapes, while URI paths decode them. SSH host
236
618
  aliases and forge-specific browse/clone prefixes are not guessed.
237
- GitLab/Gitea/Forgejo/Bitbucket web links are not implemented in this version;
619
+ Gitea/Forgejo/Bitbucket web links are not implemented in this version;
238
620
  use local-only until a tested link provider is available. Unknown web providers
239
621
  fail with a diagnostic rather than emitting a guessed link.
240
622
 
241
623
  ## Hand-placed fallback
242
624
 
243
625
  Use only when no renderer can run. Start from `assets/template.html`, keep semantic CSS classes, preserve the inline SVG/accessibility structure, and run the delivery visual checklist. Never introduce inline literal colors that break dark/light parity.
626
+
627
+ ## Node icons
628
+
629
+ For domain-specific diagrams, set an optional `icon` on architecture components,
630
+ workflow/dataflow nodes, sequence participants, or lifecycle states. Choose
631
+ `calendar`, `clock`, `person`, `briefcase`, `flag`, or `moon` for everyday concepts;
632
+ the complete catalog (including existing technical and lifecycle symbols) is
633
+ `common.schema.json#/$defs/nodeIcon`. Use `icon: "none"` to hide the corner symbol.
634
+ Omitting `icon` keeps the type-based default; lifecycle `start`, `active`, and
635
+ `neutral` states default to no symbol. These inline SVG symbols are
636
+ renderer-owned and export with the diagram; URLs and raw SVG are not accepted.
637
+
638
+ Icon selection changes only the corner symbol. The node's type still determines
639
+ color and semantic grouping; brand marks remain independent. For a holiday
640
+ workflow, pair `type: "backend", icon: "calendar"` with
641
+ `meta.legend.entries.backend.label: "假期"`, and use `icon: "briefcase"` plus
642
+ an appropriate legend label for make-up work. Keep the node label meaningful:
643
+ icons are decorative and are hidden from assistive technology.
644
+
645
+ See [holiday planning](../examples/holiday-planning.workflow.json) for a complete workflow example.