figdown 0.3.2 → 0.4.1
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.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +2 -0
- package/dist/figdown.js +3791 -213
- package/dist/figdown.mjs +3791 -213
- package/examples/evpn-fabric.svg +1 -1
- package/examples/showcase/arp-resolution.svg +3 -2
- package/examples/showcase/ethernet-frame.svg +1 -1
- package/examples/showcase/l2-forwarding-logic.svg +1 -1
- package/examples/showcase/tcp-handshake.svg +4 -3
- package/examples/showcase/tcp-header.svg +1 -1
- package/examples/showcase/tcp-state-machine.svg +53 -24
- package/guide/expressing.md +58 -6
- package/guide/layout.md +54 -10
- package/guide/showcase.md +63 -27
- package/integrations/mcp-server/README.md +11 -5
- package/integrations/mcp-server/server.js +19 -3
- package/package.json +2 -1
- package/skill/figdown/SKILL.md +49 -18
- package/skill/figdown/build-svg.js +16 -2
- package/skill/figdown/figdown.html +3982 -229
- package/skill/figdown/reference/experimental/flowchart.md +6 -4
- package/skill/figdown/reference/experimental/sequence.md +252 -0
- package/skill/figdown/reference/experimental/statechart.md +5 -3
- package/skill/figdown/reference/experimental/topology.md +6 -4
- package/skill/figdown/reference/reading.md +14 -9
- package/skill/figdown/reference/scene.md +8 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 902 984" width="902" height="984" font-family="system-ui,sans-serif"><defs><marker id="arr" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#555"/></marker><pattern id="hatch" width="6" height="6" patternUnits="userSpaceOnUse" patternTransform="rotate(45)"><line x1="0" y1="0" x2="0" y2="6" stroke="#bbb" stroke-width="2"/></pattern></defs><g transform="translate(18,6)"><line data-edge="92" x1="433.1" y1="76" x2="433.1" y2="190" stroke="#2563eb" stroke-width="1.6"/><line data-edge="93" x1="452.7652886772431" y1="73.34906513439799" x2="724.2052886772431" y2="307.34906513439796" stroke="#2563eb" stroke-width="1.6"/><line data-edge="94" x1="465.20000000000005" y1="221.63984674329504" x2="700" y2="311.6015325670498" stroke="#2563eb" stroke-width="1.6"/><line data-edge="95" x1="395.5028227438559" y1="228.0864522267111" x2="216.56282274385592" y2="313.1609371712436" stroke="#2563eb" stroke-width="1.6"/><line data-edge="96" x1="700" y1="328" x2="234.39999999999998" y2="328" stroke="#9333ea" stroke-width="1.6" stroke-dasharray="6 4"/><line data-edge="97" x1="700" y1="344.3984674329502" x2="476.58000000000004" y2="430" stroke="#2563eb" stroke-width="1.6"/><line data-edge="98" x1="215.06" y1="346" x2="391.74" y2="430" stroke="#2563eb" stroke-width="1.6"/><line data-edge="101" x1="426.1" y1="190" x2="426.1" y2="76" stroke="#9333ea" stroke-width="1.6" stroke-dasharray="6 4"/><line data-edge="102" x1="719.6347113227569" y1="312.65093486560204" x2="448.1947113227569" y2="78.65093486560201" stroke="#9333ea" stroke-width="1.6" stroke-dasharray="6 4"/><line data-edge="103" x1="213.5571772561441" y1="306.8390628287564" x2="392.4971772561441" y2="221.76457788422394" stroke="#9333ea" stroke-width="1.6" stroke-dasharray="6 4"/><line data-edge="106" x1="179.4896" y1="346" x2="206.7104" y2="560" stroke="#dc2626" stroke-width="1.6"/><line data-edge="107" x1="399.05538461538464" y1="466" x2="239.54461538461538" y2="560" stroke="#dc2626" stroke-width="1.6"/><line data-edge="108" x1="209" y1="596" x2="209" y2="690" stroke="#dc2626" stroke-width="1.6"/><line data-edge="109" x1="228.55076923076922" y1="596" x2="330.64923076923077" y2="690" stroke="#dc2626" stroke-width="1.6"/><line data-edge="110" x1="218.78923076923076" y1="596" x2="340.6107692307692" y2="820" stroke="#9333ea" stroke-width="1.6" stroke-dasharray="6 4"/><line data-edge="111" x1="228.57846153846154" y1="726" x2="330.82153846153847" y2="820" stroke="#dc2626" stroke-width="1.6"/><line data-edge="112" x1="350.2276923076923" y1="726" x2="350.3723076923077" y2="820" stroke="#dc2626" stroke-width="1.6"/><line data-edge="113" x1="396.79999999999995" y1="838" x2="697" y2="838" stroke="#dc2626" stroke-width="1.6"/><line data-edge="116" x1="472.57846153846157" y1="466" x2="697.0215384615385" y2="560" stroke="#16a34a" stroke-width="1.6"/><line data-edge="117" x1="739.003076923077" y1="596" x2="733.796923076923" y2="690" stroke="#16a34a" stroke-width="1.6"/><line data-edge="118" x1="732.7723076923077" y1="726" x2="732.6276923076923" y2="820" stroke="#16a34a" stroke-width="1.6"/><g data-node="closed" data-x="394" data-y="40" style="cursor:move"><rect x="394" y="40" width="71.2" height="36" rx="14" fill="#eef2ff" stroke="#8a8880" stroke-width="1.8"/><text x="429.6" y="62.55" font-size="13" text-anchor="middle" fill="#1d1d1b">CLOSED</text></g><g data-node="listen" data-x="394" data-y="190" style="cursor:move"><rect x="394" y="190" width="71.2" height="36" rx="14" fill="#eef2ff" stroke="#8a8880" stroke-width="1.8"/><text x="429.6" y="212.55" font-size="13" text-anchor="middle" fill="#1d1d1b">LISTEN</text></g><g data-node="synsent" data-x="700" data-y="310" style="cursor:move"><rect x="700" y="310" width="85.6" height="36" rx="14" fill="#eef2ff" stroke="#8a8880" stroke-width="1.8"/><text x="742.8" y="332.55" font-size="13" text-anchor="middle" fill="#1d1d1b">SYN-SENT</text></g><g data-node="synrcvd" data-x="120" data-y="310" style="cursor:move"><rect x="120" y="310" width="114.4" height="36" rx="14" fill="#eef2ff" stroke="#8a8880" stroke-width="1.8"/><text x="177.2" y="332.55" font-size="13" text-anchor="middle" fill="#1d1d1b">SYN-RECEIVED</text></g><g data-node="estab" data-x="376" data-y="430" style="cursor:move"><rect x="376" y="430" width="107.2" height="36" rx="14" fill="#eef2ff" stroke="#8a8880" stroke-width="1.8"/><text x="429.6" y="452.55" font-size="13" text-anchor="middle" fill="#1d1d1b">ESTABLISHED</text></g><g data-node="fw1" data-x="159" data-y="560" style="cursor:move"><rect x="159" y="560" width="100" height="36" rx="14" fill="#eef2ff" stroke="#8a8880" stroke-width="1.8"/><text x="209" y="582.55" font-size="13" text-anchor="middle" fill="#1d1d1b">FIN-WAIT-1</text></g><g data-node="fw2" data-x="159" data-y="690" style="cursor:move"><rect x="159" y="690" width="100" height="36" rx="14" fill="#eef2ff" stroke="#8a8880" stroke-width="1.8"/><text x="209" y="712.55" font-size="13" text-anchor="middle" fill="#1d1d1b">FIN-WAIT-2</text></g><g data-node="closing" data-x="311" data-y="690" style="cursor:move"><rect x="311" y="690" width="78.4" height="36" rx="14" fill="#eef2ff" stroke="#8a8880" stroke-width="1.8"/><text x="350.2" y="712.55" font-size="13" text-anchor="middle" fill="#1d1d1b">CLOSING</text></g><g data-node="closewait" data-x="690" data-y="560" style="cursor:move"><rect x="690" y="560" width="100" height="36" rx="14" fill="#eef2ff" stroke="#8a8880" stroke-width="1.8"/><text x="740" y="582.55" font-size="13" text-anchor="middle" fill="#1d1d1b">CLOSE-WAIT</text></g><g data-node="lastack" data-x="690" data-y="690" style="cursor:move"><rect x="690" y="690" width="85.6" height="36" rx="14" fill="#eef2ff" stroke="#8a8880" stroke-width="1.8"/><text x="732.8" y="712.55" font-size="13" text-anchor="middle" fill="#1d1d1b">LAST-ACK</text></g><g data-node="timewait" data-x="304" data-y="820" style="cursor:move"><rect x="304" y="820" width="92.8" height="36" rx="14" fill="#eef2ff" stroke="#8a8880" stroke-width="1.8"/><text x="350.4" y="842.55" font-size="13" text-anchor="middle" fill="#1d1d1b">TIME-WAIT</text></g><g data-node="closed2" data-x="697" data-y="820" style="cursor:move"><rect x="697" y="820" width="71.2" height="36" rx="14" fill="#eef2ff" stroke="#8a8880" stroke-width="1.8"/><text x="732.6" y="842.55" font-size="13" text-anchor="middle" fill="#1d1d1b">CLOSED</text></g><text x="439.1" y="136.3" font-size="11" text-anchor="start" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">passive OPEN / create TCB</text><text x="439.1" y="136.3" font-size="11" text-anchor="start" fill="#2563eb">passive OPEN / create TCB</text><path d="M433.1 190 L427.5 179.92 L438.70000000000005 179.92 z" fill="#2563eb" stroke="none"/><text x="588.485288677243" y="92.14216858267382" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">active OPEN / create TCB, snd SYN</text><text x="588.485288677243" y="92.14216858267382" font-size="11" text-anchor="middle" fill="#2563eb">active OPEN / create TCB, snd SYN</text><path d="M724.2052886772431 307.34906513439796 L712.9141343807203 305.008929528901 L720.2270581478983 296.52593795897457 z" fill="#2563eb" stroke="none"/><text x="582.6" y="243.43773946360156" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">SEND / snd SYN</text><text x="582.6" y="243.43773946360156" font-size="11" text-anchor="middle" fill="#2563eb">SEND / snd SYN</text><path d="M700 311.6015325670498 L688.5836683972988 313.224422808922 L692.5908047969832 302.76579680574537 z" fill="#2563eb" stroke="none"/><text x="306.03282274385595" y="315.42218915222617" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv SYN / snd SYN,ACK</text><text x="306.03282274385595" y="315.42218915222617" font-size="11" text-anchor="middle" fill="#2563eb">rcv SYN / snd SYN,ACK</text><path d="M216.56282274385592 313.1609371712436 L223.261805406868 303.7753081949488 L228.0708381872069 313.89030714292835 z" fill="#2563eb" stroke="none"/><text x="467.2" y="322.25" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv SYN / snd SYN,ACK</text><text x="467.2" y="322.25" font-size="11" text-anchor="middle" fill="#9333ea">rcv SYN / snd SYN,ACK</text><path d="M234.39999999999998 328 L244.48 322.4 L244.48 333.6 z" fill="#9333ea" stroke="none"/><text x="588.29" y="355.29980842911874" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv SYN,ACK / snd ACK</text><text x="588.29" y="355.29980842911874" font-size="11" text-anchor="middle" fill="#2563eb">rcv SYN,ACK / snd ACK</text><path d="M476.58000000000004 430 L483.9891952030168 421.1642642386956 L487.99633160270133 431.6228902418722 z" fill="#2563eb" stroke="none"/><text x="303.4" y="354.43700475435816" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv ACK of SYN / x</text><text x="303.4" y="354.43700475435816" font-size="11" text-anchor="middle" fill="#2563eb">rcv ACK of SYN / x</text><path d="M391.74 430 L380.231984556649 430.7293699716848 L385.041017336988 420.61437102370525 z" fill="#2563eb" stroke="none"/><text x="303.1" y="136.3" font-size="11" text-anchor="start" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">CLOSE / delete TCB</text><text x="303.1" y="136.3" font-size="11" text-anchor="start" fill="#9333ea">CLOSE / delete TCB</text><path d="M426.1 76 L431.70000000000005 86.08 L420.5 86.08 z" fill="#9333ea" stroke="none"/><text x="524.1979113227569" y="206.95196934836065" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">CLOSE / delete TCB</text><text x="524.1979113227569" y="206.95196934836065" font-size="11" text-anchor="middle" fill="#9333ea">CLOSE / delete TCB</text><path d="M448.1947113227569 78.65093486560201 L459.4858656192797 80.99107047109896 L452.17294185210176 89.47406204102543 z" fill="#9333ea" stroke="none"/><text x="303.0271772561441" y="227.648492305777" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv RST (note 1) / x</text><text x="303.0271772561441" y="227.648492305777" font-size="11" text-anchor="middle" fill="#9333ea">rcv RST (note 1) / x</text><path d="M392.4971772561441 221.76457788422394 L385.79819459313205 231.1502068605187 L380.9891618127931 221.03520791253922 z" fill="#9333ea" stroke="none"/><text x="199.1" y="456.3" font-size="11" text-anchor="start" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">CLOSE / snd FIN</text><text x="199.1" y="456.3" font-size="11" text-anchor="start" fill="#dc2626">CLOSE / snd FIN</text><path d="M206.7104 560 L199.88323361107894 550.7071963811783 L210.99371139541864 549.2939436070102 z" fill="#dc2626" stroke="none"/><text x="319.3" y="478.52153218495016" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">CLOSE / snd FIN</text><text x="319.3" y="478.52153218495016" font-size="11" text-anchor="middle" fill="#dc2626">CLOSE / snd FIN</text><path d="M239.54461538461538 560 L245.38572668223014 550.0577759626491 L251.0719964792192 559.7069384027706 z" fill="#dc2626" stroke="none"/><text x="86" y="646.3000000000001" font-size="11" text-anchor="start" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv ACK of FIN / x</text><text x="86" y="646.3000000000001" font-size="11" text-anchor="start" fill="#dc2626">rcv ACK of FIN / x</text><path d="M209 690 L203.4 679.92 L214.6 679.92 z" fill="#dc2626" stroke="none"/><text x="302.0616615384615" y="607.0624362606231" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv FIN / snd ACK</text><text x="302.0616615384615" y="607.0624362606231" font-size="11" text-anchor="middle" fill="#dc2626">rcv FIN / snd ACK</text><path d="M330.64923076923077 690 L319.4405255167678 687.2923577482596 L327.02659217035057 679.0527222752913 z" fill="#dc2626" stroke="none"/><text x="300.3185846153846" y="738.1800000000001" font-size="11" text-anchor="start" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv FIN,ACK / snd ACK</text><text x="300.3185846153846" y="738.1800000000001" font-size="11" text-anchor="start" fill="#9333ea">rcv FIN,ACK / snd ACK</text><path d="M340.6107692307692 820 L330.875382512483 813.820303774018 L340.7144579488292 808.469360440559 z" fill="#9333ea" stroke="none"/><text x="257.2065230769231" y="815.4656152758133" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv FIN / snd ACK</text><text x="257.2065230769231" y="815.4656152758133" font-size="11" text-anchor="middle" fill="#dc2626">rcv FIN / snd ACK</text><path d="M330.82153846153847 820 L319.61092639723944 817.3002635047485 L327.19118005561285 809.0552799101793 z" fill="#dc2626" stroke="none"/><text x="356.29999999999995" y="776.3000000000001" font-size="11" text-anchor="start" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv ACK of FIN / x</text><text x="356.29999999999995" y="776.3000000000001" font-size="11" text-anchor="start" fill="#dc2626">rcv ACK of FIN / x</text><path d="M350.3723076923077 820 L344.75680664555944 809.9286273033927 L355.9567933911451 809.9113965545532 z" fill="#dc2626" stroke="none"/><text x="546.9" y="832.25" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">Timeout=2MSL / delete TCB</text><text x="546.9" y="832.25" font-size="11" text-anchor="middle" fill="#dc2626">Timeout=2MSL / delete TCB</text><path d="M697 838 L686.92 843.6 L686.92 832.4 z" fill="#dc2626" stroke="none"/><text x="584.8000000000001" y="484.1105025773196" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv FIN / snd ACK</text><text x="584.8000000000001" y="484.1105025773196" font-size="11" text-anchor="middle" fill="#16a34a">rcv FIN / snd ACK</text><path d="M697.0215384615385 560 L685.5607329004544 561.2713519933599 L689.8873234537733 550.9407850106658 z" fill="#16a34a" stroke="none"/><text x="742.4" y="646.3000000000001" font-size="11" text-anchor="start" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">CLOSE / snd FIN</text><text x="742.4" y="646.3000000000001" font-size="11" text-anchor="start" fill="#16a34a">CLOSE / snd FIN</text><path d="M733.796923076923 690 L728.7629148866224 679.6257452537551 L739.9457765533873 680.2451037460681 z" fill="#16a34a" stroke="none"/><text x="738.7" y="776.3000000000001" font-size="11" text-anchor="start" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv ACK of FIN / x</text><text x="738.7" y="776.3000000000001" font-size="11" text-anchor="start" fill="#16a34a">rcv ACK of FIN / x</text><path d="M732.6276923076923 820 L727.0432066088549 809.9113965545532 L738.2431933544406 809.9286273033927 z" fill="#16a34a" stroke="none"/><rect x="0" y="877" width="16" height="11" fill="#eef2ff" stroke="#555"/><text x="21" y="886.5" font-size="11" fill="#1d1d1b">A state IS a TCP connection state (RFC 9293 §3.3.2); the two CLOSED states are one state drawn twice — only this label says so</text><rect x="0" y="897" width="16" height="11" fill="#fff" stroke="#2563eb"/><text x="21" y="906.5" font-size="11" fill="#1d1d1b">Connection-setup transition — opening the connection (OPEN, SYN exchange, first ACK)</text><rect x="0" y="917" width="16" height="11" fill="#fff" stroke="#dc2626"/><text x="21" y="926.5" font-size="11" fill="#1d1d1b">Active-close path (typically the client) — calls CLOSE first: FIN-WAIT-1 → FIN-WAIT-2 / CLOSING → TIME-WAIT → CLOSED</text><rect x="0" y="937" width="16" height="11" fill="#fff" stroke="#16a34a"/><text x="21" y="946.5" font-size="11" fill="#1d1d1b">Passive-close path (typically the server) — receives the peer's FIN first: CLOSE-WAIT → LAST-ACK → CLOSED</text><rect x="0" y="957" width="16" height="11" fill="#fff" stroke="#9333ea" stroke-dasharray="6 4"/><text x="21" y="966.5" font-size="11" fill="#1d1d1b">Rare / simultaneous transition — simultaneous open or close, or a reset/abort (RST, close from a half-open state)</text></g><metadata id="figdown-source" data-sha256="107a61548ef549f76483c5a2836aaf38e1021f8d9a29b82c48bf199d34aa7858" data-engine-version="0.3.2"><![CDATA[
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 902 984" width="902" height="984" font-family="system-ui,sans-serif"><defs><marker id="arr" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#555"/></marker><pattern id="hatch" width="6" height="6" patternUnits="userSpaceOnUse" patternTransform="rotate(45)"><line x1="0" y1="0" x2="0" y2="6" stroke="#bbb" stroke-width="2"/></pattern></defs><g transform="translate(18,6)"><line data-edge="92" x1="529.1525051498933" y1="77.63902772944337" x2="442.2325051498932" y2="241.63902772944337" stroke="#2563eb" stroke-width="1.6"/><line data-edge="93" x1="552.1899621776382" y1="73.86919445725937" x2="731.7632955109716" y2="307.86919445725937" stroke="#2563eb" stroke-width="1.6"/><line data-edge="94" x1="465.20000000000005" y1="265.9565772669221" x2="700" y2="318.43422733077904" stroke="#2563eb" stroke-width="1.6"/><line data-edge="95" x1="394.93537507812675" y1="271.24591239739203" x2="235.3353750781267" y2="315.50898688233656" stroke="#2563eb" stroke-width="1.6"/><line data-edge="96" x1="700" y1="328" x2="234.39999999999998" y2="328" stroke="#9333ea" stroke-width="1.6" stroke-dasharray="6 4"/><line data-edge="97" x1="700" y1="344.3984674329502" x2="476.58000000000004" y2="430" stroke="#2563eb" stroke-width="1.6"/><line data-edge="98" x1="215.06" y1="346" x2="391.74" y2="430" stroke="#2563eb" stroke-width="1.6"/><line data-edge="101" x1="436.0474948501069" y1="238.36097227055663" x2="522.9674948501068" y2="74.36097227055663" stroke="#9333ea" stroke-width="1.6" stroke-dasharray="6 4"/><line data-edge="102" x1="726.2100378223618" y1="312.13080554274063" x2="546.6367044890284" y2="78.13080554274063" stroke="#9333ea" stroke-width="1.6" stroke-dasharray="6 4"/><line data-edge="103" x1="233.46462492187325" y1="308.76359631893126" x2="393.06462492187325" y2="264.50052183398674" stroke="#9333ea" stroke-width="1.6" stroke-dasharray="6 4"/><line data-edge="106" x1="179.4896" y1="346" x2="206.7104" y2="560" stroke="#dc2626" stroke-width="1.6"/><line data-edge="107" x1="399.05538461538464" y1="466" x2="239.54461538461538" y2="560" stroke="#dc2626" stroke-width="1.6"/><line data-edge="108" x1="209" y1="596" x2="209" y2="690" stroke="#dc2626" stroke-width="1.6"/><line data-edge="109" x1="259" y1="595.3761946133797" x2="400" y2="644.3770634231104" stroke="#dc2626" stroke-width="1.6"/><line data-edge="110" x1="218.78923076923076" y1="596" x2="340.6107692307692" y2="820" stroke="#9333ea" stroke-width="1.6" stroke-dasharray="6 4"/><line data-edge="111" x1="228.57846153846154" y1="726" x2="330.82153846153847" y2="820" stroke="#dc2626" stroke-width="1.6"/><line data-edge="112" x1="430.32" y1="676" x2="359.28" y2="820" stroke="#dc2626" stroke-width="1.6"/><line data-edge="113" x1="396.79999999999995" y1="838" x2="697" y2="838" stroke="#dc2626" stroke-width="1.6"/><line data-edge="116" x1="472.57846153846157" y1="466" x2="697.0215384615385" y2="560" stroke="#16a34a" stroke-width="1.6"/><line data-edge="117" x1="739.003076923077" y1="596" x2="733.796923076923" y2="690" stroke="#16a34a" stroke-width="1.6"/><line data-edge="118" x1="732.7723076923077" y1="726" x2="732.6276923076923" y2="820" stroke="#16a34a" stroke-width="1.6"/><g data-node="closed" data-x="500" data-y="40" style="cursor:move"><rect x="500" y="40" width="71.2" height="36" rx="14" fill="#eef2ff" stroke="#8a8880" stroke-width="1.8"/><text x="535.6" y="62.55" font-size="13" text-anchor="middle" fill="#1d1d1b">CLOSED</text></g><g data-node="listen" data-x="394" data-y="240" style="cursor:move"><rect x="394" y="240" width="71.2" height="36" rx="14" fill="#eef2ff" stroke="#8a8880" stroke-width="1.8"/><text x="429.6" y="262.55" font-size="13" text-anchor="middle" fill="#1d1d1b">LISTEN</text></g><g data-node="synsent" data-x="700" data-y="310" style="cursor:move"><rect x="700" y="310" width="85.6" height="36" rx="14" fill="#eef2ff" stroke="#8a8880" stroke-width="1.8"/><text x="742.8" y="332.55" font-size="13" text-anchor="middle" fill="#1d1d1b">SYN-SENT</text></g><g data-node="synrcvd" data-x="120" data-y="310" style="cursor:move"><rect x="120" y="310" width="114.4" height="36" rx="14" fill="#eef2ff" stroke="#8a8880" stroke-width="1.8"/><text x="177.2" y="332.55" font-size="13" text-anchor="middle" fill="#1d1d1b">SYN-RECEIVED</text></g><g data-node="estab" data-x="376" data-y="430" style="cursor:move"><rect x="376" y="430" width="107.2" height="36" rx="14" fill="#eef2ff" stroke="#8a8880" stroke-width="1.8"/><text x="429.6" y="452.55" font-size="13" text-anchor="middle" fill="#1d1d1b">ESTABLISHED</text></g><g data-node="fw1" data-x="159" data-y="560" style="cursor:move"><rect x="159" y="560" width="100" height="36" rx="14" fill="#eef2ff" stroke="#8a8880" stroke-width="1.8"/><text x="209" y="582.55" font-size="13" text-anchor="middle" fill="#1d1d1b">FIN-WAIT-1</text></g><g data-node="fw2" data-x="159" data-y="690" style="cursor:move"><rect x="159" y="690" width="100" height="36" rx="14" fill="#eef2ff" stroke="#8a8880" stroke-width="1.8"/><text x="209" y="712.55" font-size="13" text-anchor="middle" fill="#1d1d1b">FIN-WAIT-2</text></g><g data-node="closing" data-x="400" data-y="640" style="cursor:move"><rect x="400" y="640" width="78.4" height="36" rx="14" fill="#eef2ff" stroke="#8a8880" stroke-width="1.8"/><text x="439.2" y="662.55" font-size="13" text-anchor="middle" fill="#1d1d1b">CLOSING</text></g><g data-node="closewait" data-x="690" data-y="560" style="cursor:move"><rect x="690" y="560" width="100" height="36" rx="14" fill="#eef2ff" stroke="#8a8880" stroke-width="1.8"/><text x="740" y="582.55" font-size="13" text-anchor="middle" fill="#1d1d1b">CLOSE-WAIT</text></g><g data-node="lastack" data-x="690" data-y="690" style="cursor:move"><rect x="690" y="690" width="85.6" height="36" rx="14" fill="#eef2ff" stroke="#8a8880" stroke-width="1.8"/><text x="732.8" y="712.55" font-size="13" text-anchor="middle" fill="#1d1d1b">LAST-ACK</text></g><g data-node="timewait" data-x="304" data-y="820" style="cursor:move"><rect x="304" y="820" width="92.8" height="36" rx="14" fill="#eef2ff" stroke="#8a8880" stroke-width="1.8"/><text x="350.4" y="842.55" font-size="13" text-anchor="middle" fill="#1d1d1b">TIME-WAIT</text></g><g data-node="closed2" data-x="697" data-y="820" style="cursor:move"><rect x="697" y="820" width="71.2" height="36" rx="14" fill="#eef2ff" stroke="#8a8880" stroke-width="1.8"/><text x="732.6" y="842.55" font-size="13" text-anchor="middle" fill="#1d1d1b">CLOSED</text></g><text x="472.5701051498932" y="199.01902772944337" font-size="11" text-anchor="start" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">passive OPEN / create TCB</text><text x="472.5701051498932" y="199.01902772944337" font-size="11" text-anchor="start" fill="#2563eb">passive OPEN / create TCB</text><path d="M442.2325051498932 241.63902772944337 L442.0048967708611 230.11016853064166 L451.9009132505192 235.35505726486048 z" fill="#2563eb" stroke="none"/><text x="647.976628844305" y="194.16919445725935" font-size="11" text-anchor="start" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">active OPEN / create TCB, snd SYN</text><text x="647.976628844305" y="194.16919445725935" font-size="11" text-anchor="start" fill="#2563eb">active OPEN / create TCB, snd SYN</text><path d="M731.7632955109716 307.86919445725937 L721.1839693969908 303.28179225404637 L730.0691816987663 296.4632145172763 z" fill="#2563eb" stroke="none"/><text x="582.6" y="276.2761813537676" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">SEND / snd SYN</text><text x="582.6" y="276.2761813537676" font-size="11" text-anchor="middle" fill="#2563eb">SEND / snd SYN</text><path d="M700 318.43422733077904 L688.9412412620329 321.7007629842558 L691.3841632251031 310.7704321437758 z" fill="#2563eb" stroke="none"/><text x="315.13537507812674" y="324.6557380709261" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv SYN / snd SYN,ACK</text><text x="315.13537507812674" y="324.6557380709261" font-size="11" text-anchor="middle" fill="#2563eb">rcv SYN / snd SYN,ACK</text><path d="M235.3353750781267 315.50898688233656 L243.5521373644276 307.4187942066073 L246.54533761443315 318.21141910805585 z" fill="#2563eb" stroke="none"/><text x="467.2" y="322.25" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv SYN / snd SYN,ACK</text><text x="467.2" y="322.25" font-size="11" text-anchor="middle" fill="#9333ea">rcv SYN / snd SYN,ACK</text><path d="M234.39999999999998 328 L244.48 322.4 L244.48 333.6 z" fill="#9333ea" stroke="none"/><text x="588.29" y="425.69865900383144" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv SYN,ACK / snd ACK</text><text x="588.29" y="425.69865900383144" font-size="11" text-anchor="middle" fill="#2563eb">rcv SYN,ACK / snd ACK</text><path d="M476.58000000000004 430 L483.9891952030168 421.1642642386956 L487.99633160270133 431.6228902418722 z" fill="#2563eb" stroke="none"/><text x="303.4" y="428.16299524564187" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv ACK of SYN / x</text><text x="303.4" y="428.16299524564187" font-size="11" text-anchor="middle" fill="#2563eb">rcv ACK of SYN / x</text><path d="M391.74 430 L380.231984556649 430.7293699716848 L385.041017336988 420.61437102370525 z" fill="#2563eb" stroke="none"/><text x="473.50749485010687" y="159.6609722705566" font-size="11" text-anchor="end" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">CLOSE / delete TCB</text><text x="473.50749485010687" y="159.6609722705566" font-size="11" text-anchor="end" fill="#9333ea">CLOSE / delete TCB</text><path d="M522.9674948501068 74.36097227055663 L523.195103229139 85.88983146935831 L513.2990867494809 80.64494273513952 z" fill="#9333ea" stroke="none"/><text x="651.972171155695" y="226.5108055427406" font-size="11" text-anchor="end" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">CLOSE / delete TCB</text><text x="651.972171155695" y="226.5108055427406" font-size="11" text-anchor="end" fill="#9333ea">CLOSE / delete TCB</text><path d="M546.6367044890284 78.13080554274063 L557.2160306030091 82.71820774595366 L548.3308183012336 89.53678548272367 z" fill="#9333ea" stroke="none"/><text x="313.26462492187324" y="262.85511771354294" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv RST (note 1) / x</text><text x="313.26462492187324" y="262.85511771354294" font-size="11" text-anchor="middle" fill="#9333ea">rcv RST (note 1) / x</text><path d="M393.06462492187325 264.50052183398674 L384.84786263557237 272.590714509716 L381.8546623855668 261.79808960826745 z" fill="#9333ea" stroke="none"/><text x="199.1" y="456.3" font-size="11" text-anchor="start" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">CLOSE / snd FIN</text><text x="199.1" y="456.3" font-size="11" text-anchor="start" fill="#dc2626">CLOSE / snd FIN</text><path d="M206.7104 560 L199.88323361107894 550.7071963811783 L210.99371139541864 549.2939436070102 z" fill="#dc2626" stroke="none"/><text x="319.3" y="478.52153218495016" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">CLOSE / snd FIN</text><text x="319.3" y="478.52153218495016" font-size="11" text-anchor="middle" fill="#dc2626">CLOSE / snd FIN</text><path d="M239.54461538461538 560 L245.38572668223014 550.0577759626491 L251.0719964792192 559.7069384027706 z" fill="#dc2626" stroke="none"/><text x="203" y="646.3000000000001" font-size="11" text-anchor="end" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv ACK of FIN / x</text><text x="203" y="646.3000000000001" font-size="11" text-anchor="end" fill="#dc2626">rcv ACK of FIN / x</text><path d="M209 690 L203.4 679.92 L214.6 679.92 z" fill="#dc2626" stroke="none"/><text x="329.5" y="594.9259339704605" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv FIN / snd ACK</text><text x="329.5" y="594.9259339704605" font-size="11" text-anchor="middle" fill="#dc2626">rcv FIN / snd ACK</text><path d="M400 644.3770634231104 L388.6402903993394 646.357820295788 L392.3168692813398 635.778464562832 z" fill="#dc2626" stroke="none"/><text x="258.89926153846153" y="662.0200000000001" font-size="11" text-anchor="start" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv FIN,ACK / snd ACK</text><text x="258.89926153846153" y="662.0200000000001" font-size="11" text-anchor="start" fill="#9333ea">rcv FIN,ACK / snd ACK</text><path d="M340.6107692307692 820 L330.875382512483 813.820303774018 L340.7144579488292 808.469360440559 z" fill="#9333ea" stroke="none"/><text x="257.2065230769231" y="815.4656152758133" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv FIN / snd ACK</text><text x="257.2065230769231" y="815.4656152758133" font-size="11" text-anchor="middle" fill="#dc2626">rcv FIN / snd ACK</text><path d="M330.82153846153847 820 L319.61092639723944 817.3002635047485 L327.19118005561285 809.0552799101793 z" fill="#dc2626" stroke="none"/><text x="400.79999999999995" y="751.3000000000001" font-size="11" text-anchor="start" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv ACK of FIN / x</text><text x="400.79999999999995" y="751.3000000000001" font-size="11" text-anchor="start" fill="#dc2626">rcv ACK of FIN / x</text><path d="M359.28 820 L358.7175233490691 808.4826209571293 L368.76174925854934 813.4377724058063 z" fill="#dc2626" stroke="none"/><text x="546.9" y="832.25" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">Timeout=2MSL / delete TCB</text><text x="546.9" y="832.25" font-size="11" text-anchor="middle" fill="#dc2626">Timeout=2MSL / delete TCB</text><path d="M697 838 L686.92 843.6 L686.92 832.4 z" fill="#dc2626" stroke="none"/><text x="584.8000000000001" y="484.1105025773196" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv FIN / snd ACK</text><text x="584.8000000000001" y="484.1105025773196" font-size="11" text-anchor="middle" fill="#16a34a">rcv FIN / snd ACK</text><path d="M697.0215384615385 560 L685.5607329004544 561.2713519933599 L689.8873234537733 550.9407850106658 z" fill="#16a34a" stroke="none"/><text x="742.4" y="646.3000000000001" font-size="11" text-anchor="start" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">CLOSE / snd FIN</text><text x="742.4" y="646.3000000000001" font-size="11" text-anchor="start" fill="#16a34a">CLOSE / snd FIN</text><path d="M733.796923076923 690 L728.7629148866224 679.6257452537551 L739.9457765533873 680.2451037460681 z" fill="#16a34a" stroke="none"/><text x="738.7" y="776.3000000000001" font-size="11" text-anchor="start" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv ACK of FIN / x</text><text x="738.7" y="776.3000000000001" font-size="11" text-anchor="start" fill="#16a34a">rcv ACK of FIN / x</text><path d="M732.6276923076923 820 L727.0432066088549 809.9113965545532 L738.2431933544406 809.9286273033927 z" fill="#16a34a" stroke="none"/><rect x="0" y="877" width="16" height="11" fill="#eef2ff" stroke="#555"/><text x="21" y="886.5" font-size="11" fill="#1d1d1b">A state IS a TCP connection state (RFC 9293 §3.3.2); the two CLOSED states are one state drawn twice — only this label says so</text><rect x="0" y="897" width="16" height="11" fill="#fff" stroke="#2563eb"/><text x="21" y="906.5" font-size="11" fill="#1d1d1b">Connection-setup transition — opening the connection (OPEN, SYN exchange, first ACK)</text><rect x="0" y="917" width="16" height="11" fill="#fff" stroke="#dc2626"/><text x="21" y="926.5" font-size="11" fill="#1d1d1b">Active-close path (typically the client) — calls CLOSE first: FIN-WAIT-1 → FIN-WAIT-2 / CLOSING → TIME-WAIT → CLOSED</text><rect x="0" y="937" width="16" height="11" fill="#fff" stroke="#16a34a"/><text x="21" y="946.5" font-size="11" fill="#1d1d1b">Passive-close path (typically the server) — receives the peer's FIN first: CLOSE-WAIT → LAST-ACK → CLOSED</text><rect x="0" y="957" width="16" height="11" fill="#fff" stroke="#9333ea" stroke-dasharray="6 4"/><text x="21" y="966.5" font-size="11" fill="#1d1d1b">Rare / simultaneous transition — simultaneous open or close, or a reset/abort (RST, close from a half-open state)</text></g><metadata id="figdown-source" data-sha256="57b42da67a86c0efb89d82ca6abe85c3fb27e364420cf2dbc7fbeb5682bc4522" data-engine-version="0.4.1"><![CDATA[
|
|
2
2
|
# FigDown — figures as text. Spec: https://github.com/FigDown/figdown
|
|
3
3
|
|
|
4
4
|
figdown 0.2 statechart
|
|
@@ -74,18 +74,18 @@ class server "Passive-close path (typically the server) — receives the peer's
|
|
|
74
74
|
class rare "Rare / simultaneous transition — simultaneous open or close, or a reset/abort (RST, close from a half-open state)" stroke=#9333ea style=dashed
|
|
75
75
|
|
|
76
76
|
# ── The 11 states (CLOSED drawn twice; see `IDENTITY-ASSERTION` note above) ────────
|
|
77
|
-
state closed "CLOSED"
|
|
78
|
-
state listen "LISTEN"
|
|
79
|
-
state synsent "SYN-SENT"
|
|
80
|
-
state synrcvd "SYN-RECEIVED"
|
|
81
|
-
state estab "ESTABLISHED"
|
|
82
|
-
state fw1 "FIN-WAIT-1"
|
|
83
|
-
state fw2 "FIN-WAIT-2"
|
|
84
|
-
state closing "CLOSING"
|
|
85
|
-
state closewait "CLOSE-WAIT"
|
|
86
|
-
state lastack "LAST-ACK"
|
|
87
|
-
state timewait "TIME-WAIT"
|
|
88
|
-
state closed2 "CLOSED"
|
|
77
|
+
state closed "CLOSED" class=states
|
|
78
|
+
state listen "LISTEN" class=states
|
|
79
|
+
state synsent "SYN-SENT" class=states
|
|
80
|
+
state synrcvd "SYN-RECEIVED" class=states
|
|
81
|
+
state estab "ESTABLISHED" class=states
|
|
82
|
+
state fw1 "FIN-WAIT-1" class=states
|
|
83
|
+
state fw2 "FIN-WAIT-2" class=states
|
|
84
|
+
state closing "CLOSING" class=states
|
|
85
|
+
state closewait "CLOSE-WAIT" class=states
|
|
86
|
+
state lastack "LAST-ACK" class=states
|
|
87
|
+
state timewait "TIME-WAIT" class=states
|
|
88
|
+
state closed2 "CLOSED" class=states
|
|
89
89
|
|
|
90
90
|
flow down
|
|
91
91
|
|
|
@@ -128,17 +128,46 @@ layout
|
|
|
128
128
|
# list than it used to be.
|
|
129
129
|
#
|
|
130
130
|
# The grid reproduces the CANONICAL Figure 5 composition, mirrored about
|
|
131
|
-
# one central vertical axis (x≈430, the shared centre of
|
|
132
|
-
#
|
|
131
|
+
# one central vertical axis (x≈430, the shared centre of LISTEN and
|
|
132
|
+
# ESTABLISHED):
|
|
133
133
|
# row0 CLOSED · row1 LISTEN · row2 SYN-RECEIVED | SYN-SENT (a mirrored
|
|
134
134
|
# pair) · row3 ESTABLISHED · row4 FIN-WAIT-1 | CLOSE-WAIT (same mirror)
|
|
135
|
-
# · row5 FIN-WAIT-2,
|
|
135
|
+
# · row4½ CLOSING · row5 FIN-WAIT-2, LAST-ACK · row6 TIME-WAIT, CLOSED
|
|
136
136
|
# (terminus, under LAST-ACK as the RFC draws it).
|
|
137
|
-
#
|
|
138
|
-
#
|
|
139
|
-
#
|
|
140
|
-
#
|
|
141
|
-
#
|
|
137
|
+
#
|
|
138
|
+
# COLUMN DISCIPLINE, AS IT ACTUALLY IS. This block used to
|
|
139
|
+
# claim four dead-vertical chains and only two of them were: measuring
|
|
140
|
+
# the centres found SYN-RECEIVED→FIN-WAIT-1 off by 32 px and
|
|
141
|
+
# CLOSE-WAIT→LAST-ACK off by 7 px, both of which had been read as
|
|
142
|
+
# vertical since the pins were written. A comment that names a chain the
|
|
143
|
+
# pins below it do not honour is worse than no comment, so this is the
|
|
144
|
+
# measured list and nothing else is claimed:
|
|
145
|
+
# DEAD VERTICAL FIN-WAIT-1→FIN-WAIT-2 (centre x 209 both)
|
|
146
|
+
# LAST-ACK→CLOSED (732.8 / 732.6)
|
|
147
|
+
# DEAD HORIZONTAL SYN-SENT→SYN-RECEIVED (centre y 328 both) — the
|
|
148
|
+
# simultaneous-open transition, across the mirrored pair
|
|
149
|
+
# NEAR, NOT DEAD CLOSE-WAIT→LAST-ACK (7.2 px), the passive-close column
|
|
150
|
+
# DELIBERATELY OFF-AXIS CLOSED (535.6) sits right of the LISTEN column
|
|
151
|
+
# (429.6), and CLOSING (439.2) right of TIME-WAIT (350.4)
|
|
152
|
+
# The last row is the 0.4 pin change and both offsets are load-
|
|
153
|
+
# bearing, not taste. CLOSED sat dead above LISTEN, which ran the
|
|
154
|
+
# CLOSED↔SYN-SENT diagonal pair straight through the `passive OPEN /
|
|
155
|
+
# create TCB` label on the CLOSED→LISTEN line; moving CLOSED right (and
|
|
156
|
+
# LISTEN 50 px down) gives each of `CLOSE / delete TCB`, `passive OPEN /
|
|
157
|
+
# create TCB` and `active OPEN / create TCB, snd SYN` its own line to
|
|
158
|
+
# belong to. CLOSING sat dead above TIME-WAIT, and that vertical ran
|
|
159
|
+
# through the `rcv FIN,ACK / snd ACK` label of the FIN-WAIT-1→TIME-WAIT
|
|
160
|
+
# diagonal (RFC Note 2's transition); lifting CLOSING up and right opens
|
|
161
|
+
# the channel that label needs. Measured: `layout-lint` lblcol 2→0 and
|
|
162
|
+
# F5 1→0, figure score 4→0.
|
|
163
|
+
# DROPPING FIN-WAIT-2 DEEPER WAS TRIED AND REJECTED. It is the obvious
|
|
164
|
+
# way to widen the same channel, and the measurement says it never is:
|
|
165
|
+
# across 150 combinations of CLOSING and TIME-WAIT positions taken at
|
|
166
|
+
# y=690 and y=700, FIN-WAIT-2 deeper is worse in 30 and better in NONE.
|
|
167
|
+
# What goes wrong is the neighbour: the FIN-WAIT-2→TIME-WAIT diagonal
|
|
168
|
+
# shortens onto its own `rcv FIN / snd ACK` label. At the pins used here
|
|
169
|
+
# it costs exactly one lblcol strike. FIN-WAIT-2 stays on row 5 at y=670.
|
|
170
|
+
# All meaning is in the transitions; this is layout, not knowledge.
|
|
142
171
|
#
|
|
143
172
|
# WHAT CHANGED, AND WHY THE TOP ROWS ARE WIDER.
|
|
144
173
|
# Hand-routed corridors used to sit below these pins: the active
|
|
@@ -159,15 +188,15 @@ layout
|
|
|
159
188
|
# anti-parallel fan-out is the language's answer to a same-pair transition, and
|
|
160
189
|
# the class colours (blue = setup, purple = rare) say which stroke is
|
|
161
190
|
# which.
|
|
162
|
-
pin closed at=(
|
|
163
|
-
pin listen at=(394,
|
|
191
|
+
pin closed at=(500,20)
|
|
192
|
+
pin listen at=(394,220)
|
|
164
193
|
pin synrcvd at=(120,290)
|
|
165
194
|
pin synsent at=(700,290)
|
|
166
195
|
pin estab at=(376,410)
|
|
167
196
|
pin fw1 at=(159,540)
|
|
168
197
|
pin closewait at=(690,540)
|
|
169
198
|
pin fw2 at=(159,670)
|
|
170
|
-
pin closing at=(
|
|
199
|
+
pin closing at=(400,620)
|
|
171
200
|
pin lastack at=(690,670)
|
|
172
201
|
pin timewait at=(304,800)
|
|
173
202
|
pin closed2 at=(697,800)
|
package/guide/expressing.md
CHANGED
|
@@ -13,8 +13,10 @@ portable figures: `block`, `bitfield`, `table` (plus the `UNIVERSAL-CORE-KEYWORD
|
|
|
13
13
|
Constructs marked EXPERIMENTAL — `threshold`, `band`, `bundle`,
|
|
14
14
|
`chart`, option keys
|
|
15
15
|
`extend=`/`data=`,
|
|
16
|
-
and genres `topology`, `flowchart`, `timing` (`CONSTRUCT-STATUS-TIERS`, spec §10)
|
|
17
|
-
|
|
16
|
+
and genres `topology`, `flowchart`, `timing` (`CONSTRUCT-STATUS-TIERS`, spec §10), plus the two
|
|
17
|
+
that arrived later on the same footing, `statechart` (`STATECHART-GENRE-SCOPE`, needs
|
|
18
|
+
`figdown 0.2`) and `sequence` (`SEQUENCE-GENRE-VOCABULARY`, needs `figdown 0.4`) — still parse
|
|
19
|
+
and are not deprecated, but they sit **outside** the v0.1 compatibility promise
|
|
18
20
|
and may change without a migration entry. **Do not use them when the figure
|
|
19
21
|
must be portable.** `path` and `routing` (with `points=`, `tailport=`,
|
|
20
22
|
`headport=`, `routing=`) were on that list until 0.1, when `EDGE-GEOMETRY-CONSTRUCTS`
|
|
@@ -49,7 +51,7 @@ is one place to look and nothing to reconcile.
|
|
|
49
51
|
|---|---|---|
|
|
50
52
|
| containment — node belongs inside a box | `group g "Label"` + `node n "…" in=g` | **`block` and `topology` only** — withdrawn from `flowchart` and `statechart` at 0.3 (`SCENE-KEYWORD-MEMBERSHIP`): no figure in the tree wrote one, and UML's word for the concept is *composite state*, not `group`. **The option key `in=` followed at 0.3 (`MEMBERSHIP-KEY-ACCEPTANCE`)** and is a named line error in those two genres: it named a `group` id and nothing else, so the `SCENE-KEYWORD-MEMBERSHIP` withdrawal left every value a dead end. Under `statechart` its spelling is additionally **RESERVED** — `in=` returns there with a `state`-id domain if UML 2.5.1 §14.2.3.4 composite states are earned. One level of nesting only (spec §2.2); for deeper, represent the inner group as a proxy node |
|
|
51
53
|
| set membership / category (color + legend) | `class c "meaning" fill=… style=…` + `class=c` on members | legend derives automatically; bare `fill=` carries no named meaning |
|
|
52
|
-
| one class used on both nodes and edges | `class c "meaning" fill=… stroke=…` — BOTH keys on the one class | Since 0.1 (`INTERIOR-LESS-ELEMENT-PAINT`) the rule is per CHANNEL: `fill=` paints members that have an interior (a node box) and is inapplicable to an edge, which has none; `stroke=` paints the edge line and a node's outline; `style=` applies to both. So one class still carries one meaning for both kinds of member — do NOT split it. A class an edge joins
|
|
54
|
+
| one class used on both nodes and edges | `class c "meaning" fill=… stroke=…` — BOTH keys on the one class | Since 0.1 (`INTERIOR-LESS-ELEMENT-PAINT`) the rule is per CHANNEL: `fill=` paints members that have an interior (a node box) and is inapplicable to an edge, which has none; `stroke=` paints the edge line and a node's outline; `style=` applies to both. So one class still carries one meaning for both kinds of member — do NOT split it. A class an edge joins must not declare `fill=` without `stroke=` (`INTERIOR-LESS-ELEMENT-PAINT`): on a line those two name the SAME channel, so the edge would otherwise lose its colour silently, and a `style=` beside the `fill=` does not answer what the author asked for. Declaring NO paint at all is legal on every member (`CLASS-CHANNEL-REACH`) — the class claims a meaning, the derived legend draws it with no swatch, and the edge keeps its default line. `fill=`, `stroke=` and `style=` are all NORMATIVE since 0.1 (`STROKE-KEY-STATUS`) |
|
|
53
55
|
| hierarchy / tree | directed `edge` chain; `flow down` to orient | the edges carry the tree; group is for spatial containment, not hierarchy |
|
|
54
56
|
| adjacency without a link | `in=` on the same `group`, no `edge` between them | the shared frame communicates co-location |
|
|
55
57
|
| cross-cutting category spanning groups | `class` + `class=` on elements in different groups | one class can mark nodes, edges, and fields across the whole document |
|
|
@@ -85,7 +87,8 @@ is one place to look and nothing to reconcile.
|
|
|
85
87
|
| event → action | `edge src -[event]-> tgt` | mid-label is the trigger; head-label can name the action |
|
|
86
88
|
| precedence / partial order | a DAG of directed edges | absence of an edge means no stated constraint |
|
|
87
89
|
| fan-out / fan-in | edges from/to a common node | AND-vs-XOR join discipline: declare a `class` (`FLOWCHART-GENRE-DESIGN` — no first-class gateway yet) |
|
|
88
|
-
| message exchange between parties |
|
|
90
|
+
| message exchange between parties, in time order | `figdown 0.4 sequence` — one `lifeline` per party, one `message` per exchange; the ladder's row order **is** declaration order | **The genre LANDED at 0.4 (`SEQUENCE-GENRE-VOCABULARY`), and this row's old advice retires with it**: nodes-as-parties plus `1:`/`2:` ordinal labels was the interim, and ordinals are naming, not semantics (`MEANING-RECOVERY-SOURCE`). Order is now structural — every message gets its own row, so no two share a span and nothing rides on a numbering convention. `state` puts a participant's condition on that participant's own lifeline, between two messages; `fragment` + `operand` say what kind of run a group of messages is (twelve UML operators, `type=` mandatory). It is **EXPERIMENTAL** and requires `figdown 0.4`, so a figure that must stay portable still writes the scene interim — and now does so as a *choice* it can state, not as a lack. See [spec/genres/experimental/sequence.md](../spec/genres/experimental/sequence.md) and [examples/sequence/](../examples/sequence/index.md) |
|
|
91
|
+
| a participant's condition at a point in an exchange | under `sequence`: `state <lifeline-id> "BOUND"`, written between the two messages it sits between (add `in=<fragment\|operand>` to put it inside a frame) | slot 1 **references** a lifeline and declares nothing; the quoted state name is mandatory. Row order places it — there is no time coordinate to write. This is the fact a scene genre plus a companion `table` could only carry as prose (`examples/showcase/tcp-handshake.fd`'s state table). One limit to know before you rely on it: a lifeline's state occurrences are **one sequence**, so two mutually exclusive operands cannot both end in a drawn `INIT` |
|
|
89
92
|
| a label too wide for its diamond / ellipse / cylinder | nothing — shapes size themselves from their **inscribed** area | do not declare an extent; see the note below |
|
|
90
93
|
|
|
91
94
|
> **Delete declared extents added to make a shape fit its text.** Non-rectangular
|
|
@@ -105,6 +108,54 @@ is one place to look and nothing to reconcile.
|
|
|
105
108
|
> document that still carries a `size` line gets a named migration diagnostic,
|
|
106
109
|
> not `unrecognized line`.
|
|
107
110
|
|
|
111
|
+
> **Choosing between `sequence` and `statechart` when many lines run between
|
|
112
|
+
> the same two blocks.** The symptom is identical in every scene genre —
|
|
113
|
+
> `block`, `flowchart` and `statechart` all crowd parallel edges into the one
|
|
114
|
+
> span between two boxes, and the reader sees confused overlap. What settles
|
|
115
|
+
> it is *what those lines are*:
|
|
116
|
+
>
|
|
117
|
+
> - **Time-ordered messages between one pair of participants → `sequence`.**
|
|
118
|
+
> The ladder spreads time down the page, so ten exchanges between A and B
|
|
119
|
+
> are ten rows on two lifelines and no two share a span. A figure like that
|
|
120
|
+
> is already a sequence; the scene genre is only where it was forced to
|
|
121
|
+
> live.
|
|
122
|
+
> - **Distinct transitions between states → `statechart`, and fix the
|
|
123
|
+
> layout.** Many edges returning to one state are different triggers with
|
|
124
|
+
> different meanings, not messages in an order. That crowding is a **layout**
|
|
125
|
+
> problem, not a genre problem, and the answer is
|
|
126
|
+
> [layout.md](layout.md), not a new header line.
|
|
127
|
+
>
|
|
128
|
+
> In one sentence: *are these lines messages between one pair over time, or
|
|
129
|
+
> transitions between states?* [`examples/sequence/dhcp-lease.fd`](../examples/sequence/dhcp-lease.fd)
|
|
130
|
+
> and [`examples/statechart/dhcp-client.fd`](../examples/statechart/dhcp-client.fd)
|
|
131
|
+
> are the same protocol answered both ways, which is the cheapest way to see
|
|
132
|
+
> the difference.
|
|
133
|
+
|
|
134
|
+
> **Three symptoms that ask you to CONFIRM the genre — and none of them
|
|
135
|
+
> decides it.** Each one means: go back to [authoring.md Step 2](authoring.md#step-2--pick-the-genre-main-standard-first)'s
|
|
136
|
+
> gate, ask the three questions again, and then either KEEP the figure where it
|
|
137
|
+
> is with the reason written down, or MOVE it. Confirming and keeping is a
|
|
138
|
+
> result; there is deliberately no lint on any of the three, because a symptom
|
|
139
|
+
> that fires on correct figures is not a rule.
|
|
140
|
+
>
|
|
141
|
+
> - **A hand-written `shape=diamond` with `yes`/`no` edges under a scene
|
|
142
|
+
> genre.** The full row, with the measured reason there is no lint and the
|
|
143
|
+
> two live instances that are right for opposite reasons, is in the
|
|
144
|
+
> [authoring.md pitfall table](authoring.md#field-tested-pitfalls-quick-reference)
|
|
145
|
+
> — read it there rather than twice.
|
|
146
|
+
> - **Ordinal mid-labels — `-[1: SYN]->`, `-[2: SYN-ACK]->`.** These are the
|
|
147
|
+
> sanctioned interim for time order under a scene genre and they are *naming,
|
|
148
|
+
> not semantics* (`MEANING-RECOVERY-SOURCE`; the rows above and the Known-limits entry below say
|
|
149
|
+
> so). Keeping them is the **deliberate-portability** pattern and it is only
|
|
150
|
+
> correct when the document SAYS so: a comment naming `sequence` as the genre
|
|
151
|
+
> not taken (it needs `figdown 0.4`) and stating that the numbers are a
|
|
152
|
+
> convention no parser reads. `examples/showcase/tcp-handshake.fd` is that
|
|
153
|
+
> pattern written out. Unstated ordinals are the failure case.
|
|
154
|
+
> - **Many parallel edges crowding one pair of boxes.** Settled by the boxed
|
|
155
|
+
> note immediately above — *messages between one pair over time* versus
|
|
156
|
+
> *distinct transitions between states* — and in the second case the answer
|
|
157
|
+
> is [layout.md](layout.md), not a new header line.
|
|
158
|
+
|
|
108
159
|
---
|
|
109
160
|
|
|
110
161
|
## Data & format
|
|
@@ -135,7 +186,7 @@ is one place to look and nothing to reconcile.
|
|
|
135
186
|
| threshold / watermark | `threshold "label" in=g offset=N%` on a `group` or `node` | spelled `guide` until 0.1 (`THRESHOLD-KEYWORD-SPELLING`). Label and the `%` are both mandatory; there is no `value=` and no `ref=` — the reference lives in the label (`THRESHOLD-VALUE-SCOPE`). `threshold` and `band` take the same two scopes (`AUTHORING-INTENT-OVER-RENDERING`). **EXPERIMENTAL** (`CONSTRUCT-STATUS-TIERS`), and **`block` only** since 0.3 (`SCENE-KEYWORD-MEMBERSHIP`). Even there, mind the irony the withdrawal turns on: in QoS a threshold is a queue depth **with a numeric value** (RFC 2309 `minth`/`maxth`, RFC 7567 — the very RFCs `THRESHOLD-KEYWORD-SPELLING` took the spelling from), while this one has no `value=` and its `offset=` is a fraction of the target's rendered extent, not a quantity |
|
|
136
187
|
| quantity comparison | `table` with numeric columns | `▁▃▅▇` Unicode blocks as sparklines in cells (`TABLE-SPARKLINE`) |
|
|
137
188
|
| signal values over time | `timing id "label"` + `signal name chars` (one char = one cycle) | lane alphabet: `0 1 p n x = .` (a strict subset of WaveDrom's; `2`–`9` retired at 0.1). `timing` is an **EXPERIMENTAL** genre (`CONSTRUCT-STATUS-TIERS`, spelled `wave` until 0.1) — the alphabet is settled, the surface around it is not |
|
|
138
|
-
| event ordering without exact times |
|
|
189
|
+
| event ordering without exact times | `figdown 0.4 sequence` — `message` declaration order **is** the order, and there are no times anywhere in the genre | vertical distance on a ladder carries no duration, so a delay or a timer belongs in the message label as prose. Under a scene genre the ordinal mid-label (`-[1: SYN]->`) remains the interim, and it remains a naming convention rather than semantics (`MEANING-RECOVERY-SOURCE`) — number consistently and say in a comment that you did |
|
|
139
190
|
| visual code / legend | `class` — legend derives automatically from declaration order | each `class` line gives swatch + meaning text |
|
|
140
191
|
| annotation explaining why — prose the **human** must see | `note="…"` on the element's OWN line: `node a "A" note="…"`, `group g "G" note="…"`, `edge a -> b note="…"`, `title "T" note="…"` (the figure-level one) | `figdown 0.3` (`DRAWN-ANNOTATION-FORM`). Attachment is by **syntactic position** — no id, no target key, so no ambiguity about which of several identically-labelled elements is meant. Not `description=`: the two divide by AUDIENCE — `description=` reaches the reading agent as an SVG `<title>` and puts **no ink** on the page, `note=` always draws. Both on one element is legal; neither is a fallback for the other. **You do not place the box** (`DOMAIN-CONVENTION-DIRECTIVES`): no `at=`, no `side=`; the engine sits it beside its carrier and takes a leader line only when adjacency fails. Refused on `field` (use `description=`) and on `cell`/`external`/`threshold`/`band`/`bundle`/`class` — zero measured demand (`plane` was on that list until `PAINT-ORDER-CONSTRUCT` withdrew the keyword itself). **Where a typed slot exists, a note is never the right answer**: a category is a `class` meaning, a containment is `in=`, a field's condition is `present=` |
|
|
141
192
|
| cross-references within a scene | `edge` + `class` naming the relation | can't reference a table cell or bitfield field — see Known limits `CELL-EDGE-ANCHORS` / `CROSS-BLOCK-REFERENCES` |
|
|
@@ -149,7 +200,8 @@ is one place to look and nothing to reconcile.
|
|
|
149
200
|
Each entry: what cannot be expressed today · OQ reference · sanctioned interim workaround.
|
|
150
201
|
|
|
151
202
|
- **same entity in two views** — no way to assert two nodes are the same participant; OQ pending; interim: shared `class` + a note stating the identity.
|
|
152
|
-
-
|
|
203
|
+
- ~~**strict message ordering**~~ — **SOLVED (`SEQUENCE-GENRE-VOCABULARY`)** by the `sequence` genre. A message's place in the ladder's row order *is* its place in time, so nothing rides on `1:`/`2:` label ordinals and a reading agent no longer answers *three links join the client and the server* where the truth is one association carrying three segments in time. **`MESSAGE-ORDER-AND-STATE` (spec §9) is CLOSED** — the closing condition it stated, *a genre landing that brings a ladder layout path with it*, is the one that was met, and the question is kept whole under its closure note. What genuinely remains open is not the genre's absence but **which surface a portable figure may use**: `sequence` is EXPERIMENTAL and requires `figdown 0.4`, so the two figures `MESSAGE-ORDER-AND-STATE` cites as evidence (`examples/showcase/tcp-handshake.fd`, `examples/showcase/arp-resolution.fd`) deliberately stay `figdown 0.1 topology` + a companion `table` and keep the ordinal interim behind an honest-limit comment. Interim, unchanged, for any figure that must stay on `figdown 0.1`: number labels consistently (`1: SYN`, `2: SYN-ACK`) and carry per-participant state in a second section.
|
|
204
|
+
- **the residual limits of `sequence` itself**, stated because the genre landing did not make them go away. A `message` is **one instant** — no separate send and receive, so no propagation delay and no two messages crossing on the wire. A `par` cannot re-order one chosen pair. A lifeline's `state` occurrences are **one sequence**, so two mutually exclusive operands cannot both end in a drawn `INIT`; the second carries the fact in `description=` instead. `ignore`/`consider` message sets and `loop` bounds live in the frame's label as prose a reader can quote and a parser cannot read, because `fragment` has no argument slot. And a **meaning-only `class`** — the sanctioned idiom for a message sent and never delivered, after `lost=` was refused (`UNDELIVERED-MESSAGE-MARKING`) — puts no ink on the page: the `.fd` reader learns which message was dropped and the `.svg` reader cannot. Every one of these is stated in the sources under `examples/sequence/`; the drawing-side ones are filed in decisions/registry.md.
|
|
153
205
|
- **cell anchors** — an `edge` cannot target a `table` cell or `bitfield` field; `CELL-EDGE-ANCHORS`; interim: whole-table relation + cell name in the edge label.
|
|
154
206
|
- **cross-block references** — no locator from one typed block to another, and no way to declare a composed region subordinate to a host element ("this table is about node X"); `CROSS-BLOCK-REFERENCES`; interim: prose note or a linking `edge` between the host nodes.
|
|
155
207
|
- **a repeat COUNT that names another field** — `index=` says a `bitfield` field repeats and gives the range, but the last index can only be prose when the count lives in another field (`index="0..Last Entry"`), because no value in the language may name a field; `BITFIELD-REPETITION-CONSTRUCT`'s surviving half, downstream of the locator problem `ANNOTATION-LOCATOR-SPLIT`; interim: write the prose end — the run is then honestly indeterminate, which is the correct reading, and say so in a `description=` or a `class` meaning.
|
package/guide/layout.md
CHANGED
|
@@ -12,6 +12,13 @@
|
|
|
12
12
|
> (`block`, `bitfield`, `table`) when the figure must be portable — see
|
|
13
13
|
> [authoring.md](authoring.md).
|
|
14
14
|
>
|
|
15
|
+
> **One genre this guide does not reach: `sequence`.** A ladder's two axes are
|
|
16
|
+
> both declaration order — columns are `lifeline` order, rows are
|
|
17
|
+
> `message` ∪ `state` order — so `flow` and `rank` are not words in that genre
|
|
18
|
+
> at all, and a `pin` parses and moves nothing. There is no rung to climb
|
|
19
|
+
> there: the edit is always to the source order. Everything below is about
|
|
20
|
+
> **scene** sections and the typed blocks beside them.
|
|
21
|
+
>
|
|
15
22
|
> Lessons come from field observation of a downstream authoring pass.
|
|
16
23
|
|
|
17
24
|
## 1. The two-zone mindset
|
|
@@ -58,7 +65,8 @@ define, redefine or extend a keyword inside the zone; `GENRE-VOCABULARY-OBLIGATI
|
|
|
58
65
|
words", does not reach in. That is what makes the default safe *for ever* and
|
|
59
66
|
what makes it usable: ONE enumeration of the members is correct under every
|
|
60
67
|
genre, so a reader may apply it without even resolving the header's genre
|
|
61
|
-
token. That enumeration is **core §10 (a′)**, it is NORMATIVE, and
|
|
68
|
+
token. That enumeration is **core §10 (a′)**, it is NORMATIVE, and
|
|
69
|
+
it has exactly **one** member — `pin`, NORMATIVE. `layout` is not a
|
|
62
70
|
member: it is the zone's OPENER and lives in the universal core of three
|
|
63
71
|
(§10 (a)) alongside `figdown` and `title`. The withdrawal of `path` and
|
|
64
72
|
`routing` left `LAYOUT-ZONE-NAMESPACE` whole and took its only experimental members with it.) If a
|
|
@@ -103,8 +111,11 @@ as the figure reads clearly.** The lowest rung that works is the right choice.
|
|
|
103
111
|
| 3 | `pin … at=(x,y)` / `pin … width= height=` | Topology/spatial where placement IS the message. One directive, three optional keys: `at=` places (nodes, groups, `external` endpoints), `width=`/`height=` extend (**nodes only** — groups, external endpoints and typed blocks size to their content). `size` was retired into `pin` at 0.1 (`ELEMENT-GEOMETRY-DIRECTIVE`). **This is the top rung** |
|
|
104
112
|
|
|
105
113
|
**Rung 1 is where authoring should begin** for **scene** sections (`block`,
|
|
106
|
-
or experimental `topology` / `flowchart`). A pure `bitfield` or
|
|
107
|
-
section usually has no `flow`/`rank`/`pin` — geometry follows content
|
|
114
|
+
or experimental `topology` / `flowchart` / `statechart`). A pure `bitfield` or
|
|
115
|
+
`table` section usually has no `flow`/`rank`/`pin` — geometry follows content,
|
|
116
|
+
and a `sequence` section has no rung at all (see the note at the top of this
|
|
117
|
+
guide): both its axes are declaration order, so the whole ladder is the
|
|
118
|
+
engine's and the only edit available is to the source order. For a
|
|
108
119
|
scene section, a `flow` line costs one line and gives the layout engine the
|
|
109
120
|
single most useful piece of intent it can receive. "Write nothing" (rung 0)
|
|
110
121
|
is reasonable only for a figure small enough that direction is obvious — or
|
|
@@ -329,11 +340,27 @@ like at scale. When the graph has a cycle, go to §9 and arrange it: explicit
|
|
|
329
340
|
arrangement is the expected cost of a cyclic figure, not a workaround for a
|
|
330
341
|
defect.
|
|
331
342
|
|
|
343
|
+
**A crowd of parallel edges may not be a layout problem at all — check the
|
|
344
|
+
genre before you tune.** When many lines run between the SAME pair of blocks, a
|
|
345
|
+
scene genre has one span to fan them into and no rung of the ladder changes
|
|
346
|
+
that: the crowding is in the shape of the figure, not in its arrangement. What
|
|
347
|
+
settles it is what those lines *are*. If they are **time-ordered messages
|
|
348
|
+
between two participants**, the figure is a ladder wearing a scene genre —
|
|
349
|
+
`sequence` (`figdown 0.4`, EXPERIMENTAL) gives every message its own row, so no
|
|
350
|
+
two share a span and nothing has to be tuned. If they are **distinct
|
|
351
|
+
transitions between states** — different triggers with different meanings,
|
|
352
|
+
several of them returning to one state — it is a `statechart` and the crowding
|
|
353
|
+
really is a layout problem, which is what §9 is for.
|
|
354
|
+
`examples/statechart/bfd-session.fd` is the second case and stays where it is;
|
|
355
|
+
`examples/sequence/dhcp-lease.fd` is the first, drawn as the ladder it always
|
|
356
|
+
was. Same protocol as `examples/statechart/dhcp-client.fd`, deliberately, so
|
|
357
|
+
the two answers can be compared on one subject.
|
|
358
|
+
|
|
332
359
|
## 7. Before / after: the same semantics, different layout zones
|
|
333
360
|
|
|
334
361
|
The first two entries are pairs, byte-identical in the content zone. The third is the counter-case: no pair, because the fix was not in the layout zone at all. In both pairs the **tuned** side is the top-level example itself (`examples/evpn-fabric.fd`, `examples/srl-evpn-irb.fd`) — only the *auto* variant needs its own file, since the tuned figure is the one the corpus already ships. 0.1 removed the duplicate copies that used to sit under `layout-compare/`; they were byte-identical to the originals and taught nothing a second time. Score = `cross×2 + thru×3 + novlp×3 + lblcol×2 + coinc×2`.
|
|
335
362
|
|
|
336
|
-
**Lint scores are a smoke alarm, not a judge.** The srl-evpn-irb
|
|
363
|
+
**Lint scores are a smoke alarm, not a judge.** The srl-evpn-irb entry below shows lint getting *worse* (ink/e 109→117) while the figure becomes dramatically more readable — and its auto arm has since stopped rendering at all, which no lint score would ever have told you — because the metrics do not measure group containment, overlap, or reading order. Always look at the render; the ladder ends when a human can read it. One variant of that example scored better on lint but had lost its column alignment — and the alignment was the peer signal; only looking at the render caught it.
|
|
337
364
|
|
|
338
365
|
### Leaf-spine fabric — `+flow down +rank sp1 sp2 +rank lf1 lf2 lf3`
|
|
339
366
|
|
|
@@ -346,16 +373,31 @@ Eight-node VXLAN/EVPN topology. Auto-layout scatters spines and leaves; three se
|
|
|
346
373
|
|
|
347
374
|
[auto .fd](../examples/layout-compare/evpn-fabric-auto.fd) · [auto .svg](../examples/layout-compare/evpn-fabric-auto.svg) · [tuned .fd](../examples/evpn-fabric.fd) · [tuned .svg](../examples/evpn-fabric.svg)
|
|
348
375
|
|
|
349
|
-
### srl-evpn-irb — two-level pins + groups (20 layout lines)
|
|
376
|
+
### srl-evpn-irb — two-level pins + groups (20 layout lines), and an auto arm that does not render
|
|
377
|
+
|
|
378
|
+
Sixteen-node EVPN-VXLAN IRB figure with three leaf groups. The tuned version pins each group as a layout module (spec §3 `PIN-COORDINATE-SCOPE`: a pinned group anchors its local origin in canvas px; members are group-local), giving three clean leaf boxes under the fabric overlay (1228×656 px).
|
|
379
|
+
|
|
380
|
+
**The auto arm has no artifact, and that is the result.** The engine guarantees that a `group` band contains only that group's members — the reader's rule is *inside the box is in the group*, so a band around a non-member states a membership the source never wrote. **Auto-layout cannot place these three groups' members contiguously.** Each leaf group's members land on different ranks, with the other groups' members and five hosts interleaved between them, so the band that has to enclose `leaf4`'s members ends up spanning most of the canvas — and no position the separation pass can reach clears every band at once. Reordering the source does not help: the ranks come from the fabric edges, not from the order the nodes are declared in. The engine therefore refuses the figure rather than drawing it:
|
|
381
|
+
|
|
382
|
+
```
|
|
383
|
+
$ node tools/build-svg.js examples/layout-compare/srl-evpn-irb-auto.fd
|
|
384
|
+
examples/layout-compare/srl-evpn-irb-auto.fd:
|
|
385
|
+
Line 25: group "leaf4" would enclose non-member "h2" and the layout pass could not separate them; the figure is not drawn rather than drawn wrongly. Give "h2" a pin outside the group, or add it with in=leaf4.
|
|
386
|
+
built 0 artifact(s) from 1 path argument(s) — 1 of 1 .fd file(s) FAILED and wrote nothing
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
(Which non-member gets named can differ between runs — several are enclosed, and the message reports the ones the pass gave up on. The refusal itself is the stable part.)
|
|
390
|
+
|
|
391
|
+
So the pair no longer compares two pictures. **It compares a picture with a refusal, and that is the sharper lesson:** for this topology the pinned arm is not a polish pass over a working auto layout, it is the only layout that exists. `pin` is what makes the figure renderable at all, and it stays that way until auto-layout learns **group-aware rank assignment** — placing a group's members in adjacent ranks so contiguous clustering can succeed (engine-backlog item 32). The `.fd` stays in the corpus as the one figure the containment guarantee cannot place; `node tools/artifact-check.js` reports it as `geometry-refused` and treats its *missing* `.svg` as the correct state.
|
|
350
392
|
|
|
351
|
-
|
|
393
|
+
The measurements below are the last ones taken before the refusal, and they are why the ratio mattered: lint ink/e got *worse* (109→117) while the figure became unambiguous, because the metrics never measured group containment or overlap — the very property the engine now enforces outright.
|
|
352
394
|
|
|
353
395
|
| variant | cross | novlp | ink/e | score |
|
|
354
396
|
|---------|-------|-------|-------|-------|
|
|
355
|
-
| auto
|
|
397
|
+
| auto (no longer renders) | 0 | 1 | 109 | 3 |
|
|
356
398
|
| `+pin` ×20 | 0 | 1 | 117 | 3 |
|
|
357
399
|
|
|
358
|
-
[auto .fd](../examples/layout-compare/srl-evpn-irb-auto.fd)
|
|
400
|
+
[auto .fd](../examples/layout-compare/srl-evpn-irb-auto.fd) (refused — no artifact) · [tuned .fd](../examples/srl-evpn-irb.fd) · [tuned .svg](../examples/srl-evpn-irb.svg)
|
|
359
401
|
|
|
360
402
|
### vxlan-encap — when layout tuning is the wrong fix (0 layout lines)
|
|
361
403
|
|
|
@@ -479,8 +521,10 @@ class that mutes the bundle so it recedes — `class discard "Discard reasons"
|
|
|
479
521
|
stroke=#b8b6b0 style=dashed` on the terminal-bound edges, used to good effect
|
|
480
522
|
by a corpus author. An edge is a line with no interior, so `stroke=` is the
|
|
481
523
|
channel that paints it; `fill=` paints only members that have an interior, and
|
|
482
|
-
a
|
|
483
|
-
`INTERIOR-LESS-ELEMENT-PAINT
|
|
524
|
+
a class joined by an edge that declares `fill=` with no `stroke=` is a line
|
|
525
|
+
error (spec/core.md §5, `INTERIOR-LESS-ELEMENT-PAINT`). A class that declares no paint at all is legal
|
|
526
|
+
— it claims a meaning and the edge keeps its default line — so mute the
|
|
527
|
+
bundle by writing the channel you want, not by omitting all of them.
|
|
484
528
|
|
|
485
529
|
**Use `rank` for a lateral bypass, not for the mainline.** Under `flow down` a
|
|
486
530
|
`rank` shares a *row*, so ranking the main chain flattens the figure sideways.
|
package/guide/showcase.md
CHANGED
|
@@ -25,6 +25,17 @@ carries it machine-readably, rather than letting it ride on geometry or
|
|
|
25
25
|
absence. Nested `table` under a single scene header is legacy, not the taught
|
|
26
26
|
path.
|
|
27
27
|
|
|
28
|
+
**A seventh figure family is missing from this page on purpose.** The
|
|
29
|
+
`sequence` genre (`SEQUENCE-GENRE-VOCABULARY`) draws the interaction ladders these
|
|
30
|
+
six cannot: time-ordered messages between participants, with each
|
|
31
|
+
participant's state on its own column and framed runs saying what kind of run
|
|
32
|
+
they are. It is **EXPERIMENTAL** and requires `figdown 0.4`; nothing below
|
|
33
|
+
declares a version later than `figdown 0.2`, which is where a reader deciding
|
|
34
|
+
whether to adopt the language actually has to judge it. Its two worked figures
|
|
35
|
+
are collected in
|
|
36
|
+
[examples/sequence/index.md](../examples/sequence/index.md), and the honest-limit
|
|
37
|
+
notes under §2 and §5 say exactly what they buy.
|
|
38
|
+
|
|
28
39
|
---
|
|
29
40
|
|
|
30
41
|
## 1. TCP header — bit-exact machine-readable layout (`bitfield`)
|
|
@@ -112,7 +123,8 @@ This is a **multi-section hybrid**: a `topology` scene section *and* a
|
|
|
112
123
|
9293 figure carries the per-endpoint state on the lifelines; the topology
|
|
113
124
|
genre has no lifeline-state construct, so the companion table section carries
|
|
114
125
|
those states machine-readably — multi-section composition is the main-standard
|
|
115
|
-
|
|
126
|
+
answer, and it is what a `figdown 0.1` document still writes now that the
|
|
127
|
+
`sequence` genre has landed (see the note below this section).
|
|
116
128
|
|
|
117
129
|
**Human sees:** two endpoints and three numbered segments — SYN out, SYN-ACK
|
|
118
130
|
back, ACK (with piggybacked data) out — with a state table below tracking each
|
|
@@ -129,10 +141,22 @@ endpoint's TCP state segment by segment.
|
|
|
129
141
|
row 2 of the state table (`1: SYN →`, Server state). Answerable only because
|
|
130
142
|
the companion table carries the RFC 9293 lifeline states.
|
|
131
143
|
|
|
132
|
-
> **Honest limit (stated in the source)
|
|
133
|
-
> label ordinals, not a first-class
|
|
134
|
-
>
|
|
135
|
-
>
|
|
144
|
+
> **Honest limit (stated in the source), and what changed under it.** Message
|
|
145
|
+
> *order* here rides on the 1/2/3 label ordinals, not on a first-class
|
|
146
|
+
> construct — `MEANING-RECOVERY-SOURCE` does not treat numbering as semantics — and per-endpoint
|
|
147
|
+
> state rides on the companion table. **The `sequence` genre landed at
|
|
148
|
+
> 0.4 (`SEQUENCE-GENRE-VOCABULARY`) and expresses both structurally**: a `message`'s place
|
|
149
|
+
> in the ladder's row order *is* its place in time, and a `state` occurrence
|
|
150
|
+
> sits on a lifeline between the two messages it falls between. This figure
|
|
151
|
+
> nonetheless stays as written, and the reason is worth stating: `sequence` is
|
|
152
|
+
> **EXPERIMENTAL** and requires `figdown 0.4`, while this figure is a
|
|
153
|
+
> `figdown 0.1` document that any released engine can render. So the
|
|
154
|
+
> interim above is now a **choice this document can defend**, not a gap it is
|
|
155
|
+
> waiting on. What the ladder does with an exchange of this shape is shown by
|
|
156
|
+
> the genre's own figures, collected in
|
|
157
|
+
> [examples/sequence/index.md](../examples/sequence/index.md) — a DHCP lease from
|
|
158
|
+
> acquisition to release, and all twelve interaction operators. See also
|
|
159
|
+
> [expressing.md](expressing.md), "message exchange between parties".
|
|
136
160
|
|
|
137
161
|
---
|
|
138
162
|
|
|
@@ -287,8 +311,12 @@ prose rather than on an edge of its own.
|
|
|
287
311
|
cache table (`before the exchange` → `(no entry for B's IP)`). Answerable only
|
|
288
312
|
because the companion table carries the before-state explicitly.
|
|
289
313
|
|
|
290
|
-
> **Honest limit
|
|
291
|
-
>
|
|
314
|
+
> **Honest limit, and a stated choice rather than a lack:**
|
|
315
|
+
> step order (1/2) rides on label ordinals, which `MEANING-RECOVERY-SOURCE` treats as naming and not
|
|
316
|
+
> as semantics. The `sequence` genre now expresses it structurally — see §2's
|
|
317
|
+
> note and [examples/sequence/](../examples/sequence/index.md) — but it is
|
|
318
|
+
> EXPERIMENTAL and needs `figdown 0.4`, and this figure stays on the frozen
|
|
319
|
+
> `figdown 0.1` surface on purpose.
|
|
292
320
|
|
|
293
321
|
---
|
|
294
322
|
|
|
@@ -306,18 +334,18 @@ class client "Active-close path (typically the client) — calls CLOSE first: F
|
|
|
306
334
|
class server "Passive-close path (typically the server) — receives the peer's FIN first: CLOSE-WAIT → LAST-ACK → CLOSED" stroke=#16a34a
|
|
307
335
|
class rare "Rare / simultaneous transition — simultaneous open or close, or a reset/abort (RST, close from a half-open state)" stroke=#9333ea style=dashed
|
|
308
336
|
|
|
309
|
-
state closed "CLOSED"
|
|
310
|
-
state listen "LISTEN"
|
|
311
|
-
state synsent "SYN-SENT"
|
|
312
|
-
state synrcvd "SYN-RECEIVED"
|
|
313
|
-
state estab "ESTABLISHED"
|
|
314
|
-
state fw1 "FIN-WAIT-1"
|
|
315
|
-
state fw2 "FIN-WAIT-2"
|
|
316
|
-
state closing "CLOSING"
|
|
317
|
-
state closewait "CLOSE-WAIT"
|
|
318
|
-
state lastack "LAST-ACK"
|
|
319
|
-
state timewait "TIME-WAIT"
|
|
320
|
-
state closed2 "CLOSED"
|
|
337
|
+
state closed "CLOSED" class=states
|
|
338
|
+
state listen "LISTEN" class=states
|
|
339
|
+
state synsent "SYN-SENT" class=states
|
|
340
|
+
state synrcvd "SYN-RECEIVED" class=states
|
|
341
|
+
state estab "ESTABLISHED" class=states
|
|
342
|
+
state fw1 "FIN-WAIT-1" class=states
|
|
343
|
+
state fw2 "FIN-WAIT-2" class=states
|
|
344
|
+
state closing "CLOSING" class=states
|
|
345
|
+
state closewait "CLOSE-WAIT" class=states
|
|
346
|
+
state lastack "LAST-ACK" class=states
|
|
347
|
+
state timewait "TIME-WAIT" class=states
|
|
348
|
+
state closed2 "CLOSED" class=states
|
|
321
349
|
|
|
322
350
|
flow down
|
|
323
351
|
|
|
@@ -419,14 +447,22 @@ arrow carrying its `event / action`.
|
|
|
419
447
|
|
|
420
448
|
## The honest limits, in one paragraph
|
|
421
449
|
|
|
422
|
-
Two figures depend on a convention
|
|
423
|
-
**message/step ordering** in the handshake and ARP is carried by
|
|
424
|
-
labels `1:`/`2:`/`3:`, which `MEANING-RECOVERY-SOURCE` treats as naming, not
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
450
|
+
Two figures depend on a convention `figdown 0.1` does not make first-class:
|
|
451
|
+
**message/step ordering** in the handshake and ARP is carried by
|
|
452
|
+
numbering edge labels `1:`/`2:`/`3:`, which `MEANING-RECOVERY-SOURCE` treats as naming, not
|
|
453
|
+
semantics, and the RFC 9293 handshake's **per-endpoint lifeline state**
|
|
454
|
+
(LISTEN, SYN-SENT, …) rides in a companion `table` section because the topology
|
|
455
|
+
genre has no construct for it. **The language itself has stopped lacking
|
|
456
|
+
both.** The `sequence` genre landed (`SEQUENCE-GENRE-VOCABULARY`) with a ladder
|
|
457
|
+
layout of its own: row order *is* time order, and a `state` occurrence sits on
|
|
458
|
+
its lifeline between the two messages it falls between. What keeps these two
|
|
459
|
+
figures as they are is not absence but **status** — `sequence` is EXPERIMENTAL
|
|
460
|
+
and requires `figdown 0.4`, and both figures are `figdown 0.1` documents any
|
|
461
|
+
released engine can render. So both limits are now stated choices, and the
|
|
462
|
+
genre's own worked figures are at
|
|
463
|
+
[examples/sequence/index.md](../examples/sequence/index.md). `MESSAGE-ORDER-AND-STATE` in spec §9
|
|
464
|
+
is CLOSED — the landing it asked for is the one that happened —
|
|
465
|
+
with the question kept whole under the closure note.
|
|
430
466
|
The Ethernet frame uses the **`BYTE-UNIT-PACKET-BLOCKS`** byte-unit workaround (single-row `table`,
|
|
431
467
|
not `bitfield`) so byte order rides on cell order, and one of its facts — the
|
|
432
468
|
FCS **coverage span** over a contiguous run of columns (DA through Payload) —
|