Skip to content

Commit c6dfadd

Browse files
committed
fix(devx): objectui pin changeset comes from declared changesets, not commit types (#4731)
The @objectstack/console changeset written on an objectui pin bump used to guess which frontend commits belonged in the platform release record from conventional-commit types on the subject line, and guess the bump level the same way. On the real range 7d9734d5e321..785b8a5d432c (53 non-merge commits) the guess dropped all 13 releasing non-feat/fix commits — every breaking `refactor(...)!` among them — pulled in 5 commits that release nothing, and truncated at `head -40` in silence. objectui already declares the answer: every releasing PR carries a `.changeset/*.md`, an empty frontmatter block is changesets' own release-nothing marker, and the declared level is the bump. The new `scripts/objectui-changeset-digest.mjs` reads those declarations over the range; `bump-objectui.sh` writes what it produces. Nothing is capped by default, a cap that fires names the real remainder, omissions are counted in the body, and an unwalkable range emits a list labelled degraded. Guarded by `pnpm check:objectui-changeset` in Lint & Type Check.
1 parent c4ab50b commit c6dfadd

5 files changed

Lines changed: 710 additions & 31 deletions

File tree

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
---
3+
4+
Tooling-only (#4731): the `@objectstack/console` changeset that `scripts/bump-objectui.sh`
5+
writes on an objectui pin bump is now derived from what objectui **declared** — the
6+
`.changeset/*.md` files added over the pinned range — instead of guessed from
7+
conventional-commit types on the subject line. Releases nothing; no package changes.
8+
9+
The guess had three measured failure modes on one real range (`7d9734d5e321..785b8a5d432c`,
10+
53 non-merge commits): `grep -iE '^- (feat|fix)'` dropped **all 13** releasing commits that
11+
were not `feat`/`fix` — every breaking `refactor(...)!` among them, including
12+
`refactor(layout)!: delete PageNodeRenderer` and the burn-ledger batches (objectui#3220 /
13+
objectui#3224) — while pulling in **5** commits that release nothing at all (two of them
14+
`fix(ci)`); `head -40` truncated the list in silence at 34/40 used; and the bump level came
15+
from `grep -ciE '^feat'`, so a range of nothing but breaking refactors stamped `patch`.
16+
17+
`scripts/objectui-changeset-digest.mjs` now answers the question the script actually needs
18+
answered — *does this commit ship in the frontend release?* — from objectui's own
19+
declaration: a `.changeset/*.md` with package names releases, an empty frontmatter block is
20+
changesets' own "release-nothing", and the declared `major`/`minor`/`patch` **is** the bump
21+
(no `^feat` inference left anywhere). Nothing is capped by default; a cap that does fire
22+
names the real remainder, the release-nothing changesets and changeset-less commits are
23+
counted in the body rather than dropped in silence, and an unwalkable range (shallow clone,
24+
initial pin) emits a list explicitly labelled degraded. Guarded by
25+
`pnpm check:objectui-changeset` (`--self-test`, wired into `Lint & Type Check`).

.github/workflows/lint.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,20 @@ jobs:
204204
- name: Durability-degradation log-level guard
205205
run: pnpm check:durability-log-level
206206

207+
# objectui pin-changeset guard (#4731). A frontend-only refresh reaches the
208+
# platform release record ONLY through the changeset `bump-objectui.sh`
209+
# writes, and that list used to be guessed off objectui's commit subjects
210+
# (`feat|fix` + a silent `head -40`). On one real range the guess dropped
211+
# all 13 releasing non-feat/fix commits — every breaking `refactor(...)!`
212+
# among them — and pulled in 5 that release nothing. The list and the bump
213+
# level now come from what objectui DECLARED (`.changeset/*.md` added over
214+
# the range; empty frontmatter = release-nothing). This self-test builds
215+
# throwaway git repos carrying those exact shapes, runs the real scripts
216+
# over them, and asserts the emitted changeset — including that a cap which
217+
# fires announces itself and that an unwalkable range degrades loudly.
218+
- name: objectui pin-changeset digest guard
219+
run: pnpm check:objectui-changeset
220+
207221
# Release-notes drift guard: the platform is one version-locked train, so
208222
# every released @objectstack/spec major must have a curated, navigable
209223
# release page at content/docs/releases/v<major>.mdx. Catches the gap that

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"check:init-service-contract": "node scripts/check-init-service-contract.mjs --self-test && node scripts/check-init-service-contract.mjs",
4747
"check:durability-log-level": "node scripts/check-durability-degradation-log-level.mjs --self-test && node scripts/check-durability-degradation-log-level.mjs",
4848
"check:console-sha": "node scripts/check-console-sha.mjs",
49+
"check:objectui-changeset": "node scripts/objectui-changeset-digest.mjs --self-test",
4950
"check:release-notes": "node scripts/check-release-notes.mjs",
5051
"check:node-version": "node scripts/check-node-version.mjs",
5152
"check:published-files": "node scripts/check-published-files.mjs --self-test && node scripts/check-published-files.mjs",

scripts/bump-objectui.sh

Lines changed: 54 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@
88
# scripts/bump-objectui.sh --no-changeset # skip the @objectstack/console changeset
99
#
1010
# Env:
11-
# CONSOLE_BUMP=minor|patch # force the changeset bump type (default: auto —
12-
# # `minor` if the objectui range has any feat, else patch)
11+
# CONSOLE_BUMP=major|minor|patch # force the changeset bump type (default: auto —
12+
# # the HIGHEST level objectui itself declared in the
13+
# # changesets added over the range; see #4731)
14+
# CONSOLE_CHANGES_MAX=<n> # cap the rendered list (default 100). A cap that
15+
# # fires says so, with the real count — never silently.
1316
#
1417
# Assumes sibling layout:
1518
# ~/work/objectui
@@ -27,6 +30,18 @@
2730
# the objectui commit range, routing the frontend delta through the SAME
2831
# changesets pipeline as the backend: it lands in @objectstack/console's
2932
# CHANGELOG and rolls up into the platform version + the curated release notes.
33+
#
34+
# WHAT GOES IN THE LIST — DECLARED, NOT GUESSED (#4731)
35+
# The list used to be a GUESS off the commit subject (`grep -iE '^- (feat|fix)'`
36+
# + `head -40`), and the bump level another (`grep -ciE '^feat'`). Both were
37+
# measured wrong on one real range: every `refactor(...)!` — the BREAKING class,
38+
# the one that must never vanish from a release record — was structurally unable
39+
# to appear, `head -40` truncated in silence, and `fix(ci)` commits that release
40+
# nothing were pulled in. objectui already DECLARES which commits ship: every
41+
# releasing PR carries a `.changeset/*.md`, and an empty frontmatter block is
42+
# changesets' own "release-nothing". So `objectui-changeset-digest.mjs` reads the
43+
# changesets added over the range — package names decide inclusion, the declared
44+
# level decides the bump. Nothing is inferred from a subject line.
3045

3146
set -euo pipefail
3247

@@ -41,7 +56,7 @@ for arg in "$@"; do
4156
--no-commit) NO_COMMIT=1 ;;
4257
--no-changeset) NO_CHANGESET=1 ;;
4358
-h|--help)
44-
sed -n '2,20p' "$0" | sed 's/^# \{0,1\}//'
59+
sed -n '2,19p' "$0" | sed 's/^# \{0,1\}//'
4560
exit 0
4661
;;
4762
*) EXPLICIT_SHA="$arg" ;;
@@ -85,52 +100,60 @@ SUBJECT_LINE="$(git -C "$OBJECTUI_ROOT" log -1 --format=%s "$NEW_SHA")"
85100
CS_FILE=""
86101
if [[ "$NO_CHANGESET" -eq 0 ]]; then
87102
# Can we walk the OLD..NEW range in the objectui checkout? (A shallow clone or
88-
# a first-ever pin may not have OLD reachable — degrade to the tip subject.)
103+
# a first-ever pin may not have OLD reachable — degrade to the tip subject,
104+
# and SAY SO in the artifact: a degraded list and a complete one must never
105+
# look alike, #4731.)
89106
RANGE_OK=0
90107
if [[ "$OLD_SHA" != "<none>" ]] && git -C "$OBJECTUI_ROOT" cat-file -e "${OLD_SHA}^{commit}" 2>/dev/null; then
91108
RANGE_OK=1
92109
fi
93110

94-
CHANGES=""
111+
CS_FILE="${FRAMEWORK_ROOT}/.changeset/console-${SHORT}.md"
112+
DIGEST_OK=0
113+
BUMP=""
95114
if [[ "$RANGE_OK" -eq 1 ]]; then
96-
CHANGES="$(git -C "$OBJECTUI_ROOT" log --no-merges --format='- %s' "${OLD_SHA}..${NEW_SHA}" \
97-
| grep -iE '^- (feat|fix)' | head -40 || true)"
98-
fi
99-
[[ -z "$CHANGES" ]] && CHANGES="- ${SUBJECT_LINE}"
100-
101-
BUMP="${CONSOLE_BUMP:-}"
102-
if [[ -z "$BUMP" ]]; then
103-
# NOTE: count, don't `grep -q`. Under `set -o pipefail`, `grep -q` exits on
104-
# the first match and the still-writing `git log` takes SIGPIPE, so the
105-
# pipeline returns 141 and this test ALWAYS took the else branch — every
106-
# refresh was silently stamped `patch`, feature ranges included. `grep -c`
107-
# drains its input, so no signal and a truthful count.
108-
FEAT_COUNT=0
109-
if [[ "$RANGE_OK" -eq 1 ]]; then
110-
FEAT_COUNT="$(git -C "$OBJECTUI_ROOT" log --format=%s "${OLD_SHA}..${NEW_SHA}" | grep -ciE '^feat' || true)"
111-
fi
112-
if [[ "$FEAT_COUNT" -gt 0 ]]; then
113-
BUMP=minor
114-
else
115-
BUMP=patch
115+
# The digest reads objectui's OWN declarations (.changeset/*.md added over
116+
# the range) — inclusion and level both come from there, nothing is guessed
117+
# off a commit subject. It writes the whole changeset file and echoes the
118+
# resolved bump level.
119+
if BUMP="$(node "${FRAMEWORK_ROOT}/scripts/objectui-changeset-digest.mjs" \
120+
--objectui-root "$OBJECTUI_ROOT" \
121+
--framework-root "$FRAMEWORK_ROOT" \
122+
--from "$OLD_SHA" --to "$NEW_SHA" \
123+
--max "${CONSOLE_CHANGES_MAX:-100}" \
124+
--bump-override "${CONSOLE_BUMP:-}" \
125+
--out "$CS_FILE")"; then
126+
DIGEST_OK=1
116127
fi
117128
fi
118129

119-
RANGE_LABEL="${OLD_SHA:0:12}...${NEW_SHA:0:12}"
120-
[[ "$OLD_SHA" == "<none>" ]] && RANGE_LABEL="(initial pin) → ${NEW_SHA:0:12}"
121-
122-
CS_FILE="${FRAMEWORK_ROOT}/.changeset/console-${SHORT}.md"
123-
cat > "$CS_FILE" <<EOF
130+
if [[ "$DIGEST_OK" -eq 0 ]]; then
131+
# Degraded path: no walkable range (initial pin, shallow clone, or the
132+
# digest could not run). Emit the tip subject ONLY, labelled as degraded —
133+
# the reader must be able to tell this list from a derived one.
134+
BUMP="${CONSOLE_BUMP:-patch}"
135+
RANGE_LABEL="${OLD_SHA:0:12}...${NEW_SHA:0:12}"
136+
WHY="the range \`${RANGE_LABEL}\` could not be walked in this objectui checkout"
137+
if [[ "$OLD_SHA" == "<none>" ]]; then
138+
RANGE_LABEL="(initial pin) → ${NEW_SHA:0:12}"
139+
WHY="this is the initial pin, so there is no previous SHA to walk from"
140+
fi
141+
cat > "$CS_FILE" <<EOF
124142
---
125143
"@objectstack/console": ${BUMP}
126144
---
127145
128146
Console (objectui) refreshed to \`${SHORT}\`. Frontend changes in this range:
129147
130-
${CHANGES}
148+
⚠️ **Degraded list** — ${WHY}, so this entry could not be derived from the
149+
changesets objectui declared. It names the tip commit only and is NOT a
150+
complete account of the range:
151+
152+
- ${SUBJECT_LINE}
131153
132154
objectui range: \`${RANGE_LABEL}\`
133155
EOF
156+
fi
134157
echo "→ wrote changeset $(basename "$CS_FILE") (@objectstack/console: ${BUMP})"
135158
fi
136159

0 commit comments

Comments
 (0)