docs(adr): list every place natural order changes, and define digit-run value (improvise-cq1q.1)

Status rows for records-mode order and fold order, the writer's other
sorted lines, GP fit row order, and two internal fingerprints. A digit
run compares by length after stripping leading zeros, then by bytes.

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 10:26:20 -07:00
committed by Edward Langley
parent 12642e40b6
commit bc08a1e41e
@@ -19,6 +19,10 @@ true. Where the amendment replaces an ADR 007 rule or an existing behaviour:
| 2 | a display already in use in a scope is refused | equal displays in a scope are shown with a gapless ` #2`, ` #3`, … suffix in id order |
| 2 | `CellKey` pairs are `(CategoryId, ItemId)` | `(CategoryId, ItemHandle)` |
| 4 | ids sort by plain string order (`CellKey::new` sorts with `String::cmp`, and the writer orders data lines by their text) | ids sort in natural order. `CellKey`'s canonical coordinate order changes with it, so `RecordHash` values change (they are on the wire, not in files), and a saved file's data lines and their coordinates are written in the new order; the loader canonicalises keys, so the data read back is the same |
| 4 | records mode string-sorts the store on entry (`DataStore::sort_by_key`, run by `SortData`) | records-mode rows come out in natural order, and so does the order `matching_positions` folds in (gotcha 18), so a `SUM`/`AVG` can change in the last bits |
| 4 | the writer string-sorts `hidden:`, `expanded(…)`, `collapsed:` and `## Aggregation` lines | those lines are written in natural order too |
| 4 | a GP fit string-sorts its records (`improvise-gp` `dataset.rs`) | the feature matrix's row order, and so a seeded fit's folds, follow natural order: a seeded fit can produce a different tree |
| 4 | `app.rs` view-shape fingerprints and `Model`'s `Debug` string-sort ids | they sort naturally too; nothing visible changes |
| 2, 5 | a collapsed entry and a group reference name a group by name | by its id |
| 4 | casefold; a run of U+0020 spaces becomes one `_`; strip characters outside `a`–`z`, `0`–`9`, `-`, `_`; remove a leading `_` | casefold; every character outside `a`–`z`, `0`–`9` and `-` becomes `_`; runs of `_` collapse; leading and trailing `_` and `-` are removed; `n` is prepended before a leading digit |
| 5 | a hand-written id uses the alphabet `a`–`z`, `0`–`9`, `-`, `_` | a hand-written id obeys every syntax rule of a generated id |
@@ -160,10 +164,11 @@ document holds is taken however it was made: a display slugging to a held `east-
becomes `east-1-<n>`, and a held counter candidate is skipped.
**Ids are always sorted in natural order**, wherever ids are ordered. Split each id into
alternating runs of digits and non-digits; compare the runs pairwise, a digit run by its
numeric value and a non-digit run by byte order; when two digit runs have equal value,
the shorter (fewer leading zeros) sorts first; when one id runs out of runs first, it
sorts first. So `profit`, `profit-1`, `profit-2`, `profit-10`, and `a-7` before `a-007`.
alternating runs of digits and non-digits; compare the runs pairwise, a non-digit run by
byte order and a digit run by value: strip its leading zeros, then the shorter run is
smaller, then compare bytes (so runs of any length work, with no fixed-width parse); when
two digit runs have equal value, the one with fewer leading zeros sorts first; when one
id runs out of runs first, it sorts first. So `profit`, `profit-1`, `profit-2`, `profit-10`, and `a-7` before `a-007`.
**Hand-written ids obey every syntax rule of a generated id.** `east-1`, `item-4` and
`q1_-_2024` load; `-east`, `east-`, `2024`, `a__b` and `_draft` are refused at load.