Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/edda

crates/nornir-saga/.nornir/saga-guide.md

Saga — integration guide (app side)

Audience: an app engineer (e.g. on Njord). Goal: record the user's navigation in your app so the nornir test matrix can later replay it as a robot test — for bug-finding and regression.

The matrix already records and replays Saga sessions. This guide is only what you do on the app side to feed it. Works for egui apps and web apps (Leptos + Axum).


What the matrix needs from you

One ordered stream of SagaEvents per user session, written to the nornir warehouse table saga_events. Navigation is the primary event. Each event carries the route + component + action + a state_json snapshot of what the user saw. That's enough for the matrix to deterministically replay the path.

Step 1 — turn capture on

Depend on nornir-saga and enable the saga feature in the build where you want capture (it compiles to nothing when off):

nornir-saga = { version = "0.1", features = ["saga"] }

Step 2 — open a session once

let ctx = nornir_saga::SessionCtx::new(
    &session_id,    // your per-user/session id
    &user,          // user id (or "anon")
    "njord",        // app name
    env!("CARGO_PKG_VERSION"),
    git_sha,        // &str — the commit you shipped (see note below)
);

git_sha is a plain &str, not read from any environment variable — you pass whatever commit your build shipped. Most builds get it from a build script (e.g. option_env!("VERGEN_GIT_SHA").unwrap_or("unknown")) or bake it in at release; if you don't track a sha, pass "unknown". Saga never reads GIT_SHA for you.

Step 3 — record navigation at the right boundary

Emit a nav on every route/view change and a click on every meaningful activation, with a small JSON snapshot of the visible state:

nornir_saga::record(
    nornir_saga::SagaEvent::nav(route, component, action, &state_json).in_session(&ctx)
);

egui app

Tap it at your navigation boundary (the facett nav/Navigable seam): on view switch → nav(...); on button/row activation → click(...).

web app (Leptos + Axum)

Keep state_json small and PII-free — it is what replay asserts against.

Step 4 — flush to the warehouse

On a cadence (timer / page-unload / request end), drain and write the batch:

let batch = nornir_saga::drain_saga_events();
sink.write(&batch)?;   // SagaSink::write → nornir warehouse `saga_events`

sink is any SagaSink implementor. Saga ships JsonFileSink (append events to a file — handy for local capture and tests) and NullSink (drop them); nornir provides the warehouse-backed IcebergSagaSink over the saga_events table.

That's it. Once the events are in saga_events, nornir replays the session and emits a standing robot test (egui → kittest; web app → WebDriver against the live Leptos app). A failing replay is a RED matrix row that names the exact step.

Checklist