From 1a7f2578b71d4e7a483259c145d83687ea9fadcb Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Mon, 2 Nov 2026 06:39:24 -0800 Subject: [PATCH] v1.92.83.0 feat(sealed): skip commits the destination already holds or whose patch landed (GSTA-156 P1) (#3689) * feat(sealed): skip commits the destination already holds (refs/pull//head) or whose patch landed (GSTA-156 P1) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix(sealed): compare landed patches byte for byte (latin1), so bytes that are not UTF-8 cannot collapse into a false match Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix(sealed): a landed-patch skip still runs sealed.label_join, which judges the whole file the base may never have held 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.md | 11 ++ VERSION | 2 +- agents-digest/gstack-AGENTS.md | 2 +- bin/gstack-pregate | 13 +- bin/gstack-redact-prepush | 2 +- docs/pregate.md | 22 ++- lib/sealed-guard.ts | 147 ++++++++++++++-- package.json | 2 +- test/egress-receipt-wiring.test.ts | 4 + test/fixtures/sealed-guard-off-golden.json | 28 +-- test/sealed-guard.test.ts | 4 +- test/sealed-skip.test.ts | 196 +++++++++++++++++++++ 12 files changed, 395 insertions(+), 38 deletions(-) create mode 100644 test/sealed-skip.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index a99754d85..b89ddb8c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## [1.92.83.0] - 2026-11-02 + +**The sealed guard no longer rescans commits the destination already holds, so a stacked branch retargeted after its parent squash-landed stops being refused for the parent's history.** gstack-evals#22 listed its parent #6's seven commits after #6 landed as one squash. One of them had added and later deleted a held-out file, so the guard refused a push whose every byte GitHub already had as `refs/pull/6/head`, and the queue sat blocked for about 50 minutes until a waiver landed. + +### Changed +- **`lib/sealed-guard.ts`** (`evaluateSealed`, shared by the pre-push hook and `gstack-pregate sealed`): a listed commit is skipped when it is an ancestor of the destination's own `refs/pull//head` for a squash `(#n)` on the base since the merge-base (at most 50 refs, a 20-second budget, an egress receipt per remote call, fetched refs deleted afterwards), or when its own `git patch-id --verbatim` and diff equal a base commit's (off above 2,000 base or 400 listed commits; a landed commit still gets the `sealed.label_join` check, which reads the whole file). Nothing is matched against a combined diff, and any failed lookup scans everything with one line saying why. docs/pregate.md#sealed-skip. +- **`gstack-pregate sealed`**: the `SEALED:` line gains `skipped=` (and `commits=` counts the commits scanned), stderr names each skipped group, and `--no-skip` scans every listed commit. + +### Tests +- `test/sealed-skip.test.ts`: the #22 shape is clear with seven commits skipped as `refs/pull/6/head`, the hook and the preflight agree, `--no-skip` refuses, no fetched ref is left behind and the egress ledger records the lookup. The same parent never published refuses although its squash equals the combined diff. An unreachable remote scans everything and says so. A cherry-pick that landed on the base is skipped and named. A whitespace near-miss (`/home/alice/` against `/home/ alice/`) is scanned and refuses, and so is a landed commit that differs only in bytes that aren't valid UTF-8. + ## [1.92.82.0] - 2026-11-02 **`gstack-review-dispatch verify` now catches a merged findings file edited after collect.** Verify used to compare only output hashes and line counts. So a `merged.jsonl` row whose label was lowered, or whose text was replaced with another line's summary, passed with `VERIFY: clean` once the judge agreed with the edited row. Verify now re-parses each reader's unchanged output and checks every merged row against the finding at its index, label and raw text byte for byte. A mismatch prints `merged_line_differs` on the OUTPUT and JUDGE rows, and verify is dirty. A missing output file or an output event with no file recorded (even for a reply with no findings), a judgment run on a copy of the merged file, merged rows that collect never wrote, and an output whose finding count no longer matches its recorded ids are dirty too. A reply refused for naming the wrong checkout is still allowed to hold findings collect never merged, but only when verify re-checks its tree line and finds it wrong. diff --git a/VERSION b/VERSION index 9a90f85b2..097482065 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.92.82.0 +1.92.83.0 diff --git a/agents-digest/gstack-AGENTS.md b/agents-digest/gstack-AGENTS.md index 2a13be4cc..b332bb94e 100644 --- a/agents-digest/gstack-AGENTS.md +++ b/agents-digest/gstack-AGENTS.md @@ -1,4 +1,4 @@ -# gstack digest v1.92.82.0 — regenerate/re-copy after upgrading gstack +# gstack digest v1.92.83.0 — regenerate/re-copy after upgrading gstack Behavioral rules from gstack (https://github.com/garrytan/gstack), compressed for agent hosts without a full skill install. The full skills add workflows, diff --git a/bin/gstack-pregate b/bin/gstack-pregate index cfee7e707..4a6671b46 100755 --- a/bin/gstack-pregate +++ b/bin/gstack-pregate @@ -9,7 +9,7 @@ * gstack-pregate clear --remote --run-url | --run [--run …] [--allow-repo-commands] | --bundle-lane