Interactive prototype
Aegis ResponseNet
An interactive reference model for command idempotency, outbox replay, read-model convergence, and compensation after a downstream failure.
Make the failure path observable
A fulfillment command can be delivered twice. Its read model can lag. A downstream step can fail after inventory has already been reserved. Each situation needs an explicit state transition.
Aegis ResponseNet now has an interactive reference model that lets you exercise those transitions in the browser. The runnable scope is a deterministic TypeScript model with synthetic data. The broader distributed platform remains an architecture design.
What you can run
The lab starts with a single command, cmd-1042, and one inventory unit. Dispatching the command reserves that unit and adds an event to an outbox. Retrying the same command increments the duplicate counter while preserving its original state.
From the reserved state, choose successful fulfillment or a downstream failure. Success consumes the reservation. Failure leaves it held until an explicit compensation releases it.
Delivering the outbox updates the read model. Delivering the same events again demonstrates consumer deduplication: previously processed event IDs produce no additional projection changes.
idle
-> reserved
-> completed
-> compensation-pending
-> compensated
Each accepted transition records an outbox event.
Delivery advances the read model.
Replay ignores previously processed event IDs.
Why separate command state and read state?
A command response and a query answer can describe different moments. If a worker has recorded a reservation but the projection has not consumed its event, the read model is behind.
The lab makes that delay visible by keeping delivery under your control. Domain state changes when an action is accepted; query state changes only when the outbox is delivered. This is the useful part of the CQRS idea here: separate models have separate update paths, so the interface should expose convergence rather than imply immediate agreement.
Reliability decisions
Deduplicate at both boundaries. Command deduplication prevents a retry from making a second reservation. Consumer deduplication prevents redelivery from applying an event twice. One does not replace the other. The lab keeps the command identity and processed event IDs separately.
Record compensation as new work. A failed downstream step does not erase the earlier reservation. Compensation releases it and appends another event. That leaves a readable history of what happened and how the system recovered.
Reject invalid transitions. A failed command cannot jump straight to successful fulfillment. Running compensation twice cannot release inventory twice. Those rules belong in the transition function as well as in the enabled UI controls.
Keep replay deterministic. This model delivers recorded events in order. The test suite checks that replay preserves the final projection and that duplicates do not expand the set of applied events.
Verification
The executable tests cover duplicate dispatch, delayed projection updates, replayed delivery, failure with a held reservation, compensation idempotency, invalid transitions, and retry after compensation. State transitions return a new snapshot so a later action cannot silently rewrite an earlier result.
Try the failure path in the lab, deliver its three events, and replay them. The command and read model should both finish at compensated, with no reservation held and no new events created by replay.
Boundary between the model and the platform
The browser model has no database, message broker, remote participant, or concurrent writer. It resets on reload. Its tests establish local transition behavior, not transactional durability or distributed exactly-once execution.
The broader design would use a transactional outbox to commit business state and event intent together, a broker for delivery, and persistent deduplication records at consumers. Those pieces need crash recovery, retention, concurrency, and ordering tests before making a production claim. Java, Kafka, and Kubernetes belong to that design target; the linked implementation runs in TypeScript.
The next implementation step would put this same command lifecycle behind a persistent store and verify that a process crash between recording and publishing an event does not lose the event.
Explore the lab · Read about recovery after ambiguous timeouts