fix(slug): canonicalize slash branches to dash form so review rows stop splitting (#1127) - #2465
Open
ShuratCode wants to merge 3 commits into
Open
fix(slug): canonicalize slash branches to dash form so review rows stop splitting (#1127)#2465ShuratCode wants to merge 3 commits into
ShuratCode wants to merge 3 commits into
Conversation
Aligns gstack-slug with ship Step 8's tr '/' '-' so gstack-review-log and gstack-review-read stop writing feat/foo to featfoo while other writers use feat-foo. The [a-zA-Z0-9._-] invariant promised in the file header still holds; tr -cd remains the final filter. Refs garrytan#1127
Step 20 built ~/.gstack/projects/$SLUG/$BRANCH-reviews.jsonl by hand and also carried a literal BRANCH token in the JSON payload. A slash branch turned the redirect into a subdirectory write, or failed outright when the directory did not exist. gstack-review-log takes no path argument and already resolves the slug and branch, creates the directory, validates the JSON, and enqueues for gbrain sync. The BRANCH placeholder is replaced by a shell expansion. Refs garrytan#1127
|
Merging to
After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here |
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.
Fixes the writer half of #1127. Complements #1851, which fixes the read
half (Context Recovery lookup across 44
SKILL.mdfiles). The two areindependent and land cleanly in either order — #1851 canonicalizes the reads,
this canonicalizes the writes. I have not touched the read path.
The problem
Three different sanitizations of the same branch name coexist in gstack:
feat/foobecomestr -cd 'a-zA-Z0-9._-'— deletes the slashfeatfoobin/gstack-slug:52→gstack-review-log,gstack-review-readtr '/' '-'— replaces the slashfeat-fooship/sections/plan-completion.md:19(Step 8)feat/fooship/SKILL.md:1356(Step 20)So one branch's review rows land in up to three places, and
/retrosees afraction of its own history.
Live evidence, one project dir
20 branches are split across two files each, and the pattern is perfectly
consistent: the dash-form file holds only the
shiprow, the strip-form fileholds only the other skills' rows. Not one of the 20 is mixed.
Clearest single case, branch
feat/cdk-app-scaffold-R-1053:feat-cdk-app-scaffold-R-1053-reviews.jsonl(form 2) — the/shiprowfeatcdk-app-scaffold-R-1053-reviews.jsonl(form 1) — the/reviewrow,written three hours earlier the same day
feat/partners-list-page-R-620is the same shape with more on the strip side:/shipin the dash file,/reviewand/plan-eng-reviewin the strip file./retroreading either filename sees half the branch's history.Transform 3 has two failure modes, not one
This is the part worth stating plainly, because the two reports on #1127 look
like different bugs and are not:
feat/directory exists → the redirect dies withno such file or directoryand the row is lost silently. Reported upstream on1.60.1.0 for
feat/4-posting-service.feat/directory already exists → the write succeeds into it, and therow is invisible to every flat glob. That is the machine this was found on:
5 rows sit in
projects/<slug>/feat/."Rows are lost" and "rows are fragmented" are the same bug seen from two
machines.
The fix
1.
bin/gstack-slug— replace the slash instead of deleting it, sotransform 1 agrees with transform 2:
The file's header promises a
[a-zA-Z0-9._-]invariant. Still holds — thetr -cdstays as the final filter. Verified across shapes:2. ship Step 20 — the old block interpolated
$BRANCHinto a redirect pathand carried a literal
BRANCHtoken in the JSON, with a "substitute BRANCH =current branch name" instruction below it. A model doing that substitution can
hit the path too, which is what produces the
feat/subdirectory.It now routes through
bin/gstack-review-log, which takes no path argument,so there is nothing left to corrupt. The helper already resolves slug and branch,
creates the directory, validates the JSON, and enqueues for gbrain sync — the
step gets shorter, not longer. The
BRANCHplaceholder is gone entirely,replaced by a real shell expansion.
Edited
ship/SKILL.md.tmpland regenerated viabun run gen:skill-docs; thethree ship golden fixtures are regenerated in the same commit.
Migration: deliberately deferred
Change 1 renames
featfoo-reviews.jsonltofeat-foo-reviews.jsonl, so existingfiles are orphaned rather than rewritten. Not adding a migration, for a measured
reason: on the machine this was found, 303 of 308 rows (98.4%) are already
top-level and reachable by a flat glob. The 5 stranded rows are all
shiprowscarrying a
coverage_pctbut no plan-item counts (four0, one-1). Aone-time merge folding
featfoo-*andfeat/*into the canonicalfeat-foo-*, sorted by timestamp, is easy to add as a follow-up if a maintainerwants it — say the word and I will.
@kkru-labs suggested a shared canonical normalizer that every caller imports.
Aligning
gstack-slugis the minimal version of that idea (one authority insteadof three); extracting a real shared helper is a clean follow-up on top.
Verification
bun run test— green, except two failures proven pre-existing by runningthe same two files against
origin/mainin a clean worktree:test/skill-e2e-ios-swift-build.test.ts(Swift toolchain, local) andtest/helpers/observability.test.ts(counts/* non-fatal */comments insession-runner.ts). Neither touches anything in this diff.test/gstack-slug-sanitize.test.tspasses unchanged — it asserts the charsetinvariant on
SLUGand never pinned BRANCH slash-deletion.test/gen-skill-docs.test.tspasses — the ship union still containsreviews.jsonlvia the Context Recovery block.test/host-config.test.tsare greenagainst the regenerated fixtures.
slop-scan: no new findings in 6 changed files.above normalize as expected, one canonical flat file written, zero nested
directories created.
Conflict risk
Four open PRs also touch
ship/SKILL.md.tmpl: #2343, #2334, #2303, #2301. Noneof them touch Step 20, so this is textual-conflict risk on the generated
SKILL.mdand goldens, not a scope overlap. Happy to rebase behind whicheverlands first.
No
VERSIONbump orCHANGELOGentry here — following #1851, the sibling PR onthe same issue, and keeping this out of the way of the four in-flight ship
template PRs. Happy to add both if that is the house preference.