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.

All checks passed·Tests and coverage from 6b1dcda on 16 Oct 2026·Nightly properties 17 Oct 2026·Fuzzing 16 Oct 2026·Live network 16 Oct 2026
Tests2,6072,607 passed · 0 skipped
Engine and server90.6%of 87,305 Rust lines
Checkout and POS95.0%of 1,655 browser lines
WooCommerce95.6%of 502 PHP lines
Properties nightly211plus 9 fuzz targets · 26 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 16 Oct 2026
128 stores, one block
75 ms
Share of the 5 s budget
1.5%
Each extra store
+0.3 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.3 ms per store on top of a fixed 37 ms.

0 ms20 ms40 ms60 ms80 ms100 ms0326496128160stores46 ms55 ms75 ms
StoresPer blockOf budgetSlowest replyBehind
3246 ms0.9%1.2 ms0
6455 ms1.1%2.6 ms0
12875 ms1.5%3.2 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: 65 msafter: 44 ms
Stores
16
Requests failed
6 of 64
Stores behind
0

Database locked

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

fault: 1,556 msafter: 8 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: 157 msafter: 141 ms
Stores
16
Custody scans
128
Longest wait
108 ms
Stores behind
0

Weekly scale run

2,048 stores, one block
550 ms
Share of the 5 s budget
11.0%
Each extra store
+0.3 ms
Peak memory
29.1 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 6 ms.

0 ms200 ms400 ms600 ms800 ms05121,0241,5362,0482,560stores142 ms265 ms550 ms
StoresPer blockOf budgetSlowest replyBehind
512142 ms2.8%5.9 ms0
1,024265 ms5.3%6.5 ms0
2,048550 ms11.0%11.9 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: 192 msafter: 88 ms
Stores
256
Requests failed
10 of 121
Stores behind
0

Database locked

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

fault: 1,649 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,716 msafter: 1,662 ms
Stores
256
Custody scans
2,560
Longest wait
227 ms
Stores behind
0

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

Runner: AMD EPYC 7763 64-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.