Repository navigation
Commit 36f13bb
fix(scripts): the manifest generator defaults its @object-ui version from the PIN, not the record (#18875)
Fixes #18819
Clause-②: no
## The defect, re-measured on this branch's base
`origin/main` `36583e989b`. The generator read its two provenance fields
at two different
moments:
```
:129 const version = arg('--objectui-version') ?? record.objectuiPackagesVersion;
:199 objectuiSha: pin,
:200 objectuiPackagesVersion: version,
```
`objectuiSha` is re-read from the LIVE `.objectui-sha`;
`objectuiPackagesVersion` fell back to
the value already sitting in `scripts/sdui-manifest.record.json`. A
regeneration after a pin bump
therefore wrote the NEW pin under the OLD version string — a record
whose two objectui fields
describe two different commits, which is exactly the record
`scripts/check-sdui-manifest.mjs`
check 4 rejects. The person that reds is the one who followed the
documented bump procedure, so
the producer is where it gets fixed.
## Step one, before writing any fix: is that path reachable today?
The counterfactual on `:129` is that the defect is unreachable if
`arg('--objectui-version')` is
never empty. It is reachable. **Paths, not counts.**
**No automated caller exists at all.** No `package.json` script, no
workflow step and no shell
line executes this generator. `scripts/bump-objectui.sh` and
`scripts/build-console.sh` only
`echo` the command. Every invocation is therefore a person or an agent
typing one of the
spellings the tree documents.
Of those spellings, six omit `--objectui-version`:
| path | spelling |
|:---|:---|
| `scripts/check-sdui-manifest.mjs:228` | `Regenerate: node
scripts/gen-sdui-manifest-node.mjs` — printed when the artefact is
missing |
| `scripts/check-sdui-manifest.mjs:275` | `Regenerate: node
scripts/gen-sdui-manifest-node.mjs` — printed on a sha256 mismatch |
| `scripts/sdui-manifest.record.json:10` | `Regenerate + re-record: node
scripts/gen-sdui-manifest-node.mjs` |
| `packages/spec/scripts/manifest-prescription.ts:81` | ``regenerate it
and its record with `node scripts/gen-sdui-manifest-node.mjs` `` |
| `scripts/gen-sdui-manifest-node.mjs:8` | the bare usage line |
| `scripts/gen-sdui-manifest-node.mjs:9` | the `--modules-root DIR`
offline usage line |
Two of those six are printed **by the gate itself**. The remaining
spellings do carry the flag:
`AGENTS.md:156`, `docs/releases-maintenance.md:116` and `:279`,
`scripts/bump-objectui.sh:11` and
`:739`, `scripts/build-console.sh:297`,
`scripts/check-sdui-manifest.mjs:301` `:303` `:320`.
The other paths that name the generator carry no command at all and are
listed here for
completeness: `.github/workflows/lint.yml:799` (a comment),
`packages/spec/scripts/check-generated.ts:391`,
`packages/spec/scripts/check-react-blocks-declaration-parity.ts:85`, and
`packages/spec/scripts/check-react-blocks-declaration-parity.test.ts:565`
`:569` (a pin test on
the prescription text).
## A or B — decided by that reading, not by preference
Zero automated call sites means option B's stated cost ("every call site
has to change") is
nearly zero *in code*. But B is not free: it would turn all six
documented no-flag spellings into
refusals, including the `--modules-root` offline mode, and it would
refuse even when the answer is
sitting in the objectui checkout the bump already required.
So: **A for the default, B for the residue.**
- `--objectui-version` still wins when passed.
- Otherwise the version is what `packages/core/package.json` DECLARES at
the pinned commit, read
through `check-sdui-manifest.mjs`'s exported `readPinnedDeclaredVersion`
— the same function
check 4 judges the written record with, imported rather than re-typed.
Producer and gate now
read one oracle; two readers of two oracles is where this drift came
from.
- When that oracle cannot answer (no objectui checkout, or one that does
not carry the pin) the
generator REFUSES and names both remedies. An unread version is never
converted into a version
string — Route and surface ownership §3, prefer failing to falling back,
and Prime Directive
#12's ban on a lenient `??` fallback in place of fixing the producer.
Importing the gate's exported oracle changes no gate:
`scripts/check-sdui-manifest.mjs` is
untouched in this diff, and its CLI body is behind
`isEntrypoint(import.meta.url)`, so importing
it runs nothing.
## Verification
Every leg below ran against a fixture tree in a scratchpad, or against
the real repo with a trap
and a proved restore. `.objectui-sha` and
`scripts/sdui-manifest.record.json` are read-only this
round; neither is in this diff.
### LIT — pin bumped, `--objectui-version` not passed. Both legs read.
A synthetic objectui checkout with two commits (`a183cfbf…` declaring
`17.6.0`, `51ecffcc…`
declaring `18.0.0-fixture`), a stub `@object-ui` install behind
`--modules-root`, and a fixture
record naming the OLD sha at `17.6.0`. The fixture pin is the NEW sha.
| leg | generator | record written | `check-sdui-manifest.mjs` |
|:---|:---|:---|:---|
| before | `36583e989b` | `51ecffccfb32 / 17.6.0` — new pin, **old
version** | **exit 1**, check 4 red |
| after | this branch | `51ecffccfb32 / 18.0.0-fixture` | **exit 0**,
green |
The before leg's gate output is check 4 naming the defect verbatim:
```
the record's two objectui fields describe different commits: objectuiPackagesVersion is "17.6.0",
but objectui 51ecffccfb32… — the pin the record itself names — declares "18.0.0-fixture" in packages/core/package.json
```
### DARK — pin not bumped. Reads zero, on the REAL artefact.
Not a fixture: the real `scripts/gen-sdui-manifest-node.mjs`, the real
pin
`53ded82bf7a494f54e344e19099dbf00854b8694`, and the real published
`@object-ui/*` 17.6.0 set
installed once and reused by both legs so the install cannot be the
variable. The base generator
was swapped in on disk, its arrival proved by anchor counts before the
leg ran
(`?? record.objectuiPackagesVersion` = 1, `readPinnedDeclaredVersion` =
0, and a `git hash-object`
differing from the HEAD blob), then restored.
```
leg after (fixed) : 57 components, 66910 bytes, sha256 49211fee7792cf51174930dc2c1be2169d5175f77a83491f68f90b3f0c19e69d
leg before (base) : 57 components, 66910 bytes, sha256 49211fee7792cf51174930dc2c1be2169d5175f77a83491f68f90b3f0c19e69d
cmp: BYTE-IDENTICAL
```
That sha256 is also the one the tracked record already carries, and the
tracked
`sdui.manifest.json` HEAD blob is still `78f870e42fe9` — unmoved.
Restore proved by state, not by
an exit code: `git diff HEAD` empty and `git status --porcelain` empty
afterwards.
### Two further legs
- **Refusal residue.** Pin bumped, no flag, oracle unreachable
(`OBJECTUI_ROOT` at a directory
with no `.git`): base generator exits 0 and silently writes the drifted
record; this branch
exits 1, writes no manifest, and leaves the record untouched.
- **Explicit precedence.** `--objectui-version 99.1.2-explicit` is
honoured unchanged on both
legs; the success line now also names where the version came from.
### Gates
- `node scripts/check-sdui-manifest.mjs` — **exit 0** on the clean tree,
and its check 4 leg
resolved for real: "@object-ui 17.6.0 is the version objectui
53ded82… declares in
packages/core/package.json (read from /home/user/objectui)".
- `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived 26
commands; all 26 run, **all exit 0**, and `--ran` with exit codes
recorded reconciles:
"26 derived famil(ies) accounted for — 26 run, 0 NOT-MEASURED (a DERIVED
zero)".
- The seven roster families the tool flags as "roster under scripts,
which one of your paths is
in — silence is not evidence in EITHER direction" were run too. Six exit
0.
`pnpm check:published-readme-exports` exits **3 — PREREQUISITE NOT MET**
(46 packages unbuilt);
that is NOT MEASURED, not a finding, and this diff moves no package
source and no README.
- `pnpm lint` (`eslint . --no-inline-config`), the whole repo, **exit
0** at `1c3a721ac1`.
- `pnpm check:nul-bytes` exit 0; an independent control-byte scan of the
changed file is clean.
No changeset: nothing published moves. `scripts/**` appears in no
package's `files[]` and the
root package is `private`, so no released package's contents change.
## Acceptance notes
Noted, not filed — none is a reproducible defect, a declared-contract
violation, or a
metadata-authoring trap, so none earns a card under Prime Directive #10:
- `scripts/check-sdui-manifest.mjs` check 4's header paragraph, and its
check-4 failure text at
`:318-319`, both explain the producer default this PR removes ("The
generator REUSES the version
already recorded when `--objectui-version` is not passed"). After this
lands those sentences
describe history rather than current behaviour. The gate is fenced
read-only for this card, so
they are left exactly as they are. The check itself stays load-bearing —
it still catches a
hand-edited record, an explicitly-wrong `--objectui-version`, and any
other producer.
- `packages/spec/scripts/check-react-blocks-declaration-parity.ts:88-89`
says the node producer
"enumerates the PUBLISHED `@object-ui/*` packages at the version named
in
`scripts/sdui-manifest.record.json`". That sentence is wrong-by-default
after this change. Not
fixed in place: editing it pulls `packages/spec` into the diff and with
it a whole gate family
this card does not otherwise owe, against the bounded-in-place-fix
condition of adding no new
verification surface.
- The residual hole this PR deliberately does not close: an operator who
passes
`--objectui-version` **explicitly and wrongly** still writes a drifted
record. The generator
could warn when an explicit value disagrees with the resolvable pin
oracle. Check 4 already reds
the resulting record, so this is a loudness improvement, not a
correctness gap.
- #17735 is not addressed here — whether the published tarballs at a
version were built from the
pinned commit is that card's producer question, and it carries
`needs-user-decision`. This
change moves the version's SOURCE and nothing about that relation.
#18814's check 4 is not
modified here either.
Fenced files honoured: `scripts/sdui-manifest.record.json` and
`.objectui-sha` are held by open PR
#18723 and are read-only in this round. The real DARK leg did rewrite
the record as a side effect
of running the generator, exactly as warned; both were restored from
HEAD and the restore is
proved by an empty `git diff HEAD`, never by an exit code.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent 0b31d90 commit 36f13bb
1 file changed
Lines changed: 50 additions & 13 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
8 | | - | |
| 8 | + | |
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
| |||
48 | 48 | | |
49 | 49 | | |
50 | 50 | | |
51 | | - | |
| 51 | + | |
52 | 52 | | |
53 | 53 | | |
54 | 54 | | |
55 | | - | |
56 | | - | |
57 | | - | |
58 | | - | |
59 | | - | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
60 | 78 | | |
61 | 79 | | |
62 | 80 | | |
| |||
71 | 89 | | |
72 | 90 | | |
73 | 91 | | |
| 92 | + | |
| 93 | + | |
74 | 94 | | |
75 | 95 | | |
76 | 96 | | |
| |||
126 | 146 | | |
127 | 147 | | |
128 | 148 | | |
129 | | - | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
130 | 155 | | |
131 | | - | |
132 | | - | |
133 | | - | |
134 | | - | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
135 | 169 | | |
136 | 170 | | |
137 | 171 | | |
| |||
205 | 239 | | |
206 | 240 | | |
207 | 241 | | |
208 | | - | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
0 commit comments