ADR-0009: Analyst — typed plan over an allowlisted semantic schema
Status: Accepted · 2026-07-14Decision
Pipeline:question → intent parse → TypedQueryPlan (Zod) → server validation → authorization injection → cost/row/depth bounds → read-only compile → execute → answer composed only from returned rows.
- The semantic schema exposes named entities (
asset,container,finding,reviewCandidate,action,domainPosture) with allowlisted fields, filters, group-bys, and measures — never tables or SQL. - Two planners behind one interface: DeterministicPlanner (pattern-based, covers
the canonical questions, used in tests) and AiPlanner (gateway task with
Zod-validated output). Both produce the same
TypedQueryPlan; the server treats plans from either source as untrusted and re-validates identically. - Tenant + domain-scope predicates are injected server-side from the authenticated session; the plan cannot set or widen them. Display values resolve to scoped internal IDs server-side.
- Scanned content passed to any AI planner/summarizer is delimited as untrusted
data; the model has no tools that mutate or fetch arbitrarily. Action drafting is
a separate, explicitly-invoked tool that creates
Draftactions only. - Every run audits question, plan, executed query descriptors, result-set IDs, template/model version, and answer reference.
Consequences
- Answers cite evidence/assertion/result IDs, coverage, and freshness watermarks and are reproducible.
- Injection tests: hostile content in fixtures attempts scope-widening, tool escape, and cross-domain reads; all must fail closed.