docs(adr): state that a hand-written id may carry the -<n> suffix, and keep slugs in the id alphabet (improvise-cq1q.1)

Codex's review of 6e467878. The suffix question followed from two
decided rules (collisions take -<n>; a hand-written id obeys the
generated syntax), so clause 4 now states the id syntax and the question
is deleted. Step 2 says the slug ends in a-z, 0-9 and _ whichever reading
of "alphanumeric" is chosen. The remaining questions are renumbered 1-4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
This commit is contained in:
Claude (adr007-steward)
2026-10-09 09:05:01 -07:00
committed by Edward Langley
parent 6e46787887
commit 2dfe088668
+20 -36
View File
@@ -27,7 +27,7 @@ amendment is approved:
| 12 | a typed name new to a formula edit is resolved against the document at commit | the client resolves it, ids first, and the wire carries only id-form text |
| 12 | the regression test commits the **unedited** text after the concurrent renames | the test edits a non-name token and commits, because a client may pass unedited text as a no-op without resolving any name |
Five questions are open (last section).
Four questions are open (last section).
## Context
@@ -100,7 +100,7 @@ the reservation needs no check in the grammar.
code, the wire, `ViewState` and the browser client spell the virtual categories
`_Index`, `_Dim` and `_Measure` today, and move to the lower-case ids in the re-key
step (clause 11). How the file records what it records today under `_Measure`,
`_Index` and `_Dim` is open question 3.
`_Index` and `_Dim` is open question 2.
- **[Amendment] Records mode's synthetic positions are values, not ids.** The row
coordinate under `_index` and the column coordinate under `_dim` (a column index,
gotcha 1) are values of those virtual categories. They are never persisted or typed,
@@ -198,7 +198,9 @@ thing's id never depends on how it was made. An id is lower case.
pass the `wasm` gate, because `improvise-core` is in the browser bundle.
2. **Replace every character that is not alphanumeric with `_`.** That includes
spaces, tabs and every other whitespace, punctuation and `-`. Whether
"alphanumeric" means ASCII only is open question 2.
"alphanumeric" means ASCII only is open question 1. Whichever it decides, the slug
ends up in `a`–`z`, `0`–`9` and `_`: a Unicode reading needs a further step that
drops or transliterates what is outside that alphabet, and question 1 picks it.
3. **Collapse each run of `_` to one `_`**, whether the underscores came from step 2
or were in the display.
4. **Remove every leading and trailing `_`.** A leading `_` is reserved for virtual
@@ -210,7 +212,9 @@ thing's id never depends on how it was made. An id is lower case.
So a generated id is a lower-case letter followed by letters, digits and single
underscores, never ending in `_`, plus, only when it collided, a `-<n>` suffix; or
`<kind>-<n>`. Whether a hand-written id may carry that suffix is open question 1.
`<kind>-<n>`. The syntax of an id is therefore a slug,
`[a-z][a-z0-9]*(_[a-z0-9]+)*`, optionally followed by `-` and a number; a `-` anywhere
else never occurs.
Examples under the amendment, with "alphanumeric" read as ASCII:
@@ -263,9 +267,11 @@ every data key and reference in that file spells it. So:
- **two identical hand-written ids in one file are refused at load**, even when they
declare different kinds of thing. Renaming one would corrupt the data section, and a
file with a duplicate cannot be resaved safely. The error names both lines.
- **[Amendment] A hand-written id obeys every syntax rule of a generated id**: lower
case, never starting with `_` or a digit, never ending in `_`, no runs of `_`, and no
character slugify would replace. One that does not is refused at load (clause 5).
- **[Amendment] A hand-written id obeys every syntax rule of a generated id**: a slug
(lower case, starting with a letter, single underscores, not ending in `_`),
optionally followed by the `-<n>` suffix. So `east-1` and `item-4`, which every save
writes, load back; `-east`, `east-`, `2024` and `_draft` do not. One that breaks the
syntax is refused at load (clause 5).
**Reuse across a save and reload is accepted.** Retired ids are not persisted. So
remove `East`, save, reload and add `East`, and the new item gets `east` again. An
@@ -366,7 +372,7 @@ lose its axis line to the view's number format, and the new-version arm puts
`=`. For a measure formula it is also the measure's id.
- **For a measure formula, `<target>` is the measure's display**, held on the
`Formula`: `- Profit(profit) = revenue - cost`. How a dimension formula's line spells
its target, and whether the `[_measure]` tag is written, is open question 4.
its target, and whether the `[_measure]` tag is written, is open question 3.
- **The expression is over ids**, spelled through `quote::quote_name`. A reference to
a formula target is the id text of its `ItemHandle`: the item id outside `_Measure`,
the formula's (and measure's) id for a `_Measure` target.
@@ -434,7 +440,7 @@ display that would otherwise read as display plus id:
a reference.
- **[Amendment] Scripts refer to things by id.** A script that names something by its
display fails. A script gets a display only through a dedicated function such as
`display_for(id)`. Which headless entry points count as scripts is open question 5.
`display_for(id)`. Which headless entry points count as scripts is open question 4.
- **A frame cannot address a thing it creates**, because it does not know the id the
host will assign. A create-then-act compound becomes **one command**:
`create-and-switch-view` sends `[CreateView, SwitchView]` today and becomes
@@ -709,29 +715,7 @@ three things:
These are open, and nothing above depends on an answer except where it says so.
### 1. May a hand-written id carry the collision suffix?
**The question.** A hand-written id obeys every syntax rule of a generated id
(clause 4), and slugify turns `-` into `_`, so a slug never contains `-`. But a
generated id that collided carries a `-<n>` suffix (`east-1`), and an empty slug
becomes `<kind>-<n>` (`item-4`). Every save writes those ids into the file, so the
next load reads them as hand-written.
**Why it matters.** If a hand-written id may never contain `-`, the app refuses to load
a file it saved itself.
**Options.**
- **(a)** The syntax of an id is a slug, optionally followed by `-` and a number:
`[a-z][a-z0-9]*(_[a-z0-9]+)*` then optionally `-[0-9]+` (which also covers
`<kind>-<n>`). A `-` anywhere else is refused.
- **(b)** Change the suffix to avoid `-`, for example `east_1`. That collides with a
display such as `East 1`, which also slugs to `east_1`, so the counter must advance
past it.
**Author's recommendation:** (a). It keeps the counter's suffix visibly distinct from
anything a display can slug to.
### 2. Does "alphanumeric" mean ASCII?
### 1. Does "alphanumeric" mean ASCII?
**The question.** Slugify replaces every non-alphanumeric character with `_`. Unicode
counts `é`, `ü` and `日` as alphanumeric, but an id's alphabet is `a`–`z`, `0`–`9`, `_`
@@ -751,7 +735,7 @@ counts `é`, `ü` and `日` as alphanumeric, but an id's alphabet is `a`–`z`,
**Author's recommendation:** (a): it is the simplest reading of "non-alphanumeric
characters are replaced", and it needs no table.
### 3. How does a file record the virtual categories, if virtual ids are never written?
### 2. How does a file record the virtual categories, if virtual ids are never written?
**The question.** Virtual ids are never written to `.improv` (clause 1). But today's
files record three things under the virtual categories (`web/demo.improv` has all of
@@ -777,7 +761,7 @@ way to say which measure a cell holds and where `_Measure` sits.
**Author's recommendation:** (a). The file needs these facts, and a keyword says so
without turning a virtual id into file content.
### 4. How does a dimension formula's line spell its target, and is the `[_measure]` tag written?
### 3. How does a dimension formula's line spell its target, and is the `[_measure]` tag written?
**The question.** A measure formula's line is `- Profit(profit) = revenue - cost`: the
measure's display, then its id (clause 5). A dimension formula (the rare case) has an
@@ -794,9 +778,9 @@ keep omitting `[_measure]`?
**Author's recommendation:** (b), so one position never holds two kinds of thing;
keep omitting `[_measure]`, which also keeps the virtual id out of the file
(question 3).
(question 2).
### 5. Which headless entry points are scripts?
### 4. Which headless entry points are scripts?
**The question.** User interfaces accept display names, and scripts refer to things by
id only (clause 6). The headless front ends are `improvise cmd '<line>'`, which runs