| 1 | 1 | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 600" width="1200" height="600"> |
| 2 | 2 | <rect width="1200" height="600" fill="#0a0a0a"/> |
| 3 | 3 | |
| 4 | + <!-- Header — the Law is the main message, scaled up --> |
| 4 | 5 | <g font-family="ui-monospace, 'SF Mono', 'JetBrains Mono', Menlo, Consolas, monospace"> |
| 5 | | - <text x="80" y="55" font-size="28" font-weight="600" fill="#e8e8e8">The four canonical layers</text> |
| 6 | | - <text x="80" y="85" font-size="18" fill="#8a8a8a">SAMA v2 §1.1 — frozen; no profile may add, remove, renumber, or rename them.</text> |
| 6 | + <text x="120" y="46" font-size="20" font-weight="600" fill="#909090">The four canonical layers</text> |
| 7 | + <text x="120" y="92" font-size="38" font-weight="700" fill="#e8e8e8">Imports only flow downward.</text> |
| 8 | + <text x="120" y="122" font-size="16" fill="#7a7a7a">never upward · never sideways · never cyclic — SAMA v2 §1.2 the Law</text> |
| 7 | 9 | </g> |
| 8 | 10 | |
| 9 | | - <!-- Layer 3: Entry (top) --> |
| 10 | | - <rect x="200" y="115" width="800" height="78" fill="#1a1a1a" stroke="#3a3a3a" stroke-width="1.5" rx="6"/> |
| 11 | + <!-- Layer 3 · Entry (top — warm/volatile) --> |
| 12 | + <rect x="120" y="148" width="960" height="80" fill="#1a1a1a" stroke="#2a2a2a" stroke-width="1.5" rx="6"/> |
| 13 | + <rect x="120" y="148" width="8" height="80" fill="#c89a3a" rx="3"/> |
| 11 | 14 | <g font-family="ui-monospace, 'SF Mono', 'JetBrains Mono', Menlo, Consolas, monospace"> |
| 12 | | - <text x="225" y="148" font-size="26" font-weight="600" fill="#e8e8e8">Layer 3 · Entry</text> |
| 13 | | - <text x="225" y="178" font-size="17" fill="#8a8a8a">main · CLI handler · HTTP route · UI mount · job entry</text> |
| 14 | | - <text x="975" y="158" font-size="14" fill="#5a5a5a" text-anchor="end">may import 0, 1, 2</text> |
| 15 | + <text x="160" y="182" font-size="24" font-weight="600" fill="#e8e8e8">Layer 3 · Entry</text> |
| 16 | + <text x="160" y="210" font-size="15" fill="#8a8a8a">outermost shell — main · CLI handler · HTTP route · UI mount · job entry</text> |
| 17 | + <text x="1060" y="195" text-anchor="end" font-size="17" font-style="italic" fill="#c89a3a">POST /checkout</text> |
| 15 | 18 | </g> |
| 16 | 19 | |
| 17 | | - <!-- Arrow 3→2 --> |
| 18 | | - <line x1="600" y1="200" x2="600" y2="220" stroke="#4a8a4a" stroke-width="2"/> |
| 19 | | - <polygon points="595,217 605,217 600,228" fill="#4a8a4a"/> |
| 20 | + <text x="600" y="246" text-anchor="middle" font-family="ui-monospace, 'SF Mono', 'JetBrains Mono', Menlo, Consolas, monospace" font-size="13" fill="#6a6a6a">↓ uses</text> |
| 20 | 21 | |
| 21 | | - <!-- Layer 2: Adapter --> |
| 22 | | - <rect x="200" y="232" width="800" height="78" fill="#1a1a1a" stroke="#3a3a3a" stroke-width="1.5" rx="6"/> |
| 22 | + <!-- Layer 2 · Adapter (boundary — warm) --> |
| 23 | + <rect x="120" y="253" width="960" height="80" fill="#1a1a1a" stroke="#2a2a2a" stroke-width="1.5" rx="6"/> |
| 24 | + <rect x="120" y="253" width="8" height="80" fill="#b8794a" rx="3"/> |
| 23 | 25 | <g font-family="ui-monospace, 'SF Mono', 'JetBrains Mono', Menlo, Consolas, monospace"> |
| 24 | | - <text x="225" y="265" font-size="26" font-weight="600" fill="#e8e8e8">Layer 2 · Adapter</text> |
| 25 | | - <text x="225" y="295" font-size="17" fill="#8a8a8a">the boundary — DB · network · filesystem · framework bindings · external input parsed here</text> |
| 26 | | - <text x="975" y="275" font-size="14" fill="#5a5a5a" text-anchor="end">may import 0, 1</text> |
| 26 | + <text x="160" y="287" font-size="24" font-weight="600" fill="#e8e8e8">Layer 2 · Adapter</text> |
| 27 | + <text x="160" y="315" font-size="15" fill="#8a8a8a">the boundary — DB · network · filesystem · framework bindings · external input parsed here</text> |
| 28 | + <text x="1060" y="300" text-anchor="end" font-size="17" font-style="italic" fill="#b8794a">Stripe.charges.create()</text> |
| 27 | 29 | </g> |
| 28 | 30 | |
| 29 | | - <!-- Arrow 2→1 --> |
| 30 | | - <line x1="600" y1="317" x2="600" y2="337" stroke="#4a8a4a" stroke-width="2"/> |
| 31 | | - <polygon points="595,334 605,334 600,345" fill="#4a8a4a"/> |
| 31 | + <text x="600" y="351" text-anchor="middle" font-family="ui-monospace, 'SF Mono', 'JetBrains Mono', Menlo, Consolas, monospace" font-size="13" fill="#6a6a6a">↓ uses</text> |
| 32 | 32 | |
| 33 | | - <!-- Layer 1: Core --> |
| 34 | | - <rect x="200" y="349" width="800" height="78" fill="#1a1a1a" stroke="#3a3a3a" stroke-width="1.5" rx="6"/> |
| 33 | + <!-- Layer 1 · Core (cool — stable) --> |
| 34 | + <rect x="120" y="358" width="960" height="80" fill="#1a1a1a" stroke="#2a2a2a" stroke-width="1.5" rx="6"/> |
| 35 | + <rect x="120" y="358" width="8" height="80" fill="#4a8a8a" rx="3"/> |
| 35 | 36 | <g font-family="ui-monospace, 'SF Mono', 'JetBrains Mono', Menlo, Consolas, monospace"> |
| 36 | | - <text x="225" y="382" font-size="26" font-weight="600" fill="#e8e8e8">Layer 1 · Core</text> |
| 37 | | - <text x="225" y="412" font-size="17" fill="#8a8a8a">domain logic · decisions · pure render — no network, disk, clock, framework</text> |
| 38 | | - <text x="975" y="392" font-size="14" fill="#5a5a5a" text-anchor="end">may import 0</text> |
| 37 | + <text x="160" y="392" font-size="24" font-weight="600" fill="#e8e8e8">Layer 1 · Core</text> |
| 38 | + <text x="160" y="420" font-size="15" fill="#8a8a8a">domain decisions — business logic · policies · pure render — no network, disk, clock, framework</text> |
| 39 | + <text x="1060" y="405" text-anchor="end" font-size="17" font-style="italic" fill="#4a8a8a">applyPaymentRules()</text> |
| 39 | 40 | </g> |
| 40 | 41 | |
| 41 | | - <!-- Arrow 1→0 --> |
| 42 | | - <line x1="600" y1="434" x2="600" y2="454" stroke="#4a8a4a" stroke-width="2"/> |
| 43 | | - <polygon points="595,451 605,451 600,462" fill="#4a8a4a"/> |
| 42 | + <text x="600" y="456" text-anchor="middle" font-family="ui-monospace, 'SF Mono', 'JetBrains Mono', Menlo, Consolas, monospace" font-size="13" fill="#6a6a6a">↓ uses</text> |
| 44 | 43 | |
| 45 | | - <!-- Layer 0: Pure (bottom) --> |
| 46 | | - <rect x="200" y="466" width="800" height="78" fill="#1a1a1a" stroke="#3a3a3a" stroke-width="1.5" rx="6"/> |
| 44 | + <!-- Layer 0 · Pure (bottom — coolest, mathematical foundation) --> |
| 45 | + <rect x="120" y="463" width="960" height="80" fill="#1a1a1a" stroke="#2a2a2a" stroke-width="1.5" rx="6"/> |
| 46 | + <rect x="120" y="463" width="8" height="80" fill="#4a9a5a" rx="3"/> |
| 47 | 47 | <g font-family="ui-monospace, 'SF Mono', 'JetBrains Mono', Menlo, Consolas, monospace"> |
| 48 | | - <text x="225" y="499" font-size="26" font-weight="600" fill="#e8e8e8">Layer 0 · Pure</text> |
| 49 | | - <text x="225" y="529" font-size="17" fill="#8a8a8a">types · constants · pure functions · domain models — no I/O, no side effects</text> |
| 50 | | - <text x="975" y="509" font-size="14" fill="#5a5a5a" text-anchor="end">imports nothing above</text> |
| 48 | + <text x="160" y="497" font-size="24" font-weight="600" fill="#e8e8e8">Layer 0 · Pure</text> |
| 49 | + <text x="160" y="525" font-size="15" fill="#8a8a8a">deterministic primitives — types · constants · pure functions — no I/O, no side effects</text> |
| 50 | + <text x="1060" y="510" text-anchor="end" font-size="17" font-style="italic" fill="#4a9a5a">Money(amount, currency)</text> |
| 51 | 51 | </g> |
| 52 | 52 | |
| 53 | | - <!-- Caption: the Law --> |
| 54 | | - <g font-family="ui-monospace, 'SF Mono', 'JetBrains Mono', Menlo, Consolas, monospace"> |
| 55 | | - <text x="80" y="578" font-size="15" fill="#7ec77e">§1.2 the Law:</text> |
| 56 | | - <text x="220" y="578" font-size="15" fill="#a0a0a0">imports always point to a strictly lower layer number — never upward, never sideways, never cyclic.</text> |
| 57 | | - </g> |
| 53 | + <!-- Worked-example caption --> |
| 54 | + <text x="120" y="582" font-family="ui-monospace, 'SF Mono', 'JetBrains Mono', Menlo, Consolas, monospace" font-size="13" fill="#6a6a6a"> |
| 55 | + Worked example, threaded through a checkout flow — each italic line shows what that layer would actually do. |
| 56 | + </text> |
| 58 | 57 | </svg> |