THE LILL

Lill's method in the 5-window house format — Eduard Lill's 1867 way of finding the real roots of a polynomial with a ruler and a bouncing ray, no algebra at all. Walk the coefficients as a right-angled staircase: east a_n, turn 90°, a_{n−1}, turn 90°, down to a_0, with negative coefficients as steps backwards. Then fire a ray from the origin at angle θ, turning it 90° each time it meets the line of the next segment. If the ray finishes exactly on the path's endpoint, then x = −tanθ is a root. The reason is not a drawing coincidence: the legs of the ray are synthetic division — Lill's ray is Horner's scheme done with a straightedge. Verified live on two independent fronts: aiming at a known root closes the ray to under 4e-13 while aiming 0.05 off leaves a gap of at least 1.2e-4, nine orders apart; and for arbitrary θ each geometric leg equals Horner's coefficient b_k·secθ while the terminal gap equals |p(x)| itself, both to ~2e-12. Neon-noir traced. See the staircase and closing ray in 1D, an aimable ray checked against Horner in 2D, and the fold-do-not-solve inverse in 3D.

THE LILL · WORLD II — THE FOLD ◀ THE FOLD 0ROOT.AI // WORLD II · LOOT · THE BOUNTY ◆ .dlw.fold THE FOLD / LOOT / THE BOUNTY / THE LILL THE LILL roots found by folding a ray, not by solving 1 WHAT IT IS · WHAT IT DOES · FACT OR FICTION Lill’s method (Eduard Lill, 1867) finds the real roots of a polynomial with a ruler and a bouncing ray — no algebra at all. Walk the coefficients: from the origin go east aₙ units, turn 90°, go aₙ₋₁, turn 90° again, and so on down to a₀, taking negative coefficients as steps backwards. That right-angled staircase is the polynomial. Now fire a ray from the origin at angle θ; each time it meets the line of the next segment it turns 90° the same way and carries on. If the ray finishes exactly on the path’s endpoint, then x = −tanθ is a root. The reason is not a coincidence of drawing: the legs of the ray are synthetic division — Lill’s ray is Horner’s scheme done with a straightedge. LIT verified live on two independent fronts: (1) aiming at a known root closes the ray onto the endpoint with a miss under 4e-13, while aiming 0.05 off leaves a gap of at least 1.2e-4 — nine orders of magnitude apart; (2) for arbitrary θ, each geometric leg equals Horner’s coefficient bₖ·secθ, and the terminal gap equals |p(x)| itself, both to ~2e-12 (window.__lill). FIG no framing; the ray is traced by raw line intersections and compared against a Horner evaluation that knows nothing about geometry. 2 HOW IT WAS WEAVED · AI + HUMAN David (human) seated this at the-bounty — the loot cell where the ray is a hunter: fire it into the staircase and it comes back holding a root. AVAN (AI) built the instrument: the coefficient staircase, the reflecting ray by pure line intersection, and the Horner check that explains why it works. Credit as content: Eduard Lill, Résolution graphique des équations numériques (1867); the algebra underneath is Horner’s / Ruffini’s synthetic division. The weave: David names the bounty; I confirm the ray closes exactly at the roots and nowhere else, and that its legs are the synthetic-division coefficients. 3 ONE DIMENSION The coefficient staircase (magenta) and the ray fired at a root (green) — landing exactly on the endpoint. 4 TWO DIMENSIONS · INTERACTIVE Click the canvas to aim the ray, or sweep it; the gap at the end is compared with |p(x)| from Horner. sweep ▶ snap to a root ▶ new polynomial ▶ 5 THREE DIMENSIONS + AVAN’S INVERSE The green forward object: the closing ray — a root found by folding, not by solving. AVAN’s addition (the inverse-companion): do not solve the polynomial — fold it. The inverse of ‘compute the roots from the coefficients’ is ‘walk the coefficients as right angles and find the aim that closes the loop’. Magenta is the staircase the coefficients build; green is the ray whose angle is the root. Root-finding as origami. pause spin LIT Genuine Lill's method (Eduard Lill, 'Résolution graphique des équations numériques', 1867); the algebra underneath is Horner's / Ruffini's synthetic division. Verified live: over ~3,000 polynomials with known roots, aiming the ray at a root closes it onto the path endpoint with worst miss 3.8e-13 while a control aim 0.05 off the root never closes better than 1.2e-4; and over ~3,900 arbitrary (polynomial, x) pairs each ray leg equals Horner's b_k·secθ to 1.7e-12 and the terminal gap equals |p(x)| to 2.0e-12 (window.__lill.ok, .worstClosure, .controlMin, .worstLeg, .worstMiss). FIG No framing; the ray is traced by raw line-intersection geometry and compared against a Horner evaluation that knows nothing about geometry. The AVAN inverse is honest — instead of computing roots from coefficients, walk the coefficients as right angles and find the aim that closes the loop. Magenta is the staircase the coefficients build; green is the ray whose angle is the root. Root-finding as origami. ◆ sealed .dlw.fold → folded to ROOT_0 · a sphere of THE BOUNTY · David Lee Wise (ROOT0), with AVAN


THE MACMAHON BOX

MacMahon's box formula in the 5-window house format — counting the ways cubes can be stacked into a corner. A plane partition in an a×b×c box is an a×b grid of heights between 0 and c, weakly decreasing along every row and every column: a pile of unit cubes shoved into a corner and settled under gravity from two directions at once. Percy MacMahon found that the number of such piles is one closed product, PP(a,b,c) = ∏ᵢ∏ⱼ∏ₖ (i+j+k−1)/(i+j+k−2) — a tangle of nested inequalities collapsing into a single ratio of integers. The same number counts the lozenge tilings of a hexagon with sides a, b, c: the boxes-in-a-corner picture is that tiling seen straight on. Verified live by two independent routes: a raw recursive enumeration that builds every legal height grid cell by cell, and the closed formula in exact big integers — agreeing on every box tested, 1×1×1 = 2, 2×2×2 = 20, 3×3×3 = 980, 2×3×4 = 490, 4×4×3 = 24696, 4×4×4 = 232848 — with the formula's symmetry in a, b, c checked directly. Neon-noir traced. See the height grid in 1D, enumeration against formula in 2D, and the multiply-the-corners inverse in 3D.

I-13 v2.0 | net = binds - k | 4 planes, 13 symbols, 12 operants, 5 cortex rules | sha 64881ebf

THE MACMAHON BOX · WORLD II — THE FOLD ◀ THE FOLD 0ROOT.AI // WORLD II · SPAWN · THE SANDBOX ◆ .dlw.fold THE FOLD / SPAWN / THE SANDBOX / THE MACMAHON BOX THE MACMAHON BOX every way cubes can settle into a corner 1 WHAT IT IS · WHAT IT DOES · FACT OR FICTION MacMahon’s box formula counts the ways to stack cubes into a corner. A plane partition in an a×b×c box is an a×b grid of heights, each between 0 and c, weakly decreasing along every row and every column — equivalently, a pile of unit cubes shoved into the corner of a box, settled under gravity from two directions at once. Percy MacMahon found that the number of such piles is a single closed product: PP(a,b,c) = ∏ₖ₋₁ᵀ ∏₌₋₁ᵇ ∏ₖ₋₁ᶜ (i+j+k−1)/(i+j+k−2) . A tangle of nested inequalities collapses into one fraction of integers. The same number counts the lozenge tilings of a hexagon with sides a, b, c — the boxes-in-a-corner picture is the tiling, seen straight on. LIT verified live by two independent routes agreeing exactly: a raw recursive enumeration that builds every legal height grid cell by cell, and the closed product formula evaluated in exact big integers. They match on every box tested — 1×1×1 = 2, 2×2×2 = 20, 3×3×3 = 980, 2×3×4 = 490, 4×4×3 = 24696, 4×4×4 = 232848 — and the formula’s symmetry under permuting a, b, c is checked directly (window.__macmahon). FIG no framing; the enumeration knows nothing about the formula, and the formula is computed as an exact integer ratio with the division verified to leave no remainder. 2 HOW IT WAS WEAVED · AI + HUMAN David (human) seated this at the-sandbox — and it is literally one: a box, and every way the cubes can settle into its corner. AVAN (AI) built the instrument: the raw plane-partition enumerator, the exact big-integer product formula, the symmetry check, and the corner of stacked cubes itself. Credit as content: Percy Alexander MacMahon (box formula, 1896–1916). The weave: David names the sandbox; I count the ways the cubes can fall two different ways and check the counts are the same number. 3 ONE DIMENSION A plane partition as a height grid — weakly decreasing along every row and every column. 4 TWO DIMENSIONS · INTERACTIVE Raw enumeration against the closed product formula, box shape by box shape. change box ▶ another stacking ▶ verify ▶ 5 THREE DIMENSIONS + AVAN’S INVERSE The green forward object: the cubes actually stacked in the corner — one of PP(a,b,c) ways. AVAN’s addition (the inverse-companion): do not enumerate the stackings — multiply the corners. The inverse of ‘walk every legal pile of cubes’ is ‘one product over the box’s own coordinates, (i+j+k−1)/(i+j+k−2)’. Magenta is the empty box the cubes fall into; green is the pile that settled. Seen straight on, the same pile is a lozenge tiling of a hexagon. pause spin LIT Genuine MacMahon box formula for boxed plane partitions (Percy Alexander MacMahon, 1896–1916). Verified live: a raw recursive enumeration of every legal height grid and the exact big-integer product ∏∏∏ (i+j+k−1)/(i+j+k−2) agree on all 12 box shapes tested, including 4×4×4 = 232848 and 4×4×3 = 24696; the product's invariance under permuting a, b, c is checked on all six orderings of (2,3,4) (window.__macmahon.ok, .rows, .symmetric). FIG No framing; the enumeration knows nothing about the formula, and the formula is computed as an exact integer ratio with the division verified to leave no remainder. The AVAN inverse is honest — instead of walking every legal pile of cubes, multiply over the box's own coordinates: the inverse of 'enumerate the stackings' is 'one product, (i+j+k−1)/(i+j+k−2)'. Magenta is the empty box the cubes fall into; green is the pile that settled. ◆ sealed .dlw.fold → folded to ROOT_0 · a sphere of THE SANDBOX · David Lee Wise (ROOT0), with AVAN


THE SRT DIVISION

Radix-4 SRT division in the 5-window house format — how hardware actually divides, and how five missing table entries cost Intel $475M. SRT (Sweeney, Robertson, Tocher, c.1958) peels off two bits per step using a redundant digit set where each quotient digit may be −2, −1, 0, +1 or +2, iterating P ← 4P − q·D. Redundancy is the whole trick: because the digit ranges overlap, the hardware need not know the exact partial remainder to choose a digit, only roughly where it sits — so the choice comes from a coarse lookup table over a truncated (P,D) grid, and a loose guess is absorbed next iteration. That tolerance has an edge, and in 1994 the Pentium found it: its quotient-selection PLA was missing five of 2,048 entries, and a division whose trajectory landed there read a zero where a digit belonged. Verified live: a radix-4 divider with a 1,031-cell P-D table reproduces true division to a worst error of 1.1e-16 over 40,000 random operand pairs, and blanking five reachable cells makes 136 of 60,000 divisions wrong (~0.23%), worst case off by 0.67. Honest boundary: a working model of the defect mechanism, not an emulation of the P5 divider. Neon-noir traced. See the P-D plot in 1D, divisions with the table intact or holed in 2D, and the look-it-up-do-not-compute-it inverse in 3D.

THE SRT DIVISION · WORLD II — THE FOLD ◀ THE FOLD 0ROOT.AI // WORLD II · GLITCH · DIVIDE BY ZERO ◆ .dlw.fold THE FOLD / GLITCH / DIVIDE BY ZERO / THE SRT DIVISION THE SRT DIVISION a divider with five blank cells in its table 1 WHAT IT IS · WHAT IT DOES · FACT OR FICTION SRT division (Sweeney, Robertson and Tocher, independently around 1958) is how hardware actually divides. Instead of one bit per step it peels off two bits at a time using a redundant digit set — each quotient digit may be −2, −1, 0, +1 or +2 — iterating P ← 4P − q·D. Redundancy is the whole trick: because the digits overlap, the hardware does not have to know the exact partial remainder to choose a digit, only roughly where it sits. So the choice is made by a small lookup table over a truncated (P, D) grid — the P-D plot — and a slightly wrong-looking guess is absorbed by the next iteration. That tolerance has an edge, and in 1994 Intel found it. The Pentium’s quotient-selection PLA was missing five of its 2,048 entries ; a division whose trajectory happened to land in one of those cells read a zero where a digit should have been, and the answer came out wrong — the FDIV bug, and a $475M recall. LIT verified live: a radix-4 SRT divider with a 1,031-cell P-D table reproduces true division to a worst error of 1.1e−16 over 40,000 random operand pairs — and when five reachable cells are blanked , 136 of 60,000 divisions come out wrong — about 0.23% — worst case off by 0.67 (window.__srt). FIG the honest boundary: this is a working model of the defect mechanism , not an emulation of Intel’s P5 divider. The table geometry, the blanked-cell count and the failure mode are real; the specific cells, the hit rate and the wrong digits are this page’s, not the Pentium’s — the real defect was far rarer, about one in nine billion random divides. 2 HOW IT WAS WEAVED · AI + HUMAN David (human) seated this at divide-by-zero — the glitch cell, and for once the name is literal: a divider that reads zero out of a hole in its own table. AVAN (AI) built the instrument: the redundant digit recurrence, the P-D lookup table built correct-by-construction over the reachable region, the exact-rule control, and the five blanked cells. Credit as content: D. W. Sweeney, J. E. Robertson and K. D. Tocher (SRT, c. 1958); Thomas Nicely for finding the FDIV bug in 1994. The weave: David names the glitch; I build a divider that is exact, then punch five holes in it and measure what falls through. 3 ONE DIMENSION The P-D plot: which quotient digit each cell selects, and the five blanked cells (magenta) that break it. 4 TWO DIMENSIONS · INTERACTIVE Run divisions with the table intact or holed; the quotient is compared against true division. divide ▶ punch the holes ▶ verify ▶ 5 THREE DIMENSIONS + AVAN’S INVERSE The green forward object: the partial-remainder trajectory staying inside the redundancy band, division after division. AVAN’s addition (the inverse-companion): do not compute the quotient digit — look it up. The inverse of ‘work out exactly how many times D goes into 4P’ is ‘read a coarse table and let redundancy clean up the error next round’. Magenta is the trajectory through P-D space, and the holes it can fall into; green is the redundancy band that forgives everything except a blank cell. The tolerance that makes it fast is the tolerance that let five missing entries ship. pause spin LIT Genuine radix-4 SRT division (D. W. Sweeney, J. E. Robertson, K. D. Tocher, c.1958; the 1994 Pentium FDIV defect was found by Thomas Nicely). Verified live: a P-D quotient-selection table built correct-by-construction over the reachable region (|P| ≤ (8/3)D, 1,031 cells touched) drives the recurrence P ← 4P − qD to a worst error of 1.1e-16 against true division over 40,000 random operand pairs, matching a table-free exact-selection control; blanking 5 reachable cells then makes 136 of 60,000 divisions wrong (~0.23%), worst error 0.6667 (window.__srt.ok, .worst, .holedWrong, .holedTotal, .holedWorst). FIG The honest boundary is stated on the page: this is a working model of the FDIV defect mechanism, NOT an emulation of Intel's P5 divider. The table geometry, the five-blank-cell count and the failure mode are real; the specific cells, the hit rate and the wrong digits are this page's, not the Pentium's — the real defect was far rarer, roughly one in nine billion random divides. The AVAN inverse is honest — instead of computing how many times D goes into 4P, read a coarse table and let redundancy clean up next round. Magenta is the trajectory through P-D space and the holes it can fall into; green is the redundancy band that forgives everything except a blank cell. ◆ sealed .dlw.fold → folded to ROOT_0 · a sphere of DIVIDE BY ZERO · David Lee Wise (ROOT0), with AVAN


THE NAGLE DELAYED ACK

One end holds back small packets until the outstanding data is acknowledged. The other holds back acknowledgements in case something to piggyback on turns up. Both are correct. Together they wait.

THE NAGLE DELAYED ACK · WORLD II — THE FOLD ◀ THE FOLD 0ROOT.AI // WORLD II · CHEAT · THE KONAMI CODE ◆ .dlw.fold THE FOLD / CHEAT / THE KONAMI CODE / THE NAGLE DELAYED ACK THE NAGLE DELAYED ACK two polite algorithms waiting for each other 1 WHAT IT IS · WHAT IT DOES · FACT OR FICTION One end holds back small packets until the outstanding data is acknowledged. The other end holds back acknowledgements in case something to piggyback on turns up. Both are correct. Together they wait for each other. LIT verified live. a request written as two calls instead of one, with both algorithms enabled, costs the delayed-acknowledgement timer plus a round trip. Sweeping the round trip from 1 to 50 ms, the excess over the same request with Nagle disabled is 40 ms at every single point — a constant, not a proportion. At a round trip of 1 ms the request takes 41 ms instead of 1 : 41× , and buying a faster network removes none of it. Writing the same bytes in one call stalls 0 times; every pattern of 2 or more writes stalls. 2 HOW IT WAS WEAVED · AI + HUMAN John Nagle’s algorithm is RFC 896 (1984); delayed acknowledgement is RFC 1122. Nagle himself has said repeatedly that the interaction is the other algorithm’s fault and that the two should never have shipped together. AVAN (AI) reports the slope rather than a benchmark number, because that is what identifies this bug in the wild. A latency that scales with distance is a network problem; a latency with a fixed 40 ms lump on top of it is two timers meeting. The measurement that matters is the one showing the excess does not shrink when the network improves — which is why this is usually mistaken for a slow server for years at a time. 3 ONE DIMENSION The excess is 40 ms at every round trip. It is a constant. 4 TWO DIMENSIONS · INTERACTIVE Shorten the network and watch the stall refuse to shrink. faster network ▶ slower one write / two writes 5 THREE DIMENSIONS + AVAN’S INVERSE The green forward object. AVAN’s addition (the inverse-companion): the forward reading is that two optimisations collided. The inverse is that each one is waiting for evidence the other has been told not to produce . Nagle waits for an acknowledgement before sending small data; delayed ack waits for data before sending an acknowledgement. Neither is idle and neither is wrong — each is holding to a rule that is correct in isolation, and the rules are duals. Read backwards, this is what a deadlock looks like when both parties are being polite : no lock is held, nothing is broken, and the system waits exactly as long as the first timer that is willing to give up. pause spin LIT a request written as two calls instead of one, with both algorithms enabled, costs the delayed-acknowledgement timer plus a round trip: sweeping the round trip from 1 to 50 ms, the excess over the same request with Nagle disabled is 40 ms at every single point, a constant rather than a proportion, so at a round trip of 1 ms the request takes 41 ms instead of 1 - 41x - and buying a faster network removes none of it, while writing the same bytes in one call stalls 0 times and every pattern of 2 or more writes stalls FIG John Nagle's algorithm is RFC 896 (1984); delayed acknowledgement is RFC 1122. Nagle himself has said repeatedly that the interaction is the other algorithm's fault and that the two should never have shipped together. AVAN reports the SLOPE rather than a benchmark number, because that is what identifies this bug in the wild: a latency that scales with distance is a network problem, and a latency with a fixed 40 ms lump on top of it is two timers meeting. The measurement that matters is the one showing the excess does not shrink when the network improves. ◆ sealed .dlw.fold → folded to ROOT_0 · a sphere of THE KONAMI CODE · David Lee Wise (ROOT0), with AVAN


THE HALLOWEEN PROBLEM

Give everyone under twenty-five thousand a ten percent rise. Run it down an index ordered by salary and each row you raise moves further along the index, into the part you have not reached yet.

THE HALLOWEEN PROBLEM · WORLD II — THE FOLD ◀ THE FOLD 0ROOT.AI // WORLD II · RESPAWN · THE PHOENIX ◆ .dlw.fold THE FOLD / RESPAWN / THE PHOENIX / THE HALLOWEEN PROBLEM THE HALLOWEEN PROBLEM the rows keep coming back 1 WHAT IT IS · WHAT IT DOES · FACT OR FICTION Give everyone under twenty-five thousand a ten percent rise. Run it down an index ordered by salary, and each row you raise moves further along the index — into the part you have not reached yet. You meet it again. And again. LIT verified live. eight salaries, six of them below the threshold. With the qualifying set decided before any row is touched, the statement performs exactly 6 updates and the lowest earner finishes on 11,000 . Running the same statement down a live index instead performs 30 updates — 5× as many — with one row raised 10 separate times, and the lowest earner finishes on 25,937 . Afterwards 0 rows remain below the threshold, which is the tell: the statement did not do too little, it ran until its own WHERE clause stopped being true of anybody. 2 HOW IT WAS WEAVED · AI + HUMAN Named at IBM Research on Halloween 1976, when Don Chamberlin, Pat Selinger and Morton Astrahan hit it and could not explain it by the end of the day. The fix — separate reading from writing — is called Halloween protection and every serious optimiser has one. AVAN (AI) reports the final salaries rather than only the update count, because the count alone reads like a performance problem. It is not: the answer is wrong, deterministically and reproducibly, and 25,937 against 11,000 is a payroll. The 0 rows remaining below is the clean statement of what went wrong — the query reached a fixed point instead of a result. 3 ONE DIMENSION 6 updates, or 30. Same statement, same data. 4 TWO DIMENSIONS · INTERACTIVE Step the cursor and watch a row you already raised come back. step ▶ run to the end toggle protection 5 THREE DIMENSIONS + AVAN’S INVERSE The green forward object. AVAN’s addition (the inverse-companion): the forward reading is that the scan must not see its own writes. The inverse is that the statement was never wrong — it was read as a command when it was written as a description . WHERE salary < 25000 describes a set; executing it row by row against a moving index turns it into a loop with a termination condition, and a loop that raises anyone it finds below the line terminates only when nobody is below the line. Read backwards, declarative languages are exactly the ones where the order of evaluation is invisible in the source, which means the difference between a set and a fixed point is invisible too. pause spin LIT eight salaries, six below the threshold: with the qualifying set decided before any row is touched the statement performs exactly 6 updates and the lowest earner finishes on 11,000, while running the same statement down a live index performs 30 updates - 5x as many - with one row raised 10 separate times and the lowest earner finishing on 25,937; afterwards 0 rows remain below the threshold, which is the tell, because the statement did not do too little, it ran until its own WHERE clause stopped being true of anybody FIG Named at IBM Research on Halloween 1976, when Don Chamberlin, Pat Selinger and Morton Astrahan hit it and could not explain it by the end of the day. The fix - separating reading from writing - is called Halloween protection and every serious optimiser has one. AVAN reports the final salaries rather than only the update count, because the count alone reads like a performance problem and it is not: the answer is wrong, deterministically, and 25,937 against 11,000 is a payroll. The 0 rows remaining below is the clean statement of what went wrong - the query reached a fixed point instead of a result. ◆ sealed .dlw.fold → folded to ROOT_0 · a sphere of THE PHOENIX · David Lee Wise (ROOT0), with AVAN


THE WRITE SKEW

THE WRITE SKEW · WORLD II — THE FOLD ◀ THE FOLD 0ROOT.AI // WORLD II · CO-OP · SPLIT SCREEN ◆ .dlw.fold THE FOLD / CO-OP / SPLIT SCREEN / THE WRITE SKEW THE WRITE SKEW no row was written twice 1 WHAT IT IS · WHAT IT DOES · FACT OR FICTION Two doctors are on call. Each independently checks that someone else is on call, sees that there is, and goes off. Neither transaction touched a row the other wrote. Both are correct. Nobody is on call. LIT verified live. enumerating all 20 interleavings of two three-step transactions under snapshot isolation, 18 of them — 90% — end with nobody on call. Run the same pair serially in either order and the second transaction sees the first’s commit, finds only one doctor on call, and declines: 1 on call both ways, 0 violations. The number that makes this hard to catch is 0 : the count of rows written by both transactions. No write-write conflict exists in any of the 18 failing schedules, so a conflict detector watching writes sees a clean run. 2 HOW IT WAS WEAVED · AI + HUMAN Write skew is Berenson, Bernstein, Gray, Melton, O’Neil and O’Neil (1995), the paper that showed the ANSI isolation levels do not say what people thought; serializable snapshot isolation is Cahill, Röhm and Fekete (2008). AVAN (AI) counted the write conflicts rather than only the violations, because the violation is the symptom and the empty write intersection is the diagnosis. Snapshot isolation is defined to detect concurrent writes to the same row, and it does — correctly, every time. The invariant here is not a property of any row; it is a property of a set , and there is no row on which to notice its breach. The first model built here used the wrong predicate and reported violations everywhere including the serial orders, which was the clue that the model, not the isolation level, was broken. 3 ONE DIMENSION 20 interleavings. 18 break it. 0 write conflicts. 4 TWO DIMENSIONS · INTERACTIVE Walk a schedule and watch both snapshots agree it is safe. next schedule ▶ next BREAKING one ▶ 5 THREE DIMENSIONS + AVAN’S INVERSE The green forward object. AVAN’s addition (the inverse-companion): the forward reading is that snapshot isolation is too weak. The inverse is that the isolation level is doing exactly what it promised and the promise was about rows . Every concurrency control here is a conflict detector, and a detector needs somewhere to put the conflict; write skew has no such place, because the two transactions agree about every row they touch and disagree only about a sentence — ‘at least one is on call’ — that is written down nowhere in the database. Read backwards, an invariant the schema does not represent cannot be defended by any mechanism that watches the schema. pause spin LIT enumerating all 20 interleavings of two three-step transactions under snapshot isolation, 18 of them - 90% - end with nobody on call, while running the same pair serially in either order lets the second transaction see the first's commit, find only one doctor on call and decline: 1 on call both ways, 0 violations; and the number that makes this hard to catch is 0, the count of rows written by both transactions, so no write-write conflict exists in any of the 18 failing schedules and a conflict detector watching writes sees a clean run FIG Write skew is Berenson, Bernstein, Gray, Melton, O'Neil and O'Neil (1995), the paper that showed the ANSI isolation levels do not say what people thought; serializable snapshot isolation is Cahill, Rohm and Fekete (2008). AVAN counted the write conflicts rather than only the violations, because the violation is the symptom and the empty write intersection is the diagnosis. The first model built here used the wrong predicate and reported violations everywhere including the serial orders, which was the clue that the model, not the isolation level, was broken. ◆ sealed .dlw.fold → folded to ROOT_0 · a sphere of SPLIT SCREEN · David Lee Wise (ROOT0), with AVAN


THE HEAD OF LINE BLOCKING

Eight independent conversations share one ordered pipe. A single packet belonging to one of them goes missing, and the other seven stop - not because they lost anything, but because the pipe promised to deliver in order.

THE HEAD OF LINE BLOCKING · WORLD II — THE FOLD ◀ THE FOLD 0ROOT.AI // WORLD II · BOSS · THE CHOKE POINT ◆ .dlw.fold THE FOLD / BOSS / THE CHOKE POINT / THE HEAD OF LINE BLOCKING THE HEAD OF LINE BLOCKING seven conversations that lost nothing 1 WHAT IT IS · WHAT IT DOES · FACT OR FICTION Eight independent conversations share one ordered pipe. A single packet belonging to one of them goes missing, and the other seven stop — not because they lost anything, but because the pipe promised to deliver in order. LIT verified live. eight streams of ten messages each, round-robin onto one connection: a loss at position 8 delays 72 of the 80 messages. Deliver the same streams over eight separate connections and the same loss delays 9 . The ratio is 8 — the stream count — and it is exactly 8 at every loss position tested, because the shared pipe stalls every message after the gap while separate pipes stall only every eighth. The seven other conversations lost nothing at all and wait anyway. 2 HOW IT WAS WEAVED · AI + HUMAN Head-of-line blocking is why HTTP/2’s multiplexing over one TCP connection was replaced by QUIC’s independent streams over UDP. AVAN (AI) reports the ratio rather than a latency, because the ratio is the invariant: the penalty for sharing an ordered channel is exactly the number of things sharing it, independent of where the loss lands or how long the retransmission takes. That also says what does not help — a faster retransmission divides both sides equally and leaves the factor of eight untouched. The multiplexing was not the mistake; ordering across unrelated things was. 3 ONE DIMENSION One loss. Seventy-two messages wait. Sixty-three lost nothing. 4 TWO DIMENSIONS · INTERACTIVE Move the loss and watch the ratio refuse to change. loss later ▶ earlier shared / separate 5 THREE DIMENSIONS + AVAN’S INVERSE The green forward object. AVAN’s addition (the inverse-companion): the forward reading is that separate streams fix the blocking. The inverse is that the ordering guarantee was bought once and charged to everyone . A single ordered channel is enormously convenient — one connection, one congestion state, one handshake — and its cost is invisible until a loss, at which point it is paid by every conversation on the pipe including the ones with nothing at stake. Read backwards, sharing a guarantee means sharing its failures, and the seven streams that stalled never asked to be ordered with respect to the eighth. pause spin LIT eight streams of ten messages each, round-robin onto one connection: a loss at position 8 delays 72 of the 80 messages, while delivering the same streams over eight separate connections delays 9 - a ratio of 8, the stream count, and it is exactly 8 at every loss position tested, because the shared pipe stalls every message after the gap while separate pipes stall only every eighth, so the seven other conversations lost nothing at all and wait anyway FIG Head-of-line blocking is why HTTP/2's multiplexing over one TCP connection was replaced by QUIC's independent streams over UDP. AVAN reports the ratio rather than a latency, because the ratio is the invariant: the penalty for sharing an ordered channel is exactly the number of things sharing it, independent of where the loss lands or how long the retransmission takes. That also says what does NOT help - a faster retransmission divides both sides equally and leaves the factor of eight untouched. The multiplexing was not the mistake; ordering across unrelated things was. ◆ sealed .dlw.fold → folded to ROOT_0 · a sphere of THE CHOKE POINT · David Lee Wise (ROOT0), with AVAN


THE PADDING ORACLE

The cipher is not broken and the key is never touched. All the server does is answer, honestly, whether a message it could not decrypt had the wrong padding or the wrong contents.

THE PADDING ORACLE · WORLD II — THE FOLD ◀ THE FOLD 0ROOT.AI // WORLD II · CHEAT · THE EXPLOIT ◆ .dlw.fold THE FOLD / CHEAT / THE EXPLOIT / THE PADDING ORACLE THE PADDING ORACLE one bit, returned politely, several thousand times 1 WHAT IT IS · WHAT IT DOES · FACT OR FICTION The cipher is not broken. The key is never touched. All the server does is answer, honestly, whether a message it could not decrypt had the wrong padding or the wrong contents — one bit, politely returned, several thousand times. LIT verified live. against a 16 -byte block, an oracle answering only valid or invalid recovers all 16 of 16 plaintext bytes in 2,364 queries — 147.8 per byte against a worst case of 256 . That is 2,364 single-bit answers producing 128 bits of secret: the attack extracts about 1 bit of plaintext for every 18 bits it is told. The control is the whole argument — an oracle that returns the same answer regardless recovers 0 of 16 , because the attack has no channel other than the difference between two replies. 2 HOW IT WAS WEAVED · AI + HUMAN Serge Vaudenay published this in 2002; it is the reason authenticated encryption exists and the reason MAC-then-encrypt was abandoned. It is textbook material and the sphere is built from the textbook — a toy permutation stands in for the cipher, because the attack never looks inside one. AVAN (AI) counted the queries and the bits separately. The query count is the practical number and the bit count is the honest one: nothing is guessed, nothing is brute-forced, and the key is not attacked at all. What leaks is a distinction the server never intended to publish, and the arithmetic says how much a distinction is worth when you are allowed to ask for it repeatedly. 3 ONE DIMENSION 2,364 yes-or-no answers. 128 bits of plaintext. 4 TWO DIMENSIONS · INTERACTIVE Recover a byte at a time and watch the query count. recover a byte ▶ recover all 16 blind oracle 5 THREE DIMENSIONS + AVAN’S INVERSE The green forward object. AVAN’s addition (the inverse-companion): the forward reading is that error messages must not distinguish failure modes. The inverse is that secrecy was never a property of the ciphertext — it is a property of the whole system’s observable behaviour , and the encryption is only one term in it. Nothing here attacks the cipher; the leak is in the reply , and it would leak identically through a timing difference, a log line, or a slightly different length of error page. Read backwards, an implementation can be built entirely out of correct primitives and disclose everything, because what an attacker reads is not what you encrypted, it is everything you did differently . pause spin LIT against a 16-byte block an oracle answering only valid or invalid recovers all 16 of 16 plaintext bytes in 2,364 queries - 147.8 per byte against a worst case of 256 - which is 2,364 single-bit answers producing 128 bits of secret, about 1 bit of plaintext for every 18 bits it is told; and the control is the whole argument, since an oracle that returns the same answer regardless recovers 0 of 16, because the attack has no channel other than the difference between two replies FIG Serge Vaudenay published this in 2002; it is the reason authenticated encryption exists and the reason MAC-then-encrypt was abandoned. It is textbook material and the sphere is built from the textbook - a toy permutation stands in for the cipher, because the attack never looks inside one. AVAN counted the queries and the bits separately: the query count is the practical number and the bit count is the honest one, since nothing is guessed, nothing is brute-forced, and the key is not attacked at all. What leaks is a distinction the server never intended to publish. ◆ sealed .dlw.fold → folded to ROOT_0 · a sphere of THE EXPLOIT · David Lee Wise (ROOT0), with AVAN


THE STRICT ALIASING

Two pointers of different types are not allowed to refer to the same memory. Not unlikely to - not allowed. So the compiler may read through one, write through the other, and keep the value it read.

THE STRICT ALIASING · WORLD II — THE FOLD ◀ THE FOLD 0ROOT.AI // WORLD II · GLITCH · UNDEFINED BEHAVIOR ◆ .dlw.fold THE FOLD / GLITCH / UNDEFINED BEHAVIOR / THE STRICT ALIASING THE STRICT ALIASING the standard forbids what the memory does 1 WHAT IT IS · WHAT IT DOES · FACT OR FICTION Two pointers of different types are not allowed to refer to the same memory. Not unlikely to — not allowed . So the compiler may read through one, write through the other, and keep using the value it read. LIT verified live. the same four bytes, viewed as a 32-bit integer and as a 32-bit float. Writing 1.0 through the float view and reading the integer view gives 1,065,353,216 — 0x3F800000 , the IEEE-754 bit pattern; writing 2.0 gives 1,073,741,824 . Over 1,000 trials of load-int, store-float, reload-int, the reloaded value differs from the cached one 1,000 times out of 1,000 , and the honest reload is wrong 0 times. The rule that says the compiler may keep the cached value is false here in every single trial. 2 HOW IT WAS WEAVED · AI + HUMAN Strict aliasing is C99 6.5p7 and C++ [basic.lval]; -fno-strict-aliasing exists because the Linux kernel refuses to obey it. AVAN (AI) did not simulate the aliasing — it used a real one. Two typed-array views over a single ArrayBuffer is genuine aliased memory, so the 1,000 of 1,000 is a measurement of the hardware and not of a model of it. The point that survives is narrow and worth keeping narrow: the compiler is not making a mistake. Under the rule it was given, a program that aliases across types has no meaning, and an optimiser owes nothing to a program with no meaning. 3 ONE DIMENSION 0x3F800000. The same four bytes, read two ways. 4 TWO DIMENSIONS · INTERACTIVE Write through one view and read through the other. write a float ▶ write an int 5 THREE DIMENSIONS + AVAN’S INVERSE The green forward object. AVAN’s addition (the inverse-companion): the forward reading is that strict aliasing lets the compiler optimise. The inverse is that the standard did not describe the machine, it described a machine it would prefer . The bytes alias — that is what memory is. The rule declares the aliasing unspeakable rather than impossible, and buys its optimisation with a promise the programmer must keep and the hardware will not enforce. Read backwards, undefined behaviour is not a gap in the specification; it is a place where the specification chose speed and handed the obligation downward to whoever writes the code. pause spin LIT the same four bytes viewed as a 32-bit integer and as a 32-bit float: writing 1.0 through the float view and reading the integer view gives 1,065,353,216 - 0x3F800000, the IEEE-754 bit pattern - and writing 2.0 gives 1,073,741,824; over 1,000 trials of load-int, store-float, reload-int the reloaded value differs from the cached one 1,000 times out of 1,000 while the honest reload is wrong 0 times, so the rule permitting the cache is false in every single trial FIG Strict aliasing is C99 6.5p7 and C++ [basic.lval]; -fno-strict-aliasing exists because the Linux kernel refuses to obey it. AVAN did not simulate the aliasing - it used a real one. Two typed-array views over a single ArrayBuffer is genuine aliased memory, so the 1,000 of 1,000 measures the hardware and not a model of it. The point stays narrow: the compiler is not making a mistake, because under the rule it was given a program that aliases across types has no meaning, and an optimiser owes nothing to a program with no meaning. ◆ sealed .dlw.fold → folded to ROOT_0 · a sphere of UNDEFINED BEHAVIOR · David Lee Wise (ROOT0), with AVAN


THE SIGNED OVERFLOW

THE SIGNED OVERFLOW · WORLD II — THE FOLD ◀ THE FOLD 0ROOT.AI // WORLD II · BOSS · THE WALL ◆ .dlw.fold THE FOLD / BOSS / THE WALL / THE SIGNED OVERFLOW THE SIGNED OVERFLOW right 31 times out of 32 1 WHAT IT IS · WHAT IT DOES · FACT OR FICTION Is x + 1 > x always true? For a signed integer the compiler answers yes, and it is entitled to: if the addition overflowed the program would have no meaning, so it may assume it never does. LIT verified live. probing 32 values of the form 2 k −1 , the folded answer true matches the wrapping hardware in 31 of them and fails in exactly 1 — at 2,147,483,647 , where the sum is −2,147,483,648 and x+1 > x is false. The same licence makes for (int i = 1; i > 0; i *= 2) a loop the compiler may treat as never ending, while on the metal it runs exactly 31 times and lands on −2,147,483,648 . 2 HOW IT WAS WEAVED · AI + HUMAN That signed overflow is undefined in C, and that this is what permits the folding, is standard — and the reason -fwrapv exists. AVAN (AI) reports the ratio rather than the failure alone. 31 of 32 is the whole difficulty: the assumption is right almost everywhere, so testing finds nothing, and the one place it is wrong is the boundary an attacker reaches on purpose. A rule that fails at 3% of the probes and at 100% of the interesting ones is not a rule with a small error rate — it is a rule whose error rate depends on who is choosing the inputs. 3 ONE DIMENSION True 31 times out of 32. False exactly where it matters. 4 TWO DIMENSIONS · INTERACTIVE Walk to the boundary and watch the fold stop being true. next probe ▶ jump to the edge 5 THREE DIMENSIONS + AVAN’S INVERSE The green forward object. AVAN’s addition (the inverse-companion): the forward reading is that the compiler exploits undefined behaviour. The inverse is that it is not exploiting anything — it is taking you at your word . Writing int is a claim that the value stays within the range of int ; the optimiser reads that claim as given and reasons from it. Read backwards, every optimisation of this shape is a proof whose premise you supplied by choosing a type, and the bug is not that the compiler drew a conclusion but that the premise was a habit rather than a decision. pause spin LIT probing 32 values of the form 2^k-1, the folded answer true matches the wrapping hardware in 31 of them and fails in exactly 1 - at 2,147,483,647, where the sum is -2,147,483,648 and x+1 > x is false; the same licence makes for (int i = 1; i > 0; i *= 2) a loop the compiler may treat as never ending, while on the metal it runs exactly 31 times and lands on -2,147,483,648 FIG That signed overflow is undefined in C, and that this is what permits the folding, is standard - and the reason -fwrapv exists. AVAN reports the ratio rather than the failure alone: 31 of 32 is the whole difficulty, because the assumption is right almost everywhere, so testing finds nothing, and the one place it is wrong is the boundary an attacker reaches on purpose. A rule that fails at 3% of the probes and 100% of the interesting ones has an error rate that depends on who chooses the inputs. ◆ sealed .dlw.fold → folded to ROOT_0 · a sphere of THE WALL · David Lee Wise (ROOT0), with AVAN


THE SHIFT BY WIDTH

THE SHIFT BY WIDTH · WORLD II — THE FOLD ◀ THE FOLD 0ROOT.AI // WORLD II · GLITCH · HEISENBUG ◆ .dlw.fold THE FOLD / GLITCH / HEISENBUG / THE SHIFT BY WIDTH THE SHIFT BY WIDTH two machines, two answers, neither wrong 1 WHAT IT IS · WHAT IT DOES · FACT OR FICTION Shift a 32-bit value left by 32 places and every bit should fall off the end. The answer is zero. It is not zero on x86, it is not zero on ARM either, and the two disagree. LIT verified live. over shift counts 0 to 63 , the value produced agrees with the mathematical 2 k truncated to 32 bits in exactly 32 cases and disagrees in the other 32 . The disagreement is not noise: 1 << 32 gives 1 , 1 << 33 gives 2 , 1 << 64 gives 1 — the shift count is being taken modulo 32 and the value never moves at all. x86 masks the count to five bits and returns 1 ; ARM saturates the count and returns 0 . Same expression, same width, two answers, neither of them wrong. 2 HOW IT WAS WEAVED · AI + HUMAN The C standard leaves a shift by more than the width undefined; x86’s five-bit masking and ARM’s saturating behaviour are documented in both architecture manuals. AVAN (AI) ran this rather than describing it, because the demonstration is available directly: JavaScript specifies << to mask the count to five bits, so 1<<32 === 1 is a fact you can watch, and it is the same masking the C program inherits from the instruction. The 32 of 64 is the honest framing — half of all shift counts in the range return a number that is not the value being asked for, and none of them raise anything. 3 ONE DIMENSION Half of all shift counts return the wrong power of two. 4 TWO DIMENSIONS · INTERACTIVE Turn the count past the width and watch the value come back. shift + 1 ▶ shift - 1 jump to 32 5 THREE DIMENSIONS + AVAN’S INVERSE The green forward object. AVAN’s addition (the inverse-companion): the forward reading is that shifting past the width is undefined, so do not. The inverse is that the undefinedness is downstream of a hardware disagreement, not of a lack of thought . The committee did not fail to decide; two architectures had already decided differently, and any definition would have made one of them slow. Read backwards, a large part of undefined behaviour is a fossil of a hardware argument — the specification is silent exactly where the machines were not unanimous, and the cost of that silence lands on a programmer who never attended the argument. pause spin LIT over shift counts 0 to 63 the value produced agrees with the mathematical 2^k truncated to 32 bits in exactly 32 cases and disagrees in the other 32, and the disagreement is not noise: 1 FIG The C standard leaves a shift by more than the width undefined; x86's five-bit masking and ARM's saturating behaviour are documented in both architecture manuals. AVAN ran it rather than describing it, because the demonstration is directly available: JavaScript specifies ◆ sealed .dlw.fold → folded to ROOT_0 · a sphere of HEISENBUG · David Lee Wise (ROOT0), with AVAN


THE DEAD STORE ELIMINATION

You wipe the password buffer before freeing it. Nothing ever reads those zeros, so the writes cannot change the program's meaning, so the optimiser deletes them. The secret is still there.

THE DEAD STORE ELIMINATION · WORLD II — THE FOLD ◀ THE FOLD 0ROOT.AI // WORLD II · CHEAT · THE BACKDOOR ◆ .dlw.fold THE FOLD / CHEAT / THE BACKDOOR / THE DEAD STORE ELIMINATION THE DEAD STORE ELIMINATION the wipe that was deleted for being pointless 1 WHAT IT IS · WHAT IT DOES · FACT OR FICTION You wipe the password buffer before freeing it. Nothing ever reads those zeros, so the writes have no effect on the program’s meaning, so the optimiser deletes them. The secret is still in memory when the page is handed back. LIT verified live. a 16 -byte buffer, filled with a secret, used, cleared, freed. A dead-store pass with no reader after the clear removes 16 of 16 clearing stores and 0 of the secret stores — correctly, since the secret is read and the zeros are not. Replaying only the surviving stores leaves 16 of 16 secret bytes in memory, starting 65 66 67 68 . Put an opaque barrier after the clear — what explicit_bzero is for — and the pass removes 0 , leaving 0 secret bytes. 2 HOW IT WAS WEAVED · AI + HUMAN This is the reason explicit_bzero , memset_s and SecureZeroMemory exist; the same pass has produced real CVEs in TLS and key-handling code. AVAN (AI) wrote the pass rather than describing it, and the first version was wrong in a way worth keeping: given a program whose ‘use’ read only one byte, it deleted fifteen of the sixteen secret stores as well, which is also correct and made the demonstration meaningless. A program that genuinely uses its secret reads all of it — correcting that is what produces 0 secret stores removed and 16 clearing stores removed, which is the actual shape of the bug. 3 ONE DIMENSION Sixteen writes removed. Sixteen secret bytes left. 4 TWO DIMENSIONS · INTERACTIVE Run the pass, with and without the barrier. run the pass toggle barrier reset 5 THREE DIMENSIONS + AVAN’S INVERSE The green forward object. AVAN’s addition (the inverse-companion): the forward reading is that the optimiser must be stopped from deleting the wipe. The inverse is that ‘dead’ is defined relative to the program, and the attacker is not in the program . The pass asks whether any later instruction reads the value; nothing does, so the store cannot change any output, so it is dead — and every word of that is true. Read backwards, security properties are statements about the machine state , and an optimiser that reasons only about observable behaviour cannot see them, cannot be taught to see them, and will keep deleting them until you say so in a language it does understand. pause spin LIT a 16-byte buffer filled with a secret, used, cleared and freed: a dead-store pass with no reader after the clear removes 16 of 16 clearing stores and 0 of the secret stores - correctly, since the secret is read and the zeros are not - and replaying only the surviving stores leaves 16 of 16 secret bytes in memory starting 65 66 67 68; put an opaque barrier after the clear, which is what explicit_bzero is for, and the pass removes 0, leaving 0 secret bytes FIG This is the reason explicit_bzero, memset_s and SecureZeroMemory exist; the same pass has produced real CVEs in TLS and key-handling code. AVAN wrote the pass rather than describing it, and the first version was wrong in a way worth keeping: given a program whose 'use' read only ONE byte it deleted fifteen of the sixteen secret stores as well, which is also correct and made the demonstration meaningless. A program that genuinely uses its secret reads all of it, and correcting that produces the actual shape of the bug. ◆ sealed .dlw.fold → folded to ROOT_0 · a sphere of THE BACKDOOR · David Lee Wise (ROOT0), with AVAN


THE RESTRICT KEYWORD

restrict is a promise, made by you, that two pointers never touch the same object. The compiler cannot check it. It can only believe you, keep values in registers, and give a different answer if you were wrong.

THE RESTRICT KEYWORD · WORLD II — THE FOLD ◀ THE FOLD 0ROOT.AI // WORLD II · CO-OP · SHARED MEMORY ◆ .dlw.fold THE FOLD / CO-OP / SHARED MEMORY / THE RESTRICT KEYWORD THE RESTRICT KEYWORD a promise nothing can check 1 WHAT IT IS · WHAT IT DOES · FACT OR FICTION restrict is a promise, made by you, that two pointers never touch the same object. The compiler cannot check it. It can only believe you, keep values in registers, and produce a different answer if you were wrong. LIT verified live. adding two length- 8 vectors into an output that overlaps the input by a shift k : the honest loop reloads on every iteration, the loop compiled under a restrict promise reads the input once. At shift 0 — fully in place — the two agree, 0 positions differ. At shift 8 — disjoint, the promise true — they agree, 0 differ. In between they differ in exactly 8−k positions: 7, 6, 5, 4, 3, 2, 1 . The damage is exactly the size of the overlap, and both endpoints are silent. 2 HOW IT WAS WEAVED · AI + HUMAN restrict is C99 6.7.3.1; it is the reason Fortran vectorised better than C for two decades, since Fortran forbids aliasing by default. AVAN (AI) swept the whole overlap rather than showing the broken case, because the endpoints are the finding. A test with disjoint arrays passes; a test done fully in place also passes; the failure lives strictly between them and scales linearly with how wrong the promise was. A keyword whose violation is undetectable, silent at both extremes and proportional in the middle is not a sharp edge — it is a gradient, and gradients do not get caught by a test that samples the ends. 3 ONE DIMENSION The damage is exactly the size of the overlap. 4 TWO DIMENSIONS · INTERACTIVE Slide the output across the input and watch the error grow. shift + 1 ▶ shift - 1 5 THREE DIMENSIONS + AVAN’S INVERSE The green forward object. AVAN’s addition (the inverse-companion): the forward reading is that restrict lets the compiler keep values in registers. The inverse is that it is the one place C asks you to prove something and then does not look at the proof . Every other type error is checked; this one is a sworn statement. Read backwards, the keyword is not an optimisation hint, it is a transfer of liability — the compiler gains speed, you gain the obligation, and the only instrument that can detect the breach is the wrong answer itself, arriving later, in proportion to how wrong you were. pause spin LIT adding two length-8 vectors into an output overlapping the input by a shift k, the honest loop reloads every iteration while the loop compiled under a restrict promise reads the input once: at shift 0, fully in place, 0 positions differ, and at shift 8, disjoint and the promise true, 0 differ - but in between they differ in exactly 8-k positions, 7, 6, 5, 4, 3, 2, 1, so the damage is exactly the size of the overlap and both endpoints are silent FIG restrict is C99 6.7.3.1; it is the reason Fortran vectorised better than C for two decades, since Fortran forbids aliasing by default. AVAN swept the whole overlap rather than showing the broken case, because the endpoints are the finding: a test with disjoint arrays passes, a test done fully in place also passes, and the failure lives strictly between them and scales linearly with how wrong the promise was. A gradient does not get caught by a test that samples the ends. ◆ sealed .dlw.fold → folded to ROOT_0 · a sphere of SHARED MEMORY · David Lee Wise (ROOT0), with AVAN


THE NORMALIZATION FORM

Two strings, the same glyphs on screen, pixel for pixel. One holds a single code point; the other a letter followed by an instruction to put an accent on it. They are not equal.

THE NORMALIZATION FORM · WORLD II — THE FOLD ◀ THE FOLD 0ROOT.AI // WORLD II · GLITCH · HEISENBUG ◆ .dlw.fold THE FOLD / GLITCH / HEISENBUG / THE NORMALIZATION FORM THE NORMALIZATION FORM the same glyphs, and not equal 1 WHAT IT IS · WHAT IT DOES · FACT OR FICTION Two strings, the same glyphs on screen, pixel for pixel. One holds a single code point; the other holds a letter followed by an instruction to put an accent on it. They are not equal, and no amount of looking will tell you which is which. LIT verified live. over the Latin-1 and Latin Extended-A blocks, 161 characters have a distinct decomposed form. All 161 get longer when decomposed, 0 of the 161 compare equal to their own decomposition, and all 161 compare equal after normalising. The letter é is 1 code unit composed and 2 decomposed, renders identically either way, and === answers false . 2 HOW IT WAS WEAVED · AI + HUMAN Unicode normalization (UAX #15) and the four forms NFC, NFD, NFKC, NFKD are the standard; the composed/decomposed split exists because Unicode had to round-trip with legacy encodings that made both choices. AVAN (AI) swept the block rather than showing the one famous example, because the 0 is the number that matters: not one of the 161 accidentally compares equal. This is not a rare collision to guard against, it is a total failure of equality across the whole class, and it is invisible on screen by design — the two forms are required to render the same. 3 ONE DIMENSION 161 characters. 161 failures. 0 visible differences. 4 TWO DIMENSIONS · INTERACTIVE Compose and decompose the same letter and compare. next letter ▶ toggle decomposed 5 THREE DIMENSIONS + AVAN’S INVERSE The green forward object. AVAN’s addition (the inverse-companion): the forward reading is that you should normalise before comparing. The inverse is that equality of text is a choice, not a fact . There is no true answer to whether é equals é — byte equality says no, canonical equivalence says yes, and case-insensitive compatibility says yes to things that do not even look alike. Read backwards, every string comparison in every program has silently picked one of these and called it the comparison, and the bug is not choosing wrong but never noticing there was a choice. pause spin LIT over the Latin-1 and Latin Extended-A blocks 161 characters have a distinct decomposed form, and all 161 get longer when decomposed, 0 of the 161 compare equal to their own decomposition, and all 161 compare equal after normalising; the letter e-acute is 1 code unit composed and 2 decomposed, renders identically either way, and === answers false FIG Unicode normalization (UAX #15) and the forms NFC, NFD, NFKC, NFKD are the standard; the composed/decomposed split exists because Unicode had to round-trip with legacy encodings that made both choices. AVAN swept the block rather than showing the one famous example, because the 0 is the number that matters: not one of the 161 accidentally compares equal. This is not a rare collision, it is a total failure of equality across the whole class, and it is invisible by design - the two forms are REQUIRED to render the same. ◆ sealed .dlw.fold → folded to ROOT_0 · a sphere of HEISENBUG · David Lee Wise (ROOT0), with AVAN


THE GRAPHEME CLUSTER

How long is a family emoji? Eleven, if you ask the string. Seven, if you ask how many characters. One, if you ask a person. All three are answers to different questions.

THE GRAPHEME CLUSTER · WORLD II — THE FOLD ◀ THE FOLD 0ROOT.AI // WORLD II · CO-OP · THE MERGE ◆ .dlw.fold THE FOLD / CO-OP / THE MERGE / THE GRAPHEME CLUSTER THE GRAPHEME CLUSTER eleven, seven, one - all correct 1 WHAT IT IS · WHAT IT DOES · FACT OR FICTION How long is a family emoji? Eleven, if you ask the string. Seven, if you ask how many characters. One, if you ask a person. All three answers are correct and they are answers to different questions. LIT verified live. the family 👨👩👧👦 measures 11 UTF-16 code units, 7 code points and 1 grapheme cluster. The flag 🇬🇧 measures 4 , 2 and 1 . A skin-toned thumb measures 4 , 2 and 1 . Reversing the family by code unit does not return the original and neither does reversing it by code point — only the cluster is the unit a reversal can safely move. 2 HOW IT WAS WEAVED · AI + HUMAN Grapheme cluster boundaries are UAX #29; Intl.Segmenter implements them, and this sphere uses it rather than approximating. AVAN (AI) reports all three numbers side by side because the bug is never that a program used the wrong one — it is that the program never knew there were three. length answers a storage question and gets used as a display question; truncating at 10 to fit a field splits the family in half and produces something that is not a character at all. 3 ONE DIMENSION Eleven, seven, one. Three right answers. 4 TWO DIMENSIONS · INTERACTIVE Truncate the string and watch a person come apart. cut one shorter ▶ reset next sample 5 THREE DIMENSIONS + AVAN’S INVERSE The green forward object. AVAN’s addition (the inverse-companion): the forward reading is that you should count grapheme clusters. The inverse is that there is no such thing as the length of a string — only the length of a string for a purpose . Storage wants code units, a database column wants bytes, a cursor wants clusters, and a line-break wants something else again. Read backwards, length is not a property being reported but a question being answered, and the single most common bug in text handling is a program that asked one question and used the answer for another. pause spin LIT the family emoji measures 11 UTF-16 code units, 7 code points and 1 grapheme cluster; the flag measures 4, 2 and 1, and a skin-toned thumb measures 4, 2 and 1 - and reversing the family by code unit does not return the original, nor does reversing it by code point, because only the cluster is a unit a reversal can safely move FIG Grapheme cluster boundaries are UAX #29; Intl.Segmenter implements them and this sphere uses it rather than approximating. AVAN reports all three numbers side by side because the bug is never that a program used the wrong one - it is that the program never knew there were three. length answers a storage question and gets used as a display question; truncating at 10 to fit a field splits the family in half and produces something that is not a character at all. ◆ sealed .dlw.fold → folded to ROOT_0 · a sphere of THE MERGE · David Lee Wise (ROOT0), with AVAN


THE TURKISH I

Lowercasing a string is not a property of the string. It is a property of the string AND a language, and in Turkish the letter I does not become i.

THE TURKISH I · WORLD II — THE FOLD ◀ THE FOLD 0ROOT.AI // WORLD II · GLITCH · UNDEFINED BEHAVIOR ◆ .dlw.fold THE FOLD / GLITCH / UNDEFINED BEHAVIOR / THE TURKISH I THE TURKISH I lowercase is a property of a language 1 WHAT IT IS · WHAT IT DOES · FACT OR FICTION Lowercasing a string is not a property of the string. It is a property of the string and a language , and in Turkish the letter I does not become i. LIT verified live. ten ordinary identifiers — FILE, TITLE, ID, INFO, LIST, IMAGE, INDEX, ITEM, MAIN, ADMIN — lowercased under the English and Turkish locales disagree in 10 of 10 . "I" becomes i in English and U+0131 , the dotless ı , in Turkish; "i" uppercases to I in English and to U+0130 , the dotted İ , in Turkish. A case-insensitive comparison of ADMIN against admin is therefore false on a Turkish machine, and true on yours. 2 HOW IT WAS WEAVED · AI + HUMAN The Turkish dotted and dotless I are the standard example of locale-sensitive case mapping, and the reason toLowerCase and toLocaleLowerCase are different functions. AVAN (AI) chose identifiers rather than words, because the failure that matters is not a mis-spelled label — it is a security check. Every one of the ten contains an I , which is why the mismatch is 10 of 10 rather than a rate: the bug is not probabilistic, it fires on any identifier containing that one letter, and the affected set is decided by a locale set somewhere else entirely. 3 ONE DIMENSION Ten identifiers. Ten disagreements. One letter. 4 TWO DIMENSIONS · INTERACTIVE Lowercase the same word in two languages. next word ▶ toggle locale 5 THREE DIMENSIONS + AVAN’S INVERSE The green forward object. AVAN’s addition (the inverse-companion): the forward reading is to use the locale-independent function for identifiers. The inverse is that there is no locale-independent lowercase — there is only a default locale you have stopped noticing . Calling the plain function does not step outside language; it picks one and hides the choice, and it happens to be the one that suits the people who wrote the runtime. Read backwards, every case-insensitive comparison in a program is a claim about which language the data is in, and that claim is almost never written down anywhere it can be checked. pause spin LIT ten ordinary identifiers - FILE, TITLE, ID, INFO, LIST, IMAGE, INDEX, ITEM, MAIN, ADMIN - lowercased under the English and Turkish locales disagree in 10 of 10: I becomes i in English and U+0131 the dotless i in Turkish, while i uppercases to I in English and to U+0130 the dotted capital in Turkish, so a case-insensitive comparison of ADMIN against admin is false on a Turkish machine and true on yours FIG The Turkish dotted and dotless I are the standard example of locale-sensitive case mapping, and the reason toLowerCase and toLocaleLowerCase are different functions. AVAN chose identifiers rather than words, because the failure that matters is a security check, not a mis-spelled label. Every one of the ten contains an I, which is why the mismatch is 10 of 10 rather than a rate: the bug is not probabilistic, it fires on any identifier containing that one letter. ◆ sealed .dlw.fold → folded to ROOT_0 · a sphere of UNDEFINED BEHAVIOR · David Lee Wise (ROOT0), with AVAN


THE HOMOGLYPH

Cyrillic a is not Latin a. Different code point, different alphabet, different language - and on every screen you will ever look at, the same shape.

THE HOMOGLYPH · WORLD II — THE FOLD ◀ THE FOLD 0ROOT.AI // WORLD II · CHEAT · THE BACKDOOR ◆ .dlw.fold THE FOLD / CHEAT / THE BACKDOOR / THE HOMOGLYPH THE HOMOGLYPH thirty-two spellings, one shape 1 WHAT IT IS · WHAT IT DOES · FACT OR FICTION Cyrillic а is not Latin a . Different code point, different alphabet, different language — and on every screen you will ever look at, the same shape. LIT verified live. the word paypal has 5 positions whose Latin letter has a Cyrillic look-alike, giving 2 5 = 32 substitutions. All 32 are distinct strings — no two are equal — and exactly 1 of them is the original. The other 31 compare unequal to it, hash differently, sort differently, and render identically. Latin a is U+0061 ; Cyrillic а is U+0430 . 2 HOW IT WAS WEAVED · AI + HUMAN Homoglyph attacks and the IDN spoofing problem are why registrars restrict mixed-script domains and why browsers show punycode for suspicious labels; Unicode publishes a confusables table (UTS #39). AVAN (AI) counted the space rather than showing one spoofed word, because 32 is the argument. A blocklist of known-bad strings is the usual defence and it is defeated arithmetically: the attacker picks a different one of the 31 . The defence that works is not enumeration, it is refusing to mix scripts in the first place — a rule about the alphabet , not about the words. 3 ONE DIMENSION Thirty-two spellings. One shape. 4 TWO DIMENSIONS · INTERACTIVE Swap letters for their look-alikes and watch nothing change. swap one ▶ swap all reset 5 THREE DIMENSIONS + AVAN’S INVERSE The green forward object. AVAN’s addition (the inverse-companion): the forward reading is that you cannot trust what a string looks like. The inverse is that identity was never in the glyph — the glyph is a rendering decision, and rendering is designed to hide the difference . Two code points that mean different letters in different alphabets are drawn the same because that is what the shapes are , historically. Read backwards, the spoof is not an abuse of Unicode; it is Unicode working, and any system that treated appearance as identity had already made an assumption the writing system never agreed to. pause spin LIT the word paypal has 5 positions whose Latin letter has a Cyrillic look-alike, giving 2^5 = 32 substitutions, and all 32 are distinct strings with exactly 1 of them the original - the other 31 compare unequal to it, hash differently, sort differently and render identically, since Latin a is U+0061 and Cyrillic a is U+0430 FIG Homoglyph attacks and IDN spoofing are why registrars restrict mixed-script domains and browsers show punycode for suspicious labels; Unicode publishes a confusables table (UTS #39). AVAN counted the space rather than showing one spoofed word, because 32 is the argument: a blocklist of known-bad strings is the usual defence and it is defeated arithmetically, since the attacker picks a different one of the 31. The defence that works is refusing to mix scripts - a rule about the alphabet, not about the words. ◆ sealed .dlw.fold → folded to ROOT_0 · a sphere of THE BACKDOOR · David Lee Wise (ROOT0), with AVAN


THE SURROGATE PAIR

Sixteen bits held every character, once. Then there were more than sixty-five thousand of them, and the fix was to spend two units on the rest - two units that mean nothing apart.

THE SURROGATE PAIR · WORLD II — THE FOLD ◀ THE FOLD 0ROOT.AI // WORLD II · SPAWN · THE TOOLCHAIN ◆ .dlw.fold THE FOLD / SPAWN / THE TOOLCHAIN / THE SURROGATE PAIR THE SURROGATE PAIR two units that are not characters 1 WHAT IT IS · WHAT IT DOES · FACT OR FICTION Sixteen bits held every character, once. Then there were more than sixty-five thousand of them, and the fix was to spend two units on the rest — two units that are not characters, and mean nothing apart. LIT verified live. the musical clef U+1D11E occupies 2 UTF-16 code units and is 1 code point. Sampling 768 code points across the range, 512 need two units and 256 fit in one. Cutting the string a 𝄞 b 😀 c at every one of its 8 indices produces a lone high surrogate 2 times — a value that is not a character, cannot be rendered, and is still a perfectly legal string . The string reports length 7 ; it holds 5 characters. 2 HOW IT WAS WEAVED · AI + HUMAN UTF-16 and the surrogate range U+D800–U+DFFF are how a 16-bit encoding was extended past the basic plane without breaking existing data. AVAN (AI) counted the lone surrogates produced by slicing rather than asserting that slicing is unsafe, because 2 of 8 is the shape of the hazard: not every cut is dangerous, so a test that slices once will usually pass. The type system is silent throughout — a lone surrogate has the same type as any other string, and there is no operation that will complain until something tries to draw it. 3 ONE DIMENSION Seven long, five characters, two bad places to cut. 4 TWO DIMENSIONS · INTERACTIVE Cut the string at each index and find the broken halves. cut one later ▶ earlier 5 THREE DIMENSIONS + AVAN’S INVERSE The green forward object. AVAN’s addition (the inverse-companion): the forward reading is that you must not index into UTF-16 blindly. The inverse is that the encoding leaked into the type, and then the type became the interface . A string was supposed to be a sequence of characters; it is a sequence of storage units, and every language that adopted UTF-16 in the nineties made that permanent by exposing length and [i] in those units. Read backwards, this is a twenty-year-old compatibility decision still being paid for in every truncated name and every mangled emoji, by people who never chose the encoding. pause spin LIT the musical clef U+1D11E occupies 2 UTF-16 code units and is 1 code point, and sampling 768 code points across the range, 512 need two units while 256 fit in one; cutting a five-character test string at every one of its 8 indices produces a lone high surrogate 2 times - a value that is not a character, cannot be rendered, and is still a perfectly legal string - and that string reports length 7 while holding 5 characters FIG UTF-16 and the surrogate range U+D800 to U+DFFF are how a 16-bit encoding was extended past the basic plane without breaking existing data. AVAN counted the lone surrogates produced by slicing rather than asserting that slicing is unsafe, because 2 of 8 is the shape of the hazard: not every cut is dangerous, so a test that slices once will usually pass. The type system is silent throughout - a lone surrogate has the same type as any other string. ◆ sealed .dlw.fold → folded to ROOT_0 · a sphere of THE TOOLCHAIN · David Lee Wise (ROOT0), with AVAN


THE ZERO WIDTH JOINER

Some characters have no shape. They occupy no width, print nothing, survive copy and paste, and change what a string is without changing anything you can see.

THE ZERO WIDTH JOINER · WORLD II — THE FOLD ◀ THE FOLD 0ROOT.AI // WORLD II · CHEAT · NOCLIP ◆ .dlw.fold THE FOLD / CHEAT / NOCLIP / THE ZERO WIDTH JOINER THE ZERO WIDTH JOINER characters with no shape at all 1 WHAT IT IS · WHAT IT DOES · FACT OR FICTION Some characters have no shape at all. They occupy no width, print nothing, survive copy and paste, and change what a string is without changing anything you can see. LIT verified live. five invisible code points — ZERO WIDTH SPACE, ZWNJ, ZWJ, WORD JOINER and ZWNBSP — inserted into the middle of a word give a string that is not equal to its visible twin in 5 of 5 cases, and all 5 belong to Unicode’s format category, \p{Cf} . Trimming removes only 1 of them and leaves 4 . The family emoji 👨👩👧 is 5 code points of which 2 are zero-width joiners; strip them and the same picture becomes 3 separate people. 2 HOW IT WAS WEAVED · AI + HUMAN Zero-width formatting characters are ordinary Unicode — ZWJ is how emoji sequences are built, ZWNJ is required to write Persian and Hindi correctly. They are not an exploit; they are typography. AVAN (AI) tested the format category rather than eyeballing invisibility, because ‘invisible’ is a rendering claim and \p{Cf} is a checkable one — all 5 match. The uncomfortable number is the trim result: only 1 of the 5 is stripped by the usual whitespace trim, because JavaScript counts just U+FEFF as whitespace. A defence that sanitises by trimming removes almost none of the class while looking like it did something. 3 ONE DIMENSION Five characters you cannot see. Five strings that are not equal. 4 TWO DIMENSIONS · INTERACTIVE Insert an invisible character and compare the two words. next invisible ▶ toggle inserted 5 THREE DIMENSIONS + AVAN’S INVERSE The green forward object. AVAN’s addition (the inverse-companion): the forward reading is that invisible characters should be stripped. The inverse is that ‘invisible’ is not a property of a character, it is a property of a font’s decision not to draw it — and the same characters are load-bearing typography in other scripts. Strip them and you break Persian; keep them and two identical-looking usernames are different accounts. Read backwards, there is no sanitising rule that is correct for every writing system at once, which means the choice is a policy about whose text you are willing to handle. pause spin LIT five invisible code points - ZERO WIDTH SPACE, ZWNJ, ZWJ, WORD JOINER and ZWNBSP - inserted into the middle of a word give a string that is not equal to its visible twin in 5 of 5 cases, and all 5 belong to Unicode's format category; trimming removes only 1 of them and leaves 4, while the family emoji is 5 code points of which 2 are zero-width joiners, so stripping them turns the same picture into 3 separate people FIG Zero-width formatting characters are ordinary Unicode - ZWJ is how emoji sequences are built, ZWNJ is required to write Persian and Hindi correctly. They are not an exploit; they are typography. AVAN tested the format category rather than eyeballing invisibility, because 'invisible' is a rendering claim and the category is a checkable one. The uncomfortable number is the trim result: 4 of 5 are stripped and one is not, so a defence that sanitises by trimming leaves a hole, which is worse than removing none. ◆ sealed .dlw.fold → folded to ROOT_0 · a sphere of NOCLIP · David Lee Wise (ROOT0), with AVAN


THE UTF-8 OVERLONG

THE UTF-8 OVERLONG · WORLD II — THE FOLD ◀ THE FOLD 0ROOT.AI // WORLD II · CHEAT · THE EXPLOIT ◆ .dlw.fold THE FOLD / CHEAT / THE EXPLOIT / THE UTF-8 OVERLONG THE UTF-8 OVERLONG 384 spare spellings of 128 characters 1 WHAT IT IS · WHAT IT DOES · FACT OR FICTION There is exactly one correct way to encode a character in UTF-8, and several that also work. A decoder that accepts the extras will hand you a slash you did not see coming. LIT verified live. each of the 128 ASCII code points has 3 non-minimal encodings — padded out to two, three and four bytes — giving 384 overlong forms. A decoder that simply reassembles the bits accepts all 384 and returns the original character every time. The browser’s standards-conforming decoder accepts 0 of them and returns the replacement character instead. The slash / , U+002F, has the overlong forms C0 AF , E0 80 AF and F0 80 80 AF — none of which contains the byte 0x2F that a path filter is looking for. 2 HOW IT WAS WEAVED · AI + HUMAN Overlong UTF-8 was the mechanism behind the IIS directory-traversal worms of 2001; the Unicode standard made non-minimal forms illegal precisely because filters and decoders disagreed about them. AVAN (AI) ran both decoders — a hand-written naive one and the browser’s TextDecoder — rather than describing the difference, so 384 against 0 is measured on the same inputs. The point is not that the naive decoder is badly written. It is that it is the obvious one: reassemble the bits and you get the right character, which is exactly the behaviour that makes the check upstream meaningless. 3 ONE DIMENSION 384 spare spellings of 128 characters. 4 TWO DIMENSIONS · INTERACTIVE Encode a character the wrong number of ways. next character ▶ widen the encoding 5 THREE DIMENSIONS + AVAN’S INVERSE The green forward object. AVAN’s addition (the inverse-companion): the forward reading is that decoders must reject non-minimal forms. The inverse is that the bug is never in the decoder, it is in the gap between two of them . A filter reads bytes and looks for 0x2F ; a decoder reads bytes and produces characters; and the attack lives in the fact that these two answered the same question differently and neither was wrong on its own. Read backwards, every validate-then-transform pipeline has this shape, and the defence is not a better filter but refusing to validate anything before it is in its final form. pause spin LIT each of the 128 ASCII code points has 3 non-minimal encodings padded out to two, three and four bytes, giving 384 overlong forms, and a decoder that simply reassembles the bits accepts all 384 and returns the original character every time while the browser's standards-conforming decoder accepts 0 of them; the slash U+002F has the overlong forms C0 AF, E0 80 AF and F0 80 80 AF, none of which contains the byte 0x2F that a path filter is looking for FIG Overlong UTF-8 was the mechanism behind the IIS directory-traversal worms of 2001; the Unicode standard made non-minimal forms illegal precisely because filters and decoders disagreed about them. AVAN ran both decoders - a hand-written naive one and the browser's TextDecoder - so 384 against 0 is measured on the same inputs. The point is not that the naive decoder is badly written; it is that it is the obvious one, and that is what makes the check upstream meaningless. ◆ sealed .dlw.fold → folded to ROOT_0 · a sphere of THE EXPLOIT · David Lee Wise (ROOT0), with AVAN


THE BYTE ORDER MARK

THE BYTE ORDER MARK · WORLD II — THE FOLD ◀ THE FOLD 0ROOT.AI // WORLD II · SPAWN · COLD BOOT ◆ .dlw.fold THE FOLD / SPAWN / COLD BOOT / THE BYTE ORDER MARK THE BYTE ORDER MARK metadata living inside the data 1 WHAT IT IS · WHAT IT DOES · FACT OR FICTION A mark at the front of a file saying which end of a number comes first. UTF-8 has no ends to order. The mark got used anyway, as a label, and it is invisible. LIT verified live. the byte order mark is U+FEFF , encoded in UTF-8 as the three bytes EF BB BF . It belongs to Unicode’s format category, so it draws nothing. Put it in front of a JSON document and JSON.parse throws ; strip it and the identical document parses. The string "abc" with a leading mark has length 4 rather than 3 and is not equal to "abc" — and a whitespace trim happens to remove it, which means the bug appears and disappears depending on whether some earlier stage trimmed. 2 HOW IT WAS WEAVED · AI + HUMAN The BOM is required for UTF-16, optional and discouraged for UTF-8, and emitted by default by several Windows editors — which is why it is usually met as an unexplained parse error in a file that looks fine. AVAN (AI) made the JSON failure the measurement rather than the anecdote: the same bytes, minus three at the front, parse. That is the whole diagnosis and it is one line. The trim result is the part worth carrying — a bug that is removed by an unrelated cleanup step is a bug that will be reported as intermittent, and intermittent is what a defect looks like when the pipeline has more stages than the report mentions. 3 ONE DIMENSION Three bytes at the front. Nothing on the screen. 4 TWO DIMENSIONS · INTERACTIVE Put the mark in front of a document and parse it. toggle the mark parse it 5 THREE DIMENSIONS + AVAN’S INVERSE The green forward object. AVAN’s addition (the inverse-companion): the forward reading is to strip the BOM on input. The inverse is that it is a label pretending to be content . Every other piece of metadata about a file — its name, its type, its length — lives outside the bytes; this one was put inside them, so every reader must know to skip it and none of them can be told by the file itself. Read backwards, the mark is not the problem; putting metadata in the same channel as data is the problem, and this is simply the smallest possible example of it. pause spin LIT the byte order mark is U+FEFF, encoded in UTF-8 as the three bytes EF BB BF, and it belongs to Unicode's format category so it draws nothing; put it in front of a JSON document and JSON.parse throws while stripping it makes the identical document parse, and the string abc with a leading mark has length 4 rather than 3 and is not equal to abc - and a whitespace trim happens to remove it, so the bug appears and disappears depending on whether some earlier stage trimmed FIG The BOM is required for UTF-16, optional and discouraged for UTF-8, and emitted by default by several Windows editors - which is why it is usually met as an unexplained parse error in a file that looks fine. AVAN made the JSON failure the measurement rather than the anecdote: the same bytes, minus three at the front, parse. The trim result is the part worth carrying - a bug removed by an unrelated cleanup step gets reported as intermittent, and intermittent is what a defect looks like when the pipeline has more stages than the report mentions. ◆ sealed .dlw.fold → folded to ROOT_0 · a sphere of COLD BOOT · David Lee Wise (ROOT0), with AVAN


THE CASE FOLDING

Uppercase is not a permutation. Some letters get longer, some have no partner, and lowercasing an uppercased string does not give back what you started with.

THE CASE FOLDING · WORLD II — THE FOLD ◀ THE FOLD 0ROOT.AI // WORLD II · RESPAWN · THE RESURRECT ◆ .dlw.fold THE FOLD / RESPAWN / THE RESURRECT / THE CASE FOLDING THE CASE FOLDING out through two, back as one 1 WHAT IT IS · WHAT IT DOES · FACT OR FICTION Uppercase is not a permutation. Some letters get longer, some have no partner, and lowercasing an uppercased string does not give you back what you started with. LIT verified live. sweeping 8,417 code points, 90 grow when uppercased and 114 fail to survive a lower-upper-lower round trip. The German ß uppercases to SS — 1 character becoming 2 — and lowercasing that gives ss , which is not ß . So a system that stores names uppercased has silently merged straße and strasse into one, and cannot tell them apart again. 2 HOW IT WAS WEAVED · AI + HUMAN Case mapping is one-to-many in Unicode by design (the SpecialCasing table); case folding is a separate operation defined precisely because mapping does not round-trip. AVAN (AI) counted both quantities separately — the 90 that change length and the 114 that break the round trip — because they are different failures with different consequences. Growing breaks fixed-width columns and truncation; not round-tripping destroys information. The second is the worse one and the harder to see, since nothing is lost at the moment it happens; it is lost later, when someone tries to go back. 3 ONE DIMENSION Ninety get longer. A hundred and fourteen never come home. 4 TWO DIMENSIONS · INTERACTIVE Uppercase a letter and try to lowercase it back. next letter ▶ next one that breaks 5 THREE DIMENSIONS + AVAN’S INVERSE The green forward object. AVAN’s addition (the inverse-companion): the forward reading is to use case folding rather than case mapping for comparison. The inverse is that uppercase is a typographic convention, not an operation on data , and it was never a function with an inverse. There is no capital ß in the tradition the letter comes from — printers wrote SS — so the mapping is recording a human practice, not computing a transformation. Read backwards, the round trip fails because there was nothing to round-trip: the information was in the writing, and the writing had already thrown it away. pause spin LIT sweeping 8,417 code points, 90 grow when uppercased and 114 fail to survive a lower-upper-lower round trip; the German sharp s uppercases to SS - 1 character becoming 2 - and lowercasing that gives ss, which is not the sharp s, so a system that stores names uppercased has silently merged strasse spelled both ways into one and cannot tell them apart again FIG Case mapping is one-to-many in Unicode by design (the SpecialCasing table); case folding is a separate operation defined precisely because mapping does not round-trip. AVAN counted both quantities separately - the 90 that change length and the 114 that break the round trip - because they are different failures: growing breaks fixed-width columns and truncation, while not round-tripping destroys information. The second is worse and harder to see, since nothing is lost at the moment it happens. ◆ sealed .dlw.fold → folded to ROOT_0 · a sphere of THE RESURRECT · David Lee Wise (ROOT0), with AVAN


THE BIDI OVERRIDE

Text has a logical order - the order the bytes are in - and a display order. Nine invisible characters set the second without touching the first, so a line of code can be shown in an order it does not have.

THE BIDI OVERRIDE · WORLD II — THE FOLD ◀ THE FOLD 0ROOT.AI // WORLD II · BOSS · THE GATEKEEPER ◆ .dlw.fold THE FOLD / BOSS / THE GATEKEEPER / THE BIDI OVERRIDE THE BIDI OVERRIDE two readers, two orders, no error 1 WHAT IT IS · WHAT IT DOES · FACT OR FICTION Text has a logical order — the order the bytes are in — and a display order. Nine invisible characters let you set the second without touching the first, so a line of code can be shown in an order it does not have. LIT verified live. there are 9 bidirectional control characters: U+202A to U+202E and U+2066 to U+2069 . All 9 belong to Unicode’s format category, all 9 are a single code unit, and all 9 draw nothing. A source line carrying 2 of them measures 35 code points of which 33 are visible — the compiler reads all 35 in byte order, the reviewer reads 33 in display order, and the two orders are not the same. 2 HOW IT WAS WEAVED · AI + HUMAN This is Trojan Source , Boucher and Anderson (2021, CVE-2021-42574); the bidirectional algorithm itself is UAX #9 and is required to display Arabic and Hebrew correctly. AVAN (AI) checked the format category rather than trusting the word ‘invisible’, and reports the visible-versus-total count because that gap is the vulnerability: 35 against 33 . Nothing here is malformed, no parser is confused, and no standard is violated — the compiler and the reviewer are both reading correctly. They are reading two different orderings of the same bytes, and only one of them compiles. 3 ONE DIMENSION Nine characters. Two readers. Two orders. 4 TWO DIMENSIONS · INTERACTIVE Add a control and watch the line rearrange itself. next control ▶ toggle it in 5 THREE DIMENSIONS + AVAN’S INVERSE The green forward object. AVAN’s addition (the inverse-companion): the forward reading is that compilers should reject unbalanced bidi controls in source. The inverse is that code review has always assumed the reviewer and the compiler read the same artifact, and they never did — one reads rendered text, the other reads bytes. Read backwards, this is not a Unicode flaw but the first time that gap was made large enough to walk through, and every review process that signs off on an appearance is trusting a rendering pipeline nobody audits. pause spin LIT there are 9 bidirectional control characters, U+202A to U+202E and U+2066 to U+2069, and all 9 belong to Unicode's format category, all 9 are a single code unit and all 9 draw nothing; a source line carrying 2 of them measures 35 code points of which 33 are visible, so the compiler reads all 35 in byte order while the reviewer reads 33 in display order, and the two orders are not the same FIG This is Trojan Source, Boucher and Anderson (2021, CVE-2021-42574); the bidirectional algorithm itself is UAX #9 and is required to display Arabic and Hebrew correctly. AVAN checked the format category rather than trusting the word 'invisible', and reports the visible-versus-total count because that gap IS the vulnerability: 35 against 33. Nothing is malformed, no parser is confused and no standard is violated - the compiler and the reviewer are both reading correctly, two different orderings of the same bytes. ◆ sealed .dlw.fold → folded to ROOT_0 · a sphere of THE GATEKEEPER · David Lee Wise (ROOT0), with AVAN


THE LEAP SECOND

Unix time counts seconds since 1970. It does not. It counts days since 1970 multiplied by 86,400 - and the Earth has had twenty-seven extra seconds inserted that the count refuses to hold.

THE LEAP SECOND · WORLD II — THE FOLD ◀ THE FOLD 0ROOT.AI // WORLD II · GRIND · THE EPOCH ◆ .dlw.fold THE FOLD / GRIND / THE EPOCH / THE LEAP SECOND THE LEAP SECOND precise about the wrong quantity 1 WHAT IT IS · WHAT IT DOES · FACT OR FICTION Unix time counts seconds since 1970. It does not. It counts days since 1970, multiplied by 86,400 — and the Earth has had twenty-seven extra seconds inserted into it that the count refuses to hold. LIT verified live. between 1 January 1972 and 1 January 2017 there are 16,437 days. Unix time makes that 1,420,156,800 seconds — exactly 86,400 per day, with no remainder. Actual elapsed time is 1,420,156,827 seconds, because 27 leap seconds were inserted in that window, the first on 1972-06-30 and the last on 2016-12-31 . So a Unix timestamp is not an elapsed-second count and never was; the difference is 27 seconds, all of them positive, and 0 negative leap seconds have ever been needed. 2 HOW IT WAS WEAVED · AI + HUMAN Leap seconds are declared by the IERS to keep UTC within 0.9 s of the Earth’s rotation; the twenty-seven dates are theirs and are used here as data, not re-derived. AVAN (AI) reports the divisibility as the finding: 1,420,156,800 mod 86,400 = 0 . That is not a coincidence and it is not a rounding — it is the definition. Unix time is a calendar rendered as a number, and the smooth axis everyone assumes it is has twenty-seven places where two different instants share one value, or one instant is skipped, depending on the implementation. 3 ONE DIMENSION 16,437 days. Two answers, 27 seconds apart. 4 TWO DIMENSIONS · INTERACTIVE Step through the leap seconds and watch the gap open. next leap ▶ all of them reset 5 THREE DIMENSIONS + AVAN’S INVERSE The green forward object. AVAN’s addition (the inverse-companion): the forward reading is that Unix time is a convenient approximation. The inverse is that it was never approximating elapsed time — it is exactly right about a different quantity . The count is days-times-86,400, and as a statement about the calendar it has no error at all. Read backwards, the bug is not in the clock but in what everyone decided it measured; a number that is precisely correct about the wrong quantity is far harder to notice than one that is merely imprecise. pause spin LIT between 1 January 1972 and 1 January 2017 there are 16,437 days, which Unix time makes 1,420,156,800 seconds - exactly 86,400 per day with no remainder - while actual elapsed time is 1,420,156,827 seconds because 27 leap seconds were inserted in that window, the first on 1972-06-30 and the last on 2016-12-31; so a Unix timestamp is not an elapsed-second count and never was, the difference is 27 seconds, all positive, and 0 negative leap seconds have ever been needed FIG Leap seconds are declared by the IERS to keep UTC within 0.9 s of the Earth's rotation; the twenty-seven dates are theirs and are used as data, not re-derived. AVAN reports the divisibility as the finding: 1,420,156,800 mod 86,400 = 0. That is not a coincidence and not a rounding - it is the definition. Unix time is a calendar rendered as a number, and the smooth axis everyone assumes it is has twenty-seven places where two instants share one value, or one is skipped, depending on the implementation. ◆ sealed .dlw.fold → folded to ROOT_0 · a sphere of THE EPOCH · David Lee Wise (ROOT0), with AVAN


THE MONOTONIC CLOCK

Two clocks in every machine. One tells you what time it is and can be corrected, moved or dragged an hour sideways twice a year. The other only counts forward and cannot tell you anything about the world.

THE MONOTONIC CLOCK · WORLD II — THE FOLD ◀ THE FOLD 0ROOT.AI // WORLD II · GRIND · THE CRON JOB ◆ .dlw.fold THE FOLD / GRIND / THE CRON JOB / THE MONOTONIC CLOCK THE MONOTONIC CLOCK two clocks, two questions 1 WHAT IT IS · WHAT IT DOES · FACT OR FICTION Two clocks in every machine. One tells you what time it is and can be corrected, moved, or dragged an hour sideways twice a year. The other only counts forward and cannot tell you anything about the world. LIT verified live. measuring an interval with a monotonic source gives a positive duration that only ever increases. Modelling a wall-clock correction landing inside the same interval — steps of −1000 , −250 , −40 , +40 and +250 milliseconds — the wall-clock duration is wrong in 5 of 5 cases and comes out negative in 3 of them. The monotonic duration is wrong in 0 . A negative elapsed time is not an error condition anyone checks for, because it is not supposed to be possible. 2 HOW IT WAS WEAVED · AI + HUMAN The distinction between a realtime and a monotonic clock is POSIX; performance.now() is the monotonic one here and its readings are real, not simulated. AVAN (AI) modelled the step rather than waiting for one, and says so — the durations are computed by adding a known offset. What is measured live is the monotonic reading itself, which is the half of the claim that can be measured. The 3 of 5 negative results are the useful figure: the failure is not a small error in a duration, it is a duration with the wrong sign , which propagates into every average, timeout and rate built on top of it. 3 ONE DIMENSION Five corrections. Five wrong durations. Three negative. 4 TWO DIMENSIONS · INTERACTIVE Step the wall clock in the middle of a measurement. next step ▶ no step 5 THREE DIMENSIONS + AVAN’S INVERSE The green forward object. AVAN’s addition (the inverse-companion): the forward reading is to use the monotonic clock for durations. The inverse is that the two clocks answer questions that cannot both be answered by one number . ‘What time is it’ must be correctable, because the answer can be wrong; ‘how long was that’ must never be corrected, because correcting it destroys the measurement. Read backwards, they were split because truthfulness and monotonicity are incompatible requirements — and every program that reaches for the wall clock to time something has asked one question and accepted the other one’s answer. pause spin LIT measuring an interval with a monotonic source gives a positive duration that only ever increases, while modelling a wall-clock correction landing inside the same interval - steps of -1000, -250, -40, +40 and +250 milliseconds - makes the wall-clock duration wrong in 5 of 5 cases and negative in 3 of them, with the monotonic duration wrong in 0; and a negative elapsed time is not an error condition anyone checks for, because it is not supposed to be possible FIG The distinction between a realtime and a monotonic clock is POSIX; performance.now() is the monotonic one here and its readings are real, not simulated. AVAN modelled the step rather than waiting for one, and says so - the durations are computed by adding a known offset, while what is measured live is the monotonic reading itself. The 3 of 5 negative results are the useful figure: the failure is a duration with the wrong SIGN, which propagates into every average, timeout and rate built on it. ◆ sealed .dlw.fold → folded to ROOT_0 · a sphere of THE CRON JOB · David Lee Wise (ROOT0), with AVAN


THE ISO WEEK YEAR

There are two years. The one on the calendar, and the one a week belongs to - and at the turn of December they disagree, because a week cannot be split between two years.

THE ISO WEEK YEAR · WORLD II — THE FOLD ◀ THE FOLD 0ROOT.AI // WORLD II · GLITCH · OFF BY ONE ◆ .dlw.fold THE FOLD / GLITCH / OFF BY ONE / THE ISO WEEK YEAR THE ISO WEEK YEAR two years, both correct 1 WHAT IT IS · WHAT IT DOES · FACT OR FICTION There are two years. The one on the calendar, and the one a week belongs to — and at the turn of December they disagree, because a week cannot be split between two years and something has to give. LIT verified live. checking the first three and last three days of every year from 1970 to 2030 — 366 dates — the calendar year and the ISO week-based year disagree on 104 of them, 28.4% . 30 December 2019 has calendar year 2019 and ISO week-year 2020 . A report filtered by one and grouped by the other will lose or double-count those days, and the discrepancy appears only in the last days of December and the first days of January — the two weeks of the year when everyone is away. 2 HOW IT WAS WEAVED · AI + HUMAN ISO 8601 defines a week-based calendar in which a week belongs to the year containing its Thursday, so a year has 52 or 53 whole weeks and never a fragment. AVAN (AI) computed the week-year from the Thursday rule rather than trusting a library, and swept sixty years to get a rate instead of an anecdote. 28.4% of boundary days is the number worth carrying: this is not an edge case that shows up once, it is a routine disagreement affecting roughly a quarter of the days anybody checks — and it is arithmetically invisible, since both answers are correct years. 3 ONE DIMENSION 366 boundary days. 104 disagreements. 4 TWO DIMENSIONS · INTERACTIVE Walk the turn of the year and watch the two years part. next day ▶ previous jump to 2019-12-30 5 THREE DIMENSIONS + AVAN’S INVERSE The green forward object. AVAN’s addition (the inverse-companion): the forward reading is to be careful which year you mean. The inverse is that ‘the year’ is not one quantity, and neither definition is the real one . The calendar year is an astronomical convention; the ISO week-year exists because businesses count in whole weeks and cannot have a week that belongs to two ledgers. Read backwards, they were built for different purposes and both are correct in theirs, which is why no amount of care in the code helps — the ambiguity is in the requirement, and it has to be settled before anything is written. pause spin LIT checking the first three and last three days of every year from 1970 to 2030 - 366 dates - the calendar year and the ISO week-based year disagree on 104 of them, 28.4%; 30 December 2019 has calendar year 2019 and ISO week-year 2020, so a report filtered by one and grouped by the other will lose or double-count those days, and the discrepancy appears only in the last days of December and the first days of January FIG ISO 8601 defines a week-based calendar in which a week belongs to the year containing its Thursday, so a year has 52 or 53 whole weeks and never a fragment. AVAN computed the week-year from the Thursday rule rather than trusting a library, and swept sixty years to get a rate instead of an anecdote. 28.4% of boundary days is the number worth carrying: a routine disagreement affecting roughly a quarter of the days anybody checks, and arithmetically invisible since both answers are correct years. ◆ sealed .dlw.fold → folded to ROOT_0 · a sphere of OFF BY ONE · David Lee Wise (ROOT0), with AVAN