Skip to content

Does §3.8.3's ladder reach the seam where a warichu's two sublines meet? The Rust and OCaml engines disagree #26

Description

@P4suta

The constructs census reaches a shape the three reference engines do not all answer the
same way, and it is the first one where two of them disagree with each other rather than
one of them lagging the other two. PR #25 measured it and deliberately left the census
variant out rather than ship a census that reports a nonzero count:

A sixth constructs variant — the same pair inside the note on a line that has to give
space 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 [...] Worth its
own issue rather than a census that reports a nonzero count.

Which of the two answers is right is not settled, and this issue does not settle it. It
records the disagreement and states both readings. engines/ocaml/probe/census.ml says the
same in the comment above warichu-pair-inside-justified.

Input

※〈〉あ※ — a warichu of three half-em members, 〈〉あ (§3.4.2's own note size, which
note in engines/ocaml/probe/census.ml also uses), standing between two ordinary full-em
characters, with no declared break so §3.4.2's own balance picks the split, and a three-em
measure the line cannot meet
.

The balance divides the note two and one, so (Appendix A cl-01) and (cl-02)
share the first subline and (cl-15) has the second. spec/captured/table1.en.tsv
states two nonzero amounts anywhere on this line, and both are 250 units — half of the
note's own half em:

boundary Table 1 amount where it stands
, cl-19cl-01 1/2 af 250 before the block, on the line
, cl-01cl-02 blank 0 inside the first subline
, cl-02cl-15 1/2 be 250 the seam where the two sublines meet
, cl-15cl-19 blank 0 after the block, on the line

spec/captured/table3.en.tsv makes both of the two nonzero boundaries the same reduction
opportunity: cl-19cl-01 and cl-02cl-15 are each 1/2-0 stage 5.

The line's natural width is 1000 + 250 + 1000 (the block, its widest subline) + 1000 = 3250
against a 3000 measure, so §3.8.3 has 250 units to give back. Schema-valid protocol-v1
request (jlreq-conformance validate):

{"protocol":"jlreq.conformance/1","spec":"jlreq-2020-08-11+unicode-17.0.0","id":"issue/warichu-interior-boundary-reduction-ladder","request":{"source":"※〈〉あ※","size":{"inline":1000,"block":1000},"frame":"full-em","clusters":[{"range":[0,3],"advance":1000},{"range":[3,6],"advance":500,"size":{"inline":500,"block":500}},{"range":[6,9],"advance":500,"size":{"inline":500,"block":500}},{"range":[9,12],"advance":500,"size":{"inline":500,"block":500}},{"range":[12,15],"advance":1000}],"line_extent":3000,"constructs":[{"kind":"warichu","range":[3,12]}],"alignment":"start","writing_mode":"horizontal-tb","style":{"profile":"jlreq-2020"}}}

Validated against crates/jlreq-conformance/protocol.schema.json, and accepted by all three
engines with no transport or schema complaint.

What this library produced

The Rust engine, crates/jlreq/src/pipeline.rs, notated
(inline_extent/block_extent) [inline:block+advance ...]:

(3125/1000) [0:0+1250 1125:0+500 1625:0+500 1125:500+500 2125:0+1000]
diagnostics: layout.overfull 3.8.1 [0,15] warning

reduction_sites offers §3.8.3's ladder both of the two 250-unit amounts — the seam's
included, because the seam is a cl-02cl-15 boundary like any other — and the two are the
same stage, so distribute_reduction divides the line's 250 units of arrears equally over
them. The 125 units charged to the boundary before the block come off the line: moves
from 1250 to 1125. The 125 units charged to the seam come off nothing at all: the seam is
inside the block, the line was never composed from it, and there is no space there to give
back. The line ends 125 units over its measure and reports layout.overfull.

It gives back exactly half of whatever is asked of it, at every measure between the natural
width and the point the one real boundary is exhausted:

measure needed Rust gives back Rust inline_extent OCaml and Racket
3250 0 0 3250 3250
3125 125 63 3187 overfull 3125
3000 250 125 3125 overfull 3000

What you expected instead

The OCaml engine (engines/ocaml/lib/pipeline.ml) and the Racket engine
(engines/racket/compose.rkt), byte for byte identical to each other:

(3000/1000) [0:0+1250 1000:0+500 1500:0+500 1000:500+500 2000:0+1000]
diagnostics: none

Neither offers the seam to the ladder at all — the OCaml engine through
is_internal_stacked_boundary, the Racket engine through the same-block? predicate PR #25
gave both of its ladders. The whole 250 units come off the one boundary the line was
composed from, the line meets its 3000-unit measure exactly, and nothing overruns.

Specification basis

JLReq 3.8.3 (reducing the inter-character space of a line that will not fit) and Appendix B
Table 3, read against JLReq 3.4.2 (a warichu's own two lines) and
docs/decisions/stacked-structure-geometry.md.

The two readings, stated as they would have to be written down:

  • The ladder reaches the seam. §3.8.3 and Table 3 are addressed to the boundary between
    two character classes, and the seam is a cl-02cl-15 boundary like any other. Nothing
    in §3.8.3 says a structure's interior is exempt, and an engine that skipped it would be
    reducing by a rule the specification does not state. This is what the Rust engine does.
  • The ladder stops at the block. §3.8.3 adjusts the spacing of the line, and space
    inside a block is not space the line put there — a boundary the line was not composed
    from is not a boundary the line can give back. This is what the OCaml and Racket engines
    do, and it is the reading stacked-structure-geometry already publishes for the block's
    interior boundaries; whether the seam between two sublines is one of those is the
    question, since the amount there is stated by Table 1 and placed by neither engine.

The disagreement is not academic: the first reading makes this line overrun by 125 units
that the second reading recovers, so the two answers differ in the line's own
inline_extent, in three cluster positions and in a diagnostic.

Other implementations

Not checked. A three-em line carrying a bracketed warichu whose sublines meet at a Table 1
amount is a shape no browser composes, and LaTeX's jlreq class reaches it through neither
its warichu macro nor its own line-breaking.

Before submitting


The coordinates. Sweeping the shape above over all 529 ordered pairs of the census's own
Appendix A representatives (just census-classes), the Rust engine differs from the OCaml
and the Racket engines at exactly 15 of them, and the OCaml and Racket engines agree with
each other at all 529:

cl-01+cl-02  cl-01+cl-05  cl-01+cl-07  cl-01+cl-29  cl-05+cl-05
cl-25+cl-02  cl-25+cl-07  cl-25+cl-29  cl-27+cl-02  cl-27+cl-07
cl-27+cl-29  cl-28+cl-02  cl-28+cl-05  cl-28+cl-07  cl-28+cl-29

Every one is a pair whose second class carries a Table 1 amount after it that lands on the
seam. just census constructs does not reach any of them today: its
warichu-pair-inside variants stand on a line wide enough to need no adjustment, and its
warichu-pair-inside-justified variant asks §3.8.4's ladder rather than §3.8.3's. The
sixth variant — the same pair on a line that has to give space back — is the one PR #25 left
out, and adding it is what closes this issue.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    conformanceObservable layout disagreements and protocol cases

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions