fix(templates): head every slot with the section's own title - #590
Merged
Conversation
Three presets renamed the author's sections. Sidebar Portrait headed all six of its slots with a label chosen when the preset was written — "Employment History" reached the page as EXPERIENCE and "Education & Certifications" as EDUCATION — Monogram Sidebar did it to its sidebar skills block, and Mint Editorial to its profile and its skill bars. The rename is invisible in a CV whose headings happen to match the preset's vocabulary and wrong in every other one, and a CV assembled at runtime carries headings nobody in the library chose, which is the reason its author wrote them. Every slot that draws a section now prints that section's title. Two blocks keep a label because neither draws the section it was handed. Sidebar Portrait's language list picks the language rows out of an "Additional Information" section — three of that fixture's four rows reach no page at all — so its title there would head content the reader cannot see; the block takes the title whenever every row it was given was drawn. Mint Editorial draws one skills section as two adjacent blocks, an index of the group names and then a bar per skill, which cannot both carry one title: the author's heads the index, the block a reader reaches first, so the section opens in their words even when the column flow puts the bars on the next page. Monogram Sidebar's four main slots already read the title through a title().isBlank() ternary whose blank branch could not run — every CvSection rejects a blank title in its constructor — and those branches are gone. A longer heading also has to fit a narrower column. Letter-spacing inserts a space between every pair of letters and wrapping breaks on whitespace, so "EDUCATION & CERTIFICATIONS" came out as "EDUCATION & CERTI / FICATIONS". TextOrnaments.spacedUpper now uses U+00A0 for the gap inside a word: Character.isWhitespace is false for it, so a break falls between words wherever a boundary exists, and a single word wider than its column is still split. Sidebar Portrait's character-for-character copy of that helper is deleted — the duplicate is what let the fix reach one preset and not the two others this change gives long author-written headings to. SlotHeadingFidelityTest renders each preset a document of exactly the sections its slots claim plus one the tail is guaranteed to draw, and asserts every slot heading appears above that marker: the leftover tail prints titles verbatim too, so without the ordering a title found anywhere would prove nothing about the slot. LeftoverSectionTest used to read placement off the heading — the slot's label against the tail's title — which this change removes as a signal; it reads placement off the order now, which asserts the position directly rather than by proxy. The continuation-page control in SidebarPortraitContentFidelityTest measured a literal read off one rendering and the moved content invalidated it; it measures the difference the page-margin rule makes instead, which attributes the inset to the rule and does not need loosening when the fixture shifts. composedText stood in three test classes verbatim; it moves to CvComposedText with the normaliser the assertions share, and the copies are gone.
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.
Why
ModularCvTemplatepromises that a section assembled at runtime reaches the page under theheading its author wrote. Three of the presets that are about to declare it did the
opposite: Sidebar Portrait headed all six of its slots with a label chosen when the
preset was written, Monogram Sidebar its sidebar skills block, Mint Editorial its
profile and its skill bars. A CV whose section is titled "Employment History" reached the
page as EXPERIENCE; "Education & Certifications" as EDUCATION.
The rename is invisible in a CV whose headings happen to match the preset's vocabulary,
and wrong in every other one — and a CV assembled from data carries headings nobody in the
library chose, which is the reason its author wrote them.
What
Every slot that draws a section prints that section's title. Two blocks keep a label,
because neither draws the section it was handed:
Information" section. Three of that fixture's four rows reach no page at all, so the
section's title there would head content the reader cannot see. The block takes the
title whenever every row it was given was drawn — the normal case for a section routed
there by its role rather than by a keyword.
names, then a bar per skill. They cannot both carry one title, so the author's heads the
index — the block a reader reaches first — and the section opens in their words even when
the column flow puts the bars on the next page. The bars carry the preset's own "Skills",
and nothing at all when the section is itself titled that.
Monogram Sidebar's four main slots already read the title, through a
title().isBlank() ? "…" : title()whose blank branch could not run: everyCvSectionrejects a blank title in its constructor. Those branches are gone.
Wrapping. A longer heading also has to fit a narrower column. Letter-spacing inserts a
space between every pair of letters and wrapping breaks on whitespace, so
"EDUCATION & CERTIFICATIONS" came out as "EDUCATION & CERTI / FICATIONS".
TextOrnaments.spacedUppernow uses U+00A0 for the gap inside a word:Character.isWhitespaceis false for it, so a break falls between words wherever aboundary exists, and a word wider than its column is still split. Sidebar Portrait's
character-for-character copy of that helper is deleted — the duplicate is what would have
let the fix reach one preset and not the two others this change gives long author-written
headings to.
Tests
SlotHeadingFidelityTestrenders each preset exactly the sections its slots claim plus a"Publications" section the tail is guaranteed to draw, and asserts every slot heading
appears above that marker. The leftover tail prints titles verbatim too, so without the
ordering a title found anywhere in the document would prove nothing about the slot.
Two existing tests changed for reasons worth naming:
LeftoverSectionTestread placement off the heading — the slot's label against thetail's title — which is exactly the signal this change removes. It reads placement off
the order now, against a section that can only be in the tail: that asserts the position
directly rather than by proxy.
SidebarPortraitContentFidelityTestpinned the unruledpage to a literal read off one rendering (
< 6.0), and the moved content made it 8.0. Itmeasures the difference the page-margin rule makes instead, so it attributes the inset to
the rule exactly and does not need loosening the next time the fixture shifts.
Every behavioural site was reverted one at a time to check the guard goes red — 14 of them,
including both directions of the language rule and the wrapping fix. All 14 red.
Measured, not assumed. The pixel gate stayed green throughout: the change moves 12,652
pixels on the Sidebar Portrait page against a 50,000 budget sized for cross-platform font
drift, so it would have shipped unnoticed. Setting the budget to 0 showed the three presets
had zero mismatch before this change while thirteen untouched ones differ by 69–47,959,
which is what makes the numbers above attributable. The U+00A0 gap on its own renders
0 changed pixels, and the cover letters — which share the ornament — report identical
numbers with and without it.
Five baselines re-recorded (
sidebar_portrait×2,monogram_sidebar,mint_editorial×2);the twelve
visual.approverewrote as collateral were reverted, which mattered here becausecommitting them would have baked this machine's drift in as the reference. Four committed
previews refreshed. Full reactor gate green.
composedTextalso stood verbatim in three test classes; it moves toCvComposedTextalongside the normaliser the assertions share, and the copies are gone.