MAQPNADocs

maqpna replay

Replay the audit ledger against a candidate policy

Govern-o json | yaml

Synopsis#

maqpna replay --ledger FILE --policy NEW.json [--captures DIR --capture-key URI] [--baseline OLD.json] [--at-ledger-time]
              [--namespace NS] [--since T] [--until T] [-o table|json|yaml] [--only-changed=false] [--include-models]
              [--rego-url URL] [--fail-on-change=false] [--strict-args]    (exit 3 when decisions change)
              (--policy and --baseline take bundle JSON or ToolPolicy YAML)

Description#

Re-evaluates every historical tool-call decision in the audit ledger with the policy in NEW.json and prints the decisions that would change. Exit status: 0 no change (unknowns included), 3 decisions changed (unless --fail-on-change=false), 1 error.

Arguments come from opt-in argument captures (gateway captureArgs; --captures DIR with --capture-key). Without a capture, a call that had arguments is evaluated with no arguments and flagged argsMissing. A changed decision of such a call is reported as unknown, not changed (the rule may depend on the missing arguments), and does not fail the run; --strict-args counts it as changed. Session taints come from the record's ext.taint. The ledger does not record the caller's groups or token scopes: rules using principals.groups or scopes are evaluated without them (use --baseline to compare like with like).

Without --baseline the new decision is compared with the recorded one (approved/denied approvals count as require_approval; denials not made by a policy - scope, budget, DLP, revocation, residency, pins - are skipped as nonPolicy). With --baseline OLD.json both policies are evaluated on the same reconstructed request, which isolates the policy change.

Flags#

FlagTypeDescriptionDefault
--at-ledger-timeswitchevaluate schedules at each record's time (default: now)none
--baselinestringcompare with these policies (same formats) instead of the recorded decisionsnone
--capture-keystringcapture key URI (file:///path; env MAQPNA_CAPTURE_KEY)none
--capturesstringargument capture directory (gateway captureArgs.dir)none
--fail-on-changeswitchexit 3 when decisions changetrue
--formatstringtable|json (same as -o)table
--include-modelsswitchalso replay model calls (server llm/<route>)none
--ledgerstringaudit ledger (JSONL)none
--namespacestringonly records of this namespacenone
--only-changedswitchlist only changed decisions (false: every evaluated decision)true
--policystringcandidate policies: ToolPolicy YAML/JSON, bundle JSON, or a directory of themnone
--rego-urlstringOPA Data API URL evaluated as engine-wide Rego policy (both engines)none
--sincestringRFC3339 start (inclusive)none
--strict-argsswitchcount a changed decision of a call without captured arguments as changed (default: unknown, exit 0)none
--untilstringRFC3339 end (exclusive)none

The global flags (--context, -o, --no-color, ...) work with every command.

Examples#

maqpna replay --ledger audit.jsonl --policy candidate.yaml
maqpna replay --ledger audit.jsonl --policy candidate.yaml --since 2026-09-01T00:00:00Z --format json

What happens when you run it#

  • Reads the audit ledger offline with --ledger FILE: audit ledger (JSONL).
  • Prints a table by default; -o json or -o yaml print the data, and --jq EXPR filters the JSON.
  • Exits 3 when the check fails or a result does not match (see exit codes below), so scripts and CI can act on it.

Exit codes#

CodeMeaning
0success
1error (the message says what failed, with a hint when there is one)
2usage error: unknown flag, missing argument or bad value; the synopsis is printed
3a check failed, a change is blocked, or a result did not match (tamper, policy mismatch)

Terminal demo#

maqpna replay.cast