Expand description
pounce verify <problem.nl> <claim.sol> — independent solution checker.
§Why this exists
When pounce is a tool an agent calls, the agent should never be the
thing you trust for “the solution satisfies the constraints.” Trust
belongs to a small, deterministic checker that re-derives the answer
from the canonical problem — not from the agent’s narration and not
even from the solver’s own exit string. Optimization is the rare setting
where this is cheap: a claimed x* is just numbers, and feasibility is
one constraint evaluation (g_l ≤ g(x*) ≤ g_u, x_l ≤ x* ≤ x_u),
O(nnz) work with no resolve.
pounce verify loads the canonical .nl, reads a claimed .sol, and
reports the worst constraint/bound violation (and, when the .sol
carries constraint duals, a first-order/KKT stationarity residual). It
defends the three agent-workflow failure modes:
- fabrication (“here’s a solution that looks like pounce ran”) — invented numbers fail the residual check against the real model;
- ignoring the solver — a downstream consumer gates on the receipt’s
verified: trueplus the problem hash, not on prose; - solving the wrong problem (dropping/relaxing a constraint to dodge infeasibility) — the check runs against the canonical constraints and bounds, so a point that is only feasible for a relaxed model is caught here.
The JSON receipt content-addresses both inputs by SHA-256 so a consumer
can confirm which problem was verified. When the POUNCE_VERIFY_KEY
environment variable holds a secret the agent does not have, the receipt
is additionally signed with HMAC-SHA256 over a float-free preimage (see
signing_preimage) — so an agent cannot mint a receipt that a consumer
holding the key will accept. The consumer recomputes the HMAC over the
same preimage and compares.
Verdict / exit code: 0 when every violation is within tolerance
(FEASIBLE); 20 when a violation exceeds tolerance (INFEASIBLE);
2 on a usage or I/O error. Optimality is reported but, by default,
does not gate — feasibility is the rigorous, sign-convention-independent
guarantee; pass --require-optimal to also gate on the stationarity
residual.
§Two different complementarity quantities (gh #516)
“Complementarity” names two distinct residuals, and printing either one under the bare label invites a comparison against the other:
- constraint complementarity —
max_i |λ_i| · dist(g_i, nearest finite side)over rows, from the.sol’s constraint duals. This is the oneverifyhas always computed. - bound complementarity —
max_j max(|z_L·(x−x_L)|, |z_U·(x_U−x)|)over variables, from the bound multipliers. This is what Ipopt prints asComplementarity, and it needs theipopt_zL_out/ipopt_zU_out.solsuffixes.
They can differ by many orders of magnitude at the same point and
neither is wrong for what it measures. verify therefore names both
explicitly, reads the bound multipliers when the .sol carries them,
and says “not checked” — rather than nothing — when it does not.
Those same suffixes also sharpen stationarity: without them the residual
is bound-projected and cannot see a bound multiplier that is missing or
wrong (gh #495); with them the exact residual is available, and
--require-optimal gates on it.
Modules§
Structs§
- RowReport
- Verify
Args - Parsed
verifysubcommand arguments. - Verify
Outcome - The fully-evaluated verification result. Serialized to the JSON receipt and rendered to the console.
Constants§
- KEY_ENV
- Environment variable holding the HMAC key. When set (non-empty) and a
--json-outputreceipt is requested, the receipt is signed.
Functions§
- run
- run_
from_ argv - Entry point dispatched from
mainwhen argv[1] == “verify”. - signing_
preimage - The exact byte string that gets HMAC-signed. Deliberately float-free
— only hex hashes, integer counts, and the verdict — so any language
reproduces it byte-for-byte (no float-formatting parity problems between
Rust and a Python/JS consumer). One
key=valueper line, fixed order, trailing newline. The consumer re-derives this from the receipt fields, recomputesHMAC-SHA256(key, preimage), and compares tosignature. Documented indocs/src/verify.md.