Skip to content

feat(templates): stop claiming runtime modules as CV meanings - #595

Open
DemchaAV wants to merge 5 commits into
feature/cv-constructor-layerfrom
feat/cv-kind-placement
Open

feat(templates): stop claiming runtime modules as CV meanings#595
DemchaAV wants to merge 5 commits into
feature/cv-constructor-layerfrom
feat/cv-kind-placement

Conversation

@DemchaAV

Copy link
Copy Markdown
Owner

Why

#594 made templates implement module kinds. Slots still asked SectionRole first, so a runtime module titled Опыт работы was treated as Experience. That is the axis the constructor is not: the template does not know Experience from Projects.

What changed

  • SectionRouter.find and SectionAllocation.claim never take a ModuleSection. Typed sections still match by heading.
  • A runtime module stays in document order, or in remaining(), and draws through CvConstructor / leftover renderers.
  • RoleRoutingTest now runs on CvTemplates.modular() and asserts the words reach the page, not that a role named a slot.
  • Lowering tests call asEntries / asRows / asSkills / asParagraph directly — that is still how a leftover takes a preset's existing renderer.

SectionRole is still on ModuleSection so existing builders compile; dropping it from the public constructor payload is the next PR.

Verification

./mvnw -B -ntp -pl :graph-compose-templates testBUILD SUCCESS, 143 tests.

./mvnw -B -ntp -pl :graph-compose-templates,:graph-compose-qa -am test -Dtest=ModularCvTemplateFidelityTest,RoleRoutingTest,SectionAllocationTest,LeftoverSectionTest,SlotHeadingFidelityTest,SectionRouterTestBUILD SUCCESS, 121 tests in qa, 0 failures.

Lane: templates — constructor placement.

Stacked on #594 (feat/cv-constructor-kinds). Next: drop SectionRole from ModuleSection.

A modular template implements one method per CvKind, with no defaults.
JSON picks the shape; the template draws the shape. It does not know
whether the section is Experience. Adding a kind is adding a method,
and every ModularCvTemplate has to implement it.
A ModuleSection is a shape. SectionRouter.find and SectionAllocation.claim
no longer take one: slots still match typed sections by heading, and
modules stay in document order or the leftover tail and draw through
CvConstructor.
@DemchaAV
DemchaAV changed the base branch from feat/cv-constructor-kinds to feature/cv-constructor-layer August 27, 2026 10:30
…role

Dropping role routing was right; dropping the heading match with it was not.
`SectionRouter.find` filtered modules out of the candidate list entirely and
`SectionAllocation.claim` skipped them, so a module reached a slot by neither
route. On a preset that composes fixed slots and keeps a
`SectionAllocation.remaining()` tail that cost nothing. On one that keeps no
tail — ClassicSerif, CompactMono, EngineeringResume, NordicClean, Panel — the
module was dropped entirely, heading and body, with nothing in the API or the
PDF reporting it. `ModuleSectionKindCoverageTest` caught it on classic-serif.

A module now matches by heading on the same terms a hand-written section does.
The distinction the change was reaching for survives: the *role* is still not
consulted, because a CV meaning declared by the document is a thing the template
has no business acting on. A heading is not that — it is the author's own word
for the block, and matching it is what the four record types have always done.

Both entry points also skip a section with no content. An empty section takes a
slot, draws nothing, and leaves the populated section that matches the same keys
to the leftover tail; `LeftoverSectionTest` pins the ordering that exposes it.
`claim` needed this as much as `find` did.

Tests:

- `ModuleReachesEveryPresetTest` (new) walks `CvTemplates.all()` rather than a
  hand-written list, so a preset joins this gate the day it is registered and
  cannot escape by being left out of one. It asserts the item title, the
  employer and the body all reach the page. Sabotaged by restoring the module
  filter: red on the five presets that were losing sections, green again on
  revert.
- `SectionRouterTest.aModuleClaimsASlotByItsHeadingAndNotByItsRole` and
  `RoleRoutingTest.aModuleIsClaimedByItsHeadingButNeverByItsRole` replace two
  tests that pinned the broken behaviour; each keeps a case proving the role is
  ignored, which is the part worth keeping.
- `aTypedSectionAheadOfAModuleKeepsTheSlot` replaces a test whose name promised
  a typed section in the fixture and whose body had none — it now has one.
- `SectionAllocationTest` asserts the claimed module leaves `remaining()`, so it
  cannot be drawn twice.

The CHANGELOG said the presets "do not read the role yet … when the routing work
lands", and described a "role-first choice". Neither is true and neither is
planned; the entry now says what the code does.

Verification: `./mvnw -B -ntp clean verify` — BUILD SUCCESS, qa 1019 green,
templates 143, core 641.

Not fixed here, and not a regression: a module under a heading **no** preset
recognises still reaches the page only where a `remaining()` tail exists. Those
five presets have never had one; the new test documents that gap rather than
pretending it is closed.
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