Found building EigenOS M13-2 (the .eigs protocol tower): a hosted twin harness defined sent is [] (a frame-capture list), then import icmp — a module whose top level declares sent is 0 as its own counter. The module's top-level assignment did NOT create module state: it rebound the IMPORTER's sent, and every later use of sent inside the module's functions resolved to the importer's variable.
Minimal repro (current main, aa8638a):
# cmod.eigs
counter is 0
define bump() as:
counter is counter + 1
return counter
# main.eigs
counter is [9, 9, 9]
import cmod
print of (type of counter) # num <- importer's list clobbered by module init
print of (cmod.bump of []) # 1 <- module state lives in the importer's scope
print of (type of counter) # num
Expected: a module body executes in its own scope; counter is 0 at module top level creates the module's binding regardless of what the importer's scope holds. SPEC's "Module write boundary" fixed module FUNCTIONS (#373: a function's bare write can never bind through), and its parenthetical "(Top-level statements in the loaded file still execute directly in the current scope.)" is documented for load_file — but the same leak through import breaks module isolation: whether a module's state is module-scoped depends on the importer's incidental variable names. With common names (sent, count, state) this silently cross-wires two unrelated states; the failure I hit surfaced as cannot apply '+' to list and num two layers away, and the quiet variant (both numbers) would be silently wrong instead.
Suggested fix: module top-level bare assignment should bind in the module scope (never walk past the module boundary), mirroring the #373 rule one level up. load_file keeps its documented current-scope semantics.
Workaround used in EigenOS meanwhile: collision-proof harness names (t_sent, ...).
Found building EigenOS M13-2 (the .eigs protocol tower): a hosted twin harness defined
sent is [](a frame-capture list), thenimport icmp— a module whose top level declaressent is 0as its own counter. The module's top-level assignment did NOT create module state: it rebound the IMPORTER'ssent, and every later use ofsentinside the module's functions resolved to the importer's variable.Minimal repro (current main, aa8638a):
Expected: a module body executes in its own scope;
counter is 0at module top level creates the module's binding regardless of what the importer's scope holds. SPEC's "Module write boundary" fixed module FUNCTIONS (#373: a function's bare write can never bind through), and its parenthetical "(Top-level statements in the loaded file still execute directly in the current scope.)" is documented for load_file — but the same leak throughimportbreaks module isolation: whether a module's state is module-scoped depends on the importer's incidental variable names. With common names (sent,count,state) this silently cross-wires two unrelated states; the failure I hit surfaced ascannot apply '+' to list and numtwo layers away, and the quiet variant (both numbers) would be silently wrong instead.Suggested fix: module top-level bare assignment should bind in the module scope (never walk past the module boundary), mirroring the #373 rule one level up. load_file keeps its documented current-scope semantics.
Workaround used in EigenOS meanwhile: collision-proof harness names (t_sent, ...).