How it works
We plant a bug, then watch your tests.
A passing test suite proves the tests ran. It does not prove they would object to wrong behaviour. abloh settles that by changing your code on purpose and checking whether anything fails.
Step one
One check, on the pull request you already opened
abloh runs in your existing CI and keeps a single GitHub check up to date as the branch moves. It confirms the suite is stable before it changes anything, checks whether your diff actually executed, plants faults in the changed lines, reviews the ones that survived, and reconciles the commits against approved tickets.
Nothing here needs a new pipeline, a new test runner, or a change to how you work.
Step two
A score for the suite, measured against your diff
Every planted fault gets a verdict: a test objected to it, or nothing did. Faults that could not be run at all are left out of the score rather than counted as caught, so a broken run never flatters the result.
Faults nothing noticed go to AI review, which separates real gaps from changes that cannot alter behaviour. A suggested test appears only after abloh has proved that it catches the planted fault and that the rest of the suite still passes.
await expect(settle({ expiresAt: settlementTime })) .rejects.toThrow("QUOTE_EXPIRED")expect(ledger.post).not.toHaveBeenCalled()
What the morning report actually holds.
One panel per engine, each with what it planted, what your tests missed, and the test that closes the gap. The tabs are clickable.
ledger-core · full repository
Four engines, one night
Engine detail →What survived the night
Full report →Every line changed this month, checked for a test that executes it AND asserts on what it does.
it("keeps the minus sign on zero-value reversals", () => {
expect(exportCsv(reversal(0)).row).toContain("-0.00");
});2,148 mutations planted across 214 files, operators weighted by the repository’s own bug history. What the suite misses is a bug it would ship.
1,982 of 2,148 planted changes were detected · 41 had no test executing them at all
it("charges the full refund, not the rounded one", () => {
expect(refundTotal(0.01, { qty: 3 })).toBe(-0.03);
});34 merged fixes re-broken overnight, one at a time. A regression a test catches is guarded; a regression nothing notices would ship silently today.
it("rounds half-cents away from the customer", () => {
expect(round(0.005)).toBe(0.01);
});it("posts once when the retry times out", () => {
expect(postWithRetry(timedOut(entry)).count).toBe(1);
});Bugs written the way engineers actually write them — a model plants the mistakes a tired reviewer approves, and the suite either objects or does not.
- const refundable = capture.amount;+ const refundable = order.total;
it("refunds only what was captured", () => {
expect(refund(capture(order, 0.6))).toBe(-0.6);
});Five properties of the ledger that must survive any refactor, attacked overnight with more than 3,000 generated inputs. Four held.
refund(0.01, qty: 3)
expected sum(ledger) = 0
got −0.02property(amounts(), quantities(), (a, q) => {
expect(sum(ledger(a, q))).toBe(0);
});- 53 closed · 35 arrived since March — ahead by 18
- every audit since April closed more than arrived
- August ran hottest both ways: 17 closed, 14 arrived
- 5 gaps have survived 3+ audits — all in settlement/
- settlement/ holds 41% of open gaps on 9% of the code
- both reopened gaps share one pattern: rounding at boundaries
See it on your own code.
One repository is enough to find out what your suite would miss.
Try now