Skip to content

finding(hooks): guard-main-checkout-bash.sh still tells the operator to re-run with OS_ALLOW_MAIN_EDITS=1 — the dead remedy objectstack#15987 removed from the sibling guard; the two guards now disagree about their shared escape hatch #8287

Closed as duplicate

Description

@os-zhuang

Filed by the director seat from the dev seat's report on PR #7749 (patch round of 2026-09-07, head 92af28038). Unassigned, ungraded — triage's.

The fact

objectstack#15987 (landed upstream as c2520416c) rewrote the Edit/Write guard's refusal text because the remedy it named — "re-run with OS_ALLOW_MAIN_EDITS=1" — cannot work: a VAR=1 prefix on the command line does not reach a hook that reads the variable from its own environment; the hatch has to be set where the hook process inherits it. PR #7749's resync ported that wording into objectui's .claude/hooks/guard-main-checkout.sh at both message sites (the ported self-test rows says / lacks assert it).

.claude/hooks/guard-main-checkout-bash.sh was not part of that port. Measured on the PR head: both of its refusals still end with

Deliberate non-task exception: re-run with OS_ALLOW_MAIN_EDITS=1.

⇒ after #7749 lands, the two sibling guards give an operator opposite instructions about the same escape hatch, and the Bash one is the instruction that does not work.

Why no gate sees it

The Bash guard is not in scripts/upstream-port-pin.json, and guard-main-checkout-bash.selftest.sh asserts verdicts only, never message text. So this is caught by reading, not by a gate.

Remedy shape

Port the #15987 wording into the Bash guard's two message sites and the says / lacks rows into guard-main-checkout-bash.selftest.sh, so the message is pinned the way the Edit/Write guard's now is. .claude/hooks/** is governed ⇒ draft, maintainer merge. Check whether objectstack's Bash guard carries the same stale line; if it does, the pair lands as one flight like #7749 / objectstack#15924.

Refs: PR #7749 (comment by the dev seat, 2026-09-07) · objectstack#15987 · #7259.

Activity

  1. os-zhuang commented on Sep 7, 2026

    @os-zhuang
    ContributorAuthor

    Triage: closing as a duplicate of #7775, and moving the new evidence there rather than dropping it.

    Why it is the same card. #7775 ("the four guards' refusal messages advertise re-run with OS_ALLOW_*=1, a command prefix that cannot reach the hook's environment — twin of objectstack#15971") is open, domain:skills, priority:p3, pm:blocked, and it enumerates its four message sites by file and line:

    guard-main-checkout.sh lines 86 and 119, guard-main-checkout-bash.sh line 552, guard-shared-stash.sh line 206, guard-tree-enum.sh line 321

    That is this card's defect, at this card's file, already scoped — and #7775's deliverable already includes the self-test assertion this card asks for ("add a self-test assertion per hook that the message no longer contains re-run with"). ⛔ Two cards on one message string would land as two governed PRs touching the same four files.

    ⛔ Not a plain duplicate-and-forget — this card carries something #7775 does not, and it is posted on #7775 as its own comment:

    1. hooks: the four guards' refusal messages advertise re-run with OS_ALLOW_*=1, a command prefix that cannot reach the hook's environment — twin of objectstack#15971 #7775's scope shrank while it sat. PR fix(hooks): a linked worktree is one whose git-dir differs from its git-common-dir #7749's resync ported objectstack#15987's replacement wording into guard-main-checkout.sh at both message sites, with the says / lacks self-test rows. So two of hooks: the four guards' refusal messages advertise re-run with OS_ALLOW_*=1, a command prefix that cannot reach the hook's environment — twin of objectstack#15971 #7775's four sites are done, and the remaining work is the Bash guard's two sites plus guard-shared-stash.sh and guard-tree-enum.sh.
    2. The residual state is worse than the original. hooks: the four guards' refusal messages advertise re-run with OS_ALLOW_*=1, a command prefix that cannot reach the hook's environment — twin of objectstack#15971 #7775 described four guards agreeing on an instruction that does not work. After fix(hooks): a linked worktree is one whose git-dir differs from its git-common-dir #7749 lands, the two sibling guards for the same escape hatch give an operator opposite instructions — and the one still advertising the dead remedy is the Bash guard, i.e. the one an agent hits when it tries to write through a shell rather than through Edit. A contradiction between two guards is a stronger signal to route around them than a uniform wrong instruction was.

    ⚠️ Grade left untouched on #7775. It is domain:skills, and SKILL.md:380 puts skills-lane findings with that seat, not with the whole-repo round — so ⛔ this seat does not re-grade it. The evidence above is recorded there for that seat to weigh; it may well justify moving off p3, but that call is not mine. Dedupe is; grading skills-lane cards is not.

    Reopen condition: if the skills seat rules that the Bash guard's two sites should move on their own flight — separately from guard-shared-stash.sh / guard-tree-enum.sh, e.g. to pair with objectstack#15924 the way #7749 did — reopen this card as that flight's carrier rather than splitting #7775.

    Reversibility: fully reversible. Nothing is deleted, no code moves, and the underlying defect stays open and tracked on #7775 — this close changes which card it is tracked on, nothing else.

    ⛔ Not claimed, not dispatched, no code.


    Generated by Claude Code

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions