Skip to content

fix(context-recovery): look up <branch>-reviews.jsonl with the canonical slug form, not the raw branch (#1127)#1851

Open
harjothkhara wants to merge 1 commit into
garrytan:mainfrom
harjothkhara:fix/1127-context-recovery-review-branch-form
Open

fix(context-recovery): look up <branch>-reviews.jsonl with the canonical slug form, not the raw branch (#1127)#1851
harjothkhara wants to merge 1 commit into
garrytan:mainfrom
harjothkhara:fix/1127-context-recovery-review-branch-form

Conversation

@harjothkhara
Copy link
Copy Markdown

Summary

The Context Recovery preamble block (present in every skill) reports REVIEWS: N entries by probing $_PROJ/${_BRANCH}-reviews.jsonl, where $_BRANCH is the raw git branch --show-current. But gstack-review-log (writer) and gstack-review-read (reader) both name that file with the sanitized slug form from gstack-slug ($BRANCH, restricted to [a-zA-Z0-9._-]).

For any slashed branch — the conventional feat/*, fix/*, chore/* — the two forms disagree (feat/foofeat/foo vs featfoo), so the current branch's review count was never found. ($_BRANCH isn't even defined inside this self-contained block, making the lookup doubly fragile.)

Closes #1127.

Audit of every *-reviews.jsonl access

Site Branch form Role
bin/gstack-review-log $BRANCH via gstack-slug (strip) writer ✓
bin/gstack-review-read $BRANCH via gstack-slug (strip) reader ✓
ship/SKILL.md.tmpl $BRANCH via gstack-slug (strip) writer ✓
Context Recovery block raw $_BRANCH existence check ✗
specialist-stats, retro, artifacts-init * glob branch-agnostic ✓

So on current main the writers and reader already agree on the gstack-slug form — the Context Recovery existence check was the sole straggler.

Fix

Route the review lookup through $BRANCH (already in scope from the block's eval gstack-slug), matching how reviews are written and read. The timeline.jsonl greps keep using raw $_BRANCH — timeline records the raw branch in its branch field — and the generator now documents the two-form convention inline so they don't get conflated again.

Edited the source-of-truth generator scripts/resolvers/preamble/generate-context-recovery.ts; regenerated all SKILL.md via bun run gen:skill-docs (idempotent — the per-skill diff is exactly the one review line).

Scope

Deliberately converges the one remaining straggler onto the existing canonical sanitizer (gstack-slug). It does not change gstack-slug's output form, so there's no on-disk migration and no conflict with the in-flight gstack-slug PRs. Changing the canonical form itself (strip → dash for readability, as the issue suggests) is an orthogonal, migration-bearing decision left to the maintainer — now a one-line change in a single function.

Tests

test/regression-1127-context-recovery-branch-form.test.ts pins both halves (reviews → $BRANCH, timeline greps → $_BRANCH) for both claude and codex hosts. Green together with preamble-compose, review-log, gen-skill-docs, gen-skill-docs-idempotency, audit-compliance415 tests, 0 fail.

🤖 Generated with Claude Code

…cal slug form, not the raw branch (garrytan#1127)

The Context Recovery preamble block reported "REVIEWS: N entries" by probing
`$_PROJ/${_BRANCH}-reviews.jsonl`, where `$_BRANCH` is the raw
`git branch --show-current`. But gstack-review-log (writer) and
gstack-review-read (reader) both name that file with the *sanitized* slug form
from `gstack-slug` (`$BRANCH`, restricted to [a-zA-Z0-9._-]). For any slashed
branch — the conventional `feat/*`, `fix/*`, `chore/*` — the two disagree
(`feat/foo` → `feat/foo` vs `featfoo`), so the review count for the current
branch was never found. ($_BRANCH is also not even defined inside this
self-contained block, so the lookup was doubly fragile.)

Route the review lookup through `$BRANCH` (already in scope from the block's
`eval gstack-slug`), matching how reviews are actually written and read. The
timeline.jsonl greps keep using raw `$_BRANCH`, because timeline records the
raw branch in its `branch` field — documented inline in the generator so the
two forms don't get conflated again.

Deliberately scoped: this converges the one remaining straggler onto the
existing canonical sanitizer (gstack-slug). It does not change gstack-slug's
output form, so there is no on-disk migration and no conflict with the
in-flight gstack-slug work. Changing the canonical form itself (strip → dash
for readability, per the issue) is an orthogonal, migration-bearing decision
left to the maintainer.

Edited the source-of-truth generator
(scripts/resolvers/preamble/generate-context-recovery.ts); regenerated all
SKILL.md via `bun run gen:skill-docs` (idempotent). Added
test/regression-1127-context-recovery-branch-form.test.ts pinning both halves.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@trunk-io
Copy link
Copy Markdown

trunk-io Bot commented Jun 3, 2026

❌ This pull request has been removed from the merge queue because required statuses are not defined in .trunk/trunk.yaml, your repo's branch protection rules for main, or the merge queue specific settings. See more details here.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

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

@jbetala7
Copy link
Copy Markdown
Contributor

jbetala7 commented Jun 3, 2026

Independently reviewed against current main (c43c850c) — looks correct and complete. The split-form handling is exactly right:

  • Timeline greps correctly keep $_BRANCH (raw). In the assembled preamble _BRANCH is defined upstream by generate-preamble-bash.ts (_BRANCH=$(git branch --show-current ...)), and that raw value is what the timeline writers record — both the started event in generate-preamble-bash.ts and the completed event in generate-completion-status.ts write the branch field from git branch --show-current (raw). So grepping timeline.jsonl by $_BRANCH matches what was written.
  • Reviews lookup correctly switches to $BRANCH (slug). gstack-review-log writes $SLUG/$BRANCH-reviews.jsonl and gstack-review-read reads the same, where $BRANCH comes from gstack-slug (tr -cd 'a-zA-Z0-9._-'). For any slashed branch (fix/foofixfoo) the raw and slug forms diverge, so the old ${_BRANCH}-reviews.jsonl probe never matched the on-disk file — confirmed on main.

Collision check: no competing open PR (#1621 also touches the context-recovery block but only its slug-derivation, unrelated to the reviews-filename form). Regression test regression-1127-context-recovery-branch-form.test.ts covers it. LGTM.

Copy link
Copy Markdown
Author

/trunk merge

@harjothkhara
Copy link
Copy Markdown
Author

These look ready from my side — the branch is clean/mergeable and an independent review confirmed the fix is correct and complete. The only red check is the Trunk merge-queue gate, which from what I can tell just needs a maintainer to enqueue it (no code/test failure). @garrytan whenever you have a moment, could these be added to the merge queue? Happy to rebase if anything is needed. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Branch name sanitization disagrees across gstack: reviews for the same branch land in multiple files, dashboard misses entries

2 participants