Skip to content

Commit 4bc18e5

Browse files
os-warrenclaude
andauthored
feat(spec): wizard view v1 — declaration-and-refusal tightening of FormViewSchema type:'wizard' (Card S) (#13733)
* feat(spec): wizard view v1 — step-key refusal, steps guidance, empty-steps refusal, ruled TSDoc (#13704) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PBjwYLS6BciTQW3c9xQiD2 * docs(spec): regenerate reference tables; changeset; strip issue id from customer-facing refusal text (#13704) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PBjwYLS6BciTQW3c9xQiD2 --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 936aa2d commit 4bc18e5

5 files changed

Lines changed: 391 additions & 19 deletions

File tree

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
"@objectstack/spec": minor
3+
---
4+
5+
feat(spec): wizard view v1 — declaration-and-refusal tightening of `FormViewSchema` `type: 'wizard'` (#13704)
6+
7+
**BREAKING** accept-set narrowing on `FormViewSchema`, shipped as `minor` under the
8+
repo's launch-window convention for breaking changes. Grade argued per the #13622
9+
ruling (T4 leaves the final call to this PR's review chain): the nearest
10+
tightening precedents are the two `ActionSchema` accept-set narrowings #11519
11+
(doubled post-success navigation refused) and #11842 (`newTabUrl` /
12+
`opensInNewTab` co-constraint), both shipped `minor` with the **BREAKING** header;
13+
the mechanism precedent is the `section.pane` non-split parse refusal this change
14+
extends. The measured population of affected authored sources is zero in every
15+
in-tree corpus (the showcase task wizard and its lint-fixture mirror are the whole
16+
authored wizard corpus; both already use only clean step keys).
17+
18+
The wizard form view existed end to end (spec enum, gated renderer, one real
19+
author) but its contract was silent: the gate semantics lived only in renderer
20+
comments, wizard-inert section keys parsed clean, and a step-less wizard silently
21+
rendered as a plain simple form. Ruled on #13622 (maintainer 2026-08-31, director
22+
batch #12, 「同意」), v1 is a declaration-and-refusal tightening with **zero new
23+
authorable keys**:
24+
25+
- **Wizard steps carry no predicate slot and do not collapse** (upgrades
26+
objectui#6237's ruled `FormSectionConfig` split to a parse refusal): on
27+
`type: 'wizard'`, a section `visibleWhen` (or its deprecated `visibleOn`
28+
alias), `collapsible: true`, or `collapsed: true` is now refused at parse with
29+
a prescription. Fix: remove the key — put visibility predicates on the fields
30+
inside the step, or use a `simple`/`tabbed` form for section-level
31+
visibility/collapsing. The same keys stay accepted on every non-wizard form
32+
type.
33+
- **A wizard must declare its steps**: `type: 'wizard'` with absent or empty
34+
`sections` is refused (it previously fell back to plain simple rendering,
35+
silently). Fix: declare at least one step — `sections: [{ label, fields }]`.
36+
The flattened runtime personalization overlay (a partial patch bound by
37+
`object` + `viewKind`) is deliberately exempt.
38+
- **`steps:` is refused with guidance, never accepted as an alias**: the
39+
unknown-key rejection now teaches the ruled spelling — sections ARE the steps,
40+
array order is step order.
41+
- **The ruled semantics are declared in the schema** (TSDoc + generated
42+
reference docs): the step gate is the default of `type: 'wizard'`; `allowSkip`
43+
is navigation freedom, not a validation exemption; the gate is UI admission,
44+
never authorization; progress is derived state with `showStepIndicator` the
45+
only authorable knob; per-step validation binds only the existing field-level
46+
vocabulary; array order is step order.
47+
48+
<!-- adr-0087: not-required (no-migration-prescription) A validity narrowing over existing keys: no key is removed, renamed or re-shaped, so there is no tombstone and nothing mechanical for `objectstack migrate meta` to rewrite. The parse refusal is the channel that reaches an affected author, at the parse site, carrying the remedy; whether an inert wizard-step `visibleWhen` meant "move it onto the fields" or "delete the leftover" is authoring intent no migration entry can decide on an upgrader's behalf — and the measured population of affected sources is zero in every corpus. Mirrors the disposition of the #11519 / #11842 ActionSchema narrowings. -->

content/docs/references/api/protocol.mdx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1674,8 +1674,8 @@ The published metadata item body, opaque by ruling (1C). Shape is the item's own
16741674
| **description** | `string` | optional | Form description |
16751675
| **defaultTab** | `string` | optional | Initially active tab (tabbed forms) |
16761676
| **tabPosition** | `Enum<'top' \| 'bottom' \| 'left' \| 'right'>` | optional | Tab strip position (tabbed forms) |
1677-
| **allowSkip** | `boolean` | optional | Allow skipping steps (wizard forms) |
1678-
| **showStepIndicator** | `boolean` | optional | Show the step indicator (wizard forms) |
1677+
| **allowSkip** | `boolean` | optional | Wizard step-gate opt-out: allow entering a later step without submitting the one before it. Navigation freedom, NOT a validation exemption — the final submit still re-validates every step and returns to the first failing one. Default (absent/false): steps unlock in array order as each prior step submits validly. UI admission only, never authorization. |
1678+
| **showStepIndicator** | `boolean` | optional | Show the wizard step indicator (renderer default: shown). Step progress (completed/current/upcoming/invalid) is derived from the step gate — this boolean is the only authorable progress surface. |
16791679
| **splitDirection** | `Enum<'horizontal' \| 'vertical'>` | optional | Split orientation (split forms) |
16801680
| **splitSize** | `number` | optional | Primary split panel size, % (split forms) |
16811681
| **splitResizable** | `boolean` | optional | Whether the split is resizable (split forms) |
@@ -1759,8 +1759,8 @@ The published metadata item body, opaque by ruling (1C). Shape is the item's own
17591759
| **description** | `string` | optional | Form description |
17601760
| **defaultTab** | `string` | optional | Initially active tab (tabbed forms) |
17611761
| **tabPosition** | `Enum<'top' \| 'bottom' \| 'left' \| 'right'>` | optional | Tab strip position (tabbed forms) |
1762-
| **allowSkip** | `boolean` | optional | Allow skipping steps (wizard forms) |
1763-
| **showStepIndicator** | `boolean` | optional | Show the step indicator (wizard forms) |
1762+
| **allowSkip** | `boolean` | optional | Wizard step-gate opt-out: allow entering a later step without submitting the one before it. Navigation freedom, NOT a validation exemption — the final submit still re-validates every step and returns to the first failing one. Default (absent/false): steps unlock in array order as each prior step submits validly. UI admission only, never authorization. |
1763+
| **showStepIndicator** | `boolean` | optional | Show the wizard step indicator (renderer default: shown). Step progress (completed/current/upcoming/invalid) is derived from the step gate — this boolean is the only authorable progress surface. |
17641764
| **splitDirection** | `Enum<'horizontal' \| 'vertical'>` | optional | Split orientation (split forms) |
17651765
| **splitSize** | `number` | optional | Primary split panel size, % (split forms) |
17661766
| **splitResizable** | `boolean` | optional | Whether the split is resizable (split forms) |

content/docs/references/ui/view.mdx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -403,8 +403,8 @@ Form-view select option — the object-field option shape minus the per-option `
403403
| **description** | `string` | optional | Form description |
404404
| **defaultTab** | `string` | optional | Initially active tab (tabbed forms) |
405405
| **tabPosition** | `Enum<'top' \| 'bottom' \| 'left' \| 'right'>` | optional | Tab strip position (tabbed forms) |
406-
| **allowSkip** | `boolean` | optional | Allow skipping steps (wizard forms) |
407-
| **showStepIndicator** | `boolean` | optional | Show the step indicator (wizard forms) |
406+
| **allowSkip** | `boolean` | optional | Wizard step-gate opt-out: allow entering a later step without submitting the one before it. Navigation freedom, NOT a validation exemption — the final submit still re-validates every step and returns to the first failing one. Default (absent/false): steps unlock in array order as each prior step submits validly. UI admission only, never authorization. |
407+
| **showStepIndicator** | `boolean` | optional | Show the wizard step indicator (renderer default: shown). Step progress (completed/current/upcoming/invalid) is derived from the step gate — this boolean is the only authorable progress surface. |
408408
| **splitDirection** | `Enum<'horizontal' \| 'vertical'>` | optional | Split orientation (split forms) |
409409
| **splitSize** | `number` | optional | Primary split panel size, % (split forms) |
410410
| **splitResizable** | `boolean` | optional | Whether the split is resizable (split forms) |
@@ -1795,8 +1795,8 @@ Tab configuration for multi-tab view interface
17951795
| **description** | `string` | optional | Form description |
17961796
| **defaultTab** | `string` | optional | Initially active tab (tabbed forms) |
17971797
| **tabPosition** | `Enum<'top' \| 'bottom' \| 'left' \| 'right'>` | optional | Tab strip position (tabbed forms) |
1798-
| **allowSkip** | `boolean` | optional | Allow skipping steps (wizard forms) |
1799-
| **showStepIndicator** | `boolean` | optional | Show the step indicator (wizard forms) |
1798+
| **allowSkip** | `boolean` | optional | Wizard step-gate opt-out: allow entering a later step without submitting the one before it. Navigation freedom, NOT a validation exemption — the final submit still re-validates every step and returns to the first failing one. Default (absent/false): steps unlock in array order as each prior step submits validly. UI admission only, never authorization. |
1799+
| **showStepIndicator** | `boolean` | optional | Show the wizard step indicator (renderer default: shown). Step progress (completed/current/upcoming/invalid) is derived from the step gate — this boolean is the only authorable progress surface. |
18001800
| **splitDirection** | `Enum<'horizontal' \| 'vertical'>` | optional | Split orientation (split forms) |
18011801
| **splitSize** | `number` | optional | Primary split panel size, % (split forms) |
18021802
| **splitResizable** | `boolean` | optional | Whether the split is resizable (split forms) |
@@ -1880,8 +1880,8 @@ Tab configuration for multi-tab view interface
18801880
| **description** | `string` | optional | Form description |
18811881
| **defaultTab** | `string` | optional | Initially active tab (tabbed forms) |
18821882
| **tabPosition** | `Enum<'top' \| 'bottom' \| 'left' \| 'right'>` | optional | Tab strip position (tabbed forms) |
1883-
| **allowSkip** | `boolean` | optional | Allow skipping steps (wizard forms) |
1884-
| **showStepIndicator** | `boolean` | optional | Show the step indicator (wizard forms) |
1883+
| **allowSkip** | `boolean` | optional | Wizard step-gate opt-out: allow entering a later step without submitting the one before it. Navigation freedom, NOT a validation exemption — the final submit still re-validates every step and returns to the first failing one. Default (absent/false): steps unlock in array order as each prior step submits validly. UI admission only, never authorization. |
1884+
| **showStepIndicator** | `boolean` | optional | Show the wizard step indicator (renderer default: shown). Step progress (completed/current/upcoming/invalid) is derived from the step gate — this boolean is the only authorable progress surface. |
18851885
| **splitDirection** | `Enum<'horizontal' \| 'vertical'>` | optional | Split orientation (split forms) |
18861886
| **splitSize** | `number` | optional | Primary split panel size, % (split forms) |
18871887
| **splitResizable** | `boolean` | optional | Whether the split is resizable (split forms) |
@@ -2155,8 +2155,8 @@ This schema accepts one of the following structures:
21552155
| **description** | `string` | optional | Form description |
21562156
| **defaultTab** | `string` | optional | Initially active tab (tabbed forms) |
21572157
| **tabPosition** | `Enum<'top' \| 'bottom' \| 'left' \| 'right'>` | optional | Tab strip position (tabbed forms) |
2158-
| **allowSkip** | `boolean` | optional | Allow skipping steps (wizard forms) |
2159-
| **showStepIndicator** | `boolean` | optional | Show the step indicator (wizard forms) |
2158+
| **allowSkip** | `boolean` | optional | Wizard step-gate opt-out: allow entering a later step without submitting the one before it. Navigation freedom, NOT a validation exemption — the final submit still re-validates every step and returns to the first failing one. Default (absent/false): steps unlock in array order as each prior step submits validly. UI admission only, never authorization. |
2159+
| **showStepIndicator** | `boolean` | optional | Show the wizard step indicator (renderer default: shown). Step progress (completed/current/upcoming/invalid) is derived from the step gate — this boolean is the only authorable progress surface. |
21602160
| **splitDirection** | `Enum<'horizontal' \| 'vertical'>` | optional | Split orientation (split forms) |
21612161
| **splitSize** | `number` | optional | Primary split panel size, % (split forms) |
21622162
| **splitResizable** | `boolean` | optional | Whether the split is resizable (split forms) |
@@ -2341,8 +2341,8 @@ This schema accepts one of the following structures:
23412341
| **description** | `string` | optional | Form description |
23422342
| **defaultTab** | `string` | optional | Initially active tab (tabbed forms) |
23432343
| **tabPosition** | `Enum<'top' \| 'bottom' \| 'left' \| 'right'>` | optional | Tab strip position (tabbed forms) |
2344-
| **allowSkip** | `boolean` | optional | Allow skipping steps (wizard forms) |
2345-
| **showStepIndicator** | `boolean` | optional | Show the step indicator (wizard forms) |
2344+
| **allowSkip** | `boolean` | optional | Wizard step-gate opt-out: allow entering a later step without submitting the one before it. Navigation freedom, NOT a validation exemption — the final submit still re-validates every step and returns to the first failing one. Default (absent/false): steps unlock in array order as each prior step submits validly. UI admission only, never authorization. |
2345+
| **showStepIndicator** | `boolean` | optional | Show the wizard step indicator (renderer default: shown). Step progress (completed/current/upcoming/invalid) is derived from the step gate — this boolean is the only authorable progress surface. |
23462346
| **splitDirection** | `Enum<'horizontal' \| 'vertical'>` | optional | Split orientation (split forms) |
23472347
| **splitSize** | `number` | optional | Primary split panel size, % (split forms) |
23482348
| **splitResizable** | `boolean` | optional | Whether the split is resizable (split forms) |

0 commit comments

Comments
 (0)