Uh oh!
There was an error while loading. Please reload this page.
fix(tooling): read the objectui commit before the pin write, and refuse an unreadable one - #10866
Merged
Merged
Conversation
…se an unreadable one bump-objectui.sh wrote .objectui-sha before it read the commit subject out of the objectui checkout. When the commit object could not be read, git log failed, set -e killed the run, and the pin file had already been rewritten: no changeset, no commit, a bare 'fatal: bad object' as the whole explanation, and a modified working tree. Re-running did not self-correct, because the pin file then held the bad SHA. Every read of the objectui commit now happens before the first mutation, and the guard IS that read rather than a cat-file -e standing in for it. An unreadable commit object is a hard refusal with the working tree untouched -- there is nothing meaningful to pin. The reachability report's warning-not-gate ruling is about a pin that is not on main and is untouched here. scripts/bump-objectui.selftest.sh (pnpm check:objectui-bump, wired into the lint job) pins the invariant on the file's BYTES: both the broken and the fixed script exit non-zero on this input, so only the file tells them apart. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DdCnBGcHeufjrq7drTD3wt
… refusal The digest self-test's #10495 R5c pinned the branch this change removes: an unreadable commit object reported as UNDETERMINED. Triage ruled that verdict belongs to a pin that is not on main -- a real commit you can still pin -- and not to one whose object cannot be read, where there is nothing to pin at all. Rewritten rather than deleted: the fixture still builds the same absent-object shape, and now demands the refusal, the untouched pin file (byte-identical) and the named remedy. R5a and R5b are untouched -- both git behaviours they measure are what make the case reachable in the first place. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DdCnBGcHeufjrq7drTD3wt
os-zhuang
marked this pull request as ready for review
August 21, 2026 14:48
os-zhuang
enabled auto-merge
August 21, 2026 14:48
Uh oh!
There was an error while loading. Please reload this page.
Contributor
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 32494150733 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#10797
The defect
scripts/bump-objectui.shwrote the pin file before it read anything else aboutthe commit:
When the commit object could not be read,
git logfailed,set -ekilled the run,and
.objectui-shahad already been rewritten: no changeset, no commit, a barefatal: bad objectas the entire explanation, and a modified working tree theoperator had to clean up by hand. Re-running did not self-correct — the pin file now
held the bad SHA, so the next run compared against it.
Reachable with no argument at all: measured, git 2.43.0,
git rev-parse HEADexits0 and prints the sha even when that commit's object is missing from the store,
because it resolves the ref without reading the object.
The fix
Every read of the objectui commit now happens ahead of the first mutation, and
the guard is that read rather than a probe standing in for it.
cat-file -eanswers "is the object present", which is one failure short of the question that
matters — a present-but-unreadable object (corrupt zlib, truncated pack) passes it
and still kills
git log. Doing the real read means anything that would fail laterhas already failed with the tree untouched.
An unreadable commit object is a hard refusal, per the triage ruling on the
judgement the card left open: there is nothing meaningful to pin, and neither the
changeset entry nor the commit message can be derived from it.
The reachability report's warning-not-gate ruling is untouched and does not
extend here — it is about a pin that is not on
main, a real commit you can stillpin, where
origin/mainmay just be stale and the judgement is the operator's.Its
#10495case R5c is retriaged rather than deleted (see below); nothing elseabout that report changes, and its "not on origin/main" behaviour is unchanged.
report_objectui_reachability's presence probe (Q2) is removed: it became a secondimplementation of a question the preflight now answers with a stronger test, and
this file's own standing rule is one implementation per rule. Its
rc != 1branchremains the backstop and still reports 128 as the error it is, never as a verdict.
Evidence
New self-test
scripts/bump-objectui.selftest.sh(pnpm check:objectui-bump, wiredinto the lint job as an unconditional step). It drives the real bytes of the script
over throwaway git repos — offline, no node, no network, ~1s.
The assertion is on bytes, not on the message. Both the broken and the fixed
script exit non-zero on this input — 128 from
set -eversus 1 from the refusal —so "did it fail?" does not tell them apart, and a test asking only that would have
passed against the defect. What discriminates is the file.
Ablation, both directions. With the reordering reverted on disk (preflight block
removed, the two reads put back after the write — confirmed by marker counts
1→0 / 0→1 and the file's byte count 29809→26372), the self-test goes red on exactly
that assertion and reproduces the card's measurement verbatim:
Restored (byte count back to 29809, markers back, tree clean against the commit):
Two of the four cases drive readable commits all the way through and assert the
pin moves, because
exit 1at the top of the script would satisfy every refusalcase on its own.
Fixture triage
objectui-changeset-digest.mjs's#10495 R5cpinned the branch this changeremoves — "an absent object is reported as UNDETERMINED". That case is rewritten,
not deleted: it builds the same absent-object fixture and now demands the refusal,
the byte-identical pin file, and the named remedy. R5a and R5b are untouched; both
git behaviours they measure are what make the case reachable at all.
Note for the reviewer: before this PR touched
objectui-changeset-digest.mjs,dispatch-gatesscoredcheck:objectui-changesetsilent for a diff that editsonly
bump-objectui.sh— even though that gate's self-test drives that exact file.Not a CI hole (lint.yml declares no
pull_requestpath filter, so it runs on everyPR, and it is what caught this locally), and
dispatch-gatesdocumentssilentasits weakest claim. Recorded, not filed.
Docs
docs/releases-maintenance.mdsaid an absent commit object lands in the"cannot be answered" bullet. That is now false, so the bullet is corrected and a
short section documents the refusal, the invariant, and the remedy.
Gates
Union re-run at head
0f90719bbd(the final commit), all green:Plus
check:node-version,check:required-contexts,check:shard-attestation,check:workflow-status-functions,check:doc-formula-expressions(filter verifiedto have matched
@objectstack/lint, not a zero-match exit 0), and the raw-nodecheck-aggregator-roster/check-ci-filter-parity/check-cross-package-test-inputs/
check-required-contexts/check-shard-attestation.check:type-check-debtneeded the workspace closure built first (its own #6376 guard refused on an
unbuilt one); it was built and the gate then re-measured clean.
check:entry-guardandcheck:parse-guardwere run by hand —dispatch-gatescannot reach either from a
scripts/**path.No changeset
Nothing here is published: a maintainer shell script, its self-test, a
scripts/node self-test fixture, internal maintainer docs, the root private
package.json,and a lint workflow step. Taking
skip-changeset.Generated by Claude Code
Generated by Claude Code