Skip to content

feat(runtime): pluggable WASI clocks for deterministic guest time#200

Open
mfw78 wants to merge 1 commit into
feat/m0-mock-backendsfrom
feat/m0-wasi-clocks
Open

feat(runtime): pluggable WASI clocks for deterministic guest time#200
mfw78 wants to merge 1 commit into
feat/m0-mock-backendsfrom
feat/m0-wasi-clocks

Conversation

@mfw78

@mfw78 mfw78 commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #198. Part of the epic #80 train; merges in stack order behind feat/m0-mock-backends.

WasiCtxBuilder::{wall_clock, monotonic_clock} is the documented per-store virtualization point for deterministic guest time, but Supervisor::build_store always took the ambient host defaults, so there was no way to run a module against a controlled clock. This becomes more load-bearing once wasi:clocks is the only guest time source. This PR threads an optional clock override from the assembly through to every module store, defaulting to ambient behaviour, and ships a ManualClock test double.

Changes

  • Add an optional WasiClockOverride (Arc<dyn HostWallClock + Send + Sync> plus Arc<dyn HostMonotonicClock + Send + Sync>) threaded from the builder assembly (AssembledRuntime.clocks, a with_wasi_clocks stage method on PresetBuilder/TypedBuilder) through Supervisor::boot, boot_single, load_one, and reinstantiate_one.
  • Apply the override in build_store to every module store's WasiCtxBuilder via by-value SharedWallClock/SharedMonotonicClock adapters; the default is None everywhere, leaving ambient host clocks untouched.
  • reinstantiate_one clones the stored override before the mutable reborrow so a restarted module reuses the same clock as the one it replaces.
  • Scope is guest-visible time only: RunId::started_at continues to use SystemTime::now() on the host side, unchanged.
  • Ship ManualClock in test_utils/clock.rs (behind the test-utils feature) with set(SystemTime) and advance(Duration); monotonic time is non-decreasing (advance only, saturating), wall time clamps pre-epoch values to zero.
  • Update all existing boot call sites (bootstrap.rs, shepherd-cow-host/tests/cow_boot.rs, the ~13 sites in supervisor/tests.rs) to pass None for the new parameter, and add e2e_manual_clock_override_boots_and_dispatches covering the override path end to end.

Test plan

  • cargo fmt --all --check
  • cargo clippy --workspace --all-targets --all-features -- -D warnings
  • cargo clippy on the crate without test-utils (confirms the new types add nothing to a production build)
  • Module wasms built in-tree (example plus M2/M3 examples and fixture bombs) so the e2e path genuinely boots and dispatches rather than hitting a skip branch
  • cargo test --workspace --all-features --no-fail-fast, including e2e_manual_clock_override_boots_and_dispatches, the four test_utils::clock unit tests, and the pre-existing supervisor suite (184 passed, 0 failed in nexum-runtime)

Notes for reviewer

  • All pre-existing boot call sites pass None for the override, so behaviour is unchanged unless a caller opts in; the feature is inert by default.
  • test_utils (and ManualClock within it) stays behind the test-utils feature, so it never reaches a normal build.
  • Two follow-ups identified but deliberately left out of scope: de-duplicating the in-memory log pipeline construction shared by mock_components_from and the deleted empty_for_test, and extending the clock e2e test to assert guest-observed time (via a module that reads wasi:clocks and reports it back) rather than only the host-side handle.

AI Assistance: Claude Code (Opus 4.8 implementation and adversarial review, Sonnet 5 PR authoring) used for the full change.

…t paths

Add WasiClockOverride, a shared wall and monotonic clock source applied to
every module store including the ones rebuilt on restart, so a test handle can
drive guest-visible time. Omitting it leaves the ambient host clocks, keeping
the default behaviour-neutral; RunId start stamps stay on the host wall clock.
Expose it on the typed and preset builders via with_wasi_clocks, and ship a
manually-driven ManualClock under a new test-utils feature.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant