Repository navigation
Commit d8830c2
test(cli): drive the two new --json members and align the noise-budget scaffold with the workspace protocol (nightly tiers) (#22699)
Fixes #22622
Clause-②: no
Two nightly-tier CLI test files change and nothing else: no accepted
input, key, export or error code moves, and nothing publishes.
Two independent reds on the nightly tiers, both in `domain:cli`. **Both
are fixed inside the nightly tests**, following the seat's review
6099406666 on #22622. Nothing else changes:
- the family-roster check;
- the noise budget and every assertion in that file;
- the `create-objectstack` template, the version-time stamp
(`scripts/sync-template-versions.mjs`) and their tests, which are
byte-for-byte as `main` has them.
## (a) Both reds, reproduced before any fix
Base `9646991283`, `OS_TEST_TIERS=nightly`, `--project integration`,
through the verify lock: `Tests 2 failed | 51 passed (53)`.
- `json-stdout-purity.e2e.test.ts`, `is exactly the set listed here`:
`expected [ 'meta resync', …(17) ] to deeply equal [ 'meta resync',
…(15) ]`, with `+ "migrate organization-ownership"` and `+ "migrate
security-catalog-overlays"`. `migrate organization-ownership` came from
PR #22643, after the nightly that filed the card. The members were taken
from `discoverFamily()`'s output.
- `serve-boot-diagnostics-noise-budget.e2e.test.ts`, `highlights the
dead button once…`: `expected 0 to be greater than 0` at `:176`. The
boot printed `✗ package 'com.example.support-desk' targets protocol ^17
(engines.protocol) but this runtime is protocol 18.0.0. This is a
major-version break. Run: objectstack migrate meta --from 17`. That is a
refusal, so no *Boot diagnostics* block is printed at all.
After, on `3d63ed7db5`: `Test Files 2 passed (2)`, `Tests 59 passed
(59)`. That is 53, plus 3 cases for each of the two new members.
## Failure 1: the two new `--json` members are driven
`FAMILY` gains both members, each in its bare form. The CLI was first
run against the purity fixture to see each one's face:
- `migrate organization-ownership` shows its refusal face. Over a
database with none of the platform tables it prints
`{"error":"plan_refused","reason":"not-an-objectstack-database",…}` and
exits 1. The JSON is emitted after `stack.shutdown()`, and no plan file
is written.
- `migrate security-catalog-overlays` shows its read-only preview:
`listed: 0`, exit 0. There is no `sys_metadata` hydration and nothing is
deleted.
Both print all three boot diagnostics on stderr. The discovery and the
`toEqual` roster check are untouched.
## Failure 2: the noise-budget e2e aligns the pair it boots
### (b) What the version-time stamp writes
Measured read-only at `9646991283`:
- `changeset status --output` (`pre.json` is
`{"mode":"pre","tag":"next"}`) gives `@objectstack/spec major 17.7.0 ->
18.0.0-next.0` and `create-objectstack major 17.7.0 -> 18.0.0-next.0`
(the `fixed` group).
- `loadScaffolderVersion()` on `18.0.0-next.0` gives
`{"version":"18.0.0-next.0","major":"18","range":"^18.0.0"}`. So the
version pass stamps `engines: { protocol: '^18' }` into the released
template.
**Triage's "every project that v18's `create-objectstack` scaffolds
would boot with the protocol-gap warning" is false.** No released v18
scaffold carries the gap. PR #22215's changeset says the same ("the
template keeps `'^17'` until the version pass stamps it").
The red is `main`'s pre-mode window: packages at `17.7.0`,
`PROTOCOL_VERSION` at `18.0.0`. Only an in-repo pairing sees it: a
published-line scaffold booted on the workspace runtime with nothing
installed.
### Round 1 changed the product side, and CI falsified that
Round 1 (`bff640d98`) stamped the template's `engines.protocol` from
`PROTOCOL_VERSION`'s major. On that head, `Scaffold with repo dist`
(`scaffold-e2e.yml`, job 1) went red: "package 'com.example.e2e-app'
targets protocol ^18 (engines.protocol) but this runtime is protocol
17.0.0".
That gate guards the path a user takes. It scaffolds with the repo-built
scaffolder and installs `@objectstack/*` from the registry (`^17.0.0`,
so protocol 17). On that path a template's range must match the protocol
of the packages it installs, which is the package major. The sync script
and the `template-consistency` ratchet already enforce exactly that on
`main`.
Commit `60fa01c7a7` removes round 1's product-side change:
- `templates/blank/objectstack.config.ts`,
`template-consistency.test.ts`, `template-version-stamps.test.ts` and
`scripts/sync-template-versions.mjs` are back at their `main` blobs
(`6308f29e`, `d32c819c`, `48ba146e`, `f7704db8`, all equal at base and
`origin/main`);
- the `create-objectstack` changeset is deleted.
### This round: the setup aligns the pair it boots
This follows the seat's verification-strategy ruling in 6099406666.
After scaffolding, and before the fixture files are written,
`alignProtocolRange()` rewrites the scaffold's `engines.protocol` to
`'^' + PROTOCOL_MAJOR`. `PROTOCOL_MAJOR` is read from
`@objectstack/spec/kernel`, the workspace spec this file boots, the same
import other CLI e2e files use.
- **Only the major's digits are rewritten.** When the majors agree, the
scaffold is left byte-for-byte as written, and the helper does not write
the file at all.
- Measured on the template: at `'^17'` (the window) the hash moves
`684e38ed0d1a` → `5d6e6468255e`, and only the `engines` line differs.
- At `'^18'` (majors agree) the hash stays `5d6e6468255e` →
`5d6e6468255e`, byte-identical.
- **A missing stamp throws in `beforeAll`.** A template that stops
declaring the key fails this file loudly instead of skipping the
alignment.
- **Why a direct rewrite of the one key, and not `objectstack migrate
meta --from 17 --write`.** The `--write` command is the step the refusal
prescribes, and it was measured first. On a scaffold under
`packages/cli/node_modules/` it exited 0 with `not written
[outside-project]` and left the config unchanged. The codemod refuses
any file whose real path has a `node_modules` segment
(`authored-source-codemod.ts`, the `outside-project` refusal). This
project has to live under this package's `node_modules` so that its
imports resolve to workspace copies.
- **What stays the same:** the noise budget, all three assertions, and
the ticket object and actions. Once the version pass lands, the window
closes and the alignment becomes a no-op.
## Ablations
Both ran through `scripts/ablation-replace.mjs` in wrap mode on
committed trees, under the verify lock. Each restore was proven by blob
equal to HEAD and an empty `git diff HEAD`. Neither subject resolves
through `dist/`: the FAMILY and the setup live in the test files.
| Mutation | Anchor | Result |
|---|---|---|
| `alignProtocolRange(join(dir, 'objectstack.config.ts'));` deleted from
the setup | x1 → x0, blob `058fbecec7dc` → `bfedb0522aa5` | noise-budget
red with the original refusal: `✗ package 'com.example.support-desk'
targets protocol ^17 … this runtime is protocol 18.0.0 …`, `expected 0
to be greater than 0`, 1 failed and 2 passed. After the restore to blob
`058fbecec7dc`: 3 passed. |
| `'migrate security-catalog-overlays': [],` deleted from `FAMILY`
(round 1, same blob as now) | x1 → x0, blob `698034ba9bcb` →
`5dfe8780897a` | roster pin red: `expected [ 'meta resync', …(17) ] to
deeply equal [ 'meta resync', …(16) ]`, `+ "migrate
security-catalog-overlays"` |
## Tests (on `3d63ed7db5`)
- **Nightly tier** (`OS_TEST_TIERS=nightly`, `--project integration`,
verify lock): the two card files, 59 passed.
- **`create-objectstack`:** suite 17 files and 254 tests passed. `pnpm
check:template-version-sync` is green with 40 assertions, the same count
as on `main`. Both are unchanged, because this diff does not touch the
package or the script.
- **`@objectstack/cli`:**
- unit layer: 279 files and 4126 tests passed;
- `typecheck` (`tsc --noEmit` plus `check:test-typecheck`) is OK, and
`tsconfig.test.json`'s `--listFiles` includes both edited files.
- **Changeset:** `node scripts/check-empty-changeset.mjs --base
origin/main` exits 0. It reports no empty-frontmatter changeset added
and no merge-base changeset modified or deleted.
- **Gates:** `dispatch-gates --commands` (no paths) derived 50 commands
from the 2-file change set. `--ran` reports `50 derived, 50 run, 0
NOT-MEASURED, 0 UNRUN`, a derived zero: every command recorded `exit 0`.
`check:type-check-debt` and `check:dual-build-cjs-loads` ran last, after
every locked suite.
- `dispatch-gates` noted that the tree is behind `origin/main`: 6
derived-from files changed there (`ci.yml`,
`check-shard-attestation.mjs` and the fleet-write relay scripts).
- No conflict exists, so per the round's direction there was no merge.
CI judges the merge ref.
- **Lint, proven narrowing:**
1. Population is read from ESLint's own config: both changed files
return results with no "File ignored".
2. File count is from `--format json`: 2 results, 0 errors, 0 warnings.
3. Invariance: `eslint.config.mjs` enables no type-aware linting, and
this diff touches neither the config nor a baseline it reads.
## Changeset
Nothing publishes: `@objectstack/cli` ships `dist`, `README.md` and
`CHANGELOG.md`, and this diff is two `test/` files. By the repo's rule
this PR takes the `skip-changeset` label. An empty-frontmatter changeset
would be the risky path that `check:empty-changeset` refuses. The seat
applies the label.
## Acceptance notes
- `objectstack migrate meta --write` on a project whose path has a
`node_modules` segment says `the literal is in …/objectstack.config.ts,
outside the project at …`, although the file is inside the project. The
real cause is the `node_modules` segment rule. Only a test layout
reaches it, so this is a wording polish, not a finding. No carrier.
- Version Packages PR #21988 was last refreshed on 2026-10-08T06:19Z,
before pre mode was entered (`a87d8be29`). This is release-lane state,
recorded as a reading, ⛔ not acted on.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01BmsuLyUeuG5CNpZFMH1jzS)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 1bb1da1 commit d8830c2
2 files changed
Lines changed: 53 additions & 1 deletion
File tree
- packages/cli/test
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
100 | 100 | | |
101 | 101 | | |
102 | 102 | | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
103 | 110 | | |
104 | 111 | | |
105 | 112 | | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
106 | 119 | | |
107 | 120 | | |
108 | 121 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
33 | | - | |
| 33 | + | |
34 | 34 | | |
35 | 35 | | |
| 36 | + | |
36 | 37 | | |
37 | 38 | | |
38 | 39 | | |
| |||
122 | 123 | | |
123 | 124 | | |
124 | 125 | | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
125 | 163 | | |
126 | 164 | | |
127 | 165 | | |
| |||
141 | 179 | | |
142 | 180 | | |
143 | 181 | | |
| 182 | + | |
144 | 183 | | |
145 | 184 | | |
146 | 185 | | |
| |||
0 commit comments