ic-memory 0.24.2

Durable stable-memory allocation governance for Internet Computer canisters
Documentation
# 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

| Check | Result |
| --- | --- |
| `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.