Fix the stacked-structure geometry the census could not yet see - #25
Merged
Conversation
`engines/racket/compose.rkt` answered two coordinates inside an inline cutting note differently from the other two engines, and both are one reading of §3.4.2: a note's sublines run BESIDE the line, and the block they make is one position on it. On the block axis the engine reported a line's `block_extent` as the sum of the note's own subline heights wherever that was larger than the paragraph's own block size. A note set at the paragraph's em rather than at the half em §3.4.2's own sizing comes to therefore made the line twice as deep as the paragraph set it, as though the two sublines were two lines of the paragraph. They are not: the line is as deep as the paragraph set it, and how deep the block is is the block's own answer (#23). On the inline axis a member of the note reported its bare body as its advance. A member standing before a Table 1 amount inside its own subline -- `cl-02` then `cl-01`, half of the note's own em -- reported 500 while the same engine placed the next member 750 units on, so the answer's own advances did not reach the answer's own positions (#24). A member's advance is now its body plus the amount after it inside its row, and the member that ends a row reports its body alone, because nothing of that row stands after it. §3.8.3's ladder is the other half of the second reading. A boundary the line was not composed from is not one the line may take space back from, so `raw-gap-terms` now stops at a block's interior exactly as the line's own geometry does; the expansion ladder already did, through `same-complex?`, and both now ask one predicate. A line beside a note it cannot fit overruns rather than squeezing the note's own interior, which is a width the block already reported to the line. `docs/decisions/stacked-structure-geometry.md` publishes both readings. No public API and no other engine changed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N8KNy2ejPqy81P2hVcRUjs
…de it The `constructs` and `tabs` censuses stood the pair under test at a structure's two edges and set every note at the half em §3.4.2's own sizing comes to, so two coordinates of a warichu block were outside what any census asked: how deep a line carrying a note it does not fit is, and what Table 1 does between two characters of one subline. Both were where the Racket engine differed from the other two (#23, #24), and neither was observable at scale. Five further `constructs` variants and two further `tabs` ones ask them at every one of the 529 class pairs. `warichu-full-size` and its vertical mirror set the note at the paragraph's own em, which makes a block twice as deep as the line that holds it and is the only shape where a block's own depth and the line's come apart; `inside-full-size-warichu` and `-found` put a tab sign in that same block, at a stop the line reaches and at one it has gone past. `warichu-pair-inside` sets the pair inside the note's own rows instead of beside them, `-row` moves it off the head of its row in a five-character note the balance divides three and two, and `-justified` asks §3.8.4's ladder whether it reaches into a block. `constructs` is 18,515 requests and `tabs` is 31,211, which puts all ten censuses at 120,612. §3.8.3's own half of the last variant is deliberately absent: a line that has to give space back beside a note whose two sublines meet at a Table 1 amount is a coordinate the Rust and OCaml engines do not agree on themselves -- the Rust engine divides the line's arrears over that in-block boundary and lays nothing down there, the OCaml engine does not offer the boundary at all -- and a census asks the settled question. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N8KNy2ejPqy81P2hVcRUjs
…erior `docs/decisions/stacked-structure-geometry.md` published four readings about a structure's own two edges and said nothing about the two coordinates inside it, which is why an engine could miss both and still be read as following the file. Both are now stated, and both are the same sentence the file already turns on -- a structure occupies one position on the line -- read on an axis and at a boundary it did not spell out. The block a structure makes is not a depth the line reports: its sublines run beside the line rather than being lines of their own, so a note set at the paragraph's own em leaves the line one em deep and keeps its own two ems to itself. And a character inside the block is spaced like any other: Table 1 answers between two characters of one subline, a member's advance is the step that reaches the member after it, the character that ends a subline reports its body alone, and neither ladder reaches a boundary the line was never composed from. Both were reached by measurement before anything was written down here (#23, #24), which is the footing the census findings in this directory already stand on. The census counts every file quotes follow the seven new variants: `constructs` is 18,515, `tabs` is 31,211, and the ten censuses are 120,612 requests at zero differences across the three engines. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N8KNy2ejPqy81P2hVcRUjs
`db4f6b4` bumps four GitHub Actions in the workflows and touches nothing this branch changes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N8KNy2ejPqy81P2hVcRUjs
This was referenced Aug 24, 2026
P4suta
added a commit
that referenced
this pull request
Aug 24, 2026
… two ends (#28) * fix(jlreq): stop §3.8.3's ladder at the block a warichu makes `reduction_sites` offered the ladder every interior boundary of a stacked structure. Two characters of one subline are one such boundary, and so is the SEAM where a note's two sublines meet -- the last character of the first and the first character of the second are adjacent in the text, so Table 1 states an amount between them like anywhere else. That amount stands nowhere. The character that ends a subline reports its body alone and the character that begins the next one begins it at its own row's origin, so the line was never composed from the seam and there is nothing there to give back. Offering it to the ladder divides the line's arrears over a site that cannot pay them: `※〈〉あ※` at a three-em measure needs 250 units back, has one boundary on the line that can give them and one seam that cannot, halves the debt between the two, recovers 125 and reports `layout.overfull` about a line it could have made fit. The expansion ladder already stopped at the block, through the same construct-interior test `boundary_expansion_site` runs; the reduction ladder now asks the same question of a warichu and a furawake. Neither public API nor any other engine changed, and no other census coordinate moves: this is the only shape where a boundary Table 1 names is not a boundary the line was composed from. Fixes #26 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N8KNy2ejPqy81P2hVcRUjs * fix(racket): give a furawake its columns' own spacing and its own far edge `compose.rkt` gathers a §3.7.2 furawake into ONE item of the line, where a §3.4.2 warichu's members stay items of their own. Two things followed from that and both were wrong. A column was measured from bare cluster advances, so a member standing before a Table 1 amount inside its own column -- `cl-02` then `cl-01`, half of the member's own em -- reported 1000 while the same engine placed the next member 1000 units on and charged the line 1500 for the step. That is the defect #24 fixed for a warichu, at the other structure the same reading is addressed to: a column is ordinary text of the structure, so a member's advance is its body plus the amount after it inside its row, and the member that ends a row reports its body alone. And the one item carried the class of its FIRST cluster, so the boundary AFTER the block was answered at the wrong end of it. A structure has two edges and they are two different characters: the amount before the block is Table 1's answer at the block's first character and the amount after it the answer at its last. The `item` struct now carries a `trailing` edge -- the occurrence a boundary after the item is read against, which is the item itself for anything one character wide -- and every reading of the before side of a boundary asks for it. A tate-chu-yoko run carries none: §3.2.5 makes it cl-30 at both of its edges however many characters it holds. The two errors are equal and opposite wherever the two amounts are, which is why `※〉〈日※` comes out 4500 wide either way and `※・・日※` does not. Both halves had to move together. Neither public API nor any other engine changed, and `across` in `furawake-item` -- computed and read by nobody since the block's depth moved to `block-room` -- goes with them. Fixes #27 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N8KNy2ejPqy81P2hVcRUjs * docs(decisions): publish the seam and the two edges, and reach both at every class pair `engines/ocaml/probe/census.ml` gains three `constructs` variants. The first is the sixth shape PR #25 deliberately withheld: `warichu-pair-inside-reduced` stands the pair under test inside a note on a line that has to give space back, which is where the two answers to "does §3.8.3's ladder reach the seam" come apart in the line's own width. The other two are `furawake-pair-inside` and its vertical mirror, which stand the pair inside one of a furawake's columns and put an ordinary character in the other, so one request asks both what Table 1 does inside a column and which of the block's characters the boundary after it is read against. The `constructs` census is 20,102 requests and all ten are at zero differences across the three engines over 122,199. Against the previous engines the same census reports 15 differing responses for the Rust one and 434 for the Racket one. `docs/decisions/stacked-structure-geometry.md` states both readings, why they follow from the sentences already published there rather than from anything new, and what a revision would have to say to settle either one the other way. The seam is the only boundary of a block that is neither strictly inside a subline nor at the block's edge, which is how an engine can reach it by asking Table 1 about two adjacent characters without asking which object they are adjacent on. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N8KNy2ejPqy81P2hVcRUjs --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two coordinates inside a warichu block were the last places the three reference engines
did not agree, and both are one reading of §3.4.2 that
docs/decisions/stacked-structure-geometry.mdturned on but never spelled out: a note's sublines run beside the line, and the block
they make is one position on it.
Fixes #23
Fixes #24
What was wrong
The block axis (#23).
engines/racket/compose.rktreported a line'sblock_extentas the sum of the note's own subline heights wherever that was larger than the
paragraph's own block size. A note set at the paragraph's em rather than at the half em
§3.4.2's own sizing comes to therefore made the line twice as deep as the paragraph set
it, as though the two sublines were two lines of the paragraph.
The boundary inside a subline (#24). A member reported its bare body as its advance,
so a member standing before a Table 1 amount inside its own row —
cl-02thencl-01,half of the note's own em — reported 500 while the same engine placed the next member 750
units on. The answer's own advances did not reach the answer's own positions.
§3.8.3's half of the same reading.
raw-gap-termshanded the reduction ladder everyinterior boundary at face value, the block's own included, so a line that could not fit a
note squeezed the note's interior instead of overrunning — and gave back space that was
never on the line. The expansion ladder already stopped at a block, through
same-complex?; both now ask one predicate,same-block?.What changed
engines/racket/compose.rkt: the warichu run contributes the paragraph's own blocksize to the line and nothing more; a member's advance is its body plus the amount after
it inside its row, and the member that ends a row reports its body alone; neither
ladder reads a boundary the line was not composed from.
warichu-layoutno longeranswers a height nobody asks for.
engines/racket/tests/test-compose.rkt: three cases computed by hand from §3.4.2 andTable 1 — the full-size note's block extent and placements, the in-row amount and the
advance that reaches it, and the overrun a three-em measure produces rather than a
squeezed block. All three fail on the previous engine.
engines/ocaml/probe/census.ml: five furtherconstructsvariants and two furthertabsones reach both shapes at every one of the 529 class pairs —warichu-full-sizeand its vertical mirror,warichu-pair-inside,warichu-pair-inside-row,warichu-pair-inside-justified,inside-full-size-warichuand-found. Against the previous engine they report 1,643and 1,058 differing responses; against this one, none.
docs/decisions/stacked-structure-geometry.mdpublishes both readings and why, and thecensus counts every file quotes follow the new variants.
Measurements
just conform-racket,just conform-ocamland the Rust sample engine each answer alleighty-nine built-in cases at exit 0;
just check,just designandjust ciare greenlocally.
One thing this PR deliberately does not ask
A sixth
constructsvariant — the same pair inside the note on a line that has to givespace back — is absent, and its comment says why. Where a note's two sublines meet at a
Table 1 amount, the Rust and OCaml engines do not agree with each other: the Rust engine
divides the line's arrears over that in-block boundary and lays nothing down there, so it
gives back half of what it needs and reports
layout.overfull; the OCaml engine does notoffer the boundary at all. This branch's Racket engine answers as OCaml does, which is
what the reading above says. Fifteen coordinates show it, all of the form
census/constructs/cl-01+cl-02/…— a repro is漢〈〉あ漢with the note at the half em, awarichu over the three, and a three-em measure. Worth its own issue rather than a census
that reports a nonzero count.
While measuring it, one further Racket coordinate turned up that is not fixed here and
is nobody's regression: a furawake row is laid out from bare advances, so a member
before a Table 1 amount inside its row is placed and reported the way #24 described for a
warichu. Fixing it needs the boundary after a furawake block to be read against the
block's last character rather than its first, which is a wider change to how
compose.rktmakes one item of a furawake — also its own issue.🤖 Generated with Claude Code
https://claude.ai/code/session_01N8KNy2ejPqy81P2hVcRUjs