Skip to content

ADR-0072: A Section reaches the device as a number and a name, not as one rendered string

Status: Accepted Date: 2026-09-20

Decisions

D-149 The Corpus snapshot carries an SDS Section as its number and its name separately, and the device keys the heading off the number

A Section crosses the seam as its number and its name rather than as one rendered English string. The device looks the Thai heading up by number, in the same sixteen-entry constant that is held once and gated across both repositories (D-134).

Context

The Section-heading ruling's curator half is built. Its reader half is not, and could not be.

The snapshot carries sdsSection as one flat English string — "Section 8 Exposure controls / personal protection" — with no number beside it. A Thai-first device therefore has nothing to key a heading off, which means the reader half of D-133 describes something the reader app does not do. The rule was ruled and half-built, and the missing half was a payload shape nobody had specified.

It was found by the frontend agent while building D-133's reader half, and reported as blocked rather than faked. That is why this is a ruling rather than a /^Section (\d+)/ in a Vue file that nobody would have read again.

This completes D-133 rather than replacing it. ADR-0060 stands untouched; what this supplies is the payload shape its reader half always needed.

Why this does not break — or amend — ADR-0056

ADR-0056 is scoped to versions that have been published, explicitly and throughout, so it does not reach the shape of a snapshot not yet published:

  • its title is "A published version is the payload the gate passed";
  • its stored-payload ruling (D-127) rules what happens "At publish", and that "every pull serves that payload";
  • its Decision is "A published version is the stored payload that passed the gate";
  • its Consequences say "A version is immutable, so rolling back to it serves exactly what it shipped" — immutability of a thing already shipped.

Nothing in it constrains what the serialiser emits for a snapshot that has not been published. So ADR-0056 is cited here and amended nowhere; a reader cannot take its text the other way. A published snapshot keeps precisely what it shipped and is never rewritten; snapshots published from now on carry the number.

No Corpus has ever been published, so today the distinction costs nothing. Writing it down is what keeps the next schema change from being argued as a precedent for rewriting a shipped one.

Where the two rulings do touch, and it is worth knowing. ADR-0056 records that "the route's response schema validates the stored payload on the way out, so one that no longer fits the contract is refused at the boundary." A payload published under the old flat-string shape would therefore be refused rather than silently served once the schema requires the number. That is the correct behaviour and it is free today, because no such payload exists. On the day one does, reconciling it is a decision — not a licence to rewrite the stored bytes, which ADR-0056 forbids.

This is also not an amendment to the snapshot-shape ruling (D-124). That rules who decides the shape and that the device derives nothing from it; this changes what the shape is, and leaves the rule exactly where it was. The rejected regex below is what a violation of D-124 would have looked like.

Decision

A Section reaches the device as a number and a name. The device keys the Thai heading off the number and renders nothing it was not sent.

Rejected options

  • Parsing the number out of the display string with /^Section (\d+)/ — rejected, and this is the operative one. A failed match falls back to English, so the failure mode is two languages on one screen, silently, on a surface a Handler reads under pressure. It is also a device deriving a value from a rendered string, which is the thing D-124 exists to refuse. The frontend agent declined to build it and was right: a half-applied D-133 is worse than an unapplied one, because the unapplied one is visible.
  • Narrowing D-133 to Curation, and letting the Handler keep English headings over Thai content — rejected. It is honest and it is smaller, and it loses because the app is Thai-first for a reason that does not stop at the heading. The person at the point of exposure is the one reader who cannot be asked to work around it.
  • Rewriting already-published payloads into the new shape — rejected on ADR-0056's authority rather than on this ADR's. It is listed here because it is the shortcut that would present itself the day a published snapshot in the old shape exists, and the answer is already written down.

This ruling may not be re-decided

If a change contradicts this ADR: stop and raise it. Do not implement over it.

Specifically: do not parse a Section number out of a display string anywhere, do not send the device a pre-rendered heading, do not let a missing number fall back to English, and do not rewrite a published payload to fit this shape.

Consequences

What becomes true. D-133's reader half becomes buildable, so a Handler reads Section headings in the language of the app. The device renders a heading it looked up rather than one it was handed, from the one list both repositories are held to.

What this costs — stated, not discovered. A third shape crossing the snapshot seam, so snapshot.golden.json, the client's isSnapshot and corpus_check.py --demo all move together. That seam was broken once before, as blocker 13, and is now gated in both repositories — the gate is what makes this a day's work rather than a risk, and it is the reason the cost is quotable in advance.

What is closed off. Any client-side derivation of a Section number, and any rewrite of a published payload.

Coverage

UpstreamLanded inEvidenceNote
D-133D-149the reader half could not be built because the payload carried no number; this supplies the shape it neededADR-0060 stands and is not restated here
D-134D-149the device looks the Thai heading up in the sixteen-entry constant held once and gated across both repositoriesADR-0060; the same list the curator half already uses
D-124D-149the server decides the shape and the device derives nothing from it — which is what the rejected regex would have brokenADR-0053; the rule is applied here, not amended
D-127Dropped: ADR-0056 governs versions already published and is cited, not consumed — no published snapshot exists, and none would be rewritten if it did (D-104)