# Use Versioned Logical Binding Identities ## Problem Continuous computation cannot depend on whether a previous cell happened to use an import, a persistent native lexical declaration, or a particular destructuring form. Reusing one native declaration environment couples source names to immutable storage choices. Renaming later occurrences alone also changes what existing closures observe, and recording every parsed declaration publishes names whose initializers never ran. Reinterpreting old journal source under repaired rules can silently change state even when recorded completions still match. ## Decision PTC Plus compiles each new cell into a private native frame and retains session state through logical identities. `internal/repl-scope-normalizer.js` owns formal scope and activation analysis; `internal/stateful-root-compiler.js` owns root declaration and reference plans; `internal/stateful-root-runtime.js` owns their live values and sources. The existing kernel, queue, leases, cancellation, budgets and DSH authority remain authoritative. This partially supersedes the new-cell behavior in [ADR 0006](0006-rewrite-module-syntax-with-an-ast.md), [ADR 0012](0012-preserve-mixed-destructuring-initialization.md) and [ADR 0013](0013-isolate-repl-redeclaration-convenience.md). Their historical language behavior remains executable for recorded legacy cells. The public `bindingUpdates` policy selects `stateful` or `protected`. Stateful declarations and assignments update the same identity within a scope and activation. Local `const` is writable under this selected dialect. `var` retains its function/root owner; blocks, parameter environments, catch, switch and iterations retain their own activation rules. Existing closures read the current identity; saving a function or object value preserves that value. A bare identifier declaration ensures existence without clearing an existing value. Each declarator publishes all candidate values only after its initializer and binding pattern complete. Separate declarators commit in order; ordinary assignments retain their actual partial-write effects. Hoisted values publish at scope instantiation, while unreached lexical declarations remain unproved. Import aliases use the same identity with a live module source. An actual successful write changes only that alias to a local value; a later static import reinstalls a module source. Static dependencies link before body execution and retain Node resolution, attributes, caches and effects. Named default declarations associate `__default` with their logical identity until it is independently overwritten. Real modules expose a PTC-managed namespace with their actual export names, including `default`; the cell-only `__default` convention does not apply. `internal/stateful-module-compiler.js` is the common module entry for binding validation, candidates, activation, workbench sources and the user module graph. `code.run` executes the selected language in an independent state owner while preserving the native tool dispatch and authority boundary. Protected mode retains native local declaration restrictions, rejects replacement of an existing root identity before execution, and protects newly created const/import bindings. It does not freeze identities already created writable or reset the worker. An explicit later stateful cell can revise earlier protected state. Generated helper identities are private implementation details and never become user catalog entries. The shared TypeScript value normalizer handles enum, const enum and namespace declarations before value ownership, export descriptors and callable reflection are derived. Runtime enums retain their objects and member reads instead of depending on constant inlining across compilation units. Ambient and type-only declarations remain erased. Binding descriptors retain original source type-name evidence while consuming the same normalized runtime declarations as modules. `compiler-intrinsics.js` captures emitted helper and runtime bookkeeping operations before an owned realm executes user code. Cell preparation connects recorded helper declarations to the existing root runtime; module preparation uses the module owner. CommonJS bootstrap dependencies are declared by the compiler-link owner. Conflicting source bindings and their declaration peers use the shared logical cells, including protected and post-transform legacy entries, while retaining native declaration validation, protection, initialization order and wrapper activation. Internal argument and metadata transport does not inherit user array species behavior. This ownership continues through runtime consumers: module graph records, logical roots, legacy dynamic adapters and their publication callbacks use captured collection and reflection operations. Source getters and callbacks retain their actual effects and identities. `compiler-service.js` is the synchronous preparation boundary for cells, modules, dynamic source, workbench completion and binding-source metadata. The compiler and its maintained JavaScript dependencies execute in a private VM realm. This realm owns no user program values, module graph, journal or authority. `compiler-platform.js` captures text codecs, hashing, URL, source-map and VM operations before user execution, independently of later prototype or synchronized Node ESM export changes; `compiler-platform-factory.js` creates the dependency interfaces in the compiler realm. Compiler-local dependencies own path operations and bounded raw-DEFLATE compression. Compiler transforms disable external configuration discovery. `compiler-data.js` reconstructs request and result collections and packed source maps; diagnostics regain their caller-realm error classes. Original callable-source lookup is a synchronous string-only callback. Executable cell parsing removes TypeScript syntax with the pinned Amaro eraser whenever the host's experimental stripper refuses an input, so erasure and its source positions do not depend on the host Node release. `module-compilation.js` returns code, source maps, export descriptions and static-link/source-registration facts. `stateful-module-compiler.js` consumes those facts and owns the existing public Node hooks, filesystem format selection and runtime registration. Compilation does not install hooks or reserve live module identities. Generated compiler bundles and maps must match their build sources; verification must account for private-realm execution against the original compiler files. Build and package procedures belong to [Publishing](../publishing.md). The VM and compiler work remain inside the existing worker budget and lifetime. The private platform loads optional Amaro and TypeScript compilers only when a transform requires them, from fixed packaged artifacts into the same compiler realm. Each operation holds its dependency exports during use; weak caches between operations allow unused code and WASM data to be reclaimed. Dependency artifacts do not install global exports, so their lifetime is independent of the core compiler. Packaged code uses compact emission with original-source maps. The build extracts large dependency string arguments into content-addressed text assets, preserving their exact UTF-16 values and source mappings. The platform reads only entries in the generated asset manifest and does not cache asset contents; binary payload text need not remain pinned by script source or literal pools after consumption. Build validation derives required Node members from compiler-owner imports; platform tests exercise maintained dependencies' supported bootstrap, reclamation, lazy and fallback paths, including native type erasure. Disabled configuration-discovery paths do not grant compiler access to user files or configuration. Runtime ownership also covers implicit native protocols. `compiler-data.js` serializes internal keys from own data fields with null prototypes, so inherited source `toJSON` hooks cannot select graph identity. `compiler-descriptors.js` supplies own-field descriptor construction, reads and writes, including internal Proxy descriptor transport to the service, platform and emitted realms; source reflection keeps native inherited-field semantics. `module-runtime-platform.js` captures the public hook registration/disposal lifecycle and URL operations for static, dynamic, require and CommonJS evidence adapters. `compiler-storage-source.js` supplies one emitted construction contract for internal weak collections, arrays and records, including captured iterator advancement, stack operations and private Promise observation. Runtime capture and standalone source reconstruction consume the same contract. `compiler-record-roles.js` proves generated plain-data record privacy from binding consumers, aliases and bound helper parameters before operation emission. Unknown calls, publication, own accessors or operations that can expose the record as a receiver deny the proof. Public decorator contexts, access objects and accessor values retain ordinary source-facing prototypes and property effects. Late dynamic environments derive ToObject and error operations from their captured realm. Compiler-service classifies compilation errors using its captured constructor before reconstructing the selected execution-realm error. Exception provenance uses the same captured bookkeeping contract and never replaces the thrown value. Root storage attaches declaration metadata to the entry it actually creates or updates; request overlays do not imply an owned logical entry. `dynamic-scope-analysis.js` owns source-environment visibility, including parameter expressions and nested closures that cannot see function-body declarations. Native binding lookup, logical binding lookup and dynamic capture consume that same ancestry rule. [Semantic validation](../semantic-validation.md) separates preserved native behavior, intentional dialect contracts and generated boundary comparisons. Hosts without native explicit resource management use the maintained Babel resource transform after logical declaration ownership is established. Babel owns lexical lifetime and abrupt-completion routing. `compiler-resource-lowering.js` consumes its context binding identities and emits acquisition GetMethod, original disposer invocation and Await in the existing source activation. Its context holds only private stack, error and suppression state; no source getter or disposer runs inside a bookkeeping helper. Per-acquisition temporaries retain the original value through method lookup before declaration initialization. Disposal preserves async-from-sync result suppression and await gaps without source-function wrappers or helper Promise layers. The shared lowering retains disposal lifetime, captured intrinsics, binding policy and source maps across cells, modules and reconstructed callable source; resource syntax never changes a protected lexical declaration into a writable root variable. Module resource acquisition always uses an unexported lifetime binding, while exported values use the shared logical lexical cells. This separation also applies in protected mode: native engines can omit disposal for an exported using binding, and fallback transforms move declarations into a try region. Both paths retain readonly exports, TDZ and disposal at module completion. New-generation cell returns leave source scopes through a private labelled break with an inert completion value. Resource disposal and finally execute with native non-exceptional completion; the worker's existing completion signal is delivered only after those scopes exit. Normal fallthrough cancels a return overridden by finally, while declaration-only bookkeeping retains expression completions. Execution preparation owns the native async-arrow frame for cells that suspend, including async resources anywhere in that activation. Kernel and workbench consume its explicitly private Promise through the shared captured observer; Node's cross-realm REPL continuation cannot acquire source then/constructor/species protocols. Source return values retain owning-realm Await and their original identities. Synchronous evaluation and historical exceptional return lowering remain on their existing paths; the legacy generation keeps native REPL declaration instantiation. ## Language and recovery generations Journal version 9 requires the closed `languageSemantics` field: `legacy-v1`, `stateful-v1` or `protected-v1`. Versions 1 through 8 migrate to `legacy-v1`, preserving their independently recorded binding, rewrite, module, reuse and shadow policies. Replay selects the recorded compiler; live requests select the current configuration. Frozen `legacy-*` preparation, parser, module rewrite, convenience and catalog owners preserve historical semantics, including bare-declaration clearing and older import closures. A void completion does not justify substituting a newer compiler. This extends [ADR 0014](0014-persist-cell-rewrite-policy.md). The post-transform native adapter records physical lexical declarations independently of logical declaration kind. The binding catalog preserves those facts across revisions and supplies them to migration, dynamic selection and publication. Only a successful current storage probe proves initialization; static declaration facts cannot establish recoverability. An unrelated same-named global property cannot override proven initialized lexical storage or confer writability on absent or readonly storage. Binding snapshots likewise distinguish `amaro@1.1.11` from `stateful-module-v1+amaro@1.1.11`. Source metadata and fingerprints remain canonical; an unsupported transform cannot be silently replaced with the current transform. A generation change participates in module reuse identity. Actual worker initialization and source facts advance the catalog; parsing a declaration alone never proves that its value exists. Model-visible provenance, verified journal ancestry and the existing recovery contraction rule still bound every retained identity. Current protected module graphs use the distinct `protected-module-v1+amaro@1.1.11` compilation identity. They retain native declaration and import protection while sharing callable source facts, dynamic interfaces and module loading with current computations. This live module identity does not add a persisted binding snapshot transform or reinterpret historical modules. The catalog retains evidence of native legacy declarations separately from provider and logical-root sources. Migration uses that evidence and actual available storage to bridge writable native lexical, var and function bindings. Scalar and whole-pattern publication use the same storage operation, preserving old read/write closures; readonly captures retain their original storage. Ambient properties and provider activation do not become native declaration evidence merely because a property exists. Newly prepared legacy cells also bridge catalog-proved logical roots through their existing native dynamic environment. Initialized native lexical storage retains precedence; names without that storage use their established logical identity. Existing native closures and saved intrinsic interfaces keep their captured environments. Native declarations replacing import aliases or restoring deleted names publish after actual initialization is proved, and legacy settlement reconciles logical source and write facts even after failure. Switching policy therefore does not create a disconnected store for names established only in the logical root. Configuration migration runs before a schema default can erase whether `bindingUpdates` was omitted. A complete enabled old policy maps to stateful, a complete protected policy maps to protected, and mixed old choices retain explicit compatibility state. The settings card uses the same resolver and exposes old controls only for that compatibility state. Selecting a unified policy atomically records it and clears its compatibility marker. Stable model guidance derives from the same resolved language generation; changing session values never changes the prompt prefix. ## Dynamic compilation environments User-selected eval and Function compilation retain their native syntax goals, completion and effect behavior. The logical environment adapter must preserve direct eval's caller scope, indirect eval's realm root, Function constructors' owning realm and `with` object lookup. `dynamic-scope-analysis.js` owns the shared source facts for declaration ownership, initializer lookup and intervening eval activations; normalization and compilation consume those facts. `dynamic-environment-compiler.js` and `dynamic-environment-runtime.js` own the actual environments; entry integration and `dynamic-binding-evidence.js` connect executed declarations to the cell's source and catalog. Native syntax does not exempt logical environment continuity, and generated names must not become a new reason for valid source to fail. Eval checks lexical conflicts before initializing its ordered declaration plan. Global function declarations also retain native property eligibility checks before source initializers or body execution. A later global declaration failure preserves earlier declarations already established by Node's global environment; it does not execute the remaining body or erase those established values. Local and logical declarations retain their own environment rules. `dynamic-native-runtime.js` owns stable interfaces for exactly six native intrinsics: eval, the four Function constructors, and Function.prototype.toString. Owned entry points prepare these interfaces before source can capture them. `dynamic-native-calls.js` selects the owning realm and generation's interface at source value and invocation boundaries, including property reads, reflected native results and asynchronous resumption. Cells that only save an intrinsic value use the same boundary. Native and opaque consumers of these values therefore use the same interface as compiled calls. Direct eval recognizes the exposed identity but executes the captured original intrinsic with its explicit caller environment. Constructors delegate coercion, validation and newTarget prototype selection to their original native operation before adapting the resulting source. Canonical user functions and module namespaces are never wrapped by this interface. Separately created user realms retain their own intrinsics. All global and prototype properties retain their original native identities, including Function.prototype.toString. Replacing global eval would invalidate native direct eval in escaped legacy closures; replacing toString would invalidate their saved intrinsic identity observations. Temporary restoration around synchronous calls cannot preserve asynchronous continuations. Kernel ambient getters return the original values while retaining volatile-read accounting. `native-root-compilation.js` adapts legacy cells after frozen declaration lowering; `native-root-dynamic.js` supplies their stable legacy interface and retains helper ancestry through the existing import namespace owner. Legacy dynamic source uses the native REPL environment; new-generation source uses its logical root. Both consume managed module namespaces. Legacy compilation units keep their native declaration behavior, environments and saved interface identities before, during and after new-generation execution, including newly created legacy cells and modules after a mode change. Interface preparation never writes user-visible properties. Module runtime creation shares interfaces, intrinsic identity associations and source facts. Invocation context carries the selected runtime and source provenance through native and asynchronous callbacks; callbacks outside such an invocation use their interface's realm owner. Interfaces remain live while escaped values can use them and end with the owning realm. For legacy top-level await, `native-await-declarations.js` retains source declarations for Node's persistent root instantiation and function hoisting. Direct eval uses a separate cell activation inside that root and outside nested lexical scopes. Initializer writes retain native ordering, including partial destructuring writes on failure; indirect eval and Function continue to use the native realm root. Uncompiled VM source that independently fetches a native intrinsic retains its native engine behavior, including physical source reflection. An opaque observer supplied with the new-generation toString interface observes the compiler-proved original source. The adapter does not rewrite arbitrary returned strings, replace native prototype properties, or wrap ordinary user functions to simulate a different engine result. Ordinary source invocations execute through a captured native continuation in a compiler-owned realm. Its fixed eval body enters the invocation context, calls the original target through native reflection, and restores the context in `finally`. Native eval adds no callable activation between source caller and callee. This preserves native caller observations and cleans up exceptions thrown in parameter initializers, including when opaque code catches them. A private invocation record passes synchronously from source argument preparation to that continuation; it is consumed before any user code runs. Source parameters, declaration environments, function identities and user-visible realm properties remain intact. Tagged templates retain their native cached template object and evaluate substitutions before invocation validation. Member reads remain native expressions in the source caller. Preparation saves the receiver as its first argument and reads the member in its second, clearing its compiler temporary before any key or getter executes. Reentrant and suspended reads therefore retain the original receiver without retaining the last object in compiler storage. Object and primitive accessors, private members, Proxy traps and nullish errors keep their native property semantics. Internal argument lists and binding-descriptor transport use indexed compiler-owned operations instead of user array methods, species or iterators. `callable-source-facts.js` carries compiler-owned source marks through normalization and associates exact emitted callable text with original JavaScript source. The class owns its constructor's source identity. Type erasure preserves source text where possible; TypeScript runtime constructs require equivalent JavaScript initialization in the reflected source. Owned realms share these facts so module observers can receive canonical function values from another owned realm. Native toString validates its receiver first and consults those facts without invoking user code. A function reconstructed from that source retains its actual source dependencies; hidden compiler helpers do not become dependencies and unavailable user closure bindings do not become available. Decorator source reflection reuses the shared language lowerer. All callable identities and their enclosing private syntax contexts are recorded before reflected products are lowered. `callable-definition-environment.js` identifies parameters and computed keys that evaluate outside a callable's body scope, and emits definition frames that preserve suspension and lexical context. The normalizer establishes class names and per-evaluation initializer state before lowering; computed object-property names carry their natively coerced key into that evaluation without a shared cache. Reflection assigns each body the transitive helper dependencies proved by lexical bindings. Exact nested source aliases preserve this ownership through repeated reconstruction. Class fragments with contextual `await` or `yield` retain their native compilation-context requirement. Temporary expression containers supply that grammar without acquiring logical declaration identities, and are removed before emission. Execution retains native static blocks and source callable activations. Compiler source regions divide static native-call expansion and module emission by parser-proved output slots. A region introduces no runtime scope, activation or completion boundary. Complete declaration ownership remains with the shared scope facts; a partial grammar wrapper cannot establish lexical binding ownership. Lexical dynamic compilation retains its complete scope graph. Normalization releases declaration trees before materializing its numeric output pieces, and copied source ranges compose directly with their known mapping segments. Private module names use the shared allocator's compact, collision-safe representation; semantic consumers use explicit binding descriptors. Source maps use packed numeric runs for large outputs. Emitters' raw mapping points stream directly into those runs when available; encoded maps remain supported for other maintained transforms. Composition reuses known segments and endpoint lookups while retaining unmapped spans and EOF anchors. Native-interface adaptation consumes the normalizer's transport descriptors: private cell objects and operations remain internal, while their value properties retain user-value adaptation. A successful native-JavaScript parse permits reusing that proof through normalization and retaining the native generator's output when no resource lowering is needed; other inputs retain maintained TypeScript lowering. Module callable catalogs store shared compressed UTF-16 source blocks and ranges. Digests select candidates only; exact source comparison proves reflection identity without retaining overlapping whole-callable strings. `compiler-operations.js` indexes logical binding descriptors once per compilation and owns a separate operation plan for each AST region. Immutable descriptor indexes are shared; newly generated binding names, operation shells and explicit source-value boundaries belong to the region. Static and dynamic native-call adaptation consume the same planner. An internal operation's arguments can still contain source expressions that require adaptation; owning the operation never implies skipping those source subtrees. Generated helper calls and values do not recursively acquire source-call instrumentation. Dynamic frames expose one binding lookup/update contract. Logical roots implement that contract as a live view over continuous identities; map-backed activations use captured native operations through a stable adapter. Consumers preserve frame identity and do not assume every binding store is a native Map. The final module emitter may erase comments. Exact source-map segments relate emitted callable starts to their marked input owners; preparation restores each proven mark inside its final native source span before registering source facts. Identical emitted function bodies therefore retain distinct original sources. The final position map includes these insertions and CommonJS wrapper extraction. Callable catalogs cross the compiler boundary as data; the module runtime entry registers them before Node can expose hoisted exports to cyclic importers. Catalog registration does not add executable text or companion modules to the source. ## Managed module interface PTC owns a stable managed namespace for each compiled module identity. Reading a member resolves the current logical source and returns its canonical value. An import remains a live source until an actual successful write selects a local value. Saving a function or object saves that original value; passing a namespace to opaque code preserves its live member reads. Neither operation substitutes a forwarding function for the source value. Native exports may carry hoisted binding accessors as transport. Compiler and loader facts identify accessor, native, forwarding and namespace exports; ordinary function names or shapes are never transport evidence. Every PTC-owned import entry consumes this same interface, including static and dynamic imports, provided REPL require, compiled CommonJS require, bindings, candidates, the workbench and isolated children. Each compilation unit owns its import operation even when import syntax occurs only in runtime-created source; eval and Function retain that unit's resolution base. Node continues to own actual resolution, attributes, URL identity, native missing/ambiguous export checks, caches, top-level await and one evaluation. Accessors must be available at module instantiation, preserve lexical TDZ and retain early function identity without executing user initializers. Session transforms apply only to session-owned module sources. Files resolved beneath `node_modules` remain under Node's native compiler and loader ownership; PTC wraps their result at the managed namespace boundary when a PTC entry consumes it. External package code therefore keeps native evaluation and identity while PTC-owned callers still receive the documented live namespace behavior. CommonJS compilation retains original JavaScript export evidence separately from executable lowering. At actual module loading, an unreachable reexport points to a private source companion for Node's own CommonJS analysis. Literal require arguments in that analysis source preserve their raw spelling and receive private routing prefixes; detected reexports resolve through the complete public hook chain from the original CommonJS parent. The private resolution request ends before loading, and the original linker performs subsequent loading and value extraction. No companion body executes, no alternative export detector is maintained, and pure compilation allocates no native module identities. Prepared CommonJS modules carry the evidence through their loader metadata; source changes before import replace the current companion association. Named-export snapshots, default values and actual execution retain native CommonJS behavior. The managed namespace provides stable membership, readonly properties and live values; it does not claim Node's native module namespace brand or identity. Opaque code independently calling native import on a compiled raw URL, or acquiring a native require through createRequire, uses a separate native interface and can observe the transport representation. This boundary does not exempt any PTC-owned entry, any ordinary exported value, or a managed namespace supplied to an opaque function. Native-only providers keep their native namespace when no adaptation is needed. Namespace reflection, `then` exports, cycles, re-export chains and builtin updates before local override are acceptance conditions. The managed module entry and worker suites exercise the `node:fs` / `syncBuiltinESMExports` regression through actual imports and opaque namespace consumers. Private import adapters reuse native module identities while preserving each call's native option validation, source resolution and thenable assimilation; repeated imports do not allocate a new native module per call. ## Alternatives considered **Mirror values into native export slots.** An uncompiled provider has no general publication callback. After syncBuiltinESMExports changes a builtin export, a local mirror can be stale before any PTC code executes. Direct native forwarding follows that update but cannot later switch to a local override. Native namespace transparency therefore cannot own this dialect's writable-export semantics using current public Node APIs. **Continue adding exceptions around the shared native REPL.** Fixes for import-to-function, lexical-to-import, failed patterns and nested var would each need separate storage rules. Independent frames remove the representation conflict at its owner. **Rename each declaration to a fresh native variable.** This removes parser collisions but makes old closures observe old values and can publish half-initialized patterns. Formal logical identities and candidate publication express those contracts directly. **Make every write transactional.** Ordinary JavaScript assignments can perform effects before throwing. Rolling those back would misrepresent executed computation; only the declared candidate publication boundary is atomic. **Reset all state when policy changes.** This discards valid, model-known work and makes a presentation or configuration change an implicit state operation. Versioned code and identity access preserve existing values without reinterpreting historical closures. **Replay every history with the latest compiler.** Matching visible results cannot establish hidden state equivalence. Frozen generations retain the evidence contract; unsupported historical evidence contracts the frontier instead of blocking the current valid cell. **Replace Node with an independent interpreter.** A separate interpreter could own more compilation surfaces, but would duplicate Node module, object and capability behavior. PTC retains Node execution and adapts the compilation units it owns; user-selected external engines keep their native results. ## Consequences The dialect deliberately changes declaration and const-update behavior; it is not a claim of complete ECMAScript equivalence. AST-derived source mappings, candidate state, runtime publication facts and versioned history are maintained together. New syntax must enter the shared owners rather than acquire entry-specific exceptions. Tests discriminate values, closures, effects, scope lifetime and replay behavior, including failures with void completions. DSH tool names, arguments, approval, sandboxing, canonical values and model-visible state boundaries remain unchanged.