Found by dogfooding the first-run path (grapharc init → plan → go).
What happens
grapharc go <run-dir> executes the saved plan and stamps executed_run_id into plan.json. Running it again on the same directory executes it again — and overwrites the stamp, rather than recording that this plan has now run more than once.
grapharc init
grapharc plan "look into the outage" --scripted --trace r5/p.jsonl --run-id p5
grapharc go r5 # exit 0
grapharc go r5 # exit 0, runs the whole graph again
grapharc go r5 # exit 0, and again
plan.json executed_run_id : f81e7318e9dc
runs in the trace : ['b563daf1c7db', '1f792472a215', 'f81e7318e9dc']
3 executions happened; plan.json names 1
Why it matters
Two separate things, and the second is the one I care about.
-
The plan record disagrees with the trace. The trace is the audit trail and it is correct — three runs are in it. plan.json is what show_graph / graph_status and the MCP path read to answer "did this plan run, and as what?", and it now points at the third run as though it were the only one. A reader of the record cannot discover that the first two happened.
-
One approval, N executions. The approval gate binds a decision to a proposal fingerprint, which does not change between these runs — so a plan approved once can be executed repeatedly by re-issuing go <dir>, with no further gate, as long as --approve is not passed again. For a mutating: true plan that is an agent editing the tree once per invocation on the strength of a single human yes. Bare grapharc go already declines to re-run an executed plan (find_unexecuted_plan skips them); the explicitly-named-directory form does not make the same check.
What to consider
go <dir> on a plan that already carries an executed_run_id: refuse by default with the id and timestamp of the previous run, and require --again (or --force) to proceed. Explicit re-runs stay possible; silent ones stop.
- Make the record accumulate:
executed_run_ids: [...] rather than a scalar that the next run clobbers. The scalar can stay as the newest for compatibility.
- Consider whether a re-run of a
mutating plan should re-park even without --approve, since the earlier approval was given for one execution.
Out of scope
The fingerprint protocol — it is doing its job. This is about the plan record, not the decision.
Acceptance criteria
A second go <dir> on an executed plan is refused unless the re-run is asked for explicitly; the plan record can name every run that executed it; bare grapharc go behaves as it does today.
🤖 Generated with Claude Code
Found by dogfooding the first-run path (
grapharc init→plan→go).What happens
grapharc go <run-dir>executes the saved plan and stampsexecuted_run_idintoplan.json. Running it again on the same directory executes it again — and overwrites the stamp, rather than recording that this plan has now run more than once.Why it matters
Two separate things, and the second is the one I care about.
The plan record disagrees with the trace. The trace is the audit trail and it is correct — three runs are in it.
plan.jsonis whatshow_graph/graph_statusand the MCP path read to answer "did this plan run, and as what?", and it now points at the third run as though it were the only one. A reader of the record cannot discover that the first two happened.One approval, N executions. The approval gate binds a decision to a proposal fingerprint, which does not change between these runs — so a plan approved once can be executed repeatedly by re-issuing
go <dir>, with no further gate, as long as--approveis not passed again. For amutating: trueplan that is an agent editing the tree once per invocation on the strength of a single human yes. Baregrapharc goalready declines to re-run an executed plan (find_unexecuted_planskips them); the explicitly-named-directory form does not make the same check.What to consider
go <dir>on a plan that already carries anexecuted_run_id: refuse by default with the id and timestamp of the previous run, and require--again(or--force) to proceed. Explicit re-runs stay possible; silent ones stop.executed_run_ids: [...]rather than a scalar that the next run clobbers. The scalar can stay as the newest for compatibility.mutatingplan should re-park even without--approve, since the earlier approval was given for one execution.Out of scope
The fingerprint protocol — it is doing its job. This is about the plan record, not the decision.
Acceptance criteria
A second
go <dir>on an executed plan is refused unless the re-run is asked for explicitly; the plan record can name every run that executed it; baregrapharc gobehaves as it does today.🤖 Generated with Claude Code