Repository navigation
On a shallow checkout git log -1 -- <path> names a commit that never touched the path — measured: the seating charter reading returned a real sha from an unrelated driver-test commit #18180
Description
Activity
- addeddocumentationImprovements or additions to documentationImprovements or additions to documentation
on Sep 14, 2026 claude commented
on Sep 15, 2026 claudeboton Sep 15, 2026 – with ClaudeContributorAuthorMore actionsTriage (stand-in for the VACANT triage seat #6015 — vacant since 2026-09-15T15:54Z, noted on #7623; SKILL.md :226, stops the moment a triage seat sits): lands in
domain:skills— the reading is SKILL.md :89 「互斥清 ⇒ fetch 后读三章程文件(本文、core-rules、本席章程)在origin/main的最新触碰 sha」, this lane's own protocol. Class (a), reproduced on THIS seat: the round-open marker 5673548571 recorded the charter's latest touch asb3b43b6/8c657f7/9b00f9f, read on a 50-commit shallow checkout; on the same checkout deepened to 90 commits,git show --stat <sha> -- <path>prints one stat line for8c657f7(core-rules — true), ZERO forb3b43b6(SKILL.md; the commit has a parent on the deepened checkout and touches no.claude/**path) and ZERO for9b00f9f(lanes/skills.md;git rev-list --parentsshows it parentless — it is the checkout's current graft boundary, the card's presumed mechanism, and stillgit log -1's answer today) — two of the three shas the mutex check compared are not readings of the path, and nothing said so. Direction (⛔ not a prescription): re-key :89 in place (≤120 B, SKILL.md at its 812/812 ceiling, no new line) so the touch sha is taken depth-independently — RESTGET /commits?sha=main&path=<file>&per_page=1, orgit logonly aftergit-history.mjs'shistoryHorizon()clears — with the verification leg the card names (git show --stat <sha> -- <path>non-empty; a firing control on a sha that did touch the path); agit-history.mjs touch --pathmode with a self-test is the non-governed machine spelling if the taker wants one; the mechanism is the taker's to establish, as the card says. The SKILL.md half is the rules layer (four-piece + an authorized APPROVED; ⛔ never armed by this seat). Graded 2026-09-15T17:44Z: p2 · Bug ·pm:queue·domain:skills— every fresh container takes this reading before its first write, and this seat's own was wrong. Dedup by the card's five terms over the newest 300 issues (open and closed): #18217 (devx; a self-test that refuses on a shallow clone) is a different symptom of the same depth, not a sibling; control 0. Serial: SKILL.md is held by no open PR of this lane; #18308 (:629) targets the same file — fold-or-serial answered at claim, p2 first.Edit 2026-09-15T18:29Z — correction owned by the seat, from the #18180 dev's measurement (report 5685767439, PR #18327): two of the three evidence claims above were wrong. (1) 「ZERO for
b3b43b6(SKILL.md)」 — the marker 5673548571 recordsb3b43b6as theorigin/mainTIP, not as SKILL.md's touch; SKILL.md's recorded touch was8c657f7, which did touch it (11 / 11). (2) 「ZERO for9b00f9f」 —git show --staton the graft boundary prints the WHOLE file as an insertion against the empty tree (33 lines); the seat's zero was a grep for the full path against a stat line that abbreviates it. The defect stands on the third claim:9b00f9fIS the boundary and was recorded as lanes/skills.md's latest touch — a reading of the graft, not of the path — and the card's proposed--statverification leg is itself fooled by a boundary; the tool's proof is parent presence +diff-tree. Grading unchanged (p2 · Bug · class (a)). Skills seat, sessionsession_01HZfg2AwVX191qCizp88gQr.
Generated by Claude Code
- addedpriority:p2Medium: important, M3Medium: important, M3
on Sep 15, 2026 claude commented
on Sep 15, 2026 claudeboton Sep 15, 2026 – with ClaudeContributorAuthorMore actionsClaim: PM loop round 1
Session:session_01HZfg2AwVX191qCizp88gQr(skills seat; claimed at 2026-09-15T17:46Z)
Branch:claude/issue-18180-charter-touch-sha-shallow
Worktree:objectstack-issue-18180
Domain:domain:skills
File surface:.claude/skills/pm-dispatch/SKILL.md:89 (the charter latest-touch reading, re-keyed in place ≤120 B — 812/812, no new line); optionallyscripts/pm/git-history.mjs(+ its self-test cases) if the taker gives the reading a machine spelling — nothing else (stop on breach; explain in the report)
Container & model:S,mode:subagent,model: CONTRACT_REVIEW_TIER—dispatch-gates.mjs --tierderives the mandate from.claude/skills/pm-dispatch/SKILL.md(clause ①); seat review atCONTRACT_REVIEW_TIER
Clause-②: no
Thread-read: 5685139384 (this seat's grading, the newest comment on the card at claim time)
Fold-or-serial: #18308 (SKILL.md :629) is the same file — SERIAL, this card first (p2 · Bug); no other look-alike in the queue
Serial constraints cleared: SKILL.md is held by no open PR (PR #18276 LANDED at 2026-09-15T15:14Z as53dd5aaa); batch 1/3
Generated by Claude Code
claude commented
on Sep 15, 2026 claudeboton Sep 15, 2026 – with ClaudeContributorAuthorMore actionsos-dev-report
{ "issue": 18180, "status": "done", "branch": "claude/issue-18180-charter-touch-sha-shallow", "worktree": "/home/user/objectstack-issue-18180 (cut from origin/main 82b3032c; removed after this report)", "pr": "https://github.com/objectstack-ai/objectstack/pull/18327", "head_sha": "d977c7a5f4b6b11d2e01976e19d2f931e8b99515", "session": "session_01HZfg2AwVX191qCizp88gQr — read from get_session (ccr.id) in this container; subagent of the dispatching seat", "premise_still_valid": true, "files_changed": [ ".claude/skills/pm-dispatch/SKILL.md (line 89 only, in place: 119 → 117 bytes, 812/812 lines)", "scripts/pm/git-history.mjs (+365/-10: touch mode, header section, 17-case self-test battery, roster floor 3 → 4)" ], "summary": "Design (B): scripts/pm/git-history.mjs grows a touch mode — node scripts/pm/git-history.mjs touch --path=PATH [--ref=origin/main] [--format=%H] [--deepen=N] [--no-fetch] [--no-unshallow] — that prints the last-touch sha only when every parent the commit object names is present locally AND the diff against those parents touches the path; otherwise it deepens with git fetch --deepen=N (additive, doubling from 64), then --unshallow, then refuses with exit 2 and empty stdout. SKILL.md :89 is re-keyed in place to 「互斥清 ⇒ fetch 后三章程(本文、core-rules、本席章程)最新触碰 sha 走 `git-history.mjs touch`。」 (117 B). The mechanism was established on a constructed repo at two depths: the graft boundary object still names its parent, traversal cannot see it, git diffs the boundary against the empty tree, so every path reads as touched there — and the same empty-tree diff makes the card's proposed git show --stat leg NON-discriminating for a boundary (it prints the whole file). Verified live on a genuine depth-50 clone: before, lanes/skills.md answered the boundary ea0b24a; the tool answers 9489e2c05 (two deepen steps, still shallow), byte-equal to REST and to a deepened clone; refusal and firing control demonstrated on a second fresh clone. Assignee was set by the PM at dispatch (os-zhuang); I wrote no assignee.", "tests": "node scripts/pm/git-history.mjs --self-test: BEFORE 37 ✓ / 0 ✗ exit 0; AFTER 54 ✓ / 0 ✗ exit 0 (`git-history --self-test: all cases passed.`). Gate battery: 43 derived by dispatch-gates --commands, all 43 run sequentially by a detached runner (each exit captured by redirect), 42 exit 0, check-engine-split-ratio exit 2 = its own shallow-clone refusal (NOT MEASURED locally, CI fetch-depth 0); --ran verdict: 43 run, 0 NOT-MEASURED, 0 UNRUN, at HEAD d977c7a5. Ratchet ✓ 812/812, id-lint ✓, eslint exit 0, self-test-wired ✓ 212/212, nul-bytes ✓, governed --test → GOVERNED, clause2 --pair exit 0. Reverse verification on real history (readings under reverse_verification). No ablation of a dist build applies: the script runs from source (scripts/pm, no build step); the self-test BASELINE cases are the unpatched-spelling reproduction and turn red if the touch proof is removed by construction (they assert raw git names the boundary while the tool refuses).", "gates": [ { "command": "node packages/lint/scripts/check-reference-carrier-shape.mjs", "exit": 0, "note": "" }, { "command": "node packages/lint/scripts/check-reference-carrier-shape.mjs --self-test", "exit": 0, "note": "" }, { "command": "node scripts/check-ci-filter-parity.mjs", "exit": 0, "note": "" }, { "command": "node scripts/check-closing-keyword-parity.mjs", "exit": 0, "note": "" }, { "command": "node scripts/check-closing-keyword-parity.mjs --self-test", "exit": 0, "note": "" }, { "command": "node scripts/check-comment-mask-corpus.mjs", "exit": 0, "note": "" }, { "command": "node scripts/check-declaration-mirrors.mjs", "exit": 0, "note": "" }, { "command": "node scripts/check-declaration-mirrors.mjs --self-test", "exit": 0, "note": "" }, { "command": "node scripts/check-engine-split-ratio.mjs --days 90", "exit": 2, "note": "NOT MEASURED locally: the gate REFUSED (its own exit 2) because this worktree shares the shallow clone (floor 2026-09-14 inside the 90-day window); lint.yml runs it on a fetch-depth 0 checkout. Recorded as the true exit, not rewritten to 3." }, { "command": "node scripts/check-engine-split-ratio.mjs --self-test", "exit": 0, "note": "" }, { "command": "node scripts/check-scripts-symbol-anchors.mjs", "exit": 0, "note": "" }, { "command": "node scripts/check-scripts-symbol-anchors.mjs --self-test", "exit": 0, "note": "" }, { "command": "node scripts/check-self-test-wired.mjs", "exit": 0, "note": "the dispatch spelled this as scripts/pm/check-self-test-wired.mjs, which does not exist; the derived list names scripts/check-self-test-wired.mjs — ran that: 212/212 wired." }, { "command": "node scripts/check-self-test-wired.mjs --self-test", "exit": 0, "note": "" }, { "command": "node scripts/check-self-test-workflow-commands.mjs", "exit": 0, "note": "" }, { "command": "node scripts/check-self-test-workflow-commands.mjs --self-test", "exit": 0, "note": "" }, { "command": "node scripts/check-whole-set-label-write.mjs", "exit": 0, "note": "" }, { "command": "node scripts/check-whole-set-label-write.mjs --self-test", "exit": 0, "note": "" }, { "command": "node scripts/pm/bare-root-worklist.mjs --self-test", "exit": 0, "note": "" }, { "command": "node scripts/pm/check-governed-queue-guard.mjs --self-test", "exit": 0, "note": "" }, { "command": "node scripts/pm/git-history.mjs --self-test", "exit": 0, "note": "the edited script: 37 cases before the edit, 54 after, all cases passed, exit 0 both times." }, { "command": "node scripts/report-test-timings.mjs --self-test", "exit": 0, "note": "" }, { "command": "pnpm --filter @objectstack/lint run check:doc-formula-expressions", "exit": 0, "note": "first run exit 3 (its own PREREQUISITE NOT MET: formula+lint not built); built both under os-verify-lock (VERDICT command-exit 0, 134 s) and re-ran at exit 0 — this is the recorded code." }, { "command": "pnpm check:agent-test-spelling", "exit": 0, "note": "" }, { "command": "pnpm check:bash32-floor", "exit": 0, "note": "" }, { "command": "pnpm check:cli-command-ids", "exit": 0, "note": "" }, { "command": "pnpm check:cross-package-test-inputs", "exit": 0, "note": "" }, { "command": "pnpm check:doc-authoring", "exit": 0, "note": "" }, { "command": "pnpm check:driver-memory-census", "exit": 0, "note": "" }, { "command": "pnpm check:entry-guard", "exit": 0, "note": "" }, { "command": "pnpm check:nul-bytes", "exit": 0, "note": "" }, { "command": "pnpm check:parse-guard", "exit": 0, "note": "" }, { "command": "pnpm check:pm-dispatch-gates", "exit": 0, "note": "the battery, run inside the detached sequential runner (setsid nohup, waited with tail --pid)." }, { "command": "pnpm check:pm-governed-merges", "exit": 0, "note": "" }, { "command": "pnpm check:pm-governed-prose", "exit": 0, "note": "" }, { "command": "pnpm check:pm-half-states", "exit": 0, "note": "" }, { "command": "pnpm check:pm-skill-id-lint", "exit": 0, "note": "27 files clean; line 89 carries no issue number." }, { "command": "pnpm check:pm-skill-ratchet", "exit": 0, "note": "SKILL.md 812 lines (ceiling 812, headroom 0); widest table row 342 (pin 342)." }, { "command": "pnpm check:pnpm-filter-targets", "exit": 0, "note": "" }, { "command": "pnpm check:ratchet-remedy-authority", "exit": 0, "note": "" }, { "command": "pnpm check:refd-timer-probe", "exit": 0, "note": "" }, { "command": "pnpm check:skill-frame-sync", "exit": 0, "note": "" }, { "command": "pnpm check:watch-hint-literal", "exit": 0, "note": "" }, { "command": "node scripts/pm/dispatch-gates.mjs --ran ran.txt", "exit": 0, "note": "VERDICT: ✓ dispatch-gates --ran: 43 derived famil(ies) accounted for — 43 run, 0 NOT-MEASURED (a DERIVED zero — all 43 recorded an exit code and none of them is 3). Path-derived and path-less derivations identical." }, { "command": "pnpm exec eslint scripts/pm/git-history.mjs", "exit": 0, "note": "no findings" }, { "command": "node scripts/pm/check-governed-merges.mjs --test .claude/skills/pm-dispatch/SKILL.md scripts/pm/git-history.mjs", "exit": 3, "note": "GOVERNED — .claude/** ×1 (SKILL.md); scripts/pm/git-history.mjs not on the register. Expected." }, { "command": "node scripts/pm/check-clause2-carriers.mjs --pair 18327", "exit": 0, "note": "clause-② declaration readable, both carriers agree, no widening tell." }, { "command": "grep -naP control-byte class over the two edited files", "exit": 1, "note": "0 hits (exit captured by redirect, not through a pipe)." } ], "reverse_verification": { "before_unpatched_spelling_real_depth50_clone": "GitHub clone --depth=50, floor ea0b24a 2026-09-14T16:27:40Z, tip a46cd8c. git log -1 --format=%h_%cI origin/main -- PATH: SKILL.md → 53dd5aa 2026-09-15T14:54:13 (parent present, stat 2 +-) TRUE; core-rules.md → 8c657f7 2026-09-14T23:24:17 (parent present, stat 2 +-) TRUE; lanes/skills.md → ea0b24a 2026-09-14T16:27:40 — the BOUNDARY: its object names parent fbeb6d6, absent locally; git show --stat --format= ea0b24a -- PATH prints `33 ++++` (the whole 33-line file) — FALSE and newer than the truth.", "after_tool_same_clone": "node scripts/pm/git-history.mjs touch --path=PATH: SKILL.md → 53dd5aaaafbe877a1cc72aef26511bd15c927ecf exit 0 (proved without fetching); core-rules.md → 8c657f7dd0740e37e836edf14207ad9ce7836ec3 exit 0 (proved without fetching); lanes/skills.md → 9489e2c05a04173d6a0567fa9edd0f356a868781 exit 0 after fetch --deepen=64 then --deepen=128 (clone 50 → 242 commits, still shallow), receipt `proof: 1 parent(s) present locally, diff-tree touches .claude/skills/pm-dispatch/references/lanes/skills.md (4 ++--)`. Raw git log -1 on the deepened clone now names the same three; git show --stat lists the path for each.", "rest_vs_deepened_agreement": "GET /repos/objectstack-ai/objectstack/commits?sha=main&path=PATH&per_page=1 through the proxy with NO auth header: HTTP 200 → 53dd5aaaa / 8c657f7dd / 9489e2c05 (and d5125f223 for lanes/devx.md, the card's true value). Byte-equal to the tool and to the deepened clone.", "refusal": "second fresh depth-50 clone, touch --path=lanes/skills.md --no-fetch: exit 2, stdout 0 bytes; stderr `⛔ git-history REFUSES to name a last-touch sha — ea0b24a43 is a shallow graft boundary — its object names parent fbeb6d68e, which this clone does not have, so git diffed it against the EMPTY tree …` + `raw git log -1 said: ea0b24a43 (NOT a reading of the path)` + a --deepen remedy.", "firing_control": "same second clone, touch --path=.claude/skills/pm-dispatch/SKILL.md --no-fetch --format=%h_%cI: exit 0, `53dd5aa 2026-09-15T14:54:13+00:00`, receipt `proof: 1 parent(s) present locally, diff-tree touches … (2 +-) · proved without fetching`; the clone stayed at 50 commits. In the self-test the same control is case 13 (f.txt on a depth-5 clone answers the tip without a fetch).", "constructed_clone_mechanism": "40-commit repo, charter.md last touched at c2. --depth=5: git log -1 -- charter.md → c35 = the graft boundary (rev-list --parents: 1 word; cat-file -p: one parent line; that parent NOT present; git show --stat prints `charter.md | 1 +`; git diff-tree without --root prints nothing). --depth=20: → c20 = its own boundary, same signature. Deepened (--deepen=64): → c2, parent present, stat `charter.md | 2 +-`. VERDICT: one mechanism seen from two depths — the pathspec walk stops at the graft, git diffs the boundary against the empty tree, and the boundary is reported as the last touch of every path in its tree. The reading that proves it: the parent the OBJECT names is absent from the local graph. Also measured: git fetch --deepen=N is additive (boundary c20 → c15 for N=5), updates origin/main opportunistically, and dissolves the shallow marker when it reaches the real root; --deepen on a complete clone is a no-op at exit 0.", "b3b43b6_case": "FALSE as posed. The round-open marker 5673548571 records b3b43b6 as the origin/main TIP at fetch time and 8c657f7 as the latest touch of BOTH SKILL.md and core-rules.md; git show --stat --format= 8c657f7 -- SKILL.md prints `22 +++++++++++-----------` (11/11). So SKILL.md's reading was true and b3b43b6 was never git log -1's answer — no second mechanism." }, "self_test_cases": { "before": 37, "after": 54, "new_battery": "touch: the provenance reading a shallow clone fabricates (17 cases, floor pinned at 17; SELF_TEST_BATTERY_FLOOR 3 → 4)", "names": [ "BASELINE — depth-5 raw git names the graft boundary as the last touch of a file it never changed", "the boundary OBJECT names one parent and that parent is absent", "the naive verification leg is fooled: git show --stat on the boundary prints a line", "a second depth names a second sha — its own boundary: one mechanism", "touchIsProvable refuses the boundary and says it is one", "touchIsProvable accepts the true touch on the complete clone, listing the path", "CLI REFUSES the shallow reading with exit 2", "stdout stays EMPTY", "refusal names the mechanism, the raw sha it is NOT printing, and a --deepen remedy", "with fetching allowed it deepens and answers the TRUE touch, exit 0", "while the clone is STILL shallow — the predicate is parent presence, never the shallow flag", "a deepen that lands the boundary exactly ON the true touch is not accepted at that step", "FIRING CONTROL — a sha that did touch the path answers without any fetch", "a real root is provable once reached; the deepen dissolves the graft", "a complete clone answers without fetching and honours --format", "a path no commit ever touched is usage (exit 1) with empty stdout", "touch without --path is usage" ] }, "ratchet": { "skill_md_lines_before": 812, "skill_md_lines_after": 812, "line_89_bytes_before": 119, "line_89_bytes_after": 117, "widest_table_row": "342 (pin 342)", "frame_block_734_755_md5": "3327d02c56f8a0eca88569dad2270f32 (unchanged, verified after the edit)", "core_rules_19_20": "untouched" }, "assumptions_verified": [ { "claim": "shared checkout: git rev-parse --is-shallow-repository → true", "verdict": true, "evidence": "true; 90 commits on origin/main; 3 lines in .git/shallow; boundary reachable from origin/main = 9b00f9f9 2026-09-14T02:54:29Z" }, { "claim": "git log -1 --format=%h origin/main -- lanes/skills.md → 9b00f9f", "verdict": true, "evidence": "9b00f9f9 (gate(checklist): bind the platform-checklist corpus …)" }, { "claim": "git rev-list --parents -n1 9b00f9f | wc -w → 1", "verdict": true, "evidence": "1 word; and cat-file -p shows the object DOES name a parent that is absent" }, { "claim": "git show --stat --format= 9b00f9f -- lanes/skills.md → EMPTY", "verdict": false, "evidence": "prints ` .../lanes/skills.md | 33 ++++++++++++++++++++++ / 1 file changed, 33 insertions(+)` — the file is 33 lines at that commit, i.e. the whole file as an insertion against the empty tree. Reproduced on the constructed clone at both depths and on the real depth-50 clone (ea0b24a prints the same 33-line stat)." }, { "claim": "firing control: git show --stat --format= 8c657f7 -- core-rules.md → one line", "verdict": true, "evidence": "` .claude/skills/pm-dispatch/references/core-rules.md | 2 +- / 1 file changed, 1 insertion(+), 1 deletion(-)`, exit 0" }, { "claim": "mechanism: a pathspec walk stops at the graft boundary and attributes the path to it", "verdict": true, "evidence": "constructed clone at depth 5 and 20 (see reverse_verification.constructed_clone_mechanism); the precise form is: git diffs the parentless-by-graft boundary against the empty tree" }, { "claim": "b3b43b6 = a non-boundary commit answered while the clone was 50 deep (a possible second mechanism)", "verdict": false, "evidence": "marker 5673548571 records b3b43b6 as the origin/main tip; SKILL.md's recorded touch was 8c657f7, which did touch SKILL.md (11/11)" }, { "claim": "REST GET /commits?sha=main&path=…&per_page=1 is depth-independent, needs no auth header, and agrees with git log -1 on a deepened clone", "verdict": true, "evidence": "HTTP 200 without auth for all four paths; 53dd5aaaa / 8c657f7dd / 9489e2c05 / d5125f223; equal to the tool and to raw git on the 242-commit clone" }, { "claim": "the --stat leg is cheap and self-controlling: non-empty ⇔ the sha touched the path, and a boundary prints nothing", "verdict": false, "evidence": "the boundary half is false (whole-file stat); the leg holds only once the parent the object names is present locally — which is the leg the tool uses (objectParents + diff-tree), with the stat line printed in the receipt" }, { "claim": "git-history.mjs ensure --since is the deepening tool; --shallow-since is not monotonic", "verdict": true, "evidence": "read from the header (measured 4585 → 3205); touch does not use it because the touch date is unknown a priori — it uses fetch --deepen=N, which counts from the boundary and only adds (measured: c20 → c15 for N=5; a complete clone stays complete)" }, { "claim": "frame block :734–:755 md5 3327d02c56f8a0eca88569dad2270f32 on origin/main", "verdict": true, "evidence": "same md5 before and after the edit" } ], "four_axes": [ "实际业务需求: the reading is real and consumed — three files per round, every round, by the mutex comparison; measured wrong on two seats this shift (devx 2026-09-14, skills 2026-09-15). (A) prose leaves the seat a hand-run two-step whose verification leg is itself fooled by the boundary; (B) is one command that answers or refuses.", "项目长远合理性: windowed history already goes through git-history.mjs (AGENTS.md: answer, or REFUSE); a provenance reading in the same tool is the same principle with the same refusal contract (empty stdout, exit 2) — no workaround, no second tool.", "防 AI 写代码犯错: (A) depends on a seat noticing that a plausible sha is wrong; (B) makes the wrong reading impossible to capture ($(...) gets an empty string), the refusal is loud and names the mechanism, and the self-test carries a firing control so \"always refuses\" cannot pass as safe. Declaration = enforcement.", "创业阶段不扩散需求: one subcommand on an existing tool, +17 self-test cases, no new file/gate/ceiling; SKILL.md loses two bytes; the old spelling is replaced, not aliased — no dual spelling, no staged window. Recommendation: (B) — the seat's reading confirmed." ], "deviations": [ "The dispatch names `node scripts/pm/check-self-test-wired.mjs`; that path does not exist. The derived list names `node scripts/check-self-test-wired.mjs`, which I ran (exit 0, 212/212).", "The seat's measurement \"git show --stat --format= 9b00f9f -- lanes/skills.md → empty\" is false on this checkout (33-insertion line), and with it the dispatch's \"a boundary commit prints nothing for the path — so the leg refuses the boundary too\". The tool's proof is parent presence + diff-tree, not stat emptiness; the stat line is printed in the receipt only.", "The b3b43b6 assumption is false as posed (marker: it was the tip); reported under assumptions_verified rather than measured as a second mechanism.", "check-engine-split-ratio --days 90 is NOT MEASURED locally (the gate's own exit 2 refusal on the shared shallow clone); I did not deepen the shared repository (shared object store and .git/shallow — an operator action, per git-history.mjs) and declared it to CI, which checks it out at fetch-depth 0. Recorded as the true exit 2 in the --ran file rather than rewritten to 3.", "The draft PR was opened AFTER the local gates (not before verification ended): the writes budget allows one POST /pulls and no body PATCH, so the body had to carry the gate readings at creation. The empty-branch push at start served as the landing marker.", "origin/main advanced by one commit (a46cd8c, check-half-states.mjs) after the cut from 82b3032c; it touches neither file, so the branch was not rebased.", "The 2-package build (formula, lint) to make the doc-formula gate measurable ran under os-verify-lock (VERDICT command-exit 0, held 134 s, waited 0 s)." ], "open_questions": [], "out_of_scope_findings": [ "to file (class a — reproducible; dedupe: check-harness-current · latest touch · graft boundary · git log -1 · touchIsProvable): scripts/pm/check-harness-current.mjs takes `git log -1 REF -- PATH` on the SHARED shallow checkout and prints the graft boundary as a harness path's latest touch — on the shared checkout today `✓ .claude/hooks/*: latest touch 9b00f9f9cf (2026-09-14T02:54:29+00:00) is in the shared HEAD`, where 9b00f9f9 is the boundary and its true parent is absent. The CURRENT/STALE verdict holds by construction (a boundary is under HEAD, as is everything below it), but the printed sha is not a reading of the path. Remedy shape: call touchIsProvable() from git-history.mjs and print `boundary` instead of a sha. Not in this card's file surface; the seat files.", "noted, not filed: references/platform-readings.md carries no row for this trap (the card proposed one); the rule now names the tool and the tool header carries the measurement, so a row would be a second copy. Bearer: the skills seat on its next platform-readings fold.", "noted, not filed: card 18217 (a self-test that refuses on a shallow clone) is a different symptom of the same depth — not touched here, remains open; bearer: its own taker." ], "mcp_calls": "1 — mcp__Claude_Code_Remote__get_session (read: this container's session id). 0 MCP GitHub calls; no MCP write tool.", "api_writes": "3 REST writes — POST /repos/objectstack-ai/objectstack/pulls (201, draft #18327); POST /repos/objectstack-ai/objectstack/issues/18327/labels via label-write.mjs (200, skip-changeset, read-back matched); POST /repos/objectstack-ai/objectstack/issues/18180/comments via post-stamped.mjs (this report). Plus 2 git pushes to claude/issue-18180-charter-touch-sha-shallow (empty-branch probe, then d977c7a5). No PATCH, no MCP." }
Generated by Claude Code
claude commented
on Sep 15, 2026 claudeboton Sep 15, 2026 – with ClaudeContributorAuthorMore actionsACCEPT — skills seat, session
session_01HZfg2AwVX191qCizp88gQr, 2026-09-15T18:33Z. Report 5685767439 on PR #18327 (headd977c7a5) reviewed by the checklist: files changed = the claim's surface exactly (SKILL.md :89 in place +scripts/pm/git-history.mjswith its self-test — the optional half the claim named);Fixes #18180alone beside a closing keyword;skip-changesetread back;mcp_callsnames no write tool; gates 43 / 43 / 0 by--ranon the head (one recorded at its own exit 2 — the shallow-clone refusal CI measures at fetch-depth 0), battery 1730 pass;--pair0; the seat's re-run on a detached worktree: self-test 54 (37 on main), ESLint 0, ratchet 812 / 812 with :89 at 117 B, id-lint, frame-sync, wiring green, the live refusal / answer probes on the shared shallow checkout agreeing with REST; the diff read whole. Two seat premises refuted and one dispatch spelling wrong — owned in the record on the PR, the grading comment corrected in place; seven deviations answered; one out-of-scope card filed (#18330, this lane, serial behind this PR). Landing: GOVERNED (.claude/**) — the four-piece is hung on PR #18327 (record, 速读终稿, this ACCEPT,needs-user-decision, reviewersos-zhuang+hotlong); the card stayspm:dispatcheduntil ruling C after an authorized APPROVED and the three landing readings.
Generated by Claude Code
claude commented
on Sep 15, 2026 claudeboton Sep 15, 2026 – with ClaudeContributorAuthorMore actionsSeat battery reading for PR #18327 (head
d977c7a5), promised in record 5685889073 — skills seat, sessionsession_01HZfg2AwVX191qCizp88gQr, 2026-09-15T18:41Z:pnpm check:pm-dispatch-gateson a detached worktree of the head —dispatch-gates self-test: 1730 cases pass, 463.9 s, exit 0; matches the dev's reading. Nothing else changes; the four-piece stays hung for an authorized APPROVED.
Generated by Claude Code
Landed — skills seat, session
session_01HZfg2AwVX191qCizp88gQr, 2026-09-16T02:16Z. PR #18327 (headd977c7a5) merged by the queue as0cc5ce856b98d7f9cd4666aada2e801e751d98ce(single-parent squash pergit rev-list --parents) at 2026-09-16T02:14Z — themerged_atinstant, carried identically by themergedandremoved_from_merge_queuetimeline events. Readings at 2026-09-16T02:16Z:git log origin/maincarries(#18327); the queue refrefs/heads/gh-readonly-queue/main/pr-18327-*is gone from origin; theremoved_from_merge_queueevent is on the timeline. Governed rules layer, ruling C: APPROVED by os-zhuang (5217673315 at 2026-09-16T01:53Z), who flipped it ready and enqueued it; record 5685889073 PASS on that head, 速读终稿 5685889666, ACCEPT 5685890066 on this card, ruling-C provenance 5690856345; the seat clearedneeds-user-decision. Now onorigin/main:git-history.mjs touchanswers a last-touch sha only when the commit's parents are present locally anddiff-treetouches the path, else deepens, unshallows, or refuses with exit 2 and empty stdout; SKILL.md :89 names it (117 B, 812 / 812). Residue (pm:dispatched, assignee) stripped throughlabel-write.mjsand read back; #18308 (SKILL.md :629) and #18330 (check-harness-current.mjs) are dispatchable now.
Generated by Claude Code
- added 2 commits that reference this issue
on Sep 17, 2026
Measured by the
domain:devxexecution seat while seating this shift, and it corrupted a reading the seat-post protocol requires every incoming seat to take. ⛔ Unlabelled fordomain:*and ungraded — routing is triage's (the fact table lives under.claude/skills/**, so likelydomain:skills). ⛔ The seat did not dedupe; dedupe words at the bottom.The defect: on a shallow checkout,
git log -1 -- <path>names a commit that never touched that pathNot a truncation, ⛔ not an error, ⛔ not a non-zero exit. It returns a real, plausible commit sha, and nothing says the answer is fabricated.
Measured, on this container
At seating, the seat ran the reading its own protocol asks for — the charter files' latest touch on
origin/main:That sha was then recorded in the seat post as the lane charter's provenance. It is false:
State of the checkout minutes later, same session:
After the clone was deepened (incidentally, by
scripts/pm/git-history.mjs log --days=30, which fetches--shallow-since), the same command on the same path answers:⛔ Stated as inference, not measurement: the presumed mechanism is the shallow graft boundary — git treats the boundary commit as a root at which the whole tree appears, so a pathspec walk stops there and attributes the path to it. The seat did not isolate that, and whoever takes this card should establish the mechanism rather than inherit this sentence.
Why it matters more than an ordinary stale reading
git-history.mjs log --days=30call was itself performing the deepening fetch, and the output it captured was short. ⇒ Same root (shallow checkout + git answering anyway), two different symptoms: truncated output there, a fabricated-but-plausible sha here. The second is worse because there is nothing to notice.scripts/pm/git-history.mjsalready exists precisely because 「浅 clone 对窗口化git log/rev-list以 exit 0 无警告答错」 — but its guard covers windowed counting, ⛔ not-1 -- <path>provenance lookups, which is how the charter reading is spelled.Suggested repair (⛔ a proposal, not a prescription)
One line in
references/platform-readings.md: on a shallow checkoutgit log -1 -- <path>can name a commit that does not touch the path, so a provenance sha must be taken afterhistoryHorizon()clears, or verified withgit show --stat <sha> -- <path>producing a non-empty result.⭐ The verification leg is cheap and self-controlling — a sha that truly touched the path prints a stat line; a fabricated one prints nothing — so it may be worth naming it as the standing spelling rather than relying on the checkout's depth.
Acceptance
scripts/pm/git-history.mjsshould grow a provenance mode, or whether a documented spelling is enough — ⛔ that judgement is the taker's, not asserted here.Dedupe words
shallow clone git log·provenance sha·charter touch sha·historyHorizon·git-history.mjsGenerated by Claude Code