Skip to Content
RuntimeSemantic & Computation Registries

Semantic & Computation Registries

If the typed query algebra is the runtime’s grammar, the registries are its dictionary. They are the mechanism behind a core engineering principle in CLAUDE.md: keep LLM outputs constrained behind Zod schemas, registries, validators, and evals. A planner may only reference concepts, metrics, and formulas that a registry defines, because an LLM left to name its own metrics will invent plausible-sounding ones — anything outside the registry becomes a typed gap, not an improvised answer.

Semantic registry (packages/semantic-registry)

A small, schema-first package (src/schema.ts, src/registry.ts, src/effect.ts) defining the controlled vocabulary v0 for planner and query-engine work:

  • Entities: Fund, LP, Commitment, SideLetter, SideLetterRight, PortfolioCompany, Investment, ValuationMark
  • Metrics: commitment_amount, current_markup, unfunded_commitment, latest_carrying_value
  • Rubrics: side_letter_onerousness, reconciliation_severity, audit_priority
  • Operations: resolveEntities, queryFacts, calculateMetric, rank, compare, retrieveEvidence, summarizeEvidence, explainResult
  • Gap types: unknown_metric, missing_extraction_schema, missing_source_data, insufficient_evidence, plus adjacent gaps

Every definition kind has a schema (EntityDefinitionSchema, MetricDefinitionSchema, RubricDefinitionSchema, OperationDefinitionSchema, GapTypeDefinitionSchema, …) and decode helpers (decodeSemanticRegistry, safeDecodeSemanticRegistry). Inspect the live vocabulary with:

bun run demo:registry

Computation registry (packages/computation-registry)

Where the semantic registry names things, the computation registry makes numbers derivable and reproducible. Its exports (src/index.ts) cover defined terms, formulas, an evaluator, reconciliation definitions and policies, typed assertions, rule sets, allocation logic, and an LPA compiler (lpa-compiler.ts — compiling limited-partnership-agreement economics into registry terms).

The centerpiece is a recursive, fully typed formula AST — no eval, no free-form expressions:

// packages/computation-registry/src/schema.ts (abridged) export type FormulaAst = | { readonly op: "literal"; ... } | { readonly op: "ref"; ... } | { readonly op: "add"; readonly args: readonly FormulaAst[] } | { readonly op: "subtract"; readonly left: FormulaAst; readonly right: FormulaAst } | { readonly op: "multiply"; readonly args: readonly FormulaAst[] } | { readonly op: "divide"; readonly numerator: FormulaAst; readonly denominator: FormulaAst } | { readonly op: "round" | "floor" | "ceil"; readonly value: FormulaAst } | { readonly op: "min" | "max"; readonly args: readonly FormulaAst[] } export const FormulaAstSchema = Schema.suspend(() => Schema.Union([ ... ]))

evaluator.ts executes these ASTs against decoded inputs (safeDecodeComputationInput), and reconciliation.ts compares registered assertions from independent sources (reconcileRegisteredAssertions) — this is what a reconcile query step invokes. execution.ts in query-runtime imports exactly these functions; a compute step cannot run a formula the registry doesn’t hold.

Version pinning

QueryExecutionContext.registryVersions (see Typed Query Runtime) records the semantic-registry, computation-registry, and permission-policy-bundle versions into each AnswerRun. An answer is reproducible only relative to the registry snapshot that produced it, so the snapshot identity is part of the audit trace.

When a question needs a metric or formula that doesn’t exist, the correct behavior is to emit a gap (unknown_metric, missing_extraction_schema), not to sneak a computation into adapter code. Gaps are first-class runtime outputs — they drive the registry-growth backlog. Adding a formula means registering it (with its defined-term provenance, DefinitionSourceSchema) so it is hashed, versioned, and auditable.

Fund-accounting computations that reach the general ledger have additional ASC 946/820 constraints — see Fund Accounting.

Last updated on