Repository navigation
Commit 05ab9ef
feat(spec)!: the page parse refuses a component data prop naming the retired view-level api source, at every door that parses a page (#23419)
Fixes #23357
Clause-②: yes (narrowing)
> The seat amended the claim to `yes (narrowing)` at ACCEPT because of
the one published export, `checkPageComponentViewData`.
## What changes
The page parse now refuses a page component's `data` prop that names the
retired view-level `api` data source, as a view's own `data` is refused.
That is triage's runtime half of this card (grade `6159116611`): the
narrow judge for `ViewDataSchema` at a component's `data`, enforced at
every door that parses a page. It is not the component-props gate's
runtime rollout, which stays as decided.
- **`packages/spec/src/ui/page.zod.ts`**: a fifth `PageSchema`
object-level check, `checkPageComponentViewData`, attached by identifier
like its four siblings. For a component of a type whose `data` is a view
data source (`object-grid`, `object-map`, `object-gantt`, `object-tree`)
whose `properties.data` names the retired provider, it raises the
prescription `ViewDataSchema`'s own parse raises, located at the
component's `properties.data.provider` (code `custom`, the code of every
object-level check on this schema). The prescription is read off
`ViewDataSchema`'s issue, not copied. It walks every component under
`regions` and `slots` at any depth, a component nested in a `page:tabs`
item or a container included.
- **`packages/spec/src/conversions/refused-shapes.ts`**: the stored
listing's fate for such a component now says what happens: the parse
refuses the page; it still loads and is served, registered under
`[metadata_spec_invalid]` with the refusal in every read's
`_diagnostics`; its next save is refused with 422.
-
**`packages/spec/src/migrations/entries/semantic/18.view-data-api-provider-retired.ts`**:
the acceptance criteria name the page parse, at every door that parses a
page, beside the component-props gate.
- `view.zod.ts`: a comment pointing from the retirement's prescription
to the page check. Generated: `api-surface/ui.json`,
`export-origins/ui.json` (the one new export).
**The renderer half is objectstack-ai/objectui#12325, which remains
open:** until objectui deletes its reader of the retired arm, a page
already stored with such a component keeps sending the request.
## Measured (mechanism hypotheses)
- **H1, half falsified.** `view.zod.ts` refuses the arm through the
discriminated union's `error` map: `invalid_union` at `provider`,
message `VIEW_DATA_API_PROVIDER_RETIRED`. `page.zod.ts` does NOT parse a
component's `data`: `properties` is `z.record(z.string(), z.unknown())`,
and on `origin/main` `PageSchema.safeParse` of an `app` page whose
`object-grid` binds the retired provider answered `success: true`.
- **H2, holds.** The save door's schema is
`getMetadataTypeSchema('page')`, which is `PageSchema` by identity
(`resolveOverlaySchema`, `protocol.ts`). Measured through the real
`saveMetaItem` in `protocol.save-union-issues.test.ts`: `422
INVALID_METADATA`, nothing persisted, issue at
`regions.0.components.0.properties.data.provider`, code `custom`, the
prescription. `metadata-protocol/src/protocol.ts` is untouched.
- **H3, the four, and only by declaration.** Derived from
`ComponentPropsMap` by def identity, the rows whose `data` member is
`ViewDataSchema` are exactly `object-grid`, `object-map`,
`object-gantt`, `object-tree` (59 rows; `object-kanban`,
`object-calendar`, `object-timeline` take a row array). The page check
cannot derive that set itself: `component.zod.ts` imports `page.zod.ts`,
`packages/spec/src` has zero import cycles (measured: 1383 modules, 0
strongly connected components), and moving `ElementDataSourceSchema` /
`RETIRED_PAGE_COMPONENT_TYPES` out of `page.zod.ts` would change the
published skill's generated references. So the set is declared in
`page.zod.ts` (the `PRINT_REFUSED_PAGE_COMPONENT_TYPES` precedent) and
pinned equal to the derivation in both directions
(`page-component-view-data.test.ts`: for every props row, the page parse
refuses the binding exactly when the row's `data` is `ViewDataSchema`).
The same cycle keeps `pageComponentSlotPositions()` out of reach, so the
walk descends every object under `regions` and `slots`, a superset of
every slot position: it reaches no less than `os migrate meta --stored`
lists or the props gate judges, and what it judges at a node stays the
one retired binding on those four types.
- **H4, stored pages load and are listed; their next save is refused.**
Boot hydration (`loadMetaFromDb`, measured with a throwaway probe over a
stub engine, not committed): two stored pages, one bound to the retired
provider: `{"loaded":2,"errors":0,"invalid":1}`, both registered, one
`[metadata_spec_invalid]` warning naming `page/partner_page` and the
prescription. Read path (`getMetaItem`, pinned): served, with
`_diagnostics.valid: false` and the prescription at the component's
position. The fate text states exactly that.
## Tests
Every run went through `scripts/pm/os-verify-lock.sh`. Final verdicts
are at `63e1e4800`, the branch merged with `origin/main` `c857a93ee`.
The newest head, `dce543307`, adds only the changeset's `Clause-②` line.
- `@objectstack/spec`, `vitest run --project local`: 675 files, 20507
passed, 1 todo, exit 0.
- `@objectstack/spec`, `--project repo`: 59 files, 1011 passed, exit 0.
This project holds the tree-scoped absence pin.
- `@objectstack/metadata-protocol`: 235 files passed, 3 skipped; 28377
tests passed, exit 0.
- `@objectstack/cli`, `--project unit`: 287 files, 4307 tests passed,
exit 0.
- `@objectstack/lint`: 138 files, 6699 tests passed, exit 0, at
`7309ef08c`. The later merge touched nothing in `packages/lint`.
- `typecheck` of spec and of metadata-protocol: exit 0 each.
- `pnpm --filter @objectstack/spec check:generated`: all 14 artifacts up
to date.
New pins:
- `packages/spec/src/ui/page-component-view-data.test.ts`:
- each of the four types is refused at
`regions.0.components.0.properties.data.provider` with the retirement's
exact message;
- a nested component, a container's grandchild and a slot are each
refused at their own position;
- `definePage`, `getMetadataTypeSchema('page')` and the stack parse all
refuse;
- controls: `object`, `value`, `schema`, no `data`, another provider,
`object-kanban`, a custom type and the element `dataSource` binding are
accepted;
- a derivation pin over all 59 `ComponentPropsMap` rows.
- `object-refinement-check-exports.test.ts`: the fifth export's parity,
count, attachment and barrel legs.
- `refused-shapes.test.ts`: the new fate text, and the page parse
refuses exactly the positions the listing lists.
- `protocol.save-union-issues.test.ts`:
- `422 INVALID_METADATA` with nothing persisted, top-level and nested;
- control saves with `object` and `value` (one row each);
- the read path serves a stored page with `_diagnostics.valid: false`
and the prescription.
Not run locally, and declared to CI:
- the cli integration layer: the diff touches no integration file and no
spawn entry;
- the full `turbo ls --affected` closure, 83 packages. That set comes
from the package dependency graph and is blind to tests that read
another package's source from disk. The root package's own suites are
not on the graph.
## Ablation (negative control)
Run on `7309ef08c` through `scripts/ablation-replace.mjs`, which mutates
and restores and proves both on disk, and
`scripts/ablation-dist-preflight.mjs`.
1. **Pristine.** The dist marker
`superRefine(checkPageComponentViewData))` is present in 18 built JS
files, and the tree is clean.
2. **Mutate.** The attachment
`.superRefine(checkPageComponentViewData));` is replaced by an inert
comment. The anchor count goes 1 to 0, and the blob goes `ed11df9efb60`
to `b310419cea20`.
- The spec source suites go red: 3 files, 17 failed, 268 passed. They
are the four type pins, nested/slot, doors, self-reference, the
derivation pin, the export parity/count/attachment legs, and the two
refused-shapes parity pins.
- After the spec rebuild, the preflight reads the marker absent from all
232 built files.
- `protocol.save-union-issues.test.ts` goes red: 3 failed, 26 passed.
They are the two 422 pins and the read path. The control save stays
green.
3. **Restore.** The blob equals HEAD, `git diff HEAD` is empty and the
whole-tree status is clean. After the spec rebuild, the marker is
present in 18 files and the tree is clean. Spec runs 285/285 and
metadata-protocol 29/29.
The expected direction: the pins turn red.
Two earlier attempts carry no reading:
- The first was a no-op. The tool refused it because the replacement
`);` already occurred in the file, so the mutation never landed.
- The second used a dist marker that the `.d.ts` docblock also carries,
so its dist reading was void. It was re-run as above, with a marker only
the runtime JS carries.
## Gates
`node scripts/pm/dispatch-gates.mjs --ran` on `7309ef08c` reports 90
derived families, all accounted for. 88 exited 0, including
`check:adr-0087-registration --base origin/main`, `check:api-surface`,
`check:generated` (all 14 artifacts up to date), `check:skill-refs`,
`check:doc-authoring`, `check:engine-double-contract`,
`check:nul-bytes`, `check:lean-entry-closure` and
`check:cross-package-test-inputs`.
NOT MEASURED:
- `check:dual-build-cjs-loads`: exit 3, PREREQUISITE NOT MET. 9 packages
outside this card's build closure have no `dist/`.
- `check:type-check-debt`: its re-measure re-runs `tsc` over every
DEBT-ledger package repo-wide, which CI owns. The touched packages' own
`typecheck` runs are green.
Repo-wide `pnpm lint` was not run locally. CI owns it.
## Acceptance notes
- One published export added (`checkPageComponentViewData`), required by
`object-refinement-check-exports.test.ts` for every object-level
`PageSchema` check so a `.shape` mirror can re-attach it; see the
`Clause-②` note at the top.
- The page check's issue code is `custom`, not the view's
`invalid_union`: the object-level-check pin reads `custom` as the code
of every check on the schema. The message is the retirement's, byte for
byte.
- ADR-0087: `not-required (already-registered
view-data-api-provider-retired)`; `check-adr-0087-registration` accepts
it.
- Consumer sweep: `examples/**` holds no `provider: 'api'` (0 hits;
control `provider: 'object'` hits in `examples/app-crm/src/views`); the
tree-scoped absence pin (`view-data-api-provider-retirement.test.ts`) is
green, and every fixture here spells the provider through a constant.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01YRp5z4kK6vgYkrdH97ztsy)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 61b1258 commit 05ab9ef
11 files changed
Lines changed: 493 additions & 17 deletions
File tree
- .changeset
- packages
- metadata-protocol/src
- spec
- api-surface
- export-origins
- src
- conversions
- migrations/entries/semantic
- ui
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
491 | 491 | | |
492 | 492 | | |
493 | 493 | | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
| 507 | + | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
| 557 | + | |
| 558 | + | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
| 567 | + | |
| 568 | + | |
| 569 | + | |
| 570 | + | |
| 571 | + | |
| 572 | + | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
496 | 496 | | |
497 | 497 | | |
498 | 498 | | |
| 499 | + | |
499 | 500 | | |
500 | 501 | | |
501 | 502 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
481 | 481 | | |
482 | 482 | | |
483 | 483 | | |
| 484 | + | |
484 | 485 | | |
485 | 486 | | |
486 | 487 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
360 | 360 | | |
361 | 361 | | |
362 | 362 | | |
363 | | - | |
| 363 | + | |
| 364 | + | |
364 | 365 | | |
365 | 366 | | |
366 | 367 | | |
| |||
374 | 375 | | |
375 | 376 | | |
376 | 377 | | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
377 | 384 | | |
378 | 385 | | |
379 | 386 | | |
| |||
414 | 421 | | |
415 | 422 | | |
416 | 423 | | |
417 | | - | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
418 | 430 | | |
419 | | - | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
| 439 | + | |
| 440 | + | |
| 441 | + | |
420 | 442 | | |
421 | 443 | | |
422 | 444 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
35 | 35 | | |
36 | 36 | | |
37 | 37 | | |
38 | | - | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
39 | 41 | | |
40 | 42 | | |
41 | 43 | | |
| |||
205 | 207 | | |
206 | 208 | | |
207 | 209 | | |
208 | | - | |
| 210 | + | |
209 | 211 | | |
210 | 212 | | |
211 | 213 | | |
212 | 214 | | |
213 | 215 | | |
214 | 216 | | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
215 | 222 | | |
216 | 223 | | |
217 | 224 | | |
| |||
237 | 244 | | |
238 | 245 | | |
239 | 246 | | |
240 | | - | |
241 | | - | |
242 | | - | |
243 | | - | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
244 | 252 | | |
245 | 253 | | |
246 | 254 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
37 | 37 | | |
38 | 38 | | |
39 | 39 | | |
40 | | - | |
41 | | - | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
42 | 43 | | |
43 | 44 | | |
44 | 45 | | |
| |||
0 commit comments