BoundaryLogEvents — one per attempt that fails on a retry, plus a terminal event when the run finishes. This is the shape that hits the network (or your custom write sink).
Shape
BoundaryLogEvent is a tagged union on ok. Successful runs always emit a single terminal event; failed runs emit one event per non-terminal attempt plus a terminal event when retries are exhausted.
Field-level reference
Identity
| Field | Set by | Notes |
|---|---|---|
contractName | Contract | The name field you passed to defineContract. Required. |
environment | Logger | From createBoundaryLogger({ environment }). Buckets data on the dashboard. |
timestamp | SDK | ISO 8601, stamped at emit time. |
runId | SDK | bnd_run_<nanoid>, generated once per accept() call, stamped on every event for that run. The backend coalesces per-attempt + terminal events into a single run row keyed by (organizationId, runId). |
Run metadata (always sent)
| Field | Meaning |
|---|---|
attempt | The attempt this event reflects. On a non-terminal failure event it’s the attempt that just failed; on a terminal event it’s the final attempt count. |
maxAttempts | From the contract’s retry config at the time of the run. |
durationMs | Per-attempt event: duration of just this attempt. Terminal event: total wall-clock across all attempts. |
ok | Discriminator — true on AcceptedEvent, false on FailedEvent. |
final | true on terminal events (run is over), false on mid-run failure events. AcceptedEvent is always final: true. |
model | Per-call override (contract.accept(run, { model })), else the logger’s default model, else undefined. |
rulesCount | Number of rules on the contract at runtime. |
Failure attribution (always sent on FailedEvent)
There is no capture.errors flag — these are structural fields that always appear when ok: false. Without them a failure event is just a flag.
| Field | Meaning |
|---|---|
category | EMPTY_RESPONSE, REFUSAL, NO_JSON, TRUNCATED, PARSE_ERROR, VALIDATION_ERROR, RULE_ERROR, or RUN_ERROR. |
issues | Schema errors or rule violations from the failed attempt. |
ruleFailures | Names of the rules that failed this attempt. Maps to the dashboard’s per-rule failure attribution. |
beforeSend to scrub issues before the event leaves.
Repair context
Gated bycapture.repairs (default on). Present only on FailedEvent with final: false — the repair message is the prompt that’s about to be sent before the next attempt.
Raw data (opt-in)
| Field | Gate |
|---|---|
input | capture.inputs — off by default |
output | capture.outputs — off by default |
SDK attribution
Stamped automatically. Used for attribution on the dashboard and for debugging version-specific behavior.runtime is "node/<version>" on Node, "browser" where navigator.userAgent exists, or omitted on edge runtimes.
Lifecycle
Each hop runs before the event is visible on the next. If capture strips a field, it can’t be added back bybeforeSend for that event.
Example success event
Example failure event (terminal)
See also
Capture policy
Three optional buckets, plus the always-on fields
createBoundaryLogger
Full options reference