-
Notifications
You must be signed in to change notification settings - Fork 0
Developers
For anyone cloning the repository and submitting PRs. The short version: the invariants below are load-bearing and enforced by tests; the backlog is GitHub Issues; and any change to layout, metrics or fonts is judged by the fidelity method, not by "looks right".
git clone https://github.com/nathanpond/n8PDF.git
cd n8PDF
dotnet build n8PDF.sln --configuration Release -warnaserror
dotnet test n8PDF.sln --configuration ReleaseRequirements: the .NET 10 SDK. Optional but strongly recommended (required in CI): qpdf (brew install qpdf), fontTools, and FriBidi. If installed, run with them required, because CI will:
N8PDF_REQUIRE_QPDF=1 N8PDF_REQUIRE_FONTTOOLS=1 N8PDF_REQUIRE_FRIBIDI=1 \
dotnet test n8PDF.sln --configuration ReleaseUseful commands:
N8PDF_BLESS=1 dotnet test # re-bless layout goldens after an INTENDED change
tools/make-reference-pdfs.sh # generate missing Word reference PDFs (macOS + Word)
dotnet pack src/n8PDF -c Release # the package, with symbols and documentationConverted fixtures land in artifacts/test-output/ (git-ignored) for eyeballing — they are evidence, not assertions.
Note on CI coverage: 46 of the 143 Word-comparison fixtures need faces only Word ships; hosted CI skips them and says so. A green hosted CI is not the full comparison for anything touching font selection or metrics — see Validation.
Do not breach one without it being the explicit, named point of the change:
-
src/n8PDFcarries zeroPackageReferenceentries.LibraryInvariantTestsfails the build otherwise. Never solve a problem in the library by taking a dependency —System.IO.CompressionandSystem.Xml.Linqare the whole of what is available. A task that seems to need a package needs a conversation instead. -
The public surface is the eight types
PublicApiTestswrites out in full (The API). Making anything public is a deliberate act with a diff to show for it — propose it, do not simply do it. -
Warnings are errors, for every project and every build (
Directory.Build.props). While working you may pass-p:TreatWarningsAsErrors=false; never commit in that state. -
Generated tables are generated. The Unicode tables under
Text/andFonts/and the hyphenation patterns are output oftools/make-*-tables.py. Fix the generator and re-run it; never hand-edit the output, and never add a one-off exception in consuming code for something a table got wrong. -
tools/means build-input generators — everything in it produces something the project consumes. General-purpose scripts do not belong there.
- Never fit a constant to make a test pass. A layout rule is derived, or measured from a probe fixture with its provenance stated. Where a constant is genuinely fitted, that is declared in the code and its gaps stated case by case. Read Matching Word before touching layout.
- A golden updated to match new output proves nothing. A change to layout, metrics or font handling needs its golden diff reviewed — the trace names the run that moved and by how much; you should be able to say why.
- New layout behaviour needs a probe. A feature story should say which fixture proves it; work that cannot be demonstrated against a fixture or golden should say so explicitly and explain how it is checked instead.
- For parsers and decoders, think hostile. Any new code reading document bytes states (and tests) what a crafted input can make it do — see Security for the framing and the existing register.
On nathanpond/n8PDF — not memory files, not README sections, not TODO comments. If work is worth remembering, it is an issue.
Labels (the list is complete; never invent one — gh label list first):
- Severity for findings:
sev:critical,sev:high,sev:medium,sev:low - Source:
security,audit,tech-debt,needs-triage,blocked,epic,documentation - Kind:
feature— a capability that does not exist yet, as against a defect in one that does; it carries no severity
Filing: search first (gh issue list --state all --search "…"); a matching open issue gets a comment, a matching closed one gets reopened. One finding per issue. The body says what, where (path:lines), why it matters, reproduction, suggested fix — and for parser/decoder findings, what a hostile .docx gets out of it. Full filing guidance, including the minimal-reproducing-document ask and the severity definitions, is on Reporting Bugs.
-
gh issue view <n> --comments— all of it. -
gh issue develop <n> --checkout— a linked branch, recorded by GitHub. CI runs on every branch. - Comment a one-line plan on the issue before writing code.
- Reference the issue in commits as
Refs #<n>— neverFixes #<n>(auto-close keywords only fire on the default branch). But beware: a linked branch closes its issue when a PR from it merges anyway, keyword or no keyword. If your merge did not finish the issue, reopen it with a comment saying what is left — checkgh issue view <n> --json stateafter every merge. - Verify: warning-clean build, full suite with the three checkers on, goldens reviewed not just regenerated.
-
Push before closing —
gh issue close <n> --reason completed --comment "Done in <branch> @ <sha>. <what changed>". A closed issue with no code on the remote is a lie told to every other machine. - Cannot finish? Leave it open, comment what blocks it, add the
blockedlabel.
Never: close an issue you did not personally verify; bulk-close; use --reason "not planned" on your own initiative — that is a human's triage call.
- Keep it to one issue's worth of work; reference the issue (
Refs #<n>). - The bar is the verification step above: warning-clean, full suite green with checkers on, goldens reviewed, and — for layout work — the probe or fixture that proves the behaviour.
- The release pipeline is tag-driven and versions come from tags only (Promises); PRs never touch version numbers.
Plan output is issues, not prose: a parent issue labelled epic, children created with --parent <n>, ordering encoded with --add-blocked-by, and each child carrying acceptance criteria as a testable checklist — a story whose criteria cannot be written as something testable is too vague. Stories should be small enough to finish in one sitting, and each feature story names the fixture that proves it.
Using n8PDF
What it does
How it works
Contributing