The 146-document registry
What it guarantees
Every document type GreatBook knows about has exactly one record, describing what it is, how to recognise it, what to extract from it, and what it does to the books. That record is generated from the ontology assets, not hand-maintained. Four independent consumers read the same file, so none of them can hold a different opinion about what a supplier invoice is.The shape of it
146 records, split by category:
Each record carries:
One record, in full
worthstate_models.schema.json value is a legacy source filename emitted by the current generator, not a product or service name.
The classification cues are bilingual.
Vietnamese source documents say hoá đơn GTGT đầu vào, not “supplier VAT invoice”, and a registry that only carried English tokens would classify by luck.
The definition states the accounting effect inline.
CREATES AP + 133 is a claim the posting rules then have to honour, and a mismatch between what a document type says it does and what the posting produces is a real defect - it is exactly how the missing input-VAT split was found.
The accounting effect
The field that connects a document to the books.
The largest bucket by far is
none.
That is the right shape: most documents in a business are evidence, and treating them as postable is how a book fills with entries nobody asked for.
Line items come from the document, not the table
Seventeen document types carry alines array.
The line shape is derived from the ontology’s own lines: {type: array, items: {$ref: LineItem}}, not from a line_table field on the record.
No record has a line_table, so anything built on it is dead code - and something was, which is why every bill once extracted lines: [].
Lines ride their own state key through the graph, never inside the flat field map, so validation can present them back under the schema’s own property name before the shape check.
Four consumers, one file
- The Clerk classifies against the cues, loads the record, and extracts the declared fields against the referenced schema.
- The Typewriter proposes documents from the same catalog, so a proposal opens in the builder as a document the Clerk will recognise.
- The SOP corpus generates its per-document-type intake rulebooks from the registry, so an agent’s playbook cannot describe a document type that does not exist.
- The renderer reads the same schema, and its Docker build asserts at build time that the schema parses and carries at least 146 types.
Regenerate, do not hand-edit
The registry is generated from the ontology. Editing it by hand produces a file that the next regeneration silently overwrites, and in the meantime an agent is working from a description of a document that does not match its schema.Where it is enforced
The records wrap under the top-level key
documents.
The loader also tolerates a development stub shape and a bare list, which exists because a mismatch there once broke graph loading in a way that looked like a model failure rather than a file-format one.The test that would fail if it broke
langgraph_chat/agents/tests/test_integration.py loads the real registry, builds the dependencies and compiles the graph.
That is the guard against a file-shape regression reaching production disguised as something else.
The renderer’s build-time assertion is the other end of it, and the renderer suite includes a gate that renders all 146 types.
What goes wrong without it
Two copies of the document catalog is the failure. The Clerk classifies a type the renderer cannot lay out, or the Typewriter proposes fields the builder’s validator rejects, and each side looks correct on its own. That is the hardest class of defect to diagnose, because there is no wrong line of code - only two files that used to agree.Related
- The Clerk - classification and extraction against the registry
- The Typewriter - composing from the same catalog
- Composition and the render seam - the renderer’s half
- The SOP store - the rulebooks generated from it