Answer prose and product-owner round 1: item 81 covers NaN too, the seed decision folds into goal 9, and each decision names its goal

This commit is contained in:
2026-10-04 11:58:50 +02:00
committed by Lillem4n
parent fa49e8ad2b
commit 9cb0ed32d3
4 changed files with 10 additions and 19 deletions
-1
View File
@@ -47,7 +47,6 @@ In [docs/decisions.md](docs/decisions.md):
- A bare reference draws each time; a reference path is held - A bare reference draws each time; a reference path is held
- Reference sigils follow the filesystem - Reference sigils follow the filesystem
- A change to what exists is a major; a minor only adds - A change to what exists is a major; a minor only adds
- Seeded output is promised within one version
- An error is a contract by what it names, not its bytes - An error is a contract by what it names, not its bytes
- A load reports every mistake at once - A load reports every mistake at once
- Formats are checked after all data is loaded, so their errors name the category - Formats are checked after all data is loaded, so their errors name the category
+1 -1
View File
@@ -293,7 +293,7 @@ ok, err := fejkdata.IsTemplate(arg) // an inline template by its shape, el
| Option | | | Option | |
|--------|--| |--------|--|
| `WithSeed(n)` | same seed, same data: identical sequence | | `WithSeed(n)` | same seed, version and data: identical sequence |
| `WithDataPath(dir)` | layer a directory; repeat to layer several, the last wins a clash | | `WithDataPath(dir)` | layer a directory; repeat to layer several, the last wins a clash |
| `WithDataFS(fsys)` | layer an `fs.FS`, such as your own `embed.FS` | | `WithDataFS(fsys)` | layer an `fs.FS`, such as your own `embed.FS` |
| `WithoutShippedData()` | load only what you give | | `WithoutShippedData()` | load only what you give |
+5 -13
View File
@@ -112,7 +112,7 @@ and `regexp.Match`, not two spellings of one result.
2026-09-02, Lilleman auf Larv. 2026-09-02, Lilleman auf Larv.
A directory a machine happens to have would make `--seed 42` machine-dependent. Data A directory a machine happens to have would make `--seed 42` machine-dependent. Data
still lives in `data/` as JSON; `--data-path` layers over it. still lives in `data/`; `--data-path` layers over it.
`todo.md` item 77 revises it: a library imports the shipped data as Go modules. `todo.md` item 77 revises it: a library imports the shipped data as Go modules.
@@ -169,14 +169,6 @@ whole migration: a fence rejects one spelling with one replacement, so the fix i
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
release instead. Before `v1.0.0` a minor carries what a major would. release instead. Before `v1.0.0` a minor carries what a major would.
## Seeded output is promised within one version
2026-09-16, Lilleman auf Larv.
Any edit to a category shifts its stream and everything drawn after it, so a promise
across versions would freeze every shipped list; a fixture is re-pinned on a bump, as
this repo's own are.
## An error is a contract by what it names, not its bytes ## An error is a contract by what it names, not its bytes
2026-09-16, Lilleman auf Larv. 2026-09-16, Lilleman auf Larv.
@@ -263,8 +255,8 @@ assumes a 64-bit int; on a 32-bit target it could overflow and panic.
load error; the fold stops where an operand varies, so `a/(b*c)` with `b` fixed at `0` load error; the fold stops where an operand varies, so `a/(b*c)` with `b` fixed at `0`
and `c` varying loads and prints `Inf` every draw — catching it needs zero-absorbing and `c` varying loads and prints `Inf` every draw — catching it needs zero-absorbing
algebra for a shape nobody writes. A [typed column](../README.md#datatype) bounds its operands algebra for a shape nobody writes. A [typed column](../README.md#datatype) bounds its operands
instead and refuses a divisor it cannot keep from zero. `Inf` in a string column works instead and refuses a divisor it cannot keep from zero. `Inf` and `NaN` in a string column
against goal 6.1 until `todo.md` item 81 refuses it there too. work against goals 6.1 and 4 until `todo.md` item 81 refuses them there too.
## In data, a default written out and a constant spelled as a sample are load errors ## In data, a default written out and a constant spelled as a sample are load errors
@@ -465,13 +457,13 @@ The benchmark suite (the README's Development) reports time for a human, not as
## Rows live in a TSV, the shape in JSON ## Rows live in a TSV, the shape in JSON
2026-09-17, Lilleman auf Larv. 2026-09-17, Lilleman auf Larv. Goals 8 and 12.
`New` allocates once per node, so a register of thirty thousand rows written as JSON `New` allocates once per node, so a register of thirty thousand rows written as JSON
objects would cost it a second; a TSV is one allocation whose cells are substrings, and objects would cost it a second; a TSV is one allocation whose cells are substrings, and
the JSON says only how a row is composed. The TSV sits beside its category file, named the JSON says only how a row is composed. The TSV sits beside its category file, named
by `rows`, so a data directory stays a directory of categories, and one nothing names is by `rows`, so a data directory stays a directory of categories, and one nothing names is
a load error rather than a file silently ignored. a load error.
## A selector is bracketed, and a dot inside it is literal ## A selector is bracketed, and a dot inside it is literal
+4 -4
View File
@@ -70,7 +70,7 @@
| 71 | 0.1.0 | | **Accept a name as a `calc` operand, so `{calc(n * 2)}` computes from the pick `{n}` prints.** | 3 | 4 | 5 | 7 | 5.3 | 17.2 | | 71 | 0.1.0 | | **Accept a name as a `calc` operand, so `{calc(n * 2)}` computes from the pick `{n}` prints.** | 3 | 4 | 5 | 7 | 5.3 | 17.2 |
| 79 | 0.1.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 | 12 | 13.7 | | 79 | 0.1.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 | 12 | 13.7 |
| 58 | 0.2.0 | | **Ship prebuilt binaries, a container image, and packages for Homebrew, Scoop and the biggest Linux package managers, so the CLI needs no Go.** | 3 | 7 | 8 | 9 | 1.1, 7 | 29.2 | | 58 | 0.2.0 | | **Ship prebuilt binaries, a container image, and packages for Homebrew, Scoop and the biggest Linux package managers, so the CLI needs no Go.** | 3 | 7 | 8 | 9 | 1.1, 7 | 29.2 |
| 81 | 0.2.0 | decision | **Refuse at load every `calc` divisor not proven nonzero, in a string column too.** | 4 | 4 | 6 | 8 | 6.1, 4 | 20.6 | | 81 | 0.2.0 | decision | **Refuse at load every `calc` operand not proven numeric and every divisor not proven nonzero, in a string column too.** | 4 | 4 | 6 | 8 | 6.1, 4 | 20.6 |
| 36 | 0.2.0 | | **Report every mistake a load finds in one error, as the decision "A load reports every mistake at once" states.** | 5 | 6 | 7 | 8 | 6 | 19.5 | | 36 | 0.2.0 | | **Report every mistake a load finds in one error, as the decision "A load reports every mistake at once" states.** | 5 | 6 | 7 | 8 | 6 | 19.5 |
| 41 | 0.2.0 | | **Key every table by one key column, as the decision "A table selects by one key column, a code, never a free-form name" states.** | 6 | 7 | 7 | 8 | 5.7 | 19.1 | | 41 | 0.2.0 | | **Key every table by one key column, as the decision "A table selects by one key column, a code, never a free-form name" states.** | 6 | 7 | 7 | 8 | 5.7 | 19.1 |
| 52 | 0.2.0 | | **Name the file a link error comes from beside its category path, `sub.x (/d/a/sub/x.json): …`.** | 1 | 2 | 5 | 7 | 6 | 19.0 | | 52 | 0.2.0 | | **Name the file a link error comes from beside its category path, `sub.x (/d/a/sub/x.json): …`.** | 1 | 2 | 5 | 7 | 6 | 19.0 |
@@ -135,7 +135,7 @@
### 77. Split the shipped data into Go modules per locale and country, which a library imports by choice, and embed every one in the CLI. ### 77. Split the shipped data into Go modules per locale and country, which a library imports by choice, and embed every one in the CLI.
The CLI binary carries every module and may grow to hundreds of MB; a library imports only what it uses, as it imports any dependency, and nothing is fetched at run time. Goal 2 says what ships where. The maintainer decided on 2026-10-04: one module per locale, one per country's `geo/` tree and one for `misc`; and a library passes a module to `New`, `New(WithData(svse.Data))`, with no registry a module's import fills, per the technical principles' dependency injection and no package globals. Before the module API ships, a panel of the README's audience personas tries pulling in data with it. The CLI binary carries every module and may grow to hundreds of MB; a library imports only what it uses, as it imports any dependency, and nothing is fetched at run time. Goal 2 says what ships where. The maintainer decided on 2026-10-04: one module per locale, one per country's `geo/` tree and one for `misc`; and a module registers nothing when imported: the library passes it to `New`, as in `New(WithData(svse.Data))`, per the technical principles' dependency injection and no package globals. The entry for `docs/decisions.md` is written when this ships. Before the module API ships, a panel of the README's audience personas tries pulling in data with it.
### 78. Ship 10% of every place's streets, at least 10, and 10% of all US places drawn by population, each place weighted by population. ### 78. Ship 10% of every place's streets, at least 10, and 10% of all US places drawn by population, each place weighted by population.
@@ -262,9 +262,9 @@ The decision "With only the shipped set, a category loads on the first call reac
GoReleaser attaches the binaries to the release the tag workflow publishes, and builds deb and rpm packages, an Alpine APK and an AUR package beside Homebrew and Scoop. A checkout build prints `devel` for `--version`; the binaries carry the stamped tag. v0.1.0 ships first, so it can be tested before it is packaged. GoReleaser attaches the binaries to the release the tag workflow publishes, and builds deb and rpm packages, an Alpine APK and an AUR package beside Homebrew and Scoop. A checkout build prints `devel` for `--version`; the binaries carry the stamped tag. v0.1.0 ships first, so it can be tested before it is packaged.
### 81. Refuse at load every `calc` divisor not proven nonzero, in a string column too. ### 81. Refuse at load every `calc` operand not proven numeric and every divisor not proven nonzero, in a string column too.
The decision "A constant zero divisor is a load error; in a string column a divisor that is not constant prints `Inf`" lets `{calc(a/(b*c))}` with `b` fixed at `"0"` write `Inf` into every row, against goal 6.1; `valueproof.go` already proves a typed column's divisor nonzero. Revise the decision when this lands. The decision "A constant zero divisor is a load error; in a string column a divisor that is not constant prints `Inf`" lets `{calc(a/(b*c))}` with `b` fixed at `"0"` write `Inf` into every row, and an operand that is sometimes not a number prints `NaN`, against goals 6.1 and 4; `valueproof.go` already proves a typed column's divisor nonzero.
### 36. Report every mistake a load finds in one error, as the decision "A load reports every mistake at once" states. ### 36. Report every mistake a load finds in one error, as the decision "A load reports every mistake at once" states.