maqpna replay
Replay the audit ledger against a candidate policy
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#
| Flag | Type | Description | Default |
|---|---|---|---|
--at-ledger-time | switch | evaluate schedules at each record's time (default: now) | none |
--baseline | string | compare with these policies (same formats) instead of the recorded decisions | none |
--capture-key | string | capture key URI (file:///path; env MAQPNA_CAPTURE_KEY) | none |
--captures | string | argument capture directory (gateway captureArgs.dir) | none |
--fail-on-change | switch | exit 3 when decisions change | true |
--format | string | table|json (same as -o) | table |
--include-models | switch | also replay model calls (server llm/<route>) | none |
--ledger | string | audit ledger (JSONL) | none |
--namespace | string | only records of this namespace | none |
--only-changed | switch | list only changed decisions (false: every evaluated decision) | true |
--policy | string | candidate policies: ToolPolicy YAML/JSON, bundle JSON, or a directory of them | none |
--rego-url | string | OPA Data API URL evaluated as engine-wide Rego policy (both engines) | none |
--since | string | RFC3339 start (inclusive) | none |
--strict-args | switch | count a changed decision of a call without captured arguments as changed (default: unknown, exit 0) | none |
--until | string | RFC3339 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 jsonWhat happens when you run it#
- Reads the audit ledger offline with
--ledger FILE: audit ledger (JSONL). - Prints a table by default;
-o jsonor-o yamlprint the data, and--jq EXPRfilters the JSON. - Exits
3when the check fails or a result does not match (see exit codes below), so scripts and CI can act on it.
Exit codes#
| Code | Meaning |
|---|---|
0 | success |
1 | error (the message says what failed, with a hint when there is one) |
2 | usage error: unknown flag, missing argument or bad value; the synopsis is printed |
3 | a check failed, a change is blocked, or a result did not match (tamper, policy mismatch) |