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.
@@ -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" shape=rounded class=states
78
- state listen "LISTEN" shape=rounded class=states
79
- state synsent "SYN-SENT" shape=rounded class=states
80
- state synrcvd "SYN-RECEIVED" shape=rounded class=states
81
- state estab "ESTABLISHED" shape=rounded class=states
82
- state fw1 "FIN-WAIT-1" shape=rounded class=states
83
- state fw2 "FIN-WAIT-2" shape=rounded class=states
84
- state closing "CLOSING" shape=rounded class=states
85
- state closewait "CLOSE-WAIT" shape=rounded class=states
86
- state lastack "LAST-ACK" shape=rounded class=states
87
- state timewait "TIME-WAIT" shape=rounded class=states
88
- state closed2 "CLOSED" shape=rounded class=states
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 CLOSED, LISTEN
132
- # and ESTABLISHED):
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, CLOSING, LAST-ACK · row6 TIME-WAIT, CLOSED
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
- # Column discipline: CLOSED→LISTEN, SYN-RECEIVED→FIN-WAIT-1→FIN-WAIT-2,
138
- # CLOSING→TIME-WAIT, CLOSE-WAIT→LAST-ACK→CLOSED run dead vertical; the
139
- # simultaneous-open transition SYN-SENT→SYN-RECEIVED runs dead horizontal
140
- # between the mirrored pair. All meaning is in the transitions; this is
141
- # layout, not knowledge.
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=(394,20)
163
- pin listen at=(394,170)
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=(311,670)
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)
@@ -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) still parse and
17
- are not deprecated, but they sit **outside** the v0.1 compatibility promise
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 MUST declare `stroke=` or `style=`: `fill=`-only (`INTERIOR-LESS-ELEMENT-PAINT`) and no-paint-at-all (`CLASS-PAINT-REQUIREMENT`) are both line errors, because the edge would otherwise lose its colour silently. `fill=`, `stroke=` and `style=` are all NORMATIVE since 0.1 (`STROKE-KEY-STATUS`) |
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 | nodes as parties + labelled directed edges; ordinal labels for ordering | strict ordering: number labels consistently (`FLOWCHART-GENRE-DESIGN`) — see Known limits |
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 | directed edges with ordinal mid-labels (`-[1: SYN]->`) | number labels consistently; no sequence genre yet |
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
- - **strict message ordering** — order carried only by label numbering convention; sequence genre candidate (v0.2, `FLOWCHART-GENRE-DESIGN`); interim: number labels consistently (e.g. `1: SYN`, `2: SYN-ACK`).
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 it has exactly **one** member — `pin`, NORMATIVE. `layout` is not a
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 `table`
107
- section usually has no `flow`/`rank`/`pin` — geometry follows content. For a
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 pair below shows lint getting *worse* (ink/e 109→117) while the figure becomes dramatically more readable — 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.
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
- Sixteen-node EVPN-VXLAN IRB figure with three leaf groups. Auto-layout lets group boxes overlap each other and member nodes escape their frames, producing a tall chaotic column (691×955 px). 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). Aspect ratio flips from portrait to landscape. Lint ink/e gets *worse* (109→117) while the figure becomes unambiguous the metrics do not measure group containment or overlap.
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 | 0 | 1 | 109 | 3 |
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) · [auto .svg](../examples/layout-compare/srl-evpn-irb-auto.svg) · [tuned .fd](../examples/srl-evpn-irb.fd) · [tuned .svg](../examples/srl-evpn-irb.svg)
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 `fill=`-only class joined by an edge is a line error (spec/core.md §5,
483
- `INTERIOR-LESS-ELEMENT-PAINT`/`CLASS-PAINT-REQUIREMENT`).
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
- interim until the sequence genre lands.
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):** message *order* rides on the 1/2/3
133
- > label ordinals, not a first-class construct — `MEANING-RECOVERY-SOURCE` does not treat numbering as
134
- > semantics. The v0.2 sequence genre (`FLOWCHART-GENRE-DESIGN`) closes this; see
135
- > [expressing.md](expressing.md), "strict message ordering".
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:** step order (1/2) rides on label ordinals, pending the v0.2
291
- > sequence genre (`FLOWCHART-GENRE-DESIGN`).
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" shape=rounded class=states
310
- state listen "LISTEN" shape=rounded class=states
311
- state synsent "SYN-SENT" shape=rounded class=states
312
- state synrcvd "SYN-RECEIVED" shape=rounded class=states
313
- state estab "ESTABLISHED" shape=rounded class=states
314
- state fw1 "FIN-WAIT-1" shape=rounded class=states
315
- state fw2 "FIN-WAIT-2" shape=rounded class=states
316
- state closing "CLOSING" shape=rounded class=states
317
- state closewait "CLOSE-WAIT" shape=rounded class=states
318
- state lastack "LAST-ACK" shape=rounded class=states
319
- state timewait "TIME-WAIT" shape=rounded class=states
320
- state closed2 "CLOSED" shape=rounded class=states
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 the language does not yet make first-class:
423
- **message/step ordering** in the handshake and ARP is carried by numbering edge
424
- labels `1:`/`2:`/`3:`, which `MEANING-RECOVERY-SOURCE` treats as naming, not semantics — the v0.2
425
- sequence genre (`FLOWCHART-GENRE-DESIGN`) will fix it, and the sources say so. Relatedly, the RFC
426
- 9293 handshake carries **per-endpoint lifeline state** (LISTEN, SYN-SENT, …)
427
- that the topology genre has no construct for; the companion state table section
428
- carries it as multi-section composition (`MULTI-FIGURE-DOCUMENTS` main-standard interim, again
429
- pending the sequence genre, `FLOWCHART-GENRE-DESIGN`).
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) —