diff --git a/AGENTS.md b/AGENTS.md index a5c182e..57c2f88 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -71,7 +71,7 @@ In [docs/decisions.md](docs/decisions.md): - A selector is bracketed, and a dot inside it is literal - `parent` names the link column and the table alike - After a row, a path names a column or a linked table -- Every reference path into one family selects the same rows, per render and group +- A selected row is fixed, not drawn, and an unnamed read beside it is refused - 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 diff --git a/README.md b/README.md index 28c288d..cdf4b8d 100644 --- a/README.md +++ b/README.md @@ -823,9 +823,12 @@ the Development section below, and who ships a register the four above then draw 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. -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. **Templates are intuitive, and text means what it says** — a template does what + its writer expects on first reading. A format renders as written; only `{…}` + varies, random characters included (`{digits(3)}`), and a selected row, `[SE]`, + is that row wherever it is written. Where a reader could expect two outputs, the + template is a load error naming a spelling for each. One spelling per result; the + wrong one is a load error naming the right one. 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 diff --git a/docs/decisions.md b/docs/decisions.md index dd0f0d4..79f24fa 100644 --- a/docs/decisions.md +++ b/docs/decisions.md @@ -359,14 +359,22 @@ folder or another column name would be asking for a second spelling. today; admitting it later is additive, since a refused spelling gains a meaning and no accepted one changes, so the door stays open for the address records the plan describes. -## Every reference path into one family selects the same rows, per render and group +## A selected row is fixed, not drawn, and an unnamed read beside it is refused -A selector pins rows for the render, and a read that draws freely before it could pin a -row the selector contradicts, so accepting both would make the result depend on which -token rendered first. Requiring one selection per family per group is checkable at load -with no data lookup beyond the selectors themselves, and the error names the rewrite. -Two selectors naming one row by key and by name compare equal, since the load check -resolves them. +Decided 2026-09-27 by the maintainer, for goal 4; valid while a selector names exactly one row. + +- Selected rows never conflict: `{/misc.territory[SE].capital} / {/misc.territory[FI].capital}` + renders `Stockholm / Helsinki`, and so may two items of one choice. +- What a path draws beneath a selected row is one draw per selection, shared by every + path through it: `{/geo.SE.region[12].locality.name}` twice names one locality. +- A read naming no row of a table whose family a selection in the render and group + names is refused, naming the selected path and a `drawGroup`: beside + `{/misc.territory[SE].capital}`, a writer reading `{/misc.territory.currency}` expects + `SEK`, and `Stockholm pays in EUR` would pass review. It stays refused beside two + selections, since adding `[FI]` to that template would otherwise make it load. + +Checked against three simulated template writers from the Audience, who agreed on each +case but the last, where two expected a render and all three accepted the refusal. ## A parent row with no child row is a load error @@ -409,8 +417,7 @@ row, and whatever they reach, do meet, and so does the format beside them. Two r meet unless they sit under different rows of one pinned table; pinning a row pins its ancestors too, so rows under different parents are alternatives as well. A table read whole draws its row apart from every pin, so the rows of one whole read are -alternatives only to each other. A choice's items are not alternatives: two items -selecting different rows of one family are refused. +alternatives only to each other. ## A table never reaches its own family, by any route diff --git a/family.go b/family.go index 22477a7..e870057 100644 --- a/family.go +++ b/family.go @@ -84,7 +84,6 @@ func (r *tableRead) selected(t *table) (tableSel, bool) { // read one consistent draw: a table rendered whole beside a path into the family, // a table one read draws that another pins, and two reads pinning different rows. // The reads come sorted by group and path, so which pair is reported does not vary. -// docs/decisions.md#every-reference-path-into-one-family-selects-the-same-rows-per-render-and-group func checkFamilies(reads []pathRead) error { for i, r := range reads { if r.tr == nil { diff --git a/todo.md b/todo.md index 5a91cc3..9f8553b 100644 --- a/todo.md +++ b/todo.md @@ -47,11 +47,9 @@ This round, in order: where `NewTemplate` and `NewRecordTemplate` do not, and `List` claims to be every path `Fake` accepts, which a selector is too. Delete the dead `table.descends` and the redundant `string(key)` in `checkNoRepeatedItem`. -- Keep only the standing choice in the decision "The rows of a table are alternatives", - a choice's items refused as alternatives, and give it the goal it serves: the rest - defines `alternatives`, which its comment in `family.go` already does, and the README's - "which pairs are weighed against each other" sends a reader to the log for that - definition. +- Delete the decision "The rows of a table are alternatives": it defines `alternatives`, + which its comment in `family.go` already does, and the README's "which pairs are + weighed against each other" sends a reader to the log for that definition. - Run the nine-seat panel again and file what it names here. ### Data @@ -59,6 +57,8 @@ This round, in order: Shape: T = table, t = template, c = choice. Read every factual list from a register by a `data-import/` script, as README goal 12 asks. +- Strip the whitespace `data-import/territory.py` copies from its register: + `misc.territory[CW].capital` renders ` Willemstad`, with a leading space. - Place xlsx cells by their `r` reference in `data-import/xlsx.py`: a sheet omitting an empty cell shifts every later column left. - Spell `misc.creditcard`'s digit runs `{digits(n)}`, and refuse a repeat over a lone @@ -171,6 +171,13 @@ by a `data-import/` script, as README goal 12 asks. ### Library and CLI +- Render selected rows as the decision "A selected row is fixed, not drawn, and an + unnamed read beside it is refused" states: `New` refuses + `{/misc.territory[SE].capital} / {/misc.territory[FI].capital}` today, and a choice + whose items select different rows. Have the refusal of an unnamed read name a + selected path that loads: beside `{/geo.SE.locality[Lund].name}`, + `{/geo.SE.municipality.name}` names none today, and the one that holds selects from + the top, `{/geo.SE.municipality[Lund].name}`. - Report the same error every load for a table with two bad options, and for a folder with two unnamed rows files: `readTableOptions` and `loadDir` return on the first in Go's map order. @@ -192,9 +199,6 @@ by a `data-import/` script, as README goal 12 asks. error names the category and the two columns but no row, so the author greps a register-sized file for the cell — and "name the fields you want instead" rewrites a cell that is not the one to fix. -- Have the family fence offer only a rewrite that works: where the drawn table's rows select - more than one row of the family, every `write {/terr[NO].name}` it offers fails the same - way, so only the `drawGroup` it also names is left. - Spell a table one way across the family errors: `checkFamilyPair` names `drawn.category`, `pinRow` names `t.path` and `mustRow` panics with `t.category`, so one table is `territory` and `misc.territory`, and the short spelling names no file where two @@ -214,6 +218,10 @@ by a `data-import/` script, as README goal 12 asks. ### Open questions to settle +- Decide whether a path steps from a row up to its parent, so + `{/geo.SE.locality[Lund].municipality.name}` reads Lund's municipality: three simulated + template writers all expected it to, per goal 4, and today it fails with "municipality + is a column, and a cell holds no fields". Adding it only accepts a refused spelling. - Decide whether a goal 5 violation joins the comprehension gate's exception list: the `{/sel}|{/sel}` panic waits behind the whole round at 5.9, and `{/geo.SE.locality}|{/geo.SE.municipality}` mispairs the shipped data meanwhile, though a