iftypeset/docs/14-external-review.md
codex e92f1c3b93
Some checks are pending
ci / ci (push) Waiting to run
iftypeset: document CI pipeline + Playwright + font contract
2026-01-08 18:10:41 +00:00

6.7 KiB

iftypeset external review pack (public technical overview)

This document is a self-contained brief for external reviewers. It explains what the project does, what is implemented today, how to verify it locally, and what limitations remain. It does not include any copyrighted book text.

Scope and non-negotiables

  • No Chicago/Bringhurst text is stored here. Rules are paraphrases with pointer refs only.
  • The runtime is deterministic by design, but PDF output still depends on the chosen renderer and fonts.
  • QA is rule- and heuristic-based; it does not claim perfect layout verification.

What iftypeset is

iftypeset is a deterministic Markdown -> HTML -> PDF pipeline with:

  • a machine-readable rule registry (NDJSON) with paraphrased rules + pointers
  • profiles that map typographic intent into CSS tokens
  • lint + QA gates that surface layout failures and fail builds in CI

The core value is not "pretty PDF." It is verifiable, repeatable quality gates and explicit limits.

What is implemented now

Runtime surface (CLI):

  • validate-spec, report, lint, render-html, render-pdf, qa, emit-css, run
  • introspection: profiles list, gates show, rules list, rules show

Artifacts produced:

  • out/lint-report.json, out/manual-checklist.md/json
  • out/render.html, out/render.css, out/render.pdf (if renderer present)
  • out/layout-report.json, out/qa-report.json
  • out/coverage-report.json, out/coverage-summary.md
  • out/trust-contract.md/json
  • out/report/index.html (HTML index of all artifacts)
  • out/run-summary.json (CI-style run summary)

Quick verification (local)

From the repo root:

python3 -m venv .venv
. .venv/bin/activate
python3 -m pip install -r requirements.txt
python3 -m pip install -e .

iftypeset validate-spec --spec spec --build-indexes
iftypeset run --input fixtures/sample.md --out out --profile web_pdf --degraded-ok --skip-pdf
iftypeset report --spec spec --out out

Expected files after a successful run:

  • out/run-summary.json
  • out/report/index.html
  • out/lint-report.json
  • out/render.html
  • out/layout-report.json
  • out/qa-report.json

If you have a PDF engine installed, omit --skip-pdf and expect out/render.pdf + out/render-log.json.

Proof points (code excerpts)

Console entrypoint (shows the CLI is installed as a tool):

[project.scripts]
iftypeset = "iftypeset.cli:main"

CI pipeline definition (ensures spec validation + report + tests run):

run_step "validate-spec" env PYTHONPATH=src python3 -m iftypeset.cli validate-spec --spec spec --build-indexes
run_step "report" env PYTHONPATH=src python3 -m iftypeset.cli report --spec spec --out out --build-indexes
run_step "tests" python3 -m unittest discover -s tests -p 'test_*.py'

End-to-end integration test (lint -> render -> qa):

lint = subprocess.run([... "lint", "--input", fixture, "--out", out_dir, "--profile", "web_pdf"], ...)
render = subprocess.run([... "render-html", "--input", fixture, "--out", out_dir, "--profile", "web_pdf"], ...)
qa = subprocess.run([... "qa", "--out", out_dir, "--profile", "web_pdf"], ...)

CI-style run command writes a single summary artifact:

{
  "ok": true,
  "exit_code": 0,
  "started_at_utc": "...",
  "finished_at_utc": "...",
  "steps": [
    {"name": "validate-spec", "rc": 0, "ok": true},
    {"name": "lint", "rc": 0, "ok": true},
    {"name": "render-html", "rc": 0, "ok": true},
    {"name": "render-pdf", "rc": 3, "ok": false},
    {"name": "qa", "rc": 0, "ok": true},
    {"name": "report", "rc": 0, "ok": true}
  ]
}

Rule registry (how to read it)

  • NDJSON files in spec/rules/**.ndjson
  • Schema in spec/schema/rule.schema.json
  • Pointers in source_refs (e.g., CMOS18 §X.Y pNNN (scan pMMM) or HOUSE §... pN)
  • No verbatim book text is stored in this repo

Example record shape (paraphrased, non-quoted):

{
  "id": "HOUSE.LINKS.URLS.PREFER_HTTPS",
  "category": "links",
  "severity": "should",
  "enforcement": "lint",
  "rule_text": "Prefer https links in published outputs."
}

Lint and manual checklist

  • Automated rules are enforced in src/iftypeset/linting.py.
  • Non-automated rules are tagged manual_checklist=true and emitted to out/manual-checklist.md.
  • This ensures reviewers see what still needs human validation.

QA (HTML + PDF)

HTML analysis:

  • detects overfull tokens, table/code overflow risk, long URL wrapping risk

PDF analysis (heuristic):

  • uses Poppler (pdfinfo, pdftotext -layout) to extract per-page text
  • detects widows/orphans, stranded headings, overfull lines
  • warnings are explicit about heuristic limits

Renderers

render-pdf uses the requested engine (default: playwright):

  1. playwright (preferred; supports header/footer templates)
  2. wkhtmltopdf (explicit --engine wkhtmltopdf only)
  3. weasyprint (explicit --engine weasyprint only)

If no engine is present, render-pdf returns exit code 3 and QA continues with HTML.

Trust contract

iftypeset report generates:

  • out/trust-contract.md
  • out/trust-contract.json

These explicitly state:

  • enforced vs manual coverage
  • QA limitations
  • determinism assumptions

This is the preferred artifact for external review.

Production readiness (what is true today)

Verified by CI and tests:

  • spec validation and coverage reporting are deterministic
  • lint emits JSON + manual checklist and is stable across runs
  • HTML rendering is deterministic given the same inputs
  • QA gates are enforced with explicit exit codes
  • run provides a single CI-friendly summary artifact

Known limitations:

  • PDF QA is heuristic, not geometry-accurate
  • PDF output depends on renderer + font availability, but render-log.json records font resolution/embedding and profiles can enforce a strict fonts contract to prevent silent fallbacks
  • not all rules are automated; manual checklist remains required

Where to look in the repo

  • CLI: src/iftypeset/cli.py
  • Linting: src/iftypeset/linting.py
  • QA: src/iftypeset/qa.py
  • Rendering: src/iftypeset/rendering.py
  • Rule schema: spec/schema/rule.schema.json
  • Rule batches: spec/rules/**.ndjson
  • Profiles: spec/profiles/*.yaml
  • Trust contract: out/trust-contract.md (generated)
  • Report index: out/report/index.html (generated)

Forgejo integration (worker)

The Forgejo worker can load the iftypeset-web_pdf theme (vendored CSS). See:

  • forgejo/README.md in this repo
  • worker/pdf/README.md in the forgejo-pdf repo

Contact and review checklist

For external review, please verify:

  1. iftypeset run succeeds and produces out/run-summary.json
  2. out/report/index.html links to all expected artifacts
  3. out/trust-contract.md reflects the current enforcement split
  4. out/manual-checklist.md exists and is non-empty