How Monokulo is tested

Monokulo handles other people’s money, so it gets tested hard. Every change runs more than 2,600 automatic tests. Every night, two kinds of robot tester invent thousands of strange situations and check that no payment goes missing. This page rebuilds itself from those runs. Open any section to see the details.

Some checks failed·Tests and coverage from 4176f6b on 18 Oct 2026·Nightly properties 23 Oct 2026·Fuzzing 23 Oct 2026·Live network 22 Oct 2026
Tests2,6572,657 passed · 0 skipped
Engine and server90.5%of 92,270 Rust lines
Checkout and POS95.1%of 1,666 browser lines
Properties nightly212plus 10 fuzz targets · 27 live daily

Scale

Could Monokulo keep up on a small computer? This test pins it to a single CPU core, gives it lots of stores at once, and keeps other work competing with it: reading the database, answering status requests, saving settings. A new block arrives every 5 seconds, and every store’s payments have to be checked before the next one lands.

Run of 18 Oct 2026
128 stores, one block
58 ms
Share of the 5 s budget
1.2%
Each extra store
+0.2 ms
Peak memory
16.1 MB

Time to scan one block for every store

Average of 4 measured blocks after warm-up. The cost grows by about 0.2 ms per store on top of a fixed 36 ms.

0 ms20 ms40 ms60 ms80 ms0326496128160stores41 ms47 ms58 ms
StoresPer blockOf budgetSlowest replyBehind
3241 ms0.8%2.6 ms0
6447 ms0.9%1.3 ms0
12858 ms1.2%1.5 ms0

Pass conditions: no store more than 3 blocks behind, status replies under 250 ms. All 3 passed.

Recovering from faults

Each run breaks one thing on purpose for 2 blocks, then gives the engine 6 blocks to recover. Each bar is how long one block took; orange bars are the broken ones. In all three, no store fell behind.

Node errors

Every node request slowed by 2 ms, and every third request failed until block 2.

fault: 35 msafter: 43 ms
Stores
16
Requests failed
3 of 57
Stores behind
0

Database locked

Another writer held the database lock for 1.5 s during each of the first 2 blocks.

fault: 1,548 msafter: 4 ms
Stores
16
Lock held
1.5 s × 2 blocks
Stores behind
0

Key custody slow

Key custody limited to 1 scan at a time, each taking an extra 5 ms.

fault: 148 msafter: 137 ms
Stores
16
Custody scans
128
Longest wait
103 ms
Stores behind
0

Weekly scale run

2,048 stores, one block
585 ms
Share of the 5 s budget
11.7%
Each extra store
+0.3 ms
Peak memory
24.3 MB

Time to scan one block for every store

Average of 4 measured blocks after warm-up. The cost grows by about 0.3 ms per store on top of a fixed 0 ms.

0 ms200 ms400 ms600 ms800 ms05121,0241,5362,0482,560stores145 ms273 ms585 ms
StoresPer blockOf budgetSlowest replyBehind
512145 ms2.9%5.1 ms0
1,024273 ms5.5%4.6 ms0
2,048585 ms11.7%10.8 ms0

Pass conditions: no store more than 3 blocks behind, status replies under 250 ms. All 3 passed.

Recovering from faults

Each run breaks one thing on purpose for 2 blocks, then gives the engine 8 blocks to recover. Each bar is how long one block took; orange bars are the broken ones. In all three, no store fell behind.

Node errors

Every node request slowed by 2 ms, and every third request failed until block 2.

fault: 162 msafter: 85 ms
Stores
256
Requests failed
10 of 120
Stores behind
0

Database locked

Another writer held the database lock for 1.5 s during each of the first 2 blocks.

fault: 1,651 msafter: 53 ms
Stores
256
Lock held
1.5 s × 2 blocks
Stores behind
0

Key custody slow

Key custody limited to 1 scan at a time, each taking an extra 5 ms.

fault: 1,735 msafter: 1,655 ms
Stores
256
Custody scans
2,560
Longest wait
233 ms
Stores behind
0

Weekly scale run of 17 Oct 2026: the same test with far more stores, so the time per block shows how far one core can go.

Runner: AMD EPYC 9V45 96-Core Processor, pinned to one of 4 cores, SQLite 3.53.2. Absolute times vary between runners; the pass condition is that every store keeps up. Full stress report.