# 0.12.2 fallible runtime construction
Historical design and validation record for 0.12.2. API sketches, wire
shapes, toolchains, budgets and measurements refer to that release, not the
current implementation. For current guidance see [README](../../README.md),
[ADVANCED](../../ADVANCED.md) and [SAFETY](../../SAFETY.md).
## Confirmed risk
`MemoryRuntime::new(memory)` previously called
`ic_stable_structures::MemoryManager::init(memory)` immediately.
`ic-stable-structures` 0.7.2 treats any nonempty memory without its `MGR` magic
as a new manager: it writes a manager header and the bucket-allocation table.
That means foreign stable memory could be changed before ic-memory's
stable-cell and ledger validation returned a typed error.
This is distinct from allocation-ledger corruption. The mutation happens at
the outer `MemoryManager` substrate boundary, before the runtime can project
the ledger virtual memory.
## API hard cut
Construction is now fallible:
```rust,ignore
let mut runtime = MemoryRuntime::new(backing_memory)?;
```
There is no infallible constructor, compatibility alias, unchecked fallback, or
public reset path. `RuntimeConstructionError` distinguishes nonempty foreign
memory from a recognized `MemoryManager` magic with an unsupported layout
version.
## Preflight and ownership
The pinned dependency documents a four-byte prefix:
```text
bytes 0..3: MGR
byte 3: layout version 1
```
Construction classifies the raw backing memory before transferring it to
`MemoryManager::init`:
```text
empty
-> safe to initialize a new MemoryManager
nonempty + MGR + version 1
-> safe to load the current MemoryManager layout
nonempty + other magic
-> ForeignMemory, no write
nonempty + MGR + other version
-> UnsupportedMemoryManagerVersion, no write
```
Here, empty means `Memory::size() == 0`. A pre-grown blank memory is nonempty
and is rejected rather than treated as disposable storage.
The check requires only `M: Memory`; it adds no `Clone`, `Send`, `Sync`, or
`'static` bound. The format constants are private and explicitly coupled to the
pinned `ic-stable-structures` version because that dependency does not expose
a fallible manager constructor.
## Default TLS runtime
The one default thread-local owner now stores
`Result<MemoryRuntime<DefaultMemoryImpl>, RuntimeConstructionError>`. Default
operations use fallible `RefCell` entry as before, then propagate any
construction failure through `RuntimeStateError::Construction`. They do not
panic, retry initialization, replace the backing memory, or publish runtime
authority after a construction failure.
## Persisted-format assessment
No ic-memory stable-cell, protected commit-store, payload-envelope, allocation
ledger, format marker, version byte, or fixture changes are required.
Construction only refuses to hand foreign or unsupported outer backing memory
to the dependency's mutating initializer.
## Tests
- Empty backing memory initializes and writes the current `MGR` v1 prefix.
- A new runtime accepts an existing current-layout manager.
- An entire foreign one-page backing memory remains byte-for-byte unchanged
after rejected construction.
- An entire one-page `MGR` backing with an unsupported version remains
byte-for-byte unchanged after rejection.
- Existing runtime bootstrap, recovery, isolation, diagnostics, and default TLS
regressions continue to run through the fallible constructor.
## Subsequent status
The policy-aware doctor report, bounded/configurable policy identity, per-slot
diagnostic size failures, and separate core/diagnostics Wasm size tiers were
implemented together in 0.12.3. Policy identity remains in-memory lifecycle
and diagnostic state; 0.12.3 does not persist it or change durable audit
semantics.
## Validation status
| `cargo fmt --all --check` | Passed |
| `cargo clippy --all-targets -- -D warnings` | Passed on Rust 1.97.1 |
| `cargo check --all-features --all-targets` | Passed |
| `cargo check --no-default-features --all-targets` | Passed |
| `cargo test --test runtime_macros -- --test-threads=1` | Passed: both default TLS libtest runtimes bootstrapped |
| `cargo test -- --test-threads=1` | Passed: 188 unit tests, 5 compile-fail fixtures, all integrations, and doctests |
| Rust 1.95.0 compile-fail suite | Passed: all 5 fixtures |
| Rust 1.85.0 `cargo check --all-targets` | Passed |
| `wasm32-unknown-unknown` test compilation | Passed |
| `cargo test --doc` and `cargo doc --no-deps` | Passed |
| Raw stripped Wasm probe | Passed: 233,916 bytes against a 240,000-byte budget |
| `cargo package --allow-dirty` | Passed: 95 files, 702.8 KiB uncompressed, 229.1 KiB compressed |
| Exact downstream two-libtest-thread reproduction | Passed |
The construction preflight adds 351 bytes (+0.15%) to the 233,565-byte 0.12.1
probe and leaves 6,084 bytes (2.60%) below the existing gate. The repository's
maintainer/whitepaper toolchain is outside this patch's requested validation
scope and was not run.