Fake ID > Articles > Fake Phone Numbers That Cannot Exist: A 12% Defect Hiding in One `mt_rand` Call

This article has not been translated into English yet — you are reading the English original. Also available in:Deutsch, Українська

Fake Phone Numbers That Cannot Exist: A 12% Defect Hiding in One mt_rand Call

Roughly one in eight of the American and Canadian phone numbers our generator emitted could not exist. Not "looked odd" — could not exist, in the sense that the North American Numbering Plan forbids them and any validator you care to name rejects them on sight.

The first line of the deployed cached/en_US/phone.txt was +12121007909. Area code 212, Manhattan, entirely real. Then the central office code: 100. There is no 100 exchange in Manhattan or anywhere else, and there never can be.

The cause was one call to mt_rand(1, 9).

What makes this worth writing up is not the defect. It is that the obvious fix would have been worse than the bug, for a reason that has nothing to do with phone numbers — and that fixing it properly forced us to ask a question we had been avoiding: whether generating plausible phone numbers is a good idea at all.

The rule that was broken

A North American number is NPA-NXX-XXXX. NPA is the area code, NXX is the central office code, XXXX is the subscriber line.

Two constraints apply to NXX that most people never think about:

  • The first digit must be 2–9. A leading 0 or 1 is structurally impossible, because 0 and 1 are the operator and long-distance prefixes. An exchange starting with either would be unreachable by construction.
  • N11 codes are reserved. 211, 311, 411, 511, 611, 711, 811, 911 are service codes and are never assigned to subscribers.

There is a third convention: 555 is the reserved fictional exchange, the one every American film uses. It is not forbidden by the numbering plan in the way 1XX is, but it is set aside, and a number in it is recognisably fake to anyone who has watched television.

Our generator picked a real area code from a table, then filled the remaining seven digits:

$num .= (string) mt_rand(1, 9);                    // first subscriber digit: not 0
for ($i = 1; $i < $rest; $i++) $num .= (string) mt_rand(0, 9);

The comment explains the intent: never start with 0. The intent is right for the wrong reason, and it stops one digit short. mt_rand(1, 9) excludes 0 and admits 1 — precisely the digit NANP also forbids. One ninth of every North American number the site had ever produced was born invalid.

What it actually measured

Measured on the deployed data files, roughly 20,000 numbers per locale, on 18 July 2026:

LocaleNumbersNXX starts with 1N11 service code555Total invalid
en_US19,9992,233 (11.17%)190 (0.95%)302,423 (12.12%)
en_CA20,0002,229 (11.14%)184 (0.92%)182,413 (12.06%)
fr_CA19,9982,222 (11.11%)178 (0.89%)242,400 (12.00%)

The three rows agree because the defect is in the algorithm, not the data — every NANP locale shares the same code path and therefore the same failure rate. Re-simulating the pre-fix algorithm over 200,000 numbers per locale reproduces it to two decimal places: 11.02% leading 1, 0.99% N11, 0.11% 555, 12.03% in union.

The theoretical value settles the matter. NXX is drawn from 900 equally likely combinations (first digit 1–9, other two 0–9):

  • 100 of them start with 1 → 11.111%
  • 9 of them are N11 → 1.000%, but 111 is already counted above, so it contributes 8 new ones
  • 555 is 1 more

(100 + 8 + 1) / 900 = 12.111%. Not the sum of the columns — the columns overlap, and adding them is how you get a wrong total that still looks about right.

That is a small warning in itself. An in-code comment describing this defect quoted 11.9%, arrived at by adding rounded components that share a member. The true figure is 12.1%. Nobody would ever have caught that from reading it, because 11.9% and 12.1% are equally plausible. Numbers in comments are unverified assertions wearing the costume of documentation — a point we made at length in A Test That Cannot Fail and then promptly demonstrated on ourselves.

Why the obvious fix is the wrong fix

The natural repair is a rejection loop:

do {
    $nxx = generate_nxx();
} while (!nanp_valid($nxx));

Three lines, perfectly uniform output over the valid space, and it would have broken the site.

Our generator's central guarantee is that a URL is a permalink. The card at a given address is derived by hashing the site's secret salt together with the id; the result initialises the PRNG, after which every field is drawn from one deterministic stream — given name, surname, city, street, postcode, employer, phone. The exact hash, its truncation and the secret itself are deliberately not published here. The same URL yields the same person today, next year, and on a rebuilt server.

That guarantee has a brittle consequence: the stream is positional. Field n gets whatever mt_rand returns at position n. If any earlier field consumes a different number of draws than it used to, every subsequent field shifts, and the card changes completely.

A rejection loop consumes a data-dependent number of draws. Most numbers pass on the first attempt; about one in eight needs a second; occasionally a third. The count depends on the values drawn, which depend on the seed. So for roughly one card in eight, the phone field would consume an extra draw, and everything after it in the stream would move.

The user-visible outcome is not "some phone numbers changed." It is that one in eight permalinks now resolves to a different person entirely — different name, different city, different employer — because a phone number three fields upstream ate one more random draw than it used to.

This is the same invariant that the picker functions protect with mt_srand($keep), and the same one that mutation testing was built around. Correctness of the phone field is worth a great deal. It is not worth the permalink.

The fix: repair the digits, not the draw

The constraint is therefore fixed before we start: the number of mt_rand calls must not depend on what they return. That rules out rejection, and it rules out any conditional extra draw.

What it leaves is repairing the digits already in hand:

if ($cc === '1' && $rest >= 7) {
    $npa = substr($num, 0, 3);          // area code, from the prefix table
    $nxx = substr($num, 3, 3);          // central office code
    $sub = substr($num, 6);             // 4 subscriber digits

    if ($nxx[0] === '1') $nxx[0] = '2';                    // N must be 2-9
    if ($nxx[1] === '1' && $nxx[2] === '1') $nxx[2] = '0';  // not N11
    if ($nxx === '555') $nxx = '554';                       // 555 is reserved

    $num = $npa . $nxx . $sub;
}

No branch draws. The draw count is constant across every input, so the stream lands in an identical position whether the number needed repair or not. Re-running the measurement after the fix gives 0.00% invalid across all three locales, and the determinism check still returns identical numbers for identical seeds.

The cost is honest and should be stated: the output distribution is no longer uniform. Every 1XX exchange collapses onto the corresponding 2XX, so 2XX codes appear roughly twice as often as 3XX through 9XX. N11 codes fold onto N10, and 555 onto 554. That skews about 12% of numbers onto neighbouring exchanges.

Is that acceptable? For this application, yes, and the reason is worth being precise about. Nobody inspects the distribution of central office codes across a corpus of fake identities. Everybody notices a phone number that a signup form rejects. The skew is invisible; the invalidity was not. Had the field been feeding a statistical model rather than a display card, the trade would have gone the other way — and we would have had to solve the determinism problem differently, probably by giving the phone field its own independently-seeded stream so that its draw count could vary without disturbing anything downstream.

That option was available and we did not take it, because it costs a second seeding path in every field that might one day need one. Recording why a cheaper fix was chosen is more useful than recording the fix.

The same audit found two smaller things

Duplicate area codes. The fr_CA prefix list contained eleven entries, but 367 and 438 each appeared twice:

'fr_CA' => ['1', ['514','438','450','579','418','367','581','819','873','367','438'], 10],

Selection is mt_rand(0, count - 1) over the raw list, so those two codes came up at 18.18% each against 9.09% for the other seven. Nothing invalid was produced; Quebec simply had two cities twice as populous as the numbering plan says. The fix is array_unique at selection time, which keeps the count of draws at one and does not disturb anything. Across all 65 locale entries the table holds 959 prefixes, of which 957 are distinct — those two duplicates were the only ones anywhere.

A restriction applied far too widely. The mt_rand(1, 9) rule — first subscriber digit is never 0 — is applied to every locale, justified by the comment "otherwise the number would look like a national-format number with a leading zero." That reasoning is wrong. The national-format leading zero sits before the prefix (07… in Britain, 06… in the Netherlands), not inside the subscriber part. In most countries 0 is a perfectly legal digit there.

The effect is that 10% of the generation space is discarded for no reason, in 62 locales where the rule does nothing useful. In the three NANP locales the rule is accidentally helpful — it blocks 0XX exchanges — but it is also the reason the real problem stayed hidden, because it looks like the leading-digit question has already been handled. A rule that is half-right in the one place it matters is a good disguise for a rule that is wrong everywhere else.

An audit that finds nothing is also a result

Everything above is a defect. That gives a misleading impression of what auditing a data table is like, so it is worth reporting the opposite outcome at the same length.

We checked Denmark, Sweden and Norway against their regulators' primary numbering documents — every prefix, every number length, every exclusion. The result was no mandatory corrections. The prefixes were right, the lengths were right, the deliberate omissions were right. The only change anywhere was two Danish prefixes, 24 and 25, which are now present and bring the Danish list to 26 entries.

Set that beside the North American case in the same codebase. There, one line of code produced a 12% defect rate across three locales. Here, a careful check against primary sources confirmed the table was already correct. Both audits cost roughly the same effort, and only one produced a finding.

This matters because of a bias that builds up quickly: if every audit you write up found something, you start to believe an audit that finds nothing was performed badly. It was not. A clean result is information — it converts an assumption into a checked fact, and the checked fact is what lets you stop re-examining Danish prefixes every time a phone bug appears elsewhere. The Norwegian and Swedish rows in our table were previously believed correct. They are now known correct, and that is a different and better state even though not a single character changed.

It also disposed of a specific myth. It is widely repeated that Swedish mobile numbers have variable length. They do not. The PTS table gives, for each of 70, 72, 73, 76 and 79, a maximum equal to the minimum equal to 9 digits. The confusion comes from Swedish geographic numbers, which genuinely do vary between 7 and 9 digits. Our data had the fixed length right all along — but before the check, being right and repeating a rumour were indistinguishable from the inside.

The same table, two reliabilities

The Danish plan turned up something that has no equivalent in NANP and that changes what the prefix table can be used for.

Denmark's document reserves ranges for mobile use with the word fortrinsvispredominantly, not exclusively: "Nummerserier, der er fortrinsvis afsat til mobilkommunikation". The consequence is that inside the formally fixed-line ranges there are roughly 90 three-digit sub-series issued for mobile service — 342, 344349, 431, 627, 771772 and others. And Danish number portability is total, so the prefix of a real number tells you which block it was originally drawn from and nothing whatsoever about who operates it or over what technology today.

Now notice that this affects the two directions of use completely differently:

DirectionWhat the prefix table gives youReliability
Generation — emit a plausible Danish mobile numberEverything drawn from these ranges is legitimately mobileCorrect. The ranges are mobile by allocation; that is all generation requires.
Classification — decide whether a given real number is mobileA guess based on the originating block, defeated by the ~90 mobile sub-series in fixed ranges and by portabilityHeuristic only.

The same table, the same data, opposite trustworthiness depending on which way you run it. This is easy to get wrong, because a table that has been validated against a regulator feels validated for all purposes, and it is not. Ours is validated for the direction we use it in — and if anyone ever reaches for it to answer "is this customer's number a mobile?", it will produce confident, plausible, frequently wrong answers.

The NANP structural rules that opened this article do not have this property: NXX cannot begin with 1, and that is true in both directions, forever. It is easy to generalise from a rule like that to an assumption that numbering plans are crisp. Most of them are not. Denmark says predominantly, and one adverb in a regulator's document is the difference between a fact and an estimate.

The question underneath: whose number is this?

Fixing structural validity makes the numbers better formed. It does nothing about a more uncomfortable property, which the same audit quantified.

We generate from real, live operator prefixes — genuine mobile ranges, chosen deliberately because they are current and, unlike landline codes, not tied to a city we would then have to keep consistent. The consequence is that we generate precisely where subscribers live. A generated number is not a number that resembles a real one. It may simply be one.

How likely depends entirely on how large the country's numbering space is relative to its population:

LocaleGeneration spaceLocaleGeneration space
is_IS1,350,000en_GB450,000,000
me_ME8,100,000ru_RU576,000,000
lv_LV9,000,000bn_BD630,000,000
hy_AM10,800,000pt_BR1,350,000,000
ka_GE10,800,000de_DE1,530,000,000
ro_MD11,700,000zh_CN2,700,000,000
sl_SI11,700,000id_ID3,060,000,000
no_NO14,400,000en_IN3,600,000,000

Iceland is the worst case by a wide margin. The generator can emit 1,350,000 distinct Icelandic numbers. Iceland has about 390,000 people and roughly as many active mobile subscriptions. Something like one in three or four generated Icelandic numbers belongs to an actual person. Montenegro, Moldova, Latvia, Slovenia, Armenia and Georgia are all in the same range.

Large countries are better but never clean. Britain's 450,000,000-number space against roughly 80,000,000 active mobiles still means about 18% of generated British numbers are live.

This is not a bug. It is the direct, unavoidable consequence of the design choice "real prefix plus random tail," and no amount of care in the tail changes it.

What regulators actually reserve — and what we could not confirm

Several countries reserve blocks specifically so that films, textbooks and test data have somewhere safe to point. We went looking for them, and the honest result is a much shorter list than we expected, plus a lesson about what "we found nothing" is worth.

Confirmed from primary regulator documents on disk:

CountryReserved rangeSizeSource
FranceRoots 01 99 00, 02 61 91, 03 53 01, 04 65 71, 05 36 49, 06 39 986 × 10,000 = 60,000ARCEP numbering plan, annexe 2 to décision 2018-0881
Ireland089 011 0000089 011 0999 (mobile)1,000ComReg 15/136r4
IrelandArea code 020, 7-digit subscriber, entirely "reserved for drama purposes"10,000,000ComReg 15/136r1
Norway680 50000680 59999, status BLOKKERT, for television and film production10,000Nkom numbering plan
UK07700 90000007700 900999 (mobile)1,000Ofcom, Telephone numbers for use in TV and radio drama programmes, rev. 03.2019
Germany0171 3920000…099, 0176 04069000…099, plus a handful of single Vodafone numbers~200BNetzA, Rufnummern für Medienproduktionen, Mitteilung 148/2021
Sweden070 1740605070 174069995PTS, Telefonnummer till böcker och filmer, decision 09.2020
Australia~30 individually listed numbers in 0491 5xx~30ACMA, Phone numbers for use in TV shows, films and creative works

Norway's entry is the most instructive row in that table, because it is useless to us. The block sits in the 68 range, which is fixed-line. Norwegian mobile numbers are 4x and 9x, and our no_NO prefix list contains sixteen entries, of which exactly zero begin with 6. So the generator cannot use the Norwegian drama block — and, by the same token, cannot accidentally stray into it. Nkom's wording is unambiguous ("Numrene i serien skal ikke brukes til ordinær bruk"), the reservation is real, and it is entirely inapplicable to the field we are generating.

That deserves stating as a general point, because "does country X reserve fictional numbers?" is the wrong question. The right one is "does country X reserve fictional numbers in the range I am generating from?" A reserved landline block is no help to a mobile generator, and a reserved mobile block is no help to anyone generating landlines. Half the value of the table above is in the mismatches.

Two other entries were surprises. France reserves six roots, one per geographic zone plus mobile — we had expected the two that get quoted in blog posts. And Ireland, a country of five million, has set aside an entire ten-million-number area code for drama, alongside its small mobile block. The mobile block gets cited everywhere; the 020 allocation gets cited nowhere.

Could not confirm from any source we hold:

Claim we could not stand behindStatus
UK: 01632 960xxx as a second drama rangeZero occurrences in any regulator document. Widely repeated online; the Ofcom page we do hold covers only the 07700 900 mobile block.
South Korea: 010-3348-xxxx and 010-6687-xxxx as reserved exchangesA myth, and the most consequential one on this list — see below.
Netherlands, Brazil, India, Iceland, Finland, Latvia: "no reserved range"We hold no finding either way. This is absence of evidence.
Denmark: "no reserved range"Checked against the numbering plan and not present there. That is weaker than it sounds: a reservation made by a separate regulatory decision, outside the plan, would be invisible to this search. Record it as "not in the numbering plan", not as "proven absent".

And one claim we had to demote after checking it properly. We had recorded Japan and South Africa as hard confirmations of "no reserved range." Only one survives.

For Japan, we hold the Ministry of Internal Affairs and Communications block-assignment tables (as of 1 September 2024) for the 060, 070, 080 and 090 ranges. Every five-digit block from 09010 to 09099 is assigned to a named carrier — NTT docomo, KDDI, SoftBank, Okinawa Cellular — with no block marked as drama, test, fictional or held in reserve. That is a genuinely strong negative: the tables are exhaustive by construction, so an unlisted category would have to be visible as a gap, and there is none.

For South Africa, our ICASA source is a Government Gazette PDF that extracted as largely garbled binary. It contains zero occurrences of "reserved", "drama", "film" or "test" — and that zero means nothing whatsoever, because a corrupt file returns zero matches for every string, including ones it definitely contains. We had banked a conclusion on a search that could not have succeeded.

That failure mode has bitten us before, in a completely different part of the system, and it is the subject of its own article: The Check That Goes Blind Exactly Where You Need It. The short version is that a search returning "nothing found" is reporting one of two very different things — the string is absent, or the search was incapable — and the output looks identical either way.

The Korean block that does not exist

One widely repeated "reservation" turned out to be worse than useless, and it is the strongest illustration in this whole article of why the range matters more than the reservation.

Wikipedia's Fictitious telephone number article lists 010-3348-xxxx and 010-6687-xxxx as South Korea's drama numbers. The primary source says something else. The Korean Film Council (KOFIC) holds six lines in total — four fixed, two mobile — for film production, and it deliberately publishes only the area code and the exchange (국번), not the full numbers, precisely so that they are not used arbitrarily. So what exists is two specific subscriber lines, not a block of ten thousand.

Generating a random four-digit tail inside exchange 3348 would therefore not avoid live subscribers. It would aim at them: it would concentrate every Korean card onto one exchange in which 9,998 of the 10,000 numbers belong to real people. A "fix" built on that citation makes the problem it claims to solve strictly worse, and it looks responsible while doing it.

The general rule this teaches is narrower than "check your sources": a reservation quoted as a range, when the primary document reserves individual numbers, is not a range. The two are written almost identically in secondary sources.

So the table above has three tiers, and the tiers matter more than the rows: confirmed from a document we can quote, believed but undocumented, and not investigated. Only the first tier is safe to build on.

The dilemma, and the three locales where it has an answer

Suppose we move to reserved ranges wherever they exist. Consider what that means.

Germany's reservation is about 200 numbers. The German locale generates cards without limit. Long before you had looked at a few thousand German identities, phone numbers would begin repeating — and repeating in a way that is instantly visible, because they all share a handful of prefixes. The field would go from "plausible, occasionally real" to "obviously synthetic, and only two hundred possible." Sweden's block is 95 numbers; Australia's is a list of about thirty individually named ones, with the rest of the surrounding exchange live.

So the reservation being real is not enough. Three conditions have to hold together: the reserved range must sit in the mobile band we generate from, it must be large enough that a card set does not visibly repeat, and it must not be a cultural marker — American 555-01xx is safe and every American reader recognises it instantly as "a number from a film", which trades one kind of falseness for another.

Exactly three locales pass all three: en_GB (Ofcom's 07700 900xxx), en_IE (ComReg's 089 011 0xxx) and fr_FR (ARCEP's 06 39 98 root). For those three the chance that a generated number belongs to a living person is now zero rather than "lower" — and for France that is the largest single gain available anywhere in the set, because roughly 40% of French numbers were somebody's before the change, against 18% for Britain.

The cost is visible and worth stating. The usable reserve is 900 numbers for Britain and Ireland and 9,000 for France — the sub-block ending …000…099 is unreachable because the first subscriber digit is always 1–9. In a set of 200 British cards, roughly 26 phone numbers repeat. That is the price of the guarantee, and it is paid in exactly the countries whose regulators bothered to help, which remains a perverse outcome even when you accept it.

And it fixes 3 locales out of 65. The other 62 are unchanged, including every case the first half of this article called urgent:

  • Iceland — the worst case in the whole table — cannot be fixed. There is no reserved range in the Icelandic plan at all, and the only theoretical route (generating from blocks never issued to any carrier) needs allocation data nobody publishes for Iceland.
  • South Korea and Japan cannot be fixed either, for the two different reasons above: Korea reserves individual lines rather than a block, and Japan's assignment tables leave no unassigned category to use.
  • Montenegro, Moldova, Latvia, Slovenia, Armenia and Georgia sit at the same order of risk as Iceland and have the same non-answer.

That is the honest shape of the result: not "solved", but the boundary of what is solvable has been found and everything inside it has been done. The remaining options are still the same compromises, and they are still open:

  • Reserved ranges everywhere one exists — rejected: it would put Germany on 200 numbers, Sweden on 95, Australia on 30, and 555-01xx into the three most-read locales.
  • Live ranges everywhere, as before — maximum variety, and a real Icelandic subscriber behind a large minority of Icelandic cards.
  • Structurally valid but deliberately unassigned exchanges — central office codes that exist in the plan but are not allocated to any carrier. This requires per-country allocation data we do not have, and the allocations change.

The rest of the work was the unambiguous part: make the numbers structurally valid, remove the duplicate prefixes, and write down the collision figures so that the trade-off is a decision someone can make rather than a property nobody has measured.

The checklist

  1. Know the structural rules of the thing you are faking. "Looks like a phone number" is not a specification. NANP has three constraints on one field; we implemented half of one.
  2. When output must be deterministic, the number of random draws must not depend on the values drawn. This rules out rejection sampling, retry loops, and any conditional extra draw — and it is not obvious until it bites.
  3. Prefer repairing drawn values to redrawing them. Repair is constant-cost. The price is distribution skew, which is usually the cheaper thing to lose.
  4. Write down what the fix costs. "About 12% of numbers shift to a neighbouring exchange" is a fact the next person needs. A silent fix leaves them to rediscover the skew and treat it as a new bug.
  5. Do not add rounded percentages that overlap. Ours summed to 11.9% where the union is 12.1%. Compute the union directly or state the components separately.
  6. Check your lookup tables for duplicates. Two repeated entries out of 959 gave two Canadian area codes double the weight of their neighbours, and nothing about the output looked wrong.
  7. Distrust a justification that is right for the wrong reason. "Never start with 0" was correct in three locales by accident, wrong in sixty-two, and it camouflaged the real defect for the entire life of the field.
  8. Separate "we confirmed there is none" from "we did not find one." They read the same in a summary and are worth completely different amounts.
  9. A zero-result search against an unreadable file is not evidence. Verify the search could have succeeded — grep the corrupt file for a string you know is in it before believing a negative.
  10. Ask whether a reserved range is reserved in your range. Norway reserves a drama block our mobile generator can neither use nor collide with. The existence of a reservation is not its applicability.
  11. Read the regulator's adverbs. Denmark allocates ranges "predominantly" to mobile. That one word means the table is sound for generating numbers and unsound for classifying them.
  12. Record clean audits as findings. "Checked, nothing wrong" converts an assumption into a fact and stops the next person re-checking it. An audit is not judged by whether it found something.
  13. Check whether a "reserved range" is a range at all. Korea reserves six individual lines and publishes only their exchange. Quoted second-hand it reads like a block of ten thousand, and building on that reading would have aimed every Korean card at live subscribers.
  14. Measure the repetition a small reserve buys before you take it. 900 usable numbers means about 26 repeats in 200 cards. That is a number to accept deliberately, not to discover in a screenshot.

The defect itself took one line to cause and eight lines to fix. Everything expensive about it was downstream: the fix that could not be used, the invariant that made it unusable, and the question — still open — of whether a phone number that might ring a real person in Reykjavík belongs on a page of invented people at all.

For the seeding path and the stream invariant this article keeps colliding with, see How Our Generator Works. For the invariant's own test suite and how we established it was capable of failing, see A Test That Cannot Fail. For other defects we found by counting rather than looking, see What We Got Wrong.


Data as of 2026-07-18

The defect measurements were taken on 18 July 2026, against share/name_gen/ng_phone.php as shipped in source_share_1.1.7 and against the deployed cached/<locale>/phone.txt files. The regulator research, the reserved-range change for en_GB, en_IE and fr_FR, and the repetition figures were done on 21 July 2026 against share 1.1.8.

⚠ The reserved ranges are a change to the numbering data; the deployed cached/<locale>/phone.txt datasets are rebuilt centrally, so the three locales carry the old live-range numbers until that rebuild runs.

Sources and notes:

  • The defect rates — measured on deployed data, ~20,000 numbers per locale: en_US 2,423 of 19,999 invalid (12.12%), en_CA 2,413 of 20,000 (12.06%), fr_CA 2,400 of 19,998 (12.00%). Independently reproduced by re-simulating the pre-fix algorithm over 200,000 numbers per locale, giving 12.03% union in all three. The theoretical value is (100 + 8 + 1) / 900 = 12.111%.
  • ⚠ A figure in the source is wrong. The explanatory comment in ng_phone.php states the combined rate as 11.9%, obtained by adding 11.00% + 0.90% + 0.11%. Those components overlap — 111 satisfies both the leading-1 and the N11 conditions — so they cannot be summed, and the addition does not even reach its own stated total (it gives 12.01%). The correct union is 12.1%. This article uses the measured and theoretical figures; the comment has not been corrected.
  • The fixng_phone.php lines 173–183. Post-fix measurement returns 0.00% invalid for all three NANP locales, and mt_srand(7) twice in succession returns the identical number +17375163779, confirming the draw count did not change.
  • The prefix table — 65 locale entries. When the duplicate defect was found the table held 959 prefixes as written and 957 distinct: 367 and 438 appeared twice each in an 11-entry fr_CA list, giving 18.18% selection probability against 9.09% for the other seven codes. Re-counted on 22 July 2026 the table holds 963 prefixes, 963 of them distinct — the fr_CA repeats are gone from the literal table, and deduplication is still applied at selection time via array_values(array_unique(...)) as a belt-and-braces measure.
  • The leading-digit rulemt_rand(1, 9) for the first subscriber digit is applied to all 65 entries. Its stated justification concerns the national-format leading zero, which sits before the prefix rather than inside the subscriber part, so the rule discards 10% of the generation space in the 62 non-NANP locales without cause.
  • Generation-space figures — computed from ng_phone_spec() as the count of distinct emittable national numbers per locale. Iceland: 1,350,000 against a population of ~390,000. Britain: 450,000,000 against ~80,000,000 active mobile subscriptions, giving the ~18% live-number estimate. These are order-of-magnitude estimates against subscription totals, not a check against any allocation database.
  • France — six fiction roots 01 99 00 / 02 61 91 / 03 53 01 / 04 65 71 / 05 36 49 / 06 39 98, from an extracted copy of the ARCEP national numbering plan, in the table headed Racines (format national). The plan cites annexe 2 to décision n° 2018-0881 modifiée, which governs numbering-plan management generally rather than the fiction block specifically. The total of 60,000 is derived (6 × 10,000), not stated in the document.
  • Ireland089 011 0000 to 089 011 0999 is reserved for drama use, from an extracted copy of ComReg 15/136r4. Separately, ComReg 15/136r1 lists area code 020 with 7-digit subscriber numbers as Reserved for Drama purposes; the implied 10,000,000 total is ours, not ComReg's.
  • United Kingdom — the 07700 900000-900999 block is recorded in our own audit note as previously-known information. No Ofcom document is held. A run of 500,000 generated British numbers produced 0 hits in that block, consistent with the expected rate of about 1 in 450,000. The frequently-cited 01632 960xxx range appears in no source we hold.
  • The Nordic audit — Denmark, Sweden and Norway checked against their regulators' primary numbering documents. No mandatory corrections. The only change was the addition of Danish prefixes 24 and 25; the shipped da_DK list now holds 26 prefixes, all two digits, national length 8, giving a generation space of 23,400,000. Verified directly in ng_phone_spec() on the date above.
  • Swedish number lengthsv_SE ships 70, 72, 73, 76, 79 at a fixed national length of 9, generation space 45,000,000. The PTS table gives maximum = minimum = 9 for all five prefixes, so the frequently-repeated claim that Swedish mobile numbers vary in length is false; the variation belongs to Swedish geographic numbers, which run 7–9 digits. Our data required no change.
  • Norway's blocked range680 50000680 59999, status BLOKKERT, reserved by Nkom for television and film production, with the note "Numrene i serien skal ikke brukes til ordinær bruk". Confirmed unusable and uncollidable by inspection of the shipped table: no_NO holds 16 prefixes (40 41 45 46 47 48 90 91 92 93 94 95 96 97 98 99), of which zero begin with 6.
  • Denmark's "predominantly mobile" wording — the plan reads "Nummerserier, der er fortrinsvis afsat til mobilkommunikation". Roughly 90 three-digit sub-series inside formally fixed ranges are issued for mobile use (342, 344349, 431, 627, 771772 among them), and portability is total. The count of ~90 is from the audit and was not independently re-counted here. The generation-versus-classification asymmetry follows from the wording and the portability, not from a measurement.
  • Germany and Sweden — the figures 5,210 (Bundesnetzagentur Verfügung 148/2021) and 495 (PTS) could not be substantiated. No BNetzA document is held. The PTS numbering plan of 8 January 2024 is held but extracted as partly-binary content with no recoverable reserved-range section; the subsequent Nordic audit found no fiction reservation in the Swedish plan either, which is consistent with the 495 figure being wrong but does not disprove a reservation made outside the plan. Both are reported here as unverified.
  • Japan — MIC 電気通信番号指定状況 block-assignment tables as of 1 September 2024 for the 060/070/080/090 ranges. All blocks 0901009099 are assigned to named carriers, with no drama, test, fictional or reserve category present. Treated as a strong negative because the tables are exhaustive.
  • South Africa — the ICASA Government Gazette extract is largely garbled and yields zero matches for "reserved", "drama", "film" and "test". This is not evidence of absence and any previous record of it as a confirmed negative was wrong.
  • Netherlands, Brazil, India, Iceland, Finland, Latvia — no finding in either direction. Listed as uninvestigated rather than as countries without reserved ranges.

← Articles