Skip to content

test(glyph): cover the metrics-only run-topology split from #66 - #81

Merged
thejustinwalsh merged 1 commit into
mainfrom
fix/restyle-run-topology-test
Aug 20, 2026
Merged

test(glyph): cover the metrics-only run-topology split from #66#81
thejustinwalsh merged 1 commit into
mainfrom
fix/restyle-run-topology-test

Conversation

@thejustinwalsh

Copy link
Copy Markdown
Collaborator

Ports the regression scenario from #66, which targets the pre-rename packages/text tree and therefore can never merge. The fix it guards (shaping_run_topology_stable) is already on main at packages/glyph/rust/shaper/src/engine/state.rs:1246; only the test was left behind.

The scenario

A colored span whose fontSize animates through value-equality with its root keeps its style segment (the paint differs) while the shaping-run table merges across it. Runs coalesce on same_layout_style, which compares layout scalars and ignores paint:

// shaping_state.rs:240
&& style_storage.same_layout_style(previous.style, run.style)

// style_state.rs:154 — font_size is a layout scalar
&& self.font_size.to_bits() == other.font_size.to_bits()

So frame 1 (span size == root, different color) merges to one run, and frame 2 (17.5) splits back to three under metrics-only invalidation. The engine once retained the merged shape against the rebuilt table and rejected every later frame with invalidRequest, poisoning the session.

What this test does and does not prove

It drives the merge → split path end to end and asserts the session stays healthy across three frames.

It does not isolate shaping_run_topology_stable. Forcing that function to return true — the pre-fix behaviour — and rebuilding the shaper leaves the entire three-engine-runtime suite green, including this scenario. Some later path absorbs the split as well; the most likely candidate is the refresh_scales_from_stream fallback dropping through to a full rebuild, though that is unverified.

The test therefore lands as a canary over the retained-shape path, and its comment says exactly that rather than claiming a proof it does not deliver.

Follow-up worth taking separately

shaping_run_topology_stable has no other coverage — no Rust test exercises it (the only topology test in the crate covers the unrelated same_edit_run_topology). Combined with the result above, it is worth determining whether the guard plus its two call sites are now redundant. That has a size payoff and belongs with the open items from the Wasm size study, not in this PR.

Verification

  • node --test tests/integration/three-engine-runtime.test.mjs — 1 test, 1 pass
  • pnpm check — exit 0, OKF 0 errors / 0 warnings
  • docs/packages/glyph.md source_digest regenerated for the new package source

Closes #66.

Ports the regression scenario from #66, which was written against the
pre-rename `packages/text` tree and so could never merge. A colored span
whose fontSize animates through value-equality with its root keeps its
style segment while the shaping-run table merges across it -- runs
coalesce on `same_layout_style`, which compares layout scalars and
ignores paint, and `font_size` is one of those scalars. The next tick
moves the size off equality and the table splits again under
metrics-only invalidation.

The engine once retained the merged shape against the rebuilt table and
rejected every later frame with invalidRequest, poisoning the session;
`shaping_run_topology_stable` was added to stop that and is already on
main.

The test does not isolate that guard. Forcing
`shaping_run_topology_stable` to return `true` -- the pre-fix behaviour
-- and rebuilding the shaper leaves the whole suite green, so a later
path absorbs the split as well. It lands as a canary over the
retained-shape path, and the comment says so rather than claiming a
proof it does not deliver. That guard has no other coverage: no Rust
test exercises it.
@github-actions

Copy link
Copy Markdown

size-limit report 📦

Path Size
Core JS (gzip) 18.75 KB (0%)
Shaper Wasm (gzip) 426.1 KB (0%)
Three.js adapter JS (gzip) 61.36 KB (0%)
Inter font · Bitmap (gzip) 545.27 KB (0%)
Inter font · MTSDF (gzip) 6.48 MB (0%)
Inter font · Slug (gzip) 604.06 KB (0%)
Font Awesome icons · Bitmap (gzip) 439.53 KB (0%)
Font Awesome icons · MTSDF (gzip) 6.89 MB (0%)
Font Awesome icons · Slug (gzip) 642.64 KB (0%)
Font validator JS (gzip) 134.24 KB (0%)
Runtime bake host JS (gzip) 5.4 KB (0%)
Runtime bake Worker JS (gzip) 142.47 KB (0%)
Font baker JS (gzip) 2.41 KB (0%)
Font baker Wasm (gzip) 379.63 KB (0%)
Bitmap baker JS (gzip) 4.66 KB (0%)
Bitmap baker Wasm (gzip) 228.34 KB (0%)
MTSDF baker JS (gzip) 5.39 KB (0%)
MTSDF baker Wasm (gzip) 209.22 KB (0%)
Slug baker JS (gzip) 4.01 KB (0%)
Slug baker Wasm (gzip) 181.26 KB (0%)

@thejustinwalsh
thejustinwalsh merged commit 7e85b27 into main Aug 20, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant