test(printplay): #204 extract page-grid geometry to pure method + 13 tests - #512
Merged
Merged
Conversation
…tests The Print & Play PDF (PrintAndPlayDocument) computed four derived layout quantities inline in Compose() with ZERO unit coverage: nbColumns, nbRows, nbCardsPerPage, nbPages. A regression in any of them (rounding instead of truncating columns, forgetting the header reserve, flooring instead of ceiling the page count) silently changes how many sheets print and how cards distribute across them, caught only by rendering and eyeballing the PDF. Extracts the arithmetic output-neutral into a pure, deterministic ComputePageGeometry (no QuestPDF dependency, no I/O) + a PrintPlayPageGeometry readonly struct. The call site preserves the exact computation (verified by reading the old inline block before extraction), so rendered output is byte-for-byte unchanged. 13 contract tests pin the layout contract additively (mirrors #500's recto-verso reorder test conventions): - columns: configured honored when >0; zero/negative fall back to floor division; floor-TRUNCATION not rounding (the fragile bit) - rows: floor division of content height - cardsPerPage = rows x columns - pages: ceil(count/perPage); partial last sheet still prints; exact multiple; zero cards -> zero pages - header reserves pageHeight/10 (matches ComposePage header band) - margin subtracted from both dimensions Gate-safe: additive tests + output-neutral extraction. The latent divide-by-zero when cardsPerPage==0 (card larger than content area) is preserved as-is, NOT guarded, and flagged in the XML doc for a separate behavior-change PR. Suite: 342 passed / 0 failed / 5 skipped (baseline 329 + 13 new). Contributes to #204. Refs #500 (sibling recto-verso extraction). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
jsboige
added a commit
that referenced
this pull request
Jun 17, 2026
… method + 9 tests (#521) PdfManager.GenerateAlternateFaceAndBack (the #119 contract) assembles a single PDF where each card's BACK is emitted immediately before its FRONT so that on a recto-verso sheet each back lines up behind its matching front, and the ORIGINAL CardSet order is preserved (so back-less Rules keep their place and appear first). This ordering is a fragile contract with ZERO unit coverage — a regression emitting front-then-back, dropping the back-less cards, or reordering by back-presence silently misaligns every printed sheet, caught only by printing. Extracts the path-sequencing output-neutral into a pure, deterministic OrderImagesForAlternateFaceAndBack (static, no MagickImage, no I/O). The call site emits the exact same path sequence (verified by reading the old inline builder before extraction), so rendered output is byte-for-byte unchanged. 9 contract tests pin the contract additively (mirror #500 recto-verso reorder + #512 page-grid geometry conventions): - per-card: back-then-front when a back exists; front-only when no back; empty back == no back (the IsNullOrEmpty guard) - ordering: original CardSet order preserved (mixed backs NOT grouped); a back-less head card stays first (the Rules-first #119 guarantee) - counts: all-with-back doubles the slot count; all-without-back singles - pairing: back immediately precedes its OWN front (indices 2i, 2i+1) - degenerate: empty input emits nothing Gate-safe: additive tests + output-neutral extraction. Suite 351/0/5 (baseline 342 + 9 new). Contributes to #204. Refs #500/#512 (sibling recto-verso extractions), #119. Co-authored-by: Your <your.email@example.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
42 tasks
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.
What
Dispatch #204 primaire (ai-01 → po-2024): extract ONE fragile uncovered contract in
PrintAndPlayDocumentto a pure method + tests, output-neutral + gate-safe, sibling to #500 (recto-verso reorder).The Print & Play PDF (
PrintAndPlayDocument) computed four derived layout quantities inline inCompose()with ZERO unit coverage:nbColumns— configured value when> 0, else floor(contentWidth / cardWidth)nbRows— floor(contentHeight / cardHeight)nbCardsPerPage— rows × columnsnbPages— ceil(frontCount / cardsPerPage)A regression in any of them (rounding instead of truncating columns, forgetting the header reserve, flooring instead of ceiling the page count) silently changes how many sheets print and how cards distribute across them — caught only by rendering and eyeballing the PDF. This is CLAUDE.md fragile area #2 (manual PDF layout math).
How (output-neutral extraction)
ComputePageGeometry(static, no QuestPDF dependency, no I/O) + aPrintPlayPageGeometryreadonly struct.Compose()call site reproduces the exact prior computation (total margin, header reservepageHeight/10, floor-truncation, ceiling page count) — verified by reading the old inline block before extraction. Rendered output is byte-for-byte unchanged.cardsPerPage == 0(card larger than the content area, or zero columns) is preserved as-is, NOT guarded, and flagged in the XML doc — guarding it is a behavior change that belongs in a separate PR.13 contract tests (mirror #500 conventions)
Namespace
Argumentum.AssetConverter.Tests.WebBasedGenerator, xUnit[Fact]+ FluentAssertions, rich XML docs:>0; zero/negative fall back to floor division; floor-TRUNCATION not rounding (699/100→6, the fragile bit)pageHeight/10; no-header contrastGate safety
RowsetNb/rscount, no workflowContributes to #204. Refs #500 (sibling recto-verso reorder extraction).
🤖 Worker po-2024 — primaire of ai-01 dispatch
msg-20260616T230915-1dn82f.