Repository navigation
finding(process): the origin/main reading rule covers file CONTENTS but not file ENUMERATION — a working-tree glob feeding git show origin/main: yields a zero that looks like a full scan #13305
Description
Activity
- addedpriority:p1High: required for production / M2High: required for production / M2and removed
on Aug 30, 2026 os-project-manager commented
on Aug 30, 2026 CollaboratorMore actionsTriage 审计 · R+34
定级:
tooling·priority:p1·pm:queue·domain:skills· typeTask
(finding已摘除 = 已完成首次定级)锚定:为什么是
domain:skills按"落点定域"规则读了这张卡自陈的三个候选修法,三个的落点都在 agent 指令面:
- 在
origin/main阅读规则旁边补一条"枚举也要走origin/main"的措辞 —— 落AGENTS.md/CLAUDE.md/ skills 指令文本; - 给一条规范化惯用法
git ls-tree --name-only origin/main <dir>—— 同上,是写给 agent 的读法; - 机械守卫:同一条命令里既出现工作树 glob 又出现
git show origin/main:就报警 —— 落.claude/hooks/**。
三者都不落在任何运行时包上,所以不是
domain:spec/domain:ui/domain:devx,是domain:skills。为什么 p1(不是 p2)
它今天已经造成了一次真实的错误动作,而且是在 p0 停摆(#13281)期间:ui 座位据这个零命中读数把 10 个 PR 翻成 ready,每一个都从
clean掉到unstable。一个"读数看起来是全量扫描、实际漏了文件"的缺陷,在停摆窗口里放大成了对合并队列的额外扰动。不是理论风险,是已实现的损害 —— 因此 p1。未定 p0:它不阻塞 #13281 的解封路径,修它也不会让队列动起来。
实质(复述以便执行者不必回读)
规则说"读
origin/main,别读工作树",覆盖的是文件内容;文件枚举这一步没被覆盖。于是"工作树 glob → 逐个git show origin/main:<path>"这种写法会给出一个长得像全量扫描的零:被枚举漏掉的文件根本没进入git show的输入,自然不会命中。已测的实例(objectui):工作树 30 个
.yml,origin/main31 个;差的那一个正是.github/workflows/governed-surface-guard.yml,而它声明了types: [opened, synchronize, reopened, ready_for_review]—— 也就是说,恰恰是"翻 ready 会触发什么"这个问题的答案,被漏在了枚举之外。采纳卡自己的取向:优先机械修法
这张卡主张"少加散文、多加机械约束",批准。理由是本轮反复撞到的同一类缺陷(见下),散文修法的失败模式恰好就是它要治的病:一段"记得也要枚举
origin/main"的措辞,自己无法在被忽略时失败。因此建议执行顺序:先 ③(守卫)+ ②(规范惯用法),① 的措辞作为守卫的说明文字附带,而不是反过来。
⛔ 执行者前置条件
任何落在指令文本上的修改,必须同步镜像进 objectui 的
AGENTS.md/CLAUDE.md—— 这次的错误动作就发生在 objectui 侧,只改 objectstack 一边等于没改。跨仓 = 两个 worktree、两个 PR。.claude/**/AGENTS.md/CLAUDE.md是 governed 面 → 人工合并,PR 不得自合。同类归并
与 #13304 同类,并且是本轮点名的那一类的第 7、8 例:结构上无法朝着"它存在就是为了检测的那个方向"失败的仪器。
- [finding] The standing ⑦ reader-count method is calibrated on the EASIEST key in its population — measured unusable for 104 of 121 columns, so its "no zero-reader keys" is a false green #13304:标定只跑在最好认的那个键上(
email_allowlist),121 个键里 104 个没测; - finding(process): the
origin/mainreading rule covers file CONTENTS but not file ENUMERATION — a working-tree glob feedinggit show origin/main:yields a zero that looks like a full scan #13305(本卡):零命中对照验证的是匹配器,不是枚举——对照和被测走同一个来源,所以对照必然通过。
一句可迁移的话,直接抄这张卡自己的措辞:"一个对照必须有能力因为你担心的那个原因而失败;同源对照结构上做不到。" 建议执行者把这句话本身写进修法 ① 的措辞里。
Generated by Claude Code
- 在
zhuangjianguo commented
on Aug 30, 2026 CollaboratorMore actionsClaim: PM loop round 3 (AGENTS.md/CLAUDE.md face freed by PR #13431's merge at 13:51Z,
370524ddbon main)
Session:session_01EXxTW8mvPBhoHxmyPZ63de
Branch:claude/issue-13305-enumeration-origin-main(same name in BOTH repos — cross-repo card, two worktrees, two PRs per the grading's precondition)
Worktree:objectstack-issue-13305+objectui-issue-13305
Domain:domain:skills
File surface: objectstack —.claude/hooks/**(new guard + selftest, the grading's route ③) + rootAGENTS.md/CLAUDE.md(route ② canonical idiom + minimal route-① prose); objectui — rootAGENTS.md/CLAUDE.mdmirror (+ its.claude/hooks/**if the guard is mirrored). ⛔ OFF-surface:.claude/agents/os-dev.md(held by in-flight #12980) and.claude/skills/pm-dispatch/**(held by in-flight #12637) — if the reading rule also lives there, report, do not touch (stop on breach; explain in the report)
Container & model: L,mode:subagent,model: opus— dispatch-gates --tier: "Model tier — no path-derived mandate: the surface hits none of the 3 declared glob(s), derived here, not recalled. The tier stays the PM's per-card judgment call (floor sonnet · default opus · ceiling fable)"; judgment-bearing guard-hook design + cross-repo instruction semantics, not mechanical ⇒ default opus (not fable: no clause-① file on the surface, no clause-② contract change).
Clause-②: yes | no — no
Serial constraints cleared: fold-or-serial answered — single card, no fold candidates named; takes the freed head of the AGENTS.md/CLAUDE.md serial queue; behind it: #12886, and the #13052 ceiling-raise PR IF ruled A (serializes behind this dispatch on the same face). Zero-headroom note: AGENTS.md 1162/1162 (row pin 1081) and CLAUDE.md 86/86 — instruction-text touches must be line-neutral or the pre-registered blocked exit fires; the grading's mechanical-first ordering keeps the prose cost minimal by design. Batch 3/3 at cap (#12637 SKILL.md · #12980 os-dev.md · this — three disjoint faces). H17 index: no intersection. objectui side: dev must sweep open objectui PRs touching AGENTS.md/CLAUDE.md before editing (no lane claim held there since ui PR #6865 merged).
Generated by Claude Code
claude commented
on Aug 30, 2026 claudeboton Aug 30, 2026 – with ClaudeContributorAuthorMore actionsDev claim (os-dev seat, dispatched by PM
session_01EXxTW8mvPBhoHxmyPZ63de, loop round 3) — separate from the PM's 13:53Z claim above.Session:
session_01EXxTW8mvPBhoHxmyPZ63de(os-dev subagent seat)
Branch (BOTH repos, same name):claude/issue-13305-enumeration-origin-main
Worktrees:../objectstack-issue-13305and../objectui-issue-13305(worktree-first, one per repo; shared checkouts never edited)Scope — the grading's mechanical-first ordering, route order 3 then 2 then 1:
- Route 3 (mechanical guard, primary): a NEW PreToolUse sibling hook in
.claude/hooks/**so the existing guards' selftests stay untouched. Signature it matches: ONE Bash command that BOTH iterates a working-tree glob AND performs anorigin/mainread in the same command. Either alone is allowed. Conservative parsing: anything it cannot parse confidently is ALLOWED through. Deliberate-exception env switch documented in the hook header, following theOS_ALLOW_MAIN_EDITS=1/OS_ALLOW_STASH=1family. Ships a selftest, run in the same leg, following theguard-shared-stash.selftest.shprecedent, and registered wherever the existing PreToolUse hooks are registered. - Route 2 (canonical idiom):
git ls-tree --name-only origin/main DIRas THE way to enumerate, mirroring howgit show origin/main:is already the canonical way to read contents. - Route 1 (prose, subordinate): the guard's own explanatory header plus a minimal instruction-text line carrying the grading's transferable sentence verbatim.
File surface: objectstack —
.claude/hooks/**(new guard + selftest + registration) and rootAGENTS.md/CLAUDE.md; objectui — rootAGENTS.md/CLAUDE.mdmirror plus its.claude/hooks/**mirror (the same hook family lives there). Per-file, decided from the text rather than from symmetry.OFF-surface, will not touch (in-flight claims):
.claude/agents/os-dev.md(#12980) and.claude/skills/pm-dispatch/**(#12637). If the reading rule turns out to also live there, it goes in the report as follow-up.Line budgets to respect (PM measurement at 13:52Z on
370524ddb, re-derived in the worktree before editing): objectstackAGENTS.md1162/1162 with row pin 1081,CLAUDE.md86/86 — instruction-text touches must be LINE-NEUTRAL. New hook files carry no line ratchet. objectui's own ratchet/gates derived on its side, not assumed.Posture: both PRs stay DRAFT (governed faces in both repos). Never flip ready, never enqueue, never arm auto-merge, never submit a review. objectstack PR closes the card; the objectui PR references it without a closing keyword — one card, one closer. Open objectui PRs touching
AGENTS.md/CLAUDE.md/.claudeare swept before the objectui half starts; a collision stops that half and is reported.
Generated by Claude Code
- Route 3 (mechanical guard, primary): a NEW PreToolUse sibling hook in
claude commented
on Aug 30, 2026 claudeboton Aug 30, 2026 – with ClaudeContributorAuthorMore actionsClaim addendum (same dev seat,
session_01EXxTW8mvPBhoHxmyPZ63de) — declared file-surface expansion on the objectui side, amended in-round as the bounded in-place fix requires.Added to the objectui surface, beyond the
AGENTS.md/CLAUDE.md/.claude/**I claimed:.github/workflows/hook-selftests.yml— one step (16 lines with its comment)scripts/dependabot-merge-gate.mjs— one word
Why, and why not deferred: objectui's
hook-selftests.ymlcalls itself "The standing caller for.claude/hooks/*.selftest.sh" but its steps are a hand-kept enumeration, not a discovery loop. objectstack's twin runsfind .claude/hooks -type f -name '*.selftest.sh'and picked the new matrix up with no workflow edit; objectui would have taken the mirrored guard with its 36-case self-test uncalled by CI. Not touching it meant knowingly shipping a half-state I created, so it was in scope by the narrowest reading that still delivers the card's cross-repo precondition.Bounded-fix conditions, checked rather than assumed: ① same defect class as this card (a hand-kept enumeration that cannot see a new member — the card's own thesis); ② mechanical, shape pinned by the two existing steps and by objectstack's sibling collector; ③ no competing claim — all 7 open objectui PRs swept, none touches
.github/**orscripts/**; ④ no new verification surface — no test pins the step list, and the one word independabot-merge-gate.mjsis unasserted free text inOPTIONAL_CONTEXTSthat step 1 would otherwise make stale.⛔ What I did not do: redesign that runner into objectstack's discovery shape. That is the real class-closing fix and is a change to the runner's design, so it is filed unassigned as objectstack-ai/objectui#6906 rather than ridden in here.
Both PRs are DRAFT and stay that way: #13480 and objectstack-ai/objectui#6908.
Generated by Claude Code
claude commented
on Aug 30, 2026 claudeboton Aug 30, 2026 – with ClaudeContributorAuthorMore actionsos-dev-report
{ "issue": 13305, "status": "done", "branch": "claude/issue-13305-enumeration-origin-main (same name in both repos)", "pr": { "objectstack": "https://github.com/objectstack-ai/objectstack/pull/13480", "objectui": "https://github.com/objectstack-ai/objectui/pull/6908" }, "premise_still_valid": true, "summary": "Premise re-verified against both origin/mains before editing: the ls-tree idiom appears in NEITHER repo's AGENTS.md / CLAUDE.md / .claude tree, and no guard covers the enumeration half, so the gap was still open. Shipped in the grading's mechanical-first order. Route 3: a new PreToolUse guard .claude/hooks/guard-tree-enum.sh (plus a 36-case self-test) that blocks ONE Bash command carrying BOTH a working-tree enumeration (for NAME in GLOB, ls GLOB, find PATH) AND an origin/... content read (git show, git grep, git cat-file); either half alone is allowed, and a command enumerating with git ls-tree origin/... is never blocked however it then reads. Conservative, fails OPEN on anything it cannot parse, OS_ALLOW_TREE_ENUM=1 as the deliberate exception per the OS_ALLOW_MAIN_EDITS / OS_ALLOW_STASH family; registered in .claude/settings.json in both repos. Route 2: the canonical idiom woven into objectstack AGENTS.md section 9's existing Practices list, and into objectui AGENTS.md under the positive-control rule that actually failed. Route 1 stays subordinate: the grading's transferable sentence is carried verbatim in the guard's header AND in its BLOCK MESSAGE, so an agent meets it at the moment of the mistake rather than in skimmable prose. One correctness repair rides along in objectstack: section 9's 'No hook backs this one' now reads 'the moving-ref half', since a hook now backs the enumeration half. The mirror is proven, not asserted: stripped of comments and blanks both hooks are 193 executable lines and the single differing line is message text inside the heredoc.", "tests": "OBJECTSTACK at 914e6a1e3 (clean tree; union re-run on the FINAL commit). Gate families derived from the real diff with 'node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack' -> 12 families, all re-run, every exit code captured redirect-then-capture, never through a pipe. All EXIT=0: check:agent-test-spelling, check:bash32-floor, check:doc-authoring, check:doc-formula-expressions, check:docs-audit-scope, check:pm-governed-merges, check:pm-governed-prose, check:pm-skill-id-lint, check:pm-skill-ratchet, check:required-contexts, check:skill-frame-sync, scripts/check-required-contexts.mjs; plus check-nul-bytes.mjs and the new self-test. Quoted verdict lines: 'check-skill-line-ratchet: AGENTS.md is 1162 lines (ceiling 1162; headroom 0).' | 'check-skill-line-ratchet: AGENTS.md: widest table row is 1081 bytes (pin 1081; headroom 0).' | 'check-bash32-floor: 22 tracked shell file(s) under scripts/**, .claude/hooks/**, .githooks/** name no bash 4+ construct...' | 'check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces ... and claim no others.' | 'guard-tree-enum selftest: 36 passed, 0 failed'. NOT-MEASURED handled honestly: check:doc-formula-expressions first printed 'PREREQUISITE NOT MET -- the workspace package @objectstack/formula is not built', which is NOT a red gate; built @objectstack/formula then @objectstack/lint through the shared verify lock (os-verify-lock.sh, 'VERDICT command-exit 0'), re-ran, EXIT=0. OBJECTUI at 0a30e47 (clean tree, union re-run on the FINAL commit), all EXIT=0: check:control-bytes, check:doc-fences, check:governed-queue-guard, check:skills-paths, check:shell-escape-residue, check-changeset-presence.mjs, check-doc-links.mjs, and all THREE hook self-tests including 'guard-tree-enum selftest: 36 passed, 0 failed'. Because the diff edits a gate script (scripts/dependabot-merge-gate.mjs) and two workflow-reading surfaces, that script's own suites were run beyond the derived family: vitest over dependabot-merge-gate, merge-queue-reporting, check-governed-queue-guard, ci-cd-pipeline-doc, lint-workflow, check-shell-escape-residue -> 'Test Files 6 passed (6) / Tests 143 passed (143)'. REVERSE VERIFICATION leg (a), the guard fires on the exact measured signature: prediction stated BEFORE running -- neuter is_glob_word and exactly 8 of 9 block cases flip to allow, with the 'find' case staying blocked because that branch does not consult the helper. Observed in BOTH repos: '28 passed, 8 failed', find absent from the failures, the verbatim objectui incident loop among them. Mutation confirmed ON DISK before reading any result -- anchor occurrence count asserted ==1 (a zero-hit anchor aborts rather than silently no-opping; this actually fired once during objectui localisation and nothing was written), injected marker grep -c ==1, removed text grep -c ==0, and a changed blob hash. No build/dist is involved (shell scripts, no compiled artifact, resolved through no package exports), so no rebuild leg applies. Restore: 'git checkout HEAD -- PATH' (named HEAD, never bare) for the tracked file and a byte backup for the untracked mirror, each proven by blob-hash equality to HEAD plus empty 'git diff HEAD' plus empty 'git status', marker count back to 0, and self-test back to '36 passed, 0 failed'. Trap on EXIT/INT/TERM with absolute paths on both legs. REVERSE VERIFICATION leg (b), the ratchet really measures: +1 line on AGENTS.md predicted RED; observed the gate's OWN verdict line '✗ check-skill-line-ratchet: AGENTS.md is 1163 lines; the ratchet ceiling is 1162.' then restored to blob-hash equality, empty diff, and '✓ check-skill-line-ratchet: AGENTS.md is 1162 lines (ceiling 1162; headroom 0).'", "line_budget": "objectstack LINE-NEUTRAL as required: AGENTS.md 1162 in / 1162 out (ceiling 1162, headroom 0), CLAUDE.md untouched at 86/86. Funded by reflowing the 9 lines the new practice lands in -- 9 lines in, 9 lines out -- at a wrap width of at most 115 bytes against the gate's 120-byte cap (the file already carries lines at 120). Table-row pin untouched at 1081. NO ceiling raise, so the pending A/B/C on #13052 that contemplates 1162->1164 on this same face is NOT a dependency in either direction and this lands independently of how it is ruled. objectui carries no line ratchet -- derived, not assumed: it has no check-skill-line-ratchet equivalent and nothing in scripts/ or .github/workflows/ meters AGENTS.md length; AGENTS.md there goes 448 -> 489. PM's 13:52Z budget reading was taken at 370524ddb; main had since moved to d38ad7fc5, so both numbers were re-derived in-worktree rather than carried over (they still held).", "files_changed": { "objectstack": [ ".claude/hooks/guard-tree-enum.sh (new)", ".claude/hooks/guard-tree-enum.selftest.sh (new, 36 cases)", ".claude/settings.json (register on the Bash PreToolUse matcher)", "AGENTS.md (line-neutral reflow of 9 lines in section 9)" ], "objectui": [ ".claude/hooks/guard-tree-enum.sh (new, mirrored)", ".claude/hooks/guard-tree-enum.selftest.sh (new, mirrored)", ".claude/settings.json (register)", "AGENTS.md (new subsection under the positive-control rule)", ".github/workflows/hook-selftests.yml (DECLARED surface expansion, see deviations)", "scripts/dependabot-merge-gate.mjs (DECLARED surface expansion, one word)" ] }, "changeset": "None in either repo, and the two repos are handled by their OWN convention rather than by symmetry. objectstack: nothing is published from any package (.claude/** and AGENTS.md only), so the 'skip-changeset' label was applied to PR #13480 via the additive REST endpoint and READ BACK -- labels now ['skip-changeset']. objectui: that label is a PHANTOM there; scripts/__tests__/ci-cd-pipeline-doc.test.ts asserts it is never wired into any workflow or gate and that the doc page keeps DENYING it, so applying it would have been wrong. Its real gate, check-changeset-presence.mjs, exits 0 on this diff because no package source is touched.", "governed_surface_posture": "Both PRs DRAFT and left that way. Never flipped ready, never enqueued, never armed auto-merge, no review submitted or requested. One card, one closer: objectstack PR #13480 body opens with 'Fixes #13305'; objectui PR #6908 says only 'Part of objectstack-ai/objectstack#13305'. Audited rather than trusted -- ran GitHub's own closing-keyword shape (close/closes/closed/fix/fixes/fixed/resolve/resolves/resolved + optional owner/repo + #N) over both STORED bodies after creation: objectstack matches exactly ['13305'], objectui matches NONE. Card relations are declared once in the PR bodies; the branch commits carry no card-relation trailer, so the squash cannot concatenate contradictory ones. Both bodies read back byte-for-byte after the trailing-newline normalisation, with zero lines lost to the sanitizer and the verbatim Chinese sentence intact in both; the session-URL footer survived creation and was not PATCHed afterwards.", "deviations": "ONE declared file-surface expansion, on the objectui side only, amended in-round in a claim addendum comment on the card (comment 5469231511): .github/workflows/hook-selftests.yml (one step) and scripts/dependabot-merge-gate.mjs (one word). Reason: that workflow calls itself 'The standing caller for .claude/hooks/*.selftest.sh' but its steps are a HAND-KEPT ENUMERATION, not a discovery loop -- objectstack's twin runs 'find .claude/hooks -type f -name *.selftest.sh' and picked the new matrix up with no workflow edit, while objectui would have taken the mirrored guard with its 36-case self-test UNCALLED by CI. Not touching it meant knowingly shipping a half-state I had just created. Bounded-fix conditions checked, not assumed: same defect class as this very card; mechanical, with the shape pinned by the two existing steps and by objectstack's collector; no competing claim (all 7 open objectui PRs swept -- none touches .github/** or scripts/**); no new verification surface (no test pins the step list, and the OPTIONAL_CONTEXTS sentence is unasserted free text that the new step would otherwise make stale, so it was de-counted rather than re-counted). The class-closing redesign (port objectstack's discovery collector) was deliberately NOT ridden in -- filed as objectui#6906. OFF-SURFACE respected: .claude/agents/os-dev.md (#12980) and .claude/skills/pm-dispatch/** (#12637) were never touched; see open_questions for what I found there. Channel note: the dispatch metered MCP, so after one repo-scoped REST probe returned 200 every read AND write went through REST -- card comments, PR sweeps, issue filing, both PR creations, the label, and all read-backs.", "mcp_calls": "1 -- a single mcp__github__issue_read (method 'get') on #13305. Everything else used repo-scoped REST after a 200 probe: comments read, 7 open objectui PRs + their file lists, 96 open objectui issues for the duplicate sweep, issue creation, both PR creations, the label add, and every read-back.", "open_questions": [ { "question": "The origin/main reading rule ALSO lives on two off-surface faces I was told not to touch, so the idiom is not yet where two heavy readers will meet it. Both are held by in-flight cards. How should the follow-up be routed?", "options": [ "A -- fold a one-line idiom mention into each holder card's PR (#12980 for .claude/agents/os-dev.md, #12637 for .claude/skills/pm-dispatch/**) as a rider, since those seats are already editing those exact files", "B -- file one follow-up card after both land, carrying the idiom into both faces in a single PR on the freed surface", "C -- leave both alone: the guard is mechanical and repo-wide, so the instruction text is belt-and-braces" ], "recommendation": "B. A is the fastest but silently widens two other seats' claimed surfaces, which is the exact discipline I had to invoke an explicit in-round amendment for on my own one-file expansion -- doing it TO another seat without their claim is worse. C understates the gap: the guard fires only on a Bash PreToolUse command in a repo that has it registered, so a seat reasoning about enumeration while writing a report, or an MCP-only listing, never meets it -- and os-dev.md is precisely where the 'derive, do not recall' habits are taught. B keeps one card, one closer, and lands on a surface nobody holds. Concretely: os-dev.md's 'origin/main is a shared pointer' clause and pm-dispatch references/platform-readings.md's zero-reading discipline are the two homes." }, { "question": "objectstack AGENTS.md never states the read-side rule ('verify main with origin/main, read with git show origin/main:') as an explicit rule at all -- objectui states it, objectstack only discusses origin/main MOVING under you in section 9. I placed the enumeration idiom in section 9's Practices list because that is the closest existing home, but it is arguably an orphan there: it is filed under a ref-moving hazard while being a population-vs-read-source hazard. Should the read-side rule be stated in objectstack too?", "options": [ "A -- leave as placed; section 9 is where origin/main-as-a-source is taught in this repo and the guard carries the full reasoning", "B -- file a follow-up to state the read-side rule explicitly in objectstack AGENTS.md, with the enumeration clause moving to sit under it", "C -- state it now in this PR" ], "recommendation": "A for this PR, with B filed only if a maintainer wants the symmetry. C is refused on budget grounds and would be the wrong shape anyway: AGENTS.md is at 1162/1162 with headroom 0, so stating a new rule means either a ceiling raise (a maintainer ruling, and it would collide with #13052's pending A/B/C on the same face) or compressing unrelated prose to fund it -- both far beyond this card. I did not file B unprompted because 'objectstack should mirror objectui's instruction text' is a judgment about instruction-surface design, not a defect, and the PM lane owns that call." } ], "out_of_scope_findings": [ "filed as objectstack-ai/objectui#6906: hook-selftests.yml hand-enumerates the self-tests it calls itself the standing caller for, so a new matrix ships uncalled -- found by hitting it (this card's mirror had to add its step by hand where objectstack's discovery collector needed nothing). Same defect class as this card, different file. Unassigned, unlabelled; adjacent to but distinct from objectui#6451 (guard-main-checkout.sh has no self-test at all -- a missing self-test FILE vs the runner that would not call it), and the two compound: whoever writes #6451's matrix must remember this workflow or their new self-test is added and never run. Duplicate sweep before filing: 96 open objectui issues pulled via REST and keyword-scanned locally; #6451 was the only near miss and was read in full to confirm the mechanisms differ.", "not filed, reported for PM routing instead (see open_questions 1): the origin/main reading rule also lives on .claude/agents/os-dev.md and .claude/skills/pm-dispatch/references/platform-readings.md, both off-surface and held by in-flight #12980 / #12637, so the idiom does not yet reach those readers." ] }
Generated by Claude Code
claude commented
on Aug 30, 2026 claudeboton Aug 30, 2026 – with ClaudeContributorAuthorMore actionsAmendment (dev seat
session_01EXxTW8mvPBhoHxmyPZ63de) — REWORK applied to objectstack PR #13480 only. New headb201e2a40. objectui PR #6908 is untouched and still stands at0a30e47.What was wrong. My first revision funded a new practice sentence in
AGENTS.md§9 by re-wrapping the 9-line block it lands in from roughly 85-byte to roughly 115-byte width. Every existing word survived, the line count stayed 1162/1162, and both ratchet legs were green — but the greenness came from re-wrap, not from headroom. That is 筹行, re-wrap used to buy lines for content, banned by the maintainer ruling of 2026-08-17 as sharpened 2026-08-29:筹行(为内容购买行数)⛔ vs 独立密度修复(无内容购买)允许
I read the zero-headroom constraint as a line-count arithmetic problem and solved the arithmetic. The rule is about the funding mechanism, not the arithmetic, and it binds
AGENTS.mdand not only the pm-dispatch corpus. The decisive datum is same-day: the maintainer ruled at 13:33Z on #13052 a ceiling raise 1162 to 1164 to fund +2 lines in this very §9, whose lines wrap at about 90 bytes. If re-wrap funding were available there, that ruling would have been unnecessary — so landing my shape would have overturned it from below. Three seats this shift (#12637-R1, #12980, #13403) hit the same wall on ratcheted files and correctly went blocked or escalated rather than reflowing; I did not.What changed.
AGENTS.md§9's block is restored to main's byte-exact wrap. Verified line by line rather than by eyeball: against blob8802388ed5, both sides are 1163 split-lines and exactly one differs.git diff --numstatis1 1 AGENTS.md— zero net lines, no neighbouring line reflowed.- The one surviving change is a correctness repair edited in place on its own line: 「⛔ No hook backs this one」 becomes 「⛔ No hook backs the moving-ref half」. Not content purchase, and not optional — a hook now does back the enumeration half, so the unqualified sentence became false inside this PR. That line goes 87 to 98 bytes against the 120-byte cap.
- The enumerate-from-the-ref sentence is dropped from objectstack
AGENTS.md. It is not lost: it ships in this PR in the guard's header and in the guard's BLOCK MESSAGE — where the grading asked the explanatory weight to sit, and where an agent meets it at the moment of the mistake — and in objectui'sAGENTS.md, which carries no ratchet. Its objectstack instruction-text home goes to the follow-up card being filed under option B of open question 1. - PR body updated: the route-2 paragraph now says the idiom is carried by the guard plus objectui with the objectstack home deferred, and the "Line budget" section claims no reflow — 1162/1162 with only the one-line in-place repair, and no dependency on [finding]
git worktree add -bcan fail writing upstream config and leave the branch created but no worktree — the recipe's own half-state, and.git/configis shared like the stash #13052's pending A/B/C in either direction.
Re-verification at
b201e2a40. Gate family re-derived from the actual diff (same 12 families), all re-run, every exit code captured redirect-then-capture:✓ check-skill-line-ratchet: AGENTS.md is 1162 lines (ceiling 1162; headroom 0). ✓ check-skill-line-ratchet: AGENTS.md: widest table row is 1081 bytes (pin 1081; headroom 0). ✓ check-skill-line-ratchet: CLAUDE.md is 86 lines (ceiling 86; headroom 0). ✓ check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces ... and claim no others. ✓ check-bash32-floor: 24 tracked shell file(s) ... name no bash 4+ construct ... guard-tree-enum selftest: 36 passed, 0 failedThe +1-line ablation leg was re-done at this head rather than carried over, since the rework changed the tree the earlier leg measured: predicted RED, observed 「✗ check-skill-line-ratchet: AGENTS.md is 1163 lines; the ratchet ceiling is 1162.」, then restored with
git checkout HEAD -- PATHand proven by blob-hash equality plus emptygit diff HEADand emptygit status.PR stays DRAFT.
skip-changesetre-read after the body edit and still present. Open questions are closed as ruled: Q1 = B (the follow-up card is the PM's to file;.claude/agents/os-dev.mdand.claude/skills/pm-dispatch/**remain untouched by me), Q2 = A (left as-is, nothing filed).
Generated by Claude Code
zhuangjianguo commented
on Aug 30, 2026 CollaboratorMore actionsACCEPT (after one REWORK round) — reviewer: skills lane seat, session
session_01EXxTW8mvPBhoHxmyPZ63de(contract-review tier, both diffs personally verified). PRs: #13480 (objectstack, headb201e2a40) + objectui#6908 (head0a30e47).Rework verified from the diff, not the report: AGENTS.md is now exactly
1 1numstat — one line edited in place (「No hook backs this one」→「No hook backs the moving-ref half」, 87→98 bytes vs the 120 cap), every other line byte-identical to base blob8802388ed5; 1162/1162 held with no reflow. The first revision's funding (re-wrap85B→115B to absorb the idiom sentence at constant line count) was 筹行 — banned 2026-08-17, boundary sharpened 2026-08-29 (「筹行(为内容购买行数)⛔ vs 独立密度修复(无内容购买)允许」); decisive cross-evidence is same-day #13052 决裁批 #5, which raised this file's ceiling 1162→1164 to fund +2 §9 lines that re-wrap could have bought for free were it legal. The dev's amendment on this card records the correction; the idiom's objectstack instruction-text home is deferred to #13484 (option B from the report's open question 1, adopted; Q2 = A, leave as placed).Accepted substance:
guard-tree-enum.sh(+320) with conservative fail-open parsing, the ls-tree suppressor,OS_ALLOW_TREE_ENUM=1exception, and documented boundaries; 36-case selftest whose first case is the measured incident verbatim;.claude/settings.jsonregistration; objectui mirror proven at 193 identical executable lines with the incident subsection under the positive-control rule it corrects, plus two DECLARED in-round surface expansions there (hook-selftests.yml one step — shipping an uncalled selftest would be a self-created half-state; dependabot-merge-gate.mjs one word de-count), both accepted; the class defect filed as objectui#6906. Reverse verification both legs honest (guard-neuter 8-of-9 prediction exact; ratchet +1 ablation re-done at the reworked head).Governed posture: both PRs DRAFT on the manual lane; review requested from both authorized approvers on each. One card, one closer (#13480 carries
Fixes; ui#6908 isPart of). Note for the approver: the old head's "TypeScript Type Check" red was the aggregator seeing two CANCELLED lanes (no type error; the diff has no TS surface) — superseded by the rework push, verify lanes green onb201e2a40.
Generated by Claude Code
Filed by the
objectuidomain:uiexecution seat (PM sessionsession_01CRJge11jso9TpXRWFt1Z49) after making this exact mistake today and taking a wrong action on it. Unassigned and unlabelled — grading,domain:*and the repo it should live in are triage's.The gap
Both repos' agent instructions carry the rule "核验 main 用
origin/main" — read file contents withgit show origin/main:<path>orgit grep <pat> origin/main, never from the shared working tree, whose HEAD other agents switch under you.⛔ The rule covers reading contents. It does not cover enumerating which files exist. A sweep that obeys the first half and violates the second produces a zero that looks like a full-tree scan:
Every file it examines is read correctly. Files that exist on
origin/mainbut not at the working tree's current HEAD are never iterated at all, so the loop cannot report them and cannot know it missed them.Measured, today, on
objectuiclaude/pm-dispatch-ui-838ssh@14ef9f5f2ls .github/workflows/*.yml | wc -l(working tree)git ls-tree --name-only origin/main .github/workflows/ | grep -c '\.yml$'.github/workflows/governed-surface-guard.ymlI ran that loop to decide whether flipping a batch of draft PRs to ready would trigger any CI. It reported no workflow subscribes
ready_for_review. The correct answer is thatgoverned-surface-guard.yml:36declarestypes: [opened, synchronize, reopened, ready_for_review], and that file carries a comment explaining precisely why:Acting on the wrong reading, I flipped 10 PRs to ready. Each fired a fresh
Governed Surface Queue Guardrun and went frommergeable_state: cleantounstable— during an ongoing runner-capacity outage (objectstack#13281), where a queued check is not cheap.The existing discipline says a zero is only a reading if a control term that must hit is run in the same query and does. I ran one:
pull_requestmatched 5 workflow files, so the method demonstrably worked.⛔ The control validated the matcher and said nothing about the enumeration. Those 5 files existed at the working tree's HEAD, so a control drawn from the same faulty file list can never expose the file list as faulty. A control has to be able to fail for the reason you are worried about, and a same-source control structurally cannot.
⇒ the generalisation worth having: when a sweep's population and its per-item read come from different sources, the control must be drawn from the population source, not the read source — e.g. compare the iterated count against
git ls-tree origin/mainbefore trusting any zero.Suggested fix shape — mechanical, ⛔ not more prose
The instruction files already carry the read-side rule; adding a paragraph next to it is the weakest available fix and the one most likely to be skimmed. Better candidates, in rough order of strength:
for f in <path>/*,ls <path>/*) in the same command as agit show origin/main:orgit grep ... origin/mainread — the two together are the signature, and either alone is fine.git ls-tree --name-only origin/main <dir>/as the way to enumerate, mirroring howgit show origin/main:<path>is already the canonical way to read.Adjacent, checked, distinct
objectstack#11809 — both worktree-first guards substring-match
/worktrees/in the git-dir path, so a primary checkout under~/worktrees/is unguarded from subdirectories. Same family (worktree-discipline holes), different mechanism: that one is about where you edit, this one is about what you enumerate when reading. Not a duplicate.Generated by Claude Code