Found while bumping the console pin (#14027 / PR #14165), on the first of two bump runs. Sibling of the closed #9408, but a different branch of the same guard.
What #9408 fixed, and the case that still degrades
#9408 taught the digest to detect a range that is walkable but truncated (findRangeTruncation, the parentless-inside-the-range test) and to DEEPEN rather than degrade. That works.
The case here is one step earlier. When the FROM endpoint's commit object is absent outright, the endpoint guard in objectui-changeset-digest.mjs returns first:
try{git(objectuiRoot,['cat-file','-e',`${from}^{commit}`]);git(objectuiRoot,['cat-file','-e',`${to}^{commit}`]);}catch{console.error(`cannot walk ${from}..${to} in ${objectuiRoot}`);return2;// <- deepen is never considered}findRangeTruncation is below that return, so the documented default deepen (git fetch --unshallow, the one the script header advertises and OBJECTUI_NO_DEEPEN=1 opts out of) is never reached. A deepen is exactly what would have repaired it.
Measured, on this container
The dispatch container's ../objectui is a 50-commit shallow clone, so the old pin object is absent. Same range, same command, before and after git fetch --unshallow:
| releasing changesets | breaking | bump level | list |
|---|
| shallow (degraded path) | not derived | not derived | patch | tip commit only, 1 line |
| unshallowed | 218 | 15 | minor | full, 143 lines |
The degraded entry does label itself degraded, so nothing lies. But the bump level it emits is wrong — patch where the range declares minor — and 15 declared-breaking entries are invisible in it. Both feed @objectstack/console's CHANGELOG and the curated release notes. It also silently skips the ADR-0087 disposition prompt, because that fires on a declared-breaking changeset and the degraded one declares none.
An operator who does not happen to know the checkout is shallow has no cue: the run exits 0, writes a changeset and commits it.
Options
- Try the deepen in the absent-endpoint branch too, then re-ask — the same shape as the truncated branch, whose re-check (not the fetch status) already decides the outcome per the C17 self-test case.
- Leave the deepen alone but make the degraded path REFUSE when the bump level could not be derived from declarations, rather than emitting
patch as a default. - Leave as is and document that a shallow objectui checkout must be deepened before a pin bump.
Option 1 mirrors the existing branch and needs no new policy; option 2 is worth pairing with it, since patch as a fallback is a guess that reads like a declaration.
Generated by Claude Code
Found while bumping the console pin (#14027 / PR #14165), on the first of two bump runs. Sibling of the closed #9408, but a different branch of the same guard.
What #9408 fixed, and the case that still degrades
#9408 taught the digest to detect a range that is walkable but truncated (
findRangeTruncation, the parentless-inside-the-range test) and to DEEPEN rather than degrade. That works.The case here is one step earlier. When the FROM endpoint's commit object is absent outright, the endpoint guard in
objectui-changeset-digest.mjsreturns first:findRangeTruncationis below that return, so the documented default deepen (git fetch --unshallow, the one the script header advertises andOBJECTUI_NO_DEEPEN=1opts out of) is never reached. A deepen is exactly what would have repaired it.Measured, on this container
The dispatch container's
../objectuiis a 50-commit shallow clone, so the old pin object is absent. Same range, same command, before and aftergit fetch --unshallow:The degraded entry does label itself degraded, so nothing lies. But the bump level it emits is wrong —
patchwhere the range declaresminor— and 15 declared-breaking entries are invisible in it. Both feed@objectstack/console's CHANGELOG and the curated release notes. It also silently skips the ADR-0087 disposition prompt, because that fires on a declared-breaking changeset and the degraded one declares none.An operator who does not happen to know the checkout is shallow has no cue: the run exits 0, writes a changeset and commits it.
Options
patchas a default.Option 1 mirrors the existing branch and needs no new policy; option 2 is worth pairing with it, since
patchas a fallback is a guess that reads like a declaration.Generated by Claude Code