Runtime Operations
Observability, failure handling, replacement, timeouts, testing evidence, and incident correlation for Fronts Hosts.
Observability model
Every host has a hostId; every application has an instanceId and traceId. All host events
carry a monotonic sequence number, timestamp, and current snapshot. State events additionally carry
the duration of the previous state; error events carry a stable Fronts error code and phase.
Every resolve, load, preload, mount, and replace action has one logical operation. Each
extension receives an immutable context carrying the same operationId, hostId, traceId,
intent, cancellation signal, and—when an application instance exists—trusted identity. Callers may
supply operationId/traceId, or let the host create them.
For mount and replace, the resolver sees the host-issued identity before a deployment version is known. After resolution, later contexts contain a new frozen identity and operation envelope enriched with that version. Extensions must correlate contexts by their IDs, not by object reference.
Core snapshots and freezes host-owned references, operation contexts, identities, resolution
policy, and resolved deployment envelopes. Opaque transport source objects, application props,
services, abort signals, and DOM targets retain their domain-specific ownership. Mount captures
the props and target references plus either a frozen static container request or a container
resolver reference before asynchronous resolution. A dynamic container resolver runs after the
deployment is resolved and before loader selection; its result is immediately snapshotted.
Built-in attributes and iframe sandbox collections are copied as part of either request
snapshot.
Runtime IDs are trimmed and must be non-empty strings. Invalid identifiers are rejected before resolution with the error code and phase of the requested operation; custom ID factories are validated by the same rules.
const deployment = await host.preload(
{ name: 'checkout', channel: 'canary' },
{ operationId: 'navigation:42:preload', traceId: 'navigation:42' },
);The intent is one of resolve, load, preload, mount, or replace. Resolve/load/preload are
not application instances, so their operation context deliberately has no identity; mount and
replace contexts have a required identity and trace. Resolver policy fields remain in
ResolveContext, while its operation property carries correlation data. AppLoader receives the
operation context directly, and ContainerPrepareContext.operation is the application-scoped
variant. Container planning and preparation also receive the frozen ResolvedApp, so deployment
metadata can choose an execution boundary without a second resolution. This composition keeps
phase-specific inputs separate without losing end-to-end correlation.
Treat identity in these contexts as host-issued authority. Do not accept an application-supplied
identity for capability authorization or audit attribution. operationId identifies one host
action; traceId may intentionally link several actions, such as preload followed by mount.
The public FrontsPhase values are deliberately application-oriented:
- resolve
- load
- container
- mount
- ready
- update
- activate
- deactivate
- unmount
Protocol validation is attributed to the load or mount boundary that encountered it. Replacement is a transaction composed from these phases, while audit is a synchronous report rather than an error phase.
Module Federation runtime hooks provide lower-level manifest, remote entry, expose, shared, and
resource events. Correlate the two streams at the @fronts/mf load boundary; do not duplicate all
MF hook payloads into core. The official runtime hooks
and DevTools loading trace remain the source of truth for MF internals.
Subscribing
Provide an initial observer or subscribe later:
const host = createFrontsHost({
// ...
observer(event) {
telemetry.emit('fronts.lifecycle', event);
},
});
const unsubscribe = host.subscribe((event) => {
if (event.kind === 'error') reportError(event.error, event);
});Observers must be non-blocking and must not throw. Ship events to a buffered telemetry client and redact application props, service arguments, URLs with credentials, and tenant-sensitive metadata.
Recommended metrics
- resolution latency and failures by app/channel/environment;
- MF load/preload latency and cache outcome;
- mount-to-ready latency and readiness timeouts;
- update/activate/deactivate latency and failures;
- replacement success, rollback, and previous cleanup failure;
- active instances by app/version/container;
- stale resolver cache use;
- denied capability count;
- iframe handshake/RPC timeout and origin rejection;
- retained containers and non-idle host audits.
Do not use high-cardinality instance/trace IDs as metric labels. Keep them in traces/logs.
Failure semantics
Fronts wraps failures in FrontsError with:
- stable code for programmatic handling;
- phase for ownership and alert routing;
- cause for diagnostics;
- structured details that avoid parsing messages.
Expected policy:
| Failure | Host behavior |
|---|---|
| Resolution/registry failure | Use configured cached/fallback resolver or reject mount |
| MF load failure | Roll back acquired resources; current replacement target remains active |
| Invalid application protocol | Reject before mount |
| Container preparation failure | Revoke services, dispose provider resources, and reject |
| Mount/ready failure or timeout | Unmount if possible, dispose service scope and container |
| Update failure | Instance remains mounted but failure is surfaced; product chooses recovery |
| Replacement staging failure | Destroy staging and retain current instance |
| Previous cleanup failure after commit | Return previousCleanupError; new instance remains committed |
| Any incomplete resource cleanup | Retain a cleanupError; fail audit and host disposal |
| Observer failure | Runtime continues; observer is not part of the transaction |
Audit and shutdown
host.inspect() returns snapshots for live transactions and terminal records retained because
cleanup could not be proven complete. Successfully destroyed or fully rolled-back transactions
release their identity reservation and are observed through host events instead. host.audit()
reports:
- active/non-destroyed instances;
- cleanup failures with their terminal instance snapshots;
- pending operations;
- replacement transactions;
- retained owned containers;
- overall
idlestate.
Direct resolve(), load(), and preload() calls are pending host operations too. They participate
in the audit count and are aborted when the host is disposed, even though they do not create an
application instance.
Use host.assertIdle() after tests, route teardown, or shell shutdown. A failure is evidence of an
application/container lifecycle leak and should fail CI.
await host.dispose();
host.assertIdle();dispose() aborts direct operations, aborts/unmounts instances, waits for replacement transactions
and their cleanup, and releases host resources. It rejects with FRONTS_RUNTIME_LEAK if cleanup
failed or an owned container remains attached; inspect audit().cleanupFailures and
audit().retainedContainers for the affected identities. Transport-specific objects with their own
lifetime should also be disposed by the composition root.
Replacement runbook
- Confirm registry response and immutable artifact availability for old and new deployment.
- Preload the target when useful; do not treat preload success as application readiness.
- Call
replace()with a fresh resolution context and stable product trace. - Alert on staging resolve/load/mount/ready failure; the old instance should remain active.
- If commit succeeds with
previousCleanupError, serve the new instance but investigate the leak. - Confirm audit has no retained old container after cleanup.
- If product validation fails after readiness, point the registry channel back and replace again; Fronts cannot infer business correctness from render readiness.
Timeouts
- Timeout values must be finite and non-negative;
0disables the corresponding deadline whileAbortSignalcancellation remains active. - Set readiness deadlines from real application SLOs, not an unlimited default.
- Keep iframe handshake and RPC deadlines finite.
- Pass abort signals through registry fetch and custom loaders.
- A timeout is a failure and triggers cleanup; it must never leave a hidden staging app active.
Testing strategy
The repository uses five evidence layers:
- unit tests for protocol, resolver, service scope, adapters, and error behavior;
- host contract tests for lifecycle transitions, cancellation, replacement, and audit;
- a real MF Runtime integration test serving a real remote container over HTTP;
- Chromium E2E for the core-only lifecycle and the React/Vue/iframe vertical slice;
- Chromium E2E for official and compatible Vite producers, covering the official MF Vite plugin,
vite-plugin-federation, and the production-only OriginJS ESM path.
pnpm test:e2e runs the browser suite against development servers. pnpm test:e2e:preview performs
a fresh production build and runs the same behavior against preview servers; CI uses this production
path. Mocks are appropriate for error matrices, but at least one runtime test must execute the
official MF instance. Official MF also recommends real-runtime integration/E2E testing to avoid a
false gap between bundler fixtures and production behavior.
Incident correlation
Record these fields together when available:
hostId, operationId, operation intent, traceId, instanceId, app name, resolved version, expose,
container type, registry deploymentId/policy revision,
MF instance name, MF remote name/entry, Fronts phase/error codeThis is enough to decide whether ownership lies with deployment policy, MF resource loading, producer protocol/rendering, container isolation, or host capability/service code.
Verification
pnpm exec vitest run packages/core/test/observability.test.ts packages/core/test/host.test.tsverifies event envelopes, phase attribution, audit, cancellation, and cleanup reporting.pnpm exec vitest run packages/core/test/replacement.test.tsverifies readiness-gated replacement, rollback, transaction serialization, and previous-instance cleanup evidence.pnpm test:e2eandpnpm test:e2e:previewverify the documented operational signals against the complete example topology.- Troubleshooting maps stable error phases and codes to recovery actions.