Skip to content

Commit c38e348

Browse files
reid-spencerclaude
andcommitted
Close out BACKLOG 1a and file what gating the page uncovered
1a is done, so it leaves BACKLOG.md. What replaces it is 1a-followup: the subset of the page's remaining skips whose reason is "this example is wrong" rather than "the harness cannot wrap it" -- OrderPlaced shown with two field sets on one page, epic steps whose paths contradict the page's own application fence, an adaptor crossing its isolation seam, a projector with no record. Each was read off a real riddlc diagnostic. 1b absorbs the last 17 blanket skips, which live in migration/ and guides/. CLAUDE.md gains the domain-prelude mechanism and, more usefully, the two ways this gate can report a green that means nothing: a probe filtering only [error]/[severe] misses [deprecated], and a directive that fails to parse degrades silently to `standalone`. Both were hit this session. Gate re-run after these edits: 183/43/0, exit 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent faa4cbe commit c38e348

3 files changed

Lines changed: 165 additions & 145 deletions

File tree

BACKLOG.md

Lines changed: 49 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -6,101 +6,47 @@ what is durably true goes to CLAUDE.md.
66

77
---
88

9-
## 1a. Retire the blanket "illustrative fragment" skips ← START HERE
10-
11-
**What:** When filed, the gated pages reported 84 validated and **128 skipped**,
12-
**118 of them carrying one identical reason**: `illustrative fragment;
13-
references vocabulary this page does not define`. That is precisely what a
14-
`<!-- riddl-prelude ... -->` exists to supply, so they were bulk-skipped rather
15-
than annotated.
16-
17-
A skip is a legitimate outcome for a fence that genuinely cannot compile — a
18-
deliberate counter-example, or an `include` resolved against a file that does
19-
not exist. What 1a retires is the **blanket** reason applied without looking.
20-
Each such fence keeps a skip, but with a reason that says which of those it is.
21-
22-
**Measured 2026-08-08**, not estimated: stripping that one reason from 8 sample
23-
concept pages (14 such skips) and re-running with `--auto`**4 of the 14
24-
needed nothing but an existing wrapper** and were skipped for no reason at all.
25-
The other 10 need a per-page prelude, which is the documented remedy, not a
26-
correction to the examples.
27-
28-
**Method per page:**
29-
```bash
30-
# strip the blanket skip (WHOLE line, indentation included -- a leftover
31-
# indent corrupts fence matching and silently changes the counts)
32-
# then see which wrapper each fence fits:
33-
python3 scripts/validate-riddl-examples.py --auto ../bin/riddlc <page>.md
34-
```
35-
Annotate the ones that place; write one page prelude for the rest.
36-
37-
**Progress:** `concepts/` and `introduction/` are **done** — not one blanket
38-
skip remains in either. `language-reference.md` has had a first slice: 23
39-
validated / 52 skipped → **35 / 40**. Gate-wide: **171 validated / 55 skipped
40-
/ 0 failed**, from 84/128 when 1a was filed.
41-
42-
**49 blanket skips remain:**
43-
44-
| Where | Count | Note |
45-
|---|---|---|
46-
| `references/language-reference.md` | 32 | in scope; see below |
47-
| `migration/1.x-to-2.0.md` | 6 | **outside the gate** — 1b territory |
48-
| `guides/authors/design/command-event-patterns.md` | 6 | outside the gate |
49-
| `guides/authors/design/ui-modeling.md` | 3 | outside the gate |
50-
| `guides/authors/index.md` | 2 | outside the gate |
51-
52-
### What the remaining 32 need (measured, do not re-derive)
53-
54-
The page's prelude has been extended once and **compiles clean on its own**
55-
probe it with `wrap("in-context", "type ProbeOnly is String", prelude)` before
56-
blaming a fence. What is left divides roughly into:
57-
58-
- **Statement fences** (`send`/`tell`/`set`/`let`/`match`/`foreach`/`become`)
59-
that want `in-handler`. The wrapper already supplies `order`, `cart` and
60-
their fields; what they lack is page vocabulary — outlets, events, target
61-
entities — some of which is now in the prelude and some not.
62-
- **Whole-context fences** (adaptor, projector, pipeline, application, epic)
63-
that declare their own `context`. These want `in-domain` plus a
64-
**`riddl-domain-prelude`** holding the sibling contexts they name
65-
(`PaymentContext`, `OrderContext`, `Storefront`). The page has no domain
66-
prelude yet; that is the single biggest lever left.
67-
- **Genuinely unskippable, needing a precise reason instead of the blanket
68-
one:** the two `import "commerce.bast"` fences, and the
69-
`on command DoIt from context Other` pair (two spellings of the same clause,
70-
which cannot share a handler — same fence as `onclause.md`).
71-
- **Known content bugs to fix while there:** `button Checkout activates type
72-
Boolean` (fifth page with that line), and the `version` fence whose
73-
`entity Order` has no handler.
74-
75-
**Two traps this page taught, both costly:**
76-
77-
- **Never name a prelude entry `Tax`.** The `in-function` wrapper supplies a
78-
sibling `context Tax`, so a prelude `function Tax` makes every `Tax.…` path
79-
ambiguous and breaks the page's in-function fences. The prelude carries a
80-
comment saying so.
81-
- **`annotate-riddl-examples.py` places a fence against the prelude AS IT
82-
WAS.** Extending the prelude afterwards can invalidate earlier placements —
83-
it silently invalidated 8. Annotate, then extend, then re-run the page.
84-
85-
**The gate's scope is a file list, not a directory.** The exact command is in
86-
CLAUDE.md § "Compiling RIDDL examples". Compare numbers only within one scope.
87-
88-
**Rules the work established** (each earned by a regression):
89-
90-
- Wrapper-internal names keep the `Example` prefix. A record named `OrderData`
91-
collided with `language-reference.md`'s own prelude — a page prelude and the
92-
wrapper share one context — and broke two of its fences.
93-
- Wrapper vocabulary is only ever ADDED, never renamed: an extra field cannot
94-
break a fence that ignores it.
95-
- **Re-run the FULL gate after any wrapper edit**, never just the page in hand.
96-
Wrapper changes have regressed other pages three times in this work.
97-
- A wrapper must satisfy the checks its own shape triggers: `in-entity` needs a
98-
state with a handler, or a fence contributing only invariants fails for the
99-
wrapper rather than for itself.
100-
101-
**Why this outranks 1b:** these pages are already gated, so the gate reports
102-
green while checking barely 40% of their RIDDL. That is the same
103-
"green-but-measured-nothing" failure recorded in NOTEBOOK.
9+
## 1a-followup. Content bugs found by gating language-reference.md
10+
11+
← START HERE
12+
13+
**What:** Retiring the blanket skips (1a, done 2026-08-10) compiled every
14+
fence on the page that can compile. The 20 that still carry a skip each name
15+
their own reason now, and these are the ones whose reason is **the example is
16+
wrong**, not "the harness cannot wrap it". Each was read off a real riddlc
17+
diagnostic, so none needs re-deriving:
18+
19+
- **`OrderPlaced` has two different shapes on one page.** One fence yields
20+
`OrderPlaced(id, total)`, another `OrderPlaced(orderId, total = cart.total,
21+
currency = "USD")`. A prelude can supply only one. Decide which is the
22+
event and make both fences agree.
23+
- **The epic's steps use paths the page's own application fence contradicts.**
24+
`step take input Storefront.AddToCartForm` treats the form as a direct child
25+
of the context, while the application fence puts forms inside `page`s. 2.0
26+
containment agrees with the application fence, so the epic's paths are
27+
wrong.
28+
- **The adaptor example crosses its own isolation seam.** `PaymentIntegration`
29+
emits `OrderPaymentReceived`, which belongs to neither its parent context
30+
nor its referent. 2.0 rejects this. The example needs the event declared in
31+
`OrderContext`, which means showing it.
32+
- **The projector example has no record.** A 2.0 projector requires one.
33+
- **`button Checkout activates type Boolean`** — the fifth page carrying this
34+
line. Still not valid 2.0.
35+
- **The `version` fence's `entity Order` has no handler and no state.**
36+
- **`match order.status`** matches a String against type-cases and a numeric
37+
`>=` threshold. For it to compile, `status` would have to be an enumerated
38+
type — which directly conflicts with the `set field status to "Active"`
39+
fence. The two examples cannot both be right.
40+
41+
**Also parked, and NOT a content bug:** the `repository CartRepository` fence
42+
names `record Cart` in its schema, while the page prelude must supply
43+
`entity Cart` for other fences. One context cannot hold both names. Fixing it
44+
means renaming the prelude's entity and every fence that reaches it, which is
45+
a bigger edit than it looks.
46+
47+
**Verification:** the page and both gates are green as it stands — 2.0 at
48+
183/43/0, 1.31 at 6/0/0. These are skips with honest reasons, not failures,
49+
so nothing is red while they wait.
10450

10551
---
10652

@@ -109,11 +55,18 @@ green while checking barely 40% of their RIDDL. That is the same
10955
**What:** Not yet gated: `tutorials/rbbq/` (30 pages, the most-read tree),
11056
`guides/`, `tools/`, and the `riddlg`/`synapify`/`shell` sites.
11157

58+
**17 blanket skips live in these trees** and are the natural first slice:
59+
`migration/1.x-to-2.0.md` (6), `guides/authors/design/command-event-patterns.md`
60+
(6), `guides/authors/design/ui-modeling.md` (3), `guides/authors/index.md` (2).
61+
They are the last of the original 118. These trees also carry 4 pre-existing
62+
failures, so starting here means going red before green -- gate a page at a
63+
time.
64+
11265
**Also open:** `check-riddl-blocks.py` flags 33 advisory items, all in
11366
`migration/` (which shows 1.x deliberately — arguably belongs in EXEMPT_PATHS)
11467
and `tutorials/rbbq/`.
11568

116-
**Order:** After 1a, which is smaller and buys more real coverage.
69+
**Order:** after 1a-followup, which fixes examples readers can see today.
11770

11871
---
11972

CLAUDE.md

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,19 @@ render, so readers never see them:
407407
| `<!-- riddl: skip -->` | not validated |
408408

409409
A page may declare a `<!-- riddl-prelude ... -->` block of definitions that its
410-
fragments reference but do not show.
410+
fragments reference but do not show. It lands at **context** level whatever the
411+
wrapper's depth.
412+
413+
Domain-level vocabulary is a **separate** `<!-- riddl-domain-prelude ... -->`
414+
block, read only by `in-domain`. The two cannot be one block — a `user` is
415+
legal only in a domain, a `record` only in a context. It is what makes
416+
whole-`context` fences gateable: a domain body may hold type definitions, and a
417+
bare name resolves upward and across sibling contexts, so a sibling context in
418+
the domain prelude can supply outlets and events a fence names but never
419+
declares.
420+
421+
A fence that defines a name a prelude also supplies must say
422+
`no-prelude=Name`. This applies to **both** preludes by the same names.
411423

412424
`--auto` tries every wrapping and reports a fence only if none works. It is a
413425
*measurement* mode for pages that do not yet carry directives — not a
@@ -430,11 +442,26 @@ python3 scripts/validate-riddl-examples.py ../bin/riddlc "${files[@]}"
430442
# 1.31 -- same shape over sites/riddl-1x/docs, with the 1.31 compiler
431443
```
432444

433-
**Status**: `quickstart.md` is fully annotated and validates clean on both
434-
branches. The ~50 concept pages are not yet annotated; with `--auto`, 99 of
435-
their 120 fences still fail, dominated by fragments that reference definitions
436-
they deliberately do not show and so need a per-page prelude. That is a
437-
known gap, not a claim that those examples are wrong.
445+
**Status** (2026-08-10): the gated set is **183 validated / 43 skipped / 0
446+
failed**, and **every blanket `"illustrative fragment"` skip is gone** — there
447+
were 118 of them when the work started. `quickstart.md`, `concepts/`,
448+
`introduction/` and `references/language-reference.md` are all annotated and
449+
green. Every remaining skip states its own reason.
450+
451+
A skip is not a pass in disguise: ~20 of them record examples that are
452+
genuinely wrong for 2.0, tracked as BACKLOG 1a-followup. `guides/`,
453+
`migration/` and `tutorials/rbbq/` are still ungated (BACKLOG 1b).
454+
455+
**Two ways this gate can lie to you, both observed:**
456+
457+
- A **hand-rolled probe that filters only `[error]`/`[severe]` will call a
458+
fence clean that the gate rejects** — the gate also fails on `[deprecated]`.
459+
Filter exactly as `validate()` does, or use the gate itself.
460+
- **A malformed directive silently degrades to `standalone`.** There is no
461+
warning for a directive that does not parse, so a deliberate skip can quietly
462+
become a validated fence. The `[^>]*` bug that caused this is fixed, but the
463+
failure mode is structural: if a fence's result surprises you, check that its
464+
directive actually parses before believing the result.
438465

439466
**Version differences that matter for examples** (verified against both
440467
compilers):

NOTEBOOK.md

Lines changed: 83 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -11,84 +11,124 @@ to the task file and note completion in this notebook.
1111

1212
---
1313

14-
## HANDOFF — as of 2026-08-10
14+
## HANDOFF — as of 2026-08-10 (late)
1515

1616
**All figures below were run in this session, not recalled.**
1717

18-
**State:** branch `main`, tree clean, **0 commits ahead of `origin/main`**,
19-
HEAD `e446a20`. Everything is pushed; CI has deployed from it.
18+
**State:** branch `main`, tree clean, **2 commits ahead of `origin/main`**
19+
`c52287c` (validator fixes) and `faa4cbe` (the page). Not yet pushed.
2020

2121
**Compiler:** `../bin/riddlc` is **`2.0.0-rc.10-57-e012ebb9`** and `build.sbt`'s
22-
`With.Riddl.library` pin matches exactly. The Homebrew `riddlc` on PATH is
23-
**2.0.0-rc.5** and is the WRONG compiler for the 2.0 docs. riddlc is restaged
24-
often — re-check the binary against the pin at session start.
22+
pin matches exactly. The Homebrew `riddlc` on PATH is **2.0.0-rc.5** and is the
23+
WRONG compiler for the 2.0 docs. Re-check the binary against the pin at session
24+
start; it is restaged often.
2525

26-
**Gates:** 2.0 — **171 validated / 55 skipped / 0 failed, exit 0**; 1.31 —
27-
6/0/0. `mkdocs build --strict` on `sites/riddl` clean.
26+
**Gates:** 2.0 — **183 validated / 43 skipped / 0 failed, exit 0** (was
27+
171/55); 1.31 — 6/0/0. `mkdocs build --strict` on `sites/riddl` clean.
2828

2929
**`task/` holds only `done/`.** Nothing awaits triage.
3030

31-
### In flight — BACKLOG 1a
31+
### BACKLOG 1a is DONE
3232

33-
Retiring the blanket `"illustrative fragment"` skips. **49 remain**, from 118
34-
at session start. `concepts/` and `introduction/` are **finished**.
33+
**Not one blanket `"illustrative fragment"` skip remains in
34+
`sites/riddl/docs`** — 118 at the start of the work, 0 now. The 20 skips left
35+
on `language-reference.md` each state their own reason.
3536

36-
`references/language-reference.md` is **half-done and is where to resume**: 12
37-
of its 44 retired (page 23/52 → 35/40), and **the other 32 were restored
38-
verbatim** so the page is green. That restore is deliberate, not abandoned
39-
work — the gate must never be left red.
37+
**Next is BACKLOG 1a-followup**, which is the subset of those reasons that mean
38+
*the example is wrong*: `OrderPlaced` shown with two different field sets on
39+
one page, epic steps whose paths contradict the page's own application fence,
40+
an adaptor that crosses its isolation seam, a projector with no record. All
41+
were read off real riddlc diagnostics — do not re-derive them.
4042

41-
**BACKLOG 1a carries the measured analysis of those 32** — which want
42-
`in-handler`, which want `in-domain` plus a domain prelude the page still
43-
lacks, which are genuinely unskippable, and which hide known content bugs.
44-
Read it first; it cost a full pass to derive.
45-
46-
The other 17 sit in `migration/` and `guides/`, **outside the gate scope**,
47-
in trees carrying 4 pre-existing failures. Starting them starts BACKLOG 1b.
43+
The remaining 17 blanket skips site-wide are in `migration/` and `guides/`,
44+
outside the gate, and are now folded into BACKLOG 1b.
4845

4946
### Traps
5047

5148
- **The gate's scope is a FILE LIST, not a directory** — exact command in
5249
CLAUDE.md § "Compiling RIDDL examples". A figure is only comparable within
53-
one scope; if one fails to reproduce, re-measure against the parent commit
54-
rather than trusting it. That is why the inherited "108/107" was discarded.
50+
one scope.
5551
- **The gate truncates diagnostics** to a position. For the real message,
56-
import the script as a module, re-wrap with `wrap()` (mirroring any
57-
`no-prelude`), and run `../bin/riddlc validate <file>` — a bare path, there
58-
is no `--input-file` flag.
59-
- **Re-run the FULL gate after any wrapper or script edit.** Wrapper changes
60-
have regressed unrelated pages four times.
61-
- **`annotate-riddl-examples.py` places a fence against the prelude AS IT
62-
WAS.** Extending the prelude afterwards silently invalidated 8 placements.
52+
import the script as a module, re-wrap with `wrap()`, and run
53+
`../bin/riddlc validate <file>` — a bare path, there is no `--input-file`.
54+
- **A diagnostic filter that watches only `[error]`/`[severe]` will lie to
55+
you.** The gate also fails on `[deprecated]`, so a hand-rolled probe called
56+
a fence clean that the gate then rejected. Filter exactly as the gate does.
57+
- **Re-run the FULL gate after any wrapper or script edit**, and the 1.31 gate
58+
too — a script change is not scoped to one tree. Wrapper changes have
59+
regressed unrelated pages five times now.
60+
- **Extending a prelude regresses fences that were already green.** Adding
61+
`currency` to `OrderPlaced` broke a fence in a different section; adding a
62+
domain-level `Storefront` broke two more. Re-run the whole page after every
63+
prelude edit, not just the fence in hand.
6364
- **Prelude/wrapper name collisions run both ways.** Wrapper names keep an
64-
`Example` prefix; equally, a prelude must not take a name a wrapper supplies
65-
`function Tax` broke every in-function fence on its own page.
66-
- **Annotate fences by LINE NUMBER**, never by matching a fence's first line.
65+
`Example` prefix; equally a prelude must not take a name a wrapper supplies.
66+
- **Annotate fences by LINE NUMBER**, never by matching a fence's first line —
67+
and check the match is unique before writing, since several fences on this
68+
page share an opening line.
6769

6870
### Certainty
6971

7072
**Verified by command this session:** git state, both compiler versions, the
71-
pin, both gates, the strict build, that `task/` is empty, and that no
72-
unexecuted plan in `~/.claude/plans/` holds open work for this repo.
73+
pin, both gates, the strict build, that `task/` is empty, and that zero blanket
74+
skips remain.
7375

74-
**Verified by compiling:** every example on the 25 pages changed, plus the
75-
rules recorded in BACKLOG 1a and in the pass entries below.
76+
**Verified by compiling:** every fence on `language-reference.md`, and every
77+
claim in BACKLOG 1a-followup.
7678

77-
**Assumed, not re-verified:** BACKLOG item 5's 18 site items were carried over
78-
as written and none was re-checked against the current site. The gh-pages
79-
deploy triggered by the last push was not inspected.
79+
**Assumed, not re-verified:** BACKLOG item 5's 18 site items. The gh-pages
80+
deploy state — nothing has been pushed this session.
8081

8182
### Pointers
8283

83-
Open work is **BACKLOG.md** — 1a is live. Durable facts are **CLAUDE.md**,
84-
notably § "Things that will bite" and § "Compiling RIDDL examples".
84+
Open work is **BACKLOG.md** — 1a-followup is live. Durable facts are
85+
**CLAUDE.md**, notably § "Things that will bite" and § "Compiling RIDDL
86+
examples".
8587

8688
**Run `/ossuminc-skills:check-tasks` in the new session.**
8789

8890
The sections below are kept as the record of how the current state was reached.
8991

9092
---
9193

94+
### BACKLOG 1a, final pass: language-reference.md done ✅ **2026-08-10**
95+
96+
The last 32 blanket skips retired; page 35/40 → 47/28, gate 171/55 → 183/43.
97+
1a is complete.
98+
99+
**The harness was hiding work behind "no wrapper fits" — four separate ways.**
100+
The pattern from pass 4 (annotate kept a stale copy of the wrapper list)
101+
turned out not to be a one-off:
102+
103+
- `no-prelude` reached only the page prelude, so a whole-context fence could
104+
never use a domain prelude — the single biggest lever on the page was
105+
unreachable, not absent.
106+
- `PRELUDE_ENTRY` did not match an intention prefix, so
107+
`application context Storefront` was invisible to `no-prelude`.
108+
- **`DIRECTIVE` used `[^>]*`, so a skip reason containing `>=` ended the match
109+
early and the fence silently became `standalone`.** This one fails toward
110+
false confidence: a deliberate skip quietly turns into a validated fence.
111+
It cost three mystery failures that looked like lost directives.
112+
113+
**A domain prelude works because bare names resolve across sibling contexts.**
114+
That was worth proving rather than assuming, so it was checked in both
115+
directions — a bare `outlet Pings` in another context resolved, and a bogus
116+
name failed. A domain body may hold type definitions, which is what makes the
117+
stream events placeable.
118+
119+
**Some fences cannot be made green without lying.** The adaptor example emits
120+
a message belonging to neither its parent nor its referent context. A prelude
121+
*can* silence that by hiding the event in the referent — and doing so would
122+
defeat exactly the check that makes the gate worth running. Those fences got
123+
an honest skip and a BACKLOG entry instead.
124+
125+
**Two examples on one page can be mutually exclusive.** `match order.status`
126+
needs `status` to be an enumerated type; `set field status to "Active"` needs
127+
it to be a String. No prelude satisfies both, and that is a content decision,
128+
not a harness gap.
129+
130+
---
131+
92132
### BACKLOG 1a, pass 4: language-reference.md, first slice ✅ **2026-08-10**
93133

94134
12 of its 44 blanket skips retired (page 23/52 → 35/40); the other 32 restored

0 commit comments

Comments
 (0)