Skip to content

fix(templates): stop Sidebar Portrait's language block losing rows - #592

Merged
DemchaAV merged 1 commit into
feature/cv-constructor-layerfrom
feat/cv-language-slot
Aug 21, 2026
Merged

fix(templates): stop Sidebar Portrait's language block losing rows#592
DemchaAV merged 1 commit into
feature/cv-constructor-layerfrom
feat/cv-language-slot

Conversation

@DemchaAV

Copy link
Copy Markdown
Owner

Why

Sidebar Portrait's language block accepts a wider "Additional Information" section and
picks the language rows out of it. It had a fallback for a section where nothing matched
— then it drew every row — so the loss needed a mixture: one row that looked like a
language suppressed the fallback, and every row that did not look like one reached no
page at all
. Because the section counted as claimed it never reached the leftover tail
either, so three of the shipped example's four rows were simply gone: work eligibility,
open source, speaking.

A section routed here by SectionRole.LANGUAGES was no safer — English (C1) beside a
plain Deutsch B2 was enough to lose the Deutsch. That is the path the modular contract
advertises, which is what made this worth fixing before the branch goes anywhere.

What

The slot claims in two steps and knows which it got:

  • Entirely languages — routed by the role, or titled for the job — is drawn whole,
    whatever its rows look like.
  • A wider section is still picked over, and the rows the block does not draw go to the
    main column under the title their author wrote, walked in document order so the rest of
    a section keeps the place it had among the sections no slot claimed.

The key list is plural-only. Keys match as a substring of the stripped title, so a
singular "language" would claim "Natural Language Processing" and "Sign Language
Interpreting" for this block and draw them upper-cased in a third of a page's width —
"languages" still reaches "Language Skills", whose stripped title starts with it.

The category row is matched exactly rather than by containing the word, so a row labelled
"Sign Language" keeps its name instead of being expanded into its body; a row whose split
yields nothing falls through instead of being consumed by a branch that drew nothing; and
a level written without brackets is drawn as a level, because the block now hands the
renderer the pair already separated instead of one joined string it had to re-split on a
bracket it may not contain.

Tests

Placement is read off the identity name — the main column draws it, the sidebar does not —
because the words alone cannot say which column drew them. That boundary is asserted to be
drawn exactly once, since it is only a boundary while that holds.

All three language tests go red against the previous commit. That is worth stating
plainly: the first version of the role test used a fixture with no bracket anywhere, which
the old code's all-or-nothing fallback drew whole — so it passed against the bug it named
and guarded nothing. It now puts a bracket on one item and leaves the other two plain,
which is the mixture that actually lost rows.

New coverage: a wider section with no language in it at all (the whole thing goes to the
main column, and the sidebar draws no heading over an empty list), and drawn-once counts
so a row cannot satisfy the assertions by appearing in both columns.

Full reactor gate green, 936 tests. One baseline re-recorded
(sidebar_portrait-page-1 — the rescued rows land on page two; the sidebar is unchanged
and page one does not move), the seventeen visual.approve rewrote as collateral reverted,
and the committed preview refreshed. Measured at budget 0 after the review pass, no CV
preset moves a pixel beyond that one page.

The block accepts a wider "Additional Information" section and picks the
language rows out of it, matching a row whose label names the category or
whose body carries a bracket or a pipe. It had a fallback for a section where
nothing matched — then it drew every row — so the loss needed a mixture: one
row that looked like a language suppressed the fallback, and every row that
did not look like one reached no page at all. The section counted as claimed,
so those rows never reached the leftover tail either. Three of the shipped
example's four rows were gone that way: work eligibility, open source,
speaking. A section routed here by SectionRole.LANGUAGES was no safer —
"English (C1)" beside a plain "Deutsch B2" was enough to lose the Deutsch.

The slot claims in two steps now and knows which it got. A section that is
entirely languages — routed by the role, or titled for the job — is drawn
whole, whatever its rows look like. A wider section is still picked over, and
the rows the block does not draw are handed to the main column, which prints
them under the title their author wrote, walked in document order so the rest
of a section keeps the place it had among the sections no slot claimed.

The key list is plural-only. Keys match as a substring of the title with its
spacing stripped, so a singular "language" would claim "Natural Language
Processing" and "Sign Language Interpreting" for this block and draw them
upper-cased in a third of a page's width; "languages" still reaches "Language
Skills", whose stripped title starts with it.

The row that names the category is recognised by an exact match rather than by
containing the word, so a row labelled "Sign Language" keeps its name instead
of being expanded into its body. A row whose split yields nothing falls
through to the branches below rather than being consumed by one that drew
nothing.

A level written without brackets is drawn as a level: the block handed the
renderer one joined string and the renderer looked for a bracket to split it
again, so "Deutsch B2" came out as a single upper-cased name. The pair travels
separated now, which is also the case the role path exists for.

The three language tests read placement off the identity name, which the main
column draws and the sidebar does not, because the words alone cannot say
which column drew them — and they assert it is drawn once, since the boundary
is only a boundary while that holds. All three go red against the previous
commit; written without the bracket on the first item, the role case would
have passed against it and guarded nothing.
@DemchaAV
DemchaAV merged commit 979f987 into feature/cv-constructor-layer Aug 21, 2026
12 checks passed
@DemchaAV
DemchaAV deleted the feat/cv-language-slot branch August 21, 2026 19:19
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