Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Traces

The trace is Verdict’s primary output. Outputs tell you what was decided; the trace tells you how, and it is what makes a decision engine auditable rather than merely fast.

Shape

type Trace struct {
    ModelID   string
    ModelHash string        // content address of the model that ran
    Entry     string        // what was asked for
    Root      *Node
    StartedAt time.Time
    Duration  time.Duration
}

type Node struct {
    DecisionID   string
    DecisionName string
    NodeKind     string         // "decisionTable", "agentDecision", "invocation", …
    Inputs       map[string]any
    Output       any
    Children     []*Node
    Annotations  map[string]any
    StartedAt    time.Time
    Duration     time.Duration
    Error        string
}

The JSON encoding is a stable contract. Dashboards, the Nexus event bus and the verdict trace renderer all read it.

Annotations

Annotation keys are exported constants in pkg/trace and are part of the contract — keys get added, never renamed.

KeyOnMeaning
hit_policydecision tablesThe policy in shorthand (U, C+, …)
aggregationcollecting tablesSUM, MIN, MAX, COUNT
matched_rulesdecision tablesThe rule IDs that fired
rule_countdecision tablesHow many rules were considered
input_valuesdecision tablesEach input clause’s evaluated value
defaulteddecision tablesNo rule matched; the default was used
invoked_bkminvocationsThe business knowledge model called
agent_promptagent decisionsThe rendered prompt
agent_session_refagent decisionsThe bridge’s identifier for the run
agent_attemptsagent decisionsHow many attempts it took
agent_tokensagent decisionsCost telemetry, when the bridge reports it
fallback_used / fallback_fromagent decisionsThe agent failed and which decision answered instead
cache_hitinvocationsA memoised result was reused
erroranyWhat went wrong

Modes

ModeRecords
full (default)Everything, including every node’s inputs and output
summaryThe node graph, timings and outputs, plus structural annotations. Inputs and data-bearing annotations are dropped
offNothing; Result.Trace is nil

summary is the mode for a service that wants to see the shape of its decisions in production without persisting the data that flowed through them.

Redaction

verdict.WithRedactedInputs("Applicant.ssn", "notes")

Named bindings are replaced with [redacted] in the trace. Redaction is a trace concern only: the decision still sees the real value, so redacting an input never changes an outcome.

Reading one

verdict eval model.dmn -i inputs.json --trace --quiet | verdict trace --values
loan_approval  [evaluation]  630µs
├── Repayment  [invocation]  279µs
│       inputs: {"Loan":{"amount":120000,"term_months":240}}
│       output: 996.27
│   └── Monthly Repayment  [invocation]  176µs
│           invoked_bkm: "Monthly Repayment"
├── Credit Rating  [decisionTable]  143µs
│       hit_policy: "U"
│       matched_rules: ["credit_rating_r1"]
│       output: "excellent"
└── Risk Tier  [agentDecision]  106µs
        agent_session_ref: "nexus://sessions/9f2c/verdict/risk_tier"
        agent_attempts: 1
        output: "low"

When an answer is wrong, the trace tells you which node is wrong before you read a single rule. matched_rules is usually the whole story: either a rule you did not expect fired, or none did and the table defaulted.

Replay

A trace plus the model and the inputs is enough to reproduce an evaluation exactly — every deterministic node takes the same path and produces the same value. ModelHash pins which model ran, so a replay against a changed model is detectable rather than silently different.

Agent decisions are the exception, and deliberately so: their answers are not a function of their inputs. The trace records the answer and the session reference rather than pretending the call is repeatable. To replay one, feed the recorded answer back in — which is exactly what a mock bridge configured from a trace does.

On the bus

With the Nexus plugin configured with publish_trace: true, every node is republished on the event bus as it completes, so a dashboard or terminal UI sees the decision graph filling in rather than waiting for a final answer.