novolis-documents (book PDF island)
Policies that keep the org coherent
name: novolis documents repo overview: Stand up Novolis-Platform/novolis-documents from the official template (correctly baselined), add Novolis.Math.Measure in novolis-math, then ship a narrow book PDF stack (Documents → Layout → Skia) with dogfood and platform registration—QuestPDF stays default for Manuscript. todos:
- id: baseline-repo
content: gh create novolis-documents from template; clone; rename identity; docs/slnx/nuget baseline; push main status: completed
- id: math-measure
content: Add Novolis.Math.Measure in novolis-math (types, tests, docs, boundaries); publish to GPR status: completed
- id: documents-model
content: "Novolis.Documents: BookDocument, blocks, TrimPresets, chrome; PackageRef Math.Measure" status: completed
- id: documents-layout
content: "Novolis.Documents.Layout: ITextMeasurer, PagePlan, H1/TOC pagination + fake-measurer tests" status: completed
- id: documents-skia
content: "Novolis.Documents.Skia: BookPdf + SkiaSharp; integration test; push publish" status: completed
- id: dogfood-platform
content: HelloBook dogfood; Generate-Platform-Slnx; org landing; verify-nuget-only + project-ref-mode status: completed isProject: false
Source of truth: novolis-documents-spec canvas. Spec locked: one-column book printer (cover / TOC / body / chrome), Skia paint, not a QuestPDF clone.
Locked decisions
- Math lives in `novolis-math`: new peer facet
Novolis.Math.Measure(BCL-only). Documents never owns Length/Size/Thickness/Rect. - Measure shapes are scalar records (
Lengthin points;Size= Width+Height;Thickness;Rect= X/Y/Width/Height asLength). No `Vector2`, no*2Dsuffixes (library-boundaries.md). - Repo create: GitHub template → clone
d:\novolis\novolis-documents→ rename identity → first packages → pushmain(maintainer path, no PR). - v1 packages:
Novolis.Documents,Novolis.Documents.Layout,Novolis.Documents.Skia(+ shared unit tests). No separateDocuments.Testingpackage — fakeITextMeasurerlives in unit tests. - Out of v1: Manuscript QuestPDF replacement / adapter flag; lists/tables/images/code blocks; fluent layout DSL.
- HelloBook demo in `novolis-dogfooding`, not under library
apps/.
flowchart LR
measure[Math.Measure]
docs[Documents]
layout[Documents.Layout]
skia[Documents.Skia]
dogfood[HelloBook dogfood]
measure --> docs --> layout --> skia --> dogfoodPhase 0 — Create and baseline `novolis-documents`
- Create public repo from template:
gh repo create Novolis-Platform/novolis-documents --public --template Novolis-Platform/novolis-template-dotnet --clone=false- Clone to `d:\novolis\novolis-documents`.
- Rename identity per repository-policy.md / template README:
NovolisGitHubRepository→novolis-documentsinDirectory.Build.props- Solution →
Novolis.Documents.slnx - Marketing README header / docs blurbs for documents island
- Confirm baseline:
net10.0,nuget.config= nuget.org + GitHub Packages only, CalVerbuild/version.json, thin.github/workflows→novolis-workflows, MIT LICENSE,docs/getting-started.md+design.md+release.md, noapps/. - Scaffold empty packable projects +
tests/Novolis.Documents.Unit(TUnit), wire slnx, fill.novolis/packages.json. - Push
mainsomerge.ymlcan publish when packages have content.
Phase 1 — `Novolis.Math.Measure` in novolis-math
Add `d:\novolis\novolis-math\src\Novolis.Math.Measure\` as a fourth BCL-only peer (same skeleton as Arrays/Topology).
| Type | Role |
|---|---|
| `Length` | Points (1/72"); `LengthUnits.FromInches` / `FromMillimeters` / `FromPoints` |
| `Size` | Width + Height `Length` |
| `Thickness` | Left/Top/Right/Bottom |
| `Rect` | X/Y/Width/Height as `Length` (page box; not a vector type) |
Wire: csproj + package README → `Novolis.Math.slnx` → ProjectReference + tests/Novolis.Math.Unit/Measure/ → update `docs/design.md` facet table + root README → list Measure in library-boundaries.md Math facet table.
Publish math to GPR (push origin main on novolis-math) before documents PackageReferences can restore from GitHub Packages. Local iteration: Platform.slnx ProjectRef mode.
Phase 2 — Documents model + Layout + Skia
`Novolis.Documents`
BookDocument,BookMeta,PageSetup,Typography,RunningChrome,LastPage- Closed blocks: Cover, Toc, Heading (1–3), Paragraph, SceneBreak, PageBreak, BlankPage
TrimPresets: TradePaperback6x9 (primary, matches `ManuscriptPrintSettings`), Digest5.5×8.5, A5, USLetter- PackageReference:
Novolis.Math.Measureonly (no Skia, no Markdig)
`Novolis.Documents.Layout`
ITextMeasurer,PagePlan/PageSlice/PlacedBlock- Algorithm: content rect = trim − margins − chrome bands; cover page; flow body; H1 break when prior content; optional TOC second pass; last page
- Unit tests with fake measurer (A4)
`Novolis.Documents.Skia`
- SkiaSharp pinned in documents
Directory.Packages.props BookPdf.Write/ToBytes+BookPdfOptions(font paths)- Skia implements
ITextMeasurer; no Skia types on Documents/Layout public APIs - One integration test: non-empty PDF + page count (A5)
Design docs in-repo must state hard non-goals from the canvas (no fluent layout, no tables/images in v1, Avalonia-free).
Phase 3 — Dogfood + platform registration
novolis-dogfoodingHelloBook console: build sampleBookDocument→ PDF under artifacts.- Regen platform map:
pwsh -File d:\novolis\novolis-governance\build\Generate-Platform-Slnx.ps1- Refresh org landing after public repo + workflows exist:
pwsh -File d:\novolis\.github\scripts\Update-OrgLandingStatus.ps1- Verify:
pwsh -File d:\novolis\novolis-governance\scripts\verify-nuget-only.ps1
pwsh -File d:\novolis\novolis-governance\scripts\verify-project-ref-mode.ps1 -SkipBuildAcceptance (v1)
| ID | Criterion |
|---|---|
| A1 | Trade 6×9 PDF: cover + ≥2 chapters + footers with page numbers |
| A2 | Optional TOC with chapter titles + page refs |
| A3 | Header/footer suppressed on cover; present on body |
| A4 | Layout unit tests without native Skia |
| A5 | Skia integration test: bytes + page count |
| A6 | MIT, net10.0, NuGet-only, Avalonia-free, no library `apps/` |
Explicitly deferred
- Manuscript Export.Pdf adapter / QuestPDF swap (keep books-grade QuestPDF until Documents proves A1–A5 on real book trees)
Novolis.Documents.Testingpackage- Geometry ProjectReference to Measure (add later only if Geometry APIs need these types)