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 00ccdf7
Browse filesBrowse the repository at this point in the historyBrowse files
feat(types): arm the seven registered node types that pass the criterion — page kinds, app-schema-renderer, object-pivot, embeddable-form, detail-section (objectui#11440) (#11493)
Part of #11440
Clause-②: yes
The first of objectui#11440's two pull requests. It arms the seven
registered node types that the seat ruling `5945530142` on
objectui#10859 (as amended by `5945583855`) passes: the spec page kinds
`record`, `home` and `utility`, and `app-schema-renderer`,
`object-pivot`, `embeddable-form` and `detail-section`.
`safeValidateSchema`, and so `objectui validate`, refused each one with
`invalid_union` at `type`. `REFUSED_AT_TYPE` falls 8 to 1. The eighth
key, `spec-report`, is the fold into `report`, which is the second pull
request (see "What is left" below).
Dispatched run: claim `5954845613` (`domain:ui` seat 1), session
`https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37`. Draft, left
for the seat.
## What changed
| key | arm | shape |
|:--|:--|:--|
| `record`, `home`, `utility` | `PageKindNodeSchema` (`layout.zod.ts`),
its own arm of `AnyComponentSchema` | every member is `PageNodeSchema`'s
own, by reference (the spec's `PageSchema` fields among them, through
`SpecPageFields`); `type` is the spec's `PageTypeSchema` narrowed with
`.extract` to the three kinds `@object-ui/components` registers on
`PageRenderer` |
| `app-schema-renderer` | `AppSchemaRendererNodeSchema` (`app.zod.ts`),
its own arm | `basePath` and `mobileNavMode` (`'drawer'` or
`'bottom_nav'`), from the registration's inputs; `children` and `body`
refused by name |
| `object-pivot` | `ObjectPivotBlockSchema` (`objectql.zod.ts`), in
`ObjectQLPublicBlockComponentSchema` | a REQUIRED `properties` bag of
the registration's inputs (the cross-tab members are the `pivot`
mirror's own, by reference; `drillDown` refuses `mode`; the retired
`dataProvider` is refused); flat props refused by name toward
`properties.KEY`; `dataSource` binding and `responsiveStyles` on the
node; `RECORD_SOURCE_REQUIRED` unless `dataSource.object` names the
object |
| `embeddable-form` | `EmbeddableFormBlockSchema` (`objectql.zod.ts`),
same union | a REQUIRED bag of exactly the registration's inputs
(`formId` required), built as above |
| `detail-section` | `DetailSectionNodeSchema` (`views.zod.ts`), in
`ViewComponentSchema` | the ten `DetailViewSectionSchema` members the
registration publishes, `.pick`ed by reference, flat; `fields` required
|
Also:
- `object-pivot`'s registration publishes `drillDown` as an input
(`@object-ui/plugin-dashboard`). `ObjectPivotTable` reads it, and the
`pivot` node's refusal of `drillDown` names this block as where a pivot
drill is authored.
- `@object-ui/types` exports `ObjectPivotBlockNode` and
`EmbeddableFormBlockNode`. objectui#11468 (landed during this run)
derives `ObjectQLPublicBlockNode` from the union's arms, so the two arms
joined it. Its `ClosedBag` closed only an optional bag, so it closes a
required one too now, and no `AuthoringNode` member carries an open bag.
- Prose this change made false is amended: three docblocks
(`ObjectPivotDrillDownConfig`, `DrillDownConfigSchema`,
`ObjectPivotTable`'s `dataProvider` note), and pure-append dated notes
on three pending changesets (`10685-drilldown-per-block.md`,
`7352-drill-down-config-mirror.md`, `11468-bag-carrier-node-types.md`).
- Changesets: `.changeset/11440-arm-passing-types.md`
(`@object-ui/types` minor, each new authorable spelling listed, no
BREAKING banner: a pure widening) and
`.changeset/11440-object-pivot-drilldown-input.md`
(`@object-ui/plugin-dashboard` minor).
## Contract notes
For the at-tier reviewer.
- **Widens.** `AnyComponentSchema` accepts seven `type` literals it
refused at `type`, on both faces, at the root and at every child slot.
`@object-ui/types/zod` exports five schemas. `@object-ui/types` exports
two TypeScript node types and `AuthoringNode` gains their members. The
`object-pivot` registration publishes one more input (`drillDown`).
- **Narrows.** Nothing that parsed before is refused now. Every document
naming one of the seven was refused before, so the refusals inside each
arm (a flat prop, a misspelt `mobileNavMode`, a missing `fields`,
`drillDown.mode`) replace a refusal at `type` with a named one. The
`ClosedBag` change touches only the two new bags: the objectui#11468 pin
shows the other members unchanged.
- **Evidence.** Base readings below (each key refused at `type`, both
faces); the new pin
`packages/types/src/__tests__/passing-keys-arms-11440.test.ts` holds
what each arm accepts and refuses on both faces with a lit control per
refusal;
`packages/cli/src/__tests__/validate-passing-keys-11440.test.ts` runs
`objectui validate` end to end; each registration's inputs are pinned
against its arm in the package that registers it (four new files); two
ablations turn the ratchet and the pins red (below).
## Zone 2 readings — the mechanism assumptions, measured
1. **Registrations: held, with one correction.** All seven are where the
brief says. `app` is registered on `PageRenderer` too (with `page`), not
only the three kinds; its literal is the app document's
(`AppComponentSchema`). Each declaration is built from the
registration's inputs; where a renderer reads a key the inputs omit, it
is named below.
2. **The page kinds: held.** At the merged base `6007dd4e4` the card's
probe `{ type: 'home', name, regions }` and the spec's own page document
were refused at `type` on both faces, while `{ type: 'page', pageType:
'home' }` passed. After: all pass. The precedent followed is
`PageNodeSchema` itself (the spec fields by reference through
`specFieldsExcept`); the strict face derives from the arm like every
other. On objectstack's example pages (objectstack `4e6dc233`, read
only, the eleven `definePage` documents of kind `home` or `record` in
`app-crm` and `app-showcase`, run through both faces by an uncommitted
probe): base, 11 of 11 refused at `type` on both faces; after, none is
refused at `type`, and 10 of 11 parse on both faces. The eleventh
(`showcase_my_work`) passes the tolerant face, and the strict face
refuses a nested `{ type: 'grid', properties: { … } }` region component
as an unrecognized key (`properties`): the `grid` arm takes its props
flat. That is the `grid` arm's existing posture, unchanged here: the
same component inside a `type: 'page'` document is refused the same way
(measured). **`app` and `list` today, unchanged here:** a spec page of
kind `app` is judged by the app document's arm (the tolerant face passes
it unjudged, the strict face refuses `regions`, `template`, `kind` as
unrecognized keys); a spec page of kind `list` meets the `list`
component's arm (refused for having no `items`, and on the strict face
for `regions` and the other page keys). No new key is registered. ⚠️ A
finding on the way: declaring the page node's members a second time
inside `AnyComponentSchema` made `tsc` refuse the union with TS7056
(inferred type too long to serialize); `PageKindNodeSchemaType` names
the arm's type by reference, so declaration emit names it.
3. **`spec-report`: not in this pull request.** Measured only: the
strict face refuses `{ type: 'report', report }` as an unrecognized key
(`report`), and the tolerant face passes it unjudged. The fold needs a
file outside the claimed surface (below).
4. **`detail-section`: armed, not folded.** The spec's `record:details`
section names its heading `label` and takes field NAMES; this node names
it `title` and takes `DetailViewField` objects. The spec row refuses the
README's section with `unrecognized_keys` on `title` and `invalid_type`
on each field object (pinned). After arming, the plugin-detail README's
`detail-view` document validates except for one issue, at
`tabs.1.content.items`: its second tab hands `record:activity` a host
feed (`items: activityData`), which objectui#11321 refuses by name in a
JSON document, and whose refusal text names this README as the TSX
composition where it stays legal. Measured both ways by `objectui
validate` (the first tab alone: valid; the full document: that one
issue). The README is not edited.
5. **`app-schema-renderer`: the guide's node validates; the `schema`
input is not declared.** The governed guide teaches the node's
`mobileNavMode` key, in prose, and `{ type: 'app-schema-renderer',
mobileNavMode: 'bottom_nav' }` validates on both faces after. The
registration declares three inputs. Measured through the real
`SchemaRenderer` and registry: `SchemaRenderer` strips the `schema` key
and hands the component the NODE as its `schema` prop, so a node with
its navigation under `schema` drew no navigation, and the same
navigation written on the node drew. A node's `children` drew nothing
either. So the arm declares `basePath` and `mobileNavMode` and refuses
both content channels; where the app document belongs on this node is an
open question for the seat (below). No `skills/**` edit.
6. **Namespaced twins: none armed; the pin holds at 362.** The seven
twins are `ui:home`, `ui:record`, `ui:utility`,
`layout:app-schema-renderer`, `plugin-dashboard:object-pivot`,
`plugin-form:embeddable-form`, `plugin-detail:detail-section`. Each is
its own literal, so the bare arm does not claim it; the ratchet row
asserts each twin is still refused at `type`.
7. **The objectui#8347 ceiling-pin tests: not tripped** (types suite
green on the head). objectui#11468 and objectui#11478 landed during the
run and were merged in; the first needed the two node types above.
## Gates
Head `ccb1077bc` (a merge of `main` `401611b21` into `34d127803`). Exit
codes captured to a file before reading. Heavy runs through the shared
verify lock; absolute times are shared-box readings.
| check | result |
|:--|:--|
| `pnpm --filter @object-ui/types build && … type-check` (three legs) |
exit 0 · "dist completeness: 1 package(s) complete (144 emitted files
verified)"; the new pin is in `tsconfig.test.json --listFilesOnly` |
| `pnpm exec vitest run packages/types/ packages/cli/` | exit 0 · Test
Files 361 passed (361) · Tests 9266 passed (9266) |
| type-check `@object-ui/plugin-dashboard`, `plugin-form`,
`plugin-detail`, `layout`, `cli` (after their closure build) | exit 0,
each `type-check: Done` |
| `packages/layout/` plus the plugin-form / plugin-detail tests that
read a zod face or name the keys, plus every `apps/console` /
`packages/app-shell` test that reads a zod face or names a key | exit 0
· 101 files, 1190 tests |
| every other test outside the touched packages that reads a zod face,
`KNOWN_SCHEMA_TYPES`, or names one of the eight keys (examples, scripts,
components, core, react, plugin-report and others) | exit 0 · 89 files,
2309 tests |
| `packages/plugin-dashboard/` whole suite, at `30614b964` (before the
two merges; neither touched this package) | exit 0 · 161 files, 1534
passed, 6 skipped; its 20 zod-reading or pivot tests re-run on the head:
exit 0 |
| `node scripts/regenerate-known-schema-types.mjs --check` | exit 0 ·
"matches the registry derivation" |
| `check:doc-snippets` (after its `--build-filter` closure build),
`check:doc-examples`, `check:readme-exports` | exit 0 each · 776 of 776
blocks judged, 0 failed; 122 examples, ledger exact; OK |
| `check:doc-types`, `check:doc-fences`, `markdown-test-inputs --audit`
| exit 0 each |
| `check:control-bytes`, `check:new-line-citations` (0 new),
`check-changeset-presence`, `check-changeset-no-major`,
`check:pending-changeset-literals` | exit 0 each |
| `check:changeset-claims` (report-only) | exit 0 · read the pending
changesets that name a touched file; three made false by this change got
the dated notes above |
| `check:handler-key-reads`, `check:element-data-source-declaration`,
`check:registry-bare-names`, `check:spec-symbols`,
`check:test-path-roots` | exit 0 each |
| `check-governed-queue-guard --test` (the changed paths) | NOT GOVERNED
|
| `pnpm check` (the CLI sweep over the repository) | before (types
source swapped to `main` `401611b21` under a trapped restore, proven by
blob hash and an empty `git diff HEAD`) and after: identical, 287
validated, 146 recognised but not validated, 0 did not validate, 47
skipped. No tracked JSON or YAML document names one of the seven types,
so the sweep has nothing new to validate. The expectation that more
documents validate does not hold |
| ESLint, narrowed | `--no-inline-config --format json` over the 24
changed lintable files: 1 error, 53 warnings, 0 of them on a line this
branch adds (attributed by `git diff -U0` against the merge base). The
error is the `no-restricted-imports` report on a `@objectstack/spec/ui`
re-export in `packages/types/src/index.ts` that an `eslint-disable`
comment covers, which `--no-inline-config` ignores; that line predates
this branch. Population: each touched package's `lint` script;
`eslint.config.js` sets no type-aware parser project (0 matches for
`parserOptions`, `project:`, `projectService`), so no untouched file's
verdict can move. Full `pnpm lint` is CI's |
## Reverse verification
- **Base, predicted and read.** At `6007dd4e4` each of the seven was
refused with one `invalid_union` at `type` on both faces, and the
ratchet read 8.
- **Ablation 1, the page kinds.** `PageKindNodeSchema` removed from the
root union by `ablation-replace` (anchor hit 1 to 0, blob moved), the
pin files run, the file restored. Predicted: the ratchet goes red with
the three kinds. Read: 3 files red, 14 rows; "`objectui validate`
refuses 4 registered bare key(s) at `type`; the pin is 1. Refused: home,
record, spec-report, utility". Restore proven: blob equals HEAD, `git
diff HEAD` empty.
- **Ablation 2, a declared plugin key.** `ObjectPivotBlockSchema`
removed from `ObjectQLPublicBlockComponentSchema` the same way. Read: 2
files red, 15 rows; "Refused: object-pivot, spec-report". Restore proven
the same way.
- The first attempt at both was a no-op, and is reported as one: the
replacement text was a prefix of the anchor, so the tool refused
(replacement count did not rise) and restored without running anything.
The readings above are the second attempt, with replacement text that
was not in the file.
- **Ablation 3, the `report` wrapper:** belongs to the second pull
request.
## What is left (the second pull request)
The `spec-report` fold, in the ruled step order (`report` declares the
wrapper shape, `DrillDownDrawer` moves to `report`, then the alias
goes), needs one file the claim does not name:
`apps/console/src/register-plugins.ts` registers a lazy `spec-report`
stub beside `report-viewer`, and an unregistered key with a surviving
console stub strands that stub. Per the brief, that waits for the seat
to amend the claim; it is not started here.
## Acceptance notes
- `object-pivot` and `embeddable-form` registrations still declare
`objectName` `required: true`, while both renderers are gate-wrapped and
the arms accept `dataSource.object` instead. The parser tier's verdict
on a binding-only node was not measured here; objectui#10392 is the
calendar instance of the same shape.
- `EmbeddableForm` reads config keys its registration does not publish
(`branding`, `thankYouPage`, the anti-spam keys and others). The arm
declares the registration's inputs only, so the strict face refuses them
as unrecognized keys.
- `PageRenderer` derives its layout from `pageType`, defaulting to
`record`, and not from `type`, so a kind node rendered outside
`PageView` (which writes both) would draw the record layout. Read from
the source, not measured.
- The plugin-dashboard README and `plugin-dashboard.mdx` describe
`object-pivot` as an "internal wrapper around `ObjectPivotTable`"; it is
a Tier A public block with an arm now.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
`safeValidateSchema` — and so `objectui validate` — accepts seven more registered node types: the spec page kinds `record`, `home` and `utility`, and `app-schema-renderer`, `object-pivot`, `embeddable-form` and `detail-section` (objectui#11440, the objectui#10859 follow-up for the keys that pass the criterion).
6
+
7
+
**Clause-②: yes** — the accept set of `AnyComponentSchema` widens by seven `type` literals, and `@object-ui/types/zod` exports five new schemas. Nothing that parsed before is refused now: every document naming one of the seven was refused with `invalid_union` at `type`, at the root and at every child slot.
8
+
9
+
**What changed, in observable terms.** Each new authorable spelling, and what it accepts:
10
+
11
+
-**`{ type: 'record' | 'home' | 'utility', … }`** — a stored `@objectstack/spec` page whose `type` is its page kind, the spelling the spec's `PageSchema` declares and the node `PageView` renders. `PageKindNodeSchema` takes every member of the `page` node (`PageNodeSchema`) by reference, so the spec's own page document validates (`{ type: 'home', name, label, regions }`), each region component is judged by the node union, and the `page` node's refusals (`actions`, `breadcrumbs`, `maxWidth`, `padding`, `body`) apply. The spec's other two kinds are not armed here: `app` stays the app document's literal (`AppComponentSchema`) and `list` the `list` component's. `{ type: 'page', pageType }` validates as before; which spelling is canonical is not changed.
12
+
-**`{ type: 'app-schema-renderer', mobileNavMode?, basePath? }`** — `AppSchemaRendererNodeSchema`, the whole-shell node `@object-ui/layout` registers. `mobileNavMode` is `'drawer'` or `'bottom_nav'`, as the registration declares it, so the node the mobile guide teaches validates and a misspelt mode is refused at `mobileNavMode`. The registration's third input, `schema`, is not declared: `SchemaRenderer` strips that key, so a node never delivers it, and the strict face refuses it as an unrecognized key. `children` and `body` are refused by name: a node draws neither.
13
+
-**`{ type: 'object-pivot', properties: { … } }`** — `ObjectPivotBlockSchema`. The `properties` bag holds the registration's inputs (`objectName`, `title`, `rowField`, `columnField`, `valueField`, `aggregation`, `showRowTotals`, `showColumnTotals`, `filter`, `format`, `drillDown`) and is required: `rowField`, `columnField` and `valueField` are required members. `objectName` is required unless the node's `dataSource.object` names the object (`RECORD_SOURCE_REQUIRED`). `drillDown` refuses `mode` by name, and the retired `dataProvider` is refused by name.
14
+
-**`{ type: 'embeddable-form', properties: { … } }`** — `EmbeddableFormBlockSchema`. The required bag holds exactly the registration's inputs (`formId`, required; `objectName`, required unless `dataSource.object` names the object; `title`, `description`, `fields` as field names, `allowMultiple`).
15
+
- On both blocks, a prop written flat on the node instead of in `properties` is refused by name, with a message naming `properties.KEY`, as `@objectstack/spec`'s page component refuses it as mis-layered; the node declares the `dataSource` binding (the spec's `ElementDataSourceSchema`) and `responsiveStyles`; `children` and `body` are refused by name.
16
+
-**`{ type: 'detail-section', fields, … }`** — `DetailSectionNodeSchema`, one field section of `@object-ui/plugin-detail` as a node: the ten `DetailViewSectionSchema` members its registration publishes (`title`, `description`, `icon`, `fields`, `collapsible`, `defaultCollapsed`, `columns`, `showBorder`, `headerColor`, `hideEmpty`), flat on the node, `fields` required. The plugin-detail README's `detail-view` tab with a `detail-section` content validates. `children` and `body` are refused by name.
17
+
18
+
The strict authoring face (`StrictAnyComponentSchema`) derives from these arms and accepts the same documents, closed to undeclared keys.
19
+
20
+
**The TypeScript face.**`@object-ui/types` exports `ObjectPivotBlockNode` and `EmbeddableFormBlockNode`, the two arms' authoring inputs, derived by reference as the other `ObjectQLPublicBlockNode` members are, so they are in `AuthoringNode` and `SchemaRenderer`'s `schema` prop accepts them. Each bag is required and closed: a misspelled bag key, a missing bag and a prop written flat do not compile. The page kinds were already typed (`PageDocumentNode`, the spec's own page input).
The `object-pivot` registration publishes `drillDown` as an input (objectui#11440).
6
+
7
+
`ObjectPivotTable` has always read `drillDown` (whether the drill is on, its filter, title, target, columns, row cap and report), and the `pivot` node's refusal of `drillDown` names `object-pivot` as where a pivot drill is authored. The registration did not list it, so the `sdui-parser` manifest and the designer did not offer it. Its description says `drillDown.mode` does not apply: every click point on a pivot is an aggregated bucket, so the pivot always drills through. `@object-ui/types/zod`'s new `object-pivot` arm declares the same member (`.changeset/11440-arm-passing-types.md`). Nothing else about the block changes.
0 commit comments