Repository navigation
v1.91.244.0 fix(pregate): waive version-stamp-only manifests from the lanes check (GBRA-95) - #3461
Merged
Merged
Conversation
|
😎 This pull request was merged. |
garrytan
force-pushed
the
fix/pregate-version-stamp-only-waiver
branch
4 times, most recently
from
October 26, 2026 07:49
78f436b to
b245f3b
Compare
… (GBRA-95) gbrain's release:restamp rewrites its plugin manifests and VERSION; its base's .gstack/pregate.json declares no lane for them, and pregate reads policy from the base, so every restamp PR failed lanes with PREGATE_NO_LANE and could not fix itself (gbrain PRs 7625 and 7606). lib/pregate/stamp-only.ts defines version-stamp-only per file kind: a JSON document of the same shape whose every changed leaf is a bare version under a key named for a version; plist <string> versions under a ...Version... key; a VERSION file that is one bare version on both sides. lane-selection applies it only after the import graph, the declarations, the regen registry and both empty lanes found nothing; lanes prints the waived files on their own line and --explain the per-file verdict. Anything else (a changed description, a new key, a dependency pin, an added or deleted manifest) keeps its PREGATE_NO_LANE. Tests: pure rows for every rule, and bin fixtures for a stamp-only PR (passes), a manifest with a changed description (refused), a mixed diff (stamped files waived, the orphan source file still refused, a mapped file still runs its test) and an added/deleted manifest. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
garrytan
force-pushed
the
fix/pregate-version-stamp-only-waiver
branch
from
October 26, 2026 08:06
b245f3b to
adc85bd
Compare
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
gbrain's
bun run release:restamprewrites its plugin manifests and VERSION. Its base's.gstack/pregate.jsondeclares no lane for them, and pregate reads policy from the base, so every restamp PR failedlaneswithPREGATE_NO_LANEand could not fix itself (gbrain #7625 at f8ef55c3b, #7606).gstack-pregate on a restamp fixture. Before:
4 touched file(s) with no test lane, exit 1, and no way for the PR to declare the lane (policy comes from the base). After:version-stamp-only (no lane needed): …, exit 0, with the per-file verdict under--explain; the same stamp plus a reworded description is stillPREGATE_NO_LANE, withnot version-stamp-only (.description changed and its key is not \version`)`.The rule (
lib/pregate/stamp-only.ts)versionStampOnly(rel, before, after)says a touched file changed as a stamp and nothing else. Three file kinds, each exact; anything else is not a stamp:*.json): both sides parse to objects of the same shape (the same own keys in the same order in every object, the same length in every array, the same type at every leaf); the only differing leaf is the document's top-levelversion, a bare version on both sides (1.2.3,v1.2.3.4,1.2.3-rc.1; never a range); and the texts are line-for-line identical once that one line has its old quoted version replaced by the new one (one recorded change consumed per differing line). Nothing nested qualifies, so a dependency pin, a lockfile entry, a catalog, a devcontainer feature or a package namedversioncan never be a stamp; nor can a changed description, a new, removed or reordered key (conditionalexportsresolve in key order), a floor such asminHostVersionorschemaVersion, a reflow, or anything the parser erases (a big integer, a shadowed duplicate key, a number or escape spelling). A document nested too deep to walk is "could not compare", not a crash.<string>version on both sides whose previous line is<key>CFBundleShortVersionString</key>or<key>CFBundleVersion</key>.MinimumOSVersionand every other key are not stamps.Texts are compared as they are: no CRLF normalisation, BOM kept (
TextDecoderwithignoreBOM), strict UTF-8 (two different invalid bytes must not both become U+FFFD), 1 MiB cap checked fromlstatbefore reading.Where it applies (
lib/pregate/lane-selection.ts)Only after the import graph, the declarations, the regen registry and both empty-lane classes found nothing, so a manifest a test reads still selects that test. Only to a modified, unrenamed file whose merge-base entry is a regular blob of the same mode (
git ls-tree; a symlink or exec-bit flip is not a stamp). Never under a test, fixture, golden, snapshot, baseline,.gstack/or CI-workflow tree (isProtectedTree, exported fromdocs-lane.ts), whose JSON a test may compare against by a path the graph cannot see.Selection.stampOnlycarries the waived files;lanesprints them on their own line (version-stamp-only (no lane needed): <files> — only version values changed against the merge base; a manifest whose other content changed still needs a lane) and names them in the no-tests detail;--explainprints the per-file verdict.Docs
docs/pregate.mdstates the rule in full; thePREGATE_NO_LANEentry indocs/troubleshooting.mdsays why a stamp PR is not that error and links the rule;lib/result-codes.ts's fix text mentions the waiver; CHANGELOG## [Unreleased]carries the entry (VERSION, package.json and the digest stay at main's: stamp-at-merge).Why
A restamp PR has nothing a test could observe, yet it was the one PR shape gbrain's lanes could never pass, and the fix was on the wrong side of the policy boundary (the base's). The waiver is as narrow as the restamp it serves: gbrain's six manifests all stamp a top-level
version, and the reviewers' three fix cycles (below) spent their effort making sure nothing else slips through it.Approvals
Summary
gstack-pregatelanes waive version-stamp-only manifests (JSON top-levelversion, plist bundle versions, VERSION files) with a stated line and per-file--explainverdicts.PREGATE_NO_LANE: nested versions, dependency pins, lockfiles, reorders, reflows, parser-erased changes, BOM/CRLF, oversize or invalid UTF-8, mode changes, symlinks, renames, adds, deletes, protected trees.Test Coverage
Step 7 audit (read-only, against tree b5ef0a79; the final commit touched only scripts/lib/windows-curation.ts): 36 decision paths across
stamp-only.tsand the lane-selection integration, 31 tested (86%), ★★★ 27, ★★ 4, gaps 5, none weak: the plistno line changedreturn (unreachable once the texts differ), the non-RangeError wording of thecould not comparecatch, the text check'schanged in the document but on no line of its ownreturn (every fixture that reaches it is caught by the per-line check first), a working-tree symlink (theisFile()guard; only the merge-base symlink is exercised), and thelstatcatch for a file that vanished mid-run. 0 E2E gaps.bun test test/pregate-stamp-only.test.ts: 21 pass, 0 fail, 173 assertions; pure rows for every rule and bin fixtures for the positive stamp, the reworded manifest, the mixed diff (orphan source refused, mapped file still runs its test), a manifest a test reads, merge-base semantics with main re-stamping after the fork, uncommitted stamp vs uncommitted reword, oversize / invalid-UTF-8 / BOM manifests, protected trees, exec-bit and symlink, rename/add/delete, and the detail line beside docs and assets.Pre-Landing Review
/ship invocation 5, unattended: five-specialist review army plus the Claude adversarial pass (codex unavailable here), four passes over three fix cycles. Pass 1 found three CRITICAL holes (prototype-named keys passing the key-set check via
in; sorted keys hiding reorders; any key containing "version" qualifying, dependency names andMinimumOSVersionincluded) — fixed. Pass 2: 0 CRITICAL; informational fixes taken (top-levelversiononly instead of a deny-list; one change per differing line; bounded recursion; strict decoding and the 1 MiB cap). Pass 3: one CRITICAL (JSON under protected trees could be waived) — fixed, plus BOM, VERSION trim, mode/symlink and lstat-first fixes. Pass 4 (final, re-bound on the shipped tree): 0 CRITICAL, 11 informational, all recorded as skipped: whitespace around a stamped plist<string>line is ignored (XML-insignificant; the line is still a bare version under a bundle key), the protected-tree denylist does not nametestdata/,__fixtures__/,__mocks__/,e2e/, and each manifest costs two serial git spawns (about nine files on a restamp). Review binding verified on the shipped tree 31157016 (records at adc85bd; the only change after pass 4 is the Windows-curation entry for the new test file, which has no code paths of its own). Gate edits: none (GATE_SUMMARY listed=1 eligible=0 tagged={}against origin/main).Exploratory QA
Fixture probes through the branch's
bin/gstack-pregate(the image above): the stamp-only PR passes with the waiver line; the reworded manifest is refused with the reason; the reviewers' /tmp mutation fuzzes (300k and 400k JSON mutations) found no waived document whose parsed content differed beyond the top-level version.Eval Results
No prompt or skill template changed; eval:select maps the diff to no skill-owned paid case. Not run.
Greptile Review
Skipped: GREPTILE_API_KEY unset.
Issues
No gstack issue closed. GBRA-95 (gbrain) is the requester; GStack Minder relays the PR number and version.
Verification Results
PREGATE_REMOTE: tree=311570169ef2… tests=15591 failed=0 spent=0.05(gstack-evidence FRESH, exit 0). Earlier trees 7fe96eff (15568/0), e5cf2efa (15569/0) and b5ef0a79 (15571/0) were green too; the first lane attempt died before running because a git worktree's.gitfile confused the VM tree check (PREGATE_VM_TREE_MISMATCH vm=unavailable), so lanes run from a plain clone.bun run typecheckexit 0;bun run typecheck:testwithin the ratchet; troubleshooting anchors, module-size ratchet, spawnSync tripwire green.pull_requestworkflow on this head because it conflicts withmainon CHANGELOG.md alone (the train merges that by section); Free Tests (run 40289961928) and Windows Free Tests (run 40289964968) were dispatched on this head byworkflow_dispatchand both succeeded. The first Windows dispatch, on 78f436b, failed in shard 2 because the new test file's bin fixtures assert the Linux-host lanes verdict and its mode-change case needs a POSIX exec bit; like every other pregate bin test,test/pregate-stamp-only.test.tsis now on the Windows-curation exclusion list inscripts/lib/windows-curation.ts(the only edit after review pass 4).TODOS
No TODOS.md entry matches; none added.
Documentation
Audit gsta102-inv5-docs (read-only snapshot against origin/main, compare clean):
docs/pregate.md(lanes section) and thePREGATE_NO_LANEentry indocs/troubleshooting.mdwere updated in the commit; README, CONTRIBUTOR_REFERENCE and CLAUDE.md do not describe lane classes and need no change.Test plan
bun test test/pregate-stamp-only.test.ts(21 pass) on the shipped treegstack-restamp --next; CHANGELOG merges by sectionEvidence
Head pinned at READY:
adc85bdb86207c36731777481753bfdcc398351b; tree311570169ef24030c80387603905173d137f0625.