Systems-testing and runtime-validation tooling for the causal-order stack.
Current npm release: @causal-order/testing@0.2.6.
Baseline stack:
npm install @causal-order/testing @causal-order/transport @causal-order/dedupe causal-orderMonitor-aware stack:
npm install @causal-order/testing @causal-order/transport @causal-order/monitor better-sqlite3 @causal-order/dedupe causal-orderBaseline pipeline:
@causal-order/transport -> @causal-order/dedupe -> causal-order
Monitor-enabled pipeline:
@causal-order/transport -> @causal-order/monitor -> @causal-order/dedupe -> causal-order
Run the built-in simulation against the installed stack:
causal-order-testing-runtime --duration 5m --time-scale 60 --profile expected-production-3way-meshRun the same harness against the published transport adapter:
causal-order-testing-adapter-runtime --adapter @causal-order/transport/testing --duration 20m --time-scale 60 --profile expected-production-3way-meshRun a monitor-aware scenario:
causal-order-testing-adapter-runtime --adapter @causal-order/transport/testing --monitor --duration 20m --time-scale 60 --profile monitor-healthy-rolling-4h --run-name monitor-healthyInspect the latest run:
causal-order-testing-latest
causal-order-testing-summary artifacts/runs/<run-folder>
causal-order-testing-compare artifacts/runs/<older-run> artifacts/runs/<newer-run>@causal-order/testing is the deployment-style harness for the causal-order ecosystem.
It is meant to exercise:
causal-order: the ordering core@causal-order/dedupe: the duplicate-filtering layer@causal-order/transport: transport implementations driven through the adapter runtime@causal-order/monitor: health-aware buffering and replay between transport ingestion and downstream delivery
It is not another pipeline stage. It is the simulation, fault-injection, runtime-validation, and reporting layer around the installed stack.
simulated nodes -> @causal-order/transport -> @causal-order/monitor -> @causal-order/dedupe -> causal-order
|<-------------------------- @causal-order/testing ----------------------------------->|
| workload, faults, adapter runtime, summaries, and validation |
Use the published @causal-order/transport/testing entrypoint when you want the harness to drive the real transport implementation directly.
npm install @causal-order/testing @causal-order/transport @causal-order/dedupe causal-order
causal-order-testing-adapter-runtime --adapter @causal-order/transport/testing --duration 20m --time-scale 60 --profile expected-production-3way-meshThen inspect the latest run:
causal-order-testing-latest
causal-order-testing-summary artifacts/runs/<run-folder>This is the npm-facing path for validating the published WebSocket + JSON transport implementation without writing custom harness glue.
The published reporting layer includes:
- dedupe-aware adapter-run verdicts based on accepted, dropped, and ordered counters
- wall-clock transport artifacts produced by
@causal-order/transportunderartifacts/transport-runs/ - monitor-aware outage artifacts from
@causal-order/monitor, including replay posture, recovery transitions, and side-by-side outage comparison signals - failed replay sessions and retry-backoff visibility through the dedicated monitor replay retry scenario
The same CLI can read both:
/testingadapter-runtime artifacts underartifacts/runs//transportwall-clock artifacts underartifacts/transport-runs/
If you want a cleaner transport sanity run before moving to the more realistic stress profiles, use transport-sanity-mesh:
causal-order-testing-adapter-runtime --adapter @causal-order/transport/testing --duration 10m --time-scale 60 --node-ids edge-a,edge-b,edge-c,edge-d,edge-e,edge-f,edge-g,edge-h --profile transport-sanity-mesh --run-name transport-sanity-8node-10m@causal-order/monitor can be exercised through the same adapter runtime by enabling monitor mode.
npm install @causal-order/testing @causal-order/transport @causal-order/monitor better-sqlite3 @causal-order/dedupe causal-orderRun a monitor-aware transport scenario against the published transport adapter entrypoint:
causal-order-testing-adapter-runtime --adapter @causal-order/transport/testing --monitor --duration 20m --time-scale 60 --profile monitor-healthy-rolling-4h --run-name monitor-healthyFor outage and recovery passes, use one of the monitor profiles:
causal-order-testing-adapter-runtime --adapter @causal-order/transport/testing --monitor --duration 20m --time-scale 60 --profile monitor-transport-outage-burst --run-name monitor-transport-outage
causal-order-testing-adapter-runtime --adapter @causal-order/transport/testing --monitor --duration 20m --time-scale 60 --profile monitor-replay-retry-backoff --run-name monitor-replay-retryThen inspect the latest run with the same reporting commands:
causal-order-testing-latest
causal-order-testing-summary artifacts/runs/<run-folder>
causal-order-testing-compare artifacts/runs/<older-run> artifacts/runs/<newer-run>Monitor-enabled runs can emit monitor-specific artifacts such as monitor-heartbeats.ndjson, monitor-health.ndjson, monitor-replay.ndjson, and monitor-summary.json.
This package gives you a deployment-style harness for stressing the causal-order stack under realistic conditions such as:
- workload profiles
- topology expansion through
--node-ids - dark-node and jitter-node fault injection
- adapter-driven transport simulation through a pluggable harness contract
- rejoin-aware recovery pacing
- run artifact generation and summary tooling
If you want to use your own transport implementation instead of @causal-order/transport/testing, point the adapter runtime at your module:
causal-order-testing-adapter-runtime --adapter ./dist/my-harness-adapter.js --duration 5m --time-scale 60 --profile expected-production-3way-meshThe package writes run artifacts under artifacts/runs/ in the caller's working directory by default.
If you are inspecting a wall-clock transport run under artifacts/transport-runs/, point the same summary and compare commands at that run folder:
causal-order-testing-summary artifacts/transport-runs/<run-folder>
causal-order-testing-compare artifacts/transport-runs/<older-run> artifacts/transport-runs/<newer-run>For adapter-driven runs, interpret the summaries in this order:
- transport lifecycle and error counts
- dedupe accepted versus dropped counters
- final ordered count
- anomaly totals and types
That keeps the report aligned with the actual pipeline semantics:
delivered -> dedupe accepted/dropped -> ordered
Baseline runtime:
causal-order-testing-runtime --duration 20m --time-scale 60 --profile expected-production-3way-meshRejoin-aware runtime:
causal-order-testing-runtime-rejoin --duration 20m --time-scale 60 --profile expected-production-mesh-dark-jitter --dark-nodes edge-b --jitter-nodes edge-cAdapter runtime:
causal-order-testing-adapter-runtime --adapter ./dist/my-harness-adapter.js --duration 20m --time-scale 60 --profile expected-production-3way-meshSummaries:
causal-order-testing-latest
causal-order-testing-summary artifacts/runs/<run-folder>
causal-order-testing-compare artifacts/runs/<older-run> artifacts/runs/<newer-run>
causal-order-testing-duplicates artifacts/runs/<run-folder>The package also exposes the reusable config and harness helpers:
import {
type HarnessAdapter,
type HarnessAdapterFactory,
type HarnessAdapterOptions,
type HarnessError,
type HarnessEventContext,
type HarnessPeerState,
buildConfig,
buildRejoinHarnessConfig,
parseDurationToMs,
formatDuration,
createSimulationClock,
} from "@causal-order/testing";This is the intended public API for composition. The CLI runtime files remain package bins rather than import-first modules.
If you only want a narrower surface area for one part of the stack, the package also exposes focused subpaths:
@causal-order/testing/transport@causal-order/testing/dedupe@causal-order/testing/order@causal-order/testing/providers/default
Use the top-level package when you want the full harness surface. Use the focused subpaths when you want clearer imports for transport adapters, dedupe-oriented provider work, or ordering-oriented provider work.
Custom transport integrations are expected to export either createHarnessAdapter or a default factory that matches HarnessAdapterFactory.
import type {
HarnessAdapterFactory,
SimulationEvent,
} from "@causal-order/testing";
export const createHarnessAdapter: HarnessAdapterFactory = async ({
nodeIds,
runDir,
log,
}) => {
const eventHandlers = new Set<
(event: SimulationEvent, context: { peerId?: string; connectionId?: string }) => void
>();
return {
async start() {
log?.(`starting adapter for ${nodeIds.length} nodes in ${runDir}`);
},
async stop() {},
async send(event) {
for (const handler of eventHandlers) {
handler(event, {
peerId: event.nodeId,
connectionId: `${event.nodeId}-example`,
});
}
},
onEvent(handler) {
eventHandlers.add(handler);
return () => eventHandlers.delete(handler);
},
onPeerState() {
return () => {};
},
onError() {
return () => {};
},
};
};The adapter runtime accepts package specifiers, subpath exports, local file paths, and file:// URLs through --adapter.
The adapter runtime keeps ownership of:
- workload generation
- event timing, duplication, and chaos shaping
- pipeline-provider orchestration for the dedupe and ordering stages
- artifact generation and summary reporting
Your adapter is responsible for:
- starting the transport under test
- accepting synthetic
SimulationEventvalues from the harness throughsend() - delivering those events through the real transport path
- calling
onEvent()with the events that come back out of the transport implementation - surfacing transport lifecycle and errors through
onPeerState()andonError()
That means an adapter should be thin glue around a transport implementation, not a second copy of the harness.
@causal-order/transport publishes a ready-made adapter entrypoint at @causal-order/transport/testing.
Use it when you want the /testing suite to drive the real transport implementation directly instead of writing a custom adapter. See the transport quickstart above for the install and runtime command.
- Built-in workload profiles now resolve relative to the installed package instead of the caller's working directory.
- The harness now loads the dedupe and ordering path through a pipeline-provider boundary, with the published
causal-orderand@causal-order/dedupepackages used by the default provider. - Default run artifacts still land under
artifacts/runs/in the caller's working directory. - The published summary and compare commands are dedupe-aware for adapter runs and also read
/transportwall-clock artifacts underartifacts/transport-runs/. - Monitor-enabled adapter runs expose replay phases, recovery transitions, failed replay sessions, and retry-horizon evidence without manual NDJSON inspection.
For repository development details, see CONTRIBUTING.md.