Indra v0 Design Review¶
| Status | Ratified 2026-09-03, team approved, with one refinement: v0 entity kinds are person and organization, more added via registry bump if needed. Logged as D22-D27; B2 and registry changes landed in interfaces.md; groundedness, kind, and relation-reconciliation mechanics in architecture.md; E6/E7, M1 additions, and milestone edits in the PRD. Frozen 2026-09-03 (D28): edits go to the canonical docs; a deferred item in section C that gets worked later arrives as its own proposal |
| Created | 2026-09-03 |
| Updated | 2026-09-03 |
| Context | Review of PRD, architecture.md, interfaces.md, relationships.md, decisions D1-D21 |
Summary¶
The architecture's spine is right: append-only links, entities as views, contract-first modules, measured-before-tuned matching. This review does not touch it. It names four problems that are contract-level or requirement-level, meaning cheap to fix before milestone 3 and expensive after (section A); one sequencing emphasis inside the already decided build order (section B); and four known bottlenecks that are deliberately NOT v0 work, named so nobody builds them early (section C). v0 discipline: correctness and contract shape now, optimization only when a measured consumer forces it.
A. Fix before milestone 3 (contract and requirement changes)¶
A1. Partial entities are untyped, and relationships expose it¶
Problem. PartialEntity in B2 carries no kind (person vs organization). Two
consequences:
- D16's
endpoint_kinds: (subject_kind, object_kind)on relation types is unenforceable: the contract cannot validate thatemploymentruns person to organization when partials are untyped. - Claim classification is kind-blind.
domainis correctly non-identifying for a person (many people share acme.com), but for an organization the registrable domain is close to identifying. With one global classification per claim type, organizations have almost no identifying claims, so they rarely merge and even more rarely reach canonical.
The second consequence chains into the relationship layer: a relation is usable only when both endpoints are canonical (invariant 9), and the object of nearly every employment, investment, and governance claim is an organization. Kind-blind classification means a structurally sparse relationship graph, regardless of extraction quality.
Proposed change. PartialEntity gains kind (from the ontology) in B2. Registry
classification (identifying class, and where it differs, search strategy) is keyed by
(claim type, entity kind), not claim type alone. One contract edit and one registry-shape
edit now; a migration plus re-resolution later.
A2. No groundedness gate on identifying claims¶
Problem. Extraction is the single LLM pass everything downstream trusts, and a hallucinated identifying claim is the worst possible output: a well-formed email that was never in the text routes a silent member merge (architecture, Matching). All the reversibility machinery makes this auditable after the fact; nothing prevents it.
Proposed change. A deterministic validation at the extraction contract boundary: an identifying claim is rejected unless its value appears literally in the event's source text (modulo the claim type's canonicalization). Non-identifying and soft claims are exempt, as they may be legitimately inferred. Proposed as a new E-requirement (P0) beside E2/E3; it is the highest-leverage precision guard available and costs one string check.
A3. Relation claims are unspecified under changed-source reconciliation¶
Problem. The reconciliation diff (architecture, Changed-source reconciliation) matches claims across runs by (type, normalized value). Relation claims have no value. And when reconciliation supersedes and recreates a target partial, a relation claim on an unchanged subject partial is left pointing at a superseded partial.
Proposed change. A relation-claim clause in the reconciliation section: relation
claims align across runs by (type, aligned-target partial, attributes); when a target
partial is superseded and its aligned successor exists, the relation claim on an
unchanged subject is re-issued against the successor and the prior one superseded
(source_changed), in the same reconciliation transaction. No new machinery, one owed
paragraph plus its tests.
A4. M1 promises precision it cannot currently produce¶
Problem. M1 reports yield (countable from the corpus) and precision (requires labeled ground truth). No eval set is budgeted: who labels, how many events, sampled how. Without it M1 silently degrades to a yield-only report, and the matching design gets parameterized on half the promised data. Two cheap metrics are also missing, both pointing at known risks:
- Alignment stability under re-extraction: share of partials that re-align with themselves when an unchanged event is re-extracted. Partials carrying only an alias ("John" vs "John Doe" across runs) are the churn risk on the calendar-heavy corpus that is I4's driving case.
- Identifying-claim error rate per source type: transcribed emails in meetings are well-formed and wrong; this number decides whether identifying hits from low-trust sources need a gate (section C4).
Proposed change. M1 gains the two metric rows, and milestone 3's done-when gains one clause: the eval-set plan (size, sampling, who labels) exists before extraction of the measured corpus begins.
B. Sequencing emphasis (no decision change)¶
D15 already orders the deferred block store and applier, then bootstrap, then matching. Within bootstrap, organizations first. Reason: the relationship layer's visible value is gated on canonical org endpoints (A1, invariant 9); bootstrapping orgs from the Platform and LinkedIn is what turns latent employment and investment claims into traversable relationships. People imports can follow.
C. Known bottlenecks, deliberately deferred (do not build in v0)¶
Named so they are recognized when they arrive, and so nobody solves them speculatively.
| # | Bottleneck | Arrives when | The later fix |
|---|---|---|---|
| C1 | Applier FIFO contention: live resolution, judge verdicts, and bootstrap imports converge on one per-org queue | Milestone 5, first large bootstrap | Priority discipline inside the FIFO, not parallelism (invariant 7 stands) |
| C2 | Judge fan-out on common aliases: one "John" landing evidence on many candidates fires many judge calls | Milestone 5, cost visible via C1 caps | Per-partial candidate cap, parameterized from M1's candidate-set sizes |
| C3 | Query-time relationship traversal under real consumers (MCP paths, profile generation) | First multi-hop consumer | Materialized projection; invariant 9 makes it a pure, safe cache |
| C4 | Identifying-hit merges from low-trust sources (transcribed emails) | Measured by the A4 metric | Trust gate routing identifying hits from low-trust sources to evidence instead of member; decide after M1, with the source-trust registry |
What this review does not touch¶
The storage model (D1, D2), the pipeline shape, the reconciliation design's core, the relationship model (D16-D21), the stack (D9), and the milestone logic (D15) all hold. D14 (no erasure) remains the one decision with legal exposure attached in Helmi's most PII-dense service; it is logged as accepted risk and should be revisited on a schedule, not on an incident. That is a reminder, not a proposal.