Skip to Content
RuntimeTyped Query Runtime

Typed Query Runtime

@opsdna/query-runtime is the heart of the runtime path. It defines a finite, closed algebra of query operations, validates typed query plans against that algebra and the current registries, executes plans through permission-gated adapters, and seals every run into an AnswerRun audit trace.

Why a closed algebra?

A planner backed by a language model will happily invent an operation called computeSuperReturn if you let it. OpsDNA doesn’t. The vocabulary in packages/query-runtime/src/algebra.ts is a const tuple of exactly fifteen operations, wrapped in a schema so nothing outside the list ever decodes:

// packages/query-runtime/src/algebra.ts export const queryOperations = [ "resolve", "select", "filter", "join", "aggregate", "coverageDiff", "compute", "reconcile", "resolvePersistedFact", "rank", "retrieveEvidence", "project", "invokePolicy", "proposeEffect", "emitGap", ] as const export const queryIntents = [ "metric_lookup", "coverage_diff", "ranking", "reconciliation", "document_lookup", "workflow_invocation", "action_preparation", "policy_check", ] as const

New domain capability arrives by registering entities, metrics, and computations in the registries — never by widening this list at runtime. When a question needs something the system can’t do, the plan emits a typed gap (emitGap, packages/query-runtime/src/gaps.ts: unknown_metric, missing_extraction_schema, missing_source_data, insufficient_evidence, …) instead of hallucinating an answer.

Plan → validate → gate → execute → seal

Planning

packages/query-planner/src/planner.ts exposes createLiveQueryPlanner, whose plan(question) returns an Effect producing a PlannerOutcome. The candidate extractor (heuristic or OpenAI-backed) emits concept-resolution candidates; the deterministic resolver binds them to registry concepts before a TypedQueryPlan exists. The AI-backed extractor is opt-in only (OPSDNA_ENABLE_LIVE_QUERY_AI=1 + OPENAI_API_KEY); otherwise the route returns a typed configuration gap. packages/planner-eval is fully deterministic and owns no LLM calls.

Validation

packages/query-runtime/src/validation.ts provides validateTypedQueryPlan and the stricter validateTypedQueryPlanForExecution, and computes requiredPermissionGatesForOperation for each step — a compute step demands a computation gate decision, a retrieveEvidence step a retrieval decision, and so on.

Execution

executeTypedQueryPlan in packages/query-runtime/src/execution.ts takes a QueryExecutionContext that makes every dependency explicit:

// packages/query-runtime/src/execution.ts (abridged) export interface QueryExecutionContext { readonly queryText: string readonly authorizationEnvelope: AuthorizationEnvelope readonly computationRegistry: ComputationRegistrySnapshot readonly permissionEngine: PermissionEngine readonly entityAdapter: EntityAdapter readonly evidenceAdapter: EvidenceAdapter readonly computationInputAdapter: ComputationInputAdapter readonly reconciliationAdapter?: ReconciliationAdapter readonly domainPolicyAdapter?: DomainPolicyAdapter readonly registryVersions?: { readonly semanticRegistry?: string readonly computationRegistry?: string readonly permissionPolicyBundle?: string } readonly plannerModelId?: string readonly plannerPromptHash?: string readonly intentClassificationAudit?: Record<string, unknown> }

Note the registryVersions pins and planner provenance fields — an AnswerRun records which registry snapshot and which model/prompt produced it.

Sealing

packages/query-runtime/src/answer-run.ts defines the AnswerRun record: plan hash (hashTypedQueryPlan from hashing.ts, over @opsdna/canonical-json), per-step permission decision bindings and their hashes, resolved step output proofs, gap-reason hashes, projection output hashes, and an aggregate trust state derived from audit verdicts (audit.ts, audit-checkers.ts, audit-seal.ts). Branded hash types come from @opsdna/brands (PlanHash, PermissionDecisionHash, ResolvedStepOutputProofHash, …), so you cannot pass the wrong hash to the wrong slot at compile time.

A real path end to end

Run the seeded demo:

bun run demo:largest-lp

It plans “Who was my largest LP in Fund 2?”, executes resolveEntities → rank → retrieveEvidence against seeded commitments, validates evidence-graph references, and prints a cited answer. bun run demo:onerous-side-letter does the same for a rubric-scored ranking (side_letter_onerousness).

Two pitfalls. First, packages/query-execution is legacy — it predates this runtime and exists only for demo/intake and side-letter fixtures; new contracts go in query-runtime. Second, permission decisions inside a run are bound to the plan hash: if you mutate a plan after decisions were issued, AnswerRun/PolicyRun schema refinements reject the record. Re-plan and re-gate; don’t patch.

Persistence of AnswerRun/PolicyRun traces lives in packages/persistence — see the entity model for tenant scoping, and Policies & Workflows for the standing-query counterpart.

Last updated on