How a task becomes work, how work becomes proof, and every place we assumed the contributor might be lying.
You cannot trust a result you did not compute. A volunteer can return garbage, or nothing at all, and claim payment. This is the problem of volunteer computing and it long predates crypto — BOINC was solving it in 2002.
Any system that pays for unverified work is a faucet for fraud. So dispatch was built last, after the accounting, and it is built around three defences.
Every unit is computed independently by need machines (3) and settles
only when their digests agree.
⚠ Raised 2 → 3. With
need = 2a single colluding pair returning the same wrong answer settles a unit. At 3 they must control a majority of three independent claims on the same unit — materially harder, though see what is still weak.
On disagreement the unit goes to disputed, nobody is credited, and it is
re-issued with need raised.
else {
// ⚠ No credit to ANYONE on a disagreement.
u.status = 'disputed'; u.results = []; u.need = Math.min(3, u.need + 1);
}It is tempting to pay the majority. With need = 2 there is no majority — and
paying the first responder rewards whoever answers fastest, which is exactly
the incentive an attacker wants. So a dispute pays nobody.
Roughly 1 unit in 4 is a canary: a unit whose correct digest we already know, computed server-side with the same shared kernel. A node that returns a wrong answer to a canary is quarantined immediately and stops being counted.
⚠ Raised from 1-in-6 → 1-in-4. Canaries are the defence collusion cannot beat. The cost is real — a quarter of the pool's effort now proves honesty rather than producing output — and that is the correct trade while money is on the line.
Quarantine covers the hardware, not just the id. Node ids are
client-generated, so a reload buys a fresh one. Quarantine therefore also
records a coarse fingerprint (vendor|arch|class|buffer|invocations), which
makes evasion cost more than pressing F5.
⚠ This is not identity and nothing here pretends it is. A determined actor can lie about their reported adapter. It raises the cost from "reload" to "lie convincingly" — that is the honest size of the improvement. The fingerprint is deliberately coarse so it cannot become a tracking identifier for honest users.
Redundancy alone is beatable by two colluding clients. A canary is not, because the client cannot tell a canary from real work — the claim response is byte-identical for both.
Quarantine fires only on a confidently wrong answer to a question we already knew the answer to. It never fires for being slow, offline, or flaky. That distinction matters: honest machines fail all the time, but they fail by being absent, not by being wrong.
Published attacks (ACM CCS 2025) reconstruct original inputs from the intermediate state peers observe. So the queue physically cannot carry private work: payloads are capped, stored in plaintext in a public blob, and served to anyone who asks.
If it would be bad for it to be public, it cannot be a work unit. That is enforced by the shape of the system, not by a policy someone has to remember — and CortexInsight runs its secret-shape gate over the whole payload and every chunk before dispatch, because chunking can split a key across a boundary and hide it from a per-chunk test.
Verification compares digests from different machines. That only works if the result is bit-identical across vendors — and JS/WebGPU floating-point operations are not guaranteed identical across GPUs, drivers, or instruction orderings.
A single float anywhere in a kernel would make honest machines look like liars.
So every kernel is integer-only:
export function fnv1a(s: string, seed = 2166136261): number {
let h = seed >>> 0;
for (let i = 0; i < s.length; i++) {
h ^= s.charCodeAt(i) & 0xff;
h = Math.imul(h, 16777619) >>> 0;
}
return h >>> 0;
}Rules for any new kernel:
- No floats. Integer arithmetic only — including the square root
(
isqrt, written with explicit parentheses precisely because clever operator precedence here would be a silent correctness bug on some machines and not others). - No
Math.random, noDate, noperformance.now()in the result path. - No iteration over unordered structures (
Object.keysordering,Set). - Seeds are derived from content and index, never random — the whole ledger must be reproducible from its own contents by anyone auditing it.
The kernels live in _motus.ts and are imported by
the server; the browser carries a byte-identical copy in live.js. If you
change one, change both.
| kind | what it computes | why it exists |
|---|---|---|
embed |
64-bucket hashed term-frequency vector, integer counts | builds a searchable index of a public corpus |
score |
integer cosine-like similarity ×10000 | ranks documents against a query |
matmul |
INT8 × INT8 → INT32 tile multiply | the actual primitive of quantized model inference |
canary |
same as embed, with a known answer |
catches liars |
matmul is the interesting one. A transformer forward pass is, overwhelmingly,
matrix multiplication — and INT8 accumulate is exactly what quantized inference
does. It also has a property float matmul does not: it is exact, so the same
consensus check that guards embed guards it too. A float matmul tile could not
be verified by digest at all; two honest GPUs would differ in the low bits and
both would look like liars.
⚠ What matmul is and is not. It is the correct primitive and it genuinely
works. It is not a running LLM — a real forward pass also needs weight
distribution, KV-cache residency, layer scheduling and a latency budget that a
pool of opening-and-closing tabs does not have yet. Building the verifiable tile
first is the right order; claiming the model runs today would be exactly the lie
this project exists to avoid.
POST /api/work {op:"kernel-probe"} runs any kernel on a known input and
returns the digest. Re-implement the kernel from this document and you must get
the same eight characters — that is what turns "reproducible by anyone" from a
claim into a check.
curl -s -X POST https://www.semble.cc/api/work -H 'content-type: application/json' -d '{"op":"kernel-probe","kind":"matmul","payload":"32","seed":424242}'kernel-conformance.sh runs seven known-answer cases against production. On its
very first run it caught two real defects:
A NUL byte had replaced a space inside the score kernel's separator —
split(' ') became split('\0'). That does not throw. It produces a
consistently wrong answer, which two honest machines compute identically and
consensus settles happily. Silently wrong and verified is the worst failure
this system has, it was invisible in every editor, and only a known-answer test
finds it.
const [q, d] = payload.split(' ') destructured only the first two tokens,
so every word after the second was silently discarded — a document scored
against one word of itself.
Both are fixed, and 7/7 kernels now reproduce exactly. The lesson generalises:
a deterministic kernel can be confidently, verifiably wrong, and consensus
will not save you. Only a known answer will.
CortexInsight task
│ secret-shape gate (whole payload, then every chunk)
▼
POST /api/work {op:"enqueue"} → units + canaries, seeded from content
│
▼
GET /api/work?node=… browser claims a unit it has not seen
│
▼
runUnit() — integer-only, in the tab, between frames
│
▼
POST /api/work {digest,out,ms}
│
├─ canary + wrong → QUARANTINE, immediately
├─ digests agree → SETTLED · both machines credited · RECEIPTS written
└─ digests differ → DISPUTED · nobody credited · re-issued
A settled unit is worth WORK.UNIT_MOTUS (25) MOTUS-seconds × the node's
capability. Completed work is worth more than availability, because
availability is a promise and a verified result is a fact.
⚠ Measured 2026-08-12: a visitor clicked lend, clicked start, and got "queue empty — nothing to compute right now." Every part of the machine worked and a stranger still got nothing. No amount of verification machinery matters if the first move lands on an empty queue — that is the funnel failing at step one, and it wastes the single moment someone was willing.
So when a machine asks for work and there is none it can take, the queue tops up from a standing corpus: real, verifiable units over text that is already public.
Two details that make this honest rather than theatre:
- Standing work is labelled everywhere —
standing: trueon the claim, a separate task name inbyTask, and its own note on the page. A pool that looks busy while secretly spinning its wheels would be worse than an honest idle one. - Replenishment is measured per-node, not globally. Counting only global open units meant a machine that had already computed everything was told "nothing to compute" while the page simultaneously reported eight units out — because a node may never take the same unit twice. The guarantee has to be measured from the perspective of the machine asking.
Operator control: POST /api/work {op:"standing", on, task, kind, corpus[]}.
Raising the agreement threshold means a unit cannot settle until three
distinct machines have computed it. With a small pool, units accumulate in
verifying and nobody is credited yet.
That is correct behaviour, not a stall — those units settle the moment enough people arrive, and everyone who computed them is credited then. The page says so directly rather than letting it look broken:
N units are waiting for more machines. Verification needs 3 independent machines and the pool currently has X.
A commons needs a crowd. That is a real property of the design, and hiding it would misrepresent what the system is.
GET /api/receipts?node=<id> returns what a machine actually did: the unit, the
task it fed, the milliseconds it took, and the agreed digest. Anyone can
re-run the unit with the published kernel and check they get the same eight hex
characters.
Receipts survive the operator clearing the queue. DELETE /api/work drops
units and keeps receipts, deliberately:
The queue is the operator's. The receipt is the contributor's. One person must never be able to erase another's proof.
For rungs 1–4 this field was hard-coded false, so that no surface could
imply work was happening while dispatch was unbuilt.
It is now derived from the queue — true when units are open or verifying, false when they are not. It earned the right to be true.
need = 3still yields to a big enough collusion. Three nodes returning the same wrong answer settle a unit. The canary rate is what actually bounds this, and an attacker running many nodes gets many rolls of the dice. Both are dials; turn them up further before meaningful money flows through work-based earnings.- Quarantine is per-client-id plus a coarse fingerprint — better than id alone, still not identity. A reload costs the attacker all accrued balance, which is a real deterrent, but a determined actor who lies about their adapter defeats it.
- The kernels are useful but modest.
embed/scoreindex a public corpus;matmulis a real INT8 tile but a tile is not a model. Anyone claiming a few browser tabs rival a rented H100 is selling something, and it will not be us. - A deterministic kernel can still be wrong. Consensus proves agreement, not correctness — see the two conformance bugs above. Known-answer tests are the only thing that catches this class, and they belong in CI.
- No work is dispatched unless the operator enqueues it. An idle queue means
an idle pool, and
jobsRunningsays so.