You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit a35f7a6
Browse filesBrowse the repository at this point in the historyBrowse files
feat(spec)!: delete checkPageComponentViewData; the component-props rule is the one judge of a page component's retired api data binding (#23784)
Fixes#23447
Clause-②: yes
Ruling `6161173492` on #23388, item 6, verbatim:
> 6. #23357's narrow judge proceeds as triaged and does not wait. Once
this PR lands, that judge overlaps the general rule and is deleted (one
operation, two implementations: the governed side wins), in #23357's PR
if it is still open, else in a one-line follow-up.
PR #23418 (`d0c09e47c1`) put `validateComponentProps` on the runtime
save door for `page` writes. This PR deletes the page-parse judge that
duplicated it, rewrites the sentences that became false, and re-pins the
save door on the props rule.
## What changes
1. **The narrow judge is deleted** (`packages/spec/src/ui/page.zod.ts`):
`checkPageComponentViewData`, `VIEW_DATA_SOURCE_COMPONENT_TYPES`, their
docblocks, the `.superRefine` on `PageSchema`, and the now-unused
`ViewDataSchema` import. The published export leaves
`@objectstack/spec/ui`; `api-surface/ui.json` and
`export-origins/ui.json` were regenerated with `check:generated --fix`
(one line each). `page-component-view-data.test.ts` is deleted, since
its subject is gone. Its reach and control cases move to the save-door
pins below, which run the real rule. In
`object-refinement-check-exports.test.ts` the judge's fixtures and rows
are removed, and absence pins (0 declarations, 0 attachments, not in the
barrel) follow the `checkListViewPageMount` precedent.
2. **Sentences rewritten:**
- the `refused-shapes.ts` docblocks and `COMPONENT_API_BINDING_FATE`,
with their tests;
- `18.view-data-api-provider-retired.ts` `acceptanceCriteria`;
- `18.ui-page-action-row-declarative-update-rules.ts` `reason`;
- the `validate-component-props.ts` header ("does not run this rule" at
the runtime publish door);
- the `view.zod.ts` comment;
- the `PageSchema` trailing comment ("five checks" is now four).
3. **The stored-page fate was measured before it was rewritten** (table
below). The new fate text says what was measured: the page loads and is
served with no read diagnostic, and its next save is refused by the
props rule.
4. **Pins**
(`packages/metadata-protocol/src/protocol.runtime-authoring-gate.test.ts`,
new describe after the #23388 block). They run the real `saveMetaItem` /
`loadMetaFromDb` / `getMetaItem` path:
- each of `object-grid`, `object-map`, `object-gantt` and `object-tree`
→ `422 INVALID_METADATA`, `rulesRun` contains `validateComponentProps`,
one `component-props-invalid` issue carrying the prescription at
`pages[0].regions[0].components[0].properties.data.provider`, nothing
stored;
- reach: a `page:tabs` item, a component nested in `flex` › `page:card`,
and a slot;
- control: `provider: 'object'` and `provider: 'value'` save, one row
each;
- stored page: `loadMetaFromDb` → `loaded: 1, errors: 0, invalid: 0`,
the page is registered, no `metadata_spec_invalid` warning,
`getMetaItem` serves it as stored with `_diagnostics.valid: true`, its
next save is refused by the props rule with the row unchanged, and the
fixed page saves.
- The old `#23357` block in `protocol.save-union-issues.test.ts` (a
spec-parse `custom` issue, plus a read-path `_diagnostics.valid: false`
pin, which is now false) is removed.
## Each door, before and after (measured)
| door | before (`29c7157af4`) | after |
| --- | --- | --- |
| `PageSchema.safeParse` / `definePage` / `defineStack` | refused:
`custom` at `regions.0.components.0.properties.data.provider` (and at
each nested and slot position) | **accepted**: these doors run no lint
rule. This is the ruling's expected consequence. No equivalent check was
added to spec. |
| `os validate` (built CLI, `defineStack` config) | exit 1: `defineStack
validation failed` with the prescription | exit 1:
`component-props-invalid at
pages[0].regions[0].components[0].properties.data.provider` with the
prescription; the control config (`provider: 'object'`) passes, exit 0 |
| `os build` | exit 2: refused inside `defineStack` | exit 1: the same
`component-props-invalid` finding; control exit 0 |
| save door `saveMetaItem` | 422 `INVALID_METADATA`, `failed spec
validation`, issue `code: custom`, no `rulesRun` | 422
`INVALID_METADATA`, `failed author-time validation`, rule
`component-props-invalid`, `rulesRun` contains `validateComponentProps`,
nothing stored |
| boot `loadMetaFromDb` | `loaded: 1, errors: 0, invalid: 1`,
`[metadata_spec_invalid]` warning | `loaded: 1, errors: 0, invalid: 0`,
registered, no warning |
| read `getMetaItem` | served, `_diagnostics.valid: false` with the
refusal at the component | served as stored, `_diagnostics.valid: true`
|
Rule-level reach, the same before and after (the probe ran
`validateComponentProps` on 10 page bodies, with identical output on
both trees): one finding per binding on all four types, the bare `{
provider }`, a `page:tabs` item, `flex` › `page:card` › component,
`slots.details` and `slots.header[0]`. No finding on the `object` and
`value` controls or on a custom type. An `object-kanban` carrying the
binding draws `component-props-invalid` at `properties.data` (`expected
array`), which is its own row's verdict, as before.
## Merge with main
`origin/main` `43567a8f` (PR #23708, PR #23800 included) was merged in
at `4087b452`, through `scripts/pm/os-regen-merge.sh`:
- `packages/spec/src/ui/page.zod.ts`: Conflict at the PageSchema
superRefine chain. Kept main's checkPageDefaultPlacement and
checkPageRegionPlacement (PR #23708, #23610 ruling A), dropped the
deleted checkPageComponentViewData. The trailing comment reads 'the six
checks above', and the props-bag sentence stays.
- `packages/spec/src/ui/object-refinement-check-exports.test.ts`: 5
hunks: main's side in each, minus every checkPageComponentViewData line,
i.e. the import, the view-data fixture block (main's #23610 fixtures
kept), the MIRRORED row and the barrel row. The leg-3 'declares all six
exports' loop names the 4 old checks plus the 2 new ones. This PR's
0-declaration, 0-attachment and barrel-absence pins are kept.
- `packages/spec/api-surface/ui.json,
packages/spec/export-origins/ui.json`: os-regen driver, not text-merged.
Step 2 took main's side, the merge commit was the deferral, then rebuild
+ gen:api-surface + gen:export-origins on the merged tree, committed as
392224e. The deferral was discharged. Delta vs origin/main: exactly one
removed line in each (checkPageComponentViewData). main's 9 new ui
exports are present.
-
`packages/spec/src/migrations/entries/semantic/18.ui-page-action-row-declarative-update-rules.ts`:
No conflict: PR #23800 left this line to this PR. Aligned with #23800's
wording precedent: '... the load path runs no such gate, so a stored
page still loads and its next save meets the component-props gate at the
metadata save door.'
## DELIBERATE CORRECTION
File: `.changeset/pre/23357-page-component-view-data-api-refused.md`,
commit `7c25be0a`. `18.0.0-next.2` consumed the note, and the 18.0.0 GA
entry is compiled from `.changeset/pre/` again (`release.yml`: "On `pre
exit` the GA version consumes them all again"). This PR makes the
following sentences false, and each is rewritten in place, measured
against this PR's head:
1. Title: "the page parse refuses …" → "a page component's `data` prop
that names the retired view-level `api` data source is refused at the
Studio, REST and MCP save door as `os validate` refuses it".
2. BREAKING paragraph: "is now refused by `PageSchema`" and "the
component-props gate … runs at the CLI doors only" → the props gate
(`validateComponentProps`, rule `component-props-invalid`) refuses it at
`os validate`, `os build`, `os lint` and the metadata save door. The
CLI-only fact now reads as history: "before 18".
3. Judge paragraph: "raised by the page parse unchanged (… `code` is
`custom` …)" → the props row parses `data` with `ViewDataSchema`, and
the finding carries that schema's prescription. The row-array types are
refused for their shape, not with this prescription. The
`checkPageComponentViewData` … re-attach sentence is deleted.
4. FROM → TO header: "(accepted by the page parse until this change)" →
"(saved by the Studio, REST and MCP door before 18)".
5. "`definePage()`, `defineStack({ pages })` … refuse the page" → `os
validate` / `os build` / `os lint` and `PUT /api/v1/meta/page/:name`
refuse it; `definePage()` and `defineStack({ pages })` run no authoring
rule and accept it.
6. Stored page: "registered under `[metadata_spec_invalid]` with the
refusal in the `_diagnostics` of every read" → served as stored, with no
read diagnostic for the binding; the next save is refused with 422 by
the props gate. objectui#12325 is now in the console pin, so the
sentence changes from "until then a stored page keeps sending it" to "so
a stored page does not send the request".
7. ADR-0087 marker reason: "makes the page parse refuse …" → "the
component-props gate refuses what that entry retired at the CLI doors
and the save door"; the disposition token itself is unchanged.
Authority: the maintainer's 「同意」, recorded in `6210183493`, as applied
by `6210987382` (which supersedes `6210952492`), with PR #23418's
`6203578381` as the precedent. `packages/spec/CHANGELOG.md` is
untouched. `Check Changeset` reds by design on this edit
(`check-empty-changeset`: DELIBERATE CORRECTION class); it is not a
required context and runs only on `pull_request`.
## Verification
- **Final head `7c25be0a`** (rounds after the merge). `dispatch-gates
--commands`: 90 derived, 89 run, 1 NOT-MEASURED
(`check:dual-build-cjs-loads`, left to CI). 88 exit 0, plus
`check-empty-changeset` exit 1, by design, for the DELIBERATE CORRECTION
class. `check-adr-0087-registration` and `check-changeset-no-major` exit
0. On `39977e95`: spec 682 files / 20873 tests, lint 140 files / 6781,
metadata-protocol pin files 170/170, typechecks exit 0. On `40624b32`:
`refused-shapes.test.ts` + `object-refinement-check-exports.test.ts`
284/284, `check:generated` and `check:doc-authoring` exit 0. `7c25be0a`
adds only the changeset text.
- **Round 1** (before the merge):
- Ablation of the general rule's runtime face:
`validateComponentProps`'s entry was set to `surfaces: ['cli']` with
`runtimeTypes` removed (through `scripts/ablation-replace.mjs`).
`@objectstack/lint` was rebuilt, and `ablation-dist-preflight` found the
marker in 4 built files. Result: the 6 refusal pins went red and the
control stayed green. On restore, the blob matched the HEAD hash, the
rebuild passed `--absent` with a clean tree, and the whole file is green
at 145/145.
- `@objectstack/metadata-protocol`: `pnpm test`, 236 files and 20580
tests passed; `pnpm typecheck` exit 0.
- `@objectstack/spec`: full `pnpm test` showed one failure (a missed
`#23357` half in `refused-shapes.test.ts`), which is fixed. Re-run:
`refused-shapes.test.ts` and `object-refinement-check-exports.test.ts`
250/250, and `pnpm typecheck` exit 0.
- `@objectstack/lint`: `pnpm test`, 139 files and 6771 tests passed;
`pnpm typecheck` exit 0.
- `check:generated`: 2 artifacts were stale (`api-surface`,
`export-origins`) and were regenerated; the other 12 were up to date.
- `check:adr-0087-registration`: `[BREAKING+bang+clause-②-narrowing]
not-required (already-registered)`.
- The derived gate families (`dispatch-gates --commands`, 90 commands)
were run locally; their results are in the report comment on #23447.
## Acceptance notes
- **The rest of the family is closed.** PR #23418 made the stale
save-half sentences false. PR #23800 (#23789) rewrote them and landed
before this PR merged `main`. The one line it left for this PR, in
`18.ui-page-action-row-declarative-update-rules.ts`, now follows
#23800's wording.
- **The 23357 note** had been consumed by `18.0.0-next.2` into
`.changeset/pre/`, and the 18.0.0 GA entry is compiled from there again.
It is corrected in place: see `## DELIBERATE CORRECTION`. The published
`packages/spec/CHANGELOG.md` entry is untouched.
- **`@objectstack/lint: patch` was dropped** from this PR's changeset.
The lint diff is the file-top comment of `validate-component-props.ts`,
and no changeset gate asks for it.
- **`COMPONENT_API_BINDING_FATE`** (`refused-shapes.ts`) now says the
console no longer reads the retired arm. objectui#12325 has been in the
console pin since PR #23709 (`53e3638e`).
- **The `_diagnostics` field is not absent** after the change: it reads
`valid: true`, and the pin asserts that.
---
_Generated by [Claude
Code](https://claude.ai/code/session_016QpnMQNQ3TQ8mvWiHJwN2j)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
feat(spec)!: `checkPageComponentViewData` is deleted; a page component's `data` prop naming the retired view-level `api` source is refused by the component-props rule alone, at the CLI doors and the metadata save door (#23447)
6
+
7
+
**BREAKING** — `checkPageComponentViewData` is no longer exported from `@objectstack/spec/ui`, and `PageSchema` no longer carries it. Since the component-props rule (`validateComponentProps`, `@objectstack/lint`) runs on a `page` write at the metadata save door, it and the page-parse check judged the same binding at the same door: one operation with two implementations. The governed side stays. The props rule parses the component's `properties` against the type's `ComponentPropsMap` row, and that row's `data` is `ViewDataSchema`, so it raises the retirement's own prescription on the same four types (`object-grid`, `object-map`, `object-gantt`, `object-tree`), at the same positions: regions, `page:tabs` items, nested containers and slots.
8
+
9
+
Clause-②: yes (narrowing)
10
+
11
+
What narrows: the published export leaves `@objectstack/spec/ui`. What `PageSchema` accepts widens by this one shape, a component `data` naming the retired provider, which the props rule then refuses at every door that runs it.
12
+
13
+
## FROM → TO
14
+
15
+
| you wrote | write instead |
16
+
| --- | --- |
17
+
|`import { checkPageComponentViewData } from '@objectstack/spec/ui'`, and `.superRefine(checkPageComponentViewData)` on a mirror built from `PageSchema.shape`| nothing on the mirror: a page component's `properties` is judged by `validateComponentProps` from `@objectstack/lint` (or `runAuthoringRules`), against the stack that carries the page |
18
+
| a page component's `properties.data` with `provider: 'api'`| unchanged from the step-18 retirement: `provider: 'object'` with `object`, or `provider: 'value'` with `items`; an endpoint read moves onto the component's `dataSource: { provider: 'api', read: { url: '/api/...' } }`|
19
+
20
+
**The one-line fix:** drop the import and the re-attachment; run the props rule where you need the verdict.
21
+
22
+
**Which doors refuse the binding now, measured:**
23
+
24
+
| door | before | after |
25
+
| --- | --- | --- |
26
+
|`definePage()`, `defineStack({ pages })`, `PageSchema.safeParse`| refused, `custom` at `…properties.data.provider`| accepted (these doors run no lint rule) |
27
+
|`os validate`, `os build`| refused inside `defineStack`| refused by the props rule: `component-props-invalid` at `pages[0].regions[0].components[0].properties.data.provider`, with the prescription |
28
+
| metadata save door (`PUT /api/v1/meta/page/:name`, the Studio, MCP) |`422 INVALID_METADATA`, spec-parse issue `custom`|`422 INVALID_METADATA`, rule `component-props-invalid` at the same component, with the prescription; nothing stored |
29
+
| boot (`loadMetaFromDb`) |`invalid: 1`, registered under `[metadata_spec_invalid]`|`invalid: 0`, registered, no warning |
30
+
| read (`getMetaItem`) | served, `_diagnostics.valid: false` with the refusal | served as stored, `_diagnostics.valid: true`|
31
+
32
+
**A page already stored with such a component** still loads and is served as stored, and no longer carries a read diagnostic for the binding; its next save is refused with 422 by the props rule. `os migrate meta --stored` still lists it under the step-18 entry `view-data-api-provider-retired`, and that entry's fate text now says so.
33
+
34
+
<!-- adr-0087: not-required (already-registered view-data-api-provider-retired) the retirement this check enforced is that step-18 entry; this change deletes the second implementation of its page-component half, and the entry's acceptance criteria now name the component-props gate at the CLI doors and the save door as the one judge -->
Copy file name to clipboardExpand all lines: .changeset/pre/23357-page-component-view-data-api-refused.md
+7-7Lines changed: 7 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,25 +2,25 @@
2
2
'@objectstack/spec': minor
3
3
---
4
4
5
-
feat(spec)!: the page parse refuses a page component's `data` prop that names the retired view-level `api` data source, so the Studio, REST and MCP save door refuses it as `os validate`does (#23357)
5
+
feat(spec)!: a page component's `data` prop that names the retired view-level `api` data source is refused at the Studio, REST and MCP save door as `os validate`refuses it (#23357)
6
6
7
-
**BREAKING** — a page whose `object-grid`, `object-map`, `object-gantt` or `object-tree` component carries `properties.data` with `provider: 'api'` is now refused by `PageSchema`, at the component's `properties.data.provider`, with the retirement's own prescription. Those four components take a view data source (`ViewDataSchema`) as `data`, so the step-18 retirement of the view-level `api` source reached them through the same schema; but the page parse leaves a component's `properties` an open record, and the component-props gate that refused the binding runs at the CLI doors only. A page saved through the Studio, REST or MCP therefore kept the binding, with its request headers, and the console kept sending it.
7
+
**BREAKING** — a page whose `object-grid`, `object-map`, `object-gantt` or `object-tree` component carries `properties.data` with `provider: 'api'` is refused at the component's `properties.data.provider`, with the retirement's own prescription, by the component-props gate (`validateComponentProps`, `@objectstack/lint`, rule `component-props-invalid`) at `os validate`, `os build`, `os lint` and the metadata save door. Those four components take a view data source (`ViewDataSchema`) as `data`, so the step-18 retirement of the view-level `api` source reached them through the same schema. The page parse leaves a component's `properties` an open record, and before 18 the component-props gate ran at the CLI doors only, so a page saved through the Studio, REST or MCP kept the binding, with its request headers, and the console kept sending it.
8
8
9
9
Clause-②: yes (narrowing)
10
10
11
-
The judge is the retirement's own: `ViewDataSchema` parses the component's `data`, and the prescription it raises is raised by the page parse unchanged (one text for a view and a page; the page's issue `code` is `custom`, as every object-level check on `PageSchema` raises). It reaches every component under `regions` and `slots`, at any depth, a component nested in a `page:tabs` item or a container included. It judges nothing else in the bag: another `data` provider, a component whose `data` is a row array (`object-kanban`, `object-calendar`, `object-timeline`), a custom or registered type with no props row, and a component's own `dataSource` binding are untouched. `checkPageComponentViewData`is exported from `@objectstack/spec/ui`, like the four other `PageSchema` checks, so a mirror built from `PageSchema.shape` can re-attach it.
11
+
The judge is the retirement's own: the component's `ComponentPropsMap` row parses its `data` with `ViewDataSchema`, and the finding carries that schema's prescription unchanged, one text for a view and a page. It reaches every component under `regions` and `slots`, at any depth, a component nested in a `page:tabs` item or a container included. Only those four types meet this prescription: a component whose `data` is a row array (`object-kanban`, `object-calendar`, `object-timeline`) is judged by its own row and refused for its shape, a custom or registered type with no props row is not judged, and a component's own `dataSource` binding is untouched.
12
12
13
13
## FROM → TO
14
14
15
-
| you wrote (accepted by the page parse until this change) | write instead |
15
+
| you wrote (saved by the Studio, REST and MCP door before 18) | write instead |
16
16
| --- | --- |
17
17
|`properties.data` with `provider: 'api'` (and its `read` / `write` request blocks) on an `object-grid`, `object-map`, `object-gantt` or `object-tree` page component |`properties.data` with `provider: 'object'` and `object: '<object_name>'`, or `provider: 'value'` with `items: [...]`; an endpoint the page must read is a page component's `dataSource: { provider: 'api', read: { url: '/api/...' }, path? }`, same-origin and with no credential key |
18
18
|`read.headers: { Authorization: '...' }` inside that binding | nothing: a credential never lives in metadata, and the console reads an element binding with its own signed-in fetch |
19
19
20
20
**The one-line fix:** bind each such component to its object or to static rows, and move any endpoint read onto a page component's `dataSource`.
21
21
22
-
**What an author who still writes it sees.**`definePage()`, `defineStack({ pages })`, `os validate` and `PUT /api/v1/meta/page/:name` refuse the page at `regions[i].components[j].properties.data.provider` (or the nested or slot position)with the prescription. At the save door that is `422 INVALID_METADATA`, nothing persisted.
22
+
**What an author who still writes it sees.**`os validate`, `os build`, `os lint` and `PUT /api/v1/meta/page/:name` refuse the page at `pages[i].regions[j].components[k].properties.data.provider` (or the nested or slot position), rule `component-props-invalid`, with the prescription. At the save door that is `422 INVALID_METADATA`, nothing persisted. `definePage()` and `defineStack({ pages })` run no authoring rule and accept the page.
23
23
24
-
**A page already stored with such a component.**`os migrate meta --stored` lists it by page and component (the step-18 entry `view-data-api-provider-retired`), and nothing rewrites it: deleting `data` would make the component query its object instead. Left as stored, the page still loads and is served, registered under `[metadata_spec_invalid]`with the refusal in the `_diagnostics` of every read, and its next save is refused with 422. The console stops sending the request when its own reader of the retired arm is deleted (objectstack-ai/objectui#12325); until then a stored page keeps sending it.
24
+
**A page already stored with such a component.**`os migrate meta --stored` lists it by page and component (the step-18 entry `view-data-api-provider-retired`), and nothing rewrites it: deleting `data` would make the component query its object instead. Left as stored, the page still loads and is served as stored, with no read diagnostic for the binding, and its next save is refused with 422 by the component-props gate. The console no longer reads the retired arm (objectstack-ai/objectui#12325), so a stored page does not send the request.
25
25
26
-
<!-- adr-0087: not-required (already-registered view-data-api-provider-retired) the step-18 entry already names the data prop of these four page components in its scope; this change makes the page parse refuse what that entry retired, and its acceptance criteria now name the page parse beside the component-props gate -->
26
+
<!-- adr-0087: not-required (already-registered view-data-api-provider-retired) the step-18 entry already names the data prop of these four page components in its scope; the component-props gate refuses what that entry retired at the CLI doors and the save door, and its acceptance criteria name that gate -->
0 commit comments