Skip to content

Promises

npond edited this page Aug 24, 2026 · 1 revision

Promises

These are the properties the project holds itself to. Each one is enforced by a test that fails the build, not by convention — a promise nobody has fired a shot at is a comment rather than a defence.

Zero dependencies

src/n8PDF carries zero PackageReference entries, and LibraryInvariantTests fails the build if that ever changes. The only things it builds on are the base class library's System.IO.Compression (the DOCX container, and Flate for PDF streams) and System.Xml.Linq. Everything domain-specific is the project's own:

  • OPC relationships and content types
  • WordprocessingML semantics and the style cascade
  • TrueType/OpenType/CFF parsing, metrics, shaping (OpenType and Apple AAT state tables), and subsetting
  • The Unicode bidirectional algorithm and its generated tables
  • PNG, GIF, BMP, TIFF, EMF/EMF+ and JPEG decoding — including progressive and arithmetic JPEG, fax-encoded TIFF strips, and 16-bit and CMYK samples
  • Text measurement, line breaking (the Unicode algorithm, plus Liang's hyphenation patterns), pagination
  • The PDF writer, including Type0/CIDFontType2 embedding with ToUnicode maps

What follows from this: no supply chain beyond the .NET runtime itself, no transitive advisories, no version conflicts in a consumer's dependency graph, and no behavior that changes because a package updated. A task that seems to need a package needs a conversation instead.

A small, frozen public surface

Eight public types (The API). PublicApiTests writes the surface out in full and fails on anything that grows it. A published version is a promise about every public name in it; keeping the surface small is what lets the internals — 170+ types of parser, cascade, font engine, layout and writer — keep improving without breaking anyone.

Warnings are errors

Directory.Build.props sets TreatWarningsAsErrors for every project and every build, so the build that introduces a warning is the build that fails — not the next push to CI. (NuGet audit warnings are the one exception, in the test project only: they report what is known about a package today rather than anything about this code.)

Deterministic output

  • The build is deterministic: the same input builds the same assembly, whoever builds it.
  • The output is deterministic: with CreationDate left null, converting the same document twice produces identical bytes. That is not a nicety — it is what makes golden-trace comparison possible (Validation).

The version is written down once

A release is cut by pushing a tag (git tag v1.0.1 && git push origin v1.0.1). The workflow builds at the version the tag names, runs the same tests every push runs, packs the library with its symbols and documentation, and writes a GitHub release. The tag is the only place a version is written down, and LibraryInvariantTests checks a package cannot disagree with the tag it was cut at.

Documentation ships

GenerateDocumentationFile is on: what a rule is and where it was measured from is written on the types that carry it, and that goes into a consumer's editor with the package. Symbols ship alongside (snupkg) so a stack trace through the converter is readable.

License

MIT. The one piece of third-party data (not code) is Liang's hyphenation patterns, as TeX has distributed them since 1990, turned into generated source; their license asks that the copyright notice be preserved, and the generated source carries it.

What a promise does not cover

Fidelity numbers ("agrees with Word to within 0.72pt") are measurements of the current suite, not API guarantees — they are held by tests and reported honestly in Matching Word, and they improve or are explained, never quietly regressed.

Clone this wiki locally