Skip to content

Stop inventing "no PR" for the canonical checkout's own branch - #1695

Merged
njrini99-code merged 2 commits into
mainfrom
fix/lifecycle-canonical-pr-lookup
Aug 31, 2026
Merged

Stop inventing "no PR" for the canonical checkout's own branch#1695
njrini99-code merged 2 commits into
mainfrom
fix/lifecycle-canonical-pr-lookup

Conversation

@njrini99-code

Copy link
Copy Markdown
Owner

Found by the repo wiring audit (#1694), in the audit's own tooling.

The bug

const pr = w.branch && !isCanonical ? prFor(w.branch)
                                    : { lookup: 'OK', state: 'NONE' };

{ lookup: 'OK', state: 'NONE' } does not say "not checked." It says
"checked, and there is no PR." classifyBranch read it exactly as written
and returned UNKNOWN_PR"no PR found — cannot prove the work landed" — for
the canonical checkout's branch, even with an OPEN PR against it.

Reproduced against #1694: gh answered 1694 OPEN from the shell while the
tool's own report printed PR NONE.

Nothing was lost — UNKNOWN_PR fails safe to KEEP. But the tool was reaching
a right answer from an invented fact, in the evidence layer, which is the
precise failure this repo keeps removing everywhere else.

The shortcut bought nothing

classifyWorktree returns ACTIVE for canonical on its first line, before
any PR fact is read. Only the BRANCH verdict ever consumed these — and that is
the separation AGENTS.md insists on:

may this CHECKOUT go · may this BRANCH be deleted

The short-circuit conflated the two inside the tool that defines the
distinction.

The test took two attempts, and the first one looked fine

It passed with the bug reverted. canonicalRoot() resolves
.claude/hooks/lib/workspace-identity.mjs against the repo under test; fixtures
do not have one; so isCanonical is always false in the harness and the bug
is unreachable there.

That null is deliberate and correct — a fixture must never be able to claim it
is the real canonical checkout — but it also means every canonical-only branch
of this tool was untestable
. The fixture now writes its own identity stub, and
the test asserts ACTIVE first, proving it really is being treated as
canonical, before asserting the branch verdict.

Verified

Injection: reverting the one-line fix turns the new test red and everything
else green; restoring it returns the file byte-identical by sha256.

typecheck 0 · lint 0 · npm test 1275 files / 12,210 passed · guards 37/37

🤖 Generated with Claude Code

https://claude.ai/code/session_01NbDxyygyXRUEERuGocpZZH

…wn branch

The PR lookup was skipped for the canonical checkout and substituted with a
literal:

    const pr = w.branch && !isCanonical ? prFor(w.branch)
                                        : { lookup: 'OK', state: 'NONE' };

`{ lookup: 'OK', state: 'NONE' }` does not mean "not checked". It means
"checked, and there is no PR" — and classifyBranch read it exactly as written,
returning UNKNOWN_PR ("no PR found — cannot prove the work landed") for
canonical's branch even with an OPEN PR against it. Reproduced against #1694
on 2026-08-30: `gh` answered `1694 OPEN` from the shell while the tool's own
report printed PR `NONE`.

Nothing was lost — UNKNOWN_PR fails safe to KEEP — but the tool was reaching a
right answer from an invented fact, in the evidence layer, which is the exact
failure this repo keeps removing everywhere else.

The shortcut also bought nothing. classifyWorktree returns ACTIVE for canonical
on its FIRST line, before any PR fact is read. Only the BRANCH verdict ever
consumed these — and that is the separation AGENTS.md insists on: may this
CHECKOUT go, versus may this BRANCH be deleted. The short-circuit conflated the
two inside the tool that defines the distinction.

The test took two attempts, and the first one is worth recording because it
looked fine. It passed with the bug reverted — because canonicalRoot() resolves
.claude/hooks/lib/workspace-identity.mjs against the repo under test, fixtures
do not have one, so isCanonical is ALWAYS false in the harness and the bug is
unreachable there. That null is deliberate and correct (a fixture must never be
able to claim it is the real canonical checkout), but it means every
canonical-only branch of this tool was untestable. The fixture now writes its
own identity stub, and the test asserts ACTIVE first — proving it really is
being treated as canonical — before asserting the branch verdict.

Verified by injection: reverting the one-line fix turns the new test red and
everything else green; restoring it returns the file byte-identical by sha256.
typecheck 0, lint 0, npm test 1275 files / 12,210 passed, guards 37/37.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NbDxyygyXRUEERuGocpZZH
@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because your trial has ended. Ask your workspace admin to add credits to resume reviews. Manage billing

@vercel

vercel Bot commented Aug 31, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
helmv3 Ignored Ignored Preview Aug 31, 2026 3:55am

Request Review

@coderabbitai

coderabbitai Bot commented Aug 31, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: bad2bf32-bf4c-440e-994e-612390b9a798

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@supabase

supabase Bot commented Aug 31, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project qmnssrrolpinvwjjnufo because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@njrini99-code
njrini99-code merged commit 47254b4 into main Aug 31, 2026
48 checks passed
@njrini99-code
njrini99-code deleted the fix/lifecycle-canonical-pr-lookup branch August 31, 2026 04:07
njrini99-code added a commit that referenced this pull request Aug 31, 2026
njrini99-code added a commit that referenced this pull request Aug 31, 2026
… reads as a git bug (#1696)

* docs(audit): record the branch-durability blind spot and the zsh :r trap

Two findings from finishing the wiring audit.

**Nine branches held commits that existed nowhere but this laptop** — up to 95
on one — and the lifecycle tool reported none of them. It was not wrong to: it
checks the protected prefixes (backup/, preserve/, recovered/, stage/) BEFORE it
checks for unique upstream-less work, so those branches return KEEP_PROTECTED
and never reach the durability verdict. Both verdicts are correct in isolation.
The ordering means the branches named for preservation are exactly the ones
whose non-durability is invisible.

That also reconciles an earlier claim rather than contradicting it. The
2026-08-30 closeout recorded `NO_UPSTREAM_UNIQUE_WORK remaining: NONE` after
pushing ten branches, and that was true as stated — protected branches were
never in that verdict's population.

All nine were scanned and pushed. gitleaks: no leaks found across 127 commits
on the four largest, run BEFORE any push; the only secret-shaped literal was
.env.example's placeholder `your-service-role-key`. Branches whose work exists
in one place: 9 -> 0.

Left as a design question, not repaired: whether KEEP_PROTECTED should also
report unique-work status. A protected branch cannot be deleted by the tool, so
the durability fact is advisory rather than load-bearing — that is a decision
about what the report should say, not a defect to fix.

**A zsh trap that reads as a git bug.** Pushing those branches failed seven
times with `src refspec ... does not match any` against refs that resolved
fine. In zsh, "refs/heads/$b:refs/heads/$b" parses $b:r as the `:r` history
modifier and eats it, producing
`refs/heads/recovered/stash-0efs/heads/recovered/stash-0`. The same command
typed literally works, which is what makes it convincing — it only appears when
the branch name is a variable. Recorded in shipping.md §3 alongside the other
traps of its kind (`timeout` on macOS, `ls` aliased to eza).

Verified: docs:schema-drift 0, docs:path-drift 0, knowledge:check 0, markdown
ratchet at baseline, and the durability re-measure returns 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NbDxyygyXRUEERuGocpZZH

* chore(control-plane): clear #1695's expired transitional row, register #1696

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NbDxyygyXRUEERuGocpZZH

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

1 participant