|
| 1 | +--- |
| 2 | +"@objectstack/spec": patch |
| 3 | +"@objectstack/platform-objects": patch |
| 4 | +--- |
| 5 | + |
| 6 | +fix(spec): stop offering retired `app` keys in the metadata form, and make the reconciliation gate see tombstones (#5280) |
| 7 | + |
| 8 | +The `app` authoring form rendered **eight** controls for keys `AppSchema` had |
| 9 | +already retired to `retiredKey()` tombstones in 17.0.0 — `version`, `homePageId`, |
| 10 | +`objects`, `apis`, `sharing`, `embed`, `mobileNavigation` and `aria`. A tombstone |
| 11 | +is `z.never().optional()`, so filling one of those controls did not lose the |
| 12 | +value quietly: it failed the **entire save** with the key's removal |
| 13 | +prescription. The controls are gone, each with a comment in place naming where |
| 14 | +the capability went (`manifest.version`; the first `navigation` item by `order` |
| 15 | +plus `isDefault`; `defineStack({ objects })`; `defineStack({ apis })`; |
| 16 | +`FormView.sharing` for both public access and embedding; the component that |
| 17 | +renders the DOM node for `aria`). |
| 18 | + |
| 19 | +Nothing about the contract changes — every one of these keys was already |
| 20 | +rejected at parse. What changes is that an author is no longer shown a control |
| 21 | +that can only produce a 422. |
| 22 | + |
| 23 | +**The reconciliation gate now judges the right thing.** #3786's |
| 24 | +`metadata-form-zod-reconciliation.test.ts` asked whether an offered key was |
| 25 | +`∈ shape`. That was the same question as "may the author write this" until |
| 26 | +`retiredKey()` existed: a tombstone **deliberately stays in the shape** so the |
| 27 | +removal can carry its own upgrade prescription, so every one of those eight keys |
| 28 | +read as "the Zod accepts it" and the gate stayed green over all of them. It now |
| 29 | +asserts `∈ shape` **and not a tombstone**, in both directions — a retired key |
| 30 | +may not be offered, and its absence needs no ledger entry to excuse it. The |
| 31 | +detector reads the schema node (`z.never()` under the optional wrapper), never a |
| 32 | +list of key names, mirroring `isRetired()` on the JSON-Schema side of |
| 33 | +`build-schemas.ts`. The next `retiredKey()` retirement that forgets a form now |
| 34 | +fails this test instead of reaching an author. |
| 35 | + |
| 36 | +Retiring an authorable key already required pruning its form input; that step is |
| 37 | +now enforced rather than remembered. |
0 commit comments