figdown 0.1.8 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 888 984" width="888" 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="70" x1="433.1" y1="76" x2="433.1" y2="190" stroke="#2563eb" stroke-width="1.6"/><line data-edge="71" x1="452.7652886772431" y1="73.34906513439799" x2="724.2052886772431" y2="307.34906513439796" stroke="#2563eb" stroke-width="1.6"/><line data-edge="72" x1="465.20000000000005" y1="221.63984674329504" x2="700" y2="311.6015325670498" stroke="#2563eb" stroke-width="1.6"/><line data-edge="73" x1="395.5028227438559" y1="228.0864522267111" x2="216.56282274385592" y2="313.1609371712436" stroke="#2563eb" stroke-width="1.6"/><line data-edge="74" x1="700" y1="328" x2="234.39999999999998" y2="328" stroke="#9333ea" stroke-width="1.6" stroke-dasharray="6 4"/><line data-edge="75" x1="700" y1="344.3984674329502" x2="476.58000000000004" y2="430" stroke="#2563eb" stroke-width="1.6"/><line data-edge="76" x1="215.06" y1="346" x2="391.74" y2="430" stroke="#2563eb" stroke-width="1.6"/><line data-edge="79" x1="426.1" y1="190" x2="426.1" y2="76" stroke="#9333ea" stroke-width="1.6" stroke-dasharray="6 4"/><line data-edge="80" 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="81" 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="84" x1="179.4896" y1="346" x2="206.7104" y2="560" stroke="#dc2626" stroke-width="1.6"/><line data-edge="85" x1="399.05538461538464" y1="466" x2="239.54461538461538" y2="560" stroke="#dc2626" stroke-width="1.6"/><line data-edge="86" x1="209" y1="596" x2="209" y2="690" stroke="#dc2626" stroke-width="1.6"/><line data-edge="87" x1="228.55076923076922" y1="596" x2="330.64923076923077" y2="690" stroke="#dc2626" stroke-width="1.6"/><line data-edge="88" x1="218.78923076923076" y1="596" x2="340.6107692307692" y2="820" stroke="#9333ea" stroke-width="1.6" stroke-dasharray="6 4"/><line data-edge="89" x1="228.57846153846154" y1="726" x2="330.82153846153847" y2="820" stroke="#dc2626" stroke-width="1.6"/><line data-edge="90" x1="350.2276923076923" y1="726" x2="350.3723076923077" y2="820" stroke="#dc2626" stroke-width="1.6"/><line data-edge="91" x1="396.79999999999995" y1="838" x2="697" y2="838" stroke="#dc2626" stroke-width="1.6"/><line data-edge="94" x1="472.57846153846157" y1="466" x2="697.0215384615385" y2="560" stroke="#16a34a" stroke-width="1.6"/><line data-edge="95" x1="739.003076923077" y1="596" x2="733.796923076923" y2="690" stroke="#16a34a" stroke-width="1.6"/><line data-edge="96" 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="264.6" 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="264.6" 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="184.59906513439796" 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="184.59906513439796" 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="260.87068965517244" 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="260.87068965517244" 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="264.8736946989773" 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="264.8736946989773" 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="381.4492337164751" 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="381.4492337164751" 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="382.25" 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="382.25" 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="149.98" 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="149.98" 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="616.4875113227569" y="217.98093486560202" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">CLOSE / delete TCB</text><text x="616.4875113227569" y="217.98093486560202" 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="324.49997725614406" y="248.34288216314627" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv RST (note 1) / x</text><text x="324.49997725614406" y="248.34288216314627" 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="507.25" 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="507.25" 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="279.6" y="637.25" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv FIN / snd ACK</text><text x="279.6" y="637.25" 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="279.7" y="767.25" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv FIN / snd ACK</text><text x="279.7" y="767.25" 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="507.25" 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="507.25" 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 node IS a TCP state (RFC 9293 §3.3.2); the two CLOSED nodes 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="8c7cba9f05b9da4dfe03b8c3fe8cc1f6f8983fe67703351f442602c4d0f7157a" data-engine-version="0.1.8"><![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="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="264.6" 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="264.6" 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="184.59906513439796" 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="184.59906513439796" 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="260.87068965517244" 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="260.87068965517244" 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="264.8736946989773" 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="264.8736946989773" 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="381.4492337164751" 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="381.4492337164751" 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="382.25" 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="382.25" 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="149.98" 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="149.98" 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="616.4875113227569" y="217.98093486560202" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">CLOSE / delete TCB</text><text x="616.4875113227569" y="217.98093486560202" 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="324.49997725614406" y="248.34288216314627" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv RST (note 1) / x</text><text x="324.49997725614406" y="248.34288216314627" 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="507.25" 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="507.25" 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="279.6" y="637.25" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv FIN / snd ACK</text><text x="279.6" y="637.25" 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="279.7" y="767.25" font-size="11" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="3" stroke-linejoin="round">rcv FIN / snd ACK</text><text x="279.7" y="767.25" 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="507.25" 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="507.25" 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.0"><![CDATA[
2
2
  # FigDown — figures as text. Spec: https://github.com/FigDown/figdown
3
3
 
4
- figdown 0.1 flowchart
4
+ figdown 0.2 statechart
5
5
  title "TCP Connection State Machine (RFC 9293, Figure 5)"
6
6
 
7
7
  # ── What this figure is ─────────────────────────────────────────────
@@ -11,97 +11,119 @@ title "TCP Connection State Machine (RFC 9293, Figure 5)"
11
11
  # notation for "no action". This is the hardest showcase figure — it
12
12
  # answers the maintainer question "can FigDown fully express the TCP
13
13
  # state machine with its transitions and conditions?" — and the answer
14
- # it gives is: yes, every state and every labelled transition rides on
15
- # an edge, so a reading agent recovers the whole machine from the text.
14
+ # it gives is: yes, every state is a `state` line and every labelled
15
+ # transition is a `transition` line, so a reading agent recovers the
16
+ # whole machine from the text.
16
17
  #
17
- # HONEST LIMIT — state-ness is not yet first-class. FigDown has no
18
- # "state" genre in which a node IS a state as a machine-declarable fact
19
- # (that genre is the `GENRE-EARNING-THRESHOLD` §6 candidate; OQ tracks it). Here each state is
20
- # a `shape=rounded` node and the fact "this node is a protocol state" is
21
- # carried by the `states` class label, not by the genre. Interim, ruled.
18
+ # STATE-NESS IS FIRST-CLASS NOW, AND WAS NOT WHEN THIS FIGURE WAS
19
+ # WRITTEN. Until v0.2.0 this file declared `figdown 0.1 flowchart` and
20
+ # the fact "this node is a protocol state" was carried by the `states`
21
+ # class label rather than by the genre. `statechart` LANDED at
22
+ # 0.2 (`STATECHART-GENRE-SCOPE`) and took its own two words (`GENRE-NODE-SPELLING`)
23
+ # `state` and `transition`, whole from OMG UML 2.5.1 §14 — so the
24
+ # machine-declarable fact this figure once could not state, it now
25
+ # states. What follows is the ONE limit that survived that.
22
26
  #
23
27
  # HONEST LIMIT — the CLOSED identity (`IDENTITY-ASSERTION`). The canonical RFC figure
24
28
  # draws CLOSED TWICE — top (origin) and bottom (the terminus TIME-WAIT
25
29
  # and LAST-ACK return to) — and so do we, because taking every terminal
26
- # edge back to a single top node produced long lines that struck the
30
+ # transition back to a single top state produced long lines that struck the
27
31
  # setup-abort labels around CLOSED and made the figure unreadable. But
28
- # FigDown CANNOT declare two nodes to be the SAME entity: there is no
32
+ # FigDown CANNOT declare two elements to be the SAME entity: there is no
29
33
  # node-identity / alias construct (`IDENTITY-ASSERTION`). So `closed` and `closed2`
30
- # are two nodes that a human reads as one state only because the shared
31
- # `states` class label SAYS "the two CLOSED nodes are one state."
34
+ # are two states that a human reads as one only because the shared
35
+ # `states` class label SAYS "the two CLOSED states are one state drawn
36
+ # twice."
32
37
  # A reading agent sees two ids; the identity is asserted
33
38
  # in the label, not machine-declarable. This is the single fact this
34
39
  # figure cannot carry that the canonical drawing implies by reusing the
35
- # name — documented, not hidden.
40
+ # name — documented, not hidden. Concretely: this figure declares 12
41
+ # `state` lines and TCP has 11 states. Merging `closed2` into `closed`
42
+ # was TRIED and REJECTED — every terminal transition then ran the length of
43
+ # the canvas and struck the setup/abort labels around the single CLOSED,
44
+ # and the figure became unreadable. So this is evidence that the
45
+ # primitive is MISSING, not that a workaround is available.
46
+ #
47
+ # WHERE ELSE THIS ONE GAP IS FILED (`OPEN-QUESTION-CITATION-STATUS`) — one primitive, three faces:
48
+ # 1. spec/core.md §9 `IDENTITY-ASSERTION` — the MODEL-side statement, and still OPEN.
49
+ # 2. the project’s working record, ISO 5807 Connector row — the
50
+ # DRAWING of the same fact in genre flowchart, status unknown
51
+ # (ISO §9.4.1 was never read here). Not a second requirement.
52
+ # 3. this figure — the live instance.
53
+ # spec/genres/experimental/statechart.md says what a reader may and may
54
+ # not conclude from two identically-labelled states meanwhile. There is
55
+ # no UML 2.5.1 §14 clause to borrow for this: UML has no "same state
56
+ # drawn twice".
36
57
  #
37
58
  # HONEST LIMIT — RFC Note 2. The canonical Figure 5 OMITS the
38
59
  # FIN-WAIT-1 → TIME-WAIT transition and says so in its Note 2 (it occurs
39
- # when a FIN arrives that also ACKs our FIN). We DRAW it (edge fw1→tw),
60
+ # when a FIN arrives that also ACKs our FIN). We DRAW it (transition
61
+ # fw1→tw),
40
62
  # so this figure is strictly MORE complete than the canonical drawing
41
63
  # while carrying the same semantics the RFC prose states. Note 1 (rcv
42
64
  # RST → LISTEN applies only to a passively-opened SYN-RECEIVED) rides on
43
- # that edge's label.
65
+ # that transition's label.
44
66
 
45
67
  # ── Semantic classes — the meaning behind every stroke ──────────────
46
68
  # A reading agent queries these to group transitions by role; the
47
69
  # colour/dash is only presentation (`MEANING-RECOVERY-SOURCE`), the meaning is the label.
48
- class states "A node IS a TCP state (RFC 9293 §3.3.2); the two CLOSED nodes are one state drawn twice — only this label says so" fill=#eef2ff
70
+ class states "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" fill=#eef2ff
49
71
  class setup "Connection-setup transition — opening the connection (OPEN, SYN exchange, first ACK)" stroke=#2563eb
50
72
  class client "Active-close path (typically the client) — calls CLOSE first: FIN-WAIT-1 → FIN-WAIT-2 / CLOSING → TIME-WAIT → CLOSED" stroke=#dc2626
51
73
  class server "Passive-close path (typically the server) — receives the peer's FIN first: CLOSE-WAIT → LAST-ACK → CLOSED" stroke=#16a34a
52
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
53
75
 
54
76
  # ── The 11 states (CLOSED drawn twice; see `IDENTITY-ASSERTION` note above) ────────
55
- node closed "CLOSED" shape=rounded class=states
56
- node listen "LISTEN" shape=rounded class=states
57
- node synsent "SYN-SENT" shape=rounded class=states
58
- node synrcvd "SYN-RECEIVED" shape=rounded class=states
59
- node estab "ESTABLISHED" shape=rounded class=states
60
- node fw1 "FIN-WAIT-1" shape=rounded class=states
61
- node fw2 "FIN-WAIT-2" shape=rounded class=states
62
- node closing "CLOSING" shape=rounded class=states
63
- node closewait "CLOSE-WAIT" shape=rounded class=states
64
- node lastack "LAST-ACK" shape=rounded class=states
65
- node timewait "TIME-WAIT" shape=rounded class=states
66
- node closed2 "CLOSED" shape=rounded class=states
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
67
89
 
68
90
  flow down
69
91
 
70
92
  # ── Opening the connection (setup) ──────────────────────────────────
71
- edge closed -[passive OPEN / create TCB]-> listen class=setup
72
- edge closed -[active OPEN / create TCB, snd SYN]-> synsent class=setup
73
- edge listen -[SEND / snd SYN]-> synsent class=setup
74
- edge listen -[rcv SYN / snd SYN,ACK]-> synrcvd class=setup
75
- edge synsent -[rcv SYN / snd SYN,ACK]-> synrcvd class=rare
76
- edge synsent -[rcv SYN,ACK / snd ACK]-> estab class=setup
77
- edge synrcvd -[rcv ACK of SYN / x]-> estab class=setup
93
+ transition closed -[passive OPEN / create TCB]-> listen class=setup
94
+ transition closed -[active OPEN / create TCB, snd SYN]-> synsent class=setup
95
+ transition listen -[SEND / snd SYN]-> synsent class=setup
96
+ transition listen -[rcv SYN / snd SYN,ACK]-> synrcvd class=setup
97
+ transition synsent -[rcv SYN / snd SYN,ACK]-> synrcvd class=rare
98
+ transition synsent -[rcv SYN,ACK / snd ACK]-> estab class=setup
99
+ transition synrcvd -[rcv ACK of SYN / x]-> estab class=setup
78
100
 
79
101
  # ── Aborting a half-open connection (rare / reset) ──────────────────
80
- edge listen -[CLOSE / delete TCB]-> closed class=rare
81
- edge synsent -[CLOSE / delete TCB]-> closed class=rare
82
- edge synrcvd -[rcv RST (note 1) / x]-> listen class=rare
102
+ transition listen -[CLOSE / delete TCB]-> closed class=rare
103
+ transition synsent -[CLOSE / delete TCB]-> closed class=rare
104
+ transition synrcvd -[rcv RST (note 1) / x]-> listen class=rare
83
105
 
84
106
  # ── Active close — the endpoint that calls CLOSE first ──────────────
85
- edge synrcvd -[CLOSE / snd FIN]-> fw1 class=client
86
- edge estab -[CLOSE / snd FIN]-> fw1 class=client
87
- edge fw1 -[rcv ACK of FIN / x]-> fw2 class=client
88
- edge fw1 -[rcv FIN / snd ACK]-> closing class=client
89
- edge fw1 -[rcv FIN,ACK / snd ACK]-> timewait class=rare
90
- edge fw2 -[rcv FIN / snd ACK]-> timewait class=client
91
- edge closing -[rcv ACK of FIN / x]-> timewait class=client
92
- edge timewait -[Timeout=2MSL / delete TCB]-> closed2 class=client
107
+ transition synrcvd -[CLOSE / snd FIN]-> fw1 class=client
108
+ transition estab -[CLOSE / snd FIN]-> fw1 class=client
109
+ transition fw1 -[rcv ACK of FIN / x]-> fw2 class=client
110
+ transition fw1 -[rcv FIN / snd ACK]-> closing class=client
111
+ transition fw1 -[rcv FIN,ACK / snd ACK]-> timewait class=rare
112
+ transition fw2 -[rcv FIN / snd ACK]-> timewait class=client
113
+ transition closing -[rcv ACK of FIN / x]-> timewait class=client
114
+ transition timewait -[Timeout=2MSL / delete TCB]-> closed2 class=client
93
115
 
94
116
  # ── Passive close — the endpoint that receives the peer's FIN ───────
95
- edge estab -[rcv FIN / snd ACK]-> closewait class=server
96
- edge closewait -[CLOSE / snd FIN]-> lastack class=server
97
- edge lastack -[rcv ACK of FIN / x]-> closed2 class=server
117
+ transition estab -[rcv FIN / snd ACK]-> closewait class=server
118
+ transition closewait -[CLOSE / snd FIN]-> lastack class=server
119
+ transition lastack -[rcv ACK of FIN / x]-> closed2 class=server
98
120
 
99
121
  layout
100
122
  # ── Presentation only (`GUI-WRITEBACK-STRUCTURE`) ─────────────────────────────────────────
101
123
  # The strip test holds: delete every line below and the machine is
102
124
  # unchanged — all 11 states, all 21 transitions and their event/action
103
- # labels live in the `node`/`edge`/`class` lines above (closed2 is not
104
- # an orphan: it is the target of two terminal edges).
125
+ # labels live in the `state`/`transition`/`class` lines above (closed2
126
+ # is not an orphan: it is the target of two terminal transitions).
105
127
  # the layout namespace is `pin` alone, so "every line below" is a shorter
106
128
  # list than it used to be.
107
129
  #
@@ -114,8 +136,8 @@ layout
114
136
  # (terminus, under LAST-ACK as the RFC draws it).
115
137
  # Column discipline: CLOSED→LISTEN, SYN-RECEIVED→FIN-WAIT-1→FIN-WAIT-2,
116
138
  # CLOSING→TIME-WAIT, CLOSE-WAIT→LAST-ACK→CLOSED run dead vertical; the
117
- # simultaneous-open edge SYN-SENT→SYN-RECEIVED runs dead horizontal
118
- # between the mirrored pair. All meaning is in the edges; this is
139
+ # simultaneous-open transition SYN-SENT→SYN-RECEIVED runs dead horizontal
140
+ # between the mirrored pair. All meaning is in the transitions; this is
119
141
  # layout, not knowledge.
120
142
  #
121
143
  # WHAT CHANGED, AND WHY THE TOP ROWS ARE WIDER.
@@ -134,7 +156,7 @@ layout
134
156
  # ~90 px further out, which pushes the two pairs' label midpoints far
135
157
  # enough apart to read. Both pairs still run close together, exactly as
136
158
  # the LISTEN↔SYN-RECEIVED pair always has in this figure — the ±7 px
137
- # anti-parallel fan-out is the language's answer to a same-pair edge, and
159
+ # anti-parallel fan-out is the language's answer to a same-pair transition, and
138
160
  # the class colours (blue = setup, purple = rare) say which stroke is
139
161
  # which.
140
162
  pin closed at=(394,20)
@@ -11,18 +11,31 @@ Purpose: one-line lookup — "I need to show X → use Y." One row per intent. N
11
11
  portable figures: `block`, `bitfield`, `table` (plus the `UNIVERSAL-CORE-KEYWORDS` core keywords
12
12
  `figdown`/`title`/`layout` and the layout namespace's normative `pin`).
13
13
  Constructs marked EXPERIMENTAL — `threshold`, `band`, `bundle`,
14
- `plane`, `chart`, option keys
15
- `plane=`/`z-index=`/`extend=`/`data=`,
14
+ `chart`, option keys
15
+ `extend=`/`data=`,
16
16
  and genres `topology`, `flowchart`, `timing` (`CONSTRUCT-STATUS-TIERS`, spec §10) — still parse and
17
17
  are not deprecated, but they sit **outside** the v0.1 compatibility promise
18
18
  and may change without a migration entry. **Do not use them when the figure
19
19
  must be portable.** `path` and `routing` (with `points=`, `tailport=`,
20
- `headport=`, `routing=`) were on that list until this release, when `EDGE-GEOMETRY-CONSTRUCTS`
20
+ `headport=`, `routing=`) were on that list until 0.1, when `EDGE-GEOMETRY-CONSTRUCTS`
21
21
  **withdrew all six from the language**: removed, not renamed, so there is no
22
22
  row for them below and no replacement to point at. Edge geometry is the
23
- engine's; the need is filed as core §9 **`EDGE-IDENTITY-AND-GEOMETRY`**. The parser never warns; this index and §10 are the only
23
+ engine's; the need is filed as core §9 **`EDGE-IDENTITY-AND-GEOMETRY`**. **`plane` went the same way
24
+ (`PAINT-ORDER-CONSTRUCT`)**, taking `z-index=` and the `plane=` option key with it —
25
+ same shape, same absence of a replacement, so no row below either. What the one
26
+ authored figure used it for, `class` already did: stripping both writings from
27
+ `examples/evpn-fabric.fd` and rebuilding changed exactly one drawn markup token
28
+ — a `data-edge` index — and nothing else. The
29
+ parser never warns; this index and §10 are the only
24
30
  status sources. Top-level keywords are also **genre-allowlisted (`GENRE-KEYWORD-ALLOWLIST`)**:
25
- `node` under `figdown 0.1 bitfield` is an error, not a silent hybrid.
31
+ `node` under `figdown 0.1 bitfield` is an error, not a silent hybrid — and
32
+ (`SUBJECT-VOCABULARY-SCOPE`) the allowlist runs **per genre all the way down**. Only
33
+ `figdown`/`title`/`layout` are cross-genre; every other keyword belongs to one
34
+ genre's own namespace, and a spelling two genres share is two independent
35
+ declarations that happen to agree today, never one inherited. So the Notes
36
+ column below names the genres each construct is legal in: `group` under
37
+ `flowchart` and `external` under `statechart` are line errors (`SCENE-KEYWORD-MEMBERSHIP`) even
38
+ though both words are live elsewhere.
26
39
 
27
40
  **This file is the single intent index.** authoring.md Step 3 used to carry a
28
41
  second, partly-overlapping table; every intent it held now lives here, so there
@@ -34,21 +47,20 @@ is one place to look and nothing to reconcile.
34
47
 
35
48
  | I need to show… | Use | Notes |
36
49
  |---|---|---|
37
- | containment — node belongs inside a box | `group g "Label"` + `node n "…" in=g` | one level of nesting only (spec §2.2); for deeper, represent the inner group as a proxy node |
50
+ | 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 |
38
51
  | set membership / category (color + legend) | `class c "meaning" fill=… style=…` + `class=c` on members | legend derives automatically; bare `fill=` carries no named meaning |
39
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`) |
40
53
  | hierarchy / tree | directed `edge` chain; `flow down` to orient | the edges carry the tree; group is for spatial containment, not hierarchy |
41
54
  | adjacency without a link | `in=` on the same `group`, no `edge` between them | the shared frame communicates co-location |
42
55
  | cross-cutting category spanning groups | `class` + `class=` on elements in different groups | one class can mark nodes, edges, and fields across the whole document |
43
- | system boundary / inside vs outside | `external ext "label"` + edges to/from it; internal nodes in a `group` | `external` is never drawn as a shape — the edge ends open; it names an external I/O *endpoint*, not the frame drawn around a system (that is `group`) |
56
+ | system boundary / inside vs outside | `external ext "label"` + edges to/from it; internal nodes in a `group` | `external` is never drawn as a shape — the edge ends open; it names an external I/O *endpoint*, not the frame drawn around a system (that is `group`). **`block`, `topology` and `flowchart` only**: withdrawn from `statechart` at 0.3 (`SCENE-KEYWORD-MEMBERSHIP`) because UML 2.5.1 §14 already defines `external` as a `TransitionKind` (`external | internal | local`), and that reading is the one a statechart's reader arrives with. It takes **no option key at all** since `PAINT-ORDER-CONSTRUCT` removed `plane=`, its only one |
44
57
  | ownership zones / domain coloring | `class zone "Owner" fill=…` on a `group` or its members | assign to the group itself to color the frame |
45
58
  | a region the source drew as a **cloud** (the internet, a transit network, an overlay fabric) | `node net "The internet" shape=ellipse` (or a `group` when other elements sit inside it), plus a `class` when the distinction is one a reader must query | `shape=cloud` was **retired at 0.1** (`SHAPE-ENUM-VOCABULARY`) — it was the only value in a geometric enum that named a domain, which `SHAPE-ENUM-VOCABULARY` forbids. `ellipse` is what preserves the drawing; the label is what preserves the meaning, and only you know which one the figure needed |
46
59
  | conditional or optional element (standby link, optional component) | `class cond "Condition text" style=dashed` + `class=cond` on the element | `style=dashed` alone states nothing (`PRESENTATION-AS-MEANING-CARRIER`); write the condition in the class label |
47
60
  | one-level nesting limit | `in=` on `node`; `group … in=…` is a line error | for two levels: add a proxy `node` representing the inner group |
48
61
  | layer stack or spatial arrangement where order is knowledge | `edge` chain + `flow down`, or single-row `table`; state the order in prose | no spatial-arrangement construct yet — see Known limits `MEANINGFUL-ARRANGEMENT` |
49
62
  | slot map / position in a spatial grid | state positions in label text + `pin` in the layout zone | `pin` is geometry only, and the layout zone is ignored by default (`GENRE-NAMESPACE`) — use a `table` for anything a reader must count or address |
50
- | several links that are one logical thing (LAG, ES, trunk group) | `bundle b1 "LAG" a--c,b--c` — ONE comma-delimited token (the space form was retired at 0.1) | the dashed ring around the members is derived automatically; members resolve **as written** (`a--c` is not `c--a`). **EXPERIMENTAL** (`CONSTRUCT-STATUS-TIERS`) works unchanged; it is `topology` vocabulary and every corpus use of it is in a `topology` document |
51
- | an independent plane a reader can separate (overlay vs underlay, control vs data) | `plane overlay "VXLAN tunnels" z-index=2` + `plane=overlay` on its elements | **EXPERIMENTAL** (`CONSTRUCT-STATUS-TIERS`) — the keyword, `z-index=` and `plane=` alike; works unchanged. The plane's **label is the knowledge**; `z` is paint order (implicit `base` is model `z` = 0; an omitted `z-index=` takes the 1-based declaration index). Honest limit: `z` reorders only the annotation pass — edges, bundle rings, thresholds, bands — nodes and groups paint in document order whatever their plane says (spec §5) |
63
+ | several links that are one logical thing (LAG, ES, trunk group) | `bundle b1 "LAG" a--c,b--c` — ONE comma-delimited token (the space form was retired at 0.1) | the dashed ring around the members is derived automatically; members resolve **as written** (`a--c` is not `c--a`). **EXPERIMENTAL** (`CONSTRUCT-STATUS-TIERS`), and **`topology` only** since 0.3 (`SCENE-KEYWORD-MEMBERSHIP`): every corpus use of it was already in a `topology` document, and only there can it be defined by its referent — an IEEE 802.1AX LAG, an ECMP set, an EVPN Ethernet Segment — instead of as "a ring drawn round these links" |
52
64
  | same row / same column (peers, stages, siblings) | `rank a,b,c` — a **semantic** (content) line, before `layout`; ONE comma-delimited token (the space form was retired at 0.1) | under `flow down` a rank shares a row, so rank the lateral peers, not the mainline ([layout.md §8](layout.md#8-cautions-from-a-production-corpus)) |
53
65
  | cardinality, port name, or role at each end of a relationship | endpoint labels: `a [1] -[places]-> [N] b` | three label positions on one edge (tail · mid · head); `[flags[3:0]]` nests, `["…"]` for `\n` or unbalanced brackets. `label=`/`taillabel=`/`headlabel=` are retired options, not spellings |
54
66
  | a shape in the source figure that carries no text at all (a junction, an unlabelled multiplexer, a bare glyph) | an explicitly empty label: `node j "" shape=circle` | `""` is a WRITTEN value, recorded as `label: ""` and drawn blank. Omitting the label instead makes the renderer display the **id**, which is text the source does not have. Reserve the omitted form for a label you could not read, and say so in a `#` comment (spec §2.1/§12.3, `EMPTY-LABEL-STATE`) |
@@ -63,12 +75,12 @@ is one place to look and nothing to reconcile.
63
75
  | I need to show… | Use | Notes |
64
76
  |---|---|---|
65
77
  | ordered steps | directed `edge` chain; order = edge direction | `flow right` or `flow down` sets reading axis |
66
- | decision + branches | under `flowchart`: `decision q "…"` + `edge q -[yes]-> …` / `edge q -[no]-> …` | **Prefer `decision` over `node … shape=diamond`, because the next reader then has to know nothing** — a diamond has to be learned, a word is just read. And the convention is not reliable: of 216 question-labelled nodes in the production corpus, 78% are diamond, 14% ellipse, 8% carry no shape. Under `block`/`topology` the keyword does not exist, so `shape=diamond` + labelled edges remains the baseline (`SHAPE-ENUM-VOCABULARY`: geometry only) |
67
- | a step, a start or an end | under `flowchart`: `process p "…"` · `terminator t "…"` | Same reason. The geometry is DERIVED (box / rounded); `shape=` still works and changes only the drawing, never the role. A bare `node` under `flowchart` states NO role use it when the thing genuinely is not a step, a branch or an endpoint (a datastore, a wait, an annotation) |
78
+ | decision + branches | under `flowchart`: `decision q "…"` + `flowline q -[yes]-> …` / `flowline q -[no]-> …` | **Prefer `decision` over `node … shape=diamond`, because the next reader then has to know nothing** — a diamond has to be learned, a word is just read. And the convention is not reliable: of 216 question-labelled nodes in the production corpus, 78% are diamond, 14% ellipse, 8% carry no shape. Under `block`/`topology` the keyword does not exist, so `shape=diamond` + labelled edges remains the baseline (`SHAPE-ENUM-VOCABULARY`: geometry only) |
79
+ | a step, a start or an end | under `flowchart`: `process p "…"` · `terminator t "…"` | Same reason. The geometry is DERIVED (box / rounded); `shape=` still works and changes only the drawing, never the role. **Prefer a role; `node` is the FALLBACK, and it means exactly one thing: THE SOURCE DOES NOT STATE THE ROLE.** ISO 5807 is a drawing standard with no "unclassified", so a genuine stage always has a classification; FigDown separates role from geometry and can therefore record the absence instead of inventing one — the transcriber's case. **A symbol this genre cannot spell is a different matter: that is a COVERAGE GAP, not an unstated role.** Nine ISO stage symbols have no word here (Data, Stored data, Predefined process, Preparation, Manual operation, Manual input, Document, Parallel mode, Loop limit). For one of those, write `node`, **name the ISO symbol in a comment** on the same line (`node cfg "Read config" # ISO 5807 Data — no FigDown role`), and report the gap — the project’s working record keeps it |
68
80
  | an n-way dispatch on a value | one `decision` with ≥3 outgoing edges, each `[mid]`-labelled with the value that selects it | The single most under-marked control point in real figures. Label every exit — including the fallback (`[other]`). There is no `default`/`otherwise` keyword and none is planned (0 corpus uses) |
69
81
  | loop / retry | directed cycle back to an earlier node; condition in the mid-label | **the back-edge IS the loop** — there is no `loop`/`while` construct and none is planned (172 back-edges in the corpus, not one marking itself). But a cyclic graph needs explicit arrangement, not acceptance of an unreadable crossing ([layout.md §9](layout.md#9-cyclic-flows-why-the-ladder-stalls-and-what-to-do-instead)) |
70
82
  | error paths | `class err "Error path" style=dashed` + `class=err` on error edges | separate semantic category from the happy path |
71
- | state machine / lifecycle | nodes as states + labelled directed edges as transitions (`block`, or experimental `flowchart`) | planned experimental genre **`statechart`** (draft only not in engine yet; see decisions/registry.md); order meaning still rides on labels |
83
+ | state machine / lifecycle | `figdown 0.2 statechart` `state` per mode, labelled directed `transition`s between them | **`statechart` LANDED at `STATECHART-GENRE-SCOPE`**, and at `GENRE-NODE-SPELLING` it took its own two words (OMG UML 2.5.1 §14): `node`→`state`, `edge`→`transition`. It is EXPERIMENTAL, and reclassifying now rewrites every connector line, not just line 1 run `tools/migrate-figdown.js`. Use it when a node is a **mode the machine is in**; use `flowchart` when it is a step performed — a retry loop is a flowchart, whatever the title says. `block` stays the portable spelling for a `figdown 0.1` corpus. No `initial`/`final` vocabulary, and order still rides on labels. See [spec/genres/experimental/statechart.md](../spec/genres/experimental/statechart.md) |
72
84
  | pipeline stages | `node` per stage + `external` at the mouths + `flow right` + `rank` | `external` marks where data enters/leaves the figure |
73
85
  | event → action | `edge src -[event]-> tgt` | mid-label is the trigger; head-label can name the action |
74
86
  | precedence / partial order | a DAG of directed edges | absence of an edge means no stated constraint |
@@ -119,13 +131,13 @@ is one place to look and nothing to reconcile.
119
131
 
120
132
  | I need to show… | Use | Notes |
121
133
  |---|---|---|
122
- | proportion of a whole / fill level | `band "Headroom" 15..35% in=g fill=…` on a `group` or `node` | the quoted label is **mandatory** and comes **first** (`BAND-LABEL-STATUS`) — a band with no name asserts nothing; `band "X" 15%` = 0..15%. The label's colour is derived from the band's fill (`LABEL-COLOUR-SOURCE`); there is no key for it. **EXPERIMENTAL** (`CONSTRUCT-STATUS-TIERS`) |
123
- | 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`) |
134
+ | proportion of a whole / fill level | `band "Headroom" 15..35% in=g fill=…` on a `group` or `node` | the quoted label is **mandatory** and comes **first** (`BAND-LABEL-STATUS`) — a band with no name asserts nothing; `band "X" 15%` = 0..15%. The label's colour is derived from the band's fill (`LABEL-COLOUR-SOURCE`); there is no key for it. **EXPERIMENTAL** (`CONSTRUCT-STATUS-TIERS`), and **`block` only** since 0.3 (`SCENE-KEYWORD-MEMBERSHIP`) — under `topology` the word reads as a *frequency* band, which is the collision that withdrew it there |
135
+ | 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 |
124
136
  | quantity comparison | `table` with numeric columns | `▁▃▅▇` Unicode blocks as sparklines in cells (`TABLE-SPARKLINE`) |
125
137
  | 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 |
126
138
  | event ordering without exact times | directed edges with ordinal mid-labels (`-[1: SYN]->`) | number labels consistently; no sequence genre yet |
127
139
  | visual code / legend | `class` — legend derives automatically from declaration order | each `class` line gives swatch + meaning text |
128
- | annotation explaining why | `node note "…" style=dashed` + dashed edge to the target | no first-class callout yetsee Known limits `ROW-INDEX-GUTTER` |
140
+ | 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=` |
129
141
  | 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` |
130
142
  | units | state them in the label or column header | no machine-readable unit type; interim: text in the label |
131
143
  | trends / rates | `table` with a values column; `▁▃▅▇` for sparklines | charts are out of scope (`CHART-SCOPE-BOUNDARY`) — keep the raster + prose |
@@ -138,7 +150,6 @@ Each entry: what cannot be expressed today · OQ reference · sanctioned interim
138
150
 
139
151
  - **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.
140
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`).
141
- - **first-class callout / annotation** — a callout is structurally a node; `ROW-INDEX-GUTTER`; interim: `node note "…" style=dashed` + dashed `edge`.
142
153
  - **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.
143
154
  - **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.
144
155
  - **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.
@@ -148,10 +159,11 @@ Each entry: what cannot be expressed today · OQ reference · sanctioned interim
148
159
  - **mode-dependent field variants** — same bit range, different decode per mode; `BITFIELD-DISCRIMINATED-VARIANTS`; interim: separate labelled `bitfield` blocks + `description=`.
149
160
  - **multiplicity / machine-readable units** — no count or unit type; pending corpus frequency; interim: state them in label text.
150
161
  - **AND vs XOR fan-out** — `decision` (`flowchart` only) settles it for a decision's own exits: exactly one fires. For any OTHER fan-out — a `process` with several successors — the language still cannot say whether all branches fire or one does; `FLOWCHART-GENRE-DESIGN` sub-question; interim: declare a `class` naming the join discipline. `fork`/`join`/`merge` are recorded as excluded (0 corpus uses).
151
- - **swimlanes / partitions in a flowchart** — no container-with-an-axis construct; recorded as the next flowchart candidate (Mermaid #2028, UML `ActivityPartition`, BPMN `Lane`); interim: `group` + a label naming the lane, which loses the axis.
162
+ - **swimlanes / partitions in a flowchart** — no container-with-an-axis construct; recorded as the next flowchart candidate (Mermaid #2028, UML `ActivityPartition`, BPMN `Lane`). A swimlane partitions **across** the flow, by responsibility. The interim used to be `group` + a label naming the lane, which lost the axis; (`SCENE-KEYWORD-MEMBERSHIP`) `group` is not a `flowchart` keyword and (`MEMBERSHIP-KEY-ACCEPTANCE`) neither is `in=`, so the box interim is gone entirely — declare a `class` per partition and put `class=` on each stage, which earns a legend entry and applies to every member at once.
163
+ - **pipeline PHASES in a flowchart — a SIBLING of the row above, not the same gap** (`MEMBERSHIP-KEY-ACCEPTANCE`). **A phase is not a swimlane.** Visio ships the two as separate constructs on orthogonal axes: swimlanes (bands) name functional units — *who is responsible* — while **phases** (separators) cut **across all the lanes** to mark a stage boundary; a cross-functional flowchart routinely has both. UML's `ActivityPartition` is the actor-ish one, so it belongs to the swimlane row. A phase is **an ordered stage-partition ALONG the flow axis**. The demand is real and **was never measured**: the downstream flowchart survey counted 3266 nodes and 2684 edges across 227 deduped figures and **never counted containers at all**, so the evidence is thin on both sides. *Reopens on:* a count of downstream production parser specifications whose phases fail to read once rendered from `class`. Interim: a `class` per phase — complete on meaning, and its one residual loss (members are not guaranteed to be drawn adjacent or in phase order) is a **renderer** question filed in `decisions/registry.md` beside items 26/27, not a missing word.
152
164
  - **conditional presence in scene elements** — `present=` is a `bitfield`-only option key; `node a "A" present="..."` is a line error; <!-- fence-check: skip --> v0.2 candidate; interim: `class cond "condition text" style=dashed` + `class=cond`.
153
165
  - **mutually exclusive `bitfield` interpretations — a correctness trap, not a cosmetic one.** `break` is presentation-only and never reorders or skips bits, so alternative decodings of the *same* bits stacked with `break` are read by a machine as one long contiguous sequence: an 18-bit register drawn as eight alternative encodings computes as 144 bits. There is no union/case construct and nothing warns. Open question: what a variant/discriminator construct should look like (adjacent to `BITFIELD-DISCRIMINATED-VARIANTS`). Interim: **one `bitfield` block per alternative**, each labelled with the discriminator value that selects it (`bitfield ctl_a "Control — mode=0 (18 bits)" word=18`).
154
- - **aside / non-participating annotation**no node kind that comments on a figure without joining its graph; a free `node` parses but reads as a participant. Open question: whether an aside is a node kind or a document-level construct. Interim: prose beside the figure, or `node note "…" style=dashed` + a dashed `edge` (which does join the graph).
166
+ - ~~**first-class callout / annotation**~~ and ~~**aside / non-participating annotation**~~**SOLVED (`DRAWN-ANNOTATION-FORM`)** by `note=`, which is an attribute and therefore not a participant at all: the workaround it replaces (a detached dashed `node`) *was* structurally a node, so a reading agent counted it in the topology and mixed annotation text into architecture descriptions. What remains open is only the **spanning** case — one note about two or more elements, measured at 10.0% (corpus A) and 6.7% (corpus B), which an attribute cannot express. Interim, and it is the corpus's own: a **footnote marker** in the label text (`*`, `**`, `#`, `##`) with the explanation in a `note=` keyed to the same marker. Legal, drawn and readable today; its only loss is that the correspondence is not machine-readable.
155
167
  - **repeated-subgraph reuse** — no way to declare a sub-structure once and instantiate it *n* times. Open question: whether declare-once/instantiate-many belongs in the language at all or in the generator above it. Interim: write each instance out.
156
168
  - **two-level group nesting** — `group … in=…` is a line error; nesting is one level in v0.1. Open question: whether deeper nesting needs new syntax or only a renderer change. Interim: a proxy `node` for the inner group.
157
169
  - **mux / selector shape** — `shape=` is a closed geometric set (`box|rounded|circle|ellipse|diamond|cylinder`); `shape=mux` is a line error. Open question: whether the mux trapezoid is geometry (admissible under `SHAPE-ENUM-VOCABULARY`) or a domain noun (excluded). Interim: `shape=diamond` or a box, with the selector role in the label or a `class`.
package/guide/layout.md CHANGED
@@ -28,7 +28,7 @@ removed, not renamed, so there is no spelling to migrate to. See
28
28
  [spec/migrations.md](../spec/migrations.md) 0.1, core §9 **`EDGE-IDENTITY-AND-GEOMETRY`** for
29
29
  the requirement that survived them, and
30
30
  the project’s working record for the evidence, which is not published.)
31
- (The zone opener was spelled `render` before this release; that spelling is now a
31
+ (The zone opener was spelled `render` before 0.1; that spelling is now a
32
32
  line error, because the zone takes geometry, not presentation.)
33
33
 
34
34
  Key invariant (`GUI-WRITEBACK-STRUCTURE`, `MEANING-RECOVERY-SOURCE`): stripping every `pin` line
@@ -174,16 +174,16 @@ Wrap long chains: one `rank` per stage row, let auto-layout stack the rows.
174
174
  ### Decision flowchart — main path on one axis
175
175
 
176
176
  ```figdown
177
- figdown 0.1 flowchart
177
+ figdown 0.2 flowchart
178
178
  terminator start "Start"
179
179
  decision check "Header valid?"
180
180
  process proc "Process"
181
181
  terminator drop "Drop"
182
182
  terminator done "Done"
183
- edge start -> check
184
- edge check -[yes]-> proc
185
- edge check -[no]-> drop
186
- edge proc -> done
183
+ flowline start -> check
184
+ flowline check -[yes]-> proc
185
+ flowline check -[no]-> drop
186
+ flowline proc -> done
187
187
  flow down
188
188
  rank start,check,proc,done
189
189
  ```
@@ -285,7 +285,7 @@ pin tx at=(120,0)
285
285
  ```
286
286
  author semantics
287
287
  → build: node tools/build-svg.js X.fd
288
- → judge: eyeball + node tools/layout-lint.js X.svg (6 metrics; --max-score gate)
288
+ → judge: eyeball + node tools/layout-lint.js X.fd (6 metrics; --max-score gate)
289
289
  → if not clear: add ONE rung (§2) and repeat
290
290
  → stop when it reads well
291
291
  ```
@@ -443,9 +443,9 @@ paragraph is for.)
443
443
 
444
444
  **Long back-edges and bypasses read as detours — say what they are.** An edge
445
445
  that skips several ranks is routed through the gaps and keeps a bend only
446
- where something is actually in the way (it used to pick up
446
+ where something is actually in the way (`EDGE-BEND-RETENTION` — it used to pick up
447
447
  a bend per rank crossed and read as a staircase); but however clean the line,
448
- a reader who cannot tell *why* a line is out there reads it as noise. Until this release the taught answer was a hand-written waypoint; `path` is withdrawn
448
+ a reader who cannot tell *why* a line is out there reads it as noise. Until 0.1 the taught answer was a hand-written waypoint; `path` is withdrawn
449
449
  and there is no replacement, so the answer moves into the content zone, where
450
450
  it arguably belonged: name the bypass so the detour is legible as a bypass.
451
451
 
@@ -515,13 +515,13 @@ better (backlog item #4) makes a layered drawing tidier; it never turns it into
515
515
  a ring.
516
516
 
517
517
  There is a second cause, and it is in the language rather than the engine.
518
- Every flowchart edge today is a generic `edge`. The renderer cannot tell the
519
- mainline from an exception branch from a retry loop — and those distinctions
518
+ Every flowchart connector today is a plain `flowline` (spelled `edge` before 0.2, `GENRE-CONNECTOR-SPELLING` the rename gave the genre its own word, not a role). The
519
+ renderer cannot tell the mainline from an exception branch from a retry loop — and those distinctions
520
520
  are *exactly* what human flowchart routing conventions are made of.
521
521
  0.1 (`FLOWCHART-ROLE-KEYWORDS`) gave the genre role vocabulary for its NODES — `process`,
522
522
  `decision`, `terminator` — which is why the sketches below use it, and the
523
523
  renderer already consults it (a short branch marker sits near its
524
- `decision`, not near any diamond). **EDGE roles are still missing**
524
+ `decision`, not near any diamond). **CONNECTOR roles are still missing**
525
525
  (`mainline` / `exception` / `loop-back`, recorded in `LOGIC-FLOWCHART-GENRE-SCOPE` and excluded from
526
526
  the 0.1 tranche), so for routing the author still has to supply by
527
527
  arrangement what the source cannot state. `class main/retry/fail`, used
@@ -562,7 +562,7 @@ the axis. Note that it needs **no layout zone at all** — with the spine
562
562
  declared and the exits ranked off it, the figure lints at 0:
563
563
 
564
564
  ```figdown
565
- figdown 0.1 flowchart
565
+ figdown 0.2 flowchart
566
566
  title "Session establishment with bounded retry"
567
567
 
568
568
  class main "Mainline — the path a successful call takes" stroke=#555
@@ -579,12 +579,12 @@ terminator give "Give up"
579
579
  flow down
580
580
  rank ok,cnt
581
581
 
582
- edge start -> send class=main
583
- edge send -> ok class=main
584
- edge ok -[yes]-> done class=main
585
- edge ok -[no]-> cnt class=fail
586
- edge cnt -[yes]-> send class=retry
587
- edge cnt -[no]-> give class=fail
582
+ flowline start -> send class=main
583
+ flowline send -> ok class=main
584
+ flowline ok -[yes]-> done class=main
585
+ flowline ok -[no]-> cnt class=fail
586
+ flowline cnt -[yes]-> send class=retry
587
+ flowline cnt -[no]-> give class=fail
588
588
  ```
589
589
 
590
590
  Note what the `class` declarations are doing: they are not decoration and not a