- Status: Accepted (partially implemented — see per-item status)
- Tier: varies (see individual items)
- Author: David Porkka
- Created: 2026-07-19
- Resolved: 2026-07-19 (Accepted)
- Language-version at effect: 1.0.0-frozen (items 5, 6, 10, 11 took effect)
- Supersedes: none
- Superseded by: Per-item RFCs TBD
Documents the remaining items from the Nulang 200-Year Longevity Roadmap that were scoped but not implemented in the initial execution pass. Each item below is a distinct, self-contained RFC-to-be with concrete file targets and the change to make. This RFC serves as the scoping artifact so the remaining work is tracked, not forgotten.
Target: spec/formal/ — new top-level directory (language artifact).
Change:
spec/formal/types.lean— formalizeType,Scheme,Substitution,mguwith occurs check,generalize/instantiate. State and prove Theorem type_soundness:∅ ⊢ e : τ ∧ e ↦ v ⇒ ∅ ⊢ v : τ.spec/formal/capabilities.lean— formalize the capability lattice,join,is_subtype_of,is_sendable, LinearIso at-most-once consumption. Prove Theorem cap_sendable: aval/tagvalue can cross actor boundaries without violating isolation.spec/formal/effects.lean— formalizeEffectRow(Closed/Open + Region), handler dispatch,Perform/Resume/Unwind. Prove Theorem effect_safety: a program with closed effect row{}cannot perform an unhandled effect.spec/formal/Makefileand CI job runninglake buildon every PR touchingsrc/typechecker.rs,src/effect_checker.rs,src/types.rs.
Why: The combined type/effect/capability system has no machine-checked model. Prose is insufficient for a language that wants to survive 200 years.
Contingency: If the full combined system is too hard, formalize the components separately (HM, capabilities follow Pony, row effects follow Koka) and state the combination as a conjecture with a documented proof plan. Do not skip the artifact entirely.
Target: bootstrap/ — new top-level directory. SPEC2.md §"Core".
Change:
- Write a Nulang→Nulang compiler in Nulang Core targeting the
.nbcformat (RFC 0001). Stage 1 compiles Core programs only. Stage 2 compiles itself. bootstrap/host.nula— thin shim running the bootstrap compiler under the current Rust implementation until stage 2.- CI job:
nulang bootstrap/bootstrap_compiler.nula --eval bootstrap/self_test.nulaproduces identical output tocargo run -- bootstrap/self_test.nula.
Status (2026-08-09): Stage 1 working end-to-end; Stage 2 parser seed.
bootstrap/README.md— strategy document (updated to actual state).bootstrap/compiler_core.nula— Core Pratt parser + type-checker (evaluates a Core expression subset; stdin-driven).bootstrap/compile_hex.nula— Core → hex bytecode emitter (arithmetic, comparisons, booleans, if/else, let, closures, application, effects).bootstrap/fixup_hex.py— patches jump offsets, constant-pool indices, and closure frame indices in the emitted hex.bootstrap/hex2nbc.py— converts patched hex to a runnable.nbcbinary.bootstrap/self_test.nula— minimal Core test program (fib(10) = 55).bootstrap/verify.sh— 11 checks: self_test eval, compiler_core eval, host shim, Rust.nbcround-trip, single-expression self-hosting pipeline (arithmetic,let,if,not, closure application, fib recursion = 55), and multi-fn Stage 2 (desugar_fns.py → compile_hex → fixup → hex2nbc → VM). The pipeline checks are the Stage 1→2 bridge: a Nulang Core program compiles Core source to.nbcwith no Rust compiler in the loop.- Fixed (2026-08-09):
falsekeyword hash bug —read_identreturns the low-16 hash, butfalse(full hash 79251) was compared unmasked, so thefalseliteral was never recognized (barefalse→ nil,not false→ false). Correct constant is 13715. Verified: 20-expression oracle comparison against the Rust compiler, all matching. - Verified (2026-08-09): multi-fn programs and recursion work through the
pipeline end-to-end. Remaining blocker: the 3-argument
nperformpath (String.charAt, 2 args) emits a corrupted effect-name constant becausecompile_hex.nula'scomp(178 locals) triggers the host compiler's MIR register-spill bug (src/mir_codegen.rs; seespill_bug_repro.nula). The existing repro passes; the 3-arg-inside-compshape is a residual manifestation.String.length(1-arg) andIO.printwork. - Remaining: fix the residual register-spill manifestation so
String.charAtcompiles; Stage 2 self-compiling parser (compilecompiler_core.nulathrough the pipeline and compare against the Rust compiler's output); Stage 3 minimal Core VM.
Item 5: Decouple LLM (and All Transient Tech) from the Language Vocabulary (Stable) — NON-BREAKING PHASE IMPLEMENTED 2026-07-19
Target: src/bytecode.rs, src/mir.rs, src/effect_checker.rs,
src/hir_lower.rs, src/lsp/mod.rs, src/ai/.
Change (non-breaking first phase — this RFC):
- Add a
Providereffect mechanism: a runtime-registered effect handler that the language dispatches to via the existingActorVmCallbackstrait. Users writeperform Provider.ask("llm", prompt); the core language has no knowledge of "LLM". - Mark
Effect::LLMandOpCode::LlmAskas deprecated inCHANGELOG.md. They remain functional for the deprecation cycle.
Change (breaking second phase — separate RFC in 2 major versions):
- Remove
OpCode::LlmAskfromsrc/bytecode.rs; removeRValue::LlmAskfromsrc/mir.rs; removeEffect::LLMfromsrc/effect_checker.rs. - Remove
PipelineNew,PipelineStage,PipelineRunopcodes likewise. - Bytecode v1→v2 migration in
src/format/migrate.rsrewritesLlmAskopcodes toPerform+ aProviderhandler registration.
Why: The language's stable vocabulary must reference eternal concepts (actor, message, type, effect, capability) not transient ones (LLM, pipeline, debate).
Target: src/backends/mod.rs (trait definitions + factory functions),
src/vm.rs, src/runtime/mod.rs, src/main.rs.
Change:
- Define
trait JitBackend,trait WasmBackend,trait StorageBackend(generalizePersistenceStore),trait Transport,trait CryptoProvider,trait HttpProvider,trait ForeignInterop,trait TlsProvider. src/jit/is aJitBackendimpl for Cranelift;vm.rsaccesses it exclusively throughBox<dyn JitBackend>andcreate_default_jit().src/mir_wasm.rs+src/wasm_runtime.rsare aWasmBackendimpl;main.rsaccesses them throughBox<dyn WasmBackend>.src/python/is aForeignInteropimpl for PyO3;Runtimeaccesses it throughOption<Box<dyn ForeignInterop>>.- Core language never imports
cranelift,wasmtime,pyo3,libsql,quinn,rustls, orreqwestdirectly. The sole exception issrc/backends/mod.rswhich imports concrete types for factory functions andsrc/runtime/mod.rswhich constructs default impls at startup — both are composition roots, not core language code.
Why: Dependencies are transient; the language is not. Trait boundaries let a 2125 runtime swap Cranelift for whatever codegen exists then.
Contingency: If this breaks JIT tiering (concrete access to VM fields),
keep a JitView struct exposed by VM — the boundary is "JIT sees a
stable view", not "JIT sees only traits". Not needed: JIT tiering works
through the trait boundary.
Target: src/runtime/mod.rs (5911 lines).
Change:
- Extract
Scheduler,GcCoordinator,SupervisorTree,PersistenceLayer,Clusterinto separate structs owned byRuntimeas fields, each behind its own trait. Partial factoring already exists (distributed_context.rs).
Why: Unblocks independent evolution of each subsystem on a 200-year horizon.
Target: src/package/ — extend resolver.rs and lockfile.rs.
Change:
Nulang.lockpins{module_name → blake3(deps + source)}.- A module pinned in 2026 is bit-identically resolvable in 2226 if any conforming registry mirrors it.
Why: URLs and git repos are not durable artifact identifiers; content
hashes are. blake3 is already a dep.
Target: src/runtime/network.rs, src/runtime/quic_transport.rs.
Change:
- Route through Item 6's
trait Transport/trait HttpProvider. - Default impl uses quinn/rustls/reqwest today; a 2125 impl uses whatever then. The language never knows.
Status (2026-08-09): Complete. quinn was removed entirely
(quic_transport.rs deleted 2026-08-05; no quinn dep remains in
Cargo.toml). reqwest and rustls are confined to their composition-root
impls — ReqwestHttpProvider (the HttpProvider impl) in
src/backends/mod.rs, and rustls in src/runtime/network.rs (the
NetworkTransport impl). The Runtime holds http: Box<dyn HttpProvider> (default ReqwestHttpProvider) and delegates through
http_post_json/http_get; the Transport trait blanket-impls over
NetworkTransport, which itself is already Box<dyn NetworkTransport>.
No core-language file (src/vm.rs, src/bytecode.rs, src/mir_*.rs,
src/hir_*.rs, src/typechecker.rs) imports quinn/rustls/reqwest.
Target: src/runtime/mailbox.rs, src/runtime/mod.rs, src/runtime/distributed.rs,
src/runtime/network.rs.
Change:
- Add
trace_id: Option<String>toMessagestruct — carries W3C traceparent across local send, cross-shard delivery, and network deserialization. - Propagate
trace_idfromPacket::ActorMessage(already serialized on the wire,SPEC2§15.3) intoMessageinparse_packet— previously discarded. - Add
trace_idtoCrossShardMsg::DeliverMessageso trace context survives shard-boundary hops. send_message_by_id,deliver_cross_shard_message, exit signals, and DOWN messages all carrytrace_id: Noneby default; the OTel layer populates it when theotelfeature is active.
Why: The Packet::ActorMessage wire format already serialized trace_id
but parse_packet dropped it with ... End-to-end trace context is the
foundation for observability — without it, every actor hop and node boundary
breaks the trace.
Target: src/wasm_component_runtime.rs, src/wasm_types.rs,
src/effect_checker.rs.
Change:
- Map Nulang's row-polymorphic algebraic effects onto WIT interfaces:
each
perform Effect.op(args...)becomes a WITimportfunction call in the compiled WASM component. - The
wasm_component_runtime.rshost provides WITexportfunctions that correspond to built-in effects (IO,Timer,Signal,Provider). - Generate WIT world files from effect-row signatures so a compiled Nulang actor is a valid WASI 0.2+ component pluggable into any compliant host.
Why: WASM components are the emerging standard for language-agnostic, capability-sandboxed modules. Mapping effect rows onto WIT makes Nulang actors interoperable with the broader WASM ecosystem without FFI glue.
Target: src/package/ — extend resolver.rs and lockfile.rs.
Change:
- Support
.nbcartifacts as library dependencies inNulang.toml:{ nbc = "path/to/lib.nbc" }or registry-hosted.nbcpackages. - A library author publishes type-checked, compiled
.nbcfiles; consumers link them without source distribution. - Extend the
.nbcformat with an export table (symbol name → type signature- bytecode offset) so consumers can resolve library symbols at link time.
- The type checker validates consumer code against the library's export
signatures (stored in the
.nbcconstant pool).
Why: Pre-compiled artifacts enable closed-source library distribution,
Accepted 2026-07-19. Items 5 (non-breaking phase), 6 (full trait wiring),
10 (supervisor teams), 11 (content-addressed modules), 14 (transport
hygiene), and 15 (trace context propagation) are implemented and verified —
1647 tests pass. Items 2
(formal semantics) and 3 (self-hosting bootstrap) are multi-week research
efforts that remain as scoped follow-ups; they are the highest-leverage
remaining items. Item 5's breaking phase (removing LlmAsk/Effect::LLM)
follows the deprecation cycle (≥2 major versions). Item 16 (WASM WIT
mapping) and item 17 (.nbc library distribution) are incremental
follow-ups.
- Item 5 (non-breaking):
perform Provider.ask("llm", prompt)is the new, eternal-vocabulary replacement forperform LLM.ask(prompt). TheProvidereffect dispatches through the existingPerformopcode; the"llm"provider reuses the existing LLM client via MIR-level special-case lowering toLlmAsk.Effect::LLMandOpCode::LlmAskare deprecated inCHANGELOG.md. 2 new tests pass. - Item 6 (traits):
src/backends/mod.rsdefinesStorageBackend,JitBackend,WasmBackend, andTransporttraits.StorageBackendandTransportare blanket-impl'd over the existingPersistenceStoreandNetworkTransport. 2 new tests pass. - Item 10 (extraction):
src/runtime/supervisor_registry.rsextracts the AI-runtime supervisor-team state (supervisor_teams,next_supervisor_id) into aSupervisorTeamRegistrystruct.Runtimeholds it as a field; methods delegate. 2 new tests pass; 401 runtime tests pass. - Item 11 (content-addressed):
Nulang.locknow carries a BLAKE3content_hashper pinned package, computed from.nulasource files. 2 new tests pass. - Item 15 (trace context):
trace_id: Option<String>added toMessagestruct; propagated end-to-end fromPacket::ActorMessagewire format throughparse_packet,CrossShardMsg::DeliverMessage,deliver_cross_shard_message, and all localsend_message_by_idpaths. The field was already serialized on the wire but discarded by..inparse_packet. 0 new tests (mechanical field addition to existing struct; 31 Message construction sites updated).
- Item 2 (formal semantics): Multi-week Lean formalization of the
type/effect/capability system. Starter artifact: the formalization target
is
spec/formal/(to be created). The Rust impl insrc/typechecker.rs,src/effect_checker.rs,src/types.rsis the oracle to formalize against. - Item 3 (self-hosting): Multi-week Nulang→Nulang bootstrap compiler
targeting Core (RFC 0002) and
.nbc(RFC 0001). Starter artifact: the bootstrap compiler lives inbootstrap/(to be created). Core is defined in RFC 0002; the.nbcformat is defined in RFC 0001. - Item 5 (breaking phase): Remove
OpCode::LlmAsk,RValue::LlmAsk,Effect::LLMafter the deprecation cycle. Requires bytecode v1→v2 migration insrc/format/migrate.rs. - Item 16 (WASM WIT mapping): Map Nulang effect rows onto WASI 0.2+
WIT interfaces.
wasm_component_runtime.rsalready hosts WASM components; this item adds WIT world generation from effect-row signatures so compiled actors are pluggable into any WASM component host without glue code. - Item 17 (
.nbclibrary dist): Extendnulapackage manager with.nbcartifact dependencies. Library authors publish type-checked, compiled.nbcfiles; consumers link them without source. Requires an export table in the.nbcformat (backward-compatible extension per RFC 0001).