Skip to content

Commit 5faa23c

Browse files
docs(sdui): declare the declaration-parity ratchet an on-demand gate triggered by the objectui pin bump (#5960) (#6421)
Maintainer ruling 2026-08-07, option D. `sdui.manifest.json` changes only when `.objectui-sha` moves, so the pin-update flow is the ratchet's trigger — and the measured answer was that nothing triggered it at all. Producing the manifest in this repo's CI (option A) is rejected; objectui publishing it as a release artefact (option B) is deferred. The procedure line now lives where a pin-bumping operator actually meets it: - scripts/bump-objectui.sh prints the `pnpm sdui:manifest` NEXT STEP on both successful exits (--no-commit moved the pin too). A reminder, not a hard gate: a machine without Playwright must still be able to move the pin. - scripts/build-console.sh's closing line names the trigger, not just the command — `pnpm objectui:refresh` runs bump-then-build, so that output is the last thing an operator sees. - docs/releases-maintenance.md gains "After the pin moves", and the pin-freshness "fix when it fires" step gains the run. - AGENTS.md's frontend section gains the step, and its `check:generated` note stops calling the manifest's provenance an open question. - scripts/objectui-changeset-digest.mjs --self-test (CI: check:objectui-changeset) pins the reminder, so the procedure line cannot be deleted in silence. Rider from the ruling: ADR-0082's Consumers row, TL;DR 4, decision 4, the chain diagram and one Consequences bullet all pointed at scripts/build-console.sh — #4472 moved the ratchet to scripts/gen-sdui-manifest.sh and the ADR was never updated, so a reader following it opened a file that deliberately dumps no manifest. Corrected in place plus a new addendum 2; docs/audits/2026-06-react-blocks-conformance.md carried the same stale pointer and is corrected with it. Releases nothing: scripts/, docs/ and AGENTS.md ship in no package. Fixes #5960 Claude-Session: https://claude.ai/code/session_01AZgRyPVwi1jLb1mNNuUQ9o Co-authored-by: Claude <noreply@anthropic.com>
1 parent 29e28a3 commit 5faa23c

7 files changed

Lines changed: 170 additions & 26 deletions

AGENTS.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ This repo ships **backend only**. All Studio/Console UI work happens in `../obje
9393

9494
Other scripts: `objectui:bump` (pull only), `objectui:build`, `objectui:clean`. ⚠️ Never hand-edit `packages/console/dist/` or `.cache/objectui-*/` — regenerated.
9595

96+
**Moving the pin has a second half: `pnpm sdui:manifest`.** ADR-0082 D4's spec↔registry declaration-parity ratchet reads objectui's `sdui.manifest.json`, which changes only when `.objectui-sha` moves — so the pin bump is the ratchet's trigger, and its only one. It is an **on-demand gate by decision** (#5960), never a CI job; `objectui:bump` and `objectui:refresh` both print the reminder. Needs Playwright chromium. Full procedure: `docs/releases-maintenance.md` → "After the pin moves".
97+
9698
**Fast iteration on `../objectui` src (no commit/refresh loop):** run objectui's own console dev server — `cd ../objectui && pnpm --filter @object-ui/console dev` (Vite on **:5180**, HMR). Its `/api` proxy targets `DEV_PROXY_TARGET || http://localhost:3000`, so **run the backend you're testing on :3000** (`PORT=3000 pnpm dev` for showcase) and browse `:5180`. Note `:3001/_console` (or whatever the backend serves) is the **published** console, not your `../objectui` src — only `:5180` reflects local UI edits. See `../objectui/AGENTS.md` for the app-id / localStorage / auth gotchas.
9799

98100
---
@@ -555,9 +557,16 @@ unavailable` and **exited 0**, so no path existed on which this gate could go re
555557
**exits 1** when it has no usable manifest, because "could not run" is a failure, not a
556558
skip (Route & surface ownership §3, *Absence must be loud*). Run it the one way that
557559
works: `pnpm sdui:manifest` (or `OBJECTUI_ROOT=../objectui pnpm objectui:build` first),
558-
which dumps the manifest and runs the ratchet against it. Where the manifest *should* come
559-
from in CI is an open provenance question, tracked separately — do not "fix" the red by
560-
re-adding a skip.
560+
which dumps the manifest and runs the ratchet against it. Where the manifest comes from is
561+
**settled** (#5960, maintainer ruling 2026-08-07): **not from CI**. It is an on-demand
562+
gate whose trigger is the **objectui pin bump**`.objectui-sha` is the only thing that
563+
moves the manifest, so `scripts/bump-objectui.sh` and `scripts/build-console.sh` print the
564+
`pnpm sdui:manifest` step and `docs/releases-maintenance.md` carries the procedure.
565+
Producing it here was rejected outright: the sole producer drives Playwright chromium over
566+
objectui's built console, so a CI-side dump means a full objectui build plus a browser
567+
download on every matching PR. So: do not "fix" the red by re-adding a skip, and do not
568+
"fix" it by wiring the gate into a workflow either — run it where it belongs, at the pin
569+
bump.
561570

562571
`check:exported-any` is the one of those that also reads the built `dist/*.d.ts`, so the
563572
stale-`dist` caveat above applies to it too. It asks the other half of the

docs/adr/0082-react-component-contract-governance.md

Lines changed: 39 additions & 11 deletions
Large diffs are not rendered by default.

docs/audits/2026-06-react-blocks-conformance.md

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ something this audit measured.)* So:
7272
**frontend-only** props (e.g. `object-form` formType/drawer*/modal*) to the
7373
spec so the protocol covers what the component accepts; and run this check in
7474
CI (with a console manifest dump) as a ratchet so new divergence is caught.
75+
*(⚠️ The last clause was **rejected** on 2026-08-07, #5960: a console manifest dump
76+
in this repo's CI means a full objectui build plus Playwright/chromium on every
77+
matching PR. The ratchet is on-demand, triggered by the objectui pin bump — see
78+
the correction under "Ratchet (implemented)" below.)*
7579
3. The `record:*` blocks declaring **zero inputs** means the visual designer can't
7680
configure them — likely a real gap to close.
7781

@@ -85,10 +89,22 @@ MANIFEST=/path/to/sdui.manifest.json pnpm --filter @objectstack/spec check:react
8589

8690
## Ratchet (implemented)
8791

88-
Running this on every framework PR isn't worth it — the manifest only exists at
89-
console-build time. So the conformance check is wired in as a **baseline ratchet**
90-
at the one place the manifest is produced for free: `scripts/build-console.sh`,
91-
right after it dumps `sdui.manifest.json` from the freshly-built console registry.
92+
Running this on every framework PR isn't worth it — the manifest only exists once a
93+
real browser has enumerated the built console registry. So the conformance check is
94+
wired in as a **baseline ratchet** at the one place the manifest is produced for free:
95+
`scripts/gen-sdui-manifest.sh` (`pnpm sdui:manifest`), right after it dumps
96+
`sdui.manifest.json` from the freshly-built console registry.
97+
98+
> **Corrected 2026-08-07 (#5960).** This paragraph named `scripts/build-console.sh`,
99+
> which is where the ratchet shipped and, since #4472, no longer where it lives —
100+
> `build-console.sh` deliberately dumps no manifest, because the console build must not
101+
> drag in a browser dependency. ADR-0082 carried the same stale pointer and is corrected
102+
> with it. #5960 also settled *when* the ratchet runs: it is an **on-demand gate**, and
103+
> its trigger is the **objectui pin bump** (`scripts/bump-objectui.sh` prints the step;
104+
> `docs/releases-maintenance.md` carries the procedure). Producing the manifest in this
105+
> repo's CI was rejected — a full objectui build plus a Playwright/chromium download on
106+
> every matching PR — and since #4690 a missing manifest exits 1 rather than skipping, so
107+
> the residual risk is "unrun", never "falsely green". See ADR-0082 addendum 2.
92108
93109
- The accepted state lives in `packages/spec/react-declaration-parity.baseline.json`
94110
(per block: the registry-only input set + whether the block is missing).

docs/releases-maintenance.md

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,34 @@ CONSOLE_BUMP=patch scripts/bump-objectui.sh # force the bump type
5050
scripts/bump-objectui.sh --no-changeset # opt out (rarely)
5151
```
5252

53+
#### After the pin moves: run the declaration-parity ratchet (#5960)
54+
55+
The bump has a second half, and it is not optional:
56+
57+
```bash
58+
pnpm sdui:manifest # rebuild objectui at the new pin, dump sdui.manifest.json, run the ratchet
59+
```
60+
61+
`sdui.manifest.json` is objectui's registry-inputs dump — the right-hand side of
62+
ADR-0082 D4's spec↔registry **declaration-parity ratchet** (`scripts/gen-sdui-manifest.sh`
63+
produces it and runs the ratchet against it; note it is *not* `scripts/build-console.sh`,
64+
which the ADR named until #5960 corrected it). That file changes when — and only when —
65+
this pin moves, so **the pin bump is the ratchet's trigger, and its only one.**
66+
67+
This is an **on-demand gate by decision** (maintainer ruling, 2026-08-07). No workflow
68+
produces the manifest and none should: the only producer drives a Playwright chromium
69+
over objectui's built console and reads `window.__MANIFEST`, so wiring it into this
70+
repo's CI would put a full objectui build plus a browser download on every matching PR.
71+
The trade is deliberate — honest on-demand coverage over expensive full coverage —
72+
and it is safe because the gate has no unearned green: since #4690 a missing, unreadable,
73+
malformed or empty manifest **exits 1** rather than skipping. The one failure mode left is
74+
that nobody runs it, which is what this step exists to close. `scripts/bump-objectui.sh`
75+
and `scripts/build-console.sh` both print the reminder when they finish.
76+
77+
Needs a Playwright browser (`pnpm exec playwright install chromium-headless-shell`). When
78+
the ratchet fires, the fix is a spec/overlay edit or an explicit `--update` to re-accept
79+
the baseline — see ADR-0082 D4 and its addendum 2.
80+
5381
## 3. Platform layer — `content/docs/releases/vN.mdx` (curated)
5482

5583
The curated, developer-facing "big picture", written for third parties building on
@@ -134,8 +162,10 @@ node scripts/check-objectui-pin-fresh.mjs --ref v17.0.0 --json
134162
down without turning red into green — the degradation is printed, not swallowed. An
135163
unreachable remote is reported as `unreadable` and exits non-zero.
136164
- **Fix when it fires:** `scripts/bump-objectui.sh` to move the pin (which writes the
137-
`@objectstack/console` changeset for the crossed range), then re-source the Console
138-
section with `scripts/objectui-range.mjs`.
165+
`@objectstack/console` changeset for the crossed range), then `pnpm sdui:manifest` to
166+
run the declaration-parity ratchet at the new pin (see "After the pin moves" above —
167+
the bump is that ratchet's only trigger), then re-source the Console section with
168+
`scripts/objectui-range.mjs`.
139169

140170
## Drift guard
141171

scripts/build-console.sh

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,5 +190,12 @@ echo "✓ @objectstack/console dist ready (${BYTES} KB) from objectui@${PINNED_S
190190
# real browser (Playwright) to enumerate the console registry, and the console
191191
# build must not drag in a browser dependency. Regenerate them on demand instead:
192192
# pnpm sdui:manifest (see scripts/gen-sdui-manifest.sh)
193+
#
194+
# The reminder names the TRIGGER, not just the command (#5960): `pnpm objectui:refresh`
195+
# runs bump-objectui.sh and then this script, so this is the last output an operator
196+
# sees while moving the pin — and the pin bump is the ratchet's only trigger, by
197+
# decision. bump-objectui.sh prints the same step; this repeats it because that one
198+
# has scrolled past a whole console build by now.
193199
echo "ℹ SDUI manifest + declaration-parity ratchet are decoupled from the console build."
194-
echo " Run 'pnpm sdui:manifest' on demand to regenerate (requires Playwright)."
200+
echo " Run 'pnpm sdui:manifest' whenever you move the objectui pin — that is the"
201+
echo " ratchet's only trigger, on demand by decision (#5960). Requires Playwright."

scripts/bump-objectui.sh

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@
77
# scripts/bump-objectui.sh --no-commit # update files only, don't commit
88
# scripts/bump-objectui.sh --no-changeset # skip the @objectstack/console changeset
99
#
10+
# After the bump — the second half of the pin-update procedure (#5960):
11+
# pnpm sdui:manifest # dump objectui's sdui.manifest.json and run the
12+
# # spec↔registry declaration-parity ratchet (ADR-0082 D4).
13+
# # The pin bump is that ratchet's ONLY trigger; it is an
14+
# # on-demand gate by decision, never a CI job. Needs
15+
# # Playwright chromium. This script prints the reminder.
16+
#
1017
# Env:
1118
# CONSOLE_BUMP=major|minor|patch # force the changeset bump type (default: auto —
1219
# # the HIGHEST level objectui itself declared in the
@@ -56,7 +63,10 @@ for arg in "$@"; do
5663
--no-commit) NO_COMMIT=1 ;;
5764
--no-changeset) NO_CHANGESET=1 ;;
5865
-h|--help)
59-
sed -n '2,19p' "$0" | sed 's/^# \{0,1\}//'
66+
# NOTE: this line range is coupled to the header block above (usage → env →
67+
# sibling layout, ending at "run from here"). Editing the header means moving
68+
# it — #5960 added the pin-update step and had to.
69+
sed -n '2,26p' "$0" | sed 's/^# \{0,1\}//'
6070
exit 0
6171
;;
6272
*) EXPLICIT_SHA="$arg" ;;
@@ -157,8 +167,36 @@ EOF
157167
echo "→ wrote changeset $(basename "$CS_FILE") (@objectstack/console: ${BUMP})"
158168
fi
159169

170+
# --- The other half of the pin-update procedure (#5960) ----------------------
171+
# ADR-0082 D4's spec↔registry declaration-parity ratchet reads objectui's
172+
# `sdui.manifest.json`, and that file changes when — and only when — this pin
173+
# moves. So the pin bump is the ratchet's trigger, and it is the ONLY one:
174+
# measured on origin/main, no workflow runs `pnpm sdui:manifest`, no workflow
175+
# installs Playwright for it, `packages/console/dist/` is gitignored and the
176+
# published @objectstack/console tarball ships no manifest. Producing it in this
177+
# repo's CI was considered and REJECTED (#5960) — it would put a full objectui
178+
# build plus a chromium download on every matching PR.
179+
#
180+
# Deliberately a REMINDER, not a hard gate: a machine without Playwright must
181+
# still be able to move the pin, and hard-failing here would be the rejected
182+
# CI cost wearing a local disguise. The gate itself cannot go falsely green —
183+
# since #4690 a missing or unusable manifest exits 1 instead of skipping — so
184+
# the only failure mode left is "nobody ran it", which is what this prints to
185+
# prevent. Printed on BOTH exits below: --no-commit still moved the pin.
186+
print_sdui_next_step() {
187+
echo
188+
echo "→ NEXT STEP — run the declaration-parity ratchet (ADR-0082 D4):"
189+
echo " pnpm sdui:manifest"
190+
echo " It rebuilds objectui at the new pin, dumps packages/console/dist/sdui.manifest.json"
191+
echo " and ratchets spec↔registry declaration parity. A pin bump is its only trigger:"
192+
echo " it is an on-demand gate by decision (#5960), never a CI job."
193+
echo " Needs a Playwright browser — 'pnpm exec playwright install chromium-headless-shell'."
194+
echo " Procedure: docs/releases-maintenance.md → 'After the pin moves'."
195+
}
196+
160197
if [[ "$NO_COMMIT" -eq 1 ]]; then
161198
echo "→ --no-commit: leaving files unstaged."
199+
print_sdui_next_step
162200
exit 0
163201
fi
164202

@@ -170,3 +208,4 @@ ${SUBJECT_LINE}
170208
171209
objectui@${NEW_SHA}" -- .objectui-sha ${CS_FILE:+"$CS_FILE"}
172210
echo "✓ Committed. Push with: git push"
211+
print_sdui_next_step

scripts/objectui-changeset-digest.mjs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,10 +1226,25 @@ function selfTest() {
12261226
for (const f of ['bump-objectui.sh', 'objectui-changeset-digest.mjs']) {
12271227
writeFileSync(join(fwRun, 'scripts', f), readFileSync(join(__dirname, f), 'utf8'));
12281228
}
1229-
execFileSync('bash', [join(fwRun, 'scripts', 'bump-objectui.sh'), '--no-commit', head], {
1230-
encoding: 'utf8',
1231-
env: { ...process.env, OBJECTUI_ROOT: ui },
1232-
});
1229+
const bumpStdout = execFileSync(
1230+
'bash',
1231+
[join(fwRun, 'scripts', 'bump-objectui.sh'), '--no-commit', head],
1232+
{
1233+
encoding: 'utf8',
1234+
env: { ...process.env, OBJECTUI_ROOT: ui },
1235+
},
1236+
);
1237+
// #5960: the pin bump is the ONLY trigger of ADR-0082 D4's declaration-parity
1238+
// ratchet — no workflow produces `sdui.manifest.json`, by ruling — so the
1239+
// procedure's second half lives in this script's output. Prose alone is
1240+
// deletable in silence; pinning it here is what makes "the procedure gained a
1241+
// line" a fact a gate can lose. Asserted on the `--no-commit` path on purpose:
1242+
// that path moved the pin too, and it is the one that returns early.
1243+
check(
1244+
'#5960 a bump prints the `pnpm sdui:manifest` step (the ratchet has no other trigger)',
1245+
bumpStdout.includes('pnpm sdui:manifest') && bumpStdout.includes('NEXT STEP'),
1246+
bumpStdout,
1247+
);
12331248
const written = join(fwRun, '.changeset', `console-${head.slice(0, 12)}.md`);
12341249
const body = existsSync(written) ? readFileSync(written, 'utf8') : '';
12351250
check('bump-objectui.sh writes the digest-derived changeset', body.length > 0);

0 commit comments

Comments
 (0)