|
| 1 | +--- |
| 2 | +"@objectstack/cli": minor |
| 3 | +--- |
| 4 | + |
| 5 | +<!-- adr-0087: not-required (no-migration-prescription) the renamed member is a CLI `--json` OUTPUT key emitted from an inline object literal — no Zod schema, no `packages/spec` declaration, no stored representation, so `objectstack migrate meta` has nothing to reach. The affected party is a script reading stdout (ADR-0087 D8). --> |
| 6 | + |
| 7 | +feat(cli)!: the `--json` payload key `specVersionGap` is renamed to `protocolVersionGap` (#14261) |
| 8 | + |
| 9 | +**BREAKING** — a published machine surface changes a key name. `os validate --json` and |
| 10 | +`os build --json` emit **`protocolVersionGap`** where they emitted `specVersionGap`. A |
| 11 | +consumer reading `specVersionGap` reads `undefined` after this release and must switch to |
| 12 | +the new name. There is **no alias and no dual-key transition window**: one axis, one name. |
| 13 | + |
| 14 | +The value shape is unchanged — `null` when the app's declared compatibility range admits |
| 15 | +the installed `@objectstack/spec`, otherwise the same advisory record with the same |
| 16 | +members. Nothing else on either payload moves: no other key is added, removed or |
| 17 | +reshaped, and the text faces of both commands are byte-identical. |
| 18 | + |
| 19 | +## Why the name had to move |
| 20 | + |
| 21 | +The axis this advisory reports moved in **#13860**: it used to read the undeclared |
| 22 | +`manifest.specVersion` and now reads `manifest.engines.protocol`, which is declared |
| 23 | +(`PluginEnginesSchema`), stamped by every scaffold, and enforced at boot. The published |
| 24 | +key name stayed behind for one release, deliberately — renaming a machine face with |
| 25 | +pinned consumers is a break, and no ruling covered it at the time. |
| 26 | + |
| 27 | +Leaving it is a correctness problem, not untidiness. A key spelled `specVersion*` invites |
| 28 | +the reader — an AI agent above all — to infer that a writable `manifest.specVersion` |
| 29 | +exists. `ManifestSchema` is not `.strict()` and **silently drops unknown keys** (#14192), |
| 30 | +so acting on that inference does not produce an error: it produces a manifest that looks |
| 31 | +entirely normal and whose `specVersion` line never took effect. That is the same |
| 32 | +ghost-key breadcrumb mechanism that caused #13860 in the first place, left standing on |
| 33 | +the output side. |
| 34 | + |
| 35 | +## What a consumer should do |
| 36 | + |
| 37 | +```diff |
| 38 | +- if (payload.specVersionGap) { … } |
| 39 | ++ if (payload.protocolVersionGap) { … } |
| 40 | +``` |
| 41 | + |
| 42 | +The breaking surface was measured before the rename and is closed inside this repository: |
| 43 | +the only consumers of the old key were three in-repo e2e suites, which move in this same |
| 44 | +change; **zero external consumers were found**. Graded `minor` by the maintainer's |
| 45 | +explicit grading of 2026-09-02; the banner above carries the breaking-ness the level |
| 46 | +cannot. |
0 commit comments