Repository navigation
Commit db0beb2
feat(types)!: an authored object-gantt takes its props in the spec's properties bag; the flat spelling is refused by name (objectui#10859, batch 6) (#11337)
Part of #10859
Clause-②: yes (narrowing)
`Clause-②: yes (narrowing)`, copied from the PM claim `5924906396`:
`@object-ui/types`' authoring faces widen (a spec-shaped `object-gantt`
bag node that is refused today parses) and narrow (a flat `object-gantt`
node that parses today is refused). This is objectui's
narrowing-as-`minor` rule with a **BREAKING (authoring)** banner in the
changeset, as in batches 1 to 5.
Batch 6 of objectui#10859, the last flat-arm block. It executes seat 1's
flat-arm answer at PR objectui#11248's ACCEPT (`5917261346`) for ONE
block, `object-gantt`, following batch 5 (PR objectui#11309) as merged
with PR objectui#11312 (one `requireRecordSource(type, rungs, at)`; the
cross-seat pointer `5924134305`). The card stays open for the designer
six and the (ii) / (iii) keys.
## What changed
- `packages/types/src/zod/objectql.zod.ts`: new
`ObjectGanttBlockSchema`, batch 5's construct. It is `BaseSchema` + the
`object-gantt` literal + `NODE_ENVELOPE` + `properties =
propsBag('object-gantt',
stripImportedDefaults(SpecObjectGanttPropsSchema))`: the shared helpers
and the installed 17.5.0 row by reference, no copy, no new helper.
Beside it:
- `dataSource`, the spec's `ElementDataSourceSchema` by reference (the
registration is `elementDataSourceBlock`-wrapped);
- one `aliasKeyRefusal` per member of the row, keyed by the row's own
key set read off the crossed row ("Did you mean `KEY` →
`properties.KEY`?"), **less `label`** (see Deviations);
- one `aliasKeyRefusal` per member of the row's `gantt` block, pointed
at `properties.gantt.KEY`, plus the flat mirror's legacy
`dependencyField` pointed at `properties.gantt.dependenciesField`. These
are the flat `GanttConfig` keys the flat mirror declared on the node;
- `body` / `children` refused with the flat mirror's objectui#9256
string;
- the maintainer's record-source rule read in the bag through the merged
`requireRecordSource('object-gantt', RECORD_SOURCE_KEYS, 'properties')`.
It counts a non-empty `dataSource.object`, so a bag node bound only
through `dataSource` parses on both faces.
- The arm joins `ObjectQLPublicBlockComponentSchema`.
`ObjectGanttSchema` (the flat mirror) leaves `ObjectQLComponentSchema`
(9 to 8 arms), stays exported, and stays paired with its TypeScript twin
in the parity census. Its docblock gains a "No longer an authoring arm"
section.
- `packages/types/src/objectql.ts`: the TypeScript `ObjectGanttSchema`
is **re-declared, not retired**. Its members are unchanged; its docblock
says it is the node as `ObjectGantt` reads it after `SchemaRenderer`
hoists `properties`, and as code composes it. The TypeScript union's
docblock names the zod union's new count.
- `packages/types/src/zod/index.zod.ts` (one barrel export) and
`packages/types/src/zod/README.md` (the ObjectQL public-block group
lists the arm, 7).
- objectui's authored flat producers, rewritten to the bag (census
below): `content/docs/plugins/plugin-gantt.mdx`, the three
`examples/schema-catalog` gantt entries,
`packages/plugin-gantt/README.md`.
- New pins:
`packages/types/src/__tests__/object-gantt-properties-bag-10859-b6.test.ts`
(both faces, the row by reference, the flat keys, the record source, the
split) and
`packages/plugin-gantt/src/ObjectGantt.propertiesBag-10859.test.tsx`
(render through the real registry).
- Two changesets: `.changeset/10859-object-gantt-properties-bag.md`
(`@object-ui/types` minor, BREAKING (authoring) banner) and
`.changeset/10859-plugin-gantt-properties-bag-docs.md`
(`@object-ui/plugin-gantt` patch: README and the two touched `src/` test
files; no runtime change).
**Files beyond the claimed surface**, each forced:
- census rows the new export forces: `zod-mirror-parity.test.ts` (one
`EXCLUSIONS` row; `EXPECTED_MIRROR_PAIRS` untouched),
`imported-defaults-8317.test.ts` (one `IMPORTED` row),
`registered-type-arms-10859-b2.test.ts` (the exact literal list gains
`object-gantt`), `objectql-union-arms-7363.test.ts` (8 arms,
`object-gantt` not among them),
`public-block-responsive-styles-10872.test.ts` (`object-gantt` joins
`DECLARES_DATA_SOURCE` and the record-source carve-out);
- fixture triage where a face now judges the bag (the mirror rows keep
the post-hoist spelling): `content-channel-e3-residual-9256.test.ts`,
`objectql-record-source-refinement-6939.test.ts`,
`strict-face-read-keys-11070.test.ts`, the schema-catalog
`objectql-record-source-render-identity-6939.test.tsx` (its anti-vacuity
row reads the bag; its PRE_REPAIR render readings hold unchanged) and
plugin-gantt's `ObjectGantt.catalogPlans-11141.test.tsx` (it mounts
`ObjectGantt` directly, so it hoists the catalog bag the way
`SchemaRenderer` does).
## Zone 1, measured before building
1. **The inherited reason holds for this arm.** Installed
`@objectstack/spec` 17.5.0: `ComponentPropsMap['object-gantt']` exists
and is the exported `ObjectGanttPropsSchema` (17 members, strict; its
`gantt` member is the 29-key `GanttConfig`). `PageComponentSchema`
refuses `{ type: 'object-gantt', objectName, gantt }` with
`unrecognized_keys ['objectName', 'gantt']` ("Unrecognized key(s) on
this page component … ADR-0089 D3a") and accepts the same props in
`properties`. A flat `startDateField` is refused the same way. Control:
a flat `action:button` `actionType` is refused the same way. The row
exists, so the bag is that row by reference (no mirror bag, unlike
`object-chart`).
2. **Census, with the stop line.** At base `5262f7dd3`, 138 tracked
files name `object-gantt`: 11 `CHANGELOG.md`, 27 pending changesets, 77
test files and 23 others:
| class | files | action |
|:--|:--|:--|
| authored page-node producers | `plugin-gantt.mdx` (10 nodes and the
Schema API block), the 3 schema-catalog entries,
`packages/plugin-gantt/README.md` (8 nodes) | rewritten |
| component mounts (post-hoist `schema` prop, no hoist) |
`plugin-gantt.mdx` "Task Click", README "Interactive Gantt" and
"Integration with Data Sources" | kept flat, now said so |
| runtime composers | `ListView.tsx`, `ObjectView.tsx` (flatten a stored
gantt view, write the flat `GanttConfig` keys and the `search` pair) |
kept flat; they render through `SchemaRenderer` and never meet the zod
faces |
| the declarations | `objectql.ts`, `objectql.zod.ts` | this change |
| renderer and registration | `ObjectGantt.tsx`,
`plugin-gantt/src/index.tsx`, `register-plugins.ts` | none |
| names the type, no node shape | `known-schema-types.ts`,
`public-blocks.ts`, `record-source.ts`, comments (`ValueDataSource.ts`,
`plugin-tree/src/index.tsx`, `registerCatalogBlocks.ts`), two
`scripts/check-*` ledgers, prose (`component.prompt.md`,
`data-source.md`) | none |
| governed `skills/**` | `skills/objectui/guides/page-builder.md` "Gantt
plugin example" (one flat node, plus prose teaching the flat field keys
on the node) | **listed, not rewritten** (governed path) |
**Stop line: not tripped.** No objectui context builds anything from the
zod `ObjectGanttSchema` object: its only non-test reader was the
`ObjectQLComponentSchema` union, and that union's only reader is
`AnyComponentSchema`. The non-page contexts that keep the flat spelling
depend on the TypeScript twin (the composers, `ObjectGantt`'s `schema`
prop) or on the registration's `inputs` (the sdui-parser html tier), not
on that object.
3. **The arm**, as above. `ObjectGanttSchema` is re-declared, not
retired.
4. **Producers**: rewritten as above; one governed producer listed.
5. **Pins**: below. The objectui#10859 ratchet does not move:
`object-gantt` was never refused at `type`.
**Batch 5's finding, re-measured.** On base, `safeValidateSchema`
already accepts the flat `{ type: 'object-gantt', dataSource: { object:
'task' }, gantt }` (PR objectui#11312 counts the binding on every arm),
so the finding no longer reproduces on the flat arm. For the bag arm it
is answered: a `dataSource`-only bag node parses on both faces (pinned),
and `dataSource: { object: '' }` with no rung is refused.
## Zone 2, re-measured
1. Held: each symbol is where the order located it at `5262f7dd3`.
2. Held: 23 non-test, non-changelog, non-changeset files name
`object-gantt` (table above).
3. Held: no open PR edits these regions. PR objectui#11333 also edits
`strict-face-read-keys-11070.test.ts`; `git merge-tree --write-tree
HEAD` against its head `139a49137` exits 0, and against `origin/main`
`5262f7dd3` exits 0.
## Tests (heavy runs through `os-verify-lock.sh`, slot `issue-10859`)
- **Base measurement** (source, before any edit): the bag node `{ type:
'object-gantt', properties: { objectName, gantt } }` refused by
`safeValidateSchema` (`RECORD_SOURCE_REQUIRED` at the root) and by the
strict face (the same, plus `unrecognized_keys ['properties']`); the
flat node accepted on both.
- **Green, union at the final head `0c673ccb8`:** `pnpm exec vitest run
packages/types/ packages/cli/ scripts/__tests__/`: `Test Files 510
passed | 2 skipped (512)`, `Tests 13626 passed | 2 skipped (13628)`,
VERDICT command-exit 0. `pnpm exec vitest run packages/plugin-gantt/
examples/schema-catalog/`: `Test Files 130 passed | 1 skipped (131)`,
`Tests 2911 passed | 114 skipped (3025)`, VERDICT command-exit 0 (the
skips are the zone-conditional `skipIf` pins). The second run holds
every test that reads a markdown file this PR changes outside
`packages/types` and `scripts` (`markdown-test-inputs.mjs` ledger),
`readme-navigation-example.test.ts` among them.
- **Arm-list consumer sweep** (declared narrowing): 232 tracked test
files outside `packages/types` and `packages/cli` that name
`AnyComponentSchema`, `StrictAnyComponentSchema`, `safeValidateSchema`,
`ObjectQLPublicBlockComponentSchema`, `ObjectQLComponentSchema`,
`ObjectGanttBlockSchema`, `nodeOracles`, `KNOWN_SCHEMA_TYPES`,
`propsLevelOf`, `PUBLIC_BLOCKS`, `unmirroredAlias`, `collectArms`,
`getPublicConfigs`, `ComponentPropsMap`, `validateSchema` or
`StrictAuthoringFace`, or reference `check-handler-key-read-sites`,
`block-config-schema-parity`, `registry-inputs-spec-parity`,
`strict-authoring-face`, `zod-mirror-parity`, `objectql.zod`,
`index.zod`, `ObjectGanttSchema`, `object-gantt` or `plugin-gantt`.
Three chunks, at `ceead94ad` plus the two triage edits later committed
byte-identical as `c572b020c`: `78 passed / 1 failed (79)` (the
render-identity anti-vacuity row, then triaged), `73 passed / 1 failed
(74)` (the catalog-plans pin, then triaged), and `79 passed` plus the
two triaged files: `Test Files 81 passed (81) / Tests 1610 passed`,
VERDICT 0. Later commits add the render pin, the docs and the
changesets; their markdown readers are re-run in the final union above.
- **Build / type-check:** `pnpm --filter @object-ui/types build && pnpm
--filter @object-ui/types type-check`, VERDICT 0 (`dist completeness: 1
package(s) complete (138 emitted files verified)`); the b6 pin is in
`tsconfig.test.json`'s `--listFilesOnly`. After `pnpm
--workspace-concurrency=2 --filter '@object-ui/plugin-gantt^...'
--filter '@object-ui/example-schema-catalog^...' build` (VERDICT 0):
`@object-ui/plugin-gantt type-check` and
`@object-ui/example-schema-catalog type-check`, VERDICT 0 (the two
plugin-gantt pins and the catalog render-identity pin are in their test
programs).
- **Runtime ablation** (objectstack `scripts/ablation-replace.mjs`, two
nested WRAP legs plus the driver's own EXIT/INT/TERM trap with an
absolute path and a blob check): the flat arm restored, i.e.
`ObjectGanttBlockSchema` out of the public-block union (anchor x1 to x0,
blob `bc957ee9` to `8390b06a`) and `ObjectGanttSchema` back into
`ObjectQLComponentSchema` (anchor x1 to x0, blob to `e5be71a8`; on disk
`ObjectGanttBlockSchema,` x0 in the public union and
`ObjectGanttSchema,` x1 in the ObjectQL union). Over 13 test files (the
two new pins, the census and triaged files, the catalog pins and the
objectui#10859 ratchet): `Tests 93 failed | 783 passed (876)`. Red: 78
b6 rows, 4 of 6939, 3 catalog validate rows, 2 of 9256, 2 of 10872, one
each in 7363, b2 and 11070, and the render pin's validator row. Green:
the census files whose subject is the export itself
(`zod-mirror-parity`, `imported-defaults-8317`), the ratchet, the
catalog-plans pin (a direct mount), every render row, and the 26 b6 rows
that read the spec or the arm directly (the lit controls, the per-member
page-component split, the row-by-reference row, the binding and channel
refusals the flat arm shared, the spec-divergence row and the
flat-mirror row). Direction red, as expected. Restored: blob == HEAD
`bc957ee9`, `git diff HEAD` empty (both tool legs and the driver).
Vitest aliases `@object-ui/types/zod` to source, so no build sat between
the mutation and the run.
- **Type-level reverse validation** (same tool): the bag replaced by
`z.strictObject({ objectName: z.string().optional() }).optional()` made
`tsc -p tsconfig.test.json` exit 2 with exactly one error, `TS2344: Type
'false' does not satisfy the constraint 'true'` on the bag `Equal` row
of the b6 pin. Restored, blob == HEAD, `git diff HEAD` empty.
- **Render** (committed pin, real registry, recording adapter): the bag
queries `find('task', …)` with its own `$filter` and `$orderby` and
hands the chart one task per row, titled by its `gantt` block; the two
flat spellings a composer builds (the `gantt` block on the node, and the
flattened `GanttConfig` keys) make the identical call and hand the chart
identical tasks; a bag bound only through `dataSource` queries the bound
object; a bag on inline rows draws them with no host query; control: a
bag naming another object queries that object and never `task`. The
catalog render-identity pin draws the three bag entries exactly as its
recorded pre-repair DOM.
## Gates (exit codes captured before any pipe)
- exit 0: `check:control-bytes` ("OK (scanned 9809 tracked text file(s);
skipped 85 binary)"; a self-scan over the 23 changed files gives 0
hits), `check:new-line-citations` ("VERDICT
new-cross-file-line-citations: 0 new citation(s)"), `node
scripts/check-changeset-presence.mjs` ("15 source file(s) of 2 released
package(s) changed, and this change declares 2 changeset(s)"),
`changeset:check` ("No changeset declares a `major` bump."),
`check:handler-key-reads` ("OK 140 arm(s), 212 registration(s) (138
keyed onto an arm), 56 reachable handler read(s), 56 judged"),
`check:spec-symbols`, `check:element-data-source-declaration` ("14
gate-consuming file(s) checked"), `check:component-surface-parity`,
`check:installed-pin-claims`, `check:test-path-roots`,
`check:vi-mock-specifiers`, `check:vi-mock-inherit`,
`check:vi-mock-override-shape`, `check:unreferenced-sources`,
`check:esm-specifiers`, `type-check:coverage` ("43/43 packages compile
their tests"), `check:registry-bare-names`, `check:prompt-keys`,
`check:pending-changeset-literals`, `census:changeset-polarity`,
`check:skill-examples`.
- docs: `check:doc-types`, `check:doc-fences`, `check:doc-example-ids`,
`check:doc-example-readers`, `docs:check-links` ("Links are valid across
17 scan roots."), `node scripts/markdown-test-inputs.mjs --audit` ("108
candidate test files, all adjudicated; 80 declared entries, all
present."), and the whole root `scripts/__tests__/` suite (in the union
above). After the `check-doc-snippet-types.mjs --build-filter` closure
build (turbo "Tasks: 35 successful, 35 total"): `check:doc-snippets`
("Semantic phase: 698 of 698 block(s) judged, 0 failed."),
`check:doc-examples`, `check:readme-exports`, each exit 0.
- `check:changeset-claims` (report-only): five pending changesets
describe what the validators say about an `object-gantt` written flat
(`6475-gantt-block-face-declared`,
`6939-objectql-record-source-refinement`,
`9256-e3-residual-content-channels`, `11070-strict-face-read-keys`,
`11117-datasource-objectname-waiver`). They are not edited; this
change's types changeset names how those readings happen in the bag now,
so the release notes read together.
- `node scripts/check-governed-queue-guard.mjs --test` over the 23
paths: "NOT GOVERNED".
- eslint narrowing: `pnpm exec eslint --no-inline-config --format json`
over the 15 changed `.ts` / `.tsx` files: 0 errors, 37 warnings, the
same count file for file as the base blobs linted through `--stdin` (the
new and the other touched files carry 0). Population: each touched
package lints `.`; `eslint.config.js` sets no type-aware parser project,
so no untouched file's verdict can move. The full `pnpm lint` is CI's.
## Deviations
- **`label` is not refused flat.** The order asks for one
`aliasKeyRefusal` per bag member. `label` is a row member AND a
node-level key of the spec's own `PageComponentSchema` (its display
label): measured, the spec's page component accepts `label` on an
`object-gantt` node while it refuses every other row member written
there. Refusing it would make objectui refuse a spec-valid document, so
`label` keeps `BaseSchema`'s member. The pin re-derives the split from
the installed spec for every row member, so a spec that moves it turns
the pin red.
- **The flat mirror's `GanttConfig` members and `dependencyField` are
refused by name on the bag arm**, beyond the row-key set: they were
declared members of the flat mirror, and their bag home is the row's
`gantt` block (batch 5's precedent for `locationField` / `titleField`).
The key set is the row's own `gantt` member, read off the crossed row.
- **`search` / `searchableFields`** (flat-mirror members, absent from
the row) are left undeclared on the bag arm, as batch 4 left the
row-absent members of `object-form`: unjudged by the tolerant face,
refused by the strict one, refused by the row inside the bag. A list
view writes them onto the node it composes, which never meets these
faces.
- **Second changeset**, `@object-ui/plugin-gantt` patch: the README, and
two test files under `src/`, which the presence gate counts as published
source.
- **Comments this change made false, or that were already false next to
the edit, corrected in passing:** `requireRecordSource`'s docblock said
neither `object-map` nor `object-gantt` has a `ComponentPropsMap` row
(both have had one since 17.5.0); the flat mirror's `gantt` member
comment and the TypeScript twin's `gantt` comment said the mirror
reaches `validate` through `AnyComponentSchema`; the
`ObjectQLComponentSchema` docblock's opening sentence named two departed
arms out of four.
- The harness attribution reminder asked for model-named commit trailers
and a different PR footer. Per `AGENTS.md` and the role file, the
commits carry the model-free pair and this body the session-URL footer.
## Acceptance notes
- **The bag follows the spec row, which is not the flat mirror.**
Measured: the row types `markers` as an array of unknown and
`navigation` as unknown, so `properties.markers: [{ date: 5 }]` and
`properties.navigation: { mode: 'nope' }` parse, where the flat mirror
refuses both (`invalid_type` at `markers.0.date`, `invalid_value` at
`navigation.mode`). The row's own contract, taken by reference; no
producer writes either.
- **The governed producer** `skills/objectui/guides/page-builder.md`
"Gantt plugin example" authors a flat `object-gantt` node (`objectName`
and `gantt` on the node), which `objectui validate` refuses after this
change, and its prose says the flat field keys may be written on the
node. `check:skill-examples` exits 0 on it (it does not run
`safeValidateSchema`). Per the answer's step 4 it goes through the
governed path; batch 4 noted its `object-form` sibling on
objectui#11183.
- The README's "A maximal node" carries `bind` on the node, which the
spec's page component refuses (`unrecognized_keys ['bind']`) while
objectui's `BaseSchema` declares it. The flat node at base carried the
same key; unchanged here.
- **The sdui-parser html tier spells this node flat by design**, as
batch 5 recorded for the other bag-armed blocks.
Written in session
`https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec` (the
dispatching seat's session; this dev ran as its subagent).
---
_Generated by [Claude
Code](https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 17dc167 commit db0beb2
23 files changed
Lines changed: 1596 additions & 515 deletions
File tree
- .changeset
- content/docs/plugins
- examples/schema-catalog
- src/schemas/plugin-gantt
- test
- packages
- plugin-gantt
- src
- __tests__
- types/src
- __tests__
- zod
| 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 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
0 commit comments