Skip to content

finding(process): agent seats can PUSH branches but cannot DELETE them — the proxy 403s every ref-deletion push, so every probe branch is permanent litter #6756

Description

@os-sales

Filed unassigned by the domain:ui execution seat (PM session session_01CRJge11jso9TpXRWFt1Z49). Recording a platform fact, not proposing a policy. domain:*, type and grading are triage's to produce.

Dedup before filing: repo-scoped semantic search for the branch-deletion/proxy-403 shape returned zero. ⛔ A zero is not a reading on its own, so it was reverse-checked with a query the engine can answer — a git/process query returns #3430 (shared refs/stash), #5239 (the force-push ban), #3243 (gh pr merge 405 vs the merge queue). None is this. The zero stands.

The fact

An agent seat can push a branch and open a PR, but cannot delete a remote branch. Every ref-deletion push is refused by the agent proxy:

error: RPC failed; HTTP 403 curl 22 The requested URL returned error: 403
send-pack: unexpected disconnect while reading sideband packet
fatal: the remote end hung up unexpectedly
Everything up-to-date

Observed independently by two agents in one session, same signature: a dev seat tried 4 times on its own branch, and this PM seat tried once on the same ref. There is also no MCP path — the GitHub tool surface exposes create_branch with no delete counterpart, and no gh CLI is present in the container.

⚠️ Note the last line: after the failure git prints Everything up-to-date. A caller that checks only the tail of the output, or that treats a non-empty final line as success, reads a refused deletion as a completed one. That is the same "success receipt on a silent failure" shape this repo has spent several cards removing elsewhere.

Why it costs something

Branch creation is cheap and routine for agents — write-permission probes, throwaway comparison trees, abandoned attempts. With no deletion path, every one of them is permanent. The cost is not any single ref; it is that the branch list is monotonically increasing and no seat can garbage-collect its own leavings. git ls-remote --heads origin 'refs/heads/claude/issue-*' already returns a long list of branches whose PRs merged.

Concrete leftover from this session

claude/probe-6716a-writecheck, pointing at faac0d93554cd67d92c92e621094154ce13dfc5e (an old main tip). It was created as a first-minute write probe during objectui#6716 and has no PR and no content of its own. It needs deleting by someone with a working delete path — this seat cannot.

What is NOT measured

  • Whether the 403 is the proxy's policy, a token-scope limit, or a branch-protection rule. The error is returned before any GitHub-level message reaches us, so the layer is not identified from here.
  • Whether deletion works from other seats or environments — only this container's path was tested.
  • Whether the same restriction applies to tags.
  • How many stale claude/* branches currently exist repo-wide. Deliberately not counted here: a census invites a bulk-cleanup proposal, and the disposition of merged-PR branches is a policy question, not this card's.

What this card is not asking for

⛔ Not proposing auto-deletion of merged branches, and ⛔ not proposing a cleanup sweep. Either would be a policy decision about the repo's branch lifecycle. This records the capability gap and the one concrete leftover, so the next agent that cannot delete its probe branch does not spend four attempts rediscovering it.

Activity

  1. huangyiirene commented on Aug 29, 2026

    @huangyiirene
    Collaborator

    定级:pm:queue · domain:skills · priority:p2。

    落点是查出来的,不是猜的:本卡没有 objectui 代码改动,交付物是一条知识行。我先确认了 objectui 根目录没有 references/ 目录(objectstack 的 references/platform-readings.md 不在这边)——⚠️ 我先用代码搜索得到零,但没有采信那个零:本轮同一个工具刚漏过一个我随后直接取回成功的文件,所以改用目录列举复核。objectui 的 agent 知识家在 AGENTS.md / .claude/** / skills/** ⇒ 本仓车道表里全部归 domain:skills,且都是治理面 ⇒ 人工合并。

    ⭐ 家在 AGENTS.md §9 多 agent 协作纪律是有先例支撑的:本卡自己引的 #3430(共享 refs/stash)与 #5239(force-push 禁令)正是住在那一节的同类平台事实。这条属于同一族,⛔ 不要另起新文件。

    ⚠️ 这张卡里最值钱的一句,不是 403 本身

    after the failure git prints Everything up-to-date

    ⇒ 失败之后打印一张成功回执。只看输出尾部、或把"最后一行非空"当成功的调用方,会把被拒绝的删除读成已完成的删除。

    ⭐ 这正是本仓这两天反复出现的那一族——「一个机制报告了它并不具备的东西」——本轮已经数到第 9 个实例了(#13014 门禁提取器、#13031 转换 walker、#13036/#13042/#13043 liveness 账本、#13041 门禁状态过滤、#13083 自由文本状态被 fold 丢弃、#13121 按名 join 合并了桶、#13128 floor 的出处与树脱钩、#13150 白纸黑字的 invariant 无人执行,以及反向的 #13110:量不了却报红)。⇒ 写进 AGENTS.md 时,请把 Everything up-to-date 这句原样写进去,它比"删除会 403"更有防错价值:知道会 403 的人仍可能把它读成成功。

    ⛔ 范围

    • ✅ 在范围内:把这条平台事实(能 push、不能删 ref;无 MCP 删除路径;create_branch 无对应的 delete;容器内无 gh CLI;以及那张假成功回执)记进 objectui 的 agent 语料。
    • ⛔ 不在范围内:任何分支清理。卡自己已经划掉了——⛔ 不提议自动删除已合并分支,⛔ 不提议清扫。那是仓库分支生命周期的策略决定,属人工地板。⛔ 也不要顺手做普查:卡明说 a census invites a bulk-cleanup proposal,这个自我克制是对的,请保持。

    一件我不派、直接上交维护者的事

    claude/probe-6716a-writecheck(指向 faac0d93554cd67d92c92e621094154ce13dfc5e,一个旧的 main tip,无 PR、无自身内容)需要一个有可用删除路径的人来删。⛔ 席位删不了,开发也删不了 ⇒ 我把它带进本轮给维护者的报告,不在本卡上挂 pm:awaiting-maintainer,以免这条可以现在就落地的知识行被一个与它无关的运维动作卡住。

    ⚠️ 卡里"未测"的四条(403 来自代理策略/token scope/分支保护中的哪一层、其他席位或环境是否可删、tag 是否同样受限、仓内还有多少 claude/* 陈旧分支)请原样保留为未测,⛔ 不要在写知识行时把它们补成断言。


    Generated by Claude Code

  2. os-litant commented on Sep 2, 2026

    @os-litant
    Collaborator

    Claim: PM loop round 1
    Session: session_01LraLgQVGq8egUwfYZpbYt1
    Branch: claude/issue-6756-branch-delete-403-fact
    Worktree: objectui-issue-6756
    Domain: domain:skills
    File surface: objectui AGENTS.md only — §9 多 agent 协作纪律, one knowledge line (stop on breach; explain in the report)
    Container & model: S mechanical (governed instruction face, one line), mode:subagent, model: opus — tier by the 2026-08-20 rule (a one-line mechanical edit on a governance face ⇒ opus construction; compensating control = the seat's review at the contract-review tier; not a pm-dispatch protocol-semantics face, not a packages/spec face)
    Clause-②: no
    Serial constraints cleared: none — no open objectui PR touches AGENTS.md (open PR list read 2026-09-02T01:3xZ: dependabot and the release PR only); no prior claim on this card; the claude/probe-6716a-writecheck deletion stays with the maintainer per triage.

    Decision re-read: triage grading comment 5460872090 (2026-08-29) is the binding scope — one knowledge line in objectui AGENTS.md §9, the Everything up-to-date false-success receipt written verbatim, the four unmeasured points kept as unmeasured, ⛔ no branch cleanup, no census, no policy. Comment 5468280978 adds the claim-signal impact (an orphan sibling branch reads as a competitor); the line should say residue is invisible from every seat surface and only a per-card prefix glob shows it. Governed face ⇒ draft PR, human merge.


    Generated by Claude Code

  3. self-assigned this
    on Sep 2, 2026
  4. os-litant commented on Sep 2, 2026

    @os-litant
    Collaborator

    Claim: dev seat (dispatched by PM loop round 1)
    Session: session_01LraLgQVGq8egUwfYZpbYt1
    Branch: claude/issue-6756-branch-delete-403-fact
    Worktree: objectui-issue-6756 cut from origin/main @ 67dadd6
    File surface: objectui AGENTS.md only — one knowledge line in ### 多 agent 协作纪律 under ## 9. Operational Rules

    Write probe: empty branch pushed before the first edit — [new branch] claude/issue-6756-branch-delete-403-fact (push path green from this seat, which is the half of the card's fact that still works).

    Scope re-read: triage grading comment 5460872090 is binding — ONE knowledge line, the Everything up-to-date false-success receipt quoted verbatim, the card's four unmeasured points kept unmeasured, ⛔ no branch cleanup / census / lifecycle policy / auto-deletion proposal. Comment 5468280978's claim-signal consequence (an orphan sibling branch for one card is invisible from every seat surface and reads as a competing claim; only a per-card prefix glob finds it) goes into the same line. AGENTS.md is a governed face ⇒ the PR stays draft, human merge.


    Generated by Claude Code

  5. os-litant commented on Sep 2, 2026

    @os-litant
    Collaborator

    os-dev-report

    {
      "issue": 6756,
      "status": "done",
      "branch": "claude/issue-6756-branch-delete-403-fact",
      "pr": "https://github.com/objectstack-ai/objectui/pull/7242",
      "premise_still_valid": true,
      "head_sha": "e362056",
      "files_changed": 1,
      "line_delta": "+1 / -0 (AGENTS.md line 276, inserted directly after the force-push-ban bullet at line 275; budget was <= +4, ZERO other files — met)",
      "changeset": "none owed — check-changeset-presence verdict on this diff: `0 of them published source of a package the release covers` => `No source or published contract of a released package changed in this range, so no changeset is owed.` No label requested (objectui has no skip-changeset mechanism).",
      "summary": "Added ONE bullet to objectui AGENTS.md section `### 多 agent 协作纪律` under `## 9. Operational Rules`, adjacent to the force-push ban. It states the capability gap (seats push fine, every ref-deletion push is refused by the agent proxy with HTTP 403; no MCP delete twin for create_branch; no gh CLI), quotes the false-success receipt `Everything up-to-date` verbatim, carries the claim-signal consequence from comment 5468280978 (orphan sibling branch invisible from every seat surface, reads as a competing claim, only a per-card prefix glob shows it), keeps all four unmeasured points explicitly marked unmeasured, and explicitly authorizes no cleanup/census/lifecycle policy. No branch touched; claude/probe-6716a-writecheck left for the maintainer.",
      "tests": "Gate union derived from the header of scripts/check-shell-escape-residue.mjs (which documents the derived union for an AGENTS.md change) plus the governed-surface guard added by #6596. All run under scripts/pm/os-verify-lock.sh on head e362056, exit codes captured by redirecting to a file first then reading $? (never through a pipe). check-control-bytes exit 0 `OK (scanned 5996 tracked text file(s); skipped 85 binary)`; check-doc-links exit 0 `Links are valid across 17 scan roots.`; check-changeset-presence exit 0 `No source or published contract of a released package changed in this range, so no changeset is owed.`; check-changeset-no-major exit 0 `No changeset declares a major bump.`; check-shell-escape-residue exit 0 `OK (4/4 root(s) resolved -- AGENTS.md: 1 file(s), 15 fence(s) ... 0 occurrence(s) outside a fence)`; check-governed-queue-guard --self-test exit 0 `132 cases pass`; check-governed-queue-guard --test AGENTS.md exit 3 `One governed path governs the WHOLE pull request` — this exit 3 is the CORRECT verdict, not a red gate: it is the seat-side predicate confirming the governed-surface disposition. Also self-scanned the file for control bytes with grep -naP outside the gate: clean. No ablation applicable (documentation line, no executable behaviour).",
      "mcp_calls": "9 — issue_read get, issue_read get_comments, add_issue_comment (claim), create_pull_request, pull_request_read (body read-back 1), update_pull_request, pull_request_read (body read-back 2), add_issue_comment (this report), plus its read-back. REST was unavailable from this seat: a repo-scoped GET to api.github.com returned 403 and no gh CLI is present, so MCP was the only channel; declared as a channel switch.",
      "pr_disposition": "STAYS DRAFT. AGENTS.md is a governed surface (row `agents-md` in GOVERNED_SURFACES). Not flipped ready, not enqueued, no auto-merge armed. draft:true was passed explicitly on the one body PATCH and the stored state read back to confirm, because governed-surface-guard.yml records PR #6183 landing unreviewed after an update_pull_request call silently set draft:false.",
      "deviations": [
        "PM mechanical assumption PARTIALLY FALSIFIED, conclusion survives. The assumption was 'no script under objectui/scripts references AGENTS.md'. Three do: scripts/check-doc-links.mjs (row `{ path: 'AGENTS.md', rule: 'disk' }`), scripts/check-shell-escape-residue.mjs (SCAN_ROOTS entry, minFiles 1), scripts/check-governed-queue-guard.mjs (GOVERNED_SURFACES row). None is a LINE RATCHET or size budget — all three are content/policy gates — so the intended conclusion holds: headroom is free and the new line owes no compensating deletion inside the section. No trade was paid.",
        "Authored the bullet with the Write tool and spliced it with python3 rather than a shell heredoc. scripts/check-shell-escape-residue.mjs exists because a heredoc nested in a single-quoted argument leaked a shell escape run into a code example in this exact section (#5150); reusing that mechanism to write into the same section was avoidable risk. Landing on disk was proven by git diff --stat plus two positive greps for the distinctive content, not by the editor's exit code.",
        "GitHub body sanitizer confirmed live on the first PR body: two angle-bracket placeholder fragments were removed EVEN INSIDE BACKTICKS, leaving an empty backtick pair. Caught by the mandatory full read-back and repaired in one PATCH; the committed file is unaffected. Both the PR body and this comment were read back after writing."
      ],
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  6. os-litant commented on Sep 2, 2026

    @os-litant
    Collaborator

    ACCEPT — skills-lane seat (session session_01LraLgQVGq8egUwfYZpbYt1), reviewer of record, verified against GitHub not the report.

    • PR objectui#7242 exists, is DRAFT, targets main, first body line Fixes #6756 (closes this card on merge — correct: the whole card is the one line).
    • Changed files: exactly one, AGENTS.md, +1/−0 at line 276 inside ### 多 agent 协作纪律, adjacent to the force-push ban — matches the claimed surface and the triage scope (fact + verbatim Everything up-to-date receipt + claim-signal consequence + four points kept unmeasured + explicit no-cleanup/no-policy clause). Spot-read of the diff: the bullet is in the section's voice, commands backticked, no assertion added beyond the card's measured facts.
    • Changeset: none owed — check-changeset-presence on this diff: "No source or published contract of a released package changed in this range"; no label requested (objectui has none).
    • Gates on head e362056 (all exit 0): control-bytes, doc-links (17 roots), changeset-presence, changeset-no-major, shell-escape-residue (AGENTS.md 15 fences, 0 residue), governed-queue-guard self-test (132); --test AGENTS.md exit 3 = the governed verdict (correct, not a red).
    • Deviation accepted: the PM's mechanical assumption "no script references AGENTS.md" was partly falsified (three content/policy gates reference it; none is a size ratchet) — conclusion unchanged, reported honestly.
    • Governed face (agents-md row of GOVERNED_SURFACES) ⇒ terminal = human merge. Review requested from the two authorized approvers on the PR with the draft bit held; ⛔ not flipped ready, not enqueued. Awaiting a human merge.

    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

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions