What happens
grapharc approve <trace> reads the parked request and writes an approve decision immediately; the plan's contents — approved: plan 337ed97f9a2c (triage, patch, verify) and the fingerprint — are printed after the decision is already written. There is no way to look first: no flag that prints the pending request without deciding, and no argument that binds the decision to a fingerprint the reviewer previously read.
The file protocol underneath is already careful — write_decision quotes the request's fingerprint and the loop discards a decision whose fingerprint does not match the parked request — so a stale decision cannot land on a newer plan. What is missing is the human half: the CLI never shows the reviewer what they are saying yes to.
Why it matters
The approval gate is the product's central trust claim ("there is no already-approved path"). An approve command that works sight-unseen reduces that gate to a button — in a Slack-driven workflow especially, approve becomes a reflex, and the audit trail then records informed consent that never happened.
What to consider
grapharc approve <trace> --show (or approve with no decision flag): print the parked plan — nodes, kinds, edges, fingerprint, estimated cost — and exit without deciding.
grapharc approve <trace> --fingerprint <fp>: write the decision bound to the fingerprint the reviewer actually reviewed; refuse with exit 2 if the parked request differs. The plumbing already exists — the CLI just never exposes it.
- Keep the current one-shot behaviour available (
--yes?) for automation; the default should lean toward review-then-decide for humans.
Out of scope
The decision file format and the loop's fingerprint matching — both are correct today.
Acceptance criteria
A reviewer can print a parked plan without deciding; a decision bound to a stale fingerprint is refused with a message naming both fingerprints; the existing approve/deny tests pass unchanged.
What happens
grapharc approve <trace>reads the parked request and writes an approve decision immediately; the plan's contents —approved: plan 337ed97f9a2c (triage, patch, verify)and the fingerprint — are printed after the decision is already written. There is no way to look first: no flag that prints the pending request without deciding, and no argument that binds the decision to a fingerprint the reviewer previously read.The file protocol underneath is already careful —
write_decisionquotes the request's fingerprint and the loop discards a decision whose fingerprint does not match the parked request — so a stale decision cannot land on a newer plan. What is missing is the human half: the CLI never shows the reviewer what they are saying yes to.Why it matters
The approval gate is the product's central trust claim ("there is no already-approved path"). An approve command that works sight-unseen reduces that gate to a button — in a Slack-driven workflow especially,
approvebecomes a reflex, and the audit trail then records informed consent that never happened.What to consider
grapharc approve <trace> --show(orapprovewith no decision flag): print the parked plan — nodes, kinds, edges, fingerprint, estimated cost — and exit without deciding.grapharc approve <trace> --fingerprint <fp>: write the decision bound to the fingerprint the reviewer actually reviewed; refuse with exit 2 if the parked request differs. The plumbing already exists — the CLI just never exposes it.--yes?) for automation; the default should lean toward review-then-decide for humans.Out of scope
The decision file format and the loop's fingerprint matching — both are correct today.
Acceptance criteria
A reviewer can print a parked plan without deciding; a decision bound to a stale fingerprint is refused with a message naming both fingerprints; the existing approve/deny tests pass unchanged.