fix(devx): deepen on an absent objectui pin endpoint, and refuse an unwalkable range - #14391

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-14178-changeset-digest-shallow-checkout
Sep 2, 2026
Merged

fix(devx): deepen on an absent objectui pin endpoint, and refuse an unwalkable range#14391
baozhoutao merged 1 commit into
mainfrom
claude/issue-14178-changeset-digest-shallow-checkout

Conversation

@claude

@claudeclaudeBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes#14178

The objectui pin bump derives the @objectstack/console changeset — its list and its bump level — from the changesets objectui declared over OLD..NEW. When the OLD endpoint's commit object was absent (what git clone --depth N produces: the shallow boundary sits after the old pin), the digest's endpoint guard returned before findRangeTruncation ran, so the deepen the script advertises was never considered, and the bump fell back to a degraded entry carrying the DEFAULT level.

Implements the triage ruling on the card: candidate 1 + 2 together — deepen on an absent endpoint and re-ask, and refuse when the re-ask still fails.

Measured, before and after

A throwaway objectui: 5 commits, 4 releasing changesets (2 patch, 2 minor, one of the minor ones carrying an author breaking annotation), cloned --depth 2 so the from object is absent. Same range, same command, one file:// remote so the run stays offline.

rundeepen attemptedexitbump levellistADR-0087 prompt
before — shallow, deepen allowedno0patch1-line degraded (tip subject)never fired
before — unshallowed by handn/a0minor4 releasing, 1 breakingfired
after — shallow, deepen allowedyes, then re-asked0minor4 releasing, 1 breakingfired
after — shallow, OBJECTUI_NO_DEEPEN=1opted out1noneno changeset written, pin untouchedn/a

The degraded entry did label itself degraded, so nothing lied — but the level was a default nobody declared, it publishes into @objectstack/console's CHANGELOG and the curated release notes, every declared-breaking entry was invisible in it, and the ADR-0087 disposition prompt never fired because the degraded changeset declares nothing breaking. That reproduction is now a self-test case (S6), asserted equal to the record the same range yields in a full clone.

The guard reorder

scripts/objectui-changeset-digest.mjs

  • findAbsentEndpoints() / describeAbsentEndpoints() — the other half of the walkability precondition, shaped like findRangeTruncation / describeTruncation on purpose: the two are one class of failure with two causes, and a caller that treats them alike must be able to read them alike. It names WHICH endpoint is missing, whether the clone is shallow, re-emits git's own captured diagnostic, and prints the remedy.
  • The endpoint guard's catch is replaced by that call, reporting PREREQUISITE NOT MET and keeping exit 2. The exit-code contract is unchanged in its codes and sharpened in its meaning: 2 (endpoint absent) and 3 (history stops inside the range) both mean "repair the input and ask again", and neither authorizes a weaker derivation.
  • The same assertion is made inside classifyRange, the single shared implementation, so objectui-range.mjs cannot derive from an absent endpoint either — and it is asked BEFORE the truncation test, because rev-list from..to cannot run without from (pinned as S1).

The refusal shape

scripts/bump-objectui.sh

  • Exit 2 now takes the same deepen-and-re-ask path as exit 3. The re-check decides, never the fetch's status — the C17 lesson, unchanged and still pinned.
  • A range still unwalkable after that refuses: non-zero, no changeset written, the cause named (absent endpoint / stops inside the range / the probe never returned a verdict), what was tried named (opted out, not shallow, fetch failed, fetch exited 0 without repairing), and two remedies plus --no-changeset for moving the pin while claiming nothing about the range.
  • The whole question is asked above the pin write, so a refusal leaves .objectui-sha byte-identical — the bump-objectui.sh leaves a half-applied bump when the objectui commit object is absent: .objectui-sha is rewritten, then the run dies on git log #10797 invariant, now owed by a second refusal and pinned as C15 and S7.
  • The degraded artifact for an unwalkable range is removed, not reshaped: the ruling asked for one code path fewer, not a fourth state. The initial pin keeps its degraded entry (no previous SHA, no range, no remedy to name) and gains the self-test coverage the removed paths had.

Self-test

pnpm check:objectui-changeset — 130 checks, all green (was 122). The #9408 shell cases C13/C14/C15/C17 now pin the refusal instead of the degraded artifact; C16 and C18 are unchanged; a new #14178 group (S1–S8) covers the absent-endpoint branch end to end.

Ablation, on the committed tree: restoring the pre-fix deepen trigger in bump-objectui.sh (only exit 3 deepened) turns S6, S6b, S7 and S8 red and the rest green. The mutation was confirmed on disk by anchor grep counts in both directions (deleted text 1 to 0, injected text 0 to 1) plus a blob-hash comparison against the HEAD blob; the restore was confirmed by git hash-object equal to the HEAD blob and an empty git diff HEAD. No rebuild leg applies: both scripts are executed from source, and the self-test copies their bytes into throwaway framework roots.

Gates

Derived in the worktree with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (16 families: 14 by path, 2 by change kind), reconciled with --ran against a record built from --commands, at 8084a7bdd:

✓ dispatch-gates --ran: 16 derived famil(ies) accounted for — 14 run, 2 NOT-MEASURED.
gateverdict
check:objectui-changesetRAN-PASS (130 + objectui-range checks)
check:objectui-bump (this file's own self-test, run beyond the derived set)RAN-PASS (13 assertions, 4 cases)
check:agent-test-spelling · check:bash32-floor · check:cli-command-ids · check:cross-package-test-inputs · check:entry-guard · check:parse-guard · check:pnpm-filter-targets · check:ratchet-remedy-authority · check:watch-hint-literalRAN-PASS
check:declared-population-live (dispatch-mandated for every scripts/** card)RAN-PASS
scripts/check-ci-filter-parity.mjs · scripts/check-cross-package-test-inputs.mjs · scripts/check-shard-attestation.mjs · scripts/pm/bare-root-worklist.mjs --self-testRAN-PASS
scripts/check-test-completeness.mjsNOT MEASURED — exit 3, PREREQUISITE NOT MET: it grades a saved turbo run test log and none was named. Its own text prescribes recording NOT MEASURED when reached from the derived family list; CI tees the log and passes the path
check:pm-dispatch-gatesNOT MEASURED — SIGTERM-killed at 600s (exit 143) against this container's ~10-minute foreground ceiling, no verdict printed. CI runs it unconditionally

pnpm lint (repo-wide) is CI's run. The narrowing here is a measurement, declared: the population comes from eslint's own config, which reports scripts/bump-objectui.sh as "File ignored because no matching configuration was supplied" (no files: glob covers .sh), leaving one linted file; --format json counts 2 entries, 1 linted, 0 errors, 0 warnings; and eslint.config.mjs enables no type-aware linting for ANY file (its own note at the QUERY_OPTIONS_TEST_GLOBS block, with a measured positive control), so this diff cannot move the verdict on a file it does not touch.

Also run: node scripts/check-nul-bytes.mjs — OK over 7841 text files — plus a direct control-byte scan of both edited files, no hits.

Changeset

skip-changeset: this diff is repo tooling under scripts/ and publishes nothing from any package — no package's files carries it, and nothing here reaches a published tarball. Same disposition as the recent scripts-only devx PRs (#14255, #14217), both landed carrying that label.

Branch base is d62f990a9; main moved 4 commits while this was in flight (ed9e6996f), none touching a workflow or a gate that declares scripts/**, so the derived family list stands. The PR's CI runs on the merge ref.

Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV

Generated by Claude Code


Generated by Claude Code

… range
The objectui pin bump derives the @objectstack/console changeset -- its list
AND its bump level -- from the changesets objectui declared over OLD..NEW.
When the OLD endpoint's commit object was absent (what `git clone --depth N`
produces: the boundary sits after the old pin), the digest's endpoint guard
returned before `findRangeTruncation` ran, so the deepen the script advertises
was never considered, and the bump fell back to a degraded entry carrying the
DEFAULT level.
Measured on a throwaway objectui, same range and command before and after
`git fetch --unshallow`: `patch` for a range that declared `minor`, the
declared-breaking entry invisible, the ADR-0087 disposition prompt never fired
(it keys on a declared-breaking changeset), exit 0.
- objectui-changeset-digest.mjs: `findAbsentEndpoints` /
`describeAbsentEndpoints` report an absent endpoint as PREREQUISITE NOT MET,
naming which endpoint, whether the clone is shallow, and the remedy. Asserted
in `classifyRange` too, so `objectui-range.mjs` cannot derive from it either.
- bump-objectui.sh: exit 2 (endpoint absent) now takes the same deepen-and-
re-ask path as exit 3 (history stops inside the range); the RE-CHECK decides,
never the fetch's status. A range still unwalkable after that REFUSES --
non-zero, no changeset, and asked above the pin write so `.objectui-sha` is
byte-identical (the #10797 invariant). The degraded artifact for an
unwalkable range is gone; the initial pin keeps its degraded entry.
- self-test: the #9408 shell cases now pin the refusal, a new #14178 group
reproduces the shallow clone end to end (deepen, re-ask, derive the same
record as a full clone), and the surviving initial-pin degradation gains the
coverage the removed paths had. 130 checks, all green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/lskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bump-objectui.sh never deepens when the OLD pin object is absent, so a shallow checkout emits a patch changeset for a minor range

2 participants

@baozhoutao@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(devx): deepen on an absent objectui pin endpoint, and refuse an unwalkable range - #14391

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-14178-changeset-digest-shallow-checkout
Sep 2, 2026
Merged

fix(devx): deepen on an absent objectui pin endpoint, and refuse an unwalkable range#14391
baozhoutao merged 1 commit into
mainfrom
claude/issue-14178-changeset-digest-shallow-checkout

Conversation

@claude

@claudeclaudeBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes#14178

The objectui pin bump derives the @objectstack/console changeset — its list and its bump level — from the changesets objectui declared over OLD..NEW. When the OLD endpoint's commit object was absent (what git clone --depth N produces: the shallow boundary sits after the old pin), the digest's endpoint guard returned before findRangeTruncation ran, so the deepen the script advertises was never considered, and the bump fell back to a degraded entry carrying the DEFAULT level.

Implements the triage ruling on the card: candidate 1 + 2 together — deepen on an absent endpoint and re-ask, and refuse when the re-ask still fails.

Measured, before and after

A throwaway objectui: 5 commits, 4 releasing changesets (2 patch, 2 minor, one of the minor ones carrying an author breaking annotation), cloned --depth 2 so the from object is absent. Same range, same command, one file:// remote so the run stays offline.

rundeepen attemptedexitbump levellistADR-0087 prompt
before — shallow, deepen allowedno0patch1-line degraded (tip subject)never fired
before — unshallowed by handn/a0minor4 releasing, 1 breakingfired
after — shallow, deepen allowedyes, then re-asked0minor4 releasing, 1 breakingfired
after — shallow, OBJECTUI_NO_DEEPEN=1opted out1noneno changeset written, pin untouchedn/a

The degraded entry did label itself degraded, so nothing lied — but the level was a default nobody declared, it publishes into @objectstack/console's CHANGELOG and the curated release notes, every declared-breaking entry was invisible in it, and the ADR-0087 disposition prompt never fired because the degraded changeset declares nothing breaking. That reproduction is now a self-test case (S6), asserted equal to the record the same range yields in a full clone.

The guard reorder

scripts/objectui-changeset-digest.mjs

  • findAbsentEndpoints() / describeAbsentEndpoints() — the other half of the walkability precondition, shaped like findRangeTruncation / describeTruncation on purpose: the two are one class of failure with two causes, and a caller that treats them alike must be able to read them alike. It names WHICH endpoint is missing, whether the clone is shallow, re-emits git's own captured diagnostic, and prints the remedy.
  • The endpoint guard's catch is replaced by that call, reporting PREREQUISITE NOT MET and keeping exit 2. The exit-code contract is unchanged in its codes and sharpened in its meaning: 2 (endpoint absent) and 3 (history stops inside the range) both mean "repair the input and ask again", and neither authorizes a weaker derivation.
  • The same assertion is made inside classifyRange, the single shared implementation, so objectui-range.mjs cannot derive from an absent endpoint either — and it is asked BEFORE the truncation test, because rev-list from..to cannot run without from (pinned as S1).

The refusal shape

scripts/bump-objectui.sh

  • Exit 2 now takes the same deepen-and-re-ask path as exit 3. The re-check decides, never the fetch's status — the C17 lesson, unchanged and still pinned.
  • A range still unwalkable after that refuses: non-zero, no changeset written, the cause named (absent endpoint / stops inside the range / the probe never returned a verdict), what was tried named (opted out, not shallow, fetch failed, fetch exited 0 without repairing), and two remedies plus --no-changeset for moving the pin while claiming nothing about the range.
  • The whole question is asked above the pin write, so a refusal leaves .objectui-sha byte-identical — the bump-objectui.sh leaves a half-applied bump when the objectui commit object is absent: .objectui-sha is rewritten, then the run dies on git log #10797 invariant, now owed by a second refusal and pinned as C15 and S7.
  • The degraded artifact for an unwalkable range is removed, not reshaped: the ruling asked for one code path fewer, not a fourth state. The initial pin keeps its degraded entry (no previous SHA, no range, no remedy to name) and gains the self-test coverage the removed paths had.

Self-test

pnpm check:objectui-changeset — 130 checks, all green (was 122). The #9408 shell cases C13/C14/C15/C17 now pin the refusal instead of the degraded artifact; C16 and C18 are unchanged; a new #14178 group (S1–S8) covers the absent-endpoint branch end to end.

Ablation, on the committed tree: restoring the pre-fix deepen trigger in bump-objectui.sh (only exit 3 deepened) turns S6, S6b, S7 and S8 red and the rest green. The mutation was confirmed on disk by anchor grep counts in both directions (deleted text 1 to 0, injected text 0 to 1) plus a blob-hash comparison against the HEAD blob; the restore was confirmed by git hash-object equal to the HEAD blob and an empty git diff HEAD. No rebuild leg applies: both scripts are executed from source, and the self-test copies their bytes into throwaway framework roots.

Gates

Derived in the worktree with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (16 families: 14 by path, 2 by change kind), reconciled with --ran against a record built from --commands, at 8084a7bdd:

✓ dispatch-gates --ran: 16 derived famil(ies) accounted for — 14 run, 2 NOT-MEASURED.
gateverdict
check:objectui-changesetRAN-PASS (130 + objectui-range checks)
check:objectui-bump (this file's own self-test, run beyond the derived set)RAN-PASS (13 assertions, 4 cases)
check:agent-test-spelling · check:bash32-floor · check:cli-command-ids · check:cross-package-test-inputs · check:entry-guard · check:parse-guard · check:pnpm-filter-targets · check:ratchet-remedy-authority · check:watch-hint-literalRAN-PASS
check:declared-population-live (dispatch-mandated for every scripts/** card)RAN-PASS
scripts/check-ci-filter-parity.mjs · scripts/check-cross-package-test-inputs.mjs · scripts/check-shard-attestation.mjs · scripts/pm/bare-root-worklist.mjs --self-testRAN-PASS
scripts/check-test-completeness.mjsNOT MEASURED — exit 3, PREREQUISITE NOT MET: it grades a saved turbo run test log and none was named. Its own text prescribes recording NOT MEASURED when reached from the derived family list; CI tees the log and passes the path
check:pm-dispatch-gatesNOT MEASURED — SIGTERM-killed at 600s (exit 143) against this container's ~10-minute foreground ceiling, no verdict printed. CI runs it unconditionally

pnpm lint (repo-wide) is CI's run. The narrowing here is a measurement, declared: the population comes from eslint's own config, which reports scripts/bump-objectui.sh as "File ignored because no matching configuration was supplied" (no files: glob covers .sh), leaving one linted file; --format json counts 2 entries, 1 linted, 0 errors, 0 warnings; and eslint.config.mjs enables no type-aware linting for ANY file (its own note at the QUERY_OPTIONS_TEST_GLOBS block, with a measured positive control), so this diff cannot move the verdict on a file it does not touch.

Also run: node scripts/check-nul-bytes.mjs — OK over 7841 text files — plus a direct control-byte scan of both edited files, no hits.

Changeset

skip-changeset: this diff is repo tooling under scripts/ and publishes nothing from any package — no package's files carries it, and nothing here reaches a published tarball. Same disposition as the recent scripts-only devx PRs (#14255, #14217), both landed carrying that label.

Branch base is d62f990a9; main moved 4 commits while this was in flight (ed9e6996f), none touching a workflow or a gate that declares scripts/**, so the derived family list stands. The PR's CI runs on the merge ref.

Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV

Generated by Claude Code


Generated by Claude Code

… range
The objectui pin bump derives the @objectstack/console changeset -- its list
AND its bump level -- from the changesets objectui declared over OLD..NEW.
When the OLD endpoint's commit object was absent (what `git clone --depth N`
produces: the boundary sits after the old pin), the digest's endpoint guard
returned before `findRangeTruncation` ran, so the deepen the script advertises
was never considered, and the bump fell back to a degraded entry carrying the
DEFAULT level.
Measured on a throwaway objectui, same range and command before and after
`git fetch --unshallow`: `patch` for a range that declared `minor`, the
declared-breaking entry invisible, the ADR-0087 disposition prompt never fired
(it keys on a declared-breaking changeset), exit 0.
- objectui-changeset-digest.mjs: `findAbsentEndpoints` /
`describeAbsentEndpoints` report an absent endpoint as PREREQUISITE NOT MET,
naming which endpoint, whether the clone is shallow, and the remedy. Asserted
in `classifyRange` too, so `objectui-range.mjs` cannot derive from it either.
- bump-objectui.sh: exit 2 (endpoint absent) now takes the same deepen-and-
re-ask path as exit 3 (history stops inside the range); the RE-CHECK decides,
never the fetch's status. A range still unwalkable after that REFUSES --
non-zero, no changeset, and asked above the pin write so `.objectui-sha` is
byte-identical (the #10797 invariant). The degraded artifact for an
unwalkable range is gone; the initial pin keeps its degraded entry.
- self-test: the #9408 shell cases now pin the refusal, a new #14178 group
reproduces the shallow clone end to end (deepen, re-ask, derive the same
record as a full clone), and the surviving initial-pin degradation gains the
coverage the removed paths had. 130 checks, all green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/lskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bump-objectui.sh never deepens when the OLD pin object is absent, so a shallow checkout emits a patch changeset for a minor range

2 participants

@baozhoutao@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(devx): deepen on an absent objectui pin endpoint, and refuse an unwalkable range - #14391

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-14178-changeset-digest-shallow-checkout
Sep 2, 2026
Merged

fix(devx): deepen on an absent objectui pin endpoint, and refuse an unwalkable range#14391
baozhoutao merged 1 commit into
mainfrom
claude/issue-14178-changeset-digest-shallow-checkout

Conversation

@claude

@claudeclaudeBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes#14178

The objectui pin bump derives the @objectstack/console changeset — its list and its bump level — from the changesets objectui declared over OLD..NEW. When the OLD endpoint's commit object was absent (what git clone --depth N produces: the shallow boundary sits after the old pin), the digest's endpoint guard returned before findRangeTruncation ran, so the deepen the script advertises was never considered, and the bump fell back to a degraded entry carrying the DEFAULT level.

Implements the triage ruling on the card: candidate 1 + 2 together — deepen on an absent endpoint and re-ask, and refuse when the re-ask still fails.

Measured, before and after

A throwaway objectui: 5 commits, 4 releasing changesets (2 patch, 2 minor, one of the minor ones carrying an author breaking annotation), cloned --depth 2 so the from object is absent. Same range, same command, one file:// remote so the run stays offline.

rundeepen attemptedexitbump levellistADR-0087 prompt
before — shallow, deepen allowedno0patch1-line degraded (tip subject)never fired
before — unshallowed by handn/a0minor4 releasing, 1 breakingfired
after — shallow, deepen allowedyes, then re-asked0minor4 releasing, 1 breakingfired
after — shallow, OBJECTUI_NO_DEEPEN=1opted out1noneno changeset written, pin untouchedn/a

The degraded entry did label itself degraded, so nothing lied — but the level was a default nobody declared, it publishes into @objectstack/console's CHANGELOG and the curated release notes, every declared-breaking entry was invisible in it, and the ADR-0087 disposition prompt never fired because the degraded changeset declares nothing breaking. That reproduction is now a self-test case (S6), asserted equal to the record the same range yields in a full clone.

The guard reorder

scripts/objectui-changeset-digest.mjs

  • findAbsentEndpoints() / describeAbsentEndpoints() — the other half of the walkability precondition, shaped like findRangeTruncation / describeTruncation on purpose: the two are one class of failure with two causes, and a caller that treats them alike must be able to read them alike. It names WHICH endpoint is missing, whether the clone is shallow, re-emits git's own captured diagnostic, and prints the remedy.
  • The endpoint guard's catch is replaced by that call, reporting PREREQUISITE NOT MET and keeping exit 2. The exit-code contract is unchanged in its codes and sharpened in its meaning: 2 (endpoint absent) and 3 (history stops inside the range) both mean "repair the input and ask again", and neither authorizes a weaker derivation.
  • The same assertion is made inside classifyRange, the single shared implementation, so objectui-range.mjs cannot derive from an absent endpoint either — and it is asked BEFORE the truncation test, because rev-list from..to cannot run without from (pinned as S1).

The refusal shape

scripts/bump-objectui.sh

  • Exit 2 now takes the same deepen-and-re-ask path as exit 3. The re-check decides, never the fetch's status — the C17 lesson, unchanged and still pinned.
  • A range still unwalkable after that refuses: non-zero, no changeset written, the cause named (absent endpoint / stops inside the range / the probe never returned a verdict), what was tried named (opted out, not shallow, fetch failed, fetch exited 0 without repairing), and two remedies plus --no-changeset for moving the pin while claiming nothing about the range.
  • The whole question is asked above the pin write, so a refusal leaves .objectui-sha byte-identical — the bump-objectui.sh leaves a half-applied bump when the objectui commit object is absent: .objectui-sha is rewritten, then the run dies on git log #10797 invariant, now owed by a second refusal and pinned as C15 and S7.
  • The degraded artifact for an unwalkable range is removed, not reshaped: the ruling asked for one code path fewer, not a fourth state. The initial pin keeps its degraded entry (no previous SHA, no range, no remedy to name) and gains the self-test coverage the removed paths had.

Self-test

pnpm check:objectui-changeset — 130 checks, all green (was 122). The #9408 shell cases C13/C14/C15/C17 now pin the refusal instead of the degraded artifact; C16 and C18 are unchanged; a new #14178 group (S1–S8) covers the absent-endpoint branch end to end.

Ablation, on the committed tree: restoring the pre-fix deepen trigger in bump-objectui.sh (only exit 3 deepened) turns S6, S6b, S7 and S8 red and the rest green. The mutation was confirmed on disk by anchor grep counts in both directions (deleted text 1 to 0, injected text 0 to 1) plus a blob-hash comparison against the HEAD blob; the restore was confirmed by git hash-object equal to the HEAD blob and an empty git diff HEAD. No rebuild leg applies: both scripts are executed from source, and the self-test copies their bytes into throwaway framework roots.

Gates

Derived in the worktree with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (16 families: 14 by path, 2 by change kind), reconciled with --ran against a record built from --commands, at 8084a7bdd:

✓ dispatch-gates --ran: 16 derived famil(ies) accounted for — 14 run, 2 NOT-MEASURED.
gateverdict
check:objectui-changesetRAN-PASS (130 + objectui-range checks)
check:objectui-bump (this file's own self-test, run beyond the derived set)RAN-PASS (13 assertions, 4 cases)
check:agent-test-spelling · check:bash32-floor · check:cli-command-ids · check:cross-package-test-inputs · check:entry-guard · check:parse-guard · check:pnpm-filter-targets · check:ratchet-remedy-authority · check:watch-hint-literalRAN-PASS
check:declared-population-live (dispatch-mandated for every scripts/** card)RAN-PASS
scripts/check-ci-filter-parity.mjs · scripts/check-cross-package-test-inputs.mjs · scripts/check-shard-attestation.mjs · scripts/pm/bare-root-worklist.mjs --self-testRAN-PASS
scripts/check-test-completeness.mjsNOT MEASURED — exit 3, PREREQUISITE NOT MET: it grades a saved turbo run test log and none was named. Its own text prescribes recording NOT MEASURED when reached from the derived family list; CI tees the log and passes the path
check:pm-dispatch-gatesNOT MEASURED — SIGTERM-killed at 600s (exit 143) against this container's ~10-minute foreground ceiling, no verdict printed. CI runs it unconditionally

pnpm lint (repo-wide) is CI's run. The narrowing here is a measurement, declared: the population comes from eslint's own config, which reports scripts/bump-objectui.sh as "File ignored because no matching configuration was supplied" (no files: glob covers .sh), leaving one linted file; --format json counts 2 entries, 1 linted, 0 errors, 0 warnings; and eslint.config.mjs enables no type-aware linting for ANY file (its own note at the QUERY_OPTIONS_TEST_GLOBS block, with a measured positive control), so this diff cannot move the verdict on a file it does not touch.

Also run: node scripts/check-nul-bytes.mjs — OK over 7841 text files — plus a direct control-byte scan of both edited files, no hits.

Changeset

skip-changeset: this diff is repo tooling under scripts/ and publishes nothing from any package — no package's files carries it, and nothing here reaches a published tarball. Same disposition as the recent scripts-only devx PRs (#14255, #14217), both landed carrying that label.

Branch base is d62f990a9; main moved 4 commits while this was in flight (ed9e6996f), none touching a workflow or a gate that declares scripts/**, so the derived family list stands. The PR's CI runs on the merge ref.

Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV

Generated by Claude Code


Generated by Claude Code

… range
The objectui pin bump derives the @objectstack/console changeset -- its list
AND its bump level -- from the changesets objectui declared over OLD..NEW.
When the OLD endpoint's commit object was absent (what `git clone --depth N`
produces: the boundary sits after the old pin), the digest's endpoint guard
returned before `findRangeTruncation` ran, so the deepen the script advertises
was never considered, and the bump fell back to a degraded entry carrying the
DEFAULT level.
Measured on a throwaway objectui, same range and command before and after
`git fetch --unshallow`: `patch` for a range that declared `minor`, the
declared-breaking entry invisible, the ADR-0087 disposition prompt never fired
(it keys on a declared-breaking changeset), exit 0.
- objectui-changeset-digest.mjs: `findAbsentEndpoints` /
`describeAbsentEndpoints` report an absent endpoint as PREREQUISITE NOT MET,
naming which endpoint, whether the clone is shallow, and the remedy. Asserted
in `classifyRange` too, so `objectui-range.mjs` cannot derive from it either.
- bump-objectui.sh: exit 2 (endpoint absent) now takes the same deepen-and-
re-ask path as exit 3 (history stops inside the range); the RE-CHECK decides,
never the fetch's status. A range still unwalkable after that REFUSES --
non-zero, no changeset, and asked above the pin write so `.objectui-sha` is
byte-identical (the #10797 invariant). The degraded artifact for an
unwalkable range is gone; the initial pin keeps its degraded entry.
- self-test: the #9408 shell cases now pin the refusal, a new #14178 group
reproduces the shallow clone end to end (deepen, re-ask, derive the same
record as a full clone), and the surviving initial-pin degradation gains the
coverage the removed paths had. 130 checks, all green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/lskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bump-objectui.sh never deepens when the OLD pin object is absent, so a shallow checkout emits a patch changeset for a minor range

2 participants

@baozhoutao@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(devx): deepen on an absent objectui pin endpoint, and refuse an unwalkable range - #14391

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-14178-changeset-digest-shallow-checkout
Sep 2, 2026
Merged

fix(devx): deepen on an absent objectui pin endpoint, and refuse an unwalkable range#14391
baozhoutao merged 1 commit into
mainfrom
claude/issue-14178-changeset-digest-shallow-checkout

Conversation

@claude

@claudeclaudeBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes#14178

The objectui pin bump derives the @objectstack/console changeset — its list and its bump level — from the changesets objectui declared over OLD..NEW. When the OLD endpoint's commit object was absent (what git clone --depth N produces: the shallow boundary sits after the old pin), the digest's endpoint guard returned before findRangeTruncation ran, so the deepen the script advertises was never considered, and the bump fell back to a degraded entry carrying the DEFAULT level.

Implements the triage ruling on the card: candidate 1 + 2 together — deepen on an absent endpoint and re-ask, and refuse when the re-ask still fails.

Measured, before and after

A throwaway objectui: 5 commits, 4 releasing changesets (2 patch, 2 minor, one of the minor ones carrying an author breaking annotation), cloned --depth 2 so the from object is absent. Same range, same command, one file:// remote so the run stays offline.

rundeepen attemptedexitbump levellistADR-0087 prompt
before — shallow, deepen allowedno0patch1-line degraded (tip subject)never fired
before — unshallowed by handn/a0minor4 releasing, 1 breakingfired
after — shallow, deepen allowedyes, then re-asked0minor4 releasing, 1 breakingfired
after — shallow, OBJECTUI_NO_DEEPEN=1opted out1noneno changeset written, pin untouchedn/a

The degraded entry did label itself degraded, so nothing lied — but the level was a default nobody declared, it publishes into @objectstack/console's CHANGELOG and the curated release notes, every declared-breaking entry was invisible in it, and the ADR-0087 disposition prompt never fired because the degraded changeset declares nothing breaking. That reproduction is now a self-test case (S6), asserted equal to the record the same range yields in a full clone.

The guard reorder

scripts/objectui-changeset-digest.mjs

  • findAbsentEndpoints() / describeAbsentEndpoints() — the other half of the walkability precondition, shaped like findRangeTruncation / describeTruncation on purpose: the two are one class of failure with two causes, and a caller that treats them alike must be able to read them alike. It names WHICH endpoint is missing, whether the clone is shallow, re-emits git's own captured diagnostic, and prints the remedy.
  • The endpoint guard's catch is replaced by that call, reporting PREREQUISITE NOT MET and keeping exit 2. The exit-code contract is unchanged in its codes and sharpened in its meaning: 2 (endpoint absent) and 3 (history stops inside the range) both mean "repair the input and ask again", and neither authorizes a weaker derivation.
  • The same assertion is made inside classifyRange, the single shared implementation, so objectui-range.mjs cannot derive from an absent endpoint either — and it is asked BEFORE the truncation test, because rev-list from..to cannot run without from (pinned as S1).

The refusal shape

scripts/bump-objectui.sh

  • Exit 2 now takes the same deepen-and-re-ask path as exit 3. The re-check decides, never the fetch's status — the C17 lesson, unchanged and still pinned.
  • A range still unwalkable after that refuses: non-zero, no changeset written, the cause named (absent endpoint / stops inside the range / the probe never returned a verdict), what was tried named (opted out, not shallow, fetch failed, fetch exited 0 without repairing), and two remedies plus --no-changeset for moving the pin while claiming nothing about the range.
  • The whole question is asked above the pin write, so a refusal leaves .objectui-sha byte-identical — the bump-objectui.sh leaves a half-applied bump when the objectui commit object is absent: .objectui-sha is rewritten, then the run dies on git log #10797 invariant, now owed by a second refusal and pinned as C15 and S7.
  • The degraded artifact for an unwalkable range is removed, not reshaped: the ruling asked for one code path fewer, not a fourth state. The initial pin keeps its degraded entry (no previous SHA, no range, no remedy to name) and gains the self-test coverage the removed paths had.

Self-test

pnpm check:objectui-changeset — 130 checks, all green (was 122). The #9408 shell cases C13/C14/C15/C17 now pin the refusal instead of the degraded artifact; C16 and C18 are unchanged; a new #14178 group (S1–S8) covers the absent-endpoint branch end to end.

Ablation, on the committed tree: restoring the pre-fix deepen trigger in bump-objectui.sh (only exit 3 deepened) turns S6, S6b, S7 and S8 red and the rest green. The mutation was confirmed on disk by anchor grep counts in both directions (deleted text 1 to 0, injected text 0 to 1) plus a blob-hash comparison against the HEAD blob; the restore was confirmed by git hash-object equal to the HEAD blob and an empty git diff HEAD. No rebuild leg applies: both scripts are executed from source, and the self-test copies their bytes into throwaway framework roots.

Gates

Derived in the worktree with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (16 families: 14 by path, 2 by change kind), reconciled with --ran against a record built from --commands, at 8084a7bdd:

✓ dispatch-gates --ran: 16 derived famil(ies) accounted for — 14 run, 2 NOT-MEASURED.
gateverdict
check:objectui-changesetRAN-PASS (130 + objectui-range checks)
check:objectui-bump (this file's own self-test, run beyond the derived set)RAN-PASS (13 assertions, 4 cases)
check:agent-test-spelling · check:bash32-floor · check:cli-command-ids · check:cross-package-test-inputs · check:entry-guard · check:parse-guard · check:pnpm-filter-targets · check:ratchet-remedy-authority · check:watch-hint-literalRAN-PASS
check:declared-population-live (dispatch-mandated for every scripts/** card)RAN-PASS
scripts/check-ci-filter-parity.mjs · scripts/check-cross-package-test-inputs.mjs · scripts/check-shard-attestation.mjs · scripts/pm/bare-root-worklist.mjs --self-testRAN-PASS
scripts/check-test-completeness.mjsNOT MEASURED — exit 3, PREREQUISITE NOT MET: it grades a saved turbo run test log and none was named. Its own text prescribes recording NOT MEASURED when reached from the derived family list; CI tees the log and passes the path
check:pm-dispatch-gatesNOT MEASURED — SIGTERM-killed at 600s (exit 143) against this container's ~10-minute foreground ceiling, no verdict printed. CI runs it unconditionally

pnpm lint (repo-wide) is CI's run. The narrowing here is a measurement, declared: the population comes from eslint's own config, which reports scripts/bump-objectui.sh as "File ignored because no matching configuration was supplied" (no files: glob covers .sh), leaving one linted file; --format json counts 2 entries, 1 linted, 0 errors, 0 warnings; and eslint.config.mjs enables no type-aware linting for ANY file (its own note at the QUERY_OPTIONS_TEST_GLOBS block, with a measured positive control), so this diff cannot move the verdict on a file it does not touch.

Also run: node scripts/check-nul-bytes.mjs — OK over 7841 text files — plus a direct control-byte scan of both edited files, no hits.

Changeset

skip-changeset: this diff is repo tooling under scripts/ and publishes nothing from any package — no package's files carries it, and nothing here reaches a published tarball. Same disposition as the recent scripts-only devx PRs (#14255, #14217), both landed carrying that label.

Branch base is d62f990a9; main moved 4 commits while this was in flight (ed9e6996f), none touching a workflow or a gate that declares scripts/**, so the derived family list stands. The PR's CI runs on the merge ref.

Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV

Generated by Claude Code


Generated by Claude Code

… range
The objectui pin bump derives the @objectstack/console changeset -- its list
AND its bump level -- from the changesets objectui declared over OLD..NEW.
When the OLD endpoint's commit object was absent (what `git clone --depth N`
produces: the boundary sits after the old pin), the digest's endpoint guard
returned before `findRangeTruncation` ran, so the deepen the script advertises
was never considered, and the bump fell back to a degraded entry carrying the
DEFAULT level.
Measured on a throwaway objectui, same range and command before and after
`git fetch --unshallow`: `patch` for a range that declared `minor`, the
declared-breaking entry invisible, the ADR-0087 disposition prompt never fired
(it keys on a declared-breaking changeset), exit 0.
- objectui-changeset-digest.mjs: `findAbsentEndpoints` /
`describeAbsentEndpoints` report an absent endpoint as PREREQUISITE NOT MET,
naming which endpoint, whether the clone is shallow, and the remedy. Asserted
in `classifyRange` too, so `objectui-range.mjs` cannot derive from it either.
- bump-objectui.sh: exit 2 (endpoint absent) now takes the same deepen-and-
re-ask path as exit 3 (history stops inside the range); the RE-CHECK decides,
never the fetch's status. A range still unwalkable after that REFUSES --
non-zero, no changeset, and asked above the pin write so `.objectui-sha` is
byte-identical (the #10797 invariant). The degraded artifact for an
unwalkable range is gone; the initial pin keeps its degraded entry.
- self-test: the #9408 shell cases now pin the refusal, a new #14178 group
reproduces the shallow clone end to end (deepen, re-ask, derive the same
record as a full clone), and the surviving initial-pin degradation gains the
coverage the removed paths had. 130 checks, all green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/lskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bump-objectui.sh never deepens when the OLD pin object is absent, so a shallow checkout emits a patch changeset for a minor range

2 participants

@baozhoutao@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(devx): deepen on an absent objectui pin endpoint, and refuse an unwalkable range - #14391

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-14178-changeset-digest-shallow-checkout
Sep 2, 2026
Merged

fix(devx): deepen on an absent objectui pin endpoint, and refuse an unwalkable range#14391
baozhoutao merged 1 commit into
mainfrom
claude/issue-14178-changeset-digest-shallow-checkout

Conversation

@claude

@claudeclaudeBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes#14178

The objectui pin bump derives the @objectstack/console changeset — its list and its bump level — from the changesets objectui declared over OLD..NEW. When the OLD endpoint's commit object was absent (what git clone --depth N produces: the shallow boundary sits after the old pin), the digest's endpoint guard returned before findRangeTruncation ran, so the deepen the script advertises was never considered, and the bump fell back to a degraded entry carrying the DEFAULT level.

Implements the triage ruling on the card: candidate 1 + 2 together — deepen on an absent endpoint and re-ask, and refuse when the re-ask still fails.

Measured, before and after

A throwaway objectui: 5 commits, 4 releasing changesets (2 patch, 2 minor, one of the minor ones carrying an author breaking annotation), cloned --depth 2 so the from object is absent. Same range, same command, one file:// remote so the run stays offline.

rundeepen attemptedexitbump levellistADR-0087 prompt
before — shallow, deepen allowedno0patch1-line degraded (tip subject)never fired
before — unshallowed by handn/a0minor4 releasing, 1 breakingfired
after — shallow, deepen allowedyes, then re-asked0minor4 releasing, 1 breakingfired
after — shallow, OBJECTUI_NO_DEEPEN=1opted out1noneno changeset written, pin untouchedn/a

The degraded entry did label itself degraded, so nothing lied — but the level was a default nobody declared, it publishes into @objectstack/console's CHANGELOG and the curated release notes, every declared-breaking entry was invisible in it, and the ADR-0087 disposition prompt never fired because the degraded changeset declares nothing breaking. That reproduction is now a self-test case (S6), asserted equal to the record the same range yields in a full clone.

The guard reorder

scripts/objectui-changeset-digest.mjs

  • findAbsentEndpoints() / describeAbsentEndpoints() — the other half of the walkability precondition, shaped like findRangeTruncation / describeTruncation on purpose: the two are one class of failure with two causes, and a caller that treats them alike must be able to read them alike. It names WHICH endpoint is missing, whether the clone is shallow, re-emits git's own captured diagnostic, and prints the remedy.
  • The endpoint guard's catch is replaced by that call, reporting PREREQUISITE NOT MET and keeping exit 2. The exit-code contract is unchanged in its codes and sharpened in its meaning: 2 (endpoint absent) and 3 (history stops inside the range) both mean "repair the input and ask again", and neither authorizes a weaker derivation.
  • The same assertion is made inside classifyRange, the single shared implementation, so objectui-range.mjs cannot derive from an absent endpoint either — and it is asked BEFORE the truncation test, because rev-list from..to cannot run without from (pinned as S1).

The refusal shape

scripts/bump-objectui.sh

  • Exit 2 now takes the same deepen-and-re-ask path as exit 3. The re-check decides, never the fetch's status — the C17 lesson, unchanged and still pinned.
  • A range still unwalkable after that refuses: non-zero, no changeset written, the cause named (absent endpoint / stops inside the range / the probe never returned a verdict), what was tried named (opted out, not shallow, fetch failed, fetch exited 0 without repairing), and two remedies plus --no-changeset for moving the pin while claiming nothing about the range.
  • The whole question is asked above the pin write, so a refusal leaves .objectui-sha byte-identical — the bump-objectui.sh leaves a half-applied bump when the objectui commit object is absent: .objectui-sha is rewritten, then the run dies on git log #10797 invariant, now owed by a second refusal and pinned as C15 and S7.
  • The degraded artifact for an unwalkable range is removed, not reshaped: the ruling asked for one code path fewer, not a fourth state. The initial pin keeps its degraded entry (no previous SHA, no range, no remedy to name) and gains the self-test coverage the removed paths had.

Self-test

pnpm check:objectui-changeset — 130 checks, all green (was 122). The #9408 shell cases C13/C14/C15/C17 now pin the refusal instead of the degraded artifact; C16 and C18 are unchanged; a new #14178 group (S1–S8) covers the absent-endpoint branch end to end.

Ablation, on the committed tree: restoring the pre-fix deepen trigger in bump-objectui.sh (only exit 3 deepened) turns S6, S6b, S7 and S8 red and the rest green. The mutation was confirmed on disk by anchor grep counts in both directions (deleted text 1 to 0, injected text 0 to 1) plus a blob-hash comparison against the HEAD blob; the restore was confirmed by git hash-object equal to the HEAD blob and an empty git diff HEAD. No rebuild leg applies: both scripts are executed from source, and the self-test copies their bytes into throwaway framework roots.

Gates

Derived in the worktree with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (16 families: 14 by path, 2 by change kind), reconciled with --ran against a record built from --commands, at 8084a7bdd:

✓ dispatch-gates --ran: 16 derived famil(ies) accounted for — 14 run, 2 NOT-MEASURED.
gateverdict
check:objectui-changesetRAN-PASS (130 + objectui-range checks)
check:objectui-bump (this file's own self-test, run beyond the derived set)RAN-PASS (13 assertions, 4 cases)
check:agent-test-spelling · check:bash32-floor · check:cli-command-ids · check:cross-package-test-inputs · check:entry-guard · check:parse-guard · check:pnpm-filter-targets · check:ratchet-remedy-authority · check:watch-hint-literalRAN-PASS
check:declared-population-live (dispatch-mandated for every scripts/** card)RAN-PASS
scripts/check-ci-filter-parity.mjs · scripts/check-cross-package-test-inputs.mjs · scripts/check-shard-attestation.mjs · scripts/pm/bare-root-worklist.mjs --self-testRAN-PASS
scripts/check-test-completeness.mjsNOT MEASURED — exit 3, PREREQUISITE NOT MET: it grades a saved turbo run test log and none was named. Its own text prescribes recording NOT MEASURED when reached from the derived family list; CI tees the log and passes the path
check:pm-dispatch-gatesNOT MEASURED — SIGTERM-killed at 600s (exit 143) against this container's ~10-minute foreground ceiling, no verdict printed. CI runs it unconditionally

pnpm lint (repo-wide) is CI's run. The narrowing here is a measurement, declared: the population comes from eslint's own config, which reports scripts/bump-objectui.sh as "File ignored because no matching configuration was supplied" (no files: glob covers .sh), leaving one linted file; --format json counts 2 entries, 1 linted, 0 errors, 0 warnings; and eslint.config.mjs enables no type-aware linting for ANY file (its own note at the QUERY_OPTIONS_TEST_GLOBS block, with a measured positive control), so this diff cannot move the verdict on a file it does not touch.

Also run: node scripts/check-nul-bytes.mjs — OK over 7841 text files — plus a direct control-byte scan of both edited files, no hits.

Changeset

skip-changeset: this diff is repo tooling under scripts/ and publishes nothing from any package — no package's files carries it, and nothing here reaches a published tarball. Same disposition as the recent scripts-only devx PRs (#14255, #14217), both landed carrying that label.

Branch base is d62f990a9; main moved 4 commits while this was in flight (ed9e6996f), none touching a workflow or a gate that declares scripts/**, so the derived family list stands. The PR's CI runs on the merge ref.

Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV

Generated by Claude Code


Generated by Claude Code

… range
The objectui pin bump derives the @objectstack/console changeset -- its list
AND its bump level -- from the changesets objectui declared over OLD..NEW.
When the OLD endpoint's commit object was absent (what `git clone --depth N`
produces: the boundary sits after the old pin), the digest's endpoint guard
returned before `findRangeTruncation` ran, so the deepen the script advertises
was never considered, and the bump fell back to a degraded entry carrying the
DEFAULT level.
Measured on a throwaway objectui, same range and command before and after
`git fetch --unshallow`: `patch` for a range that declared `minor`, the
declared-breaking entry invisible, the ADR-0087 disposition prompt never fired
(it keys on a declared-breaking changeset), exit 0.
- objectui-changeset-digest.mjs: `findAbsentEndpoints` /
`describeAbsentEndpoints` report an absent endpoint as PREREQUISITE NOT MET,
naming which endpoint, whether the clone is shallow, and the remedy. Asserted
in `classifyRange` too, so `objectui-range.mjs` cannot derive from it either.
- bump-objectui.sh: exit 2 (endpoint absent) now takes the same deepen-and-
re-ask path as exit 3 (history stops inside the range); the RE-CHECK decides,
never the fetch's status. A range still unwalkable after that REFUSES --
non-zero, no changeset, and asked above the pin write so `.objectui-sha` is
byte-identical (the #10797 invariant). The degraded artifact for an
unwalkable range is gone; the initial pin keeps its degraded entry.
- self-test: the #9408 shell cases now pin the refusal, a new #14178 group
reproduces the shallow clone end to end (deepen, re-ask, derive the same
record as a full clone), and the surviving initial-pin degradation gains the
coverage the removed paths had. 130 checks, all green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/lskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bump-objectui.sh never deepens when the OLD pin object is absent, so a shallow checkout emits a patch changeset for a minor range

2 participants

@baozhoutao@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(devx): deepen on an absent objectui pin endpoint, and refuse an unwalkable range - #14391

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-14178-changeset-digest-shallow-checkout
Sep 2, 2026
Merged

fix(devx): deepen on an absent objectui pin endpoint, and refuse an unwalkable range#14391
baozhoutao merged 1 commit into
mainfrom
claude/issue-14178-changeset-digest-shallow-checkout

Conversation

@claude

@claudeclaudeBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes#14178

The objectui pin bump derives the @objectstack/console changeset — its list and its bump level — from the changesets objectui declared over OLD..NEW. When the OLD endpoint's commit object was absent (what git clone --depth N produces: the shallow boundary sits after the old pin), the digest's endpoint guard returned before findRangeTruncation ran, so the deepen the script advertises was never considered, and the bump fell back to a degraded entry carrying the DEFAULT level.

Implements the triage ruling on the card: candidate 1 + 2 together — deepen on an absent endpoint and re-ask, and refuse when the re-ask still fails.

Measured, before and after

A throwaway objectui: 5 commits, 4 releasing changesets (2 patch, 2 minor, one of the minor ones carrying an author breaking annotation), cloned --depth 2 so the from object is absent. Same range, same command, one file:// remote so the run stays offline.

rundeepen attemptedexitbump levellistADR-0087 prompt
before — shallow, deepen allowedno0patch1-line degraded (tip subject)never fired
before — unshallowed by handn/a0minor4 releasing, 1 breakingfired
after — shallow, deepen allowedyes, then re-asked0minor4 releasing, 1 breakingfired
after — shallow, OBJECTUI_NO_DEEPEN=1opted out1noneno changeset written, pin untouchedn/a

The degraded entry did label itself degraded, so nothing lied — but the level was a default nobody declared, it publishes into @objectstack/console's CHANGELOG and the curated release notes, every declared-breaking entry was invisible in it, and the ADR-0087 disposition prompt never fired because the degraded changeset declares nothing breaking. That reproduction is now a self-test case (S6), asserted equal to the record the same range yields in a full clone.

The guard reorder

scripts/objectui-changeset-digest.mjs

  • findAbsentEndpoints() / describeAbsentEndpoints() — the other half of the walkability precondition, shaped like findRangeTruncation / describeTruncation on purpose: the two are one class of failure with two causes, and a caller that treats them alike must be able to read them alike. It names WHICH endpoint is missing, whether the clone is shallow, re-emits git's own captured diagnostic, and prints the remedy.
  • The endpoint guard's catch is replaced by that call, reporting PREREQUISITE NOT MET and keeping exit 2. The exit-code contract is unchanged in its codes and sharpened in its meaning: 2 (endpoint absent) and 3 (history stops inside the range) both mean "repair the input and ask again", and neither authorizes a weaker derivation.
  • The same assertion is made inside classifyRange, the single shared implementation, so objectui-range.mjs cannot derive from an absent endpoint either — and it is asked BEFORE the truncation test, because rev-list from..to cannot run without from (pinned as S1).

The refusal shape

scripts/bump-objectui.sh

  • Exit 2 now takes the same deepen-and-re-ask path as exit 3. The re-check decides, never the fetch's status — the C17 lesson, unchanged and still pinned.
  • A range still unwalkable after that refuses: non-zero, no changeset written, the cause named (absent endpoint / stops inside the range / the probe never returned a verdict), what was tried named (opted out, not shallow, fetch failed, fetch exited 0 without repairing), and two remedies plus --no-changeset for moving the pin while claiming nothing about the range.
  • The whole question is asked above the pin write, so a refusal leaves .objectui-sha byte-identical — the bump-objectui.sh leaves a half-applied bump when the objectui commit object is absent: .objectui-sha is rewritten, then the run dies on git log #10797 invariant, now owed by a second refusal and pinned as C15 and S7.
  • The degraded artifact for an unwalkable range is removed, not reshaped: the ruling asked for one code path fewer, not a fourth state. The initial pin keeps its degraded entry (no previous SHA, no range, no remedy to name) and gains the self-test coverage the removed paths had.

Self-test

pnpm check:objectui-changeset — 130 checks, all green (was 122). The #9408 shell cases C13/C14/C15/C17 now pin the refusal instead of the degraded artifact; C16 and C18 are unchanged; a new #14178 group (S1–S8) covers the absent-endpoint branch end to end.

Ablation, on the committed tree: restoring the pre-fix deepen trigger in bump-objectui.sh (only exit 3 deepened) turns S6, S6b, S7 and S8 red and the rest green. The mutation was confirmed on disk by anchor grep counts in both directions (deleted text 1 to 0, injected text 0 to 1) plus a blob-hash comparison against the HEAD blob; the restore was confirmed by git hash-object equal to the HEAD blob and an empty git diff HEAD. No rebuild leg applies: both scripts are executed from source, and the self-test copies their bytes into throwaway framework roots.

Gates

Derived in the worktree with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (16 families: 14 by path, 2 by change kind), reconciled with --ran against a record built from --commands, at 8084a7bdd:

✓ dispatch-gates --ran: 16 derived famil(ies) accounted for — 14 run, 2 NOT-MEASURED.
gateverdict
check:objectui-changesetRAN-PASS (130 + objectui-range checks)
check:objectui-bump (this file's own self-test, run beyond the derived set)RAN-PASS (13 assertions, 4 cases)
check:agent-test-spelling · check:bash32-floor · check:cli-command-ids · check:cross-package-test-inputs · check:entry-guard · check:parse-guard · check:pnpm-filter-targets · check:ratchet-remedy-authority · check:watch-hint-literalRAN-PASS
check:declared-population-live (dispatch-mandated for every scripts/** card)RAN-PASS
scripts/check-ci-filter-parity.mjs · scripts/check-cross-package-test-inputs.mjs · scripts/check-shard-attestation.mjs · scripts/pm/bare-root-worklist.mjs --self-testRAN-PASS
scripts/check-test-completeness.mjsNOT MEASURED — exit 3, PREREQUISITE NOT MET: it grades a saved turbo run test log and none was named. Its own text prescribes recording NOT MEASURED when reached from the derived family list; CI tees the log and passes the path
check:pm-dispatch-gatesNOT MEASURED — SIGTERM-killed at 600s (exit 143) against this container's ~10-minute foreground ceiling, no verdict printed. CI runs it unconditionally

pnpm lint (repo-wide) is CI's run. The narrowing here is a measurement, declared: the population comes from eslint's own config, which reports scripts/bump-objectui.sh as "File ignored because no matching configuration was supplied" (no files: glob covers .sh), leaving one linted file; --format json counts 2 entries, 1 linted, 0 errors, 0 warnings; and eslint.config.mjs enables no type-aware linting for ANY file (its own note at the QUERY_OPTIONS_TEST_GLOBS block, with a measured positive control), so this diff cannot move the verdict on a file it does not touch.

Also run: node scripts/check-nul-bytes.mjs — OK over 7841 text files — plus a direct control-byte scan of both edited files, no hits.

Changeset

skip-changeset: this diff is repo tooling under scripts/ and publishes nothing from any package — no package's files carries it, and nothing here reaches a published tarball. Same disposition as the recent scripts-only devx PRs (#14255, #14217), both landed carrying that label.

Branch base is d62f990a9; main moved 4 commits while this was in flight (ed9e6996f), none touching a workflow or a gate that declares scripts/**, so the derived family list stands. The PR's CI runs on the merge ref.

Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV

Generated by Claude Code


Generated by Claude Code

… range
The objectui pin bump derives the @objectstack/console changeset -- its list
AND its bump level -- from the changesets objectui declared over OLD..NEW.
When the OLD endpoint's commit object was absent (what `git clone --depth N`
produces: the boundary sits after the old pin), the digest's endpoint guard
returned before `findRangeTruncation` ran, so the deepen the script advertises
was never considered, and the bump fell back to a degraded entry carrying the
DEFAULT level.
Measured on a throwaway objectui, same range and command before and after
`git fetch --unshallow`: `patch` for a range that declared `minor`, the
declared-breaking entry invisible, the ADR-0087 disposition prompt never fired
(it keys on a declared-breaking changeset), exit 0.
- objectui-changeset-digest.mjs: `findAbsentEndpoints` /
`describeAbsentEndpoints` report an absent endpoint as PREREQUISITE NOT MET,
naming which endpoint, whether the clone is shallow, and the remedy. Asserted
in `classifyRange` too, so `objectui-range.mjs` cannot derive from it either.
- bump-objectui.sh: exit 2 (endpoint absent) now takes the same deepen-and-
re-ask path as exit 3 (history stops inside the range); the RE-CHECK decides,
never the fetch's status. A range still unwalkable after that REFUSES --
non-zero, no changeset, and asked above the pin write so `.objectui-sha` is
byte-identical (the #10797 invariant). The degraded artifact for an
unwalkable range is gone; the initial pin keeps its degraded entry.
- self-test: the #9408 shell cases now pin the refusal, a new #14178 group
reproduces the shallow clone end to end (deepen, re-ask, derive the same
record as a full clone), and the surviving initial-pin degradation gains the
coverage the removed paths had. 130 checks, all green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/lskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bump-objectui.sh never deepens when the OLD pin object is absent, so a shallow checkout emits a patch changeset for a minor range

2 participants

@baozhoutao@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(devx): deepen on an absent objectui pin endpoint, and refuse an unwalkable range - #14391

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-14178-changeset-digest-shallow-checkout
Sep 2, 2026
Merged

fix(devx): deepen on an absent objectui pin endpoint, and refuse an unwalkable range#14391
baozhoutao merged 1 commit into
mainfrom
claude/issue-14178-changeset-digest-shallow-checkout

Conversation

@claude

@claudeclaudeBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes#14178

The objectui pin bump derives the @objectstack/console changeset — its list and its bump level — from the changesets objectui declared over OLD..NEW. When the OLD endpoint's commit object was absent (what git clone --depth N produces: the shallow boundary sits after the old pin), the digest's endpoint guard returned before findRangeTruncation ran, so the deepen the script advertises was never considered, and the bump fell back to a degraded entry carrying the DEFAULT level.

Implements the triage ruling on the card: candidate 1 + 2 together — deepen on an absent endpoint and re-ask, and refuse when the re-ask still fails.

Measured, before and after

A throwaway objectui: 5 commits, 4 releasing changesets (2 patch, 2 minor, one of the minor ones carrying an author breaking annotation), cloned --depth 2 so the from object is absent. Same range, same command, one file:// remote so the run stays offline.

rundeepen attemptedexitbump levellistADR-0087 prompt
before — shallow, deepen allowedno0patch1-line degraded (tip subject)never fired
before — unshallowed by handn/a0minor4 releasing, 1 breakingfired
after — shallow, deepen allowedyes, then re-asked0minor4 releasing, 1 breakingfired
after — shallow, OBJECTUI_NO_DEEPEN=1opted out1noneno changeset written, pin untouchedn/a

The degraded entry did label itself degraded, so nothing lied — but the level was a default nobody declared, it publishes into @objectstack/console's CHANGELOG and the curated release notes, every declared-breaking entry was invisible in it, and the ADR-0087 disposition prompt never fired because the degraded changeset declares nothing breaking. That reproduction is now a self-test case (S6), asserted equal to the record the same range yields in a full clone.

The guard reorder

scripts/objectui-changeset-digest.mjs

  • findAbsentEndpoints() / describeAbsentEndpoints() — the other half of the walkability precondition, shaped like findRangeTruncation / describeTruncation on purpose: the two are one class of failure with two causes, and a caller that treats them alike must be able to read them alike. It names WHICH endpoint is missing, whether the clone is shallow, re-emits git's own captured diagnostic, and prints the remedy.
  • The endpoint guard's catch is replaced by that call, reporting PREREQUISITE NOT MET and keeping exit 2. The exit-code contract is unchanged in its codes and sharpened in its meaning: 2 (endpoint absent) and 3 (history stops inside the range) both mean "repair the input and ask again", and neither authorizes a weaker derivation.
  • The same assertion is made inside classifyRange, the single shared implementation, so objectui-range.mjs cannot derive from an absent endpoint either — and it is asked BEFORE the truncation test, because rev-list from..to cannot run without from (pinned as S1).

The refusal shape

scripts/bump-objectui.sh

  • Exit 2 now takes the same deepen-and-re-ask path as exit 3. The re-check decides, never the fetch's status — the C17 lesson, unchanged and still pinned.
  • A range still unwalkable after that refuses: non-zero, no changeset written, the cause named (absent endpoint / stops inside the range / the probe never returned a verdict), what was tried named (opted out, not shallow, fetch failed, fetch exited 0 without repairing), and two remedies plus --no-changeset for moving the pin while claiming nothing about the range.
  • The whole question is asked above the pin write, so a refusal leaves .objectui-sha byte-identical — the bump-objectui.sh leaves a half-applied bump when the objectui commit object is absent: .objectui-sha is rewritten, then the run dies on git log #10797 invariant, now owed by a second refusal and pinned as C15 and S7.
  • The degraded artifact for an unwalkable range is removed, not reshaped: the ruling asked for one code path fewer, not a fourth state. The initial pin keeps its degraded entry (no previous SHA, no range, no remedy to name) and gains the self-test coverage the removed paths had.

Self-test

pnpm check:objectui-changeset — 130 checks, all green (was 122). The #9408 shell cases C13/C14/C15/C17 now pin the refusal instead of the degraded artifact; C16 and C18 are unchanged; a new #14178 group (S1–S8) covers the absent-endpoint branch end to end.

Ablation, on the committed tree: restoring the pre-fix deepen trigger in bump-objectui.sh (only exit 3 deepened) turns S6, S6b, S7 and S8 red and the rest green. The mutation was confirmed on disk by anchor grep counts in both directions (deleted text 1 to 0, injected text 0 to 1) plus a blob-hash comparison against the HEAD blob; the restore was confirmed by git hash-object equal to the HEAD blob and an empty git diff HEAD. No rebuild leg applies: both scripts are executed from source, and the self-test copies their bytes into throwaway framework roots.

Gates

Derived in the worktree with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (16 families: 14 by path, 2 by change kind), reconciled with --ran against a record built from --commands, at 8084a7bdd:

✓ dispatch-gates --ran: 16 derived famil(ies) accounted for — 14 run, 2 NOT-MEASURED.
gateverdict
check:objectui-changesetRAN-PASS (130 + objectui-range checks)
check:objectui-bump (this file's own self-test, run beyond the derived set)RAN-PASS (13 assertions, 4 cases)
check:agent-test-spelling · check:bash32-floor · check:cli-command-ids · check:cross-package-test-inputs · check:entry-guard · check:parse-guard · check:pnpm-filter-targets · check:ratchet-remedy-authority · check:watch-hint-literalRAN-PASS
check:declared-population-live (dispatch-mandated for every scripts/** card)RAN-PASS
scripts/check-ci-filter-parity.mjs · scripts/check-cross-package-test-inputs.mjs · scripts/check-shard-attestation.mjs · scripts/pm/bare-root-worklist.mjs --self-testRAN-PASS
scripts/check-test-completeness.mjsNOT MEASURED — exit 3, PREREQUISITE NOT MET: it grades a saved turbo run test log and none was named. Its own text prescribes recording NOT MEASURED when reached from the derived family list; CI tees the log and passes the path
check:pm-dispatch-gatesNOT MEASURED — SIGTERM-killed at 600s (exit 143) against this container's ~10-minute foreground ceiling, no verdict printed. CI runs it unconditionally

pnpm lint (repo-wide) is CI's run. The narrowing here is a measurement, declared: the population comes from eslint's own config, which reports scripts/bump-objectui.sh as "File ignored because no matching configuration was supplied" (no files: glob covers .sh), leaving one linted file; --format json counts 2 entries, 1 linted, 0 errors, 0 warnings; and eslint.config.mjs enables no type-aware linting for ANY file (its own note at the QUERY_OPTIONS_TEST_GLOBS block, with a measured positive control), so this diff cannot move the verdict on a file it does not touch.

Also run: node scripts/check-nul-bytes.mjs — OK over 7841 text files — plus a direct control-byte scan of both edited files, no hits.

Changeset

skip-changeset: this diff is repo tooling under scripts/ and publishes nothing from any package — no package's files carries it, and nothing here reaches a published tarball. Same disposition as the recent scripts-only devx PRs (#14255, #14217), both landed carrying that label.

Branch base is d62f990a9; main moved 4 commits while this was in flight (ed9e6996f), none touching a workflow or a gate that declares scripts/**, so the derived family list stands. The PR's CI runs on the merge ref.

Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV

Generated by Claude Code


Generated by Claude Code

… range
The objectui pin bump derives the @objectstack/console changeset -- its list
AND its bump level -- from the changesets objectui declared over OLD..NEW.
When the OLD endpoint's commit object was absent (what `git clone --depth N`
produces: the boundary sits after the old pin), the digest's endpoint guard
returned before `findRangeTruncation` ran, so the deepen the script advertises
was never considered, and the bump fell back to a degraded entry carrying the
DEFAULT level.
Measured on a throwaway objectui, same range and command before and after
`git fetch --unshallow`: `patch` for a range that declared `minor`, the
declared-breaking entry invisible, the ADR-0087 disposition prompt never fired
(it keys on a declared-breaking changeset), exit 0.
- objectui-changeset-digest.mjs: `findAbsentEndpoints` /
`describeAbsentEndpoints` report an absent endpoint as PREREQUISITE NOT MET,
naming which endpoint, whether the clone is shallow, and the remedy. Asserted
in `classifyRange` too, so `objectui-range.mjs` cannot derive from it either.
- bump-objectui.sh: exit 2 (endpoint absent) now takes the same deepen-and-
re-ask path as exit 3 (history stops inside the range); the RE-CHECK decides,
never the fetch's status. A range still unwalkable after that REFUSES --
non-zero, no changeset, and asked above the pin write so `.objectui-sha` is
byte-identical (the #10797 invariant). The degraded artifact for an
unwalkable range is gone; the initial pin keeps its degraded entry.
- self-test: the #9408 shell cases now pin the refusal, a new #14178 group
reproduces the shallow clone end to end (deepen, re-ask, derive the same
record as a full clone), and the surviving initial-pin degradation gains the
coverage the removed paths had. 130 checks, all green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/lskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bump-objectui.sh never deepens when the OLD pin object is absent, so a shallow checkout emits a patch changeset for a minor range

2 participants

@baozhoutao@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(devx): deepen on an absent objectui pin endpoint, and refuse an unwalkable range - #14391

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-14178-changeset-digest-shallow-checkout
Sep 2, 2026
Merged

fix(devx): deepen on an absent objectui pin endpoint, and refuse an unwalkable range#14391
baozhoutao merged 1 commit into
mainfrom
claude/issue-14178-changeset-digest-shallow-checkout

Conversation

@claude

@claudeclaudeBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes#14178

The objectui pin bump derives the @objectstack/console changeset — its list and its bump level — from the changesets objectui declared over OLD..NEW. When the OLD endpoint's commit object was absent (what git clone --depth N produces: the shallow boundary sits after the old pin), the digest's endpoint guard returned before findRangeTruncation ran, so the deepen the script advertises was never considered, and the bump fell back to a degraded entry carrying the DEFAULT level.

Implements the triage ruling on the card: candidate 1 + 2 together — deepen on an absent endpoint and re-ask, and refuse when the re-ask still fails.

Measured, before and after

A throwaway objectui: 5 commits, 4 releasing changesets (2 patch, 2 minor, one of the minor ones carrying an author breaking annotation), cloned --depth 2 so the from object is absent. Same range, same command, one file:// remote so the run stays offline.

rundeepen attemptedexitbump levellistADR-0087 prompt
before — shallow, deepen allowedno0patch1-line degraded (tip subject)never fired
before — unshallowed by handn/a0minor4 releasing, 1 breakingfired
after — shallow, deepen allowedyes, then re-asked0minor4 releasing, 1 breakingfired
after — shallow, OBJECTUI_NO_DEEPEN=1opted out1noneno changeset written, pin untouchedn/a

The degraded entry did label itself degraded, so nothing lied — but the level was a default nobody declared, it publishes into @objectstack/console's CHANGELOG and the curated release notes, every declared-breaking entry was invisible in it, and the ADR-0087 disposition prompt never fired because the degraded changeset declares nothing breaking. That reproduction is now a self-test case (S6), asserted equal to the record the same range yields in a full clone.

The guard reorder

scripts/objectui-changeset-digest.mjs

  • findAbsentEndpoints() / describeAbsentEndpoints() — the other half of the walkability precondition, shaped like findRangeTruncation / describeTruncation on purpose: the two are one class of failure with two causes, and a caller that treats them alike must be able to read them alike. It names WHICH endpoint is missing, whether the clone is shallow, re-emits git's own captured diagnostic, and prints the remedy.
  • The endpoint guard's catch is replaced by that call, reporting PREREQUISITE NOT MET and keeping exit 2. The exit-code contract is unchanged in its codes and sharpened in its meaning: 2 (endpoint absent) and 3 (history stops inside the range) both mean "repair the input and ask again", and neither authorizes a weaker derivation.
  • The same assertion is made inside classifyRange, the single shared implementation, so objectui-range.mjs cannot derive from an absent endpoint either — and it is asked BEFORE the truncation test, because rev-list from..to cannot run without from (pinned as S1).

The refusal shape

scripts/bump-objectui.sh

  • Exit 2 now takes the same deepen-and-re-ask path as exit 3. The re-check decides, never the fetch's status — the C17 lesson, unchanged and still pinned.
  • A range still unwalkable after that refuses: non-zero, no changeset written, the cause named (absent endpoint / stops inside the range / the probe never returned a verdict), what was tried named (opted out, not shallow, fetch failed, fetch exited 0 without repairing), and two remedies plus --no-changeset for moving the pin while claiming nothing about the range.
  • The whole question is asked above the pin write, so a refusal leaves .objectui-sha byte-identical — the bump-objectui.sh leaves a half-applied bump when the objectui commit object is absent: .objectui-sha is rewritten, then the run dies on git log #10797 invariant, now owed by a second refusal and pinned as C15 and S7.
  • The degraded artifact for an unwalkable range is removed, not reshaped: the ruling asked for one code path fewer, not a fourth state. The initial pin keeps its degraded entry (no previous SHA, no range, no remedy to name) and gains the self-test coverage the removed paths had.

Self-test

pnpm check:objectui-changeset — 130 checks, all green (was 122). The #9408 shell cases C13/C14/C15/C17 now pin the refusal instead of the degraded artifact; C16 and C18 are unchanged; a new #14178 group (S1–S8) covers the absent-endpoint branch end to end.

Ablation, on the committed tree: restoring the pre-fix deepen trigger in bump-objectui.sh (only exit 3 deepened) turns S6, S6b, S7 and S8 red and the rest green. The mutation was confirmed on disk by anchor grep counts in both directions (deleted text 1 to 0, injected text 0 to 1) plus a blob-hash comparison against the HEAD blob; the restore was confirmed by git hash-object equal to the HEAD blob and an empty git diff HEAD. No rebuild leg applies: both scripts are executed from source, and the self-test copies their bytes into throwaway framework roots.

Gates

Derived in the worktree with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (16 families: 14 by path, 2 by change kind), reconciled with --ran against a record built from --commands, at 8084a7bdd:

✓ dispatch-gates --ran: 16 derived famil(ies) accounted for — 14 run, 2 NOT-MEASURED.
gateverdict
check:objectui-changesetRAN-PASS (130 + objectui-range checks)
check:objectui-bump (this file's own self-test, run beyond the derived set)RAN-PASS (13 assertions, 4 cases)
check:agent-test-spelling · check:bash32-floor · check:cli-command-ids · check:cross-package-test-inputs · check:entry-guard · check:parse-guard · check:pnpm-filter-targets · check:ratchet-remedy-authority · check:watch-hint-literalRAN-PASS
check:declared-population-live (dispatch-mandated for every scripts/** card)RAN-PASS
scripts/check-ci-filter-parity.mjs · scripts/check-cross-package-test-inputs.mjs · scripts/check-shard-attestation.mjs · scripts/pm/bare-root-worklist.mjs --self-testRAN-PASS
scripts/check-test-completeness.mjsNOT MEASURED — exit 3, PREREQUISITE NOT MET: it grades a saved turbo run test log and none was named. Its own text prescribes recording NOT MEASURED when reached from the derived family list; CI tees the log and passes the path
check:pm-dispatch-gatesNOT MEASURED — SIGTERM-killed at 600s (exit 143) against this container's ~10-minute foreground ceiling, no verdict printed. CI runs it unconditionally

pnpm lint (repo-wide) is CI's run. The narrowing here is a measurement, declared: the population comes from eslint's own config, which reports scripts/bump-objectui.sh as "File ignored because no matching configuration was supplied" (no files: glob covers .sh), leaving one linted file; --format json counts 2 entries, 1 linted, 0 errors, 0 warnings; and eslint.config.mjs enables no type-aware linting for ANY file (its own note at the QUERY_OPTIONS_TEST_GLOBS block, with a measured positive control), so this diff cannot move the verdict on a file it does not touch.

Also run: node scripts/check-nul-bytes.mjs — OK over 7841 text files — plus a direct control-byte scan of both edited files, no hits.

Changeset

skip-changeset: this diff is repo tooling under scripts/ and publishes nothing from any package — no package's files carries it, and nothing here reaches a published tarball. Same disposition as the recent scripts-only devx PRs (#14255, #14217), both landed carrying that label.

Branch base is d62f990a9; main moved 4 commits while this was in flight (ed9e6996f), none touching a workflow or a gate that declares scripts/**, so the derived family list stands. The PR's CI runs on the merge ref.

Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV

Generated by Claude Code


Generated by Claude Code

… range
The objectui pin bump derives the @objectstack/console changeset -- its list
AND its bump level -- from the changesets objectui declared over OLD..NEW.
When the OLD endpoint's commit object was absent (what `git clone --depth N`
produces: the boundary sits after the old pin), the digest's endpoint guard
returned before `findRangeTruncation` ran, so the deepen the script advertises
was never considered, and the bump fell back to a degraded entry carrying the
DEFAULT level.
Measured on a throwaway objectui, same range and command before and after
`git fetch --unshallow`: `patch` for a range that declared `minor`, the
declared-breaking entry invisible, the ADR-0087 disposition prompt never fired
(it keys on a declared-breaking changeset), exit 0.
- objectui-changeset-digest.mjs: `findAbsentEndpoints` /
`describeAbsentEndpoints` report an absent endpoint as PREREQUISITE NOT MET,
naming which endpoint, whether the clone is shallow, and the remedy. Asserted
in `classifyRange` too, so `objectui-range.mjs` cannot derive from it either.
- bump-objectui.sh: exit 2 (endpoint absent) now takes the same deepen-and-
re-ask path as exit 3 (history stops inside the range); the RE-CHECK decides,
never the fetch's status. A range still unwalkable after that REFUSES --
non-zero, no changeset, and asked above the pin write so `.objectui-sha` is
byte-identical (the #10797 invariant). The degraded artifact for an
unwalkable range is gone; the initial pin keeps its degraded entry.
- self-test: the #9408 shell cases now pin the refusal, a new #14178 group
reproduces the shallow clone end to end (deepen, re-ask, derive the same
record as a full clone), and the surviving initial-pin degradation gains the
coverage the removed paths had. 130 checks, all green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/lskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bump-objectui.sh never deepens when the OLD pin object is absent, so a shallow checkout emits a patch changeset for a minor range

2 participants

@baozhoutao@claude