How we set groundinglab's admission policy

groundinglab's admission gate lets a PCOC in when its making kept a steady pace, enough of its points are anchored in Bitcoin, and a check of a few legs drawn at random from across the whole making matches.

The count in the table is this policy's live setting, not a rule of the specification. Below are the live numbers, the reasoning behind the calibration study, and the evidence, which anyone can check and rerun.

25 October 2026 (ACDT). Live policy: groundinglab admission policy gl-admit-v12, status active. Born height is 972685. Heights below 972685 are testing, not production. An earlier object is rejected with before_born_height. The gate runs it under SPEC 2.3 (pin spec-2.3.0). Live testing floor is 0.1 legs/s (1/10). There is no tip-versus-last-beacon submission deadline, and verify_cap_per_door_session is unset (no door-session cap). Specification 2.3 folds errata 1 and 2 into the ratified text and gives no lever a default.

The policy

These are the settings groundinglab's own gate uses. The specification defines each one, its unit and its allowed range; a policy picks values inside those ranges. Version 2.3 gives no lever a default. They are groundinglab's choices, not rules of the specification, and another service's gate can choose differently.

SettingValueWhat it meansAllowed by the specification
Leg-rate floor0.1 legs per second (1/10), testingAt least one leg every 10 seconds on average, over the making, measured against Bitcoin's block times. Live testing floor; retune after more producesany whole-number ratio p/q
Deep check18 legs, in 3 rounds of 618 randomly drawn legs are recomputed in fullat least 1 round of 6
Anchored minimum6 of 16 pointsAt least 6 of the 16 recorded points are anchored in Bitcoin, any 62 to 16
Submission deadlinenoneNo tip-versus-last-beacon deadline. SPEC 2.3 defines no such lever; this policy does not set one—
Door-session verify capunsetNo per-door-session verify cap. A valid PCOC is judged on merit, not on how many times this door verifiedinteger ≥ 1, or unset
Held retry600 secondsA check that could not read Bitcoin's record is retried every 10 minutesat least 1 second
Fake legno expiryA key caught with a fake leg is ignored at this gate from then onany time, or no expiry

The full policy file and its notes: policy/groundinglab-admission on GitHub (gl-admit-v12.toml).

The live testing floor is 0.1 legs per second (1/10). The 0.2 calibration in the argument and speed tables below is the measurement study that argued for a production floor candidate; it is labelled as that study and is not the live lever.

The argument

  1. What the floor is for. A PCOC is worth something because making one costs real resources over real time. The floor is the slowest pace the gate accepts. Together with the memory each PCOC needs, it caps how many PCOCs one machine can make at once, and that cap keeps PCOCs scarce. See the threat model and cost and incidence.
  2. One honest maker passes easily, even on modest hardware. Making one PCOC, our three commodity reference systems (two laptops and a mini PC) run at 0.402, 0.375 and 0.242 legs per second (table below). The slowest is reference system 2, the low-end machine the specification names. Even reference system 2 is about 20% above the 0.2 calibration study floor (and well above the live 0.1 testing floor).
  3. Making many at once runs into memory bandwidth. Each PCOC needs its own 256 MiB of memory, and no cache on these machines holds it. On the two six-core laptops the total levels off at about 1.0 to 1.14 legs per second, however many PCOCs are added, so each one gets slower. At four at once both laptops stay above the 0.2 calibration study floor. At six at once both fall below it, at 0.190 and 0.170. Reference system 2 stays above that study floor making two at once, at 0.238. At a ceiling of 1.14 and a study floor of 0.2, a machine like reference system 1 can make at most 5 PCOCs at once and still pass that study bar (derived).
  4. Optimising is welcome, because the work still gets done. Vector instructions, the processor's SHA instructions and running real PCOCs side by side all fulfil the contract. The cost holds because every leg is really computed. Six builds in six languages land within the same range on each machine, set by how fast it moves memory, and none found a way to skip work and still pass.
  5. Faking legs is cheating, and it doesn't pay. Each leg starts from the previous one's result, so the chain is sequential, and its pace is measured against Bitcoin blocks that no one can predict. The 18 legs are drawn after the PCOC is submitted. Faking a quarter of the legs would gain at best one extra PCOC for every three, and is caught 99.44% of the time. Faking 1% is caught about one time in six but saves only about 1%, and one catch means the gate ignores that key from then on (odds below). In our judgment the trade loses at every fake fraction.
  6. The other settings are operational. Six anchored points are enough to time the making without punishing a weak connection. This live policy sets no tip-versus-last-beacon submission deadline. A ten-minute retry waits out a temporary outage without hammering Bitcoin's record. Version 2.3 gives these levers no default. The values in the table are this policy's live settings.
  7. The verifier measures; the policy decides. Every gate measures a PCOC the same way. This page argues for groundinglab's choices, and a service with other needs can choose other values inside the same ranges. See How it works and the specification, sections 15.4 and 15.5.

Calibration study (not the live lever): a 0.2 production-floor candidate was calibrated on reference system 2 (low-end), with reference system 1 as the primary reference. The live testing floor is 0.1 (1/10). The full derivation of the 0.2 study is in the calibration note.

What this is, and isn't

This is not a claim of proof; it is a judgment call based on the evidence we have so far.

More research and results will follow, including SDK optimisation and refinements to the specification. PCOC is an evolving, flexible design. Its settings can be tuned for different contexts, environments and cost floors, and any new value will come with a new policy id and new evidence.

How we tested

  • One specification, nothing else. Each builder got only the public specification (2.2 with erratum 1), the policy files and a fixtures list naming the cases and output keys, with no expected values. Everything was pinned to one commit.
  • One prompt. Every builder got the same published prompt, with only the language changed. It asked them to optimise as far as their language allows, and to report any way to do less work than the specification intends as a possible flaw.
  • Isolation. Each build was written by an AI model working on its own, in a new empty repository, with no access to any other implementation.
  • Six models, six providers, six languages, all at high effort (table below).
  • Reference systems. Code can be built anywhere, by anyone. The timings that count were taken by compiling each build from its own source and running it on three fixed reference systems, all commodity hardware (two laptops and a mini PC): reference system 1 (primary), reference system 2 (the specification's low-end host) and reference system 3. Their configurations are in the table below and in REFERENCE-SYSTEMS.md. The builders' own cloud runs only showed that the builds work, and are not used.
  • A first round. Two builds at low effort, on purpose, to expose ambiguity. Their disagreements became the 29 clarifications of erratum 1 (round 1).
BuildModelProviderLanguageEffortCommit
AClaude Sonnet 5.5AnthropicTypeScript, Node 22 with WebAssemblyhighb3d7b02
BGPT-5.6 SolOpenAIPython 3 with a C extensionhigh (no separate effort setting was exposed to it)b18a5f6
CGrok 4.7xAIZig 0.15.2highffcfc22
DGemini 4 ArgonGoogleKotlin, JVM 21highfd24932
EKimi K3MoonshotC#, .NET 8highd9fa6ea
FGLM 5p3ZhipuSwift 6.1 with C kernelshigh6d976f4

Each build's code, prompt, model card and its own unedited report are on GitHub.

Six builds agree

  • Same bytes. On all three machines, all six builds produce byte-identical test objects: O1 800ad07a87a567c8…, O2 6bfc769b831b62de… and the production object O3 b16ecdaa13ad6df2….
  • Every build verifies every other build. 6 verifiers × 6 producers × 3 objects × 3 machines: 324 of 324 cross-verify cells match.
  • Negatives refused. Every build reports all 13 permanent negatives, the known wrong shortcuts, as non-matches, on every machine.
  • Fixtures. 13 of 14 fixture outputs are identical across all six builds. The exception is one test vector in build F (hashcash.txt): it hashes a header once where the fixtures ask for twice. It touches no object and no verify record.
ObjectRef. system 1Ref. system 2Ref. system 3
O1 (small test profile)36 of 36 match36 of 36 match36 of 36 match
O2 (larger test profile)36 of 36 match36 of 36 match36 of 36 match
O3 (production profile)36 of 36 match36 of 36 match36 of 36 match

Every cell is listed in verify-grid.csv. O3 records differ only where build C draws its six spot-check legs from the operating system's random source; all its results match.

How fast, on reference systems

SystemRoleCPUCores / threadsL3 cacheSHA instructions
Reference system 1primary referenceAMD Ryzen 5 5600H, laptop6 / 1216 MiByes
Reference system 2the specification's low-end hostIntel Core i7-10610U, mini PC4 / 88 MiBno
Reference system 3second commodity laptopAMD Ryzen 5 7430U, laptop6 / 1216 MiByes

One production leg (2,000,000 steps), seconds, median of 3 runs, optimised / plain scalar (measured):

BuildRef. system 1Ref. system 3Ref. system 2
A TypeScript6.32 / 139.446.56 / 133.819.47 / 183.77
B Python + C5.74 / 5.735.85 / 5.757.92 / 7.91
C Zig2.47 / 2.512.72 / 2.727.59 / 4.21
D Kotlin2.75 / 6.112.95 / 6.095.16 / 9.52
E C#3.94 / 6.224.03 / 6.146.34 / 8.77
F Swift + C3.17 / 4.853.27 / 5.045.04 / 7.80

Making several at once (measured): N independent PCOCs on one machine, each with its own key and its own 256 MiB of memory, nothing shared and nothing skipped. Build C was the producer: its fast engine, except on reference system 2, where its scalar engine is the faster one. The last counted leg of every instance was recomputed by build D, and every one matched.

MachineAt onceEach, legs/s (median / slowest)All together, legs/sAbove the 0.2 study floor?
Reference system 110.402 / 0.4020.402yes
Reference system 140.283 / 0.2821.133yes
Reference system 160.190 / 0.1841.140no
Reference system 310.375 / 0.3750.375yes
Reference system 340.246 / 0.2420.985yes
Reference system 360.170 / 0.1631.015no
Reference system 210.242 / 0.2420.242yes
Reference system 220.238 / 0.2380.477yes

Method: all instances start together. The memory fill and first leg are discarded, then a 60-second window is measured with every instance running. These are steady leg rates over that window, not yet the full rate over a real hike paced by Bitcoin blocks (still open). Load: reference system 3 had a browser open; on reference system 2, a batch job was paused during these runs.

How the floor follows (derived, then judgment):

  • The specification says to set the floor a little below the low-end host's best legal rate. Reference system 2 runs 0.242 alone and 0.238 each with two at once. 0.2 is about 17% below its single rate.
  • On the six-core laptops the floor falls between four and six at once. At the measured ceiling that means at most 5 per machine.
  • So the calibration study kept 0.2 legs per second as the production-floor candidate. The live testing floor is 0.1 (1/10).

What each language could do

  • TypeScript (A). Node gives no access to the SHA instructions, so it relies on a WebAssembly kernel. It is the slowest optimised build, and its plain version is about 20 times slower again.
  • Python with C (B). Its only fast path needs AVX-512, which none of the reference systems has. There, its optimised and plain results are the same compiled C.
  • Zig (C). Its explicit vectors give the fastest leg on the machines with SHA instructions. On reference system 2 its fast path is slower than its plain one, which is untuned and flagged in its review.
  • Kotlin (D). The JVM's compiler vectorises the loop on its own. Its 512-bit vector path is emulated on these machines and is not used.
  • C# (E). It uses an AVX2 engine. .NET has no direct SHA instructions, so it calls the system's crypto library for the hashing.
  • Swift with C (F). It uses C kernels with an AVX2 path.

Every build that reached the processor's vector and SHA features lands within about 2.5 to 4 seconds per leg on the Ryzen laptops. The limit is memory bandwidth, not the language, and no language gives a way below the floor.

Attacks we considered

Faking legs. A fake leg is one whose result was never computed. The deep check recomputes 18 legs drawn at random after submission. The chance of being caught when a fraction f of legs is faked is 1 − (1 − f)18 (specification section 15.5):

Share of legs fakedWork saved, at bestCaught
1%about 1%16.5%
5%about 5%60.3%
10%about 10%85.0%
25%about 25% (at best one extra PCOC for every three)99.44%
50%about 50%99.9996%
  • Sequential chaining. Each leg starts from the previous leg's result, so a fake cannot be patched in after the fact.
  • Unpredictable timing. The pace is measured against Bitcoin's block times, which no one controls, so a saving can't be banked ahead.
  • The cost of a catch. The PCOC is refused, and that gate ignores the key from then on.
  • Known shortcuts. The specification lists 13 permanent negatives, ways to do less work that must give a different answer. All six builds rejected all 13.
  • Optimising is not cheating. Doing every leg faster, or running several real PCOCs side by side, fulfils the contract. Faking skips the work.

Still open

  • Confirm the floor with full hikes paced by real Bitcoin blocks, on reference system 2 (low-end) and reference system 1. The figures above are steady 60-second windows. This is open, not blocking.
  • Publish the policy under its final id and deploy it on the gate.
  • Confirm four operational settings carried over from the earlier policy: retry count, held-block limit, fast-accept bound and the background check budget.
  • The next specification revision (2.3), now queued.
  • SDK optimisation.
  • More machines, especially ones that you test.

Test it yourself

This is an open test, and we'd like more people to run it. Clone the evidence, build any of the six, or write your own from the specification, then run the same kit on whatever you have: a laptop, a server, an ARM board. Compare your numbers with the tables above and send them to us. A different machine or a better build is exactly the evidence we want.

  1. Get the code: git clone https://github.com/groundinglab/pcoc, then follow the evidence README. The kit installs every toolchain in your user directory, with no root needed.
  2. Build, test and cross-verify. Your objects should match the published SHA-256 sums exactly.
  3. Time a leg and a few PCOCs at once.
  4. Submit through a Reference results issue, or a pull request in the results format. See how to submit.

Submissions are listed as community-measured, kept apart from our reference runs, and considered at the next calibration.

Read more and sources

If you think a figure is wrong, rerun it and tell us.