Supervision, recovery and replay
Supervise cooperative per-app failures and replay RPC, clock and randomness with bounded journals.
These APIs belong to the host and work with the singleton or a private new WuCore() instance. Import their functions explicitly. The core releases supervisors and sessions when destroy() runs.
superviseApp
superviseApp(core, appName, options?): WuHealthHandle
The app must be registered and can have only one supervisor. Report failures through handle.report(error) from the host or context.wu.reportError(error) from the app. At the threshold, the supervisor revokes the scope, unmounts the app and shows a fallback; it attempts to recover in the same container and restore its props.
import { superviseApp } from 'wu-framework/health';
// runtime already registered checkout; #checkout-slot exists.
const health = superviseApp(runtime, 'checkout', {
threshold: 3, windowMs: 30000, retries: 2, delay: 1000, maxDelay: 30000,
onState: status => console.log(status.state),
fallback: element => { element.textContent = 'Checkout unavailable'; },
});
await runtime.mount('checkout', '#checkout-slot');
// Teardown when the owner of this supervisor exits:
health.stop();
The example values are the defaults. threshold and retries are integers; windowMs measures the failure window. Recovery uses exponential delay capped by maxDelay and consumes at most retries attempts over the supervisor’s lifetime. onState(status) observes transitions; fallback(element, status) customizes the message.
status() returns { appName, state, attempts, failures, error? }. States are healthy, quarantined, recovering, exhausted and stopped. isBlocked() is true in quarantine or exhaustion: manual mounting rejects with WU_APP_QUARANTINED. settled() awaits the current task, not all future retry delays. stop() cancels recovery and removes the fallback; it does not remount the app.
Supervision requires reported errors and cooperative code. It does not interrupt an infinite loop or automatically detect every browser exception. A second supervisor fails with WU_HEALTH_ALREADY_SUPERVISED; an unknown app fails with WU_APP_NOT_REGISTERED.
createReplaySession
createReplaySession(core, { apps, mode?, journal?, maxEntries?, maxBytes? }): WuReplaySession
Records scoped request, now and random calls for registered apps. Use context.wu.now() and context.wu.random() in replayable code. The default mode is record, with 5000 entries and 2 MiB; sessions cannot overlap for the same app.
import { createReplaySession } from 'wu-framework/replay';
import 'wu-framework/timeline';
// checkout performs its scoped operations during its awaited lifecycle.
const recording = createReplaySession(runtime, { apps: ['checkout'] });
await runtime.mount('checkout', '#checkout-slot');
const journal = await recording.export({ timeline: true });
recording.stop();
await runtime.unmount('checkout', { force: true });
const playback = createReplaySession(runtime, { apps: ['checkout'], mode: 'replay', journal });
try {
await runtime.mount('checkout', '#checkout-slot');
playback.assertComplete();
} finally {
playback.stop();
}
During replay, app, operation and input must match, including RPC channel, data and version. It returns the recorded result or error without calling the real provider. A difference throws WU_REPLAY_MISMATCH; non-JSON data produces WU_REPLAY_VALUE, and exceeding limits produces WU_REPLAY_LIMIT. Entries replay in invocation order, not completion order.
status() reports { mode, entries, cursor, pending, stopped, invalid }. export() returns a promise for the wu-replay/1 format and rejects while RPC calls are pending or the journal is invalid. export({ timeline: true }) includes the same core’s timeline; with the core entrypoint, import timeline explicitly. assertComplete() requires no pending calls or unconsumed replay entries. stop() releases interceptors and allows calls to real providers again.
The journal does not capture direct fetch, Date.now, Math.random, timers, DOM or external effects. It also does not automatically restore initial state or execute the imported timeline. Prepare the same inputs and state before replaying. Journals may contain application data: control storage and access. Replay is not rollback or durable auditing.
Evidence and lifecycle
Implementation: superviseApp in src/core/wu-health.js, createReplaySession in src/core/wu-replay.js and facade in src/core/wu-app-scope.js. Tests: tests/unit/app-health-supervision.test.js, tests/unit/replay-journal.test.js, tests/unit/replay-session.test.js and tests/unit/subsystem-lifecycle.test.js.