Repository navigation
ESTATE: total ReScript-surface elimination from all .affine (committed goal; blocked-on #228) #229
Description
Is your feature request related to a problem? Please describe.
A subset of estate .affine files are unfinished ReScript→AffineScript hand-ports:
the file declares itself AffineScript (module …;) but the body still carries
ReScript surface syntax. A .affine file with ReScript syntax is neither valid
ReScript nor valid AffineScript — it is debt in limbo, and it cannot be
oracle-certified.
Found in the estate dialect-conformance audit (oracle main.exe check over 28
repos / ~1177 .affine on origin/main). Confirmed ReScript-surface
constructs seen in .affine: array<T> / option<T> / Dict.t<T> generics,
mutable record fields, type rec, open Mod, %%raw(\…`), (~x) => …arrow-fn,List(X)(vsList[X]), JSON.t, import … as`.
This is a committed goal: total elimination of ReScript surface from every
estate .affine file. The end state is that every .affine parses and checks
on affinescript main, with zero ReScript syntax remaining.
Describe the solution you'd like
Per-repo, oracle-validated RS→AffineScript completion ports, sequenced after
#228:
- Blocked-on LANG: type/effect grammar has no module-qualified path —
Pkg.Type/Pkg.Effectunrepresentable (estate-wide port blocker; ADR-014) #228 (ADR-014, module-qualified type/effect path). The oracle
stops at the first parse error. Today only ~22 files fail first on RS
surface — a floor, not the truth: e.g. burble has 19 first-fault-RS files +
16 that fail first onExterns.Foobut are the same RS port with RS
surface hidden behind the qualified-path fault. Until LANG: type/effect grammar has no module-qualified path —Pkg.Type/Pkg.Effectunrepresentable (estate-wide port blocker; ADR-014) #228 clears
qualified-path faults, each file's full RS inventory is invisible and a port
cannot be re-validated. LANG: type/effect grammar has no module-qualified path —Pkg.Type/Pkg.Effectunrepresentable (estate-wide port blocker; ADR-014) #228 landing is what makes a complete and
verifiable RS sweep possible. - Re-audit after LANG: type/effect grammar has no module-qualified path —
Pkg.Type/Pkg.Effectunrepresentable (estate-wide port blocker; ADR-014) #228: rebuild oracle, re-run/tmp/affine-audit/audit.sh,
produce the true per-file RS construct inventory. - Derive the RS→AffineScript canonical map from the language side, not
guessed.array<T>→List[T]is mechanical, butmutablefields,
Dict.t,type rec,%%raw,(~x) =>map onto the affine/ownership model
and several are redesigns. Any construct with no clean target is escalated
as its own language-side issue/ADR (bidirectional evidence — same discipline
that produced LANG: type/effect grammar has no module-qualified path —Pkg.Type/Pkg.Effectunrepresentable (estate-wide port blocker; ADR-014) #228), not patched divergently across N repos. - Per-repo branch + PR, each oracle-validated locally before push (estate
CI does not compile.affine), squash-merge, noreply author. - Per-repo hands-off confirm before touching: policy hands-off is the
ReScript ecosystem (.res);.affine-with-RS is an in-scope unfinished
port — but confirm per repo it is an intended AffineScript target, not a
deliberate interop artefact, before removal (burble's standing caveat).
Describe alternatives considered
- One mechanical estate-wide sweep now. Rejected: ports blind in files that
cannot be re-validated until LANG: type/effect grammar has no module-qualified path —Pkg.Type/Pkg.Effectunrepresentable (estate-wide port blocker; ADR-014) #228 (unsound-codemod trap), and treats semantic
RS→affine transforms as cosmetic. - Leave as permanent "residue". Rejected — this is the user-committed goal:
zero ReScript surface in any.affine.
Additional context
- Blocked on: LANG: type/effect grammar has no module-qualified path —
Pkg.Type/Pkg.Effectunrepresentable (estate-wide port blocker; ADR-014) #228 (type/effect qualified-path grammar, ADR-014). - STAGE-C peer. Refs stdlib Http: typed-wasm target (convergence ABI; shared with Ephapax) #225, stdlib: portable Http.fetch (body/headers/methods/response) #160 — not "Closes" (multi-repo, sequenced,
human-gated). RS→affine target forms must equal the LANG: type/effect grammar has no module-qualified path —Pkg.Type/Pkg.Effectunrepresentable (estate-wide port blocker; ADR-014) #228/STAGE-C canonical. - Largest known port: burble (~35
.affine, whole-repo RS port). Other
RS-bearing repos surfaced by the audit: idaptik-dlc-vm, git-scripts,
game-server-admin, invariant-path (+ any revealed post-LANG: type/effect grammar has no module-qualified path —Pkg.Type/Pkg.Effectunrepresentable (estate-wide port blocker; ADR-014) #228 re-audit). - Audit artefacts:
/tmp/affine-audit/{results.tsv,drift_lines.txt,audit.sh}.
Method: buildbin/main.exe,AFFINESCRIPT_STDLIB=$PWD/stdlib,
main.exe check, classify on stdout (Type checking passedvsparse error). Estate repo CI is not an affine oracle — local build only.
Activity
docs: truth CORE-03 / ADR-014 grammar landed (PR #241) (Refs #175 #176 …
docs: authoritative ledger — CAPABILITY-MATRIX/ECOSYSTEM/TECH-DEBT (R…
feat(parser)!: ADR-014 — module-qualified type/effect paths (Refs #228)
feat(parser)!: ADR-014 — module-qualified type/effect paths (Refs #228)…
docs(estate): #229 ledger — oracle-grounded corrections (Refs #229)
docs(estate): #229 foundation — post-#228 re-audit, RS inventory, can…
docs(estate): #229 ledger — oracle-grounded corrections (Refs #229)
docs(estate): #229 foundation — post-#228 re-audit, RS inventory, can…
docs(estate): #229 ledger — record-sigil correction + string `++` + 3…
docs(estate): #229 closure status — completable done, false scope rem…
docs(adr): renumber block-module ADR 016->017 (main merged a different …
feat(stdlib): ESC-02 — portable Json primitive (Refs #161 #246 #229) (#…
docs(adr): ESC-01 — ADR-018 no raw/FFI escape, typed extern only (Refs …
feat(stdlib): ESC-03 — Dict/Map keyed container (Refs #162 #247 #229)
docs(adr): ESC-04 — ADR-017 ReScript block-module disposition (Refs #262
feat(stdlib): ESC-03 — Dict/Map keyed container (Refs #162 #247 #229) (…
docs(adr): ESC-04 — ADR-017 ReScript block-module disposition (Refs #262
chore(fixtures): delete stale SafeDOMExample.res ReScript fixture (Re…
hyperpolymath commentedon May 27, 2026
Cross-reference (triage 2026-05-27): scope-disambiguated against #230 and #392 — these three are distinct, not consolidatable.
array<T>,mutable,type rec,%%raw,(~x) =>etc.) from.affinefiles in independent consumer repos (burble, idaptik-dlc-vm, git-scripts, game-server-admin, invariant-path). Blocked-on LANG: type/effect grammar has no module-qualified path —Pkg.Type/Pkg.Effectunrepresentable (estate-wide port blocker; ADR-014) #228. Per the ESTATE: de-vendor embedded affinescript trees (bofj-kitt / proof-burrower / developer-ecosystem) #230 comment, the 3 vendored-tree repos (bofj-kitt / proof-burrower / developer-ecosystem) were reclassified OUT of ESTATE: total ReScript-surface elimination from all .affine (committed goal; blocked-on #228) #229 because their flagged files were vendored copies of the affinescript repo, not consumer drift. ESTATE: total ReScript-surface elimination from all .affine (committed goal; blocked-on #228) #229 will not re-list them.Pkg.Type/Pkg.Effectunrepresentable (estate-wide port blocker; ADR-014) #228.affinescript-*subtrees to their own repos (or to developer-ecosystem/) #392 — extraction: push five misplaced subtrees (affinescript-vite/,affinescript-dom/,affinescript-pixijs/,affinescript-tea/,affinescriptiser/) OUT of the affinescript repo itself into their proper homes (developer-ecosystem monorepo or standalone repos). Reverts the 2026-04-22 consolidation mistake. Independent of LANG: type/effect grammar has no module-qualified path —Pkg.Type/Pkg.Effectunrepresentable (estate-wide port blocker; ADR-014) #228.Directions and target sets are disjoint. Consolidation is not safe.
hyperpolymath commentedon Jun 1, 2026
Status update — AS stdlib codegen pattern now established (2026-06-01) 📌
For ticket coordinators / anyone tracking this gap:
lib/codegen_deno.ml. Tests live intests/codegen-deno/*.What this means for the gap tracked in this ticket:
stdlib/*.affine→ wire indeno_builtinstable + prelude → smoke-test intests/codegen-deno/*.🤖 Cross-estate AS-status sweep on 2026-06-01.
feat(lang): `const mut <name>: T = init;` module-level mutable binding (
feat(parser): accept slash-effect-row in type-expression position (cl…
hyperpolymath commentedon Sep 19, 2026
Status measured today (2026-09-19) — the block is cleared and two of the five repos are already clean.
blocked-on #228no longer applies: #228 is implemented in full (parser layer in #2415cca379, typecheck slice since landed —strip_module_qualifier,Module_resolution_error,module_quals,UnknownModule, with the four proposed tests intest/test_qualified_paths.ml).ReScript surface remaining in
.affinefiles:.affinefilesclient/web/src/bindings/PhoenixSocket.affine,client/web/src/app/voice/VoiceEngine.affine,client/web/src/app/voice/VoiceControls.affineui/src/HarApi.affine,ui/src/App.affineSo the work is now concrete: five files across two repos, plus one stale repo reference in this issue's own scope list. Keeping it open — that is a real residual, not a duplicate.