ChemLabs builds real-time perception for wet chemistry. Our first system watches a separation funnel at the bench and announces the moment the lower phase reaches the stopcock, inside an end-to-end budget of 200–300 ms. It abstains when it cannot see, and it never speaks on stale evidence.
A camera does not wait. The architecture is built around that single fact, and every latency number depends on it being honest.
Frames arrive at the capture rate. Anything the consumer was not ready for is dropped and counted — never queued. Falling behind costs frames, never time.
A distilled percept student computes the scene inside the loop, on its own thread, and every percept lands stamped with its age. Nothing is precomputed.
Evidence past the declared 300 ms staleness limit produces silence, not a cautious answer. Across 20,092 refusals, zero carried a value.
Six pre-registered gates, written before any engine code was committed. Every figure below comes from a run directory that ships with the command that produced it.
| Gate | What it requires | Verdict | The number |
|---|---|---|---|
| R1 | The source behaves like a clock | PASS | scheduled = emitted + dropped, exactly, in all 14 runs |
| R2 | Announce latency inside 200 / 300 ms | PASS 6/6 | worst p50 178.9 ms · worst p95 270.5 ms |
| R3 | No decision precedes its evidence | PASS | 0 violations in 22,513 decisions |
| R4 | Bounded memory over a long replay | PASS | +22.3 MB across a 630 s replay |
| R5 | A refusal carries no value | PASS | 0 of 20,092 refusals carried one |
| R6 | Degrades gracefully under load | PASS | every drop counted · 0 announcements past the limit |
The comparison that matters is not accuracy on a saved frame — it is whether a system says anything at all when the clock is running and it has to pay for its own inference.
| Percept source | Announcements | Decisions | Outcome |
|---|---|---|---|
| SAM 3, in the loop | 0 | 1,027 | A percept costing 2.1 s is already past the tracker's own 1.2 s mask-age limit when it lands. The system is reduced to silence. |
| Distilled percept student | 3,159 | — | The same six dev videos, at replay speed 1.0, no precomputed evidence anywhere in the run. |
The student is load-bearing, not an optimisation. Both arms run on the same videos, at true realtime with no speed multiplier, and every input is paid for as it happens.
The drain-stop trigger is not stable run to run: on one video it fires at 9.08 s against an 11.72 s reference, and a second run of the same configuration the same afternoon fired at 6.96 s. Coverage of decided frames fell to 26 % on the best video under the current gating. No number on this page is a claim until it appears in an experiment folder with its command — and none of them is a bench demonstration: the dev videos are 24–30 fps, not the ≥60 fps the requirement names.
Occasional notes when a gate moves or a system reaches the bench. No cadence promised, no list sharing.
Questions about the method, the numbers, or running this on your own footage.