iftypeset/docs/14-document-ci-model.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

3.9 KiB

iftypeset as Document CI (the mental model)

iftypeset should behave like eslint + a renderer + a preflight tool + a report generator.

Rendering is one stage. The product is: profiles + gates + artifacts + exit codes.

This document is the “shared understanding” for humans and Codex sessions.


The pipeline

Input: Markdown (plus assets)
Profile: web_pdf, print_pdf, dense_tech, memo, slide_deck
Pipeline: validate → lint → render → qa → report
Output:

  • Machine artifacts (*.json, optionally *.sarif)
  • Human artifacts (*.md and an out/report/index.html)
  • Deterministic outputs (or explicit nondeterminism in the trust contract)
  • Exit codes that CI can gate on (no “looks good on my machine”)

The one command humans and CI want

iftypeset run --input docs/spec.md --profile web_pdf --out out

Expected behavior:

  • Runs the full pipeline.
  • Writes artifacts under out/.
  • Exits non-zero when must-level gates fail.
  • Prints a short, boring summary to stdout (what failed, where to look).

Subcommands (when you want control)

Spec + registry

iftypeset validate-spec --spec spec --build-indexes
iftypeset profiles list
iftypeset gates show --profile web_pdf
iftypeset rules list --category links
iftypeset rules show HOUSE.LINKS.URLS.PREFER_HTTPS

Lint (source-level)

iftypeset lint --input docs/spec.md --profile web_pdf --out out
iftypeset lint --input docs/spec.md --profile web_pdf --out out --fix --fix-mode rewrite

Rendering (adapter-based)

iftypeset render-html --input docs/spec.md --profile web_pdf --out out
iftypeset render-pdf  --input docs/spec.md --profile web_pdf --out out

Post-render QA (where the money is)

iftypeset qa --out out --profile web_pdf

Reports (human artifact hub + trust contract)

iftypeset report --spec spec --out out

Outputs a clickable hub:

  • out/report/index.html
  • out/trust-contract.md and out/trust-contract.json

Exit codes (CI-friendly)

The CLI should be unambiguous:

  • 0: pass (no failing gates)
  • 1: gate failed (must violations / gate thresholds breached)
  • 2: usage/config error (bad flags, missing profile, missing input)
  • 3: internal/tool error (renderer crash, missing dependency)

If we ever add “nondeterminism detected” as a separate code, it must be documented here and in app/CLI_SPEC.md.


Artifacts (what you keep)

The durable contract is: everything important is written to out/ and is stable across runs.

Minimum set:

  • out/lint-report.json
  • out/manual-checklist.md (and optionally .json)
  • out/render.html + out/render.css
  • out/render.pdf (when a PDF engine is available)
  • out/layout-report.json
  • out/qa-report.json
  • out/run-summary.json
  • out/trust-contract.{md,json}
  • out/report/index.html

The trust contract must state, in plain language:

  • what is enforced automatically vs manual checklist
  • QA limitations (what we detect vs what we currently miss)
  • determinism assumptions (renderer version, fonts, locale)

Configuration

Repo defaults live in iftypeset.yaml. Priority order:

  1. CLI flags
  2. iftypeset.yaml
  3. profile defaults
  4. hard defaults

Humans need predictable overrides because humans are chaos.


Profiles are the product

A profile is a contract, not a vibe:

  • which rules apply
  • which are must vs should
  • which incidents fail gates
  • which tokens/CSS are used
  • which renderer(s) are recommended

Everything emitted should name the profile explicitly.


Traps to avoid

  • Treating iftypeset as “pretty PDF generator” instead of CI for doc quality.
  • Shipping false authority (big rule counts) without a clear enforced/manual split.
  • Overfitting to one renderer (adapters are the point).
  • Sneaking copyrighted text into the repo (paraphrase + pointer discipline is non-negotiable).