Repository navigation
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
Conversation
…e retired view-level api provider A page component whose `data` prop is a view data source (object-grid, object-map, object-gantt, object-tree) is judged by `PageSchema` through the retirement's own judge, `ViewDataSchema`: the `invalid_union` issue it raises at `provider` is raised unchanged at the component's `properties.data.provider`, at any depth under `regions` and `slots`. Claude-Session: https://claude.ai/code/session_01YRp5z4kK6vgYkrdH97ztsy Co-authored-by: Claude <noreply@anthropic.com>
…tored page's fate The listing's fate for a page component bound to the retired view-level api source now says the parse refuses the page: it still loads and is served under [metadata_spec_invalid], reads carry the refusal in _diagnostics, and its next save is refused with 422. The step-18 entry's acceptance criteria name the page parse beside the component-props gate. Claude-Session: https://claude.ai/code/session_01YRp5z4kK6vgYkrdH97ztsy Co-authored-by: Claude <noreply@anthropic.com>
…w-level api source is refused at the save door Claude-Session: https://claude.ai/code/session_01YRp5z4kK6vgYkrdH97ztsy Co-authored-by: Claude <noreply@anthropic.com>
…evel api data binding Claude-Session: https://claude.ai/code/session_01YRp5z4kK6vgYkrdH97ztsy Co-authored-by: Claude <noreply@anthropic.com>
…omponentViewData Claude-Session: https://claude.ai/code/session_01YRp5z4kK6vgYkrdH97ztsy Co-authored-by: Claude <noreply@anthropic.com>
…ge-component-api-data
📓 Docs Drift CheckThis PR changes 1 package(s): 1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
What this run could not see
Coarse fallback — 142 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 543d9f315c7e97cc8526f20a83f5ef662c7d126a && git checkout 543d9f315c7e97cc8526f20a83f5ef662c7d126a
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin a7a135dc267f0d154aca453f098c49ce8aac550c dce5433072dcd82b591b3fc3831927cf1cbc0007 && git checkout -B drift-repro a7a135dc267f0d154aca453f098c49ce8aac550c && git merge --no-ff dce5433072dcd82b591b3fc3831927cf1cbc0007
node scripts/docs-audit/affected-docs.mjs --json a7a135dc267f0d154aca453f098c49ce8aac550c
|
…ge-component-api-data
…d export Claude-Session: https://claude.ai/code/session_01YRp5z4kK6vgYkrdH97ztsy Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: Inputs: card #23357 (body; comments ① Derived judgments(a) The narrowing — right.
(b) The reach — right. (c) The hand-declared set — holds over the map's domain; one direction has a blind spot. (d) The generic walk — it can refuse one contrived non-component shape. The walk descends every object and array under (e) The new published export — right. ② Semver level
③ Boundary flagsDev report
Gates: Seat-3 pointer Renderer half objectstack-ai/objectui#12325: open ( Check-runs as found. Implemented-by: VERDICT: PASS Generated by Claude Code |
Fixes #23357
Clause-②: yes (narrowing)
What changes
The page parse now refuses a page component's
dataprop that names the retired view-levelapidata source, as a view's owndatais refused. That is triage's runtime half of this card (grade6159116611): the narrow judge forViewDataSchemaat a component'sdata, 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 fifthPageSchemaobject-level check,checkPageComponentViewData, attached by identifier like its four siblings. For a component of a type whosedatais a view data source (object-grid,object-map,object-gantt,object-tree) whoseproperties.datanames the retired provider, it raises the prescriptionViewDataSchema's own parse raises, located at the component'sproperties.data.provider(codecustom, the code of every object-level check on this schema). The prescription is read offViewDataSchema's issue, not copied. It walks every component underregionsandslotsat any depth, a component nested in apage:tabsitem 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)
view.zod.tsrefuses the arm through the discriminated union'serrormap:invalid_unionatprovider, messageVIEW_DATA_API_PROVIDER_RETIRED.page.zod.tsdoes NOT parse a component'sdata:propertiesisz.record(z.string(), z.unknown()), and onorigin/mainPageSchema.safeParseof anapppage whoseobject-gridbinds the retired provider answeredsuccess: true.getMetadataTypeSchema('page'), which isPageSchemaby identity (resolveOverlaySchema,protocol.ts). Measured through the realsaveMetaIteminprotocol.save-union-issues.test.ts:422 INVALID_METADATA, nothing persisted, issue atregions.0.components.0.properties.data.provider, codecustom, the prescription.metadata-protocol/src/protocol.tsis untouched.ComponentPropsMapby def identity, the rows whosedatamember isViewDataSchemaare exactlyobject-grid,object-map,object-gantt,object-tree(59 rows;object-kanban,object-calendar,object-timelinetake a row array). The page check cannot derive that set itself:component.zod.tsimportspage.zod.ts,packages/spec/srchas zero import cycles (measured: 1383 modules, 0 strongly connected components), and movingElementDataSourceSchema/RETIRED_PAGE_COMPONENT_TYPESout ofpage.zod.tswould change the published skill's generated references. So the set is declared inpage.zod.ts(thePRINT_REFUSED_PAGE_COMPONENT_TYPESprecedent) 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'sdataisViewDataSchema). The same cycle keepspageComponentSlotPositions()out of reach, so the walk descends every object underregionsandslots, a superset of every slot position: it reaches no less thanos migrate meta --storedlists or the props gate judges, and what it judges at a node stays the one retired binding on those four types.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 namingpage/partner_pageand the prescription. Read path (getMetaItem, pinned): served, with_diagnostics.valid: falseand 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 at63e1e4800, the branch merged withorigin/mainc857a93ee. The newest head,dce543307, adds only the changeset'sClause-②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, at7309ef08c. The later merge touched nothing inpackages/lint.typecheckof 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:regions.0.components.0.properties.data.providerwith the retirement's exact message;definePage,getMetadataTypeSchema('page')and the stack parse all refuse;object,value,schema, nodata, another provider,object-kanban, a custom type and the elementdataSourcebinding are accepted;ComponentPropsMaprows.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_METADATAwith nothing persisted, top-level and nested;objectandvalue(one row each);_diagnostics.valid: falseand the prescription.Not run locally, and declared to CI:
turbo ls --affectedclosure, 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
7309ef08cthroughscripts/ablation-replace.mjs, which mutates and restores and proves both on disk, andscripts/ablation-dist-preflight.mjs.superRefine(checkPageComponentViewData))is present in 18 built JS files, and the tree is clean..superRefine(checkPageComponentViewData));is replaced by an inert comment. The anchor count goes 1 to 0, and the blob goesed11df9efb60tob310419cea20.protocol.save-union-issues.test.tsgoes red: 3 failed, 26 passed. They are the two 422 pins and the read path. The control save stays green.git diff HEADis 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:
);already occurred in the file, so the mutation never landed..d.tsdocblock 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 --ranon7309ef08creports 90 derived families, all accounted for. 88 exited 0, includingcheck: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-closureandcheck: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 nodist/.check:type-check-debt: its re-measure re-runstscover every DEBT-ledger package repo-wide, which CI owns. The touched packages' owntypecheckruns are green.Repo-wide
pnpm lintwas not run locally. CI owns it.Acceptance notes
checkPageComponentViewData), required byobject-refinement-check-exports.test.tsfor every object-levelPageSchemacheck so a.shapemirror can re-attach it; see theClause-②note at the top.custom, not the view'sinvalid_union: the object-level-check pin readscustomas the code of every check on the schema. The message is the retirement's, byte for byte.not-required (already-registered view-data-api-provider-retired);check-adr-0087-registrationaccepts it.examples/**holds noprovider: 'api'(0 hits; controlprovider: 'object'hits inexamples/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