Skip to content

Commit 0bbee29

Browse files
reid-spencerclaude
andcommitted
Track the deferred field/alias prefix scope as [1.10]
The prefix-truthfulness rule shipped covering TypeRef only. Extending it to AliasedTypeExpression -- a field type or a type alias -- is a DECISION rather than effort, and it roughly triples a migration that already touches 1,032 sites in 188 of 188 models, so it is filed with the measurement rather than assumed. NOTEBOOK records the rule, that it fires in both directions, and the JSON fidelity defect it exposed: a keyword field that only ever held its default value hid a round-trip loss. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent cb05e37 commit 0bbee29

2 files changed

Lines changed: 68 additions & 0 deletions

File tree

BACKLOG.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,8 @@ task files, so they were NOT physically reshuffled; this index carries the order
237237
| 11 | Cross-context `tell` isolation seam | 5 | Largest item and the biggest corpus-migration risk. Needs a counting mode built and run under real resolution before the Error ships. Wants its own plan. |
238238
| ~~12~~ | ~~Two narrow-operand gaps~~ || **Part 1 DONE `faf7551c0`** — and it was NOT false-positive-only as filed, it was a missed Error. Part 2 (`emittedMessageTypes`) split out and left last: genuinely advisory, genuinely a restructuring. |
239239

240+
| 13 | **[1.10]** Prefix truthfulness for fields/aliases || A DECISION, not effort. Shipped for `TypeRef` 2026-08-24; extending to `AliasedTypeExpression` roughly triples an already 1,032-site migration, so measure first. |
241+
240242
Three real dependency edges, not twelve: **4 ← 3**, **10 ← 9**, **11 ← 5**.
241243
Everything else is independent and may be reordered by appetite. Items 10 and 11
242244
each want an approved plan before implementation, per the standing rule.
@@ -898,6 +900,37 @@ each want an approved plan before implementation, per the standing rule.
898900
replay at all. The cache-restore path is real and is now closed, but the timing observation
899901
was not the proof it was presented as.
900902

903+
- **[1.10]** **Does prefix truthfulness extend to a field's type and a type alias?**
904+
— a DECISION, not effort. The check shipped 2026-08-24 (`cb05e3748`) covering
905+
`TypeRef`: portlet types, invariant `requires`, a function's `requires`/`returns`.
906+
A field's type (`two: Ctx.Cmd`) and a type alias (`type A is Ctx.Rec`) are
907+
**`AliasedTypeExpression`** (`AST.scala:1958`) — a different node that carries its
908+
own `keyword` and does NOT route through `checkRef`, so nothing checks them.
909+
Verified against the staged binary: `record Holder is { two: Ctx.Cmd }` naming a
910+
command draws zero errors.
911+
912+
**The requesting task asked for it** (`task/done/2026-08-24-reference-prefix-must-
913+
match-declared-kind.md`): *"the rule is about `type_ref` generally — a field's
914+
type, a `let`'s ascription, an `updates repository` … applying it everywhere at
915+
once is the honest reading of the requirement."* It was deliberately NOT done,
916+
and the reason is cost, measured rather than guessed: reactive-bbq alone holds
917+
**283** portlet references and **542** aliased field references, so extending the
918+
rule roughly TRIPLES a migration that already touches 1,032 sites in 188 of 188
919+
models. That deserves its own estimate, not a ride-along.
920+
921+
**Pinned, so it cannot quietly become permanent**: `ReferencePrefixAndRepository
922+
PortsTest` has a case named *"NOT yet cover a field's type, which is a different
923+
AST node"*. If the scope widens, that test fails — which is the intended
924+
direction; update it rather than narrowing the check back.
925+
926+
**What to decide:** whether a field typed by a record must read `two: record
927+
Ctx.Cmd`. The argument for is Reid's own — the prefix exists to make a model
928+
readable without chasing the declaration, and a field is where a reader most
929+
often wants that. The argument against is that it is the single most common
930+
syntactic position in the language, so the cost is not proportional to the
931+
ambiguity being removed. Measure the corpus-wide count before choosing; the
932+
542 above is one model.
933+
901934
### 2. Queued, needs a plan
902935

903936
#### Decided in `../RIDDL-Tools-To-Do-List.md` but never built

NOTEBOOK.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,41 @@ Orientation for a session with no memory of this work. **Open work is in
1010
`BACKLOG.md`**; durable facts are in `CLAUDE.md`; what things TAUGHT us is in this
1111
NOTEBOOK's body. Ask `git` for branch, tree and unpushed span.
1212

13+
**`../bin/riddlc` IS `2.0.0-rc.24-5-cb05e374`, ahead of rc.24, and riddl-models is
14+
ALREADY RUNNING IT (2026-08-24).** No RC was cut for it, deliberately. Beyond rc.24 it
15+
carries: product-on-stdout, morph-after-morph, and now **prefix truthfulness**.
16+
17+
**A reference's prefix must name what the target was DECLARED as.** Keyed off the
18+
DECLARATION, never off what the reference carries — an alternation declared
19+
`type XEvent is one of { … }` IS a type, so `is type XEvent` stays legal, and keying
20+
off the carried kind would have reddened all 230 such references in reactive-bbq and
21+
been wrong about every one. **A BARE reference is held to the same standard** (Reid's
22+
ruling): `TypeRef.keyword` defaults to `"type"`, so the AST cannot tell an omitted
23+
prefix from a written one, and the prefix exists to remove exactly that ambiguity.
24+
**Corpus cost: 1,032 sites in 188 of 188 models** — no model is clean.
25+
**The rule fires in BOTH directions**, which the requesting task did not anticipate:
26+
riddl's own `dokn.riddl` had `is event CompanyEvent` where `CompanyEvent` is a declared
27+
*alternation*, so that site LOST a keyword rather than gaining one.
28+
29+
**SCOPE IS PARTIAL AND TRACKED AS `[1.10]`.** Only `TypeRef` is covered — portlets,
30+
invariant `requires`, function `requires`/`returns`. A field's type and a type alias
31+
are `AliasedTypeExpression`, a different node, and are NOT checked. Deliberate: 283
32+
portlet vs **542** aliased field references in reactive-bbq alone. A test named *"NOT
33+
yet cover a field's type"* pins the boundary; if scope widens that test fails, which is
34+
the intended direction.
35+
36+
**It also exposed a REFLECTIVITY defect worth remembering the shape of:** the JSON
37+
surface dropped a `TypeRef`'s keyword on schema fields, so a round trip rewrote
38+
`as record X` to `as type X`. BAST was already correct. It was invisible for as long as
39+
`type` was the only keyword anyone wrote — **a fidelity bug can hide behind a field
40+
that only ever holds its default value.**
41+
42+
**`riddlc find -replace` did 13 of the 24 in-repo migration sites**, at Reid's
43+
suggestion, and found sites in an INCLUDED file that a grep on the entry file would
44+
have missed. The script reads `source` + `type.carries` from the projection and returns
45+
the source unchanged when `carries` is absent (an alternation), so those are left alone.
46+
47+
1348
**`../bin/riddlc` IS AHEAD OF rc.24 — it is `2.0.0-rc.24-3-40c0574f`, staged with
1449
`publishLocal`, and that is deliberate (2026-08-24).** Reid's call: *"don't build an RC,
1550
just stage riddlc to ../bin and publishLocal — I want to avoid this round-trip between

0 commit comments

Comments
 (0)