Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .machine_readable/6a2/META.a2ml
Original file line number Diff line number Diff line change
Expand Up @@ -1096,6 +1096,57 @@ references = [
"docs/specs/SETTLED-DECISIONS.adoc (ADR-016 section)",
]

[[adr]]
id = "ADR-017"
status = "accepted"
date = "2026-05-19"
title = "ReScript block-module disposition: one module per file (split, do not nest)"
context = """
ReScript `module Name { … }` block modules have no AffineScript block
form: the grammar (parser.mly:130-134) is a single optional `module
Path;` header, before imports — `module A { }` parse-errors. ADR-011
settled "real modules": the file IS the module. The estate #229 ports
carry block modules; a SINGLE one per file is mechanical (hoist header,
drop braces, dedent — in the #229 canonical map, verified to parse), but
MULTIPLE block-modules in one file (e.g. standards/lol/.../OpenCyc.affine:
module Config{} module Concepts{} module Types{}…; 14 estate
occurrences) had no clean target. Escalated language-side as ESC-04
(#262) — the bidirectional-evidence discipline of ADR-014 / #228.
(ADR-016 is effect-threaded async-boundary, #234/#270; ADR-018 is the
no-raw-escape doctrine, #245 — this is ADR-017, sequential.)
"""
decision = """
One module per file — split, do not nest. Each ReScript `module X {
body }` becomes its own `X.affine` whose first declaration is `module
X;`, body dedented, `use` after the header. A file with N block-modules
is split into N files. The grammar is NOT extended with a block/nested
module form: that contradicts ADR-011 (file = module) and is a major
conflict-risky grammar change for cosmetic gain — the contortion ADR-012
forbids. No compiler change (the file-header form already parses); this
ADR settles the porting doctrine + the #229 canonical-map structural
rule. Adjacent and explicitly OUT of scope: a split file still hits
Resolve.UndefinedModule until the repo module-path<->file-layout matches
the loader — cross-module graph coherence (INT-02 loader-bridge),
tracked in RESCRIPT-ELIMINATION.adoc Tier-4, never conflated here.
"""
consequences = """
- The #229 block-module residue (idaptik-dlc-vm, standards/lol, parts of
burble) has a defined target: split-per-file. Full validation still
needs the per-repo module graph (INT-02), tracked separately.
- No language/compiler change; no estate consumer churn from this ADR.
- This decision is settled; do not reopen without amending this ADR.
ESC-04 #262; #229 canonical map in docs/RESCRIPT-ELIMINATION.adoc.
"""
references = [
"https://github.com/hyperpolymath/affinescript/issues/262",
"https://github.com/hyperpolymath/affinescript/issues/229",
"lib/parser.mly (module_decl; one `module Path;` header per file)",
"docs/specs/SETTLED-DECISIONS.adoc (ADR-017 section)",
"docs/RESCRIPT-ELIMINATION.adoc (#229 canonical map; Tier-4 INT-02)",
"META.a2ml [[adr]] ADR-011 (real modules: file = module)",
"META.a2ml [[adr]] ADR-012 (grammar changes are correctness assertions)",
]

[[adr]]
id = "ADR-018"
status = "accepted"
Expand Down
10 changes: 7 additions & 3 deletions docs/RESCRIPT-ELIMINATION.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -271,9 +271,13 @@ ReScript `import P [as A]`→`use P [as A];`, single block-module
`module P;` header (hoisted before imports — `parser.mly:130-134`
requires the header first), braces dropped, body dedented one level.
Oracle-verified to parse.
* *Tier-3 ESC-04 (#262):* *multi*-block-module per file (e.g.
`standards/lol/.../OpenCyc.affine`) has *no clean target* —
AffineScript is one-module-per-file. Escalated, not guessed.
* *ESC-04 (#262) — SETTLED by ADR-017:* AffineScript is strictly
one-module-per-file. Doctrine: *split, do not nest* — each ReScript
`module X { body }` (incl. each of N in a multi-block file like
`standards/lol/.../OpenCyc.affine`) becomes its own `X.affine` with a
`module X;` header. No grammar change (ADR-011 file=module; a
block-module form is the ADR-012-forbidden contortion). Full
validation still needs the per-repo module graph (INT-02, Tier-4).

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

Expand Down
34 changes: 34 additions & 0 deletions docs/specs/SETTLED-DECISIONS.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,40 @@ This decision is settled; do not reopen without amending the ADR. Full
ADR in `.machine_readable/6a2/META.a2ml` (ADR-016); ledger #234 /
CORE-02 in `docs/TECH-DEBT.adoc`.

== ReScript Block-Module Disposition: One Module Per File (ADR-017)

ReScript `module Name { … }` block modules have no AffineScript block
form: the grammar (`parser.mly:130-134`) is a single optional
`module Path;` *header*, before imports — `module A { }` parse-errors.
ADR-011 already settled "real modules": *the file is the module*. The
estate ReScript→AffineScript ports (#229) carry block modules — a single
one per file is mechanical (hoist the header, drop the braces, dedent;
already in the #229 canonical map and verified to parse), but *multiple*
block-modules in one file (e.g. `standards/lol/.../OpenCyc.affine`:
`module Config { } module Concepts { } module Types { } …`, 14 estate
occurrences) had no clean target. Escalated language-side as ESC-04
(#262), the same bidirectional-evidence discipline as ADR-014 / #228.

Decision: *one module per file — split, do not nest.* Each ReScript
`module X { body }` becomes its own `X.affine` whose first declaration is
`module X;`, body dedented, `use` imports after the header. A file with N
block-modules is split into N files. The grammar is **not** extended with
a block/nested-module form: that would contradict ADR-011 (file = module)
and is a major, conflict-risky grammar change for cosmetic gain — exactly
the contortion ADR-012 forbids. No language/compiler change is needed
(the file-header form already parses); this ADR settles the *porting
doctrine* + the #229 canonical-map structural rule.

Adjacent, explicitly NOT in scope here: a split file still hits
`Resolve.UndefinedModule` until the repo's module-path↔file-layout
matches the loader — that is cross-module graph coherence (INT-02
loader-bridge territory), tracked in `RESCRIPT-ELIMINATION.adoc` Tier-4
and the INT-02 ledger, never conflated with this disposition.

This decision is settled; do not reopen without amending the ADR. Full
ADR in `.machine_readable/6a2/META.a2ml` (ADR-017); #229 canonical map in
`docs/RESCRIPT-ELIMINATION.adoc`; escalation issue #262.

== No Raw/FFI Escape: Typed `extern` Is the Only Host Bridge (ADR-018)

ReScript `%%raw("<host source>")` / `%raw` injects arbitrary untyped host
Expand Down
Loading