Files
fejkdata/todo.md
T
lilleman f206a18027
Tests / vet + fmt + tests (pull_request) Successful in 1m24s
Tests / Gitea release from CHANGELOG.md (pull_request) Has been skipped
Gate everything on the comprehension score, and replay the round until it passes
2026-09-20 22:53:14 +02:00

246 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Plan
Ordered as the releases that ship it.
## v0.1.0
### 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
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`.
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
README sections today, and every reader paid for it before the three files read at all.
- Say on the `template` struct which pass fills which field, and that `compileFormat`
runs a second time once `linkTemplateRefs` binds the references: nine of its fields
are written by four other files, and the order lives only in `loadData`'s body.
- State on `rowSet` that it simulates `(*draws).pin` and `rowOf`, and prove the two
agree with a test: the load-time walk reimplements the render-time pinning, nothing
catches them drifting, and the failure is data that loads and then renders a family
that disagrees.
- Put `draws` and its methods in one file: it is declared in `hold.go:262` and all
eight of its methods sit in `family.go`, so a jump to the type lands where none of
the behaviour is.
- Split `hold.go`, `draw.go` and `family.go` so each file holds one phase, the
load-time fences apart from the render-time machinery, changing no logic.
- Move `nodeScope`, `checkScope` and `checkRenders` out of `graph.go` and refresh the
README Layout lines for `graph.go` and `data.go`: the order every load fence runs in
is the load path's spine, and no file name carries it.
- Name the `draw` stem apart: the free `pinned` in `hold.go` is not `(*draws).pinned`
in `family.go`, `compileFormat` is a method on both `*template` and `*table`, and
`draws`, `drawSet`, `drawScope`, `drawWalk`, `drawAt`, `drawKey`, `drawVisit` and
`drawRoute` no longer tell each other apart.
- Spell one fresh draw set one way: `newDrawSet` exists, and `render.go` and `draw.go`
hand-roll `drawSet{unnamed: draws{s: s}}` at three sites; name the lazy-map variant
if the difference is deliberate.
### 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.
- 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
international make and model source; vPIC and Mobility Sweden are national, so they
build `en_US.car` and `sv_SE.car`.
- Add the remaining locale categories: company, phone, finance, vehicle, words.
- Give every shipped category building-block columns, `misc.uuid` → `variant` among
them, and one record shape across the national ids; re-pin the shape.
- Give the address records one column set across countries: `region` and
`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
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
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.
- 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.
- Give a `sv_SE.personnummer` over 100 the `+` separator Skatteverket spells, or stop
drawing birthdates that reach 100: the format hard-codes `-`, and the 1930 floor
makes the oldest draws invalid from 2031.
- Settle `en_US.ip` and `sv_SE.ip`, today byte-identical: either one `misc.ip` as the
decision "`misc` is what every locale shares" asks, or a decision saying why an
address that carries no locale stays per-locale.
- Accept a middle name, and draw a shipped `personnummer` inside a *selected* sex;
both want a draw group sharing its family's pins. Stop the conflict error naming a
rewrite that returns a different value where the read it conflicts with sits inside
another category, and report a struct column's draw conflict with the path spelling
a tag takes.
- Let `geo.SE.locality[Lund].address` descend from a selected row into the template
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
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
shipped categories breaks a consumer once tagged, so it rides a 0.(x+1).0 after that.
`misc` (locale-neutral)
| Category | Shape | Source | Licence |
|---|---|---|---|
| `ip` v4 documentation ranges, private, CIDR; `ipv6` `2001:db8::/32`; `mac` locally administered | t | RFC 5737, 1918, 9637 | facts |
| `creditcard` per network: IIN, length, CVV, expiry | T+t | network rules, `{luhn()}` | facts |
| `bic`, `isin`, `cusip` | t | structure rules | facts |
| `ean`, `upc`, `gtin`, `isbn`, `issn`, `imei`, `asin`, `sku` | t | check-digit rules, GS1 demo prefix 952 | facts |
| `product` name, adjective, material, department, `garmentsize` | T/c | LLM-written lists | — |
| `airport` IATA, ICAO, territory, municipality; `airline`; `aircraft`; `flight`, `seat`, `pnr` | T+t | OurAirports, Wikidata | public domain, CC0 |
| `element`, `unit`, `planet` | T | PubChem, BIPM, NASA | public domain, CC BY 4.0 |
| `animal` by class, `plant` | T | Wikidata | CC0 |
| `bloodtype` weighted (global) | c | AABB | facts |
| `color` named, hex, rgb, hsl, cmyk | T+t | CSS Color 4, XKCD | W3C, CC0 |
| `programminglanguage`, `os`, `browser`, `database` column/type/engine, `fileext` | T/c | Linguist, curated | MIT |
| `commit` message, branch, `sha` | t | LLM-written, `{hex(40)}` | — |
| `password`, `hash`, `jwt`, `slug`, `hostname`, `avatar`, `placeholderimage` | t | shapes | — |
| `book` title, author; `genre`; `instrument`; `dish`, `ingredient` | T | Gutenberg catalog, MusicBrainz, USDA | CC0 |
| `lorem`, `hacker`, `hipster`, `catchphrase`, `buzzword`, `quote` | T/c | lorem ipsum, LLM-written | — |
| `direction`, `continent`, `ulid` | c/t | — | — |
`sv_SE` ([source research](docs/research/research-sources-se.md))
| Category | Shape | Source | Licence |
|---|---|---|---|
| `person` title, birthdate, age, blood type weighted | t | geblod.nu distribution | facts |
| `organisationsnummer` by form, `vat` | t | Bolagsverket group digits, Luhn, `SE…01` | facts |
| `company` name patterns, legal form weighted | t | Bolagsverket registrations 2025 | CC BY 2.5 SE |
| `sni` industry codes | T | SCB SNI 2025 | "Källa: SCB" |
| `ssyk` occupations | T | SCB SSYK 2012 | "Källa: SCB" |
| `phone` mobile, fixed per area code, E.164 | T+t | PTS numbering plan 2024 | facts |
| `bankgiro`, `plusgiro`, `bankaccount` clearing + Luhn/mod-11 | T+t | Bankinfrastruktur CSV, Bankgirot rules | facts |
| `licenseplate` `ABC 123`, `ABC 12A`, blocked combinations | t | Transportstyrelsen | facts |
| `car` make, model weighted by registrations | T | Mobility Sweden 2025 | cite |
| `word` noun, verb, adjective, adverb; `sentence` | T+t | SALDO | CC BY 4.0 |
| month and weekday names, `holiday` | t+T | CLDR sv, lag 1989:253 | Unicode |
| `territory` localised names keyed by alpha2 | T | CLDR sv territory names | Unicode |
`en_US` ([source research](docs/research/research-sources-world.md), and `part1`–`part4`)
| Category | Shape | Source | Licence |
|---|---|---|---|
| `ein` valid ranges | t | IRS | facts |
| `company` names, suffix, `naics` | t+T | SEC tickers for patterns, NAICS 2022 | public domain |
| `phone` NANP with valid NPA/NXX | t | NANPA rules | facts |
| `routing` ABA with check, `bankaccount` | t | Fed prefix ranges | facts |
| `licenseplate` per state | T | hand-authored patterns | facts |
| `car` make, model | T | NHTSA vPIC | public domain |
| `word`, `sentence`, `paragraph` | T+t | Moby POS or WordNet | public domain / WordNet |
| month and weekday names, `holiday` | t+T | CLDR en | Unicode |
### Builtins the data cannot express
- Add `{isin()}` (Luhn over letters expanded to digits), `{cusip()}`, `{aba()}`
(3-7-1 weights) and `{vin()}` (position 9 over the whole; a sample taking the WMI,
since the check sits mid-string).
- Add `{base64url(n)}` for JWT shapes.
- Add a `unix` layout to `date()` once something needs it.
### Library and CLI
- Name a spelling that works when a row selector misses: `misc.protocol[tcp]`,
`misc.httpmethod[get]` and `misc.territory[se]` all answer "no row … has key or name"
and stop there, where a case-insensitive match could name the row that exists, and a
table with no `name` column could say it selects by key alone. `misc.tld[se]` misses
on the leading dot its keys carry rather than on case, and `misc.loglevel[Error]`
misses although a column carries `Error`, so the near miss is worth naming whatever
shape it takes.
- Let a table column carry a `datatype`, so `--format json` writes
`"safe": true` and `--format sql` a boolean rather than the text `'true'`. Today only
a JSON field takes one, so `misc.httpmethod`'s booleans are typed in Go and text
everywhere else. Typing a shipped column changes what `json` and `sql` write, so the
capability is a minor and applying it to `misc.httpmethod` is a major.
### Open questions to settle
- 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
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
consumer, so it rides a 0.(x+1).0.
- Decide whether `misc.timezone` keeps every zone tzdb names: one added recently,
`Europe/Kyiv` among them, is rejected by a consumer resolving it against older
tzdata, and the population weight makes that zone likelier, not rarer. Today the
README names the action a reader takes instead; narrowing what ships is the
alternative.
- Decide whether `misc.territory.country` is renamed `sovereign`: it holds a code, and
`country` collides with the `misc.country` path it replaced. A rename after v0.1.0
breaks a consumer, so it rides a 0.(x+1).0.
- Decide whether `parent: territory` stays, given a `--data-path` override of
`misc.territory` now fails `New` unless `misc.timezone` is overridden with it.
### Release
- Move the README's Decisions section to `docs/decisions.md`, leaving a one-line index
of the titles in `AGENTS.md`, and drop the `AGENTS.md` line pointing decisions at the
README. Carry the timezone weight's premise in with it: weighting by GeoNames city
population moved 300 seeded draws of `misc.territory[US].timezone` from 44 landing on
the four zones most Americans live in to 278, and dropped `America/Indiana/Petersburg`
(pop. 2,400) from 17 draws to 0.
- Rewrite `CHANGELOG.md`'s `[Unreleased]` as what v0.1.0 holds: nothing has shipped, so
"no longer paths", "where it used to fail" and "where it used to be an empty string"
describe versions no reader can have installed.
- Ship prebuilt binaries so the CLI needs no Go: GoReleaser attaching them to the Gitea
release the tag workflow publishes, a container image, Homebrew and Scoop. A checkout
build prints `devel` for `--version`; the binaries carry the stamped tag.
## v0.2.0
- Ship the full registers as packs, each a Go module with its own `embed.FS` and a zip
for `--data-path`: every US place of 10,000 and more streets per locality, built by
`--min-population` and `--streets-per-locality`. The default embed stays under ~1 MB
per country and `New` under ~50 ms.
- Add the locales nb_NO, da_DK, fi_FI, de_DE, en_GB, nl_NL, fr_FR and es_ES, with
person, address, phone, national id, company and date names each, and the `geo/`
trees NO, DK, FI, NL, FR, AU, CA, ES, GB and DE their `address` reads by reference;
AU and CA get a tree with no locale of their own.
- Add `{btc()}` and `{eth()}`, which need sha256 and keccak for Base58Check and EIP-55.
- Pair a street with its exact postnummer, which needs an application to Lantmäteriet;
today a street goes to the nearest postal code centroid. It rewrites shipped rows, so
it is a major once 1.0 is cut and a minor before that.
## v0.3.0
Names no items yet, so planning it is a chunk of its own: it takes the additive work
that lands after v0.2.0, and it has to add something, since a minor only adds. Its job
is to be the release with no breaking change that v1.0.0 waits on — v0.2.0 cannot be,
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.
## Not release-bound
- Stop `/cache` collecting root-owned files, which today every command documented
without `--user` leaves for the next `--user` one to trip over, and which the README
answers with a chown a reader has to repeat. Put `--user` on all of them, or give the
`x-go` anchor a `user:` — that one needs a mechanism, since Compose interpolates from
the process environment and neither `UID` nor `GID` is exported there, so
`user: "${UID}:${GID}"` resolves to `":"`.
- Publish a homepage with an in-browser generator: the library compiled to WebAssembly,
so visitors generate as much data as they like in their own browser.