Reasoning
Class:
reasoning· audience: "why is nornir shaped like this?" This is thef0file — why the overall shape, and the big rejected alternatives that cut across functions. Per-function "why" lives in each*-reasoning.md. The descriptive what is indesign.md; nothing here restates it — this file is only the forks in the road and the reasons we took the branch we took.
f0 — why one warehouse, peer functions, few surfaces
The whole design falls out of one commitment: every fact nornir knows is an append-only Iceberg row, keyed by the git SHA it was true at. Given that, the rest is forced.
- Why peer verb-functions, not a hierarchy. If
build"owned"test, orrelease"contained"docbook, then the containing function's data model would leak into the contained one and you could not ask "what did the tests say at SHA X?" without going through "the build". By making every function a peer that reads/writes the shared warehouse, each capability is answerable on its own, at any SHA, and uses-edges between them are explicit rather than structural. The function map (f0) is a bus, not a tree. - Why a single substrate. The alternative — a store per function (a test DB, a release DB, a docs index, …) — was rejected because cross-function questions ("did the release that shipped SHA X pass the coverage gate recorded at SHA X?") become distributed joins across schemas nobody owns. One catalog, one SHA key, and those are a single scan.
- Why few surfaces over many entry points. CLI, viz, serve and key are how you reach a function, deliberately kept off the function axis. A surface must never grow business logic — if it does, two surfaces drift. The MCP/gRPC server and the CLI call the same function code, which is what lets an airgapped agent do everything the CLI can.
Rejected: shelling out (and Mermaid, and JS)
nornir is 100% Rust with no subprocess and no JavaScript: git via gix/russh, Iceberg via skade, docs/diagrams via embedded typst. We rejected the pragmatic "just call the git binary / a Node renderer / Mermaid" path because a shellout makes the tool non-hermetic — it can't run in the airgap, its behaviour depends on what's on PATH, and it can't be a single static binary. The one accepted C exception is the vector embedder's ONNX/tokenizer (opt-in, isolated) — see vector.md. Diagrams are never Mermaid (NUKE-MERMAID): every figure is a static SVG, so the README renders on any git host and the book renders with no diagram engine. The full docbook rationale is in docbook-reasoning.md.
Rejected: reconstructing state from a git walk
The tempting cheap version of "past state" is to git checkout <sha> and re-derive. We rejected it: it is slow (a full re-scan per query), it is lossy (test results, bench numbers and coverage were never in git), and it cannot answer "what did we know at SHA X" — only "what was the source at SHA X". The warehouse records the derived facts too, so a past state is a warehouse read, not a rebuild. Why Iceberg specifically, why a single-writer redb catalog, and the rejected service-catalog (Nessie/Polaris) alternative are in warehouse-reasoning.md.
Rejected: one fat book
The docs used to render to a single book.pdf. We split it into three books by audience — manual.pdf (design + guide, thin), idiot_guide.pdf (every step), unsorted.pdf (the why + the record) — because a single lump forces one reader's needs on every reader, and it made the manual grow every time someone added rationale. The chosen-design rule (a design section names only the design we run; every alternative moves here, to reasoning) is the discipline that keeps manual.pdf thin. This file, and every *-reasoning.md, is where the pruned "why" lives — kept, never thrown away. Full argument: docbook-reasoning.md.
Where each "why" lives
| the question | answered in |
| why a workspace is a redb-registry set, not a TOML file | workspace-reasoning.md |
| why Iceberg + single-writer redb + SHA keys | warehouse-reasoning.md |
| why one gate matrix, bench-as-gate, headless robot | test-reasoning.md |
| why rehearse-before-promote, gates-as-code, the publish traps | release-reasoning.md |
| why typst + three books + suffix-routing | docbook-reasoning.md |
| why a single-writer in-process job ledger | jobs-reasoning.md |
| why sealed bundles over a registry mirror | airgap-reasoning.md |