Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

ADR-048: Keep enrichment synchronous; async is trigger-gated, not now

Date: 2026-07-07 Status: Accepted Author: Rômulo Febasi

Resolves the #160 (SYN-194) placeholder. Confirms BR-13 (insertion-time enrichment). Companion to ADR-008 (backends) and ADR-046 (disposability).


Context

BR-13 runs enrichment (chunk embeddings + mentions:* NER/gazetteer links) synchronously inside Workspace::tx, before commit, under a latency budget (median ≤ 500 ms, p95 ≤ 800 ms on 10k entities, Apple M1 Pro). #160 registered a possible v0.6+ async path: run enrichment after tx.commit() returns, make the entity searchable on FTS immediately, and reach vector/NER consistency within a documented window (~2–5 s). It was filed as a placeholder: “do not start work” until real usage shows the synchronous write penalty is the wrong trade-off.

Decision

Keep enrichment synchronous. The async path stays deferred and is trigger-gated: build it only when a measured p95 write regression on real usage crosses the BR-13 budget. No async scheduler, no [enrichment] schedule config ships now.

Rationale:

  • The budget holds. No evidence the synchronous penalty is a problem; the synapse-bench write path (SYN-293/298) stays within budget, and enrichment already runs its embed + NER legs in parallel threads inside the tx.
  • Async contradicts the enrich-before-commit principle. An eventual- consistency window means a fact is briefly committed without its semantic edges/embeddings: searchable by FTS but not by meaning, and momentarily missing mentions:*. That weakens the “a write is complete and findable when it lands” guarantee for a latency win nobody has asked for.
  • Disposability already covers the backfill case. The one real gap async was partly meant to soften (entities written before models were downloaded) is handled by syn reindex --relink (heuristic edges, SYN-271) + syn embed --all (embeddings), both shipped in v1.2 (ADR-046 disposability line). So the pressure for async is lower than when #160 was filed.

Consequences

  • Improves: the write contract stays simple and honest, a committed fact is fully enriched and findable, no consistency window to reason about. No new scheduler/retry/queue surface to maintain or verify.
  • Worsens / limits: very fast capture flows pay the full enrichment latency per write. If that becomes real (a measured p95 breach, or a user report on a large corpus), the async path is revisited.
  • Trigger to revisit: a persona-bench/write-path p95 above the BR-13 budget on a real corpus, or a concrete user report. At that point: design the opt-in [enrichment] schedule = async with a documented consistency window and a crash-safe queue: its own change, not a default.

Alternatives considered

  • Ship async now (opt-in config). Rejected: adds a scheduler + eventual- consistency semantics + crash-safety for a latency problem not observed; against the enrich-before-commit principle.
  • Close #160 as won’t-do. Rejected: the trade-off is legitimate at scale; keep it registered as trigger-gated so it is revisited on evidence, not forgotten.