Latency at the chain head
At the head, the question is how long a new source block takes to become queryable. Historical blocks per second measure a different workload.
Follow the whole path
| Stage | What to observe |
|---|---|
| Zcash source | The configured node observes a block and its hash |
| Prep | /height reports the block as indexed and queries can return it |
| Local scanner, when used | Authorized notes finish decryption before their receipt handler runs |
| Chef | The handler's entities and checkpoint commit to PostgreSQL |
| GraphQL | Your reader first observes that committed checkpoint and entity |
A low query response time does not prove a short delay across those stages. Block timestamps also do not tell you exactly when your node received a block. Record observation times on one clock, or synchronize clocks when measuring across hosts.
Start near the available head
Public and blank guided zeer init setups default to latest: they capture Prep's available indexed height once and write that number into chef.config.ts. This avoids replaying all historical blocks for a new application. It does not backfill older activity. Choose 0 or another explicit height when your application needs history. A shielded inbox requires an explicit numeric wallet birthday at or before the notes it must read; it does not default to latest.
After installation, database configuration and migration, run separate terminals:
pnpm run follow
pnpm run serve
Inspect progress with:
pnpm run status --json
With npm, use npm run status -- --json. Read the CLI reference for direct invocation and output flags.
Read the two gaps separately
| Observation | Meaning |
|---|---|
source.prepSourceLagBlocks | Source-observed height minus Prep's indexed height, when follower metadata is available |
source.chefPrepLagBlocks | Blocks still to commit from this project's next block through Prep's indexed height |
source.sourceObservedAt | Time of the reported source observation; check its age |
checkpoint.height, checkpoint.status | Durable project progress and whether reads are ready, reconciling or blocked |
A zero Chef–Prep gap means caught up with the observed Prep data. It does not prove Prep has the newest network block. A historical snapshot has no current source-tip guarantee, and unavailable source metadata must remain unknown rather than zero.
Observe work before a page finishes
Chef 0.7.0 sync/follow emits a best-effort cached heartbeat every five seconds while source reads, local scanning, handlers or commits are still running. It adds no Prep or PostgreSQL requests and does not change follow's polling interval.
Read progress.phase, its phaseSince, the inclusive pending processingRange and committedHeight together. lastProgressAt changes when a local stage completes; it can advance after a source read or handler without a durable commit. heartbeatAt only identifies the diagnostic emission time. A long scanner stage can therefore show repeated heartbeats with the same committed height and last-progress time. A blocked event loop or backpressured output can delay or suppress heartbeats; their absence is not a complete process-health test.
The phases help locate waiting, but do not measure exact stage duration or receipt latency. Use observation timestamps for the whole path above, and the source interruption recipe to verify continuation after a controlled outage. Preserve canonicality/read gates during both measurement and recovery.
Tune the delay you measured
Chef polls every 5 seconds while following by default. You can test a shorter interval:
pnpm run follow --poll-seconds 1
The supported interval is 1–60 seconds. Polling more often can reduce the waiting component of detection while increasing request load. It cannot make Prep publish blocks before ingestion or make a database commit instantaneous. Source polling, confirmation depth, handler work, commit size and your application's own polling also affect the observed delay.
For a new block, record its height and hash when the source is observed, when Prep returns it, when Chef commits it and when GraphQL first returns the expected entity. Repeat across several blocks and publish sample count, median and tail delays in seconds. Client polling gives an observation bound, not an exact server publication time.
Confirmations and reorgs
Fresh data can still be reorganized. Chef reconciles supported chain changes behind its read gate; a checkpoint can become blocked when recovery cannot prove a retained ancestor. Follow checkpoint and reorg handling rather than resetting the namespace to make it appear ready.
Applications such as payment observers must recheck their required confirmations and source canonicality before settlement. Private scanner work adds a separate processing stage. The public block-summary recorded benchmark does not measure note decryption or establish a chain-head latency SLA.
Recorded polling experiment
On 21 October 2026, three separate 12-block paired studies compared Chef 0.1.3's 5-second polling with 1-second and 2-second candidates. Shorter intervals reduced median source-to-GraphQL latency, but every study still observed temporary 503 read gates. None passed the predeclared availability criterion, so polling defaults and production services remained unchanged.
An extra Prep observer affected capacity in the first study. Without that observer, writer-derived Prep timestamps include polling detection delay and cannot isolate source publication latency. See the live following results and limits for timings in seconds, tail observations, correctness checks and raw evidence.
The later source-admission study keeps Chef 0.2.0 and polling fixed. It tests bounded metadata waiting with a modern live-tail archive. Both variants had zero failed timed reads; its results cannot establish a live error-rate improvement or full-history cold-start performance.
The later six uninterrupted shielded receipts measure local decryption, PostgreSQL commit and a standalone SQLite consumer: 2.27 s median / 3.17 s maximum from matching Prep response to consumer storage. All six were future mined notes in one run. Candidate Prep and PostgreSQL used SSH tunnels; public ingress was not measured. Broadcast-to-Prep waiting is reported separately, and the six-sample maximum is not an SLA.
The earlier interrupted and recovery runs remain available with their catch-up samples clearly separated. Prep full-history startup is another workload entirely; do not use its admission times as receipt latency.