From 1a29fbc3444f858c72ec001abdb4f0f3bebfa76c Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Sat, 7 Nov 2026 11:18:08 -0800 Subject: [PATCH] fix(autoplan): bind rec_hash to its run and plan; keep legacy gates answerable (GST-1819) (#4137) * fix(autoplan): bind rec_hash to its run and plan; keep legacy gates answerable (GST-1819) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs(autoplan): legacy rec_hash is not run-bound; re-render pending pre-change gates (GST-1819) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --------- Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --- changelog.d/gst-1819-rec-hash-run-bound.md | 1 + docs/troubleshooting.md | 10 ++++++++ docs/unattended.md | 2 +- lib/autoplan-gate.ts | 11 +++++---- lib/gate-list.ts | 17 ++++++++++++-- lib/result-codes.ts | 2 +- test/autoplan-residuals.test.ts | 27 +++++++++++++++++++++- test/gate-list.test.ts | 9 ++++++++ 8 files changed, 70 insertions(+), 9 deletions(-) create mode 100644 changelog.d/gst-1819-rec-hash-run-bound.md diff --git a/changelog.d/gst-1819-rec-hash-run-bound.md b/changelog.d/gst-1819-rec-hash-run-bound.md new file mode 100644 index 000000000..69d75defe --- /dev/null +++ b/changelog.d/gst-1819-rec-hash-run-bound.md @@ -0,0 +1 @@ +- **An autoplan `rec_hash` now names its run, so two unrelated gates no longer print the same one.** The hash a gate render prints, and `gstack-autoplan answer --rec-hash` checks, covered only the gate revision and the recommended letters, so any two runs with the same decision shape shared it (GST-1749's and GST-1811's gates both printed `f94689f795a5`), and a `rec` relayed for one run passed the check on the other. It now also covers the run id, the reviewed plan's sha256 and each item's title and option keys, and a hash from another run's gate is refused as `GATE_REC_STALE`. Gates written before this keep working. A `gate.json` without the new `rec_hash_v` marker still accepts the hash it printed then, and the answer records that hash. That old hash is not bound to its run, so re-render a gate still pending from before this change and answer with the new hash its render prints. Recorded approvals are untouched, since `gstack-approvals import --autoplan` and the plan record bind by run id and gate revision, never by `rec_hash`. See docs/troubleshooting.md#gate-rec-stale. (GST-1819) diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 753e29c55..bf145c534 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -4967,6 +4967,16 @@ recommended `b` pending, and `all` now takes them. and answer with `--rec-hash ` from that render. Explicit `