Make being the best fake-data tool, and known for it, the goal the rest serve
Tests / vet + fmt + tests (pull_request) Successful in 1m23s
Tests / Gitea release from CHANGELOG.md (pull_request) Has been skipped

This commit is contained in:
2026-09-20 23:01:30 +02:00
parent f206a18027
commit 343c9fa98a
4 changed files with 39 additions and 28 deletions
+1 -1
View File
@@ -11,7 +11,7 @@
- Gitea queues Actions runs that `/repos/{owner}/{repo}/actions/tasks` does not - Gitea queues Actions runs that `/repos/{owner}/{repo}/actions/tasks` does not
list, so an empty task list says nothing about whether CI ran; read list, so an empty task list says nothing about whether CI ran; read
`/repos/{owner}/{repo}/commits/<sha>/status`. `/repos/{owner}/{repo}/commits/<sha>/status`.
- README goal 13 is gated at 7.0 on the `comprehension-panel` skill, and below it - README goal 14 is gated at 7.0 on the `comprehension-panel` skill, and below it
nothing else merges — no feature, no category, no data — bar a security fix and a nothing else merges — no feature, no category, no data — bar a security fix and a
dependency bump. `todo.md` carries the round: the nine-seat findings run at depth 1, dependency bump. `todo.md` carries the round: the nine-seat findings run at depth 1,
a PR per item it names, then the run again, until the score passes. At or above 7.0 a PR per item it names, then the run again, until the score passes. At or above 7.0
+1 -1
View File
@@ -14,7 +14,7 @@ Every shipped dataset, its source, its licence and the attribution it asks for.
| `sv_SE/first-name.tsv`, `last-name.tsv` | [SCB](https://www.scb.se/) names with at least two bearers, 31 December 2022 | CC0 1.0 | "Källa: SCB" | `data-import/names-se.py` | | `sv_SE/first-name.tsv`, `last-name.tsv` | [SCB](https://www.scb.se/) names with at least two bearers, 31 December 2022 | CC0 1.0 | "Källa: SCB" | `data-import/names-se.py` |
| `en_US/first-name.tsv` | [SSA](https://www.ssa.gov/oact/babynames/) baby names, births 1930 to 2020, through [hackerb9/ssa-baby-names](https://github.com/hackerb9/ssa-baby-names) | public domain | none required | `data-import/names-us.py` | | `en_US/first-name.tsv` | [SSA](https://www.ssa.gov/oact/babynames/) baby names, births 1930 to 2020, through [hackerb9/ssa-baby-names](https://github.com/hackerb9/ssa-baby-names) | public domain | none required | `data-import/names-us.py` |
| `en_US/last-name.tsv` | Census Bureau surnames occurring 100 or more times, 2010 | public domain | none required | `data-import/names-us.py` | | `en_US/last-name.tsv` | Census Bureau surnames occurring 100 or more times, 2010 | public domain | none required | `data-import/names-us.py` |
| `sv_SE/sex.tsv`, `sv_SE/birth-number.tsv`, `sv_SE/title.tsv`, `en_US/sex.tsv`, `en_US/title.tsv`, `misc/car.tsv` | curated; Skatteverket's test birth numbers are facts, and `car.tsv` waits for an international source (goal 10) | — | — | — | | `sv_SE/sex.tsv`, `sv_SE/birth-number.tsv`, `sv_SE/title.tsv`, `en_US/sex.tsv`, `en_US/title.tsv`, `misc/car.tsv` | curated; Skatteverket's test birth numbers are facts, and `car.tsv` waits for an international source (goal 11) | — | — | — |
| `misc/currency.tsv` | [datasets/currency-codes](https://github.com/datasets/currency-codes); symbols from [Unicode CLDR](https://github.com/unicode-org/cldr) `en.xml` and `root.xml` | PDDL 1.0; [Unicode License v3](https://www.unicode.org/license.txt) | CLDR: "Copyright © 1991-2025 Unicode, Inc. Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the United States and other countries." | `data-import/currency.py` | | `misc/currency.tsv` | [datasets/currency-codes](https://github.com/datasets/currency-codes); symbols from [Unicode CLDR](https://github.com/unicode-org/cldr) `en.xml` and `root.xml` | PDDL 1.0; [Unicode License v3](https://www.unicode.org/license.txt) | CLDR: "Copyright © 1991-2025 Unicode, Inc. Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the United States and other countries." | `data-import/currency.py` |
| `misc/httpmethod.tsv` | [IANA HTTP Method Registry](https://www.iana.org/assignments/http-methods/) | [public domain](https://www.iana.org/help/licensing-terms) | none required | `data-import/httpmethod.py` | | `misc/httpmethod.tsv` | [IANA HTTP Method Registry](https://www.iana.org/assignments/http-methods/) | [public domain](https://www.iana.org/help/licensing-terms) | none required | `data-import/httpmethod.py` |
| `misc/httpstatus.tsv` | [IANA HTTP Status Code Registry](https://www.iana.org/assignments/http-status-codes/) | [public domain](https://www.iana.org/help/licensing-terms) | none required | `data-import/httpstatus.py` | | `misc/httpstatus.tsv` | [IANA HTTP Status Code Registry](https://www.iana.org/assignments/http-status-codes/) | [public domain](https://www.iana.org/help/licensing-terms) | none required | `data-import/httpstatus.py` |
+22 -17
View File
@@ -801,45 +801,50 @@ the Development section below, and who ships a register the four above then draw
## Goals ## Goals
1. **Valid by construction** — every value passes the check its real consumer 1. **The best fake-data tool available, and used because it is** — a developer
choosing a seed-data library or CLI, in any language, should find this the one
worth switching to, and every goal below it is what that costs. Merit is only
half the goal: once the grammar, the data and the CLI are complete and stable,
it ships where those developers install from and is announced where they read.
2. **Valid by construction** — every value passes the check its real consumer
applies; facts that belong together come from one draw, within a value and applies; facts that belong together come from one draw, within a value and
across categories. across categories.
2. **Text means what it says** — a format renders as written; only `{…}` varies, 3. **Text means what it says** — a format renders as written; only `{…}` varies,
random characters included (`{digits(3)}`). One spelling per result; the wrong random characters included (`{digits(3)}`). One spelling per result; the wrong
one is a load error naming the right one. one is a load error naming the right one.
3. **Every mistake is a load error** — `New` rejects the data and `NewTemplate` 4. **Every mistake is a load error** — `New` rejects the data and `NewTemplate`
the inline template; on a loaded generator `Fake` fails only for an unknown the inline template; on a loaded generator `Fake` fails only for an unknown
path, `FakeStruct` only for a non-struct argument or a type its tags do not path, `FakeStruct` only for a non-struct argument or a type its tags do not
describe, with the same error every call, and `Template.Fake` cannot fail at all. describe, with the same error every call, and `Template.Fake` cannot fail at all.
4. **Zero to a value in one command** — `go install`, then `fejkdata sv_SE.person`: 5. **Zero to a value in one command** — `go install`, then `fejkdata sv_SE.person`:
no checkout, no flag. Flags are GNU-form (`--seed 42`, `-n 3`) in any position; no checkout, no flag. Flags are GNU-form (`--seed 42`, `-n 3`) in any position;
the first custom template needs no escape and no option. the first custom template needs no escape and no option.
5. **Data lives in JSON** — a builtin only for what data can't express. 6. **Data lives in JSON** — a builtin only for what data can't express.
6. **Reproducible** — seed in, same stream out; no builtin reads a clock. 7. **Reproducible** — seed in, same stream out; no builtin reads a clock.
7. **Zero dependencies** — standard library only. 8. **Zero dependencies** — standard library only.
8. **Docs index the grammar** — every syntax feature is a heading; every example 9. **Docs index the grammar** — every syntax feature is a heading; every example
runs under test and shows its output; a rule is stated once. runs under test and shows its output; a rule is stated once.
9. **Fast enough to be free** — a value renders in about a microsecond and `New` 10. **Fast enough to be free** — a value renders in about a microsecond and `New`
parses and validates the whole set once upfront, so generating fixtures stays parses and validates the whole set once upfront, so generating fixtures stays
noise against a test's own runtime. noise against a test's own runtime.
10. **Data is sourced, or on its way there** — a shipped fact, a name, place, 11. **Data is sourced, or on its way there** — a shipped fact, a name, place,
code, id or classification, is read from a register or open dataset by a code, id or classification, is read from a register or open dataset by a
[`data-import/`](data-import) script wherever one exists to read; where none [`data-import/`](data-import) script wherever one exists to read; where none
does yet a small hand-written set ships and [`todo.md`](todo.md) carries the does yet a small hand-written set ships and [`todo.md`](todo.md) carries the
step that replaces it. Only non-factual copy stays authored. A sourced table step that replaces it. Only non-factual copy stays authored. A sourced table
holds the rows its source holds: none is added by hand, and one is dropped holds the rows its source holds: none is added by hand, and one is dropped
only by a rule the script states. only by a rule the script states.
11. **Breadth follows what most systems store** — a category is added in proportion 12. **Breadth follows what most systems store** — a category is added in proportion
to how many real schemas hold it: names, addresses, phones, ids, money and to how many real schemas hold it: names, addresses, phones, ids, money and
timestamps before anything domain-specific, and a catalogue serving one niche timestamps before anything domain-specific, and a catalogue serving one niche
waits behind everything serving many. waits behind everything serving many.
12. **Realism is the default, inertness is selectable** — where a value could reach 13. **Realism is the default, inertness is selectable** — where a value could reach
something real, a domain anyone may register or an account a bank could issue, something real, a domain anyone may register or an account a bank could issue,
the realistic breadth ships *and* so does the subset that provably reaches the realistic breadth ships *and* so does the subset that provably reaches
nothing, each on its own path. A fixture that looks nothing like production nothing, each on its own path. A fixture that looks nothing like production
tests nothing; the caller who needs a value that can touch nothing asks for it tests nothing; the caller who needs a value that can touch nothing asks for it
by name. by name.
13. **A cold reader lands in the right place** — the code is judged on what it costs 14. **A cold reader lands in the right place** — the code is judged on what it costs
to read, not only on what it does: reaching the unit behind a symptom without to read, not only on what it does: reaching the unit behind a symptom without
asking a person, changing one piece without holding the rest, a layout whose asking a person, changing one piece without holding the rest, a layout whose
names tell the truth, and a file that stands with no second document open beside names tell the truth, and a file that stands with no second document open beside
@@ -1243,7 +1248,7 @@ the Development section below, and who ships a register the four above then draw
fejkdata has no business making. fejkdata has no business making.
- **`misc.loglevel` is a table keyed by the code, rendering POSIX's keyword.** A flat - **`misc.loglevel` is a table keyed by the code, rendering POSIX's keyword.** A flat
list of names carries neither the code a PRI encodes nor a selector reaching it, and list of names carries neither the code a PRI encodes nor a selector reaching it, and
goal 1 draws the two as one fact. The canonical spelling losing to the one its domain goal 2 draws the two as one fact. The canonical spelling losing to the one its domain
writes, above, settles the rest: a configuration writes `info`, so RFC 5424's writes, above, settles the rest: a configuration writes `info`, so RFC 5424's
`Informational` stays the `severity` column, and the code and the keyword hold the `Informational` stays the `severity` column, and the code and the keyword hold the
two selector slots. two selector slots.
@@ -1253,7 +1258,7 @@ the Development section below, and who ships a register the four above then draw
host with no separator. `misc.tld[se]` misses for it, which `todo.md` carries. host with no separator. `misc.tld[se]` misses for it, which `todo.md` carries.
- **`misc.tld` is a table of its own, and `misc.territory.tld` stays a column.** A - **`misc.tld` is a table of its own, and `misc.territory.tld` stays a column.** A
`parent` demands a child for every parent row, so linking them would drop every root `parent` demands a child for every parent row, so linking them would drop every root
zone row naming no territory, which is most of them, and goal 10 holds a sourced zone row naming no territory, which is most of them, and goal 11 holds a sourced
table whole. The loader refuses the link outright anyway: `tld` is a column of table whole. The loader refuses the link outright anyway: `tld` is a column of
`misc.territory`, and a table may not be named like a column of its ancestor. `misc.territory`, and a table may not be named like a column of its ancestor.
- **`misc.territory` carries a currency code, it does not link to `misc.currency`.** - **`misc.territory` carries a currency code, it does not link to `misc.currency`.**
+15 -9
View File
@@ -7,7 +7,7 @@ Ordered as the releases that ship it.
### Comprehension, until the panel scores 7.0 ### Comprehension, until the panel scores 7.0
Nothing else ships while the score is under 7.0 — no feature, no category, no data — Nothing else ships while the score is under 7.0 — no feature, no category, no data —
bar a security fix and a dependency bump, per README goal 13. This section is one bar a security fix and a dependency bump, per README goal 14. This section is one
round, replayed: the `comprehension-panel` skill's nine-seat findings run at depth 1, round, replayed: the `comprehension-panel` skill's nine-seat findings run at depth 1,
a PR per item it names, then the run again, until the score passes. The run is the a PR per item it names, then the run again, until the score passes. The run is the
nine-seat one: the round is meant to buy architectural change, and the four-seat nine-seat one: the round is meant to buy architectural change, and the four-seat
@@ -50,7 +50,7 @@ This round, in order:
### Data ### Data
Shape: T = table, t = template, c = choice. Read every factual list from a register Shape: T = table, t = template, c = choice. Read every factual list from a register
by a `data-import/` script, as README goal 10 asks. by a `data-import/` script, as README goal 11 asks.
- Add the remaining `misc` tables and templates, one row of the table below per chunk. - Add the remaining `misc` tables and templates, one row of the table below per chunk.
- Read `misc.emoji` from the Unicode `emoji-test.txt` register, and `misc.car` from an - Read `misc.emoji` from the Unicode `emoji-test.txt` register, and `misc.car` from an
@@ -63,16 +63,16 @@ by a `data-import/` script, as README goal 10 asks.
`municipality` as columns on `geo.SE.address` too. `municipality` as columns on `geo.SE.address` too.
- Fill the 398 Swedish localities weighted 200 from SCB småorter. - Fill the 398 Swedish localities weighted 200 from SCB småorter.
- Give `url` and `email` a path that draws only domains nobody can register, keeping - Give `url` and `email` a path that draws only domains nobody can register, keeping
the wide set as the default, per goal 12: 17 of the 40 distinct ones shipped today the wide set as the default, per goal 13: 17 of the 40 distinct ones shipped today
sit on `.se`, `.nu`, `.io` and `.co`, which anyone may register, and only RFC 2606's sit on `.se`, `.nu`, `.io` and `.co`, which anyone may register, and only RFC 2606's
`example.com`, `.net`, `.org`, `.test`, `.example`, `.invalid` and `.localhost` `example.com`, `.net`, `.org`, `.test`, `.example`, `.invalid` and `.localhost`
provably reach nothing. provably reach nothing.
- Audit the rest of the shipped set against goal 12 and give each a never-reaching - Audit the rest of the shipped set against goal 13 and give each a never-reaching
path where it lacks one: `phone` draws live PTS and NANP ranges, `bankgiro`, path where it lacks one: `phone` draws live PTS and NANP ranges, `bankgiro`,
`plusgiro` and `routing` draw live prefixes. `plusgiro` and `routing` draw live prefixes.
- Stop `misc.territory[EH].tld` rendering `.eh`, the one shipped TLD `misc.tld` does - Stop `misc.territory[EH].tld` rendering `.eh`, the one shipped TLD `misc.tld` does
not hold: ISO 3166 reserves it for Western Sahara and the root zone has never been not hold: ISO 3166 reserves it for Western Sahara and the root zone has never been
delegated it, so no resolver answers for it and goal 1 promises otherwise. delegated it, so no resolver answers for it and goal 2 promises otherwise.
- Draw `en_US.phone`'s `exch` as a NANP central office code: `{int(100,999)}` renders - Draw `en_US.phone`'s `exch` as a NANP central office code: `{int(100,999)}` renders
a leading 1 in about an eighth of draws, which libphonenumber rejects, and a leading 1 in about an eighth of draws, which libphonenumber rejects, and
`TestShippedUSPhone` proves the shape rather than the rule. Assert the rule with it. `TestShippedUSPhone` proves the shape rather than the rule. Assert the rule with it.
@@ -91,7 +91,7 @@ by a `data-import/` script, as README goal 10 asks.
beside the family: require the path step to reach a sibling category, and seed every beside the family: require the path step to reach a sibling category, and seed every
draw group of the render from the outer selector's pins. draw group of the render from the outer selector's pins.
- Read `email.local`'s and `username`'s handles from the shipped name tables, which - Read `email.local`'s and `username`'s handles from the shipped name tables, which
goal 10 asks for and the hand-written list they use today does not meet. Keep the goal 11 asks for and the hand-written list they use today does not meet. Keep the
handle shape: `username` shortens a surname to `ahl` or `sjo`, and the US one draws handle shape: `username` shortens a surname to `ahl` or `sjo`, and the US one draws
unisex given names, neither of which falls out of the tables unaided. unisex given names, neither of which falls out of the tables unaided.
- Decide whether `email.local` and `username` share one list: a reference between - Decide whether `email.local` and `username` share one list: a reference between
@@ -173,8 +173,11 @@ by a `data-import/` script, as README goal 10 asks.
### Open questions to settle ### Open questions to settle
- Decide where the module is found from, before goal 1's announcement: the import
path is `gitea.larvit.se/larvit/fejkdata`, a developer looking for a fake-data
library searches GitHub and pkg.go.dev, and a module path is a major to change.
- Decide whether `data/misc`'s 33 flat files gain a level before v1.0.0: a folder is a - Decide whether `data/misc`'s 33 flat files gain a level before v1.0.0: a folder is a
path segment, so `misc/net/tld` is a rename a consumer pays for, and goal 11 promises path segment, so `misc/net/tld` is a rename a consumer pays for, and goal 12 promises
the directory keeps growing. the directory keeps growing.
- Decide whether `misc.browser` becomes a parent of `misc.useragent`, so - Decide whether `misc.browser` becomes a parent of `misc.useragent`, so
`misc.browser[Chrome].useragent` resolves. Adding a `parent` after v0.1.0 breaks a `misc.browser[Chrome].useragent` resolves. Adding a `parent` after v0.1.0 breaks a
@@ -230,8 +233,11 @@ because pairing a street with its exact postnummer rewrites shipped rows.
## v1.0.0 ## v1.0.0
- Cut it once the shipped data is in its record shape and one full minor has shipped - Cut it once the shipped data is in its record shape and one full minor has shipped
with no breaking change, per the README's Versioning table. It plans no work of its with no breaking change, per the README's Versioning table: v0.1.0 settles the
own: v0.1.0 settles the record shape and v0.3.0 is the quiet minor. record shape and v0.3.0 is the quiet minor.
- Announce it where a developer choosing a fake-data tool already reads, which is
goal 1's second half and waits for the tag: complete, stable, installable without
Go. Write the README's first screen for someone deciding in a minute.
## Not release-bound ## Not release-bound