Skip to content

Commit 6f4e1db

Browse files
hyperpolymathclaude
andcommitted
docs(adr): ESC-04 — ADR-016 ReScript block-module disposition (Refs #262 #229)
AffineScript is strictly one-module-per-file (ADR-011 file=module; grammar parser.mly:130-134 — `module A { }` parse-errors). The #229 ports carry ReScript block modules; single-per-file is mechanical (canonical map), but multi-block-module-per-file had no clean target (ESC-04 #262). ADR-016 (accepted): one module per file — split, do not nest. Each `module X { body }` -> its own X.affine with a `module X;` header; N block-modules -> N files. Grammar NOT extended with a block/nested form (contradicts ADR-011; the conflict-risky cosmetic change ADR-012 forbids). No compiler change — settles the porting doctrine + #229 canonical-map structural rule. The adjacent Resolve.UndefinedModule on split files is cross-module graph coherence (INT-02), tracked in RESCRIPT-ELIMINATION Tier-4, explicitly NOT conflated here. SETTLED-DECISIONS.adoc + META.a2ml [[adr]] ADR-016 + RESCRIPT- ELIMINATION.adoc cross-linked (ADR-014 precedent: PR proposes, owner ratifies by merge). Docs-only; gate unaffected by construction. Refs #262 #229 (not Closes — per-repo split execution + INT-02 remain). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent cba836f commit 6f4e1db

3 files changed

Lines changed: 90 additions & 3 deletions

File tree

.machine_readable/6a2/META.a2ml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,3 +1016,52 @@ references = [
10161016
"hyperpolymath/typed-wasm (multi-producer ownership-section ABI)",
10171017
"WASI 0.2 / WebAssembly Component Model specification",
10181018
]
1019+
1020+
[[adr]]
1021+
id = "ADR-016"
1022+
status = "accepted"
1023+
date = "2026-05-19"
1024+
title = "ReScript block-module disposition: one module per file (split, do not nest)"
1025+
context = """
1026+
ReScript `module Name { … }` block modules have no AffineScript block
1027+
form: the grammar (parser.mly:130-134) is a single optional `module
1028+
Path;` header, before imports — `module A { }` parse-errors. ADR-011
1029+
settled "real modules": the file IS the module. The estate #229 ports
1030+
carry block modules; a SINGLE one per file is mechanical (hoist header,
1031+
drop braces, dedent — in the #229 canonical map, verified to parse), but
1032+
MULTIPLE block-modules in one file (e.g. standards/lol/.../OpenCyc.affine:
1033+
module Config{} module Concepts{} module Types{}…; 14 estate
1034+
occurrences) had no clean target. Escalated language-side as ESC-04
1035+
(#262) — the bidirectional-evidence discipline of ADR-014 / #228.
1036+
"""
1037+
decision = """
1038+
One module per file — split, do not nest. Each ReScript `module X {
1039+
body }` becomes its own `X.affine` whose first declaration is `module
1040+
X;`, body dedented, `use` after the header. A file with N block-modules
1041+
is split into N files. The grammar is NOT extended with a block/nested
1042+
module form: that contradicts ADR-011 (file = module) and is a major
1043+
conflict-risky grammar change for cosmetic gain — the contortion ADR-012
1044+
forbids. No compiler change (the file-header form already parses); this
1045+
ADR settles the porting doctrine + the #229 canonical-map structural
1046+
rule. Adjacent and explicitly OUT of scope: a split file still hits
1047+
Resolve.UndefinedModule until the repo module-path<->file-layout matches
1048+
the loader — cross-module graph coherence (INT-02 loader-bridge),
1049+
tracked in RESCRIPT-ELIMINATION.adoc Tier-4, never conflated here.
1050+
"""
1051+
consequences = """
1052+
- The #229 block-module residue (idaptik-dlc-vm, standards/lol, parts of
1053+
burble) has a defined target: split-per-file. Full validation still
1054+
needs the per-repo module graph (INT-02), tracked separately.
1055+
- No language/compiler change; no estate consumer churn from this ADR.
1056+
- This decision is settled; do not reopen without amending this ADR.
1057+
ESC-04 #262; #229 canonical map in docs/RESCRIPT-ELIMINATION.adoc.
1058+
"""
1059+
references = [
1060+
"https://github.com/hyperpolymath/affinescript/issues/262",
1061+
"https://github.com/hyperpolymath/affinescript/issues/229",
1062+
"lib/parser.mly (module_decl; one `module Path;` header per file)",
1063+
"docs/specs/SETTLED-DECISIONS.adoc (ADR-016 section)",
1064+
"docs/RESCRIPT-ELIMINATION.adoc (#229 canonical map; Tier-4 INT-02)",
1065+
"META.a2ml [[adr]] ADR-011 (real modules: file = module)",
1066+
"META.a2ml [[adr]] ADR-012 (grammar changes are correctness assertions)",
1067+
]

docs/RESCRIPT-ELIMINATION.adoc

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -270,9 +270,13 @@ ReScript `import P [as A]`→`use P [as A];`, single block-module
270270
`module P;` header (hoisted before imports — `parser.mly:130-134`
271271
requires the header first), braces dropped, body dedented one level.
272272
Oracle-verified to parse.
273-
* *Tier-3 ESC-04 (#262):* *multi*-block-module per file (e.g.
274-
`standards/lol/.../OpenCyc.affine`) has *no clean target* —
275-
AffineScript is one-module-per-file. Escalated, not guessed.
273+
* *ESC-04 (#262) — SETTLED by ADR-016:* AffineScript is strictly
274+
one-module-per-file. Doctrine: *split, do not nest* — each ReScript
275+
`module X { body }` (incl. each of N in a multi-block file like
276+
`standards/lol/.../OpenCyc.affine`) becomes its own `X.affine` with a
277+
`module X;` header. No grammar change (ADR-011 file=module; a
278+
block-module form is the ADR-012-forbidden contortion). Full
279+
validation still needs the per-repo module graph (INT-02, Tier-4).
276280

277281
=== Reclassified OUT of #229 — permanently (scanner over-scope)
278282

docs/specs/SETTLED-DECISIONS.adoc

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,3 +308,37 @@ default wasm target to component and demote preview1 to a legacy target.
308308
This decision is settled; do not reopen without amending the ADR. Full
309309
ADR in `.machine_readable/6a2/META.a2ml` (ADR-015); ledger INT-03 in
310310
`docs/TECH-DEBT.adoc`; roadmap in `docs/ECOSYSTEM.adoc`.
311+
312+
== ReScript Block-Module Disposition: One Module Per File (ADR-016)
313+
314+
ReScript `module Name { … }` block modules have no AffineScript block
315+
form: the grammar (`parser.mly:130-134`) is a single optional
316+
`module Path;` *header*, before imports — `module A { }` parse-errors.
317+
ADR-011 already settled "real modules": *the file is the module*. The
318+
estate ReScript→AffineScript ports (#229) carry block modules — a single
319+
one per file is mechanical (hoist the header, drop the braces, dedent;
320+
already in the #229 canonical map and verified to parse), but *multiple*
321+
block-modules in one file (e.g. `standards/lol/.../OpenCyc.affine`:
322+
`module Config { } module Concepts { } module Types { } …`, 14 estate
323+
occurrences) had no clean target. Escalated language-side as ESC-04
324+
(#262), the same bidirectional-evidence discipline as ADR-014 / #228.
325+
326+
Decision: *one module per file — split, do not nest.* Each ReScript
327+
`module X { body }` becomes its own `X.affine` whose first declaration is
328+
`module X;`, body dedented, `use` imports after the header. A file with N
329+
block-modules is split into N files. The grammar is **not** extended with
330+
a block/nested-module form: that would contradict ADR-011 (file = module)
331+
and is a major, conflict-risky grammar change for cosmetic gain — exactly
332+
the contortion ADR-012 forbids. No language/compiler change is needed
333+
(the file-header form already parses); this ADR settles the *porting
334+
doctrine* + the #229 canonical-map structural rule.
335+
336+
Adjacent, explicitly NOT in scope here: a split file still hits
337+
`Resolve.UndefinedModule` until the repo's module-path↔file-layout
338+
matches the loader — that is cross-module graph coherence (INT-02
339+
loader-bridge territory), tracked in `RESCRIPT-ELIMINATION.adoc` Tier-4
340+
and the INT-02 ledger, never conflated with this disposition.
341+
342+
This decision is settled; do not reopen without amending the ADR. Full
343+
ADR in `.machine_readable/6a2/META.a2ml` (ADR-016); #229 canonical map in
344+
`docs/RESCRIPT-ELIMINATION.adoc`; escalation issue #262.

0 commit comments

Comments
 (0)