From 3dc1cf82f19accd7812762d8cfdba62169b15431 Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Sun, 20 Sep 2026 22:45:22 +0200 Subject: [PATCH 1/4] Make the cost of reading the code a goal, and answer to a reader panel each PR --- AGENTS.md | 4 ++++ README.md | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 203d92c..ca6a574 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11,6 +11,10 @@ - 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 `/repos/{owner}/{repo}/commits//status`. +- Every pull request scores with the `comprehension-panel` skill's four-seat run at + depth 1 and answers it in the same PR, per README goal 13: at or above 7.0, address + the findings in one run; below it, fix what the panel names within this PR's reach + and re-score, looping while the score climbs. No merge lowers the last score. - Hard tabs. No comment by default; delete a restatement, a rationale, history, or a file preamble. - One spelling per result: reject the other at `New`, and let the error name the spelling to use. - A standing choice a reader would relitigate goes under Decisions in the README, not in a comment. diff --git a/README.md b/README.md index 5b7528b..a128688 100644 --- a/README.md +++ b/README.md @@ -839,6 +839,12 @@ the Development section below, and who ships a register the four above then draw 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 by name. +13. **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 + 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 + it. A simulated reader panel scores those four, the score is a ratchet no release + lowers, and [`AGENTS.md`](AGENTS.md) says how each pull request answers to it. ## Decisions -- 2.52.0 From f206a1802723597a2b69bc28bd2549563b46a3ec Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Sun, 20 Sep 2026 22:53:14 +0200 Subject: [PATCH 2/4] Gate everything on the comprehension score, and replay the round until it passes --- AGENTS.md | 10 ++++++---- todo.md | 19 ++++++++++++++----- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index ca6a574..48905a0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11,10 +11,12 @@ - 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 `/repos/{owner}/{repo}/commits//status`. -- Every pull request scores with the `comprehension-panel` skill's four-seat run at - depth 1 and answers it in the same PR, per README goal 13: at or above 7.0, address - the findings in one run; below it, fix what the panel names within this PR's reach - and re-score, looping while the score climbs. No merge lowers the last score. +- README goal 13 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 + 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 + every pull request scores with the four-seat run and answers it in one run. No merge + lowers the last score. - Hard tabs. No comment by default; delete a restatement, a rationale, history, or a file preamble. - One spelling per result: reject the other at `New`, and let the error name the spelling to use. - A standing choice a reader would relitigate goes under Decisions in the README, not in a comment. diff --git a/todo.md b/todo.md index b37618c..723f721 100644 --- a/todo.md +++ b/todo.md @@ -4,13 +4,22 @@ Ordered as the releases that ship it. ## v0.1.0 -### Reading the fence layer +### Comprehension, until the panel scores 7.0 -Nine readers scored the project 5.9 of 10 — Navigation 7.0, Locality 5.2, Shape 5.9, -Self-sufficiency 5.7 — and eight of them capped on Locality or Self-sufficiency. Every -one put `hold.go`, `draw.go` and `family.go` first for reading cost: 1,138 lines in +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 +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 +nine-seat one: the round is meant to buy architectural change, and the four-seat +scoring run names too little to steer one. A fresh run replaces the items below. + +Scores, newest last: 5.9 on 2026-09-20 (Navigation 7.0, Locality 5.2, Shape 5.9, +Self-sufficiency 5.7), eight of nine seats capped by Locality or Self-sufficiency, all +nine naming `hold.go`, `draw.go` and `family.go` first for reading cost: 1,138 lines in which each file carries both a load-time fence and render-time machinery, so no file -name says whether a unit runs at `New` or at `Fake`. One chunk per item, in this order. +name says whether a unit runs at `New` or at `Fake`. + +This round, in order: - Define the fence vocabulary where a reader of the code meets it: fence, hold, pin, draw, draw group, expansion against render, family, whole. It exists only across five -- 2.52.0 From 343c9fa98aa6349d98bec554e760f7e2d34df9e9 Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Sun, 20 Sep 2026 23:01:30 +0200 Subject: [PATCH 3/4] Make being the best fake-data tool, and known for it, the goal the rest serve --- AGENTS.md | 2 +- DATA-LICENSES.md | 2 +- README.md | 39 ++++++++++++++++++++++----------------- todo.md | 24 +++++++++++++++--------- 4 files changed, 39 insertions(+), 28 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 48905a0..38b547d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11,7 +11,7 @@ - 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 `/repos/{owner}/{repo}/commits//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 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 diff --git a/DATA-LICENSES.md b/DATA-LICENSES.md index c59a400..c0b5209 100644 --- a/DATA-LICENSES.md +++ b/DATA-LICENSES.md @@ -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` | | `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` | -| `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/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` | diff --git a/README.md b/README.md index a128688..10b1e6a 100644 --- a/README.md +++ b/README.md @@ -801,45 +801,50 @@ the Development section below, and who ships a register the four above then draw ## 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 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 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 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. -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; 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. **Reproducible** — seed in, same stream out; no builtin reads a clock. -7. **Zero dependencies** — standard library only. -8. **Docs index the grammar** — every syntax feature is a heading; every example +6. **Data lives in JSON** — a builtin only for what data can't express. +7. **Reproducible** — seed in, same stream out; no builtin reads a clock. +8. **Zero dependencies** — standard library only. +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. -9. **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 - noise against a test's own runtime. -10. **Data is sourced, or on its way there** — a shipped fact, a name, place, +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 + noise against a test's own runtime. +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 [`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 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 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 timestamps before anything domain-specific, and a catalogue serving one niche 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, 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 tests nothing; the caller who needs a value that can touch nothing asks for it 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 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 @@ -1243,7 +1248,7 @@ the Development section below, and who ships a register the four above then draw fejkdata has no business making. - **`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 - 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 `Informational` stays the `severity` column, and the code and the keyword hold the 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. - **`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 - 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 `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`.** diff --git a/todo.md b/todo.md index 723f721..0017621 100644 --- a/todo.md +++ b/todo.md @@ -7,7 +7,7 @@ Ordered as the releases that ship it. ### Comprehension, until the panel scores 7.0 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, 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 @@ -50,7 +50,7 @@ This round, in order: ### Data 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. - 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. - 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 - 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 `example.com`, `.net`, `.org`, `.test`, `.example`, `.invalid` and `.localhost` 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`, `plusgiro` and `routing` draw live prefixes. - 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 - 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 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. @@ -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 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 - 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 unisex given names, neither of which falls out of the tables unaided. - 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 +- 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 - 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. - 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 @@ -230,8 +233,11 @@ because pairing a street with its exact postnummer rewrites shipped rows. ## v1.0.0 - 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 - own: v0.1.0 settles the record shape and v0.3.0 is the quiet minor. + with no breaking change, per the README's Versioning table: v0.1.0 settles the + 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 -- 2.52.0 From 976d2e5ac13b332f93a8ba669c9f929a3785a2f5 Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Sun, 20 Sep 2026 23:19:53 +0200 Subject: [PATCH 4/4] Rank understanding the code second, and say why it is not an afterthought --- AGENTS.md | 2 +- DATA-LICENSES.md | 2 +- README.md | 45 +++++++++++++++++++++++---------------------- todo.md | 14 +++++++------- 4 files changed, 32 insertions(+), 31 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 38b547d..e2b0b93 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11,7 +11,7 @@ - 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 `/repos/{owner}/{repo}/commits//status`. -- README goal 14 is gated at 7.0 on the `comprehension-panel` skill, and below it +- README goal 2 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 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 diff --git a/DATA-LICENSES.md b/DATA-LICENSES.md index c0b5209..8da2f33 100644 --- a/DATA-LICENSES.md +++ b/DATA-LICENSES.md @@ -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` | | `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` | -| `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) | — | — | — | +| `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 12) | — | — | — | | `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/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` | diff --git a/README.md b/README.md index 10b1e6a..32464e6 100644 --- a/README.md +++ b/README.md @@ -806,51 +806,52 @@ the Development section below, and who ships a register the four above then draw 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 +2. **Understanding the code is part of the product** — it is a compiler with static + fences behind a small API, it will grow, and the people who extend it will not be + the people who wrote it. So reading cost is judged alongside behaviour: reaching + the unit behind a symptom without asking a person, changing one piece without + holding the rest, names that tell the truth, and a file that stands with no second + document open beside it. A simulated reader panel scores those four, the score is a + ratchet no release lowers, and [`AGENTS.md`](AGENTS.md) says what each pull request + owes it. +3. **Valid by construction** — every value passes the check its real consumer applies; facts that belong together come from one draw, within a value and across categories. -3. **Text means what it says** — a format renders as written; only `{…}` varies, +4. **Text means what it says** — a format renders as written; only `{…}` varies, random characters included (`{digits(3)}`). One spelling per result; the wrong one is a load error naming the right one. -4. **Every mistake is a load error** — `New` rejects the data and `NewTemplate` +5. **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 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. -5. **Zero to a value in one command** — `go install`, then `fejkdata sv_SE.person`: +6. **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; the first custom template needs no escape and no option. -6. **Data lives in JSON** — a builtin only for what data can't express. -7. **Reproducible** — seed in, same stream out; no builtin reads a clock. -8. **Zero dependencies** — standard library only. -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. -10. **Fast enough to be free** — a value renders in about a microsecond and `New` +7. **Data lives in JSON** — a builtin only for what data can't express. +8. **Reproducible** — seed in, same stream out; no builtin reads a clock. +9. **Zero dependencies** — standard library only. +10. **Docs index the grammar** — every syntax feature is a heading; every example + runs under test and shows its output; a rule is stated once. +11. **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 noise against a test's own runtime. -11. **Data is sourced, or on its way there** — a shipped fact, a name, place, +12. **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 [`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 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 only by a rule the script states. -12. **Breadth follows what most systems store** — a category is added in proportion +13. **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 timestamps before anything domain-specific, and a catalogue serving one niche waits behind everything serving many. -13. **Realism is the default, inertness is selectable** — where a value could reach +14. **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, 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 tests nothing; the caller who needs a value that can touch nothing asks for it by name. -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 - 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 - it. A simulated reader panel scores those four, the score is a ratchet no release - lowers, and [`AGENTS.md`](AGENTS.md) says how each pull request answers to it. - ## Decisions - **Options and fields share one namespace.** `format`, `weight`, `repeat`, @@ -1248,7 +1249,7 @@ the Development section below, and who ships a register the four above then draw fejkdata has no business making. - **`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 - goal 2 draws the two as one fact. The canonical spelling losing to the one its domain + goal 3 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 `Informational` stays the `severity` column, and the code and the keyword hold the two selector slots. @@ -1258,7 +1259,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. - **`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 - zone row naming no territory, which is most of them, and goal 11 holds a sourced + zone row naming no territory, which is most of them, and goal 12 holds a sourced 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` carries a currency code, it does not link to `misc.currency`.** diff --git a/todo.md b/todo.md index 0017621..76e2cce 100644 --- a/todo.md +++ b/todo.md @@ -7,7 +7,7 @@ Ordered as the releases that ship it. ### Comprehension, until the panel scores 7.0 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 14. This section is one +bar a security fix and a dependency bump, per README goal 2. This section is one 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 nine-seat one: the round is meant to buy architectural change, and the four-seat @@ -50,7 +50,7 @@ This round, in order: ### Data Shape: T = table, t = template, c = choice. Read every factual list from a register -by a `data-import/` script, as README goal 11 asks. +by a `data-import/` script, as README goal 12 asks. - 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 @@ -63,16 +63,16 @@ by a `data-import/` script, as README goal 11 asks. `municipality` as columns on `geo.SE.address` too. - 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 - the wide set as the default, per goal 13: 17 of the 40 distinct ones shipped today + the wide set as the default, per goal 14: 17 of the 40 distinct ones shipped today 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` provably reach nothing. -- Audit the rest of the shipped set against goal 13 and give each a never-reaching +- Audit the rest of the shipped set against goal 14 and give each a never-reaching path where it lacks one: `phone` draws live PTS and NANP ranges, `bankgiro`, `plusgiro` and `routing` draw live prefixes. - 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 - delegated it, so no resolver answers for it and goal 2 promises otherwise. + delegated it, so no resolver answers for it and goal 3 promises otherwise. - 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 `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 11 asks. 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. - Read `email.local`'s and `username`'s handles from the shipped name tables, which - goal 11 asks for and the hand-written list they use today does not meet. Keep the + goal 12 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 unisex given names, neither of which falls out of the tables unaided. - Decide whether `email.local` and `username` share one list: a reference between @@ -177,7 +177,7 @@ by a `data-import/` script, as README goal 11 asks. 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 - path segment, so `misc/net/tld` is a rename a consumer pays for, and goal 12 promises + path segment, so `misc/net/tld` is a rename a consumer pays for, and goal 13 promises the directory keeps growing. - 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 -- 2.52.0