Back to trackLesson 3 of 5

Monitoring 1: Who's Running This

The problem

A build server kicks off a nightly regression run. A developer runs the same model by hand to chase down something odd in yesterday’s output. A CI pipeline replays a fixed seed on every merge. All three might be hitting the exact same model file, possibly on the exact same machine, and from the output alone you can’t tell which run produced which batch — or, for that matter, whether a given day’s usage was one person iterating at a terminal or an unattended job looping all night. When you need that distinction — tracing a weird result back to its run, or just attesting to how the install is actually being used — you need something that isn’t in the generated data itself.

Every run leaves a local trail

When --audit is enabled, grind writes three real events to ~/.spicegrinder/logs/audit.ndjson: one when the process starts, one run-summary per model run, one when it stops.

grind --audit --seat --seed 42 --count 5 samples/financial/claims-frequency-severity.xml
{"@timestamp":"2026-09-09T19:56:24.263987Z","event.action":"instance.start","instance.id":"2ead3cd7-36cb-4bef-bef1-1717fa3e7e13","seat.id":"kevin-laptop","instance.kind":"seat","message":"SpiceGrinder instance started"}
{"@timestamp":"2026-09-09T19:56:24.467462Z","event.action":"run.summary","instance.id":"2ead3cd7-36cb-4bef-bef1-1717fa3e7e13","seat.id":"kevin-laptop","instance.kind":"seat","spicegrinder.model.name":"ClaimObservation","spicegrinder.model.path":"/Users/kevinkrom/src/spicegrinder/samples/financial/claims-frequency-severity.xml","spicegrinder.seed":"42","spicegrinder.observation_count":5,"spicegrinder.node_count":3,"spicegrinder.complexity_score":32}
{"@timestamp":"2026-09-09T19:56:24.468089Z","event.action":"instance.stop","instance.id":"2ead3cd7-36cb-4bef-bef1-1717fa3e7e13","seat.id":"kevin-laptop","instance.kind":"seat","message":"SpiceGrinder instance stopped"}

(Trimmed to the fields that matter here — the real line also carries run.started/run.ended/duration_ms and a full complexity breakdown: analysis mode, predicted/measured average depth, min/max depth.)

Two identity fields answer “who”: instance.id is a fresh UUID minted for every process — you never set it, it’s just always there, so even a run with nothing else configured is at least distinguishable from every other run that ever happened. seat.id is different: it’s an opt-in label you choose (kevin-laptop above), meant for attributing a run to a specific person or workstation, not derived from the OS account or hostname automatically.

Seat vs. runtime, and how it’s decided

The third field, instance.kind, labels a run as either seat (a person at a terminal) or runtime (something unattended — CI, cron, a service). If not specified as a parameter, SpiceGrinder defaults to an interactive terminal (System.console() != null) meaning seat with anything else defaulting to runtime. Using --seat/--runtime overrides that explicitly, and is recommended, especially for unattended jobs:

grind --audit --runtime --seed 7 --count 5 samples/financial/claims-frequency-severity.xml
{"@timestamp":"2026-09-09T19:56:34.892097Z","event.action":"instance.start","instance.id":"240e85df-6075-499a-af4f-058079db1db1","instance.kind":"runtime","message":"SpiceGrinder instance started"}

No seat.id field at all this time, because none was set.

Two runs, same log file, same model: one clearly by a person as a seat named kevin-laptop, one an unattended runtime invocation with no human attached. That’s what you get: a durable, local answer to “who or what ran this,” built from fields you either set explicitly or get for free just by running the application.

Everything is opt-in

Nothing reads an OS username, a machine’s hostname, or anything else off the box without being asked — seat.id is a string you provide, not a value SpiceGrinder infers. Our mantra is “opt-in, local-only, no network.” Every one of the three logging streams (audit, performance, diagnostic) defaults to off, and turning each one on writes to a plain NDJSON file on disk — nothing is ever sent anywhere by SpiceGrinder. That’s a deliberate design decision, not an oversight.

Turning auditing on for good (rather than per-invocation with --audit) is a one-line edit to ~/.spicegrinder/instrumentation.properties: audit.enabled=true, optionally with your own seat.id set once so you don’t have to pass --seat on every command. We strongly recommend enabling audit and performance logging, but leave it as opt-in to put the choice in your hands.

The same audit stream is evidence that can back customer-side license attestation and peak-concurrency reporting — knowing who’s running this isn’t just a debugging convenience, it’s the record you’d actually want on hand if you ever needed to answer that question for real.