Systems and subsystems

The local API

A thin FastAPI wrapper around the pipeline for the demo frontend: upload a file, get the same explanation record the runner writes. It is not on the scoring path.

In plain words

The demo needs to score one file on demand and read back records from a finished run. The API does exactly that and nothing more: models load lazily on the first request and stay loaded, one clip is analysed at a time, and every response is the runner's own record.

What goes in and comes out

  • POST /analyze: a multipart upload; returns the explanation record plus the API's own timing. An undecodable upload returns an "undetermined" record rather than an error.
  • GET /results/{filename} and GET /results: records from a results directory named by an environment variable.
  • GET /health: whether models are loaded, the rule, the policy, the scorers and the version block.

Where it lives

src/hearsay/api.py. Start it with uv run uvicorn hearsay.api:app --port 8000source: docs/handoffs/2026-09-26_frontend-contract.md.

Parameters and where each is set

  • Settings come from the environment: rule, policy, detectors, constants file, model directories, results directory, thread count (api.py, lines 82–105).
  • Models load under a lock on the first analyse call; the M5 hash gate runs before and after; a load failure is remembered so the API does not retry per request (api.py, lines 108–131).
  • Results lookups accept bare file names only and answer with an error status when the directory is unset or the name is absent (api.py, lines 136–143).

Status

Built and tested. A separate toy analyser that predates the real pipeline still exists in the package; the frontend contract says it must be rewired away from and must never export a TSV.

Numbers

None.

Known limits

Single-clip concurrency by design. No authentication; it is a local demo server.

Tests that pin it

tests/test_api.py: health without loading models, probe-only mode, results lookup and its environment requirement, analyse uses the pipeline, rule and policy from the environment, the default rule mapped once, an undecodable upload is undetermined, health reports the file's scorers, M5 loads only when the constants need it.

Sources

The frontend contract; the frontend wiring handoff.