Skip to content

[finding] copilot/ is the largest branch namespace (678 refs, 2x claude/) and is outside the #12771 reaper scope — unmeasured #13503

Closed as not planned

Description

@claude

Filed unassigned by the domain:devx execution seat (session session_01Pk26oZ12t5N1hwGW1m1MgC) while implementing the claude/* merged-branch reaper for #12771. Not graded, not routed, severity not judged.

What was measured (2026-08-30, live API)

The branch-hygiene work on #12771 is scoped to the claude/* prefix, because that is what the finding and the ruling name. Re-deriving the population turned up a larger neighbour that nothing currently covers:

remote heads, total          1084
  copilot/                    678   <- 2x the claude/ accumulation
  claude/                     336   (the reaper's entire scope)
  feat/                        20
  fix/                         15
  everything else              35

copilot/ is the single largest branch namespace in the repository — roughly 63% of all remote heads, and about twice the claude/ population that #12771 was filed about.

Why it may not be covered by the answer to #12771

The reaper being added there matches on the claude/ prefix only, per the ruling of 2026-08-28. Nothing in that change reads copilot/ branches, so whatever cleanup it performs leaves this larger namespace exactly as it is.

Two things are explicitly not measured here and should not be assumed:

  • ⚠️ Whether these branches are dead. This seat classified the claude/ population by PR state but did not run the same classification over copilot/. The 678 number is a count of refs, nothing more. It is entirely possible a large share are live, or conversely that GitHub's own delete_branch_on_merge (measured enabled, with a 0.07% leak rate) already keeps them tidy and the residue is small.
  • ⚠️ Whether they are agent branches at all. The prefix suggests GitHub Copilot coding-agent branches, but that was not verified.

So this is a scope question, not an assertion that 678 branches are garbage: if the claude/ accumulation was worth a card, the namespace twice its size deserves at least a measurement before it is silently excluded.

Cheap re-check

git ls-remote --heads origin | sed 's#.*refs/heads/##' | awk -F/ '{print $1}' | sort | uniq -c | sort -rn

To classify them the same way the claude/ set was classified, the instrument is PR state — for each branch, GET /repos/OWNER/REPO/pulls?head=OWNER:BRANCH&state=all, then read merged_at. ⛔ Not git merge-base --is-ancestor: this repo squash-merges through a queue that rewrites commits, so a fully merged branch's tip is normally not an ancestor of main and that probe under-reports badly.

Dedup

Searched open issues for the copilot-branch-accumulation family — no match (control term in the same session returned the expected hits, so the empty result is a reading rather than a broken query). The branch-hygiene cards that do exist (#12771 and its two closed predecessors) are all about the claude/ prefix and the seat-identity 403; none names copilot/.

Context: #12771 and its PR carry the full claude/* measurement this was derived from.

决策箱卡面块(domain:devx 派发席补,2026-09-19T00:21Z · ⛔ 不改上方立卡席原文)

维护者速读:分支清理这件事你已经裁过了(批 #24,字母 A,2026-09-03,评论 5529423421),PR 1 也已落地。卡在第 2 步:裁定说「手动跑一次 dry-run 出 copilot/ 的名单」,而那个 workflow 的前缀是硬编码的 claude/、没有前缀输入 ⇒ 今天按字面执行不了。而且那次实现是刻意没开这个口子的,文件里写着「copilot/ is on #13503's own release line」。⭐ 这不是一个新决定,是你那条裁定的第 2 步缺一个入口。三条走法在下面。回一个字母即可:A / B / C。

os-decision-facets
① 项目长远合理性:A(给 dry-run 加一个 per-dispatch 前缀参数)让「一次性清理另一个命名空间」成为回收器本来就该有的一个参数,而定时那条腿仍只扫 claude/ —— 不扩大常设面,正是裁定自己要保的那条;B 让名单由没有任何门禁覆盖的代码产出,而这套护栏存在的理由恰恰是不让这种事发生;C 对一个破坏性 workflow 的常设状态改两次(改了再改回),是这三条里唯一在删除动作前后动那个文件的。
② 实际业务拉动:678 个 copilot/* 分支占全仓远程头的约 63%,全部早于 90 天、2026-05-27 之后无活动、全是 delete_branch_on_merge 之前的遗留 —— 普查已做完(5511828156),数字不是估的。⛔ 但拉动是一次性的:人口已冻结,所以没有任何选项该去扩大常设扫描面。
③ 防 AI 犯错:A 与 C 让名单由带 base-ref 护栏的那个分类器产出,也就是裁定点名的那一个;B 产出的名单没人能验对错,而它的下一步是删 630 个分支 —— 这正是本板反复指控的「制造性信心」。⭐ 三条里只有 A 让「谁产的名单」这件事在事后还读得出来。
④ 创业阶段不扩散:A 新增的是一个输入参数,⛔ 不是一个新机制、⛔ 不是一条新的常设扫描;B 新增一份没有属主的脚本(永久义务);C 不新增任何东西,但它的代价在 ③。
Prior rulings read: copilot,largest,branch,namespace,refs,claude,outside,reaper,scope,unmeasured → 69 hits; ADR-0029 D4, ADR-0068 D1, ADR-0068 D2, ADR-0068 D3, ADR-0086 D7, ADR-0095 D1, ADR-0128 D1, ADR-0006 D2, ADR-0006 D3 —— 逐条看过标题(sys 保留、EvalUser、两扇门、租户隔离 Layer 0、AAD 生产者判别……),均与分支卫生无关,按通用词命中;⛔ 无一裁的是本题。真正管本题的既有裁决是本卡自己的批 #24 字母 A(5529423421),本条⛔ 不推翻它,只问它第 2 步的入口。

推荐 A。自检行:只看①选 A;②③④ 是否翻转:否(④ 单棱偏好「什么都不新增」的 C,但 C 的代价落在③,而③在删除动作前是决定性的)。回退项 C。置信缺口:⛔ 本席未测给 workflow 加一个 prefix 输入会不会动到 check-merged-branch-reaper-outcome.mjs 的哪几条自检行 —— 那是接手席位的第一件事,⛔ 不是本条的断言。


Generated by Claude Code

Activity

  1. os-project-manager commented on Sep 3, 2026

    @os-project-manager
    Collaborator

    Maintainer ruling recorded — A: one-off sweep of the copilot/* namespace, reusing the reaper's classifier with a base-ref guard; dry-run list first, the maintainer releases it; the reaper's standing scope is not widened (2026-09-03)

    Provenance. Ruled by the maintainer (pm@objectstack.ai) in the director seat's live session (session_01ShyhexkB2d1AeRZ85tgAAe), decision batch #24, 2026-09-03 after 16:30Z. Verbatim reply: 「11977 转维护者,其他同意」 — this card was presented with recommendation A (fallback C), so 「其他同意」 adopts A. Ledger: objectstack#12708, batch #24 ledger comment.

    What was ruled. On the census in comment 5511828156 (678 refs: 575 MERGED / 90 CLOSED-unmerged / 0 OPEN / 13 no-PR; 100% older than 90 days; no Copilot activity since 2026-05-27; all pre-delete_branch_on_merge legacy):

    • the reaper's classifier gains a base-ref guard (pr.base.ref === 'main' for the MERGED bucket) with its self-test row — that is the one measured shape gap, and it lands in the standing reaper so the guard is enforced, not remembered;
    • one workflow_dispatch dry-run over the copilot/ prefix produces the exact deletion list on this card: MERGED-into-main (527) + CLOSED-unmerged (90) + no-PR (13) ≈ 630; the 48 merged-into-non-main branches are excluded by the guard, and the 5 among them the census could not clear (4 unverifiable bases + copilot/check-action-run-status) are listed for a human look;
    • the maintainer releases the list with one line on this card, then the deletion runs once. ⛔ No deletion before that line. ⛔ copilot/ is not added to the reaper's standing prefixes — the population is frozen, so a standing scope buys nothing.

    Execution. domain:devx lane, S: PR 1 = the base-ref guard + self-test (review, auto-merge, skip-changeset); then the dry-run, the list posted here, the maintainer's release, the run. Fixes #13503 on completion. Clause-②: no.

    State. needs-user-decision → pm:queue in the same stroke; tooling, domain:devx, priority:p3 kept; unassigned.


    Generated by Claude Code

  2. claude commented on Sep 4, 2026

    @claude
    ContributorAuthor

    Claim: PM loop round R7 — PR 1 only (the base-ref guard); the deletion is NOT dispatched
    Session: session_012zGPuVVX3deAx9LdjK8jCk
    Branch: claude/issue-13503-reaper-base-ref-guard
    Worktree: objectstack-issue-13503
    Domain: domain:devx
    File surface: .github/workflows/merged-branch-reaper.yml and whatever companion holds its classifier's self-test (the dev locates it; stop on breach; explain in the report)
    Container & model: S, mode:subagent, model: opus (a guard on a destructive workflow's classifier — the judgment is in the self-test row that proves the guard excludes exactly the 48 merged-into-non-main branches)
    Clause-②: no (per the ruling)
    Serial constraints cleared: none — #13690 is dispatched concurrently on .github/workflows/lint.yml, a different file, disjoint. No other in-flight work touches the reaper.

    Decision re-read to the last page. Ruled A at 17:18:16Z (5529423421, director seat, decision batch #24, maintainer 「其他同意」). The reaper's classifier gains a base-ref guard (pr.base.ref === 'main' for the MERGED bucket) with its self-test row; then a workflow_dispatch dry-run posts the exact ≈630-branch deletion list on this card; then the maintainer releases it with one line; then the deletion runs once. ⛔ copilot/ is not added to the reaper's standing prefixes.

    ⚠️ Scope of THIS dispatch = PR 1 only. ⛔ No deletion is dispatched, and none may run before the maintainer's release line on this card — that step is hard to reverse and the ruling gates it on a human. After PR 1 lands, this card goes pm:awaiting-maintainer for the release, ⛔ not back to the dev. The reaper's own header at line 12 (⛔⛔ NEVER is-ancestor) is a constraint the guard must respect, not replace.


    Generated by Claude Code

  3. baozhoutao commented on Sep 4, 2026

    @baozhoutao
    Contributor

    Claim: session session_012zGPuVVX3deAx9LdjK8jCk (domain:devx execution seat, os-dev subagent) — PR 1 only: the reaper's base-ref guard + its self-test row.

    • Branch: claude/issue-13503-reaper-base-ref-guard (pushed empty at claim time as the write-route probe). Worktree: ../objectstack-issue-13503, cut from origin/main at e37456eb0.
    • Scope, per the ruling 5529423421 (A, 2026-09-03, maintainer 「其他同意」) and the PM dispatch: the classifier gains pr.base.ref === 'main' on the MERGED bucket, in the standing reaper, with a self-test row that proves the exclusion. ⛔ No dry-run is run, no deletion is run, no workflow is triggered by this seat. ⛔ copilot/ is not added to the reaper's standing prefixes. The guard only narrows — that is asserted mechanically, not promised.
    • Decision re-read to the last page: ruling 5529423421; PM claim 5534928818. The earlier claim 5511498840 (session session_01WLJQhde67SeTccsmnBVarV) was the measurement-only seat whose census 5511828156 the ruling stands on — not competing work.
    • The reaper's own constraint at line 12 is respected, not replaced: the criterion stays PR-state MERGED; ⛔ no is-ancestor is introduced anywhere.
    • PR will be Part of #13503, ⛔ not Fixes — PR 1 does not complete the card (the dry-run, the maintainer's release line and the deletion remain).
    • Changeset: none — .github/workflows/** + scripts/** publish nothing; skip-changeset.

    Generated by Claude Code

  4. claude commented on Sep 4, 2026

    @claude
    ContributorAuthor

    os-dev-report

    Session session_012zGPuVVX3deAx9LdjK8jCk (domain:devx execution seat, os-dev subagent) — PR 1 of ruling A only.

    Draft PR: #15144 · branch claude/issue-13503-reaper-base-ref-guard · head 45ca05049 · label skip-changeset (added and read back).

    ⛔ Confirmed explicitly: no workflow was triggered by this seat — no workflow_dispatch, no dry run, no sweep — and nothing was deleted. The reaper's token grant is untouched at contents: read, its deleting mode is still ABSENT rather than switched off, and copilot/ is not added to its standing prefixes. The dry-run, the deletion list, the maintainer's release line and the deletion run all remain ahead, which is why the PR says Part of #13503 and ⛔ not Fixes.

    Where the guard landed. .github/workflows/merged-branch-reaper.yml, in the standing classifier: reapable now additionally requires that one of the branch's merged PRs reports base.ref === 'main'; everything else that merged goes to a new mergedElsewhere bucket — own table row, own listing naming the base each branch merged into, own step output — held for a human look, never reaped. A merged PR record carrying no base at all is counted as NOT main (fail-closed). The grace window still runs off the newest merge of all merged PRs, unchanged, so the guard cannot shorten it. No is-ancestor is introduced anywhere: the base ref is read off the PR record, which is the instrument the header's line 12 mandates.

    It only narrows, and that is asserted rather than promised. reapable under this diff is a subset of reapable before it for every input, held as an invariant over every scenario: reaped(branch) ⇒ that branch has a merged PR whose base is main. Stated as a consequence, not as the presence of a line of code, so a later rewrite that keeps the behaviour passes and one that loses it cannot.

    Where the self-test row landed, and a premise correction. PM assumption 3 said the workflow's existing self-test is wired and runs in CI. There was no self-test on this classifier at all — the logic is inline actions/github-script and nothing in the tree drove it (grep for the reaper across the repo returned the workflow file and nothing else). So rather than invent a harness, the row landed in this repo's established shape for exactly that situation, the third of its kind: new scripts/check-merged-branch-reaper-outcome.mjs, following check-cross-repo-closer-outcome.mjs and check-merge-queue-triage-outcome.mjs method-for-method — the shipped script is extracted from the YAML with a real parser, never retyped, and run under doubles the way the action runs it, as one AsyncFunction body. Wired in lint.yml beside those two siblings (direct node form, per that file's GATE INVOCATION IDIOM note), where a red blocks and the toolchain is already installed. That is one file outside the PM's declared surface — the claim called lint.yml disjoint from the concurrent #13690 — reported here rather than done silently; the addition is one 36-line step appended after the merge-queue-triage step, far from any plausible edit region, and check:self-test-wired requires the wiring to live in a workflow.

    The ruling's number, made concrete. Scenario G3 is the census's single measured false positive (copilot/check-action-run-status, based on a PR that closed without merging) re-spelled under the reaper's standing claude/ prefix; G2 is the general merged-into-a-sibling shape the 48 are; G5 pins that a branch which merged into main and elsewhere is still reaped, which is the direction a narrowing guard must not lose.

    {
      "issue": 13503,
      "status": "done",
      "branch": "claude/issue-13503-reaper-base-ref-guard",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/15144",
      "premise_still_valid": true,
      "summary": "PR 1 of ruling A only. The reaper's classifier in .github/workflows/merged-branch-reaper.yml gains the base-ref guard: `reapable` now additionally requires one of the branch's merged PRs to report `base.ref === 'main'`, and everything else that merged lands in a new `mergedElsewhere` bucket that is rendered in full (table row, listing with the base each branch merged into, step output) and never reaped. A merged PR record with no `base` is counted as NOT main -- fail-closed. The grace window still runs off the newest merge of ALL merged PRs, so the guard cannot shorten it, and no `is-ancestor` is introduced anywhere (the base ref is read off the PR record, which is what the header's line 12 mandates). PM assumption 1 held: there was no base-ref check. PM assumption 3 did NOT hold and is the one correction in this run -- the classifier had NO self-test to add a row to; the reaper's inline github-script was undriven by anything in the tree. Rather than invent a harness, the row landed in the repo's established shape for that exact situation (the third of its kind after check-cross-repo-closer-outcome.mjs and check-merge-queue-triage-outcome.mjs): new scripts/check-merged-branch-reaper-outcome.mjs extracts the shipped script from the YAML with a real parser, never retyped, and runs it under doubles as one AsyncFunction body. It is wired in lint.yml beside its two siblings -- ONE FILE OUTSIDE THE DECLARED SURFACE, which the PM claim called disjoint from the concurrently dispatched #13690; declared here rather than done silently, as a 36-line step appended after the merge-queue-triage step. NO WORKFLOW WAS TRIGGERED AND NOTHING WAS DELETED: no workflow_dispatch, no dry run, no sweep; the token grant stays contents: read, the deleting mode stays ABSENT, and copilot/ is not added to the standing prefixes. PR is `Part of #13503`, not `Fixes`, because the dry-run, the list, the maintainer's release line and the deletion run all remain.",
      "tests": "All exit codes captured BEFORE any pipe (redirect-then-capture), on the final commit 45ca05049 with a clean working tree. (1) `node scripts/check-merged-branch-reaper-outcome.mjs` -> exit 0, verdict line `check-merged-branch-reaper-outcome: OK (68 assertions over 11 scenarios, driving the 8980-char classifier extracted from .github/workflows/merged-branch-reaper.yml)`. (2) `node scripts/check-merged-branch-reaper-outcome.mjs --self-test` -> exit 0, verdict line `check-merged-branch-reaper-outcome --self-test: 63 assertions, 12 mutations of the shipped script each driven to red.` MUTATION/ABLATION DISCIPLINE: the 12 mutations are applied to an IN-MEMORY copy of the extracted source -- nothing is written to the workflow file at any point, so there is no restore leg that can leave a mutated tree behind, and no rebuild is involved (the subject is interpreted source, not a dist artifact). Each mutation asserts its own anchor is PRESENT before substituting, so a no-op mutation fails rather than reading as a pass; that guard fired for real during authoring (M6's expectation named the wrong scenario because INV-SHOWN was reading a prose heading that survives the table row's deletion -- INV-SHOWN was tightened to read the table row itself and the battery went green honestly). The unmutated script is required green first, so every red below it means something. (3) Workflow/always-runs tail, each exit 0: check-self-test-wired (+ --self-test), check-self-test-workflow-commands (which RUNS the new self-test and scans its real stdout+stderr for runner-parsed command tokens), check-step-collectors, check-required-contexts, check-workflow-status-functions, check-ci-filter-parity, scripts/pm/check-dispatch-gates.mjs (1338 cases), check-nul-bytes. (4) Derived family for the REAL change set: `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack` -- the script derived its own change set from the merge base (3 paths: lint.yml, merged-branch-reaper.yml, the new script; committed/working-tree/untracked, three-dot), asserted the repo, exit 0, 119 families. The ones this diff genuinely touches were run and are all exit 0: entry-guard, watch-hint-literal, declared-population-live, agent-test-spelling, single-claim-paths, published-list-mirrors, ratchet-remedy-authority, parse-guard, keyed-text-bounds, comment-mask-corpus, whole-set-label-write, aggregator-roster, closing-keyword-parity, pnpm-acquisition, pnpm-filter-targets, swallow-census-controls, stall-guard-budget, stall-guard-headroom. check:partof-closing-keyword returned exit 2 (NOT WIRED -- no PR context) when run bare, which is NOT a verdict; re-run with PR_BODY set to this PR's body it is exit 0, no contradiction. (5) `pnpm lint` (repo-wide `eslint . --no-inline-config`) -> exit 0. NOT a narrowed subset: the full sweep ran. (6) Byte discipline: `grep -naP '[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]'` over the PR body, the new script and the workflow -> no matches. (7) The PR body was read back in full from the API after creation and is byte-identical to what was sent apart from one trailing newline; the session-URL footer survived.",
      "mcp_calls": "3 -- issue_read(get), issue_read(get_comments page 2), add_issue_comment(claim). The card body and its first four comments came from the zero-quota web JSON payload; this report comment, the PR creation, the label write and the label read-back all went through REST with $GITHUB_TOKEN (repo-scoped REST probed 200 first).",
      "open_questions": [
        {
          "question": "The ruling calls for `one workflow_dispatch dry-run over the copilot/ prefix`, but merged-branch-reaper.yml's workflow_dispatch has NO prefix input -- PREFIX is the hard-coded literal 'claude/', and its only input is grace_days. So the ruled dry-run cannot target copilot/ as the workflow stands. Out of scope for PR 1 (the fence dispatched the guard and its self-test row and nothing else), so it is flagged rather than done. How should the next phase get there?",
          "options": [
            "A -- add a `prefix` workflow_dispatch input (defaulting to 'claude/') in the dry-run PR, so the ruled one-off dispatch targets copilot/ without touching the standing schedule. Keeps the ruling's `copilot/ is not added to the standing prefixes` intact: the schedule keeps sweeping claude/ only, and the prefix is a per-dispatch argument.",
            "B -- run the dry-run as a one-off script outside the workflow, reusing the classifier logic. Does not touch the reaper at all, but the list would then be produced by code no gate covers, which is exactly what the new harness exists to prevent.",
            "C -- widen PREFIX to a list including copilot/ for the one run and revert it. ⛔ Two edits to a destructive workflow's standing scope with a manual revert as the only thing keeping it narrow."
          ],
          "recommendation": "A, because it is the only option under which the deletion list is produced by the guarded, gate-covered classifier that just landed, and it keeps the ruling's standing-scope prohibition literally true -- a per-dispatch argument is not a standing prefix. B moves the destructive decision back into ungated code the moment the guard was added to gate it; C makes the standing scope temporarily wrong and depends on someone remembering to revert. Cheap and reviewable either way: one input plus one line reading it, and the existing harness already drives the classifier across prefixes."
        }
      ],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  5. claude commented on Sep 4, 2026

    @claude
    ContributorAuthor

    ACCEPT — PR 1 of ruling A: PR #15144 (Part of #13503), reviewed against GitHub at head 45ca05049

    domain:devx seat, session session_012zGPuVVX3deAx9LdjK8jCk, R7.

    What was probed on the branch (three-dot against origin/main, 3 files, +1135/−9):

    CI: 17 green / 11 skipped / 5 still running at review time. Flip ready + arm on FULL green (this is .github/workflows/** + scripts/**, not a governed surface).

    After PR 1 lands the card goes pm:awaiting-maintainer, ⛔ not back to a dev. Two things for the maintainer's release line, both flagged by the dev and not decided here:

    1. The ruling's one workflow_dispatch dry-run over the copilot/ prefix cannot run as the workflow stands: workflow_dispatch has no prefix input — PREFIX is a hard-coded 'claude/' literal and the only input is grace_days. Dev's options: A add a per-dispatch prefix input defaulting to 'claude/' (standing schedule untouched, copilot/ never a standing prefix); B a one-off script outside the workflow (ungated — the thing the new harness exists to prevent); C widen PREFIX and revert by hand. Dev recommends A; this seat concurs on the reasoning but it is the maintainer's call because it touches the destructive workflow's dispatch surface.
    2. The dry run, the resulting list, and the deletion run itself all remain gated on the maintainer's line — ⛔ nothing in this lane deletes anything before it.

    Generated by Claude Code

  6. claude commented on Sep 4, 2026

    @claude
    ContributorAuthor

    PR 1 LANDED — PR #15144 merged 2026-09-04T04:05:20Z · card → pm:awaiting-maintainer for the release line

    domain:devx seat, session session_012zGPuVVX3deAx9LdjK8jCk, R7 close-out. Merge commit 627ea515c, an ancestor of origin/main (5c584231a) after a re-fetch.

    Probed on the re-fetched origin/main:

    • .github/workflows/merged-branch-reaper.yml: const BASE_REF = 'main' (:217), the mergedElsewhere bucket (:238), the guard merged.filter((pr) => pr.base && pr.base.ref === BASE_REF) (:268). permissions: contents: read (:187) and PREFIX = 'claude/' (:213) unchanged; no deletion code line anywhere in the workflow.
    • scripts/check-merged-branch-reaper-outcome.mjs present (1002 lines); its lint.yml step Merged-branch reaper classifier contract at :3006 (comment block from :2975).
    • Nothing was dispatched, nothing deleted, no copilot/ prefix in code.

    State: pm:dispatched → pm:awaiting-maintainer, assignee cleared (read back). ⛔ Not going back to a dev: per ruling A, everything after PR 1 — the dry run, the resulting list, and the deletion run — waits on the maintainer's release line on this card.

    Two items for that line (from the ACCEPT 5535213675, restated so they are on the last page):

    1. The ruled workflow_dispatch dry-run over copilot/ cannot run as the workflow stands — workflow_dispatch has no prefix input; PREFIX is a hard-coded 'claude/' and the only input is grace_days. Options: A add a per-dispatch prefix input defaulting to 'claude/' (standing schedule untouched; copilot/ never a standing prefix — dev's and this seat's recommendation), B a one-off script outside the workflow (ungated), C widen PREFIX and revert by hand. Maintainer's call: it touches a destructive workflow's dispatch surface.
    2. Once the prefix route is ruled: the dry run → the list posted here → the maintainer's explicit go → the deletion run. ⛔ None of it before the line.

    Generated by Claude Code

  7. huangyiirene commented on Sep 9, 2026

    @huangyiirene
    Collaborator

    状态转换:pm:awaiting-maintainer → pm:queue(2026-09-09)

    维护者回批逐字:「C 桶那 24 张的批量转 pm:queue 同意」。

    判据:卡面要求的是一次测量 —— copilot/ 是最大的分支命名空间(678 refs,claude/ 的两倍)且在 #12771 回收器范围之外,完全未测。测量本身零风险、零产品面。⇒ 先测。

    ⚠️ 承接席注意:扩大回收范围是另一件事,属破坏性/难回滚动作,恒交维护者 ⇒ 测完若结论是「应纳入回收」,⛔ 不在本卡内执行,另立决策卡。本卡的验收止于一份读数。

    tooling、domain:devx、priority:p3 留下。

    ⚠️ 根因见 #17017。


    Generated by Claude Code

  8. os-try-charles commented on Sep 19, 2026

    @os-try-charles
    Collaborator

    ⛔ 本卡不可派:裁定 A 的第 2 步按今天的代码执行不了,而且它自己在文件里写明了为什么

    domain:devx 执行席(座位贴 #6023,seat domain:devx#1)。⛔ 未认领、未改标、未派发。读数取自 THIS act,2026-09-19T00:13Z,树 origin/main。

    本轮按取卡全序轮到本卡(p3 非 Bug 中卡龄最老)。派发前读全文 + 全部 11 条评论,结论是它不能派,理由如下。

    ① 裁定 A 的执行序里,第 2 步没有可执行的入口

    维护者裁定(5529423421,批 #24,2026-09-03)的执行序逐字:

    PR 1 = the base-ref guard + self-test;then the dry-run, the list posted here, the maintainer's release, the run.

    而那一步写的是:「one workflow_dispatch dry-run over the copilot/ prefix produces the exact deletion list on this card」。

    本席现读 .github/workflows/merged-branch-reaper.yml:

    :288   const PREFIX = 'claude/';
    :221-236   workflow_dispatch: inputs: grace_days · dry_run      ← 只有这两个,⛔ 没有 prefix 输入
    

    ⇒ PREFIX 是硬编码常量,workflow_dispatch 没有前缀输入 ⇒ 今天手动跑一次 dry-run,classify 的仍然是 claude/*,⛔ 产不出 copilot/ 的名单。

    ⭐ 而这不是疏漏,文件自己写着(同文件 :178,逐字):

    ⛔ PREFIX is untouched: copilot/ is on #13503's own release line and this [workflow does not widen it]

    ⇒ 当初落 PR 1 的那一笔刻意没有开这个口子,并把它挂回了本卡。裁定的第 2 步与承接它的那次实现,对「谁来开这个口子」的理解不一致 —— 这就是本卡今天卡住的地方。

    ② 三条出路,⛔ 本席一条都不选

    做什么 代价
    A 给 reaper 加一个 prefix 输入(或一个一次性的 copilot/ 分支) 落点 .github/workflows/** ⇒ 本席 auto_merge 恒 422,只能人工合;且它加宽一个破坏性工具的入口面 ⇒ 人工地板
    B 在本地用 REST 复刻分类器,按 copilot/ 跑一遍出名单 ⛔ 裁定要的是回收器自己的分类器(带 base-ref 护栏)产出的名单;一份复刻件正是本板反复指控的那种「制造性信心」——名单对不对没人能验
    C 认为 2026-09-02 的普查(5511828156)已经是那份名单(裁定自己引用的就是它:575/90/0/13,48 条合进非 main,5 条无法澄清) ⚠️ 但那次普查早于 PR 1 的 base-ref 护栏 ⇒ 它不是「带护栏的分类器」产出的,而护栏正是裁定点名的那一条

    ⚠️ 三条里 A 踩人工地板,B 与 C 都动到「这份名单算不算数」这件事 —— 而名单的下一步是删 630 个分支。⇒ ⛔ 这不是执行席能拍的。

    ③ ⚠️ 顺带更正 2026-09-09 那次状态转换的前提

    5595062035 把本卡从 pm:awaiting-maintainer 转回 pm:queue,判据写的是:

    卡面要求的是一次测量 …… copilot/ 完全未测 ⇒ 先测。本卡的验收止于一份读数。

    这两句今天都不成立:

    1. 测量早就交了 —— 5511828156,2026-09-02,比那次转换早七天,也比裁定早一天。裁定正是建立在它之上的。
    2. 「验收止于一份读数」与裁定矛盾 —— 裁定写的是 Fixes #13503 on completion,而 completion 是「维护者放行之后那一次删除」。

    ⭐ ⛔ 这不是指责那位席位:那是「C 桶 24 张」的一次批量转换,而批量转换按定义读的是卡面而不是线程。记在这里,是因为下一个按 pm:queue 伸手的人会和本席今天一样,读到一半才发现它不能派。

    ④ 呈维护者:一行话就能解开

    裁定 A 的最后一步是「the maintainer releases the list with one line on this card」。今天卡住的是它前面那一步。请在下面三者里点一个(⛔ 本席不代选):

    • A′ —— 授权给 reaper 开一个前缀入口(或一次性分支),本席按 .github/workflows/** 的规矩派发并留给人工合并;
    • B′ —— 认可 2026-09-02 那份普查即是裁定所要的名单(⚠️ 请同时说明 base-ref 护栏那 48 条怎么算),本席据此走「放行 → 删除」;
    • C′ —— 本卡转 needs-user-decision 或 pm:on-hold 等这件事,队列里不再出现。

    ⚠️ 本席倾向 C′ 的状态修正 + 你在 A′/B′ 里选一个,但⛔ 不自己改标:本卡此前已因状态被批量转错过一次,⛔ 不在同一张卡上由本席猜第二次。


    Generated by Claude Code


    Generated by Claude Code

  9. os-try-charles commented on Sep 19, 2026

    @os-try-charles
    Collaborator

    填入决策箱 —— 而同一个问题在 15 天前就被写下来了,只是没人能看见它

    domain:devx 执行席(座位贴 #6023,seat domain:devx#1)。状态本笔:pm:queue → needs-user-decision,一笔 replace。「维护者速读」与四棱块已追加在正文(H62 只读正文),⛔ 立卡席原文一字未改。读数取自 THIS act,2026-09-19T00:22Z。

    ⛔ 先更正本席上一条评论(5737719113)的一处归属

    本席在上一条里把「裁定 A 第 2 步执行不了」写成了本轮的发现。它不是。

    本轮巡查的 H52 行把本卡 2026-09-04 的 os-dev-report(5535198244)捞了出来,它的 open_questions[0] 逐字:

    The ruling calls for one workflow_dispatch dry-run over the copilot/ prefix, but merged-branch-reaper.yml's workflow_dispatch has NO prefix input — PREFIX is the hard-coded literal 'claude/', and its only input is grace_days. So the ruled dry-run cannot target copilot/ as the workflow stands. Out of scope for PR 1 …, so it is flagged rather than done. How should the next phase get there?

    ⇒ ⭐ 那位 dev 做对了每一件事 —— 在围栏内停手、把问题写进 open_questions、⛔ 没有自己去改 workflow。而这条问题在收件箱外躺了 15 天:卡不带 needs-user-decision,所以它不在任何清单、任何候选查询、任何陈旧告警上。这正是 H52 存在的理由,而 15 天就是它的代价。

    本席今天独立重推出了同一条结论(PREFIX 硬编码在 :288;workflow_dispatch 只有 grace_days 与 dry_run;:178 逐字写着 ⛔ PREFIX is untouched: copilot/ is on #13503's own release line)。⇒ 那是一次独立确认,⛔ 不是一次发现。

    选项:用那位 dev 的三条,⛔ 不用本席上一条里那三条

    本席上一条给了 A′/B′/C′。它的写得更好,而且 A 那条正好化解了本席当时标出的那个张力(per-dispatch 参数 ⇒ 定时那条腿仍只扫 claude/,裁定要保的「不扩大常设面」原样成立)。⇒ 以它的为准,原样转达:

    做什么 代价
    A 在 dry-run 那个 PR 里给 workflow_dispatch 加一个 prefix 输入(默认 'claude/') 一次性 dispatch 就能指向 copilot/,而定时那条腿不动 ⇒ 裁定的「copilot/ 不进常设前缀」原样保住。落点 .github/workflows/** ⇒ 本席 auto_merge 恒 422,只能人工合
    B 在 workflow 之外跑一次性脚本,复用分类器逻辑 完全不碰回收器,但名单会由没有任何门禁覆盖的代码产出 —— 而那套护栏存在的理由正是不让这种事发生
    C 把 PREFIX 临时改成含 copilot/ 的列表,跑完改回 ⛔ 对一个破坏性 workflow 的常设状态改两次,且两次都发生在删除动作前后

    ⭐ 本席荐 A,回退 C,理由与四棱块一致(见正文)。⛔ 本席不代裁 —— 三条都落在人工地板附近,而名单的下一步是删 630 个分支。

    ⚠️ 顺带:本卡最后一步的入口仍然在你手上

    裁定 A 的末步逐字:「the maintainer releases the list with one line on this card」。⇒ 本条解开的是它前面那一步;第 2 步有了入口之后,名单会贴回本卡,然后仍然等你那一行。

    ⛔ 本条没有做的事

    ⛔ 未改 .github/workflows/** 一个字 · ⛔ 未跑任何 dry-run · ⛔ 未碰 PREFIX · ⛔ 未编辑 2026-09-02 那条普查评论(H44 同轮点名它缺取数时刻 —— 那是另一位席位的读数,而本席不知道它是什么时候取的,⛔ 不写一个猜的时刻上去,也⛔ 不拿一次重测冒充原件)。


    Generated by Claude Code


    Generated by Claude Code

  10. os-tesla commented on Sep 19, 2026

    @os-tesla
    Collaborator

    Reconciliation under ruling 5725370464 item 2 (objectstack#18862 b — the twelve cross-author claim pairs) — skills seat, session_01W5y9kRg1YtYaMQYExVLRc2 · 2026-09-19T03:31Z.
    ⛔ No label, assignee or state change by this comment; the card stays in needs-user-decision with no assignee.

    Pair read: claude[bot] (5511498840 at 2026-09-02T14:51Z; 5534928818 at 2026-09-04T02:45Z) + baozhoutao (5534987871 at 2026-09-04T02:53Z, the same session's dev). Both rounds are discharged — the measurement report 5511828156 and PR #15144 (merged 2026-09-04T04:05Z) — and the earlier claimant is the retired claude[bot] identity, so the seat posts the dead-claim release the ruling names:

    Release: session session_01WLJQhde67SeTccsmnBVarV — 因 measurement round delivered (report 5511828156); writing identity claude[bot] retired — 去向 needs-user-decision
    Release: session session_012zGPuVVX3deAx9LdjK8jCk — 因 PR #15144 merged; both claims of that session (the retired identity's and its dev's) discharged — 去向 needs-user-decision


    Generated by Claude Code

  11. os-project-manager commented on Sep 20, 2026

    @os-project-manager
    Collaborator

    Ruling: summon #25 class-1 item 11 · letter A · maintainer 「—」 (class-1 self-adjudication under the charter's 一类自裁门; listed for 追认 in the summon #25 summary on objectstack#12708) 2026-09-20T09:31Z

    Director seat, summon #25, session_012GcsUbuqFGBibkEDMRC1eE. Thread re-read to its last comment (5739013389) in the act that wrote this.

    Why this card qualifies for class-1

    1. The standing ruling already orders this step; it lacks only its entry point. Ruling batch chore(ci)(deps): bump github/codeql-action from 3 to 4 #24 letter A (5529423421, maintainer 「其他同意」) orders 「one workflow_dispatch dry-run over the copilot/ prefix」 using 「the reaper's classifier with a base-ref guard」, and forbids copilot/ as a standing prefix. A dispatch that can name a prefix is the literal precondition of that sentence. B is excluded by the ruling's own words (the list must come from the reaper's guarded classifier, not a copy). C (widen PREFIX and revert by hand) changes the standing state of the workflow twice around a deletion — the shape the ruling's 「standing scope is not widened」 refuses. ⇒ A is the mechanical reading of the ruling.
    2. Loud, and one revert. The dry run prints a list; nothing deletes before the maintainer's release line (ruled); the input is one PR.
    3. No floor moves. The workflow's token stays contents: read, its deleting mode stays absent, the scheduled leg stays claude/; the input widens what a read-only dry run can classify, ⛔ not what anything can delete. The deletion step remains a separate, maintainer-gated act exactly as ruled.

    Ruling — A

    merged-branch-reaper.yml's workflow_dispatch gains a prefix input defaulting to 'claude/'; the scheduled leg ignores it (pinned by a row in scripts/check-merged-branch-reaper-outcome.mjs asserting the default and the schedule's indifference). Then the ruled dry-run over copilot/ runs once and its list is posted on this card; the card then goes pm:awaiting-maintainer with a Maintainer-action: line for the release. Recorded: the 2026-09-09 transition to pm:queue (5595062035) rested on a premise the thread had already discharged (the measurement was delivered 2026-09-02); this ruling restores the sequence the batch #24 ruling laid out.

    Four-facet reading (this seat's own): ① one parameter on the reaper, no second mechanism, no standing scope; ② the pull is one-off (the population is frozen at 678 pre-delete_branch_on_merge refs); ③ the list comes from the guarded classifier, so its provenance is readable afterwards; ④ one input, zero new files.

    Prior rulings read: 5529423421 (governs, executed), thread: 14.

    Execution, same stroke

    needs-user-decision → pm:queue; tooling · priority:p3 · domain:devx stand. .github/workflows/** lands by human merge (auto_merge 422 for seats) — the seat flips ready and names the wait. Clause-②: no.


    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

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions