F
Fabra

How It Works

Fabra’s job is to turn an AI request into evidence you can use during an incident.

The unit of evidence is a context_id. Under incident pressure, the workflow is:

fabra context show <context_id>
fabra context verify <context_id>
fabra context diff <a> <b>

Components

1) Your code (authoring)

You define a FeatureStore and register:

  • features (values served over HTTP)
  • contexts (assembled “what the model saw”, with lineage and integrity)

Fabra loads your Python file and discovers the FeatureStore by importing it.

2) Fabra server (FastAPI)

When you run:

fabra serve <file.py>

Fabra starts a FastAPI app that exposes:

Features

  • GET /v1/features/{feature_name}?entity_id=...{"value","freshness_ms","served_from"}
  • POST /v1/features and POST /v1/features/batch for batch reads

Context assembly

  • POST /v1/context/{context_name}{"id","content","meta","lineage"}

Evidence retrieval

  • GET /v1/record/{context_id} → CRS-001 Context Record (verifiable receipt)
  • GET /v1/context/{context_id} → legacy context view (best-effort fallback)

Replay / diff

  • POST /v1/context/{context_id}/replay?timestamp=... (time-travel feature reads when historical data is available)
  • GET /v1/context/diff/{a}/{b} (legacy context diff endpoint)

3) Offline store (durable evidence)

The offline store is where Fabra keeps durable artifacts for replay/audit.

Defaults:

  • Dev: DuckDB at ~/.fabra/fabra.duckdb (override with FABRA_DUCKDB_PATH)
  • Prod: Postgres (set FABRA_ENV=production and FABRA_POSTGRES_URL)

Fabra persists two related artifacts:

  • CRS-001 Context Record: immutable, verifiable (preferred)
  • Legacy context log: used for listing/legacy compatibility

4) Online store (serving + freshness metadata)

The online store is what the server uses to serve cached feature values quickly.

Defaults:

  • Dev: in-memory
  • Optional: Redis (set FABRA_REDIS_URL)

Online stores wrap feature values with an internal as_of timestamp so Fabra can compute freshness_ms at serve-time.

5) Events + worker (optional)

For event-driven features:

  1. Your app sends an event:
    • POST /v1/ingest/{event_type}?entity_id=...
  2. Fabra publishes to Redis Streams:
    • fabra:events:{event_type}
    • fabra:events:all (shared stream)
  3. A worker consumes streams and updates triggered features:
    • fabra worker

See docs/events-and-workers.md for exact flags and defaults.

Receipts: legacy vs CRS-001

CRS-001 Context Record (preferred)

CRS-001 is the durable, verifiable receipt. It contains:

  • content (“what the model saw”)
  • structured fields (inputs/lineage/decisions)
  • integrity.content_hash and integrity.record_hash

Use:

  • fabra context verify to verify hashes
  • fabra context export --bundle to generate a ticket attachment

Legacy context (fallback)

Legacy contexts are a best-effort view retrieved via GET /v1/context/{id}. They exist for compatibility and debugging, but CRS-001 is the audit-grade artifact.

Evidence modes (no fake receipts)

Fabra can enforce that it never returns a context_id unless a CRS-001 record was persisted successfully:

  • FABRA_EVIDENCE_MODE=best_effort (development default): request succeeds, meta.evidence_persisted indicates whether the receipt was persisted.
  • FABRA_EVIDENCE_MODE=required (production default): if persistence fails, the request fails (no “fake” receipt).

Where the “aha” lands

  • Incident response: paste context_id into the ticket; run show/verify/diff/export.
  • AI engineers: add receipts with minimal code (adapters/exporters) and still get verifiable artifacts.
  • ML engineers: serve features with explicit freshness numbers, and optionally materialize via events/workers.

FAQ

Link
What’s the difference between the offline store and the online store?
The offline store is durable evidence and replay history (DuckDB in dev, Postgres in prod). The online store is a serving cache for fast feature reads (in-memory in dev, Redis optional).
How does Fabra compute freshness_ms for features?
Online stores wrap feature values with an as_of timestamp; Fabra computes freshness_ms at serve/assembly time as now (or replay timestamp) minus as_of.
Where does Fabra expose CRS-001 Context Records over HTTP?
The server exposes GET /v1/record/<record_ref>, where record_ref is ctx_<...> or sha256:<record_hash> for content-addressed lookup.
What does FABRA_EVIDENCE_MODE=required do?
It prevents “fake receipts”: if CRS-001 persistence fails, the request fails and no context_id is returned.
How do events and workers update triggered features?
POST /v1/ingest/<event_type> publishes to Redis Streams (fabra:events:<type> and fabra:events:all); a fabra worker process consumes streams and writes updated feature values to the online store.
What’s required for time-travel replay?
Replay re-executes the context function using time-travel reads; it requires historical feature data to be available in the offline store for the requested timestamp.