dsh-archify-projects 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/README.md +204 -2
  2. package/cordis.patch.yml +99 -0
  3. package/dist/client.js +2261 -0
  4. package/dist/client.js.map +1 -0
  5. package/docs/CONTAINER.md +197 -0
  6. package/docs/DESIGN.md +905 -0
  7. package/docs/HANDOVER.md +391 -0
  8. package/docs/PUBLISH.md +107 -0
  9. package/icon.svg +12 -0
  10. package/lib/host/archify-skill.js +116 -0
  11. package/lib/host/archify-skill.js.map +1 -0
  12. package/lib/host/config.js +95 -0
  13. package/lib/host/config.js.map +1 -0
  14. package/lib/host/context.js +28 -0
  15. package/lib/host/context.js.map +1 -0
  16. package/lib/host/git.js +185 -0
  17. package/lib/host/git.js.map +1 -0
  18. package/lib/host/http.js +184 -0
  19. package/lib/host/http.js.map +1 -0
  20. package/lib/host/index.js +90 -0
  21. package/lib/host/index.js.map +1 -0
  22. package/lib/host/policy.js +124 -0
  23. package/lib/host/policy.js.map +1 -0
  24. package/lib/host/routes.js +667 -0
  25. package/lib/host/routes.js.map +1 -0
  26. package/lib/host/runner.js +913 -0
  27. package/lib/host/runner.js.map +1 -0
  28. package/lib/host/store.js +370 -0
  29. package/lib/host/store.js.map +1 -0
  30. package/lib/host/workspace.js +65 -0
  31. package/lib/host/workspace.js.map +1 -0
  32. package/lib/shared/format.js +138 -0
  33. package/lib/shared/format.js.map +1 -0
  34. package/lib/shared/prompt.js +257 -0
  35. package/lib/shared/prompt.js.map +1 -0
  36. package/lib/shared/protocol.js +31 -0
  37. package/lib/shared/protocol.js.map +1 -0
  38. package/lib/shared/types.js +173 -0
  39. package/lib/shared/types.js.map +1 -0
  40. package/locale/en.json +6 -0
  41. package/locale/zh.json +6 -0
  42. package/package.json +98 -4
  43. package/skills/archify/LICENSE +22 -0
  44. package/skills/archify/SKILL.md +109 -0
  45. package/skills/archify/THIRD_PARTY_NOTICES.md +69 -0
  46. package/skills/archify/assets/JetBrainsMono-OFL.txt +93 -0
  47. package/skills/archify/assets/template.html +13709 -0
  48. package/skills/archify/bin/archify.mjs +6936 -0
  49. package/skills/archify/bin/delivery-update.mjs +91 -0
  50. package/skills/archify/bin/finalize.mjs +895 -0
  51. package/skills/archify/bin/open-artifact.mjs +146 -0
  52. package/skills/archify/bin/preview.mjs +969 -0
  53. package/skills/archify/bin/recover-output.mjs +41 -0
  54. package/skills/archify/bin/visual-check.mjs +2667 -0
  55. package/skills/archify/brand-marks/README.md +31 -0
  56. package/skills/archify/brand-marks/catalog.json +131 -0
  57. package/skills/archify/delta/architecture-delta.mjs +1313 -0
  58. package/skills/archify/examples/agent-run.lifecycle.json +55 -0
  59. package/skills/archify/examples/agent-tool-call.workflow.json +74 -0
  60. package/skills/archify/examples/async-job-roundtrip.sequence.json +56 -0
  61. package/skills/archify/examples/brand-aware-delivery.architecture.json +34 -0
  62. package/skills/archify/examples/cache-miss-request.sequence.json +77 -0
  63. package/skills/archify/examples/checkout-platform.base.architecture.json +32 -0
  64. package/skills/archify/examples/checkout-platform.head.architecture.json +32 -0
  65. package/skills/archify/examples/dataflow-product-analytics.html +13820 -0
  66. package/skills/archify/examples/deployment-release.lifecycle.json +48 -0
  67. package/skills/archify/examples/event-stream.dataflow.json +52 -0
  68. package/skills/archify/examples/holiday-planning.workflow.json +143 -0
  69. package/skills/archify/examples/incident-response.workflow.json +59 -0
  70. package/skills/archify/examples/lifecycle-agent-run.html +13765 -0
  71. package/skills/archify/examples/locales/de.json +425 -0
  72. package/skills/archify/examples/locales/es.json +440 -0
  73. package/skills/archify/examples/locales/fr.json +425 -0
  74. package/skills/archify/examples/locales/fr.partial.json +22 -0
  75. package/skills/archify/examples/locales/it.json +425 -0
  76. package/skills/archify/examples/locales/ja.json +425 -0
  77. package/skills/archify/examples/locales/ko.json +440 -0
  78. package/skills/archify/examples/locales/pt.json +425 -0
  79. package/skills/archify/examples/locales/ru.json +425 -0
  80. package/skills/archify/examples/product-analytics.dataflow.json +71 -0
  81. package/skills/archify/examples/production-deployment.architecture.json +51 -0
  82. package/skills/archify/examples/release-delivery.workflow.json +57 -0
  83. package/skills/archify/examples/sequence-cache-miss-request.html +13835 -0
  84. package/skills/archify/examples/web-app-rendered.html +13808 -0
  85. package/skills/archify/examples/web-app.architecture.json +41 -0
  86. package/skills/archify/examples/workflow-agent-tool-call-rendered.html +13826 -0
  87. package/skills/archify/migrations/workflow-v2.mjs +280 -0
  88. package/skills/archify/package.json +17 -0
  89. package/skills/archify/recipes/scenarios.mjs +430 -0
  90. package/skills/archify/references/architecture-layout-repair.md +18 -0
  91. package/skills/archify/references/authoring-contract.md +419 -0
  92. package/skills/archify/references/authoring-defaults.md +41 -0
  93. package/skills/archify/references/brand-marks.md +82 -0
  94. package/skills/archify/references/delivery-contract.md +588 -0
  95. package/skills/archify/references/repository-authoring.md +105 -0
  96. package/skills/archify/references/update-awareness.md +12 -0
  97. package/skills/archify/references/viewer-runtime.md +35 -0
  98. package/skills/archify/renderers/architecture/grid.mjs +62 -0
  99. package/skills/archify/renderers/architecture/labels.mjs +215 -0
  100. package/skills/archify/renderers/architecture/render-architecture.mjs +1001 -0
  101. package/skills/archify/renderers/architecture/routing.mjs +1157 -0
  102. package/skills/archify/renderers/dataflow/README.md +105 -0
  103. package/skills/archify/renderers/dataflow/render-dataflow.mjs +544 -0
  104. package/skills/archify/renderers/lifecycle/README.md +171 -0
  105. package/skills/archify/renderers/lifecycle/grid-routing.mjs +429 -0
  106. package/skills/archify/renderers/lifecycle/render-lifecycle.mjs +938 -0
  107. package/skills/archify/renderers/sequence/README.md +129 -0
  108. package/skills/archify/renderers/sequence/render-sequence.mjs +526 -0
  109. package/skills/archify/renderers/shared/atomic-output.mjs +1982 -0
  110. package/skills/archify/renderers/shared/brand-marks.mjs +670 -0
  111. package/skills/archify/renderers/shared/cli.mjs +451 -0
  112. package/skills/archify/renderers/shared/desktop-readability.mjs +132 -0
  113. package/skills/archify/renderers/shared/diagnostics.mjs +173 -0
  114. package/skills/archify/renderers/shared/engineering-profiles.mjs +157 -0
  115. package/skills/archify/renderers/shared/generated-brand-marks.mjs +2003 -0
  116. package/skills/archify/renderers/shared/generated-validators.mjs +134 -0
  117. package/skills/archify/renderers/shared/geometry.mjs +1941 -0
  118. package/skills/archify/renderers/shared/i18n.mjs +603 -0
  119. package/skills/archify/renderers/shared/layout-report.mjs +42 -0
  120. package/skills/archify/renderers/shared/legend.mjs +217 -0
  121. package/skills/archify/renderers/shared/output-path.mjs +440 -0
  122. package/skills/archify/renderers/shared/path-semantics.mjs +1017 -0
  123. package/skills/archify/renderers/shared/portable-path.mjs +408 -0
  124. package/skills/archify/renderers/shared/repository-evidence.mjs +352 -0
  125. package/skills/archify/renderers/shared/repository-location.mjs +59 -0
  126. package/skills/archify/renderers/shared/route-quality.mjs +614 -0
  127. package/skills/archify/renderers/shared/sidecar-path.mjs +38 -0
  128. package/skills/archify/renderers/shared/spatial-grid.mjs +66 -0
  129. package/skills/archify/renderers/shared/text-fit.mjs +105 -0
  130. package/skills/archify/renderers/shared/utils.mjs +254 -0
  131. package/skills/archify/renderers/shared/validator.mjs +86 -0
  132. package/skills/archify/renderers/workflow/README.md +301 -0
  133. package/skills/archify/renderers/workflow/render-workflow.mjs +37 -0
  134. package/skills/archify/renderers/workflow/workflow-compiler.mjs +4913 -0
  135. package/skills/archify/renderers/workflow/workflow-migration-geometry.mjs +144 -0
  136. package/skills/archify/schemas/README.md +256 -0
  137. package/skills/archify/schemas/architecture.schema.json +152 -0
  138. package/skills/archify/schemas/common.schema.json +181 -0
  139. package/skills/archify/schemas/dataflow.schema.json +254 -0
  140. package/skills/archify/schemas/lifecycle.schema.json +280 -0
  141. package/skills/archify/schemas/sequence.schema.json +234 -0
  142. package/skills/archify/schemas/workflow.schema.json +439 -0
  143. package/skills/archify/scripts/check-render-output.mjs +1388 -0
  144. package/skills/archify/scripts/check-update.mjs +1710 -0
  145. package/skills/archify/scripts/delivery-update-child.mjs +23 -0
  146. package/skills/archify/scripts/render-examples.mjs +26 -0
  147. package/skills/archify/scripts/update-contract.mjs +182 -0
  148. package/skills/archify/skill-release.json +10 -0
@@ -0,0 +1,301 @@
1
+ # Workflow Renderer
2
+
3
+ Render `diagram_type: "workflow"` JSON files into the standard Archify HTML
4
+ template.
5
+
6
+ ```bash
7
+ node archify/renderers/workflow/render-workflow.mjs input.workflow.json output.html
8
+ ```
9
+
10
+ The renderer validates input against `archify/schemas/workflow.schema.json`
11
+ with the bundled standalone validator. No dependency installation is required.
12
+
13
+ If `output.html` is omitted, the renderer uses the required `meta.output` value
14
+ from the JSON file.
15
+
16
+ After rendering, run the artifact checker:
17
+
18
+ ```bash
19
+ node archify/scripts/check-render-output.mjs output.html
20
+ ```
21
+
22
+ It catches final-SVG issues that are easiest to see in a browser: non-finite
23
+ SVG values, accidental two-point diagonal arrows, and arrows crossing the
24
+ legend.
25
+
26
+ ## Input
27
+
28
+ Workflow JSON files must set:
29
+
30
+ ```json
31
+ {
32
+ "schema_version": 2,
33
+ "diagram_type": "workflow",
34
+ "meta": {
35
+ "title": "Agent Tool Call Workflow",
36
+ "output": "agent-tool-call.html"
37
+ },
38
+ "lanes": [],
39
+ "phases": [],
40
+ "groups": [],
41
+ "mainPath": [],
42
+ "nodes": [],
43
+ "edges": [],
44
+ "cards": []
45
+ }
46
+ ```
47
+
48
+ Use `schema_version: 2` for new workflows. Its readable layout compiler treats
49
+ every `col` as a logical rank in `0..5` and derives geometry from the measured
50
+ document. `schema_version: 1` remains the fixed legacy contract for existing
51
+ sources; valid v1 output is preserved byte-for-byte and never silently
52
+ reinterpreted as v2.
53
+
54
+ Omit `meta.viewBox` for the common v2 case so the compiler can use intrinsic
55
+ measured bounds. In v1, the omitted width remains fixed at 720 and height is
56
+ derived from lane count. A complete worked example lives at
57
+ `archify/examples/agent-tool-call.workflow.json`; its `schema_version` selects
58
+ the applicable contract.
59
+
60
+ The schema lives at:
61
+
62
+ ```text
63
+ archify/schemas/workflow.schema.json
64
+ ```
65
+
66
+ ## Migration and layout receipt
67
+
68
+ Migrate an existing v1 source into a separate v2 file:
69
+
70
+ ```bash
71
+ node archify/bin/archify.mjs migrate workflow old.json new.json --to-schema 2 --json
72
+ ```
73
+
74
+ Running the command again with its schema-v2 output as the new source is an
75
+ idempotent verification pass: the destination bytes and geometry stay unchanged.
76
+
77
+ If a legacy v1 source is blocked solely because `meta.output` is missing or no
78
+ longer portable, supply its replacement for the separate v2 destination:
79
+
80
+ ```bash
81
+ node archify/bin/archify.mjs migrate workflow old.json new.json --to-schema 2 --output reports/workflow.html --json
82
+ ```
83
+
84
+ `--output` must itself be a portable POSIX-relative `.html` path. It updates
85
+ only the verified destination candidate; the source bytes remain unchanged and
86
+ all non-output schema and compiler diagnostics still block migration.
87
+
88
+ The command never overwrites the source by default. It maps absolute
89
+ `via[*][0]`, `labelAt[0]`, and `channelX` values from legacy to solved rank
90
+ space, preserves y coordinates unless a reported vertical constraint needs
91
+ author input, expands an explicit viewBox only for an unambiguous containment
92
+ repair, and writes the destination only after v2 compilation and artifact
93
+ checks pass. Ambiguous explicit pins fail without producing the destination.
94
+
95
+ Inspect the stable author-facing v2 plan with:
96
+
97
+ ```bash
98
+ node archify/bin/archify.mjs validate workflow input.workflow.json --layout-json
99
+ ```
100
+
101
+ The receipt reports the selected contract, measured `viewBox` and
102
+ `requiredViewBox`, solved columns, nodes, edges, labels, and causal diagnostics.
103
+ It deliberately omits solver iterations and candidate scores.
104
+
105
+ ## Legend
106
+
107
+ The default legend derives component kinds from `nodes[].type`. Supported
108
+ `meta.legend.entries` keys, in stable order, are `frontend`, `backend`,
109
+ `security`, `messagebus`, `database`, `cloud`, and `external`. Labels and
110
+ visibility may be overridden through the shared legend contract; only kinds
111
+ backed by rendered nodes receive Semantic Legend controls.
112
+
113
+ ## Layout contracts
114
+
115
+ ### Fixed v1
116
+
117
+ | Constant | Value |
118
+ |----------|-------|
119
+ | viewBox | default `[720, auto]` — auto height = 52 + lanes×104 + (lanes−1)×20 + 124 |
120
+ | Lane frame | x 40, width 640, height 104, gap 20; first lane top at y 52 |
121
+ | Lane title strip | top 30px of each lane; node boxes must stay below it |
122
+ | Column centers (`col` 0–5) | x = 88, 220, 300, 430, 500, 625 |
123
+ | Phase headers | Optional `phases[]` render above the first lane, spanning `fromCol..toCol` |
124
+ | Lane groups | Optional `groups[]` frame parallel work or branch work inside one lane |
125
+ | Exception lanes | Set `lane.variant: "exception"` for retry, denial, fallback, or failure paths |
126
+ | Main path lint | Optional `mainPath[]` checks that happy-path steps have matching edges and do not move backward |
127
+ | Default node | 92×52 (height 68 when `tag` is set) |
128
+ | Node spacing | ≥8px between nodes in the same lane |
129
+ | Edge length | straight segments must span ≥28px |
130
+ | Legend row | y = lane bottom + 44; viewBox height must be ≥ legend y + 18 |
131
+
132
+ Column-center gaps are 132 / 80 / 130 / 70 / 125 px: columns 1↔2 (80px) and
133
+ 3↔4 (70px) cannot both hold default-width 92px nodes in the same lane. Such an
134
+ invalid v1 source receives one causal `workflow/column-capacity` diagnostic and
135
+ a verified migration-to-v2 repair; v1 never falls through to adaptive layout.
136
+
137
+ ### Readable v2
138
+
139
+ | Invariant | Contract |
140
+ |----------|----------|
141
+ | Logical columns | `col` is an integer in `0..5`; pixel centers are measured output |
142
+ | Adjacent-rank baseline | 120px center distance before document-specific constraints |
143
+ | Same-lane node clearance | ≥8px when vertical node intervals overlap |
144
+ | Facing direct edge | clear gap ≥`max(28px, measured label mask width + 8px)` |
145
+ | Automatic route rhythm | direct segment ≥28px; endpoint stub ≥8px; interior turn segment ≥16px |
146
+ | Implicit viewBox | intrinsic content bounds plus contract padding |
147
+ | Explicit viewBox | containment capacity; too-small input reports exact `requiredViewBox` and contributors |
148
+ | Lane measurement | A same-column vertical stack (two or more distinct `yOffset` values) opts an implicit, unpinned workflow into per-lane measurement. Explicit `meta.viewBox`, `via`, `labelAt`, `channelX`, or `channelY`, and workflows without a stack retain shared-height v2 geometry for compatibility. |
149
+
150
+ The compiler applies constraints only to actual related or overlapping
151
+ same-lane nodes, so a wide node in an unrelated lane does not expand every
152
+ rank. Legacy centers are a soft preference after correctness constraints, not
153
+ a geometry promise. Phase and group frames derive from the solved rank bands.
154
+ Automatic routes are normalized once and the same final scene drives
155
+ validation and SVG serialization. Long automatic labels compare direct-gutter
156
+ growth with a legal channel instead of widening every downstream rank. Measured
157
+ multi-row legends participate in intrinsic height and explicit viewBox
158
+ capacity.
159
+
160
+ The Issue #250 shape already has a v2 representation without an authored lane
161
+ size. Keep the three stages in one grouped lane, omit `meta.viewBox`, and center
162
+ their offsets around zero:
163
+
164
+ ```json
165
+ {
166
+ "schema_version": 2,
167
+ "diagram_type": "workflow",
168
+ "meta": { "title": "stack", "output": "stack.html" },
169
+ "lanes": [{ "id": "cage", "label": "one cage" }],
170
+ "groups": [{ "id": "g", "label": "cage", "lane": "cage", "fromCol": 1, "toCol": 3 }],
171
+ "nodes": [
172
+ { "id": "a", "lane": "cage", "col": 2, "type": "security", "label": "stageA", "yOffset": -90 },
173
+ { "id": "b", "lane": "cage", "col": 2, "type": "security", "label": "stageB", "yOffset": 0 },
174
+ { "id": "c", "lane": "cage", "col": 2, "type": "security", "label": "stageC", "yOffset": 90 }
175
+ ],
176
+ "edges": [
177
+ { "from": "a", "to": "b", "fromSide": "bottom", "toSide": "top" },
178
+ { "from": "b", "to": "c", "fromSide": "bottom", "toSide": "top" }
179
+ ]
180
+ }
181
+ ```
182
+
183
+ An implicit readable-v2 vertical stack whose measured lane height exceeds the
184
+ 104px baseline opts into the desktop Viewer's height budget. This decision
185
+ comes from compiled geometry, not an authored sizing field. The Viewer changes only
186
+ the outer reader width so the complete lane remains on screen; canonical SVG
187
+ geometry and explicit `meta.viewBox` workflows retain their authored contracts.
188
+ When necessary, the Viewer may scale below the intrinsic 1:1 width only as far
189
+ as the 6px projected node-text floor. If the complete workflow still cannot fit
190
+ at that readable scale, `visual-check` reports the remaining viewport overflow
191
+ instead of clipping or introducing an internal scroller.
192
+
193
+ Authored `via`, `labelAt`, `channelX`, and `channelY` are absolute hard pins in
194
+ v2; an infeasible pin returns `workflow/explicit-pin-conflict` rather than being
195
+ silently moved. `fromSide` and `toSide` remain direction constraints. A route
196
+ preset restricts the automatic candidate family but is not itself an absolute
197
+ coordinate pin. When either endpoint side is omitted, the v2 compiler chooses
198
+ a feasible side; an authored side restricts that endpoint to the named port.
199
+
200
+ ## Design Rules
201
+
202
+ - Use lanes for ownership or runtime boundaries.
203
+ - Use phase headers for high-level story beats such as Intake, Plan, Execute, and Report.
204
+ - Use groups for parallel checks, branch handling, or bounded work within a lane; every group must contain at least one node.
205
+ - For sequential stages stacked inside one container, use one v2 lane and one group, keep the stages in one column, and omit `meta.viewBox`. `yOffset` is relative to the center of the lane's content area, so center a three-stage stack with `-90 / 0 / 90` rather than `0 / 90 / 180`. With compiler-owned routes and canvas, the compiler expands only that lane.
206
+ - Use `lane.variant: "exception"` for human wait, denial, retry, fallback, and failure lanes instead of mixing those paths into the happy path.
207
+ - Set `mainPath` when the diagram has a clear happy path; the renderer validates that consecutive ids have matching edges and move left-to-right.
208
+ - Place nodes with lane IDs and `col` indexes in `0..5`, not raw SVG coordinates.
209
+ - Preserve semantic edge labels. Readable v2 allocates measured label clearance;
210
+ when a label does not fit, repair the reported capacity or route constraint
211
+ instead of deleting meaning.
212
+ - Use labels for decisions, approvals, protocols, async traces, return paths,
213
+ and any other relationship meaning not fully implied by its endpoints.
214
+ - Prefer route presets — `drop` (bend between lanes; `bias` 0–1 picks where),
215
+ `outside-right`, `return-left`, `bottom-channel`, and `up-channel` — before
216
+ using raw `via` points. `straight` and the default `auto` cover the rest.
217
+ - Keep workflow examples compact enough to render well in narrow chat/browser
218
+ previews.
219
+
220
+ ### Optional semantic checks
221
+
222
+ Layout validation cannot infer domain truth from labels or cards. When source
223
+ evidence establishes roots, terminals, mandatory direct relationships, or
224
+ mandatory directed reachability, encode those facts in `semanticChecks`:
225
+
226
+ ```json
227
+ "semanticChecks": {
228
+ "allowedRoots": ["request", "resource_catalog"],
229
+ "allowedTerminals": ["reply", "audit_log"],
230
+ "requiredEdges": [
231
+ { "from": "dispatch", "to": "dispatch_ledger" }
232
+ ],
233
+ "requiredPaths": [
234
+ { "from": "event_ledger", "to": "runtime_host" }
235
+ ]
236
+ }
237
+ ```
238
+
239
+ When `allowedRoots` or `allowedTerminals` is present, it is the complete allow
240
+ list for zero-incoming or zero-outgoing nodes respectively. `requiredEdges`
241
+ requires one exact authored direction; `requiredPaths` permits intermediate
242
+ nodes but follows authored edge direction. These checks run before layout, do
243
+ not alter SVG or receipt bytes, and must not be weakened merely to resolve a
244
+ route or composition diagnostic. Omit fields whose domain facts are unknown.
245
+
246
+ Schema violations exit non-zero with path-prefixed messages annotated with the
247
+ element's id or label. The renderer additionally fails when it can detect
248
+ layout problems, including node overlap, nodes outside their lanes, invalid
249
+ phase/group column ranges, empty groups, broken `mainPath` steps, unknown edge
250
+ targets, labels colliding with nodes or other labels, labels wider than their
251
+ node, legends outside the viewBox, or straight arrows that are too short to
252
+ read cleanly. The shared Clean Flow Gate also rejects edges crossing unrelated
253
+ nodes with 2px clearance; lanes, phases, and groups remain intentional
254
+ pass-through containers. Text width is estimated CJK-aware: fullwidth glyphs
255
+ count as two units.
256
+
257
+ Diagnostics are causal: a rank-capacity failure suppresses derivative short
258
+ edge, endpoint-direction, and label-overlap findings. Every
259
+ `supportedFixes[]` entry is verified by replanning the proposed edit, and a
260
+ diagnostic never proposes removing a semantic label when label presence does
261
+ not cause the failed invariant.
262
+
263
+ Set `meta.quality_profile` to `showcase` for polished delivery. Unrelated proper
264
+ X crossings then fail with `composition/proper-crossing`; default `standard`
265
+ keeps them as artifact-receipt warnings. Collinear lane corridors are outside
266
+ the proper-X rule, but a separate gate warns in `standard` and fails in
267
+ `showcase` when unrelated edges overlap for at least 8px. V1 keeps its authored
268
+ shared-endpoint contract. V2 also checks shared endpoints, including explicitly
269
+ controlled routes: long or mixed-style trunks, counterflow, proper interior X
270
+ crossings and overlapping independent arrowheads are not exempt. Pins are
271
+ preserved, not silently repaired; unresolved v2 corridor/arrowhead collisions
272
+ warn in `standard` and fail in `showcase`.
273
+
274
+ V2 permits a same-direction shared terminal stub of at most 24 SVG units only
275
+ when both relationships share the actual source or target port, effective
276
+ variant, stroke width and role. A nonterminal overlap is never such a stub;
277
+ forward-collinear waypoints do not split a long trunk into permitted pieces.
278
+ Compatible short merges may share their terminal arrowhead. Automatic routes
279
+ consider separate ports, reserve absolute routes at contested nodes, and prefer
280
+ clear paths over shorter ambiguous ones. Crowded automatic corridors can use a
281
+ bounded local adjustment without moving nodes or changing explicit coordinates.
282
+
283
+ The SVG carries `data-layout-contract="readable-v2"` and each edge's role so
284
+ artifact checks apply the same classification to actual visible path geometry,
285
+ not stale composition-point metadata. These internal output attributes do not
286
+ add authoring schema fields. Other diagram types retain their existing rules.
287
+ V2 proper-crossing diagnostics retain the relationship IDs, intersection point,
288
+ and supported fixes in both compiler/layout-JSON receipts and final HTML checks;
289
+ `standard` reports warnings while `showcase` rejects the crossing. Both analyses
290
+ merge forward-collinear waypoints without rewriting authored paths; real bends
291
+ and reversals remain endpoint touches rather than being merged into an X.
292
+
293
+ The older per-edge `data-composition-routing="workflow-v2-auto"` marker remains
294
+ for compatibility with first-round exported HTML that has no root layout
295
+ contract and with older artifact checkers. Marker-only artifacts retain their
296
+ narrower automatic-pair crossing/counterflow policy; the root `readable-v2`
297
+ contract is authoritative when present and also checks explicit routes. Do not
298
+ remove the marker-only path as dead code without retiring that export format.
299
+ Showcase also
300
+ rejects any route segment below 8px and any interior turn segment below 16px;
301
+ ordinary 8–15px endpoint stubs remain valid for fixed lane gaps.
@@ -0,0 +1,37 @@
1
+ import path from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { loadDiagramWithBrandMarks, writeDiagram } from '../shared/cli.mjs';
4
+ import { throwDiagnosticError } from '../shared/diagnostics.mjs';
5
+ import { compileWorkflow } from './workflow-compiler.mjs';
6
+
7
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
8
+ const { diagram: workflow, template, outPath, sourceEvidence } = await loadDiagramWithBrandMarks({
9
+ rendererDir: __dirname,
10
+ diagramType: 'workflow',
11
+ defaultExample: 'agent-tool-call.workflow.json'
12
+ });
13
+
14
+ const compiled = compileWorkflow({
15
+ workflow,
16
+ qualityProfile: process.env.ARCHIFY_QUALITY_PROFILE || workflow.meta?.quality_profile,
17
+ sourceEvidence,
18
+ });
19
+
20
+ const layoutJson = process.argv.includes('--layout-json');
21
+
22
+ if (layoutJson) {
23
+ process.stdout.write(`${JSON.stringify(compiled.receipt, null, 2)}\n`);
24
+ if (!compiled.ok) process.exitCode = 1;
25
+ } else if (!compiled.ok) {
26
+ throwDiagnosticError(compiled.error || 'Workflow compilation failed.', compiled.diagnostics);
27
+ } else {
28
+ writeDiagram({
29
+ outPath,
30
+ template,
31
+ diagramType: 'workflow',
32
+ meta: workflow.meta,
33
+ svg: compiled.svg,
34
+ cards: workflow.cards,
35
+ sourceEvidence,
36
+ });
37
+ }