Repository navigation
v1.91.261.0 fix(restamp): quoted since: rows and stale base-version mentions on branch-added lines when VERSION equals the base (gbrain #7640) - #3491
Merged
Conversation
…ranch-added lines when VERSION equals the base (gbrain #7640)
A PR that stamped X, lost its slot and merged a base that had reached X on
its own had no branch stamp, and the mention scanner could not pass the
opening quote of a quoted row, so gstack-restamp --next left the PR's
{ since: 'X' } rows at X while the release shipped as X+1.
- tentativeMentions and rewriteStamps accept since: 'X' / since: "X" /
(was 'X') / (was "X") and keep the quote style; the scanner also reads
the policy's stamp_patterns templates.
- With no branch stamp and no --was, a stamp-form mention of the base
version on a line the branch added moves; the same version on a base
line stays. The stamp_paths stage detail names both counts per file.
- test/restamp-mentions.test.ts (pure forms + the reporter's state rebuilt
with the real bin), stamp-templates pin updated, docs/ship-policy.md,
--was help line, CHANGELOG [Unreleased].
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
|
😎 This pull request was merged. |
…retry after a partial apply - since: 'X' and (was 'X') require the quote to close right after X in the scanner and the rewrite table, so a quoted prerelease or a mismatched pair is never a stamp (the tree receipt shares the table). - branchAddedLines records positions from the unified=0 hunk headers; the stamp_paths stage rewrites by position, so a base line with the same text stays and a CRLF checkout still finds the branch's row. - Journal recovery restores the equal-base provenance (no branch stamp) so a stamp interrupted after VERSION was written retries as a stamp, not noop. - Skipped detail names the explicit version it searched for; --was help line names the CHANGELOG re-heading; docs and CHANGELOG state the boundaries, the fork-point attribution and the rule's false-positive class. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
…ontext parseUnifiedDiff records each added line's new-side position (addedAt), counting context lines a hunk carries, and branchAddedLines pins --inter-hunk-context=0, so a diff.interHunkContext setting that joins two hunks around a base row no longer shifts the branch's second row onto the base row. Test with interHunkContext=1 (red on the pass-1 tree). Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
… help default Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
… base=origin/main@6c5b2d4 policy=base origin/main@6c5b2d46123c:.gstack/ship-policy.json) STAMP_VERSION: 1.91.261.0 FILES: CHANGELOG.md VERSION agents-digest/gstack-AGENTS.md package.json MERGE_CONDITION: sha=b5ca5a68cd950946a78cd08a1579f0a35e6f72c1 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
Before (left): the real
bin/gstack-restamp --next --base master --pr 7640 --dry-runat 1.91.253.0 on a two-commit scratch repo in gbrain's state (master released .467, the PR stamped itself .468 and added{ since: '0.60.468.0', id: 'sync_anchor_relative' }, master then shipped .468 on its own with its own{ since: '0.60.468.0', id: 'bun_floor_1_4_4' }row, the PR merged master; VERSION .468 on both sides).stage stamp_paths: skipped (no tentative mention newer than the fork version 0.60.467.0)and the PR's row stays at .468 while the release goes out as .469. After (right): the PR's row moves to .469, master's .468 row is untouched, and the stage detail readsVERSION equals base 0.60.468.0, so 0.60.468.0 moved only on lines this branch added and stayed on the base's own lines (src/core/behavior-change-notice.ts: 1 moved, 1 kept). Captured at e27c799; the stage output is unchanged since (the later commits changed how provenance is computed, not what it prints), and the outside reviewer's pass-3 probes reproduced the same counts at 8f3f686.Quoted versions are stamp forms.
tentativeMentions(the scanner over branch-added lines) andrewriteStamps(the exact rewrite table, shared with the tree receipt and the gate-reuse normalizers) in lib/restamp.ts acceptsince: 'X',since: "X",(was 'X')and(was "X")beside the bare forms and keep the quote style; an opened quote must close right after X (since: '1.2.3-beta'andsince: '1.2.3"are not the form), andvXalready accepted a quote before thev. The scanner also reads the policy'sstamp_patternstemplates, so a template-only form on a branch-added line is a candidate too.The equal-version rule. When the branch has no stamp of its own (its VERSION equals the base's and no
--wasis given), a stamp-form mention of the base version on a line the branch added is its stale tentative stamp and moves to the allocated version; the same version on a line the base already carries stays. The stage is its own function (rewriteStampPaths) and its detail, printed in the stage table and kept in the journal, names both counts per file. When the branch has an explicit stamp that no stamp file mentions, the skipped detail names it instead of hiding it.--was Xis unchanged: it rewrites X on every line, the base's own included, and re-heads## [X](its help line now says both).Provenance is by position, not text.
branchAddedLinesreturns the new-side line positions fromgit diff --unified=0 --inter-hunk-context=0, andparseUnifiedDiffcounts context lines on the new side (Hunk.addedAt), so a branch-added line whose text equals a base line moves alone, adiff.interHunkContextsetting that joins hunks cannot shift positions, and a CRLF checkout whose diff is LF-normalized still finds its rows. A stamp interrupted after VERSION was written (EACCES on a stamp file) retries as a stamp, not a noop: the journal restores the equal-base provenance.Why
Relayed from gbrain #7640 (gstack 1.91.246.0): the PR stamped 0.60.468.0, lost its slot, merged master, and master was 0.60.468.0 by then. At its slot
gstack-restamp --nextleft the PR's notice rows at .468 while the release shipped as .469, and gbrain'scompareReleasesthen hid that notice from every user already on .468. Two gaps combined:branchStampwas null because VERSION matched the base, so nothing was rewritten everywhere, and the scanner'ssince:\s*(\d…)could not pass the opening quote, so the branch-added-lines path found nothing either (--was 0.60.468.0rewrites master's rows too, so it was no workaround). Both verified by reproducing the state with the real bin (screenshot above) and by running the new test file against the unfixedlib/restamp.ts: eleven of its thirteen cases are red there (the template-overlap and--wascases pass, as they should).Approvals
No approvals recorded for branch capy/quoted-since-rows-and.
None were needed: a bug fix inside the GSTA-118 brief from GStack Minder (2026-10-26), within the lane's file ownership. Deferred, filed as noted in the body: none.
Summary
since:and(was …)forms are stamp forms in both the writer and the tree-receipt classifier; the scanner readsstamp_patternstemplates.--inter-hunk-context=0,Hunk.addedAt), CRLF-safe, and journal recovery of the equal-base provenance on retry.--washelp and docs/ship-policy.md stage 4 state the quoted forms, the provenance rule, its false-positive class and the escape hatch; CHANGELOG under[Unreleased](VERSION, package.json and the digest stay at main's; the train stamps at the slot).Test Coverage
New: test/restamp-mentions.test.ts, 13 cases. Pure: single and double quote, bare unchanged, quote style kept, mismatched pair refused, template overlapping the built-in form counted once, fork-version floor on quoted mentions. Fixture repo with the real
bin/gstack-restamp: the reporter's state with and without thesince: '{version}'template, a negative control, fork equals base,--wasrewriting the base's row too, prerelease and mismatched-quote boundaries, duplicate text at two positions,diff.interHunkContext=1, a CRLF checkout, and an EACCES-interrupted apply whose retry completes the stamp (skipped on win32 and as root). Changed: test/stamp-templates.test.ts counts the quotedsince:row once with or without a template.Regression proof: 11 of 13 cases fail at the base
lib/restamp.ts, all 13 pass at HEAD; each review pass's new cases failed on the tree before that pass's fix.Tests ran: free tier (remote, Ubicloud) 9379, failed 0, tree 1ac3e5f54779 · macos-named-regressions 2 (run 40398992761) · windows-free-shard 290 (run 40398998688) · focused restamp-mentions + stamp-templates 16 ·
bun run typecheckclean ·typecheck:test819 known, none new · module-size ratchet pass (lib/restamp.ts under 800 lines).Pre-Landing Review
Three passes (the cap), blocking floor applied: pass 1 over the whole diff at e27c799 (core review: 0 critical, 4 informational; outside voice openai/gpt-6.1-sol: 4 blocking, all fixed in 6469472: closing-quote rule, positional provenance for duplicate text, CRLF, retry after a partial apply); pass 2 over e27c799..6469472 (1 blocking: inter-hunk context shifting positions, fixed in 8f3f686); pass 3 over 6469472..8f3f686 (inter-hunk finding resolved, no new findings, all saved probes green). b5ca5a6 is three one-line text corrections from the docs re-audit, checked in-host against the code, no code change.
Gate edits: none detected (GATE_SUMMARY listed=0; test/stamp-templates.test.ts flips a pinned
count 0to1for a quotedsince:row with no template, which is the change under test).Outside review: completed, converged (openai/gpt-6.1-sol, 3 passes). Informational items kept as design decisions, named here: the equal-version rule reads line ownership, not meaning, so a branch-added
Requires vX or lateron a branch forked at X moves with it (documented in ship-policy stage 4 with the escape hatch); no--after(gate-ahead) fixture for the equal-version rule (code path shared with--next, read but not fixture-tested).Exploratory QA
Reproduced the reporter's state on a gbrain-shaped scratch repo with the real bin, before and after (screenshot above). Not run: a live gbrain checkout.
Design Review
No frontend files changed — design review skipped.
Eval Results
No prompt-related files changed — evals skipped (no SKILL.md or template touched).
Greptile Review
Greptile triage: UNAVAILABLE (not run in this unattended Capy lane).
Issues
Refs #7640
Verification Results
Fixture before/after PASS (real bin, dry run); 11-of-13 red proof PASS; focused suites PASS; remote free tier PASS; macOS and Windows lanes PASS via hand-dispatched runs (the pull_request event does not schedule CI on a head GitHub shows as CONFLICTING on CHANGELOG.md). Not run: live gbrain repository.
Documentation
Status: updated at b5ca5a6. The read-only re-audit at 8f3f686 (audit id ship-20261026T204211Z-8f3f686, second attempt) returned blocked on two text corrections and nothing else; both are applied in b5ca5a6 together with its advisory wording note, so no claim in the audited scope contradicts the code.
Scope. The six committed files (lib/restamp.ts, bin/gstack-restamp, docs/ship-policy.md, CHANGELOG.md, test/restamp-mentions.test.ts, test/stamp-templates.test.ts) plus lib/tree-receipt.ts, docs/pregate.md and docs/troubleshooting.md. The auditor read the restamp stages, the stamp_paths and stamp_patterns table rows, the tree-receipt sentence and the restamp error anchors, grepped the rest of the doc tree for stamp forms,
--was,stamp_patternsand restamp contracts, and ran both test files from a scratch extract (16 pass, 0 fail; 11 of 13 red with the base lib).Corrections applied in b5ca5a6. CHANGELOG: the red-case count is eleven of thirteen (was "seven of the first nine", left over from before pass 1 added cases). docs/ship-policy.md stage 4: the branch's own stamp and
--was <X>, when given, are each rewritten everywhere (explicitis their union inrewriteStampPaths; the old "else" said only one). bin/gstack-restamp--washelp default: "plus the stale mentions on lines the branch added".Documentation health. docs/ship-policy.md: current (stage 4, both table rows, receipt sentence). CHANGELOG.md: current under
[Unreleased]. bin/gstack-restamp help: current. docs/pregate.md, docs/troubleshooting.md: current, no new result code so no new anchor. README/AGENTS/CLAUDE/CONTRIBUTING/ARCHITECTURE: no restamp stamp-form contract to update.Debt, not blocking. The journal-recovery behaviour (a retry after an apply interrupted once VERSION was written now completes as a stamp) is stated in the CHANGELOG and tests, not in ship-policy stage 6 or the RESTAMP_CONFLICT anchor.
Test plan
gstack-pregate --stage tests --remote --spend-cap 2 --timeout 2700 --allow-repo-commands: PREGATE_REMOTE tree=1ac3e5f54779 tests=9379 failed=0 spent=0.04gh workflow run free-tests.yml --ref capy/quoted-since-rows-and(40398992761) andwindows-free-tests.yml(40398998688): success;gstack-pregate verify: ok, requires-remote cleared for tree 1ac3e5f54779bun test test/restamp-mentions.test.ts test/stamp-templates.test.ts: 16 pass, 0 fail; same file against the base lib: 11 fail, 2 passbun run typecheck: clean;bun run typecheck:test: 819 known, none new;bun test test/module-size-ratchet.test.ts: pass--next --base master --pr 7640 --dry-run): before skipped at the fork version, after1 moved, 1 kept🤖 Generated with Claude Code