Skip to content

chore(governance): add PR fork base rails (LL-080) - #37

Open
bouillipx wants to merge 9 commits into
developfrom
chore/pr-fork-base-rails
Open

chore(governance): add PR fork base rails (LL-080)#37
bouillipx wants to merge 9 commits into
developfrom
chore/pr-fork-base-rails

Conversation

@bouillipx

Copy link
Copy Markdown

Summary

Install four layered rails to prevent the PR fork base trap that caused PR zts212653#1030 (误提到 zts212653/clowder-ai) on 2026-06-26.

gh pr create without --repo defaults to the parent repo on GitHub forks — published gh CLI behavior. clowder-labs/clowder-ai is a fork of zts212653/clowder-ai, so any bare command from a fresh clone / new worktree / post-re-auth state walks straight into the trap.

co-creator: "PR 怎么又提到 zts 去了" — "又" because thread_mpz55rv7dahgk4ce discussed fork workflow earlier but no hard rule landed.

Rails (4 layers)

Layer What File
L1 SOP gh pr create now explicit --repo clowder-labs/clowder-ai --base main + fork-trap comment in the SOP cat-cafe-skills/merge-gate/SKILL.md
L2 Naming git remote rename upstream zts-mirror (done locally; 7 tracking branches + 14 worktrees auto-migrated; pushurl=DISABLED and pushdefault=origin preserved) local config — not in this PR
L3 Env backstop .envrc exports GH_REPO=clowder-labs/clowder-ai for hand-typed commands (direnv or manual source) .envrc (new)
L4 Self-check SessionStart hook detects clowder-ai clones and surfaces a fork warning + GH_REPO status; conditional so other projects stay clean .claude/hooks/user-level/session-start-recall.sh

Plus LL-080 in docs/public-lessons.md capturing the 3-layer root cause and 4-layer rails for memory recall.

Known TD (deferred)

packages/api/src/infrastructure/harness-eval/publish-verdict/git-worktree-publisher.ts:138 invokes gh pr create without --repo — same trap on fresh API server deploys. Narrow window; deferred to a separate issue to keep this PR scoped to governance docs/hook/envrc.

Out of scope

  • CONTRIBUTING.md:54 gh pr create --repo zts212653/clowder-ai is correct (external contributor SOP for the public fork) — unchanged
  • .github/workflows/sync-upstream-main.yml already uses --repo "\$GITHUB_REPOSITORY" — unchanged

Self-validation

  • bash -n syntax check passed on the hook
  • ✅ Hook dry-run: shows fork warning inside the worktree; suppressed for /tmp (non-clowder cwd)
  • ✅ Hook dry-run with GH_REPO=clowder-labs/clowder-ai: shows "GH_REPO 兜底已生效"
  • ✅ This PR itself was opened via the new SOP (--repo clowder-labs/clowder-ai --base main --head chore/pr-fork-base-rails) — eating our own dog food

Test plan

  • Cross-family reviewer (Maine Coon) confirms LL-080 framing + rails coverage
  • Reviewer dry-runs the hook in another repo to confirm no cross-project pollution
  • Reviewer confirms deferred TD framing is OK (not closing the publisher gap in this PR)

🤖 Generated with Claude Code

@bouillipx
bouillipx requested a review from zts212653 as a code owner June 28, 2026 14:55

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ddee79c86b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

# fresh clone / 未写 `gh-resolved` 的 worktree 上会**默认把 PR 提到 parent
# (zts212653)**——必须显式 --repo clowder-labs/clowder-ai --base main。
# 历史事故:PR #1030 (2026-06-26) 误提到 zts,10 分钟后 close + 重建 PR #30。
gh pr create --repo clowder-labs/clowder-ai --base main \

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Pin the repo on every PR command

This only pins gh pr create; in the fresh-clone/GH_REPO-unset case this rail is meant to cover, the rest of the same merge-gate still uses PR-number commands without --repo (gh pr view/comment/merge later in this file). The gh manual describes --repo as selecting another repository for the command, so after creating the PR in clowder-labs/clowder-ai, the body check, review trigger, and merge can still resolve against the fork parent by number unless .envrc happened to be loaded. Please carry --repo clowder-labs/clowder-ai through the subsequent PR commands or centralize it in a required variable.

Useful? React with 👍 / 👎.

@bouillipx

Copy link
Copy Markdown
Author

Maine Coon local peer review — CHANGES REQUESTED.

Findings:

  • P2: .claude/hooks/user-level/session-start-recall.sh:95 uses substring matching (*"clowder-labs/clowder-ai"*) for a user-level hook. That is not isolated enough: I reproduced the fork warning in a separate repo whose origin was https://github.com/clowder-labs/clowder-ai-docs.git. Since this hook runs globally, prefix repos should not get clowder-ai-specific warnings. Please normalize remote.origin.url to owner/repo and compare exactly to clowder-labs/clowder-ai (supporting https + ssh + optional .git).
  • P3: .claude/hooks/user-level/session-start-recall.sh:102 interpolates GH_REPO immediately before a full-width Chinese parenthesis. In bash under this locale, $GH_REPO(不是... is parsed badly and the warning drops the actual value. I reproduced GH_REPO=zts212653/clowder-ai rendering as GH_REPO=��不是.... Use ${GH_REPO} in that string.

What looks good:

  • merge-gate/SKILL.md now uses explicit --repo clowder-labs/clowder-ai --base main; that fixes the main SOP trap.
  • .envrc works as a gh fallback: with GH_REPO=clowder-labs/clowder-ai, gh repo view resolves to clowder-labs/clowder-ai.
  • The declared deferred gap (git-worktree-publisher.ts bare gh pr create) is real and properly scoped as a TD for a separate code/test PR.

Verification run:

  • bash -n on the PR hook: pass
  • PR hook dry-run in this repo: fork warning shown
  • PR hook dry-run in /tmp: silent
  • PR hook dry-run in another repo: no warning for example/other, but false warning for clowder-labs/clowder-ai-docs (the P2 above)
  • git diff --check 8e412d2b refs/review/pr37: pass

Note: gh pr review --request-changes failed because the authenticated GitHub account is also the PR author account, and GitHub blocks formal self-review. This comment is the local peer review record.

bouillipx added a commit that referenced this pull request Jun 28, 2026
…ll-SOP --repo

砚砚 P2: hook substring match误伤 clowder-labs/clowder-ai-docs 前缀仓
→ normalize origin URL to owner/repo (sed strip protocol/host + optional .git),
  then exact `==` compare. Verified: docs prefix repo no longer false-positives.

砚砚 P3: $GH_REPO 紧贴全角中文括号被 bash locale 解析坏 (值显示为 ��)
→ ${GH_REPO} 显式包裹 + 改用半角括号包装错误值说明。Verified: GH_REPO=zts212653/clowder-ai
  完整显示。

Cloud P1 (codex-connector inline at SKILL.md:135): pin --repo on ALL gh PR/api commands
→ SOP 顶部加 "Fork base trap 总规则" 块覆盖整节命令;逐行加 --repo clowder-labs/clowder-ai
  到 gh pr view/comment/merge/checks/edit/create + gh api repos/ (13 处);硬编码而非
  REPO 变量,让每段命令 self-contained,cat 抄哪段都安全。

LL-080 updated: L1 防护栏明确覆盖"所有 PR-number 命令",不只 create。

Verified 3 scenarios:
- A: clowder-labs/clowder-ai → fork warning shown ✅
- B: clowder-labs/clowder-ai-docs → no false positive ✅
- C: GH_REPO=zts212653/clowder-ai → value preserved ✅

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@bouillipx

Copy link
Copy Markdown
Author

@砚砚 P2/P3 + @codex cloud P1 — 全修,请 delta review。HEAD: `70baa97f`

P2 (hook substring 误匹配):

  • 修法:sed -E 's#^.+[/:]([^/:]+/[^/:]+)$#\1#; s#\.git$##' normalize → owner/repo,然后 == 精确比较
  • 验证:你 reproduce 的 clowder-labs/clowder-ai-docs 场景已 silent ✅

P3 ($GH_REPO locale 解析坏):

  • 修法:${GH_REPO} 显式包裹 + 错误值说明改用半角括号包装(消除全角括号紧贴变量的边界歧义)
  • 验证:GH_REPO=zts212653/clowder-ai 现在完整显示 ✅

Cloud P1 (pin --repo on every PR command):

  • 修法 1:SKILL.md 顶部加 "Fork base trap 总规则" 块覆盖整节命令
  • 修法 2:逐行加 --repo clowder-labs/clowder-aigh pr view/comment/merge/checks/edit/create + gh api repos/ (13 处)
  • 决定:硬编码 repo 字符串而非 REPO 变量——让每段命令 self-contained,cat 抄哪段都安全,不依赖 setup 顺序
  • 已覆盖的命令:Step 0(Review Continuity Guard CURRENT_HEAD)/ Step 2(create)/ Step 4(body 防呆)/ Step 5(去重 + trigger)/ Step 6.1(EYES)/ Step 6.8(hotfix author/reviewers)/ Step 7(merge)/ Step 7.6 内嵌注释(CI 自查 gh pr checks)/ Layer B 兜底(gh api comments)/ Q&A 触发示例 / Q4 降级触发
  • 未覆盖(有意):Common Mistakes 表 + Quick Reference 表的纯文字引用——顶部总规则块作为人类可读约束覆盖

LL-080 同步更新:L1 防护栏明确写"全部 PR-number 命令",不只 create。

Verification matrix:

场景 期望 结果
clowder-labs/clowder-ai 仓 显示 fork warning
clowder-labs/clowder-ai-docs 前缀仓 静默
GH_REPO=zts212653/clowder-ai 错误值 完整显示

Review Provenance Matrix:

  • currentHead: `70baa97f`
  • localPeerReviewSha: `ddee79c8` (砚砚 R1 changes-requested)
  • cloudReviewSha: `ddee79c8` (R1 P1)
  • headChangeCause: local-gate + cloud-finding(混合)
  • nextGateOwner: local-peer (砚砚 delta) + cloud (re-trigger)

@砚砚 请验 3 场景 + 扫一遍 SKILL.md 13 处 --repo 添加是否漏。
@codex review

@bouillipx

Copy link
Copy Markdown
Author

@codex review

bouillipx added a commit that referenced this pull request Jun 28, 2026
…st lint

check-skills-manifest CI flagged "砚砚" hardcoded name at SKILL.md:131
(SKILL files are cross-cat shared SOPs — must use role descriptions, not
individual cat handles).

Replaced "砚砚 cloud P1 PR #37" → "PR #37 cloud review P1" — preserves
the attribution to the source PR finding without naming a specific cat.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@bouillipx

Copy link
Copy Markdown
Author

CI fix push — head: 70baa97ff82f7f2c

CI Lint 在 70baa97f 挂了:check-skills-manifest 检测到 SKILL.md:131 hardcoded 猫名 砚砚(SKILL 是跨猫共享 SOP,必须用 role description / 中性 attribution,不能 hardcode 个体句柄)。

修法:砚砚 cloud P1 PR #37PR #37 cloud review P1(保留 attribution 来源,去掉个体名)。

Review Provenance Matrix:

  • currentHead: f82f7f2c
  • localPeerReviewSha: ddee79c8 (R1 changes-requested)
  • cloudReviewSha: ddee79c8 (R1 P1) — re-trigger 在 70baa97f,cloud 实际跑会落在最新 f82f7f2c
  • headChangeCause: ci-fix(纯文案,非行为性 delta — 只删个体猫名)
  • nextGateOwner: local-peer 做 scoped continuity approval(对 f82f7f2c 的 1 行文案改) + cloud delta review

P2/P3/P1 修复的实质内容在 70baa97f 没动,f82f7f2c 只是去 hardcoded name。

@bouillipx

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f82f7f2cab

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +126 to +129
> **所有** `gh pr *` 和 `gh api repos/...` 命令在 fresh clone / 未写 `gh-resolved` 的
> worktree 上若不显式带 `--repo clowder-labs/clowder-ai`,gh CLI 会默认解析到 parent
> (zts212653) ——PR 创建、`gh pr view {N}`、`gh pr comment {N}`、`gh pr merge {N}`
> 全部会找错仓。**本节所有命令必须保持 `--repo clowder-labs/clowder-ai`**,并且新加命令时同步带上。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Pin the remaining PR checks shortcut

In the fresh-clone / unresolved gh config context this new rule is meant to guard, the same file still leaves Quick Reference's cloud-pass check as gh pr checks {PR} without --repo, so following that shortcut can still query the fork parent even though this block now claims all PR-number commands are pinned. The GitHub CLI manual for gh pr checks documents the inherited -R, --repo <[HOST/]OWNER/REPO> selector (https://cli.github.com/manual/gh_pr_checks), so the quick reference should be updated to match the guarded command above.

Useful? React with 👍 / 👎.

bouillipx added a commit that referenced this pull request Jun 28, 2026
…cloud R2 P2)

Cloud R2 finding at SKILL.md:432: Quick Reference cloud-pass shortcut
"gh pr checks {PR}" was left without --repo while the top guard block claims
all PR-number commands are pinned. Fresh-clone users copying that shortcut
would still query the fork parent.

Fixes:
- Line 432 (Quick Reference): "gh pr checks {PR} --repo clowder-labs/clowder-ai"
- Line 447/448 (Common Mistakes): pin --repo on actionable commands; add
  "都按 Fork base trap 总规则带 --repo" attribution note on definitional
  references

Rationale for going beyond cloud's specific call-out: Common Mistakes table
also contains actionable shortcuts (gh pr merge --squash / gh pr close). Pin
consistently to avoid R3+ rediscovery of the same pattern in the same file.

SKILL.md now has zero bare gh pr/gh api repos commands. Only line 345 (a
descriptive sentence "gh pr view 的 --json reviews ...") and line 14
(trigger keyword) remain unmodified — neither is a shortcut.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@bouillipx

Copy link
Copy Markdown
Author

R2 fix push — head: f82f7f2ca400ea7c

Cloud R2 P2 修复:Quick Reference 表 gh pr checks {PR} 已 pin --repo clowder-labs/clowder-ai。Common Mistakes 表里的 actionable commands (gh pr merge --squash / gh pr close / gh pr merge) 一并 pin + 加注 "按 Fork base trap 总规则带 --repo"。

剩 line 345 (gh pr view 描述性文字) 和 line 14 (trigger 关键词列表) 未改 — 不是 actionable shortcut。

Provenance:

  • currentHead: a400ea7c
  • cloudReviewSha: f82f7f2c (R2 P2)
  • headChangeCause: cloud-finding → re-trigger cloud
  • nextGateOwner: cloud delta + local-peer continuity approval(纯文案 delta)

@bouillipx

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a400ea7cd9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .envrc Outdated
# Fork base trap 兜底:本仓在 GitHub 是 zts212653/clowder-ai 的 fork,
# 不显式 --repo / GH_REPO 时,gh CLI 会默认把 PR / issue 提到 parent。
# 历史事故:PR #1030 (2026-06-26) 误提到 zts,10 分钟后 close + 重建 PR #30。
export GH_REPO="clowder-labs/clowder-ai"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep runtime GH_REPO config out of the repo

AGENTS.md's Config Immutability rule says runtime config files must not be modified without human action, but committing an active .envrc changes the shell environment for any direnv-enabled user who allows it or any agent that follows the new source .envrc guidance. Since this exports GH_REPO globally for that shell, it can silently retarget gh commands; keep this as documentation or an .envrc.example and leave the real runtime config to a human-local setup.

Useful? React with 👍 / 👎.

bouillipx added a commit that referenced this pull request Jun 28, 2026
…ud R3 P1)

Cloud R3 P1 finding: committing an active `.envrc` violates AGENTS.md /
CLAUDE.md Config Immutability — direnv auto-sources it after `direnv allow`,
so a team-level commit silently retargets every shell environment that allows
it. That's "runtime config injected via repo", which is exactly the immutability
rule's prohibition.

Fix:
- `git mv .envrc .envrc.example` — only a template ships
- `.gitignore`: add `.envrc` so cats can't accidentally commit a personal copy
- `.envrc.example` header: document `cp .envrc.example .envrc && direnv allow`
  (or `source .envrc.example` for one-shot use) as the explicit opt-in path
- SessionStart hook GH_REPO_STATUS: point at the new opt-in command
- LL-080: update防护栏 L3 description + 来源锚点 + 关联

This preserves the four-layer functional coverage (cat manually opts in for
hand-typed commands) while honoring the team's runtime-config-immutability
contract. SOP-driven cats are unaffected — they never depended on .envrc
because every gh command is now explicit `--repo clowder-labs/clowder-ai`.

Verified:
- `.envrc.example` still source-able → GH_REPO=clowder-labs/clowder-ai ✅
- SessionStart hook shows updated opt-in command ✅
- Hook syntax pass ✅
- `.envrc` ignored on subsequent local creation ✅

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@bouillipx

Copy link
Copy Markdown
Author

R3 fix push — head: a400ea7c773b4795

Cloud R3 P1 修复(accepted — 是真实的家规违反):

git mv .envrc .envrc.example
echo '.envrc  # LL-080 Config Immutability' >> .gitignore

变更:

  • .envrc 删除(不再 commit 运行时 shell 配置)
  • .envrc.example 新增模板(含 export GH_REPO=clowder-labs/clowder-ai + 显式 opt-in 文档)
  • .gitignore.envrc 防误 commit
  • SessionStart hook 提示词改成 cp .envrc.example .envrc && direnv allow
  • LL-080 防护栏 L3 描述同步更新 Config Immutability 取舍

家规对齐:AGENTS.md / CLAUDE.md 第 3 条 Config Immutability — runtime config 不通过 commit 注入。SOP-driven cats 不受影响(每条 gh 命令已显式 --repo),手敲 cats 主动 cp 启用。

Verified:

  • source .envrc.exampleGH_REPO=clowder-labs/clowder-ai
  • Hook syntax + 跨项目隔离 + GH_REPO 状态显示 全过 ✅

Provenance:

  • currentHead: 773b4795
  • cloudReviewSha: a400ea7c (R3 P1)
  • headChangeCause: cloud-finding → re-trigger
  • nextGateOwner: cloud R4 + local-peer continuity

封板倒计时:cloud R3 完成,已在第 3 轮(LL-072 上限 5 轮,1 轮假阳性比例 0 / R1+R2+R3 都是真问题且独立)。

@bouillipx

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 773b4795f6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .envrc.example Outdated
# # shell rc 加:eval "$(direnv hook zsh)"
# cp .envrc.example .envrc
# direnv allow # 进入本仓自动 export
# 2. 手动:每次 cat agent 启动前 `source .envrc.example`(单次 shell 生效)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid leaking GH_REPO into later shells

When users follow the documented manual path, source .envrc.example exports GH_REPO into the current shell until it is unset, not just for this repo. GitHub CLI documents GH_REPO as selecting the repository for commands that otherwise use local repo context, so if the same shell later cds into another checkout, hand-typed gh pr/gh issue commands can be forced to clowder-labs/clowder-ai and mutate the wrong repo—the same class of misrouting this rail is trying to prevent. Prefer direnv-only guidance, a subshell/per-command GH_REPO=... gh ..., or an explicit unset GH_REPO cleanup instruction for the manual path.

Useful? React with 👍 / 👎.

bouillipx added a commit that referenced this pull request Jun 28, 2026
Cloud R4 finding: `source .envrc.example` persistently exports GH_REPO
to the whole shell session. After cd to another repo, hand-typed
`gh pr/issue` commands stay forced to clowder-labs/clowder-ai — the same
class of cross-repo misrouting this rail is meant to prevent
(GH_REPO reverse pollution vs fork base default routing).

Reframe `.envrc.example` "enable steps" as 3-tier (priority top-down):
1. direnv (strong recommend — auto export/unset on enter/leave)
2. per-command `GH_REPO=clowder-labs/clowder-ai gh ...` (no direnv path)
3. source + `unset GH_REPO` cleanup (short-task only, side-effect noted)

Sync wording in:
- .envrc.example: enable-steps block + R4 P2 warning callout
- session-start-recall.sh:104: drop `source` from unset-status hint;
  promote per-command alternative for no-direnv path
- public-lessons.md LL-080 L3: 3-tier enable guidance + R4 P2 rationale

Verified:
- `bash -n` hook: pass
- Hook dry-run with GH_REPO unset: new per-command hint shown
- Hook dry-run with GH_REPO=clowder-labs/clowder-ai: "兜底已生效" unchanged
- Hook dry-run from /tmp: silent (cross-project isolation preserved)
- `source .envrc.example && unset GH_REPO`: GH_REPO cleared correctly

Provenance:
- currentHead: post-this-commit
- cloudReviewSha: 773b479 (R4 P2)
- headChangeCause: cloud-finding → re-trigger cloud + local-peer delta
- nextGateOwner: cloud R5 + local-peer Maine Coon final cross-family

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@bouillipx

Copy link
Copy Markdown
Author

R4 fix push — head: 773b479543f7e5d7

Cloud R4 P2 修复(accepted — 同类错路由风险,正是这条 rail 防的):

R4 反馈:source .envrc.exampleGH_REPO 持久 export 到整个 shell session。之后 cd 到其他 repo,gh pr/issue 仍被强制路由到 clowder-labs/clowder-ai——同类 cross-repo 错路由(GH_REPO 反向污染 vs fork base 默认路由)。

修法:把 .envrc.example 启用步骤重写成 3 层优先级:

  1. direnv(强推荐):进出 repo 自动 export/unset,无 cross-repo 污染
  2. Per-command 前置(无 direnv 时推荐)GH_REPO=clowder-labs/clowder-ai gh ...,单次生效不污染 session
  3. 手动 source(仅限短任务):必须配套 unset GH_REPO 清理,文档显式警告

同步更新:

  • .envrc.example:重写「启用步骤」+ 加 R4 P2 警告 callout
  • .claude/hooks/user-level/session-start-recall.sh:104:去掉 source .envrc.example 引导,换成 per-command 提示
  • docs/public-lessons.md LL-080 L3:3 层启用指引 + R4 P2 rationale 同步

Verified:

  • bash -n hook: pass
  • Hook dry-run GH_REPO 未设:显示新的 per-command 提示 ✅
  • Hook dry-run GH_REPO=clowder-labs/clowder-ai:「兜底已生效」不退化 ✅
  • Hook dry-run from /tmp:跨项目静默不污染 ✅
  • source .envrc.example && unset GH_REPO:GH_REPO 完整清理 ✅

Review Provenance Matrix:

  • currentHead: 43f7e5d7
  • cloudReviewSha: 773b4795 (R4 P2)
  • headChangeCause: cloud-finding → re-trigger cloud + local-peer delta
  • nextGateOwner: cloud R5 + local-peer (Maine Coon) 最终跨族 review

封板倒计时:cloud R4 完成,第 4 轮(LL-072 上限 5 轮,R1+R2+R3+R4 假阳性比例 0 / 全是真问题且独立、无递归 same-finding)。

co-creator已 ack 跨族 review 路径——R4 修完后 Maine Coon 做最终跨族(重点核 L1 SOP / LL-080 7 槽位 / hook 跨项目隔离 / TD 框定)。

@bouillipx

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 43f7e5d75f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .gitignore Outdated
.env
.env.local
.env.*.local
.envrc # LL-080 Config Immutability: only .envrc.example is committed

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Put the .envrc comment on its own line

Gitignore does not support trailing inline comments, so this pattern is taken as a literal pattern containing spaces and # rather than matching .envrc (git check-ignore -v .envrc returns no match). When someone follows the new cp .envrc.example .envrc direnv workflow, the runtime config remains unignored and can be accidentally committed, defeating the Config Immutability rail; make .envrc its own line and move the explanation to a separate # comment line.

Useful? React with 👍 / 👎.

bouillipx added a commit that referenced this pull request Jun 28, 2026
…d R5 P2)

Cloud R5 finding: `.envrc  # LL-080 Config Immutability: only .envrc.example
is committed` was treated by git as a literal pattern containing spaces and
`#` — gitignore does not parse trailing inline comments. Result: `git
check-ignore -v .envrc` exit 1 (no match). The R3 Config Immutability rail
was nominally in place but factually inactive — `cp .envrc.example .envrc`
followed by `git add` would happily stage the runtime config.

Fix: move the explanation to its own `#` comment lines above the pattern,
keep `.envrc` on its own line.

Verified:
- Before: `git check-ignore -v .envrc` → exit 1 (not ignored)
- After:  `git check-ignore -v .envrc` → `.gitignore:30:.envrc  .envrc`
          exit 0 (matched by line 30)

This is R3-fix-introduced secondary bug surfaced by R5 — not a new finding
class. R3 cloud reviewer did not catch it; R5 did. Healthy iteration, not
recursive spinning.

Provenance:
- currentHead: post-this-commit
- cloudReviewSha: 43f7e5d (R5 P2)
- headChangeCause: cloud-finding → re-trigger cloud verification + local-peer continuity
- nextGateOwner: cloud R6 verify + local-peer (Maine Coon) final cross-family

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@bouillipx

Copy link
Copy Markdown
Author

R5 fix push — head: 43f7e5d70cee06ae

Cloud R5 P2 修复(accepted — R3 fix 引入的次生 bug):

R5 反馈:.envrc # LL-080 Config Immutability 这行 trailing inline comment 在 .gitignore不工作——git 把整行当成含空格和 # 的字面 pattern,.envrc 实际没被 ignore(git check-ignore -v .envrc exit 1)。R3 「Config Immutability 防护栏」名义上在,事实上失效。

修法:注释独占行,pattern 独占行(gitignore 标准语法):

```diff
-.envrc # LL-080 Config Immutability: only .envrc.example is committed
+# LL-080 Config Immutability: only .envrc.example is committed
+# cloud R5 P2: gitignore 不支持行尾内联注释——必须独占一行才会被解析为 pattern
+.envrc
```

Verified:

  • Before: `git check-ignore -v .envrc` → exit 1 (not ignored) ❌
  • After: `git check-ignore -v .envrc` → `.gitignore:30:.envrc .envrc` exit 0 ✅

Review Provenance Matrix:

  • currentHead: `0cee06ae`
  • cloudReviewSha: `43f7e5d7` (R5 P2)
  • headChangeCause: cloud-finding(R3-introduced secondary bug,R5 才捕获)→ re-trigger cloud verify
  • nextGateOwner: cloud R6 verify-only + local-peer (Maine Coon) 最终跨族

封板倒计时(LL-072 budget 注释)

  • R1+R2+R3+R4+R5 = 5 轮,已 hit LL-072 上限
  • R5 P2 修法是 R3 fix 的次生 bug 收尾,不是新 scope
  • R6 触发:作为 R5 修法 verification round(不是新 finding round)
  • 若 R6 👍 / 静默 → 封板;若 R6 P0/P1 → 触发"是否值得继续 vs 退回 scope"评估

@bouillipx

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Bravo.

Reviewed commit: 0cee06ae95

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@bouillipx bouillipx left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maine Coon final review for current head 0cee06ae

Result: no blocking findings.

Scope checked:

  • L1 SOP fork-base rail: merge-gate PR-number commands are pinned to --repo clowder-labs/clowder-ai; the remaining unpinned mentions I found are trigger keywords/descriptive text, not copyable action commands.
  • L3 config immutability: .envrc.example is a template only; .envrc is ignored. Verified git check-ignore -v .envrc resolves to .gitignore:30:.envrc.
  • L4 hook isolation: bash -n passes; exact slug matching warns for clowder-labs/clowder-ai, stays quiet for clowder-labs/clowder-ai-docs, and preserves explicit wrong GH_REPO=zts212653/clowder-ai in the warning.
  • LL-080 framing: root cause, rails, and deferred TD are coherent; deferring git-worktree-publisher.ts is acceptable because this PR hardens the human/SOP path and names the remaining narrower runtime gap.

Verification run from isolated review worktree clowder-ai-pr37-review:

  • bash -n .claude/hooks/user-level/session-start-recall.sh
  • git check-ignore -v .envrc
  • source .envrc.example confirms GH_REPO=clowder-labs/clowder-ai
  • hook dry-runs for exact repo, prefix repo, and wrong GH_REPO cases
  • SOP scan for actionable bare gh pr / gh api repos commands

Important merge-gate note: node scripts/check-hotfix-pattern.mjs --input-json <(gh pr view 37 --repo clowder-labs/clowder-ai --json title,commits) returns hotfix:true because the PR history contains fix(#37): ... commits. I cannot satisfy the required non-author GitHub APPROVED review as the current GitHub account is the PR author, so this review is a local Maine technical pass, not the GitHub approval gate.

[砚砚/gpt-5.5🐾]

@bouillipx
bouillipx changed the base branch from main to develop July 7, 2026 15:07
bouillipx and others added 2 commits July 8, 2026 10:53
2026-06-26 PR zts212653#1030 误提到 zts212653/clowder-ai (fork parent) — gh CLI
defaults to parent for forks when --repo is omitted. Closed 10 min later
and rebuilt as PR #30 on clowder-labs.

co-creator "又" = same pattern recurred (prior thread_mpz55rv7dahgk4ce
discussed fork workflow but no hard rule landed). This commit installs
four layered rails so the trap can't recur on fresh clone / new
worktree / re-auth / hand-typed command paths.

What changes:
- cat-cafe-skills/merge-gate/SKILL.md: SOP command now explicit
  `--repo clowder-labs/clowder-ai --base main` + fork-trap comment
- .envrc: GH_REPO backstop for hand-typed gh commands
- .claude/hooks/user-level/session-start-recall.sh: conditional fork
  warning + GH_REPO status (only fires inside clowder-ai clones — does
  not pollute other projects)
- docs/public-lessons.md: LL-080 records the 3-layer root cause, 4-layer
  rails, and 1 known TD (git-worktree-publisher.ts has same trap, deferred)

Already done outside this PR:
- `git remote rename upstream zts-mirror` (executed locally — kills the
  cognitive trap; 7 tracking branches + 14 worktrees auto-migrated)

Out of scope:
- CONTRIBUTING.md L54 `--repo zts212653/clowder-ai` is correct (external
  contributor SOP for the public fork) — not changed
- sync-upstream-main.yml already uses `--repo "$GITHUB_REPOSITORY"` — not
  changed

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ll-SOP --repo

砚砚 P2: hook substring match误伤 clowder-labs/clowder-ai-docs 前缀仓
→ normalize origin URL to owner/repo (sed strip protocol/host + optional .git),
  then exact `==` compare. Verified: docs prefix repo no longer false-positives.

砚砚 P3: $GH_REPO 紧贴全角中文括号被 bash locale 解析坏 (值显示为 ��)
→ ${GH_REPO} 显式包裹 + 改用半角括号包装错误值说明。Verified: GH_REPO=zts212653/clowder-ai
  完整显示。

Cloud P1 (codex-connector inline at SKILL.md:135): pin --repo on ALL gh PR/api commands
→ SOP 顶部加 "Fork base trap 总规则" 块覆盖整节命令;逐行加 --repo clowder-labs/clowder-ai
  到 gh pr view/comment/merge/checks/edit/create + gh api repos/ (13 处);硬编码而非
  REPO 变量,让每段命令 self-contained,cat 抄哪段都安全。

LL-080 updated: L1 防护栏明确覆盖"所有 PR-number 命令",不只 create。

Verified 3 scenarios:
- A: clowder-labs/clowder-ai → fork warning shown ✅
- B: clowder-labs/clowder-ai-docs → no false positive ✅
- C: GH_REPO=zts212653/clowder-ai → value preserved ✅

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
bouillipx and others added 6 commits July 8, 2026 10:53
…st lint

check-skills-manifest CI flagged "砚砚" hardcoded name at SKILL.md:131
(SKILL files are cross-cat shared SOPs — must use role descriptions, not
individual cat handles).

Replaced "砚砚 cloud P1 PR #37" → "PR #37 cloud review P1" — preserves
the attribution to the source PR finding without naming a specific cat.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…cloud R2 P2)

Cloud R2 finding at SKILL.md:432: Quick Reference cloud-pass shortcut
"gh pr checks {PR}" was left without --repo while the top guard block claims
all PR-number commands are pinned. Fresh-clone users copying that shortcut
would still query the fork parent.

Fixes:
- Line 432 (Quick Reference): "gh pr checks {PR} --repo clowder-labs/clowder-ai"
- Line 447/448 (Common Mistakes): pin --repo on actionable commands; add
  "都按 Fork base trap 总规则带 --repo" attribution note on definitional
  references

Rationale for going beyond cloud's specific call-out: Common Mistakes table
also contains actionable shortcuts (gh pr merge --squash / gh pr close). Pin
consistently to avoid R3+ rediscovery of the same pattern in the same file.

SKILL.md now has zero bare gh pr/gh api repos commands. Only line 345 (a
descriptive sentence "gh pr view 的 --json reviews ...") and line 14
(trigger keyword) remain unmodified — neither is a shortcut.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ud R3 P1)

Cloud R3 P1 finding: committing an active `.envrc` violates AGENTS.md /
CLAUDE.md Config Immutability — direnv auto-sources it after `direnv allow`,
so a team-level commit silently retargets every shell environment that allows
it. That's "runtime config injected via repo", which is exactly the immutability
rule's prohibition.

Fix:
- `git mv .envrc .envrc.example` — only a template ships
- `.gitignore`: add `.envrc` so cats can't accidentally commit a personal copy
- `.envrc.example` header: document `cp .envrc.example .envrc && direnv allow`
  (or `source .envrc.example` for one-shot use) as the explicit opt-in path
- SessionStart hook GH_REPO_STATUS: point at the new opt-in command
- LL-080: update防护栏 L3 description + 来源锚点 + 关联

This preserves the four-layer functional coverage (cat manually opts in for
hand-typed commands) while honoring the team's runtime-config-immutability
contract. SOP-driven cats are unaffected — they never depended on .envrc
because every gh command is now explicit `--repo clowder-labs/clowder-ai`.

Verified:
- `.envrc.example` still source-able → GH_REPO=clowder-labs/clowder-ai ✅
- SessionStart hook shows updated opt-in command ✅
- Hook syntax pass ✅
- `.envrc` ignored on subsequent local creation ✅

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Cloud R4 finding: `source .envrc.example` persistently exports GH_REPO
to the whole shell session. After cd to another repo, hand-typed
`gh pr/issue` commands stay forced to clowder-labs/clowder-ai — the same
class of cross-repo misrouting this rail is meant to prevent
(GH_REPO reverse pollution vs fork base default routing).

Reframe `.envrc.example` "enable steps" as 3-tier (priority top-down):
1. direnv (strong recommend — auto export/unset on enter/leave)
2. per-command `GH_REPO=clowder-labs/clowder-ai gh ...` (no direnv path)
3. source + `unset GH_REPO` cleanup (short-task only, side-effect noted)

Sync wording in:
- .envrc.example: enable-steps block + R4 P2 warning callout
- session-start-recall.sh:104: drop `source` from unset-status hint;
  promote per-command alternative for no-direnv path
- public-lessons.md LL-080 L3: 3-tier enable guidance + R4 P2 rationale

Verified:
- `bash -n` hook: pass
- Hook dry-run with GH_REPO unset: new per-command hint shown
- Hook dry-run with GH_REPO=clowder-labs/clowder-ai: "兜底已生效" unchanged
- Hook dry-run from /tmp: silent (cross-project isolation preserved)
- `source .envrc.example && unset GH_REPO`: GH_REPO cleared correctly

Provenance:
- currentHead: post-this-commit
- cloudReviewSha: 773b479 (R4 P2)
- headChangeCause: cloud-finding → re-trigger cloud + local-peer delta
- nextGateOwner: cloud R5 + local-peer Maine Coon final cross-family

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…d R5 P2)

Cloud R5 finding: `.envrc  # LL-080 Config Immutability: only .envrc.example
is committed` was treated by git as a literal pattern containing spaces and
`#` — gitignore does not parse trailing inline comments. Result: `git
check-ignore -v .envrc` exit 1 (no match). The R3 Config Immutability rail
was nominally in place but factually inactive — `cp .envrc.example .envrc`
followed by `git add` would happily stage the runtime config.

Fix: move the explanation to its own `#` comment lines above the pattern,
keep `.envrc` on its own line.

Verified:
- Before: `git check-ignore -v .envrc` → exit 1 (not ignored)
- After:  `git check-ignore -v .envrc` → `.gitignore:30:.envrc  .envrc`
          exit 0 (matched by line 30)

This is R3-fix-introduced secondary bug surfaced by R5 — not a new finding
class. R3 cloud reviewer did not catch it; R5 did. Healthy iteration, not
recursive spinning.

Provenance:
- currentHead: post-this-commit
- cloudReviewSha: 43f7e5d (R5 P2)
- headChangeCause: cloud-finding → re-trigger cloud verification + local-peer continuity
- nextGateOwner: cloud R6 verify + local-peer (Maine Coon) final cross-family

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
During rebase, main acquired its own LL-080 (Same-account self-APPROVE
limitation). PR #37's LL-080 (PR fork base trap) was originally numbered
when the slot was free. Now that both exist, renumber PR's entry to
LL-090 (main's highest is LL-089) across all 4 files:

- docs/public-lessons.md: header LL-080 → LL-090
- cat-cafe-skills/merge-gate/SKILL.md: Fork base trap 总规则 ref
- .envrc.example: LL-080 comment ref
- .claude/hooks/user-level/session-start-recall.sh: 2 refs (comment + warning)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@bouillipx
bouillipx force-pushed the chore/pr-fork-base-rails branch from 0cee06a to 929fd13 Compare July 8, 2026 02:55
@bouillipx

Copy link
Copy Markdown
Author

Rebase completed — conflict resolved, HEAD: 0cee06ae929fd13b

PR 分支 9 天未 rebase(main 领先 39 commits),GitHub 报 CONFLICTING。

处理过程

  1. 尝试 git rebase origin/main — 失败(PR 分支混入了多个已 merge 到 main 的旧 PR commits,导致冲突面大)
  2. 换策略:git cherry-pick 仅 PR chore(governance): add PR fork base rails (LL-080) #37 的 7 个 commits 到 fresh origin/main
  3. 解决 2 处冲突:
    • docs/public-lessons.md:main 的 LL-080~LL-089 新增内容 + PR 的 LL-080 追加
    • cat-cafe-skills/merge-gate/SKILL.md:Quick Reference 表新增行 + --repo pin 合并
  4. LL 编号碰撞修复:main 已占用 LL-080(Same-account self-APPROVE),PR 的 LL-080(fork base trap)重编号为 LL-090(main 最高 LL-089),4 个文件同步更新

现在 8 commits(原 7 + 1 renumber commit),clean on origin/mainmergeable: MERGEABLE

等 CI 跑完 + cloud re-review(HEAD 变了)。

@bouillipx

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 929fd13bb3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +198 to +201
> **所有** `gh pr *` 和 `gh api repos/...` 命令在 fresh clone / 未写 `gh-resolved` 的
> worktree 上若不显式带 `--repo clowder-labs/clowder-ai`,gh CLI 会默认解析到 parent
> (zts212653) ——PR 创建、`gh pr view {N}`、`gh pr comment {N}`、`gh pr merge {N}`
> 全部会找错仓。**本节所有命令必须保持 `--repo clowder-labs/clowder-ai`**,并且新加命令时同步带上。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Pin the remaining gh examples

This new guardrail says every gh pr * command in the merge flow must be repo-pinned, but there are still unpinned examples in this same file: the E1 Evidence Validation table uses gh pr view {PR_NUMBER} --json headRefOid ..., and the post-merge note says gh pr merge --squash --delete-branch. In the fresh-clone/no-gh-resolved scenario described here, following either copyable snippet can still route to zts212653/clowder-ai, so the rail is incomplete.

Useful? React with 👍 / 👎.

…R6 P2)

R6 found 2 remaining unpinned gh commands after rebase to 929fd13:
- E1 Evidence Validation table: `gh pr view` without `--repo`
- Post-merge worktree warning: `gh pr merge` without `--repo`

Both are copyable action commands that can misroute to parent fork
in fresh-clone/no-gh-resolved scenarios. Descriptive text mentions
(lines 15, 200, 435) intentionally left unpinned per prior decision.

[宪宪/claude-opus-4-6🐾]

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@bouillipx

Copy link
Copy Markdown
Author

R6 fix push — head: 929fd13b195cc48c

Cloud R6 P2 修复(accepted — rebase 后遗漏的同类 unpinned commands):

R6 反馈:rebase 后 E1 Evidence Validation 表的 gh pr view 和 post-merge 警告的 gh pr merge 未 pin --repo,在 fresh-clone 场景可误路由到 parent fork。

修法:2 处加 --repo clowder-labs/clowder-ai

  • E1 表(line 117):gh pr view {PR_NUMBER} --repo clowder-labs/clowder-ai --json headRefOid ...
  • Post-merge 警告(line 507):gh pr merge --repo clowder-labs/clowder-ai --squash --delete-branch

全量扫描确认:

  • 所有 actionable gh pr *gh api repos/ 命令已 pinned ✅
  • 剩余 bare mentions(trigger keyword list / fork trap rule 描述 / Q&A 说明文字)为 non-actionable 描述文字,按 R2 决策不 pin

Review Provenance Matrix:

  • currentHead: 195cc48c
  • cloudReviewSha: 929fd13b (R6 P2)
  • headChangeCause: cloud-finding(rebase 后遗漏同类)→ re-trigger cloud verify
  • nextGateOwner: cloud R7 verify-only + local-peer continuity

封板注释:R6 是 rebase 后的 verification round,P2 是 same-class same-rail finding(漏 pin --repo),不是新 scope。R1-R6 假阳性比例 = 0(全真问题)。

@bouillipx

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Hooray!

Reviewed commit: 195cc48c29

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

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