Make great documentation goal 1.2, and plan the README's reorganisation and the nested-template gaps #33

Open
lilleman wants to merge 966 commits from worktree-todo-relative-dates-exact-counts into main
3 changed files with 33 additions and 56 deletions
Showing only changes of commit 4930a2ac8d - Show all commits
+2 -3
View File
@@ -42,7 +42,7 @@ In [docs/decisions.md](docs/decisions.md):
- A struct tag is a template by its shape - A struct tag is a template by its shape
- The CLI renders exactly the template on its stdin, and adds nothing - The CLI renders exactly the template on its stdin, and adds nothing
- A template that does not compile is misuse (exit 2), including a reference that resolves to nothing, save a lone reference under the CLI's `--format` until item 129 - A template that does not compile is misuse (exit 2), including a reference that resolves to nothing, save a lone reference under the CLI's `--format` until item 129
- `NewTemplate` rejects a padded JSON template, and the CLI's stdin drops the whitespace around one - Whitespace around a JSON template is dropped, in `NewTemplate` and on stdin
- `FakeTemplate` and `NewTemplate` both stay - `FakeTemplate` and `NewTemplate` both stay
- The shipped data is embedded, not discovered - The shipped data is embedded, not discovered
- With only the shipped set, a category loads on the first call reaching it; beside a `--data-path`, every category loads in `New` - With only the shipped set, a category loads on the first call reaching it; beside a `--data-path`, every category loads in `New`
@@ -59,7 +59,7 @@ In [docs/decisions.md](docs/decisions.md):
- The repeat cap bounds renders, not bytes - The repeat cap bounds renders, not bytes
- 64-bit targets only - 64-bit targets only
- A constant zero divisor is a load error; in a string column a divisor that is not constant prints `Inf` - A constant zero divisor is a load error; in a string column a divisor that is not constant prints `Inf`
- In data, a default written out and a constant spelled as a sample are load errors - In data, a constant spelled as a sample is a load error
- Samples say what they emit, transforms what they do - Samples say what they emit, transforms what they do
- A record is a template seen as columns; a Go struct is the one second schema - A record is a template seen as columns; a Go struct is the one second schema
- A struct's records follow Go's field access, and compile on first use - A struct's records follow Go's field access, and compile on first use
@@ -81,7 +81,6 @@ In [docs/decisions.md](docs/decisions.md):
- `..` steps up to the parent row, and a step down after it draws afresh, or once per name's pick - `..` steps up to the parent row, and a step down after it draws afresh, or once per name's pick
- A table selects by one key column, a code, never a free-form name - A table selects by one key column, a code, never a free-form name
- A parent row with no child row is a load error - A parent row with no child row is a load error
- The choice-of-rows fence guards a data file's root, and requires string fields
- A table is a record of string columns - A table is a record of string columns
- The key map is built at load, the rest on first draw - The key map is built at load, the rest on first draw
- Two categories may name one TSV - Two categories may name one TSV
+22 -39
View File
@@ -65,14 +65,10 @@ can never collide with any of those spellings, and the leading `[` or `"` is gat
valid JSON so a stray copied bracket never swallows a tag — it names nothing, and says valid JSON so a stray copied bracket never swallows a tag — it names nothing, and says
so. Reserving the characters whole — though only a leading one so. Reserving the characters whole — though only a leading one
could collide — keeps one simple name rule instead of a leading-position special case. could collide — keeps one simple name rule instead of a leading-position special case.
The JSON string is what makes the library's own advice reachable: the error for an A JSON string stays a template even where its bare text renders alike, `"x {/a}"` beside
object holding only a format names `"…"`, and that spelling has to work where it is `x {/a}`: its escapes put a tab or a newline on one `echo` line. A folder-relative `{.name}` or `{..name}` is refused naming
printed. On stdin and in `NewTemplate`, `"x {/a}"` and `x {/a}` render alike, and the `{/name}`, since an inline template sits in no folder. `IsTemplate` exports the rule, so
maintainer kept the JSON string on 2026-10-07, so goal 5.7 does not refuse it: its escapes, struct tags and any other caller read one.
`\t` and `\n`, carry what bare text cannot. A struct tag of one reference alone,
`{/users}`, is refused naming the path `users`: both render the same text, and only the
path names a record. A folder-relative `{.name}` or `{..name}` is refused naming
`{/name}`, since an inline template sits in no folder. `IsTemplate` exports the rule, so struct tags and any other caller read one.
## The CLI renders exactly the template on its stdin, and adds nothing ## The CLI renders exactly the template on its stdin, and adds nothing
@@ -86,9 +82,9 @@ bench of the README's personas picked this on 2026-10-07 over dropping a newline
adding one: a rule a user states in one sentence, at the cost of `printf` or a adding one: a rule a user states in one sentence, at the cost of `printf` or a
`--separator` now and then. `--separator` now and then.
A JSON template is its JSON: the maintainer ruled the whitespace around it no part of the A JSON template is its JSON, so the whitespace around it is no part of the template, per
template, so goal 5.7 does not refuse it on stdin, while `NewTemplate` still refuses a the decision "Whitespace around a JSON template is dropped, in `NewTemplate` and on
padded one. Stdin holding only whitespace is misuse, since an unset variable sends just a stdin". Stdin holding only whitespace is misuse, since an unset variable sends just a
newline. newline.
A lone reference, `{/users}` or `"{/users}"`, names the record `users` under `--format`, A lone reference, `{/users}` or `"{/users}"`, names the record `users` under `--format`,
@@ -110,14 +106,14 @@ The whole template is the spelling under test, and `NewTemplate` compiles, links
validates as one step. Under the CLI's `--format`, a lone reference to nothing exits 1 validates as one step. Under the CLI's `--format`, a lone reference to nothing exits 1
until item 129: it reads a path, and only the data is absent. until item 129: it reads a path, and only the data is absent.
## `NewTemplate` rejects a padded JSON template, and the CLI's stdin drops the whitespace around one ## Whitespace around a JSON template is dropped, in `NewTemplate` and on stdin
2026-09-03, Lilleman auf Larv; the CLI's stdin 2026-10-07. Serves goal 5.7. 2026-10-07, Lilleman auf Larv. Applies KISS.
Padding is the one place the two readings disagree — a format string renders it, JSON Padding is where the two readings disagree: a format string renders it, JSON drops it. A
drops it — so `NewTemplate` names the spelling that renders rather than silently template that parses as JSON is its JSON, so its padding is dropped, as `encoding/json`
choosing. On stdin the CLI drops it, per the decision "The CLI renders exactly the drops it. Goal 5.7 refuses only a spelling that suggests a mistake, and padding around
template on its stdin, and adds nothing". JSON suggests none.
## `FakeTemplate` and `NewTemplate` both stay ## `FakeTemplate` and `NewTemplate` both stay
@@ -169,10 +165,6 @@ from the one pick a name keeps.
- `{x as n}` binds a reference, or a field of the template binding it or a path into one, - `{x as n}` binds a reference, or a field of the template binding it or a path into one,
`{place as p}`: an inline template, and a choice of rows inside one category, have no reference to `{place as p}`: an inline template, and a choice of rows inside one category, have no reference to
bind, and goal 4.1 holds there too. bind, and goal 4.1 holds there too.
- A name read once is refused where writing what it binds in its place draws the same, and
the error names that spelling (goal 5.7): `{/x as n}{n.y}` is `{/x.y}`. A calc cannot read
a reference or a path, so a calc's one read of a name bound to either is not refused, and
neither is a read inside a nested repeat, which keeps one pick on every line.
Valid while goal 5.2 has each `{…}` make a new pick. Valid while goal 5.2 has each `{…}` make a new pick.
@@ -191,8 +183,8 @@ naming the locale, so a folder renames and copies without editing its references
Data files, the CLI and the Go API are the public API, and a consumer must be able to Data files, the CLI and the Go API are the public API, and a consumer must be able to
take a minor without an edit — so an added column is a major, since it changes the CSV take a minor without an edit — so an added column is a major, since it changes the CSV
header and the `INSERT` column list, as is a removed value, which changes what a fixture header and the `INSERT` column list, as is a removed value, which changes what a fixture
holds, and a new option, which reserves a field name. Goal 5.7's refusals grow by holds, and a new option, which reserves a field name. A new refusal tightens what
tightening, so every fence invalidates some file. Each such release names the rejected loads, so every new fence invalidates some file. Each such release names the rejected
spelling and its replacement in the changelog and in the load error, and that is the spelling and its replacement in the changelog and in the load error, and that is the
whole migration: a fence rejects one spelling with one replacement, so the fix is local whole migration: a fence rejects one spelling with one replacement, so the fix is local
to each site. A fence that would need a non-local rewrite ships a converter with its to each site. A fence that would need a non-local rewrite ships a converter with its
@@ -291,14 +283,14 @@ is sometimes not a number loads, and prints `NaN` on each draw where it is not o
and `NaN` in a string column work against goals 6.1 and 4 until `todo.md` item 81 and `NaN` in a string column work against goals 6.1 and 4 until `todo.md` item 81
refuses them there too. refuses them there too.
## In data, a default written out and a constant spelled as a sample are load errors ## In data, a constant spelled as a sample is a load error
2026-09-24, Lilleman auf Larv. 2026-09-24, Lilleman auf Larv; narrowed 2026-10-07. Serves goal 5.7.
`weight: 1`, `repeat: 1`, `separator: ""`, `datatype: "string"`, `int(5,5)`, `int(5,5)` and `float(1,1,2)` draw nothing, which suggests a range typed wrong, so each is
`float(1,1,2)`, `+5` and `05` each spell what a shorter form already spells, so each is rejected naming the constant. A default written out, `weight: 1`, `repeat: 1`,
rejected naming that form. The CLI's numbers follow the shell instead: `--seed 007` and `separator: ""` or `datatype: "string"`, and a number spelled `+5` or `05`, load as the
`--repeat +3` are 7 and 3, as every command line reads them. shorter form, as the CLI's `--seed 007` and `--repeat +3` do.
## Samples say what they emit, transforms what they do ## Samples say what they emit, transforms what they do
@@ -516,15 +508,6 @@ lead to a row at every level below it, or a render could find nothing to draw. T
import script drops or fills such rows; the alternative, falling back to a free draw, import script drops or fills such rows; the alternative, falling back to a free draw,
would break the consistency the link exists for without saying so. would break the consistency the link exists for without saying so.
## The choice-of-rows fence guards a data file's root, and requires string fields
2026-09-17, Lilleman auf Larv.
A table is a category with a TSV beside its file, so only a root choice has the spelling
the fence names; a nested choice of same-shaped templates and an inline one keep
loading. Fields must all be strings because a cell is a string node: a choice whose
items carry a nested choice is not one table but two linked ones.
## A table is a record of string columns ## A table is a record of string columns
2026-09-17, Lilleman auf Larv. 2026-09-17, Lilleman auf Larv.
@@ -865,7 +848,7 @@ Valid while names are read only inside the category binding them.
2026-10-04, Lilleman auf Larv. Serves goal 3 and applies KISS. 2026-10-04, Lilleman auf Larv. Serves goal 3 and applies KISS.
Shipped under the floor by the maintainer's decision of 2026-10-07: the CLI reading its template from stdin, with the scoring run and its ratchet waived for that chunk. Shipped under the floor by the maintainer's decisions of 2026-10-07: the CLI reading its template from stdin, with the scoring run and its ratchet waived for that chunk; and narrowing goal 5.7 to the refusals that catch a mistake, dropping the rest.
Last scoring run, 2026-10-07, on commit ad59967: Navigation 7.00, Locality 5.88, Shape 6.50, Self-sufficiency 6.13, overall 6.38. The nine-seat panel at depth 1, run beside it: Navigation 7.17, Locality 6.06, Shape 6.67, Self-sufficiency 6.56, overall 6.56. Against the runs on ac6158e, the scoring run's overall rose from 6.25 and its Shape from 6.38, while its Self-sufficiency fell from 6.38; the panel's overall held, and its Locality and Self-sufficiency fell by 0.05 each. Locality is lowest again, as at every panel since 2026-09-22. All 13 seats named the named-pick read path hardest: `readField`, `readName`, `readUnder` and `keeps`, with the pick keys `levelKeys` and `addressedKeys` build at load; twelve kept `doc.go`'s vocabulary open beside it. What the two runs found is filed in `todo.md`, and `todo.md` item 153 runs both again. Valid while `AGENTS.md` gates goal 3 at 7.0. Last scoring run, 2026-10-07, on commit ad59967: Navigation 7.00, Locality 5.88, Shape 6.50, Self-sufficiency 6.13, overall 6.38. The nine-seat panel at depth 1, run beside it: Navigation 7.17, Locality 6.06, Shape 6.67, Self-sufficiency 6.56, overall 6.56. Against the runs on ac6158e, the scoring run's overall rose from 6.25 and its Shape from 6.38, while its Self-sufficiency fell from 6.38; the panel's overall held, and its Locality and Self-sufficiency fell by 0.05 each. Locality is lowest again, as at every panel since 2026-09-22. All 13 seats named the named-pick read path hardest: `readField`, `readName`, `readUnder` and `keeps`, with the pick keys `levelKeys` and `addressedKeys` build at load; twelve kept `doc.go`'s vocabulary open beside it. What the two runs found is filed in `todo.md`, and `todo.md` item 153 runs both again. Valid while `AGENTS.md` gates goal 3 at 7.0.
+9 -14
View File
@@ -70,7 +70,7 @@
| 61 | 0.1.0 | | **Add a locale, with its `geo/` tree, for each of the ten most-spoken languages and each Nordic country.** | 4 | 9 | 9 | 10 | 2.1 | 30.8 | | 61 | 0.1.0 | | **Add a locale, with its `geo/` tree, for each of the ten most-spoken languages and each Nordic country.** | 4 | 9 | 9 | 10 | 2.1 | 30.8 |
| 16 | 0.1.0 | | **Add locale categories: company, phone, finance, vehicle, words.** | 3 | 8 | 8 | 9 | 2.2, 15 | 28.1 | | 16 | 0.1.0 | | **Add locale categories: company, phone, finance, vehicle, words.** | 3 | 8 | 8 | 9 | 2.2, 15 | 28.1 |
| 15 | 0.1.0 | | **Add `misc` tables and templates, one row of its detail's table per chunk.** | 3 | 9 | 8 | 8 | 2, 15, 14 | 25.9 | | 15 | 0.1.0 | | **Add `misc` tables and templates, one row of its detail's table per chunk.** | 3 | 9 | 8 | 8 | 2, 15, 14 | 25.9 |
| 129 | 0.1.0 | decision | **Take a template wherever the library renders, so `fake:"{/sv_SE.person.first}"` and `Fake("{/sv_SE.person}")` render, and text with no `{…}` prints as written, as the CLI already does.** | 5 | 8 | 8 | 10 | 5.9, 5.7, 7 | 25.0 | | 129 | 0.1.0 | decision | **Take a template wherever the library renders, so `fake:"{/sv_SE.person.first}"` and `Fake("{/sv_SE.person}")` render, and text with no `{…}` prints as written, as the CLI already does.** | 5 | 8 | 8 | 10 | 5.9, 7 | 25.0 |
| 57 | 0.1.0 | | **Rewrite `CHANGELOG.md`'s `[Unreleased]` as what v0.1.0 holds.** | 1 | 2 | 6 | 6 | 1.1 | 22.5 | | 57 | 0.1.0 | | **Rewrite `CHANGELOG.md`'s `[Unreleased]` as what v0.1.0 holds.** | 1 | 2 | 6 | 6 | 1.1 | 22.5 |
| 96 | 0.1.0 | | **Refuse two reads into one sibling, category or struct category that no name joins, `{place.postal-code} {place.locality}`, showing the spelling for one pick and the one for two.** | 4 | 4 | 7 | 7 | 5.6, 4 | 20.9 | | 96 | 0.1.0 | | **Refuse two reads into one sibling, category or struct category that no name joins, `{place.postal-code} {place.locality}`, showing the spelling for one pick and the one for two.** | 4 | 4 | 7 | 7 | 5.6, 4 | 20.9 |
| 153 | 0.1.0 | decision | **Run the nine-seat comprehension panel and the scoring run again once items 145 to 152 and item 10 have merged, and file what the panel names.** | 1 | 3 | 3 | 9 | 3 | 20.4 | | 153 | 0.1.0 | decision | **Run the nine-seat comprehension panel and the scoring run again once items 145 to 152 and item 10 have merged, and file what the panel names.** | 1 | 3 | 3 | 9 | 3 | 20.4 |
@@ -115,17 +115,15 @@
| 29 | 0.2.0 | | **Let a path go from a selected row into the template beside its family: `geo.US.locality[1714000].address`.** | 4 | 4 | 5 | 6 | 5 | 14.6 | | 29 | 0.2.0 | | **Let a path go from a selected row into the template beside its family: `geo.US.locality[1714000].address`.** | 4 | 4 | 5 | 6 | 5 | 14.6 |
| 42 | 0.2.0 | | **Refuse a struct tag's `datatype` naming the Go type that sets it before proving its values, as the README's Library section promises.** | 2 | 2 | 4 | 6 | 6 | 14.5 | | 42 | 0.2.0 | | **Refuse a struct tag's `datatype` naming the Go type that sets it before proving its values, as the README's Library section promises.** | 2 | 2 | 4 | 6 | 6 | 14.5 |
| 32 | 0.2.0 | | **Add `misc.browser` as the parent of `misc.useragent`, so `misc.browser[Chrome].useragent` resolves.** | 3 | 3 | 4 | 6 | 4.1 | 14.4 | | 32 | 0.2.0 | | **Add `misc.browser` as the parent of `misc.useragent`, so `misc.browser[Chrome].useragent` resolves.** | 3 | 3 | 4 | 6 | 4.1 | 14.4 |
| 27 | 0.2.0 | | **Merge `en_US.ip` and `sv_SE.ip`, today byte-identical, into one `misc.ip`.** | 3 | 2 | 4 | 6 | 5.7 | 14.1 |
| 159 | 0.2.0 | | **Name the quoted spelling where a template that is a bare JSON number, boolean or null is refused, padded or not: `42` names `"42"`.** | 1 | 2 | 3 | 6 | 6, 5.1 | 14.1 | | 159 | 0.2.0 | | **Name the quoted spelling where a template that is a bare JSON number, boolean or null is refused, padded or not: `42` names `"42"`.** | 1 | 2 | 3 | 6 | 6, 5.1 | 14.1 |
| 22 | 0.2.0 | | **Give `url` and `email` a path that draws only domains nobody can register, keeping the wide set as the default.** | 3 | 4 | 7 | 8 | 16 | 14.0 | | 22 | 0.2.0 | | **Give `url` and `email` a path that draws only domains nobody can register, keeping the wide set as the default.** | 3 | 4 | 7 | 8 | 16 | 14.0 |
| 46 | 0.2.0 | | **Report the same error every load for a table with two bad options, and for a folder with two unnamed rows files.** | 2 | 2 | 3 | 7 | 6, 10 | 14.0 | | 46 | 0.2.0 | | **Report the same error every load for a table with two bad options, and for a folder with two unnamed rows files.** | 2 | 2 | 3 | 7 | 6, 10 | 14.0 |
| 158 | 0.2.0 | | **Drop a UTF-8 byte order mark that starts stdin, and say in the README how to stop PowerShell 5.1 sending `Göteborg` as `G?teborg`.** | 2 | 2 | 4 | 5 | 7.2, 5.1 | 13.5 | | 158 | 0.2.0 | | **Drop a UTF-8 byte order mark that starts stdin, and say in the README how to stop PowerShell 5.1 sending `Göteborg` as `G?teborg`.** | 2 | 2 | 4 | 5 | 7.2, 5.1 | 13.5 |
| 79 | 0.2.0 | decision | **Beside a `--data-path`, load in `New` the user's categories, the shipped ones they override or read, and the shipped ones whose reads reach an overridden one; load the rest on first reach.** | 6 | 6 | 7 | 8 | 13 | 12.9 | | 79 | 0.2.0 | decision | **Beside a `--data-path`, load in `New` the user's categories, the shipped ones they override or read, and the shipped ones whose reads reach an overridden one; load the rest on first reach.** | 6 | 6 | 7 | 8 | 13 | 12.9 |
| 27 | 0.2.0 | | **Merge `en_US.ip` and `sv_SE.ip`, today byte-identical, into one `misc.ip`.** | 3 | 2 | 4 | 6 | 8 | 12.3 |
| 107 | 0.2.0 | decision | **Move the template engine into `internal/`, leaving the root the public API and its options.** | 6 | 9 | 3 | 8 | 3.2, 3.4 | 12.2 | | 107 | 0.2.0 | decision | **Move the template engine into `internal/`, leaving the root the public API and its options.** | 6 | 9 | 3 | 8 | 3.2, 3.4 | 12.2 |
| 112 | 0.2.0 | | **Check a calc's field operands where its template resolves, beside its name operands, once item 36 reports every mistake at once.** | 2 | 2 | 1 | 6 | 3.2 | 10.3 | | 112 | 0.2.0 | | **Check a calc's field operands where its template resolves, beside its name operands, once item 36 reports every mistake at once.** | 2 | 2 | 1 | 6 | 3.2 | 10.3 |
| 94 | 0.2.0 | | **Refuse a name whose every read passes one deeper level, naming the binding of that level: `{place as p}{p.geo.town.name} {p.geo.town.zip}` is `{place.geo.town as t}{t.name} {t.zip}`.** | 3 | 3 | 3 | 5 | 5.7 | 10.2 |
| 108 | 0.2.0 | defect | **Name item 26 in the decision "No builtin reads the clock, so a date is bounded by days, never by an age", as the item that ends its conflict with goal 4.** | 1 | 1 | 1 | 4 | 3.4 | 8.0 | | 108 | 0.2.0 | defect | **Name item 26 in the decision "No builtin reads the clock, so a date is bounded by days, never by an age", as the item that ends its conflict with goal 4.** | 1 | 1 | 1 | 4 | 3.4 | 8.0 |
| 14 | 0.3.0 | | **Spell `misc.creditcard`'s digit runs `{digits(n)}`.** | 2 | 2 | 4 | 6 | 5.7 | 15.1 |
| 38 | 0.3.0 | defect | **Compare `calcParser.binary`'s operator as a rune.** | 1 | 1 | 3 | 6 | 6 | 13.8 | | 38 | 0.3.0 | defect | **Compare `calcParser.binary`'s operator as a rune.** | 1 | 1 | 3 | 6 | 6 | 13.8 |
| 45 | 0.3.0 | | **Name the node a selector follows in `childNamed`'s refusal.** | 1 | 1 | 3 | 6 | 6 | 13.8 | | 45 | 0.3.0 | | **Name the node a selector follows in `childNamed`'s refusal.** | 1 | 1 | 3 | 6 | 6 | 13.8 |
| 49 | 0.3.0 | | **Report a CRLF rows file holding only its header as having no rows.** | 1 | 1 | 3 | 6 | 6 | 13.8 | | 49 | 0.3.0 | | **Report a CRLF rows file holding only its header as having no rows.** | 1 | 1 | 3 | 6 | 6 | 13.8 |
@@ -133,17 +131,18 @@
| 39 | 0.3.0 | | **Stop the `columnKinds` suggestion naming a field's own kind or a narrower one.** | 1 | 2 | 3 | 6 | 6 | 13.5 | | 39 | 0.3.0 | | **Stop the `columnKinds` suggestion naming a field's own kind or a narrower one.** | 1 | 2 | 3 | 6 | 6 | 13.5 |
| 51 | 0.3.0 | | **Spell a table one way across the errors that name it.** | 1 | 2 | 3 | 6 | 6 | 13.5 | | 51 | 0.3.0 | | **Spell a table one way across the errors that name it.** | 1 | 2 | 3 | 6 | 6 | 13.5 |
| 115 | 0.3.0 | | **Spell a rows file's line one way in every error, naming the file.** | 1 | 2 | 3 | 6 | 6 | 13.5 | | 115 | 0.3.0 | | **Spell a rows file's line one way in every error, naming the file.** | 1 | 2 | 3 | 6 | 6 | 13.5 |
| 14 | 0.3.0 | | **Spell `misc.creditcard`'s digit runs `{digits(n)}`.** | 2 | 2 | 4 | 6 | 8 | 13.3 |
| 11 | 0.3.0 | | **Test that every `geo` tree holds the five table names and the `address` columns that port across countries.** | 1 | 2 | 3 | 5 | 4 | 13.0 | | 11 | 0.3.0 | | **Test that every `geo` tree holds the five table names and the `address` columns that port across countries.** | 1 | 2 | 3 | 5 | 4 | 13.0 |
| 35 | 0.3.0 | | **Add `{base64url(n)}` for JWT shapes.** | 1 | 2 | 4 | 5 | 8 | 13.0 | | 35 | 0.3.0 | | **Add `{base64url(n)}` for JWT shapes.** | 1 | 2 | 4 | 5 | 8 | 13.0 |
| 40 | 0.3.0 | | **Parse `defaultTable`'s path with the library's grammar.** | 2 | 2 | 3 | 5 | 3.2 | 12.5 |
| 21 | 0.3.0 | | **List `title` in both locales, and `sv_SE`'s `birth-number`, in the README's Data list of what each locale carries.** | 1 | 1 | 4 | 6 | 12 | 12.2 | | 21 | 0.3.0 | | **List `title` in both locales, and `sv_SE`'s `birth-number`, in the README's Data list of what each locale carries.** | 1 | 1 | 4 | 6 | 12 | 12.2 |
| 30 | 0.3.0 | | **Draw `email.local` from `username`, so the two share one handle list.** | 2 | 2 | 3 | 5 | 5.7 | 11.5 |
| 40 | 0.3.0 | | **Parse `defaultTable`'s path with the library's grammar.** | 2 | 2 | 3 | 5 | 5.7 | 11.5 |
| 86 | 0.3.0 | | **Read both `en_US.phone` formats' area codes from one category, as their exchange reads `en_US.phone-exchange`.** | 1 | 2 | 2 | 5 | 3.2 | 11.5 | | 86 | 0.3.0 | | **Read both `en_US.phone` formats' area codes from one category, as their exchange reads `en_US.phone-exchange`.** | 1 | 2 | 2 | 5 | 3.2 | 11.5 |
| 23 | 0.3.0 | | **Give every other shipped category that could reach something real a path that never does.** | 3 | 6 | 6 | 7 | 16 | 11.0 | | 23 | 0.3.0 | | **Give every other shipped category that could reach something real a path that never does.** | 3 | 6 | 6 | 7 | 16 | 11.0 |
| 75 | 0.3.0 | | **Run every README `sh`, `go` and `text` example as a test, and compare each "Renders" line to a seeded render.** | 2 | 6 | 4 | 7 | 12.2 | 10.8 | | 75 | 0.3.0 | | **Run every README `sh`, `go` and `text` example as a test, and compare each "Renders" line to a seeded render.** | 2 | 6 | 4 | 7 | 12.2 | 10.8 |
| 33 | 0.3.0 | | **Group `data/misc` into folders where a group name makes a path easier to guess.** | 4 | 5 | 4 | 5 | 5 | 10.8 | | 33 | 0.3.0 | | **Group `data/misc` into folders where a group name makes a path easier to guess.** | 4 | 5 | 4 | 5 | 5 | 10.8 |
| 47 | 0.3.0 | defect | **Refuse a category naming a hidden rows file, `"rows": ".x.tsv"`, as a rows file that is not there.** | 1 | 1 | 2 | 5 | 6 | 10.2 | | 47 | 0.3.0 | defect | **Refuse a category naming a hidden rows file, `"rows": ".x.tsv"`, as a rows file that is not there.** | 1 | 1 | 2 | 5 | 6 | 10.2 |
| 72 | 0.3.0 | principle | **Fail the merge gate when test coverage falls below the last recorded figure.** | 2 | 3 | 2 | 5 | 3 | 10.2 | | 72 | 0.3.0 | principle | **Fail the merge gate when test coverage falls below the last recorded figure.** | 2 | 3 | 2 | 5 | 3 | 10.2 |
| 30 | 0.3.0 | | **Draw `email.local` from `username`, so the two share one handle list.** | 2 | 2 | 3 | 5 | 8 | 10.0 |
| 95 | 0.3.0 | principle | **Hold a struct's columns and the field each fills in one slice.** | 1 | 2 | 1 | 5 | 3.2 | 9.5 | | 95 | 0.3.0 | principle | **Hold a struct's columns and the field each fills in one slice.** | 1 | 2 | 1 | 5 | 3.2 | 9.5 |
| 116 | 0.3.0 | | **Turn a row index into its rows file's line in one function.** | 1 | 2 | 1 | 5 | 3.2 | 9.5 | | 116 | 0.3.0 | | **Turn a row index into its rows file's line in one function.** | 1 | 2 | 1 | 5 | 3.2 | 9.5 |
| 19 | 0.3.0 | | **Fill the 398 Swedish localities weighted 200 from SCB småorter.** | 2 | 4 | 4 | 6 | 14 | 9.2 | | 19 | 0.3.0 | | **Fill the 398 Swedish localities weighted 200 from SCB småorter.** | 2 | 4 | 4 | 6 | 14 | 9.2 |
@@ -463,18 +462,10 @@ The engine returns column values and the root builds `Record`. Revises the decis
Needs item 36. `checkCalcFields` runs at compile and `checkCalcNames` in `resolveTemplates`, two passes over one rule. Moving the field check there before item 36 would change which of two mistakes in two category files a load reports, since every category compiles before any resolves. Needs item 36. `checkCalcFields` runs at compile and `checkCalcNames` in `resolveTemplates`, two passes over one rule. Moving the field check there before item 36 would change which of two mistakes in two category files a load reports, since every category compiles before any resolves.
### 94. Refuse a name whose every read passes one deeper level, naming the binding of that level: `{place as p}{p.geo.town.name} {p.geo.town.zip}` is `{place.geo.town as t}{t.name} {t.zip}`.
Both spellings load and draw alike, against goal 5.7. Widen the read-once refusal in `namefence.go` to the longest prefix every read of a name shares.
### 108. Name item 26 in the decision "No builtin reads the clock, so a date is bounded by days, never by an age", as the item that ends its conflict with goal 4. ### 108. Name item 26 in the decision "No builtin reads the clock, so a date is bounded by days, never by an age", as the item that ends its conflict with goal 4.
Item 26 revises the decision, but the decision does not point back to it. Item 26 revises the decision, but the decision does not point back to it.
### 14. Spell `misc.creditcard`'s digit runs `{digits(n)}`.
A `"repeat": 14` over `{digits(1)}` draws every 14-digit run with the odds `{digits(14)}` does. Both load, since neither has a part that changes nothing; the shipped data writes the obvious one. Re-pin seeded output in its own commit.
### 38. Compare `calcParser.binary`'s operator as a rune. ### 38. Compare `calcParser.binary`'s operator as a rune.
`byte(p.rs[p.pos])` reads U+012B `ī` as `+`, so `{calc(a ī b)}` compiles as `a + b`. `byte(p.rs[p.pos])` reads U+012B `ī` as `+`, so `{calc(a ī b)}` compiles as `a + b`.
@@ -503,6 +494,10 @@ In `internal/rows`, `Pins.PinRow` names `t.path` and `Pins.MustRow` panics with
Today a cell reads `g.t.b, line 3` (`namedNode.labelIn`), a cell check `t.tsv: line 3, b` (`checkCells`) and a link `t.tsv line 3` (`rows.Table.Link`). A reference cycle found from a table's format through a cell names no line at all: `reference cycle: g.t -> format -> b -> b -> /h -> …`, where the column-to-cell step in `renderEdges` repeats the column name. Today a cell reads `g.t.b, line 3` (`namedNode.labelIn`), a cell check `t.tsv: line 3, b` (`checkCells`) and a link `t.tsv line 3` (`rows.Table.Link`). A reference cycle found from a table's format through a cell names no line at all: `reference cycle: g.t -> format -> b -> b -> /h -> …`, where the column-to-cell step in `renderEdges` repeats the column name.
### 14. Spell `misc.creditcard`'s digit runs `{digits(n)}`.
A `"repeat": 14` over `{digits(1)}` draws every 14-digit run with the odds `{digits(14)}` does. Both load, since neither has a part that changes nothing; the shipped data writes the obvious one. Re-pin seeded output in its own commit.
### 11. Test that every `geo` tree holds the five table names and the `address` columns that port across countries. ### 11. Test that every `geo` tree holds the five table names and the `address` columns that port across countries.
Nothing checks it, and a new country breaks it silently. Nothing checks it, and a new country breaks it silently.