Fresh on commit

The current core has an atomic projected-write path and a framework-free useClinicalQuery store over Postgres LISTEN/NOTIFY. Universal governed-write coverage, a browser/React adapter, polling fallback, and a unified pending → fresh lifecycle remain target work.

The sync / async split

Some reads can’t wait. Some reads shouldn’t block.

FHIR servers often separate writes from search indexing. For an app, the target is a single governed writer that updates required operational projections atomically while expensive indexes run asynchronously with explicit status. The core implements the projected-write primitive today; complete route coverage is still in progress.

A FHIR server

Write the resource, then wait for eventual consistency before search reflects it. AWS HealthLake, for one, documents a default eventual-consistency window of ~15–30s between a write and when it’s searchable. Realtime is best-effort: rest-hook delivery can silently drop, events arrive out of commit order, bulk $import emits zero events, and the channel can fall days behind.

  • List screen shows stale data right after a write
  • You poll, refetch, or hand-invalidate caches yourself
  • Your search index and analytics silently rot

bonfireDB target

The canonical record is FHIR R4 (lossless JSONB) in Postgres. The target keeps required operational read models fresh inside the same governed write transaction, then reports async index status. The projected-write primitive and framework-free reactive store exist; universal governed-write coverage and a browser adapter do not yet.

  • List screens reflect the write immediately
  • No polling, no refetch, no manual invalidation
  • Indexes report pending → fresh, never silently rot

The freshness lifecycle

Target: every governed write reports the full freshness lifecycle

The target response reports commit status, which operational views are fresh, and which heavy indexes are catching up. The projected-write primitive has a narrower current receipt; the unified lifecycle below is not shipped.

target pseudocode · notes.ts
// Target clinical verb and unified receipt
const result = await clinical.notes.create({ patientId, encounterId, text })

// result is the freshness lifecycle object
{
  status: "committed",
  views: {
    notesByPatient: "fresh",
    timeline: "fresh"
  },
  indexes: {
    semanticSearch: "pending",
    agentContext: "pending"
  }
}

Current boundary: projected writes update their configured views atomically. Governed commits and search indexing still use separate paths. The pending → fresh lifecycle below is the contract being built to unify them.

How it works — Postgres-first

The current primitive is Postgres-native and framework-free.

The core can update configured projections in the same transaction as a projected write. The shipped framework-free useClinicalQuery store registers a Postgres listener, loads one RLS-scoped projection, and re-queries it after matching NOTIFY wake-ups. Complete route coverage, browser delivery, a React adapter, and unified freshness receipts are target work.

Projected-write primitive

Configured SQL-on-FHIR projections can update in the same transaction as the canonical write. Governed commits do not yet all use this path.

Current: LISTEN, then scoped re-query

The framework-free store listens for projection changes and re-queries inside the caller's tenant-scoped transaction. Subscribers emit only when that scoped snapshot changes.

Target: browser and framework adapters

A React adapter and browser transport still need to carry store updates into an app. A polling fallback for permanently silent reconnects is also an upgrade path, not current behavior.

Current boundary: transactional projected writes and a server-side, framework-free useClinicalQuery store with LISTEN/NOTIFY wake-ups, RLS-scoped re-query, content-hash suppression, manual refresh, and reconnect resync. Browser delivery, React bindings, polling fallback, complete route coverage, downstream indexing lifecycle, and unified freshness receipts are target work.

Current framework-free store: useClinicalQuery

Despite its contract-pinned name, this is not a React hook. It exposes subscribe and getSnapshot, so a React adapter can use it later; today it runs over a Postgres listener and RLS-scoped re-queries.

  • Current: store subscribers emit after a protected snapshot changes
  • Current: configured projected writes can maintain views transactionally
  • Target: React and browser adapters expose the store to app clients
projection-store.ts
// Current framework-free API — not a React hook
const opened = useClinicalQuery(
  session,
  db,
  listener,
  { view: "vd_patient_demographics" }
)

if (opened.ok) {
  const store = opened.data
  const unsubscribe = store.subscribe(renderSnapshot)
  store.getSnapshot()
}

Heavy work, off the commit path

Target: expensive reads run async — and report status

Production semantic search, embeddings, agent context assembly, and complex FHIR search are too heavy to block a write. The target runs them asynchronously and reports pending → fresh through one receipt. That lifecycle is not a shipped current-core guarantee.

Target: every governed commit

The projected-write primitive can keep configured views fresh transactionally. Universal governed-route coverage is still in progress.

Async, reported

Hybrid search and embeddings rebuild off the commit path, surfacing pending until they’re caught up.

Hybrid search →

Agent context

Cited, permission-aware context for agents is assembled async — never blocking the clinician’s write.

Agent context tools →

FHIR underneath

FHIR R4 is the canonical record underneath. Clean, governed Bundle export is planned rather than part of the current hot path.

FHIR underneath →

Target: report agent-context freshness separately

The current context tool returns cited records under practice/resource/purpose policy. Tying its derived state to a write receipt and asynchronously rebuilding a richer packet are target work.

  • Cited to source records, scoped by permission
  • Target: derived context runs async and reports status
  • Agents read cited evidence packets, never raw FHIR by default
See the agent context tools →
target pseudocode · sessionPrep.ts
// Target SDK — the current core exposes a narrower MCP context tool
const ctx = await clinical.agent.sessionPrep({
  patientId,
  windowDays: 90,
  include: ["recentNotes", "assessments", "tasks"]
})

// Planned clean FHIR R4 Bundle export
await clinical.fhir.export(patientId)

You build the app. Bonfire is the clinical data layer underneath.

Canonical FHIR R4, an atomic projected-write primitive, and a framework-free LISTEN/NOTIFY query store today; unified governed writes, browser/React adapters, and honest async freshness receipts next.

FAQ

Frequently asked questions

How do I get fresh reads on commit without eventual-consistency lag?

The current core has a projected-write API that updates canonical FHIR and configured SQL-on-FHIR projections in one transaction. Making governed commits use that path and adding a complete freshness receipt are still in progress.

Why does AWS HealthLake have a delay before a write is searchable?

As of mid-2026, AWS HealthLake documents a default eventual-consistency window between a write and searchable results. Bonfire's target separates atomic operational projections from explicitly asynchronous heavy indexes; universal route coverage is not shipped yet.

How does bonfireDB do reactive reads without Redis?

The current framework-free useClinicalQuery store uses Postgres LISTEN/NOTIFY as a wake-up signal, then re-queries one whitelisted projection through tenant-scoped RLS. It emits only when that scoped snapshot changes. A browser transport, React adapter, and polling fallback are target work.

What happens to hybrid search and embeddings if they aren’t fresh on commit?

The target freshness receipt marks production semantic indexing and agent context as pending until fresh. Current search documents have a separate write path, so this unified lifecycle is not shipped yet.

Can I subscribe to live clinical query results in the UI?

The current useClinicalQuery store exposes subscribe and getSnapshot, but it is explicitly framework-free and not a React hook. A supported React adapter and browser delivery path are planned.