|
| 1 | +--- |
| 2 | +'@objectstack/spec': minor |
| 3 | +--- |
| 4 | + |
| 5 | +**BREAKING** — retire `ListViewSchema.navigation.view`, the detail-view binding nothing |
| 6 | +ever resolved. |
| 7 | + |
| 8 | +`navigation.view` was an unconstrained string whose describe promised *"the form view to |
| 9 | +use for details"*. No layer from spec to console ever resolved a view by that name. Its |
| 10 | +one read in the shipped console passed the value into the **second argument of |
| 11 | +`onNavigate`** — the slot that otherwise carries the navigation-MODE token — so an |
| 12 | +authored name did not select a view, it **substituted for the mode**. A consumer in the |
| 13 | +same bundle reads that argument against a closed two-value vocabulary (`edit` / `view`), |
| 14 | +so any other authored value matched neither branch: invisible on grids whose handler |
| 15 | +takes one argument, a dead row click on the ones that do not. |
| 16 | + |
| 17 | +The enumeration behind the removal was exhaustive rather than sampled — every `.view` |
| 18 | +property read in the bundle (exactly three) and every `formViews` read — and **no read |
| 19 | +anywhere is keyed by an authored view name**. There was no path by which the key could |
| 20 | +resolve one. ADR-0049 enforce-or-remove; maintainer ruling 2026-09-13 (director decision |
| 21 | +batch #126 item 4, option B). Zero authored instances in this repository; the one |
| 22 | +external author removed its occurrence. |
| 23 | + |
| 24 | +## FROM → TO |
| 25 | + |
| 26 | +| you wrote (17.4 and earlier) | write instead | |
| 27 | +| --- | --- | |
| 28 | +| `navigation: { view: 'summary_view' }` on a list view | `navigation: { }` — delete the key. Then publish the layout you wanted as a `record` page on that object and mark the one that should open `isDefault` | |
| 29 | +| `navigation: { mode: 'drawer', view: 'edit_form' }` | `navigation: { mode: 'drawer' }` — the mode, size and every other key of the block are **unchanged** | |
| 30 | + |
| 31 | +**The one-line fix:** delete `view` from the list view's `navigation` block; to choose |
| 32 | +what opens for a record, assign a `record` page to the object and let `isDefault` pick |
| 33 | +the one that opens. |
| 34 | + |
| 35 | +Nothing regresses by deleting it: the key never selected anything. What decides how the |
| 36 | +detail is surfaced is `mode` and `size`, and both are untouched. |
| 37 | + |
| 38 | +## The retirement kit |
| 39 | + |
| 40 | +- **`navigation.view`** — a `retiredKey()` tombstone on `NavigationConfigSchema`. `tsc` |
| 41 | + types the key `never`, so writing it fails at the authoring site; a value reaching a |
| 42 | + parse raises the prescription rather than a bare unrecognized-key report. Refused at |
| 43 | + all three doors — `ListViewSchema`, `ObjectListViewSchema` and the flattened |
| 44 | + `PUT /api/v1/meta/view` overlay — and pinned at each. |
| 45 | +- **ADR-0087 disposition: a D3 SEMANTIC entry**, `list-view-navigation-view-retired`, not |
| 46 | + a D2 conversion. A mechanical strip would delete the key without recording which list |
| 47 | + view lost it, and an author who wrote it wanted a named detail layout — a want page |
| 48 | + assignment serves and a stripped key does not record. So the TODO names the surface and |
| 49 | + hands the judgement back, which is what a semantic entry is for. The tombstone |
| 50 | + prescription therefore carries **no** `os migrate meta` sentence: that sentence is owed |
| 51 | + only where a conversion covers the surface. |
| 52 | +- **The five surviving keys of the block** — `mode`, `preventNavigation`, `openNewTab`, |
| 53 | + `size`, `width` — are unchanged, and pinned accepting beside the refusal. A tombstone |
| 54 | + that broke its live siblings would satisfy every refusal assertion while being a larger |
| 55 | + bug; `navigation` is one closed shape, so that blast radius is the whole block. |
| 56 | +- **`ui/NavigationConfig:view`** is registered in `RETIRED_KEYS_BY_MAJOR[18]`, which is |
| 57 | + also what starts its aging clock. |
| 58 | + |
| 59 | +## What is deliberately NOT in this change |
| 60 | + |
| 61 | +`view/list/navigation`'s six children are unclassified in the liveness ledger because |
| 62 | +`check-liveness` drills one level. That is #17424's subject and is cited here, not fixed: |
| 63 | +the ledger row for `navigation` itself is untouched, and no row exists for `view` to |
| 64 | +update. |
| 65 | + |
| 66 | +The sibling `objectui` contract twin — `ViewNavigationConfig`, a re-export of this very |
| 67 | +type — is in the other repository and is left to it. Its parity pin authors |
| 68 | +`{ view: 'summary_view' }` as a legal value, so it needs the tombstone pin before that |
| 69 | +repo picks up a spec carrying this retirement. |
| 70 | + |
| 71 | +Clause-②: no |
| 72 | + |
| 73 | +<!-- adr-0087: registered list-view-navigation-view-retired --> |
0 commit comments