@afokapu/atdd-bun 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/PLANNER_PORT.md +1 -1
  2. package/README.md +56 -1
  3. package/conventions/planner.docs/planner.docs.journey-view-current.convention.yaml +53 -0
  4. package/detectors/planner_docs_capability/atdd.implementation.yaml +2 -0
  5. package/detectors/planner_docs_capability/fixtures/clean/docs/purpose/journeys/index.adoc +170 -0
  6. package/detectors/planner_docs_capability/fixtures/clean/docs/purpose/journeys/svg/journey-buy.svg +61 -0
  7. package/detectors/planner_docs_capability/fixtures/clean/docs/purpose/journeys/svg/path-buy-nominal.svg +81 -0
  8. package/detectors/planner_docs_capability/fixtures/clean/docs/purpose/journeys/svg/train-orders-archive-order.svg +13 -0
  9. package/detectors/planner_docs_capability/fixtures/clean/docs/purpose/journeys/svg/train-orders-place-order.svg +31 -0
  10. package/detectors/planner_docs_capability/fixtures/clean/docs/purpose/journeys/svg/train-orders-reject-empty-cart.svg +22 -0
  11. package/detectors/planner_docs_capability/fixtures/clean/docs/purpose/journeys/svg/train-orders-retry-payment.svg +22 -0
  12. package/detectors/planner_docs_capability/fixtures/clean/docs/purpose/journeys/svg/train-orders-ship-order.svg +35 -0
  13. package/detectors/planner_docs_capability/fixtures/clean/docs/purpose/journeys/svg/train-orders-take-payment.svg +27 -0
  14. package/detectors/planner_docs_capability/fixtures/clean/plan/_journeys/buy.yaml +24 -0
  15. package/detectors/planner_docs_capability/fixtures/clean/plan/_themes.yaml +3 -0
  16. package/detectors/planner_docs_capability/fixtures/clean/plan/_trains/_interlockings/checkout.yaml +43 -0
  17. package/detectors/planner_docs_capability/fixtures/clean/plan/_trains/_interlockings/fulfilment.yaml +33 -0
  18. package/detectors/planner_docs_capability/fixtures/clean/plan/_trains/_interlockings/payment.yaml +43 -0
  19. package/detectors/planner_docs_capability/fixtures/clean/plan/_trains/_interlockings/returns.yaml +33 -0
  20. package/detectors/planner_docs_capability/fixtures/clean/plan/_trains/orders/archive-order.yaml +11 -0
  21. package/detectors/planner_docs_capability/fixtures/clean/plan/_trains/orders/place-order.yaml +21 -0
  22. package/detectors/planner_docs_capability/fixtures/clean/plan/_trains/orders/reject-empty-cart.yaml +16 -0
  23. package/detectors/planner_docs_capability/fixtures/clean/plan/_trains/orders/retry-payment.yaml +16 -0
  24. package/detectors/planner_docs_capability/fixtures/clean/plan/_trains/orders/ship-order.yaml +21 -0
  25. package/detectors/planner_docs_capability/fixtures/clean/plan/_trains/orders/take-payment.yaml +21 -0
  26. package/detectors/planner_docs_capability/fixtures/clean/plan/_trains/orders/unrouted-refund.yaml +11 -0
  27. package/detectors/planner_docs_capability/fixtures/dirty_journey_view/docs/index.adoc +3 -0
  28. package/detectors/planner_docs_capability/fixtures/dirty_journey_view/plan/_trains/_interlockings/fulfilment.yaml +33 -0
  29. package/detectors/planner_static_validators/atdd.implementation.yaml +2 -0
  30. package/detectors/planner_static_validators/fixtures/dirty/plan/_trains/_interlockings/uncomposed.yaml +4 -0
  31. package/integrity.json +39 -10
  32. package/package.json +3 -2
  33. package/planner-nodes/ENFORCEMENT_SCOPE.yaml +7 -1
  34. package/planner-nodes/nodes/planner.journey.interlocking-composed.convention.yaml +43 -0
  35. package/relationships.yaml +4514 -0
  36. package/src/cli.ts +9 -0
  37. package/src/docs-capability.ts +10 -1
  38. package/src/index.ts +2 -0
  39. package/src/journey-docs.ts +355 -0
  40. package/src/planner-validators.ts +29 -0
package/PLANNER_PORT.md CHANGED
@@ -5,7 +5,7 @@ to port ATDD's full planner yet.
5
5
 
6
6
  ## Portable planner kernel
7
7
 
8
- The package ships 195 canonical convention nodes in `planner-nodes/` and
8
+ The package ships 196 canonical convention nodes in `planner-nodes/` and
9
9
  21 schemas in `planner-schemas/`. It does not ship Python validator files:
10
10
  they are executable Python/pytest code, not portable package assets. Port each
11
11
  selected validator into Bun/TypeScript before enabling it in a `planner` profile.
package/README.md CHANGED
@@ -98,7 +98,7 @@ name.
98
98
  |---|---|
99
99
  | `traceability` | plan acceptance, Bun test, and implementation closure |
100
100
  | `planner` | plan parsing/graph integrity plus the explicitly scoped planner rules |
101
- | `docs` | the optional documentation capability and its declared artifacts |
101
+ | `docs` | the optional documentation capability and its declared artifacts, including the generated journey view |
102
102
  | `coder`, `tester`, `security`, `architecture`, `metrics`, `runtime` | Bun source and test conventions for that concern |
103
103
  | `interlocking` | declared train/interlocking binding, infrastructure, and coverage |
104
104
  | `htmx` | htmx-specific source and test conventions |
@@ -146,6 +146,50 @@ every exported component has a consumer. Defining a custom property
146
146
  (`--accent: #0ea5e9`) is defining a token and is allowed anywhere. A repository
147
147
  without a design directory is not judged by these rules.
148
148
 
149
+ ### Journey documentation
150
+
151
+ A plan describes behaviour on three levels. A journey (`plan/_journeys/`) enters
152
+ at one interlocking and continues, through an artifact the selected train
153
+ produces, into the next one. An interlocking chooses one route by its guards.
154
+ A route runs one train, a linear sequence of handovers. Generate the view of all
155
+ three from `plan/`:
156
+
157
+ ```sh
158
+ bun run atdd-bun docs journeys # writes docs/purpose/journeys/
159
+ bun run atdd-bun docs journeys --check # fails when the committed view differs from plan/
160
+ ```
161
+
162
+ It writes `docs/purpose/journeys/index.adoc` and one SVG for each of:
163
+
164
+ - **journey map:** the entry action, each interlocking, the routes it chooses
165
+ and their guards, the trains they run, continuations (labelled with the
166
+ artifact that carries control) and terminal outcomes;
167
+ - **nominal path, end to end:** the journey's trains across all its
168
+ interlockings, joined into one sequence diagram;
169
+ - **train:** each routed train as its own sequence diagram, under its
170
+ interlocking's route table.
171
+
172
+ The page also tables every path with how it ends, and every **gap**: unreached
173
+ interlockings, routes with no continuation or outcome, unrouted trains,
174
+ unresolved guards. Participants are coloured by what they are (wagon, person,
175
+ outside system) and arrows by the boundary they cross. Diagrams are inlined
176
+ (`opts=inline`) and coloured with `var(--atdd-*, fallback)`, so a doc site can
177
+ theme them by defining `--atdd-ink`, `--atdd-paper`, `--atdd-wagon`,
178
+ `--atdd-person`, `--atdd-system`, `--atdd-nominal`, `--atdd-alternate`,
179
+ `--atdd-error`, `--atdd-exception`, and the like. The output carries no
180
+ timestamp and no package version, so it changes only when the plan does.
181
+
182
+ The planner requires the journey level itself: `planner.journey.interlocking-composed`
183
+ fails when a plan declares interlockings and no journey, or when an interlocking
184
+ is neither a journey's entrypoint nor reached by one of its continuations.
185
+ `planner.journey.continuation-closure` then checks each declared journey closes.
186
+
187
+ **Required.** In a repository with `docs/` whose plan has journeys or
188
+ interlockings, the `docs` profile's `planner.docs.journey-view-current` rule
189
+ fails when any generated file is missing, stale, hand-edited, or extra. The
190
+ generator refuses to overwrite a hand-written `index.adoc` unless you pass
191
+ `--force`; use `--out <dir>` to preview elsewhere.
192
+
149
193
  ### Theme and contract registry
150
194
 
151
195
  Theme vocabulary belongs to the repository, not the package. When a plan uses
@@ -391,6 +435,17 @@ It creates no tag, makes no network request, and does not publish anything.
391
435
  The separate optional release workflow is where a repository may create a tag or
392
436
  publish using its own credentials and registry configuration.
393
437
 
438
+ ## Convention relationships
439
+
440
+ `relationships.yaml` relates every convention the package ships (`planner-nodes/`
441
+ and `conventions/`) to at least one other, as
442
+ `planner.relationship.no-orphan-nodes` requires. Edges that touch a shipped
443
+ convention are imported from the upstream ATDD graphs with their `origin`; the
444
+ package adds its own for the conventions it introduces. A test fails when any
445
+ shipped convention has no edge, when the node list drifts from the shipped
446
+ conventions, or when an edge breaks `relationship.schema.json`, so a new
447
+ convention cannot land without its relationships.
448
+
394
449
  ## Verification of this package
395
450
 
396
451
  `bun test` runs the package’s real-Git fixtures and detector clean/dirty corpora.
@@ -0,0 +1,53 @@
1
+ schema_version: 1.1.0
2
+ rule_id: planner.docs.journey-view-current
3
+ kind: rule
4
+ status: active
5
+ name: The journey documentation is generated from plan/ and matches it
6
+ statement: >-
7
+ When a repository documents itself (`docs/` exists) and its plan declares journeys or interlockings,
8
+ `docs/purpose/journeys/` MUST contain exactly what `atdd-bun docs journeys` generates from `plan/`:
9
+ `index.adoc` and one SVG per journey map, per journey's nominal path, and per routed train. A missing,
10
+ stale, hand-edited, or extra file is a violation.
11
+ terms:
12
+ - term_id: journey_view
13
+ text: >-
14
+ the generated page, top down: each journey as a map (entry action, interlockings, the routes they
15
+ choose, the trains they run, continuations and terminal outcomes); the journey's nominal path walked
16
+ end to end as one sequence across its interlockings; every path as a table; each interlocking's
17
+ routes with their guards; each train as a sequence diagram; and a table of what the plan leaves
18
+ unconnected.
19
+ - term_id: generated
20
+ text: >-
21
+ byte-for-byte what the installed package renders from the current `plan/`. The output carries no
22
+ timestamp and no package version, so it changes only when the plan (or the renderer) does.
23
+ content:
24
+ summary: >-
25
+ A journey page drawn by hand drifts from the plan it describes the moment either changes. Generating
26
+ it, and failing when the committed copy differs, keeps the documented journeys the planned journeys,
27
+ and keeps the plan's gaps (unreached interlockings, open routes, unrouted trains) visible.
28
+ normative_text: |
29
+ The view renders planned behaviour, not acceptance evidence. It is generated so that reviewing a
30
+ decomposition does not require reading interlocking YAML: who hands what to whom, which guard
31
+ selects which route, and where each path ends.
32
+
33
+ The gaps table is part of the contract. A plan with interlockings but no journey still gets a page;
34
+ it shows every interlocking as unreached, which is the truthful state of the decomposition.
35
+ fix_hint: |
36
+ Regenerate and commit:
37
+
38
+ bun run atdd-bun docs journeys
39
+
40
+ If `docs/purpose/journeys/index.adoc` is a hand-written page, move its content elsewhere (the
41
+ generator refuses to overwrite it without --force). Change the plan, never the generated files.
42
+ exceptions:
43
+ - A repository with no `docs/` directory is not in scope.
44
+ - A plan with no journey and no interlocking is not in scope.
45
+ metadata:
46
+ aliases:
47
+ - DOCS-JOURNEY-VIEW-001
48
+ severity: 3
49
+ disposition: strict
50
+ introduced_in: 0.4.0
51
+ implementation:
52
+ type: validator
53
+ ref: docs_capability
@@ -21,6 +21,7 @@ realizes_convention:
21
21
  - planner.docs.artifact-path-shape
22
22
  - planner.docs.undeclared-change
23
23
  - planner.docs.reference-integrity
24
+ - planner.docs.journey-view-current
24
25
 
25
26
  # The filesystem report emits the six corpus-observable rules. The Bun capability
26
27
  # API additionally evaluates declaration-only rules and reference integrity.
@@ -31,6 +32,7 @@ emits_rule_ids:
31
32
  - planner.docs.graph-target-resolves # disposition: advisory (edge names an undeclared id)
32
33
  - planner.docs.area-index-required # disposition: advisory (area exists, no index.adoc)
33
34
  - planner.docs.adr-registry-derived # disposition: advisory (registry drifted from :decides:)
35
+ - planner.docs.journey-view-current # disposition: strict (generated journey view differs from plan/)
34
36
 
35
37
  # TWO SURFACES, ONE DETECTOR.
36
38
  #
@@ -0,0 +1,170 @@
1
+ = Journeys
2
+ :doc-id: purpose.journeys
3
+ :status: generated
4
+ :toc: left
5
+ :toclevels: 2
6
+ :sectanchors:
7
+
8
+ // Generated by @afokapu/atdd-bun from plan/. Do not edit; run `atdd-bun docs journeys`.
9
+
10
+ [.headline]
11
+ The journeys this plan declares, the interlockings they pass through, and the trains those run, drawn from `plan/`. These are planned behaviour, not acceptance evidence.
12
+
13
+ == Coverage
14
+
15
+ [cols="1,1,1,1,1",options="header"]
16
+ |===
17
+ | Journeys | Interlockings reached | Routes | Trains | Gaps
18
+
19
+ | 1
20
+ | 3 of 4
21
+ | 6
22
+ | 7
23
+ | 2
24
+ |===
25
+
26
+ == Gaps
27
+
28
+ What the plan leaves unconnected. Each row is a decision still to be made in `plan/`.
29
+
30
+ [cols="1,2,3",options="header"]
31
+ |===
32
+ | Gap | Subject | Detail
33
+
34
+ | unreached interlocking
35
+ | `+interlocking:returns+`
36
+ | no journey enters or continues into it
37
+
38
+ | unrouted train
39
+ | `+train:orders:unrouted-refund+`
40
+ | no interlocking route selects it
41
+
42
+ |===
43
+
44
+ == Buy a product
45
+
46
+ `+journey:buy+` · checked · enters at `+interlocking:checkout+` · exposed through `+place-order+` · source `+plan/_journeys/buy.yaml+`
47
+
48
+ image::svg/journey-buy.svg[Buy a product journey map,opts=inline]
49
+
50
+ === Nominal path, end to end
51
+
52
+ Checkout decision → nominal ⇒ Payment decision → charged ⇒ Fulfilment decision → ship ⇒ *shipped*
53
+
54
+ image::svg/path-buy-nominal.svg[Buy a product nominal path,opts=inline]
55
+
56
+ === Every path
57
+
58
+ [cols="1,6,2",options="header"]
59
+ |===
60
+ | # | Interlocking → route, in order | Ends
61
+
62
+ | 1
63
+ | Checkout decision → nominal ⇒ Payment decision → charged ⇒ Fulfilment decision → ship
64
+ | shipped
65
+
66
+ | 2
67
+ | Checkout decision → nominal ⇒ Payment decision → declined
68
+ | declined
69
+
70
+ | 3
71
+ | Checkout decision → empty-cart
72
+ | rejected
73
+
74
+ |===
75
+
76
+ == Interlockings and their trains
77
+
78
+ === Checkout decision
79
+
80
+ `+interlocking:checkout+` · exposed through `+place-order+` · source `+plan/_trains/_interlockings/checkout.yaml+`
81
+
82
+ [cols="1,1,3,3",options="header"]
83
+ |===
84
+ | Priority | Category | Taken when | Runs
85
+
86
+ | 1
87
+ | nominal
88
+ | `+cart.items > 0+`
89
+ | `+train:orders:place-order+`
90
+
91
+ | 2
92
+ | error
93
+ | `+cart.items == 0+`
94
+ | `+train:orders:reject-empty-cart+`
95
+
96
+ |===
97
+
98
+ ==== nominal (nominal): Place an order
99
+
100
+ image::svg/train-orders-place-order.svg[Place an order,opts=inline]
101
+
102
+ ==== empty-cart (error): Reject an empty cart
103
+
104
+ image::svg/train-orders-reject-empty-cart.svg[Reject an empty cart,opts=inline]
105
+
106
+ === Fulfilment decision
107
+
108
+ `+interlocking:fulfilment+` · internal · source `+plan/_trains/_interlockings/fulfilment.yaml+`
109
+
110
+ [cols="1,1,3,3",options="header"]
111
+ |===
112
+ | Priority | Category | Taken when | Runs
113
+
114
+ | 1
115
+ | nominal
116
+ | `+order.paid+`
117
+ | `+train:orders:ship-order+`
118
+
119
+ |===
120
+
121
+ ==== ship (nominal): Ship the order
122
+
123
+ image::svg/train-orders-ship-order.svg[Ship the order,opts=inline]
124
+
125
+ === Payment decision
126
+
127
+ `+interlocking:payment+` · internal · source `+plan/_trains/_interlockings/payment.yaml+`
128
+
129
+ [cols="1,1,3,3",options="header"]
130
+ |===
131
+ | Priority | Category | Taken when | Runs
132
+
133
+ | 1
134
+ | nominal
135
+ | `+quote.accepted and card.valid+`
136
+ | `+train:orders:take-payment+`
137
+
138
+ | 2
139
+ | alternate
140
+ | `+card.declined+`
141
+ | `+train:orders:retry-payment+`
142
+
143
+ |===
144
+
145
+ ==== charged (nominal): Take payment
146
+
147
+ image::svg/train-orders-take-payment.svg[Take payment,opts=inline]
148
+
149
+ ==== declined (alternate): Retry a declined payment
150
+
151
+ image::svg/train-orders-retry-payment.svg[Retry a declined payment,opts=inline]
152
+
153
+ === Returns decision
154
+
155
+ `+interlocking:returns+` · internal · source `+plan/_trains/_interlockings/returns.yaml+`
156
+
157
+ [cols="1,1,3,3",options="header"]
158
+ |===
159
+ | Priority | Category | Taken when | Runs
160
+
161
+ | 1
162
+ | nominal
163
+ | `+order.cancelled+`
164
+ | `+train:orders:archive-order+`
165
+
166
+ |===
167
+
168
+ ==== archive (nominal): Archive a cancelled order
169
+
170
+ image::svg/train-orders-archive-order.svg[Archive a cancelled order,opts=inline]
@@ -0,0 +1,61 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" class="atdd-diagram" width="504" height="966" viewBox="0 0 504 966" role="img" aria-labelledby="t-map-buy d-map-buy">
2
+ <title id="t-map-buy">Buy a product — journey map</title><desc id="d-map-buy">Journey Buy a product: enters at interlocking:checkout; 2 continuation(s), 3 terminal outcome(s).</desc>
3
+ <defs><marker id="map-buy-arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M0,0 L10,5 L0,10 z" style="fill: var(--atdd-ink-3, #64748b)"/></marker></defs>
4
+ <path d="M 252 88 C 252 132, 252 116, 252 158" style="fill: none; stroke: var(--atdd-ink-3, #64748b); stroke-width: 1.6" marker-end="url(#map-buy-arrow)"/>
5
+ <path d="M 252 210 C 252 254, 138 238, 138 280" style="fill: none; stroke: var(--atdd-nominal, #15803d); stroke-width: 1.6" marker-end="url(#map-buy-arrow)"/>
6
+ <path d="M 138 332 C 138 376, 138 360, 138 402" style="fill: none; stroke: var(--atdd-accent, #0f766e); stroke-width: 1.6" marker-end="url(#map-buy-arrow)"/>
7
+ <path d="M 252 210 C 252 254, 366 238, 366 280" style="fill: none; stroke: var(--atdd-error, #b91c1c); stroke-width: 1.6" marker-end="url(#map-buy-arrow)"/>
8
+ <path d="M 366 332 C 366 376, 366 360, 366 402" style="fill: none; stroke: var(--atdd-terminal, #334155); stroke-width: 1.6" marker-end="url(#map-buy-arrow)"/>
9
+ <path d="M 138 454 C 138 498, 138 482, 138 524" style="fill: none; stroke: var(--atdd-nominal, #15803d); stroke-width: 1.6" marker-end="url(#map-buy-arrow)"/>
10
+ <path d="M 138 576 C 138 620, 138 604, 138 646" style="fill: none; stroke: var(--atdd-accent, #0f766e); stroke-width: 1.6" marker-end="url(#map-buy-arrow)"/>
11
+ <path d="M 138 454 C 138 498, 366 482, 366 524" style="fill: none; stroke: var(--atdd-alternate, #2563eb); stroke-width: 1.6" marker-end="url(#map-buy-arrow)"/>
12
+ <path d="M 366 576 C 366 620, 366 604, 366 646" style="fill: none; stroke: var(--atdd-terminal, #334155); stroke-width: 1.6" marker-end="url(#map-buy-arrow)"/>
13
+ <path d="M 138 698 C 138 742, 252 726, 252 768" style="fill: none; stroke: var(--atdd-nominal, #15803d); stroke-width: 1.6" marker-end="url(#map-buy-arrow)"/>
14
+ <path d="M 252 820 C 252 864, 252 848, 252 890" style="fill: none; stroke: var(--atdd-terminal, #334155); stroke-width: 1.6" marker-end="url(#map-buy-arrow)"/>
15
+ <rect x="152" y="38" width="200" height="50" rx="25" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-ink-2, #475569); stroke-width: 1.6"/>
16
+ <text x="252" y="61" text-anchor="middle" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; font-weight: 600; fill: var(--atdd-ink, #1f2937)">place-order</text>
17
+ <text x="252" y="80" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 8px; letter-spacing: .08em; fill: var(--atdd-ink-2, #475569)">STATION MASTER ACTION</text>
18
+ <rect x="152" y="160" width="200" height="50" rx="6" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-ink, #1f2937); stroke-width: 2.2"/>
19
+ <path d="M 166 185 l 7 -7 l 7 7 l -7 7 z" style="fill: var(--atdd-ink, #1f2937)"/>
20
+ <text x="262" y="183" text-anchor="middle" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; font-weight: 600; fill: var(--atdd-ink, #1f2937)">Checkout decision</text>
21
+ <text x="262" y="202" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 8px; letter-spacing: .08em; fill: var(--atdd-ink, #1f2937)">INTERLOCKING · 2 ROUTES</text>
22
+ <rect x="38" y="282" width="200" height="50" rx="6" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-nominal, #15803d); stroke-width: 1.6"/>
23
+ <text x="138" y="305" text-anchor="middle" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; font-weight: 600; fill: var(--atdd-ink, #1f2937)">Place an order</text>
24
+ <text x="138" y="324" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 8px; letter-spacing: .08em; fill: var(--atdd-nominal, #15803d)">NOMINAL · 3 STEPS</text>
25
+ <rect x="266" y="282" width="200" height="50" rx="6" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-error, #b91c1c); stroke-width: 1.6"/>
26
+ <text x="366" y="305" text-anchor="middle" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; font-weight: 600; fill: var(--atdd-ink, #1f2937)">Reject an empty cart</text>
27
+ <text x="366" y="324" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 8px; letter-spacing: .08em; fill: var(--atdd-error, #b91c1c)">ERROR · 2 STEPS</text>
28
+ <rect x="266" y="404" width="200" height="50" rx="25" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-terminal, #334155); stroke-width: 1.6"/>
29
+ <text x="366" y="427" text-anchor="middle" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; font-weight: 600; fill: var(--atdd-ink, #1f2937)">rejected</text>
30
+ <text x="366" y="446" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 8px; letter-spacing: .08em; fill: var(--atdd-terminal, #334155)">OUTCOME</text>
31
+ <rect x="38" y="404" width="200" height="50" rx="6" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-ink, #1f2937); stroke-width: 2.2"/>
32
+ <path d="M 52 429 l 7 -7 l 7 7 l -7 7 z" style="fill: var(--atdd-ink, #1f2937)"/>
33
+ <text x="148" y="427" text-anchor="middle" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; font-weight: 600; fill: var(--atdd-ink, #1f2937)">Payment decision</text>
34
+ <text x="148" y="446" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 8px; letter-spacing: .08em; fill: var(--atdd-ink, #1f2937)">INTERLOCKING · 2 ROUTES</text>
35
+ <rect x="38" y="526" width="200" height="50" rx="6" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-nominal, #15803d); stroke-width: 1.6"/>
36
+ <text x="138" y="549" text-anchor="middle" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; font-weight: 600; fill: var(--atdd-ink, #1f2937)">Take payment</text>
37
+ <text x="138" y="568" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 8px; letter-spacing: .08em; fill: var(--atdd-nominal, #15803d)">NOMINAL · 3 STEPS</text>
38
+ <rect x="266" y="526" width="200" height="50" rx="6" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-alternate, #2563eb); stroke-width: 1.6"/>
39
+ <text x="366" y="549" text-anchor="middle" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; font-weight: 600; fill: var(--atdd-ink, #1f2937)">Retry a declined payment</text>
40
+ <text x="366" y="568" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 8px; letter-spacing: .08em; fill: var(--atdd-alternate, #2563eb)">ALTERNATE · 2 STEPS</text>
41
+ <rect x="266" y="648" width="200" height="50" rx="25" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-terminal, #334155); stroke-width: 1.6"/>
42
+ <text x="366" y="671" text-anchor="middle" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; font-weight: 600; fill: var(--atdd-ink, #1f2937)">declined</text>
43
+ <text x="366" y="690" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 8px; letter-spacing: .08em; fill: var(--atdd-terminal, #334155)">OUTCOME</text>
44
+ <rect x="38" y="648" width="200" height="50" rx="6" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-ink, #1f2937); stroke-width: 2.2"/>
45
+ <path d="M 52 673 l 7 -7 l 7 7 l -7 7 z" style="fill: var(--atdd-ink, #1f2937)"/>
46
+ <text x="148" y="671" text-anchor="middle" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; font-weight: 600; fill: var(--atdd-ink, #1f2937)">Fulfilment decision</text>
47
+ <text x="148" y="690" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 8px; letter-spacing: .08em; fill: var(--atdd-ink, #1f2937)">INTERLOCKING · 1 ROUTE</text>
48
+ <rect x="152" y="770" width="200" height="50" rx="6" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-nominal, #15803d); stroke-width: 1.6"/>
49
+ <text x="252" y="793" text-anchor="middle" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; font-weight: 600; fill: var(--atdd-ink, #1f2937)">Ship the order</text>
50
+ <text x="252" y="812" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 8px; letter-spacing: .08em; fill: var(--atdd-nominal, #15803d)">NOMINAL · 3 STEPS</text>
51
+ <rect x="152" y="892" width="200" height="50" rx="25" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-terminal, #334155); stroke-width: 1.6"/>
52
+ <text x="252" y="915" text-anchor="middle" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; font-weight: 600; fill: var(--atdd-ink, #1f2937)">shipped</text>
53
+ <text x="252" y="934" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 8px; letter-spacing: .08em; fill: var(--atdd-terminal, #334155)">OUTCOME</text>
54
+ <text x="145" y="273" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9px; fill: var(--atdd-nominal, #15803d)">nominal: cart.items &gt; 0</text>
55
+ <text x="145" y="395" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9px; fill: var(--atdd-accent, #0f766e)">orders:quote</text>
56
+ <text x="373" y="273" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9px; fill: var(--atdd-error, #b91c1c)">empty-cart: cart.items == 0</text>
57
+ <text x="145" y="517" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9px; fill: var(--atdd-nominal, #15803d)">charged: quote.accepted and card.valid</text>
58
+ <text x="145" y="639" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9px; fill: var(--atdd-accent, #0f766e)">orders:paid</text>
59
+ <text x="373" y="517" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9px; fill: var(--atdd-alternate, #2563eb)">declined: card.declined</text>
60
+ <text x="259" y="761" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9px; fill: var(--atdd-nominal, #15803d)">ship: order.paid</text>
61
+ </svg>
@@ -0,0 +1,81 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" class="atdd-diagram" width="850" height="685" viewBox="0 0 850 685" role="img" aria-labelledby="t-walk-buy d-walk-buy">
2
+ <title id="t-walk-buy">Buy a product — nominal path</title><desc id="d-walk-buy">◇ Checkout decision → nominal (nominal) → Place an order 1.1. buyer to checkout, orders:cart: Submit the cart for checkout 1.2. checkout to pricing, orders:priced-cart: Price the cart with current promotions 1.3. pricing to checkout, orders:quote: Return the priced quote ◇ Payment decision → charged (nominal) → Take payment 2.1. checkout to payment-gateway, orders:charge: Request the charge from the payment gateway 2.2. payment-gateway to checkout, orders:charge-result: Report whether the charge succeeded 2.3. checkout to checkout, orders:paid: Record the order as paid ◇ Fulfilment decision → ship (nominal) → Ship the order 3.1. checkout to fulfilment, orders:paid: Hand the paid order to fulfilment 3.2. fulfilment to carrier, orders:shipment: Book the shipment with the carrier 3.3. fulfilment to buyer, orders:tracking: Send tracking to the buyer ■ outcome: shipped</desc>
3
+ <defs><marker id="walk-buy-wagon" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M0,0 L10,5 L0,10 z" style="fill: var(--atdd-ink-3, #64748b)"/></marker><marker id="walk-buy-person" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M0,0 L10,5 L0,10 z" style="fill: var(--atdd-person, #b45309)"/></marker><marker id="walk-buy-system" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M0,0 L10,5 L0,10 z" style="fill: var(--atdd-system, #7c3aed)"/></marker></defs>
4
+ <line x1="100" y1="54" x2="100" y2="679" style="stroke: var(--atdd-line, #cbd5e1); stroke-width: 1.4; stroke-dasharray: 3 4"/>
5
+ <rect x="41" y="10" width="118" height="44" rx="8" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-person, #b45309); stroke-width: 1.8"/>
6
+ <text x="100" y="32" text-anchor="middle" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 10.5px; font-weight: 600; fill: var(--atdd-ink, #1f2937)">buyer</text>
7
+ <text x="100" y="47" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 8px; letter-spacing: .1em; fill: var(--atdd-ink-3, #64748b)">PERSON</text>
8
+ <line x1="232" y1="54" x2="232" y2="679" style="stroke: var(--atdd-line, #cbd5e1); stroke-width: 1.4; stroke-dasharray: 3 4"/>
9
+ <rect x="173" y="10" width="118" height="44" rx="8" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-wagon, #2563eb); stroke-width: 1.8"/>
10
+ <text x="232" y="32" text-anchor="middle" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 10.5px; font-weight: 600; fill: var(--atdd-ink, #1f2937)">checkout</text>
11
+ <text x="232" y="47" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 8px; letter-spacing: .1em; fill: var(--atdd-ink-3, #64748b)">WAGON</text>
12
+ <line x1="364" y1="54" x2="364" y2="679" style="stroke: var(--atdd-line, #cbd5e1); stroke-width: 1.4; stroke-dasharray: 3 4"/>
13
+ <rect x="305" y="10" width="118" height="44" rx="8" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-wagon, #2563eb); stroke-width: 1.8"/>
14
+ <text x="364" y="32" text-anchor="middle" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 10.5px; font-weight: 600; fill: var(--atdd-ink, #1f2937)">pricing</text>
15
+ <text x="364" y="47" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 8px; letter-spacing: .1em; fill: var(--atdd-ink-3, #64748b)">WAGON</text>
16
+ <line x1="496" y1="54" x2="496" y2="679" style="stroke: var(--atdd-line, #cbd5e1); stroke-width: 1.4; stroke-dasharray: 3 4"/>
17
+ <rect x="437" y="10" width="118" height="44" rx="8" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-system, #7c3aed); stroke-width: 1.8"/>
18
+ <text x="496" y="32" text-anchor="middle" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 10.5px; font-weight: 600; fill: var(--atdd-ink, #1f2937)">payment-gateway</text>
19
+ <text x="496" y="47" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 8px; letter-spacing: .1em; fill: var(--atdd-ink-3, #64748b)">SYSTEM</text>
20
+ <line x1="628" y1="54" x2="628" y2="679" style="stroke: var(--atdd-line, #cbd5e1); stroke-width: 1.4; stroke-dasharray: 3 4"/>
21
+ <rect x="569" y="10" width="118" height="44" rx="8" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-wagon, #2563eb); stroke-width: 1.8"/>
22
+ <text x="628" y="32" text-anchor="middle" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 10.5px; font-weight: 600; fill: var(--atdd-ink, #1f2937)">fulfilment</text>
23
+ <text x="628" y="47" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 8px; letter-spacing: .1em; fill: var(--atdd-ink-3, #64748b)">WAGON</text>
24
+ <line x1="760" y1="54" x2="760" y2="679" style="stroke: var(--atdd-line, #cbd5e1); stroke-width: 1.4; stroke-dasharray: 3 4"/>
25
+ <rect x="701" y="10" width="118" height="44" rx="8" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-system, #7c3aed); stroke-width: 1.8"/>
26
+ <text x="760" y="32" text-anchor="middle" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 10.5px; font-weight: 600; fill: var(--atdd-ink, #1f2937)">carrier</text>
27
+ <text x="760" y="47" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 8px; letter-spacing: .1em; fill: var(--atdd-ink-3, #64748b)">SYSTEM</text>
28
+ <rect x="4" y="74" width="842" height="22" rx="4" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-nominal, #15803d); stroke-width: 1.2"/>
29
+ <text x="14" y="89" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 10px; fill: var(--atdd-nominal, #15803d)">◇ Checkout decision → nominal (nominal) → Place an order</text>
30
+ <text x="20" y="147" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9.5px; fill: var(--atdd-ink-3, #64748b)">1.1</text>
31
+ <text x="96" y="120" text-anchor="start" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; fill: var(--atdd-ink-2, #475569)">Submit the cart for checkout</text>
32
+ <text x="96" y="133" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9px; fill: var(--atdd-accent, #0f766e)">orders:cart</text>
33
+ <circle cx="100" cy="143" r="3" style="fill: var(--atdd-person, #b45309)"/>
34
+ <line x1="103" y1="143" x2="227" y2="143" style="stroke: var(--atdd-person, #b45309); stroke-width: 1.7" marker-end="url(#walk-buy-person)"/>
35
+ <text x="20" y="196" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9.5px; fill: var(--atdd-ink-3, #64748b)">1.2</text>
36
+ <text x="228" y="169" text-anchor="start" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; fill: var(--atdd-ink-2, #475569)">Price the cart with current promotions</text>
37
+ <text x="228" y="182" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9px; fill: var(--atdd-accent, #0f766e)">orders:priced-cart</text>
38
+ <circle cx="232" cy="192" r="3" style="fill: var(--atdd-ink-3, #64748b)"/>
39
+ <line x1="235" y1="192" x2="359" y2="192" style="stroke: var(--atdd-ink-3, #64748b); stroke-width: 1.7" marker-end="url(#walk-buy-wagon)"/>
40
+ <text x="20" y="245" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9.5px; fill: var(--atdd-ink-3, #64748b)">1.3</text>
41
+ <text x="228" y="218" text-anchor="start" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; fill: var(--atdd-ink-2, #475569)">Return the priced quote</text>
42
+ <text x="228" y="231" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9px; fill: var(--atdd-accent, #0f766e)">orders:quote</text>
43
+ <circle cx="364" cy="241" r="3" style="fill: var(--atdd-ink-3, #64748b)"/>
44
+ <line x1="361" y1="241" x2="237" y2="241" style="stroke: var(--atdd-ink-3, #64748b); stroke-width: 1.7" marker-end="url(#walk-buy-wagon)"/>
45
+ <rect x="4" y="257" width="842" height="22" rx="4" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-nominal, #15803d); stroke-width: 1.2"/>
46
+ <text x="14" y="272" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 10px; fill: var(--atdd-nominal, #15803d)">◇ Payment decision → charged (nominal) → Take payment</text>
47
+ <text x="20" y="330" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9.5px; fill: var(--atdd-ink-3, #64748b)">2.1</text>
48
+ <text x="228" y="303" text-anchor="start" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; fill: var(--atdd-ink-2, #475569)">Request the charge from the payment gateway</text>
49
+ <text x="228" y="316" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9px; fill: var(--atdd-accent, #0f766e)">orders:charge</text>
50
+ <circle cx="232" cy="326" r="3" style="fill: var(--atdd-system, #7c3aed)"/>
51
+ <line x1="235" y1="326" x2="491" y2="326" style="stroke: var(--atdd-system, #7c3aed); stroke-width: 1.7" marker-end="url(#walk-buy-system)"/>
52
+ <text x="20" y="379" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9.5px; fill: var(--atdd-ink-3, #64748b)">2.2</text>
53
+ <text x="228" y="352" text-anchor="start" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; fill: var(--atdd-ink-2, #475569)">Report whether the charge succeeded</text>
54
+ <text x="228" y="365" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9px; fill: var(--atdd-accent, #0f766e)">orders:charge-result</text>
55
+ <circle cx="496" cy="375" r="3" style="fill: var(--atdd-system, #7c3aed)"/>
56
+ <line x1="493" y1="375" x2="237" y2="375" style="stroke: var(--atdd-system, #7c3aed); stroke-width: 1.7" marker-end="url(#walk-buy-system)"/>
57
+ <text x="20" y="428" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9.5px; fill: var(--atdd-ink-3, #64748b)">2.3</text>
58
+ <text x="228" y="401" text-anchor="start" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; fill: var(--atdd-ink-2, #475569)">Record the order as paid</text>
59
+ <text x="228" y="414" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9px; fill: var(--atdd-accent, #0f766e)">orders:paid</text>
60
+ <circle cx="232" cy="424" r="3" style="fill: var(--atdd-ink-3, #64748b)"/>
61
+ <path d="M 232 424 h 32 v 18 h -26" style="fill: none; stroke: var(--atdd-ink-3, #64748b); stroke-width: 1.7" marker-end="url(#walk-buy-wagon)"/>
62
+ <rect x="4" y="458" width="842" height="22" rx="4" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-nominal, #15803d); stroke-width: 1.2"/>
63
+ <text x="14" y="473" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 10px; fill: var(--atdd-nominal, #15803d)">◇ Fulfilment decision → ship (nominal) → Ship the order</text>
64
+ <text x="20" y="531" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9.5px; fill: var(--atdd-ink-3, #64748b)">3.1</text>
65
+ <text x="228" y="504" text-anchor="start" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; fill: var(--atdd-ink-2, #475569)">Hand the paid order to fulfilment</text>
66
+ <text x="228" y="517" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9px; fill: var(--atdd-accent, #0f766e)">orders:paid</text>
67
+ <circle cx="232" cy="527" r="3" style="fill: var(--atdd-ink-3, #64748b)"/>
68
+ <line x1="235" y1="527" x2="623" y2="527" style="stroke: var(--atdd-ink-3, #64748b); stroke-width: 1.7" marker-end="url(#walk-buy-wagon)"/>
69
+ <text x="20" y="580" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9.5px; fill: var(--atdd-ink-3, #64748b)">3.2</text>
70
+ <text x="624" y="553" text-anchor="start" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; fill: var(--atdd-ink-2, #475569)">Book the shipment with the carrier</text>
71
+ <text x="624" y="566" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9px; fill: var(--atdd-accent, #0f766e)">orders:shipment</text>
72
+ <circle cx="628" cy="576" r="3" style="fill: var(--atdd-system, #7c3aed)"/>
73
+ <line x1="631" y1="576" x2="755" y2="576" style="stroke: var(--atdd-system, #7c3aed); stroke-width: 1.7" marker-end="url(#walk-buy-system)"/>
74
+ <text x="20" y="629" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9.5px; fill: var(--atdd-ink-3, #64748b)">3.3</text>
75
+ <text x="96" y="602" text-anchor="start" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; fill: var(--atdd-ink-2, #475569)">Send tracking to the buyer</text>
76
+ <text x="96" y="615" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9px; fill: var(--atdd-accent, #0f766e)">orders:tracking</text>
77
+ <circle cx="628" cy="625" r="3" style="fill: var(--atdd-person, #b45309)"/>
78
+ <line x1="625" y1="625" x2="105" y2="625" style="stroke: var(--atdd-person, #b45309); stroke-width: 1.7" marker-end="url(#walk-buy-person)"/>
79
+ <rect x="4" y="641" width="842" height="22" rx="4" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-terminal, #334155); stroke-width: 1.2"/>
80
+ <text x="14" y="656" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 10px; fill: var(--atdd-terminal, #334155)">■ outcome: shipped</text>
81
+ </svg>
@@ -0,0 +1,13 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" class="atdd-diagram" width="360" height="149" viewBox="0 0 360 149" role="img" aria-labelledby="t-seq-orders-archive-order d-seq-orders-archive-order">
2
+ <title id="t-seq-orders-archive-order">Archive a cancelled order</title><desc id="d-seq-orders-archive-order">1. checkout to checkout, orders:archived: Archive the cancelled order</desc>
3
+ <defs><marker id="seq-orders-archive-order-wagon" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M0,0 L10,5 L0,10 z" style="fill: var(--atdd-ink-3, #64748b)"/></marker><marker id="seq-orders-archive-order-person" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M0,0 L10,5 L0,10 z" style="fill: var(--atdd-person, #b45309)"/></marker><marker id="seq-orders-archive-order-system" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M0,0 L10,5 L0,10 z" style="fill: var(--atdd-system, #7c3aed)"/></marker></defs>
4
+ <line x1="100" y1="54" x2="100" y2="143" style="stroke: var(--atdd-line, #cbd5e1); stroke-width: 1.4; stroke-dasharray: 3 4"/>
5
+ <rect x="41" y="10" width="118" height="44" rx="8" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-wagon, #2563eb); stroke-width: 1.8"/>
6
+ <text x="100" y="32" text-anchor="middle" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 10.5px; font-weight: 600; fill: var(--atdd-ink, #1f2937)">checkout</text>
7
+ <text x="100" y="47" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 8px; letter-spacing: .1em; fill: var(--atdd-ink-3, #64748b)">WAGON</text>
8
+ <text x="20" y="111" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9.5px; fill: var(--atdd-ink-3, #64748b)">1</text>
9
+ <text x="96" y="84" text-anchor="start" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; fill: var(--atdd-ink-2, #475569)">Archive the cancelled order</text>
10
+ <text x="96" y="97" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9px; fill: var(--atdd-accent, #0f766e)">orders:archived</text>
11
+ <circle cx="100" cy="107" r="3" style="fill: var(--atdd-ink-3, #64748b)"/>
12
+ <path d="M 100 107 h 32 v 18 h -26" style="fill: none; stroke: var(--atdd-ink-3, #64748b); stroke-width: 1.7" marker-end="url(#seq-orders-archive-order-wagon)"/>
13
+ </svg>
@@ -0,0 +1,31 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" class="atdd-diagram" width="454" height="229" viewBox="0 0 454 229" role="img" aria-labelledby="t-seq-orders-place-order d-seq-orders-place-order">
2
+ <title id="t-seq-orders-place-order">Place an order</title><desc id="d-seq-orders-place-order">1. buyer to checkout, orders:cart: Submit the cart for checkout 2. checkout to pricing, orders:priced-cart: Price the cart with current promotions 3. pricing to checkout, orders:quote: Return the priced quote</desc>
3
+ <defs><marker id="seq-orders-place-order-wagon" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M0,0 L10,5 L0,10 z" style="fill: var(--atdd-ink-3, #64748b)"/></marker><marker id="seq-orders-place-order-person" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M0,0 L10,5 L0,10 z" style="fill: var(--atdd-person, #b45309)"/></marker><marker id="seq-orders-place-order-system" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M0,0 L10,5 L0,10 z" style="fill: var(--atdd-system, #7c3aed)"/></marker></defs>
4
+ <line x1="100" y1="54" x2="100" y2="223" style="stroke: var(--atdd-line, #cbd5e1); stroke-width: 1.4; stroke-dasharray: 3 4"/>
5
+ <rect x="41" y="10" width="118" height="44" rx="8" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-person, #b45309); stroke-width: 1.8"/>
6
+ <text x="100" y="32" text-anchor="middle" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 10.5px; font-weight: 600; fill: var(--atdd-ink, #1f2937)">buyer</text>
7
+ <text x="100" y="47" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 8px; letter-spacing: .1em; fill: var(--atdd-ink-3, #64748b)">PERSON</text>
8
+ <line x1="232" y1="54" x2="232" y2="223" style="stroke: var(--atdd-line, #cbd5e1); stroke-width: 1.4; stroke-dasharray: 3 4"/>
9
+ <rect x="173" y="10" width="118" height="44" rx="8" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-wagon, #2563eb); stroke-width: 1.8"/>
10
+ <text x="232" y="32" text-anchor="middle" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 10.5px; font-weight: 600; fill: var(--atdd-ink, #1f2937)">checkout</text>
11
+ <text x="232" y="47" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 8px; letter-spacing: .1em; fill: var(--atdd-ink-3, #64748b)">WAGON</text>
12
+ <line x1="364" y1="54" x2="364" y2="223" style="stroke: var(--atdd-line, #cbd5e1); stroke-width: 1.4; stroke-dasharray: 3 4"/>
13
+ <rect x="305" y="10" width="118" height="44" rx="8" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-wagon, #2563eb); stroke-width: 1.8"/>
14
+ <text x="364" y="32" text-anchor="middle" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 10.5px; font-weight: 600; fill: var(--atdd-ink, #1f2937)">pricing</text>
15
+ <text x="364" y="47" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 8px; letter-spacing: .1em; fill: var(--atdd-ink-3, #64748b)">WAGON</text>
16
+ <text x="20" y="111" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9.5px; fill: var(--atdd-ink-3, #64748b)">1</text>
17
+ <text x="96" y="84" text-anchor="start" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; fill: var(--atdd-ink-2, #475569)">Submit the cart for checkout</text>
18
+ <text x="96" y="97" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9px; fill: var(--atdd-accent, #0f766e)">orders:cart</text>
19
+ <circle cx="100" cy="107" r="3" style="fill: var(--atdd-person, #b45309)"/>
20
+ <line x1="103" y1="107" x2="227" y2="107" style="stroke: var(--atdd-person, #b45309); stroke-width: 1.7" marker-end="url(#seq-orders-place-order-person)"/>
21
+ <text x="20" y="160" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9.5px; fill: var(--atdd-ink-3, #64748b)">2</text>
22
+ <text x="228" y="133" text-anchor="start" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; fill: var(--atdd-ink-2, #475569)">Price the cart with current promotions</text>
23
+ <text x="228" y="146" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9px; fill: var(--atdd-accent, #0f766e)">orders:priced-cart</text>
24
+ <circle cx="232" cy="156" r="3" style="fill: var(--atdd-ink-3, #64748b)"/>
25
+ <line x1="235" y1="156" x2="359" y2="156" style="stroke: var(--atdd-ink-3, #64748b); stroke-width: 1.7" marker-end="url(#seq-orders-place-order-wagon)"/>
26
+ <text x="20" y="209" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9.5px; fill: var(--atdd-ink-3, #64748b)">3</text>
27
+ <text x="228" y="182" text-anchor="start" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; fill: var(--atdd-ink-2, #475569)">Return the priced quote</text>
28
+ <text x="228" y="195" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9px; fill: var(--atdd-accent, #0f766e)">orders:quote</text>
29
+ <circle cx="364" cy="205" r="3" style="fill: var(--atdd-ink-3, #64748b)"/>
30
+ <line x1="361" y1="205" x2="237" y2="205" style="stroke: var(--atdd-ink-3, #64748b); stroke-width: 1.7" marker-end="url(#seq-orders-place-order-wagon)"/>
31
+ </svg>
@@ -0,0 +1,22 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" class="atdd-diagram" width="360" height="180" viewBox="0 0 360 180" role="img" aria-labelledby="t-seq-orders-reject-empty-cart d-seq-orders-reject-empty-cart">
2
+ <title id="t-seq-orders-reject-empty-cart">Reject an empty cart</title><desc id="d-seq-orders-reject-empty-cart">1. buyer to checkout, orders:cart: Submit an empty cart 2. checkout to buyer, orders:rejection: Refuse the empty cart and say why</desc>
3
+ <defs><marker id="seq-orders-reject-empty-cart-wagon" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M0,0 L10,5 L0,10 z" style="fill: var(--atdd-ink-3, #64748b)"/></marker><marker id="seq-orders-reject-empty-cart-person" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M0,0 L10,5 L0,10 z" style="fill: var(--atdd-person, #b45309)"/></marker><marker id="seq-orders-reject-empty-cart-system" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M0,0 L10,5 L0,10 z" style="fill: var(--atdd-system, #7c3aed)"/></marker></defs>
4
+ <line x1="100" y1="54" x2="100" y2="174" style="stroke: var(--atdd-line, #cbd5e1); stroke-width: 1.4; stroke-dasharray: 3 4"/>
5
+ <rect x="41" y="10" width="118" height="44" rx="8" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-person, #b45309); stroke-width: 1.8"/>
6
+ <text x="100" y="32" text-anchor="middle" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 10.5px; font-weight: 600; fill: var(--atdd-ink, #1f2937)">buyer</text>
7
+ <text x="100" y="47" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 8px; letter-spacing: .1em; fill: var(--atdd-ink-3, #64748b)">PERSON</text>
8
+ <line x1="232" y1="54" x2="232" y2="174" style="stroke: var(--atdd-line, #cbd5e1); stroke-width: 1.4; stroke-dasharray: 3 4"/>
9
+ <rect x="173" y="10" width="118" height="44" rx="8" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-wagon, #2563eb); stroke-width: 1.8"/>
10
+ <text x="232" y="32" text-anchor="middle" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 10.5px; font-weight: 600; fill: var(--atdd-ink, #1f2937)">checkout</text>
11
+ <text x="232" y="47" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 8px; letter-spacing: .1em; fill: var(--atdd-ink-3, #64748b)">WAGON</text>
12
+ <text x="20" y="111" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9.5px; fill: var(--atdd-ink-3, #64748b)">1</text>
13
+ <text x="96" y="84" text-anchor="start" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; fill: var(--atdd-ink-2, #475569)">Submit an empty cart</text>
14
+ <text x="96" y="97" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9px; fill: var(--atdd-accent, #0f766e)">orders:cart</text>
15
+ <circle cx="100" cy="107" r="3" style="fill: var(--atdd-person, #b45309)"/>
16
+ <line x1="103" y1="107" x2="227" y2="107" style="stroke: var(--atdd-person, #b45309); stroke-width: 1.7" marker-end="url(#seq-orders-reject-empty-cart-person)"/>
17
+ <text x="20" y="160" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9.5px; fill: var(--atdd-ink-3, #64748b)">2</text>
18
+ <text x="96" y="133" text-anchor="start" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; fill: var(--atdd-ink-2, #475569)">Refuse the empty cart and say why</text>
19
+ <text x="96" y="146" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9px; fill: var(--atdd-accent, #0f766e)">orders:rejection</text>
20
+ <circle cx="232" cy="156" r="3" style="fill: var(--atdd-person, #b45309)"/>
21
+ <line x1="229" y1="156" x2="105" y2="156" style="stroke: var(--atdd-person, #b45309); stroke-width: 1.7" marker-end="url(#seq-orders-reject-empty-cart-person)"/>
22
+ </svg>
@@ -0,0 +1,22 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" class="atdd-diagram" width="360" height="180" viewBox="0 0 360 180" role="img" aria-labelledby="t-seq-orders-retry-payment d-seq-orders-retry-payment">
2
+ <title id="t-seq-orders-retry-payment">Retry a declined payment</title><desc id="d-seq-orders-retry-payment">1. checkout to buyer, orders:decline: Ask the buyer for another payment method 2. buyer to checkout, orders:payment-method: Provide a new payment method</desc>
3
+ <defs><marker id="seq-orders-retry-payment-wagon" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M0,0 L10,5 L0,10 z" style="fill: var(--atdd-ink-3, #64748b)"/></marker><marker id="seq-orders-retry-payment-person" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M0,0 L10,5 L0,10 z" style="fill: var(--atdd-person, #b45309)"/></marker><marker id="seq-orders-retry-payment-system" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M0,0 L10,5 L0,10 z" style="fill: var(--atdd-system, #7c3aed)"/></marker></defs>
4
+ <line x1="100" y1="54" x2="100" y2="174" style="stroke: var(--atdd-line, #cbd5e1); stroke-width: 1.4; stroke-dasharray: 3 4"/>
5
+ <rect x="41" y="10" width="118" height="44" rx="8" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-wagon, #2563eb); stroke-width: 1.8"/>
6
+ <text x="100" y="32" text-anchor="middle" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 10.5px; font-weight: 600; fill: var(--atdd-ink, #1f2937)">checkout</text>
7
+ <text x="100" y="47" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 8px; letter-spacing: .1em; fill: var(--atdd-ink-3, #64748b)">WAGON</text>
8
+ <line x1="232" y1="54" x2="232" y2="174" style="stroke: var(--atdd-line, #cbd5e1); stroke-width: 1.4; stroke-dasharray: 3 4"/>
9
+ <rect x="173" y="10" width="118" height="44" rx="8" style="fill: var(--atdd-paper, #ffffff); stroke: var(--atdd-person, #b45309); stroke-width: 1.8"/>
10
+ <text x="232" y="32" text-anchor="middle" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 10.5px; font-weight: 600; fill: var(--atdd-ink, #1f2937)">buyer</text>
11
+ <text x="232" y="47" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 8px; letter-spacing: .1em; fill: var(--atdd-ink-3, #64748b)">PERSON</text>
12
+ <text x="20" y="111" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9.5px; fill: var(--atdd-ink-3, #64748b)">1</text>
13
+ <text x="96" y="84" text-anchor="start" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; fill: var(--atdd-ink-2, #475569)">Ask the buyer for another payment method</text>
14
+ <text x="96" y="97" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9px; fill: var(--atdd-accent, #0f766e)">orders:decline</text>
15
+ <circle cx="100" cy="107" r="3" style="fill: var(--atdd-person, #b45309)"/>
16
+ <line x1="103" y1="107" x2="227" y2="107" style="stroke: var(--atdd-person, #b45309); stroke-width: 1.7" marker-end="url(#seq-orders-retry-payment-person)"/>
17
+ <text x="20" y="160" text-anchor="middle" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9.5px; fill: var(--atdd-ink-3, #64748b)">2</text>
18
+ <text x="96" y="133" text-anchor="start" style="font-family: var(--atdd-sans, system-ui, sans-serif); font-size: 11px; fill: var(--atdd-ink-2, #475569)">Provide a new payment method</text>
19
+ <text x="96" y="146" text-anchor="start" style="font-family: var(--atdd-mono, ui-monospace, monospace); font-size: 9px; fill: var(--atdd-accent, #0f766e)">orders:payment-method</text>
20
+ <circle cx="232" cy="156" r="3" style="fill: var(--atdd-person, #b45309)"/>
21
+ <line x1="229" y1="156" x2="105" y2="156" style="stroke: var(--atdd-person, #b45309); stroke-width: 1.7" marker-end="url(#seq-orders-retry-payment-person)"/>
22
+ </svg>