Make goal 4 ask for intuitive templates, and decide a selected row is fixed, not drawn

This commit is contained in:
2026-09-27 15:00:16 +02:00
committed by Lillem4n
parent 538114a926
commit fb7a30e505
5 changed files with 39 additions and 22 deletions
+1 -1
View File
@@ -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
+6 -3
View File
@@ -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
+16 -9
View File
@@ -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
-1
View File
@@ -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 {
+16 -8
View File
@@ -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