Skip to content

A family change re-measures, an unchanged one does not (RFC-0034) - #240

Open
Briany4717 wants to merge 2 commits into
feat/font-propfrom
feat/font-family-invalidation
Open

A family change re-measures, an unchanged one does not (RFC-0034)#240
Briany4717 wants to merge 2 commits into
feat/font-propfrom
feat/font-family-invalidation

Conversation

@Briany4717

Copy link
Copy Markdown
Owner

Stacked on #239, which is stacked on #238. This diff is only the third commit.

The family already reaches the measurement cache key, the layout fingerprint, the sizer callback and the glyph-run key: all four were threaded when the registration landed, because a parameter without a cache key is a bug you know about while you are writing it. What was missing is the half that makes any of it provable.

Both directions, on the same leaf

The negative one carries the weight. A fingerprint that invalidates on everything is trivially correct and useless: it would make every text leaf re-measure every frame, which is precisely the cost the retained path exists to remove. So the test asserts that an unchanged family marks nothing, a changed one marks exactly its leaf, and dropping the family entirely is a change too rather than a return to a neutral value that happens to hash the same as a name.

Alongside it, a recording sizer proves the family reaches the measurement at all. That is the shape of defect this project keeps paying for — everything plumbed, every bookkeeping assertion green, and the value never arriving where it does the work.

Both were watched failing: once with the family dropped from the fingerprint, once with it dropped on the way to the sizer.

Frame budget

Unchanged, and no ceiling is raised. The font table rides every frame, so it is on the per-frame path by construction; the reference scene declares no families and must therefore pay nothing, which the existing allocation ceiling already enforces. The one added assertion records which table that ceiling was measured against, so a later change that starts building a fresh table per frame reads as the regression it is rather than as noise in the number.

Gates

cargo fmt --all --check, cargo clippy --locked --workspace --all-targets -- -D warnings, cargo test --locked --workspace (96 suites, 0 failures), cargo run -p byard-cli -- check crates/byard-cli/examples/font_families.

…-0034)

The family already reaches the measurement cache key, the layout
fingerprint, the sizer callback and the glyph-run key: it was threaded
through all four when the registration landed, because a parameter without a
cache key is a bug you know about while you write it. What was missing is the
half that makes any of that provable.

Both directions on the same leaf, and the negative one carries the weight. A
fingerprint that invalidates on everything is trivially correct and useless,
since it would make every text leaf re-measure every frame, which is the cost
the retained path exists to remove. So: an unchanged family marks nothing, a
changed one marks exactly its leaf, and dropping the family entirely is a
change too rather than a return to a neutral value that hashes the same.

Alongside it, the assertion that the family reaches the sizer at all. That is
the shape of defect this project keeps paying for — everything plumbed, every
bookkeeping assertion green, and the value never arriving where it does the
work — and it is cheap to rule out with a recording sizer.

Both were watched failing: with the family dropped from the fingerprint, and
with it dropped on the way to the sizer.

The frame budget is unchanged and its ceiling is not raised. The table rides
every frame, so it is on the per-frame path by construction; the reference
scene declares no families and must therefore pay nothing, which the existing
allocation ceiling already enforces. The added assertion only records *which*
table that ceiling was measured against, so a later change that starts
building a fresh one per frame reads as a regression rather than as noise.
Copilot AI lite review requested due to automatic review settings September 4, 2026 22:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The changes are additive test/assertion coverage that aligns with existing APIs and validates required RFC-0034 behavior without introducing production-path risk.

Pull request overview

This PR strengthens RFC-0034’s retained-layout and per-frame-budget guarantees by adding tests/assertions that prove font-family changes affect text measurement invalidation, while unchanged families do not trigger re-measurement.

Changes:

  • Adds retained-layout tests verifying (1) unchanged family does not dirty a text leaf, (2) changed family dirties exactly that leaf, and (3) Some(family) -> None is treated as a change.
  • Adds a test proving the leaf’s family value actually reaches the TextSizer measurement callback.
  • Extends the frame-budget test to assert the reference scene’s frame carries an empty font table, tying the allocation ceiling to the intended “no declared fonts” baseline.
File summaries
File Description
crates/byard-platform/tests/frame_budget.rs Adds an assertion that the reference scene’s frame has no declared fonts, clarifying what the allocation ceiling is measured against.
crates/byard-core/src/atlas/layout/retained_build_tests.rs Adds retained-layout tests ensuring family participates in dirtying behavior and reaches the text sizer.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

The paint digest decides whether a primitive is redrawn by comparing its own
bytes at its own pool position, and the text line's hash covered its content,
its position, its size and its colour. Not its weight, and not its family.

So a heading that turns bold, or a title that changes typeface, was judged
clean and kept the previous frame's pixels. It rendered correctly exactly
once, on the frame it first appeared, and never again. The glyph run was
re-shaped, the buffer was correct, and the encoder was told not to draw it.

Weight reached the shaper without reaching this hash when the axis landed;
family arrived by the same route. It is one omission made twice, which is why
both go in together rather than as two changes that would each have looked
like a special case.

Watched failing on the weight half before the fix, and the test carries the
control that matters: after both changes, the same line a third time must
still be clean, so the two assertions above it are not passing because
everything is dirty.
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.

2 participants