feat(spec): object-map, object-gantt and object-tree get ComponentPropsMap rows, derived from the renderers' read points (objectui#8348 Q1-C) - #18403
Conversation
…psMap rows, derived from the renderers' read points WIP: the three rows plus their flat-config guidance sets. Key sets measured from objectui's plugin-map / plugin-gantt / plugin-tree at the .objectui-sha pin 53ded82b, per the #7751 derivation method. Claude-Session: https://claude.ai/code/session_01KB5PFtxuy1x3dcR5gxudx6 Co-authored-by: Claude <noreply@anthropic.com>
…rescriptions and door lists Claude-Session: https://claude.ai/code/session_01KB5PFtxuy1x3dcR5gxudx6 Co-authored-by: Claude <noreply@anthropic.com>
… docs and strictness ledger; add the changeset Claude-Session: https://claude.ai/code/session_01KB5PFtxuy1x3dcR5gxudx6 Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 6 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 7 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 136 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 d20154227410f6a7b1d37f07ae61e0cce799fa02 && git checkout d20154227410f6a7b1d37f07ae61e0cce799fa02
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin b6fe311a9ab7bebdfb22631030ac19ebeb87c6a5 c431c22e058f0f74be179cd2388911634d64c67f && git checkout -B drift-repro b6fe311a9ab7bebdfb22631030ac19ebeb87c6a5 && git merge --no-ff c431c22e058f0f74be179cd2388911634d64c67f
node scripts/docs-audit/affected-docs.mjs --json b6fe311a9ab7bebdfb22631030ac19ebeb87c6a5
|
Contract reviewServed-tier: ① Derived judgmentsThe method was tested against the renderers themselves at the
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
…tree states the real reason its objectName is optional; two citations corrected Claude-Session: https://claude.ai/code/session_01KB5PFtxuy1x3dcR5gxudx6 Co-authored-by: Claude <noreply@anthropic.com>
…describes Claude-Session: https://claude.ai/code/session_01KB5PFtxuy1x3dcR5gxudx6 Co-authored-by: Claude <noreply@anthropic.com>
Contract review126/126 at-tier stamps (control: an ① Derived judgmentsMethod: every read point re-read from objectui at the pin Accept-set and public-surface changes, one by one:
FALSE claims — text only; no key, value shape, row membership or level moves:
② Semver levelChangeset ③ Boundary flags
Implemented-by: VERDICT: FAIL Generated by Claude Code |
…ree describes The `objectName` / `data` / `staticData` describes on `object-gantt` and `object-tree` named `getDataConfig` as the reader that resolves the record source. Measured at the `.objectui-sha` pin `53ded82b`: `ObjectGantt.tsx` and `ObjectTree.tsx` contain zero occurrences of that name (control: `ObjectMap.tsx` has 8 — it keeps a local wrapper at :135, so the map describes stay as they are). Both renderers reach the shared three-rung ladder `resolveRecordSourceConfig` (`@object-ui/core` `record-source.ts` :151 / :155 / :162) — gantt at :593, tree at :359. The ladder ORDER those sentences describe was already true; only the function they named was wrong, and all six ship into the public reference. Also: the tree `data` JSDoc cited two read points where the schema header already rules that `:496` is not a second site for the object arm, and two source citations were off by a line (`safeParse` is at :500, not :501; the "Not authorable" marker is at :482, not :477). Claude-Session: https://claude.ai/code/session_01KB5PFtxuy1x3dcR5gxudx6 Co-authored-by: Claude <noreply@anthropic.com>
…rce describes Six rows follow the corrected describes: `object-gantt` and `object-tree` now name `resolveRecordSourceConfig`. The three `object-map` rows keep `getDataConfig` because that renderer really does keep a local wrapper of that name above the shared ladder. Claude-Session: https://claude.ai/code/session_01KB5PFtxuy1x3dcR5gxudx6 Co-authored-by: Claude <noreply@anthropic.com>
Contract review119/119 at-tier stamps (control: an ① Derived judgmentsMethod: every read point re-read from objectui at the pin Accept-set and public-surface changes, one by one:
Every sentence asserting runtime behaviour, re-read at the pin — all 32 describes on the three new schemas, on BOTH sides (32 of 32 byte-exact in
Citations: every Non-blocking imprecisions, source or docs text, none a false attribution and none moving a key, value shape, row or level — the seat may fold them into the next round that touches these lines, with
② Semver levelChangeset ③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
Provenance — at-tier PASS at the current head, carriers cleared, pre-check clear
Landing pre-check, all three, ⛔ every one re-read AFTER the carrier strip: ① the PASS above names this head. ②
|
Fixes #18305
Executes the objectui#8348 ruling 「8348 以协议为准」 (decision batch #83, 2026-09-08) and batch #136 item 3 (Q1-C, maintainer 「同意」):
ComponentPropsMapgainsobject-map,object-ganttandobject-tree, each row's key set derived the #7751 way — from the objectui renderer's own read points, at the.objectui-shapin53ded82b.Not derived from
@object-ui/types' mirror. That mirror standing in as the authority for map and gantt is the defect this card closes, and forobject-treethe mirror is measurably wrong about four keys (below).The #7751 derivation table, extended by three rows
Every citation is a line in the objectui checkout at
53ded82b. The shared record-source ladder isresolveRecordSourceConfigincore/src/utils/record-source.ts— rung 1data(:151, returned VERBATIM as aViewData), rung 2staticData(:155, wrapped into{ provider: 'value' }), rung 3objectName(:162).object-map—plugin-map/src/ObjectMap.tsx, registry shellplugin-map/src/index.tsxobjectName:793(fetch dep),:890(navigation)z.string().optional()data:169array-shorthand head, thenresolveRecordSourceConfigat:174ViewDataSchemastaticDataz.array(z.unknown())filter:742—$filter: schema.filterz.array(ViewFilterRuleSchema)sort:743—$orderby: convertSortToQueryParams(schema.sort)z.array(SortItemSchema)map:370—getMapConfigbranch 1, the author face; the registration's declared{ name: 'map', type: 'object' }inputz.unknown()(see note)mapStyle:365—schema.mapStyle || schema.map?.stylez.string()navigation:889—useNavigationOverlayz.unknown()enableClustering:905—enableClustering ?? (schema.enableClustering || …)z.boolean()Measured and deliberately NOT declared: the flat
map-config spellingsgetMapConfigbranch 2 reads at:382-396(locationField,latitudeField,longitudeField,titleField,descriptionField,zoom,center) — the ObjectView/ListView flatten product, ruled an internal transport form, not a second authoring surface (maintainer ruling objectui#5018, 2026-08-17);style, which:283reads ONLY to say it is not consumed as a map style (objectui#5017) and which is the node's own inline CSS record; and the React props ofObjectMapProps(clusterRadius, thedataARRAY prop, the four callbacks,className,dataSource).object-gantt—plugin-gantt/src/ObjectGantt.tsx, registry shellplugin-gantt/src/index.tsxobjectName:1359(layout key),:1491(navigation),:1873(export name)z.string().optional()dataresolveRecordSourceConfigat:593ViewDataSchemastaticDataz.array(z.unknown())filter:738—$filter: schema.filterz.array(ViewFilterRuleSchema)sort:739—$orderby: convertSortToQueryParams(schema.sort)z.array(SortItemSchema)gantt:499-501—getGanttConfigbranch 1; the registration's{ name: 'gantt', type: 'object' }input, and:501validates it against this repo's OWNGanttConfigSchemaGanttConfigSchemanavigation:1487—schema.navigation ?? { mode: 'drawer' }z.unknown()label:1871—resolveInlineI18nLabel(schema.label, displayLocale)in the export-file-name chain (:1849is the comment ABOVE that chain, not a read)I18nLabelSchemaskipWeekends:1205—!!swinto the working calendarz.boolean()holidays:1206—new Set(hol)for the duration mathz.array(z.string())persistLayout:1357—schema.persistLayout === falsez.boolean()viewName:1359— theobjectName:viewNamestorage keyz.string()markers:1826—markers={schema.markers}z.array(z.unknown())criticalPath:1829—criticalPathDefault={!!schema.criticalPath}z.boolean()showBaselines:1832—schema.showBaselines !== falsez.boolean()readOnly:1833,:1916—!!schema.readOnlyz.boolean()mobileReadOnly:1834—schema.mobileReadOnly !== falsez.boolean()Measured and deliberately NOT declared: the 30 flat
GanttConfigspellings branch 2 reads at:513-543(objectui#6469 inherited the objectui#5018 ruling for this block);title, which this renderer never reads; and a row cap — the reload's$topis the platform ceilingNON_GRID_ROW_CEILING_TOP, which the renderer's own comment marks 「⛔ Not authorable」.object-tree—plugin-tree/src/ObjectTree.tsx, registry shellplugin-tree/src/index.tsxobjectName:534,:570,:605z.string().optional()dataresolveRecordSourceConfigat:359— rung 1, returned VERBATIM as aViewData. That ONE site is the whole support for this armViewDataSchemastaticDataz.array(z.unknown())filter:474—$filter: schema.filterz.array(ViewFilterRuleSchema)tree:108— the nested blockgetTreeConfigreads; the registration's{ name: 'tree', type: 'object' }inputTreeConfigSchemanavigation:591—useNavigationOverlay({ navigation: (schema as any).navigation })z.unknown()dataIS on the row, and that is the measurement, not family symmetry. The card left this conditional — 「if the renderer's authored surface has nodata, the row declares none」 — and the condition is FALSE here: the renderer reachesschema.datathrough the shared ladder at:359, which returns it verbatim as aViewData. ⛔:496is not a second site for that arm, and an earlier revision of this body over-claimed it as one:(rest as any).data ?? (schema as any).datais gated byArray.isArray(passed)on the very next line, so it honours only the bare-ARRAY shorthand this row refuses — the same shorthandobject-mapmeasures and declines above. One ladder site is sufficient and:359is it, so the row stands on a corrected citation. What is absent is the DECLARATION, on both published faces:ObjectTreeSchemaon@object-ui/typesat this pin declares nodata, nostaticData, nofilterand nonavigationat all, and makesobjectNamerequired — four keys the renderer reads. That is precisely the mirror-is-wrong shape the ruling puts the protocol in front of, so the row follows the read points and the mirror is the face that has to follow.No
sort.ObjectTree.tsx:473-484issues$filter,$topand$expandand no$orderby, and nothing else in the file reads an order. Asortdoor here would publish a key with no read site — the exact defect #7751 exists to remove, in the other direction.Three derivation decisions, each pinned rather than left to review
ObjectView/ListViewbuild these nodes by spreadingoptions.map/options.gantt/options.tree's CONTENTS at the top level, carrying no block key at all; that is an internal transport form (objectui#5018, inherited by objectui#6469), and the map and gantt renderers name every flat key beside a present block as IGNORED in a dev warning. Writing one now gets a wrong-layer prescription naming the config block — the channelobject-calendaralready uses. Each set is held equal to the config block it points at (ListMapConfigSchema.shape;GanttConfigSchema.shapeplus the legacy singulardependencyField;TreeConfigSchema.shapeplustitleField, whichgetTreeConfig:117reads only aslabelField's last fallback), so it cannot drift silently.filterandsortare the family's one orthography from birth —ViewFilterRule[](ui#6206-B reaching the family: finding(spec): fourobject-*filterdoors inComponentPropsMapdeclarez.unknown()— no orthography at all — so they still accept the MongoDB-style record ui#6206-B retired, silently; the card that closed the lastFilterConditionSchemadoor assumed they declared the array #15449, batch Refactor: Separate authentication configuration from identity data models #55 option A) andSortItem[](objectui#8221, batch 🔗 Broken links detected in documentation #77 option B). A new door on a family-wide ruling has no "measured before the ruling" arm. The whole-map census pins incomponent.test.tsalready demanded it: everyfilterdoor must refuse the record form, and onlyrecord:related_listmay take a stringsort.gantttakesGanttConfigSchemabecauseObjectGantt.tsx:501literally validates the authored block against that schema, imported from@objectstack/spec/ui.treetakesTreeConfigSchema, which spec:GanttConfigSchemaisstrictObject(...).passthrough(), so a mistyped gantt key is silently accepted — the only one of the three view config schemas that does not refuse it #15469 shut against unknown keys on this very measurement, re-measured unchanged here.mapstaysz.unknown()— and that is measured, not conservative-by-default: the spec's ownListMapConfigSchemais strict and declares nostyle, the keygetMapConfig:365reads atschema.map?.style, so pointing this door at it would refuse a value the renderer honours today. The pin records the reason so the later value ratchet has one.Measured file face
13 files, all additive to a published surface; nothing retired, nothing narrowed.
No corpus moves: a whole-tree grep for an authored
object-map/object-gantt/object-treepage node finds zero outsidesdui.manifest.json(a registry dump, not authored metadata), against a positive control that findsobject-gridauthored twice inexamples/app-showcase.PageComponentSchema.typealready accepted all three through its open string arm and still does; what changes is that an authored props bag on one of them is judged instead of skipped.Verification
All readings below are at
e7967ce543(the branch tip) unless a row says otherwise, exit codes captured by redirect-then-$?, never through a pipe. The spec suite, typecheck and the generated-artifact checks were re-run after the patch round below.pnpm --filter @objectstack/spec buildpnpm --filter @objectstack/spec testpnpm --filter @objectstack/spec typechecktsc --noEmit+check:scripts-typecheck+check:test-typecheck)pnpm --filter @objectstack/lint testComponentPropsMapconsumer; its closure built first)pnpm --filter @objectstack/lint typecheckpnpm --filter @objectstack/spec check:generated--fixregenerated the 5 it proved staleMANIFEST=… check:react-declaration-parity --baseline … --strictobject-map2 both / 7 spec-only / 0 registry-only,object-gantt2 both / 14 spec-only / 0 registry-only; baseline ratchet: no new divergencepnpm exec eslint . --no-inline-config --format jsonscripts/pm/dispatch-gates.mjs --commands)packages/spechas no workspace dependencies, so the dependency-closure build is an empty run by construction.CI on this head is not enumerated here and is not claimed green — the verdicts above are local runs only.
Patch round — the at-tier review's two text findings, and the citations
The contract review returned PASS; these are the three things its scope did not settle, all of them text or citation, with no key, no value shape and no row membership moved. Verified after the round rather than asserted: the three key sets read back identical,
ComponentPropsMapstill carries 48 rows,object-treestill accepts theViewDataobject arm and still refuses the bare array, the gantt block is still strict,object-chartis still absent.object-gantt's describes said "chart". Every sibling names its own noun, andobject-chartis the row this section deliberately leaves absent, so "chart" pointed an author at the one block with no row. Three describes now name gantt (objectName,label,readOnly). Proof on the shipping artifact —content/docs/references/ui/component.mdx, regenerated with the repo's owngen:docs, never by hand:Object this chart binds to→ 0;Object this gantt binds to→ 1, at:398; controlObject this NOUN binds to→ 6, unchanged, so all six blocks name their own noun exactly once.object-tree'sobjectNamegave a reason that is false for tree. It said the component-leveldataSourcebinding can supply the object. Measured at the pin53ded82b:plugin-tree/src/index.tsxhas 0 hits for theElementDataSource*wiring, against 7 each inplugin-map,plugin-gantt,plugin-gridandplugin-calendar— four controls, so the zero discriminates. The key stays optional; the reason is now the true one, the ladder's first two rungs (datacan name the object itself,staticDataneeds none), plus the explicit negative. In the generated doc the false reason reads 0 hits and the new line 1, at:768.labelat:1871(:1849is the comment), and treedataon:359alone.check:docswas red one3a256daa3— source fixed, shipping artifact not yet regenerated — and is green one7967ce543:check:docsexit 0, "223 generated files in sync with packages/spec";check:generatedexit 0, "All 15 generated artifacts are up to date";check:authorable-surfaceexit 0, which is whygen:schemahad nothing to write andgen:docswas the only stale artifact.pnpm --filter @objectstack/spec testexit 0, 482 files / 13727 tests, andtypecheckexit 0, both re-run after the round.git diff --name-only origin/main...HEAD -- content/docs/releases/→ 0 paths, against a control of 2 undercontent/docs/references/.On this head
Type Check · source gatesis completed / success — the job the red had truncated now reaches its end. The rest of CI is still running and is not claimed green.Patch round 2 — the at-tier review's FAIL: F1 blocking, F2 and F3 in passing
Review of record: comment
5696414075on this PR,VERDICT: FAILat heade7967ce543. That review re-derived the accept set, the public surface, all three key sets, every value posture and theminorlevel and judged them RIGHT — nothing in this round moves a key, a value shape, a row membership or the level. Text, plus the one regeneration it forces.F1 (blocking) — six describes named a function that does not exist in the code they describe. The
objectName/data/staticDatadescribes onobject-ganttandobject-treesaid the record source is resolved by, or "read FIRST/SECOND by",getDataConfig. Re-measured at the.objectui-shapin53ded82b, each file fetched withgit showin the same command block as its count:53ded82bgetDataConfigresolveRecordSourceConfigplugin-gantt/src/ObjectGantt.tsx:64, call:593plugin-tree/src/ObjectTree.tsx:41, call:359, comment:422plugin-map/src/ObjectMap.tsx(control)The control discriminates, and it also settles what the map keeps:
ObjectMap.tsxreally does hold a localgetDataConfigat:135— the array-shorthand head, delegating to the shared ladder at:174— so the three map describes are TRUE and keep the name. Gantt and tree reach the shared three-rung ladder directly:resolveRecordSourceConfigin@object-ui/coreutils/record-source.ts:146, rungs at:151(data, returned verbatim),:155(staticData, wrapped as{ provider: 'value', items }) and:162(objectName, folded to{ provider: 'object', object }). So the ladder ORDER those six sentences describe was already true and only the name was wrong; the six now nameresolveRecordSourceConfig. Neither renderer has any reader above its ladder call, so "read FIRST" is literal for both — unlike the map, whose array head runs first, which is the second reason its describes keep the wrapper's name.Both sides counted, because this trap already bit this PR once. An earlier round fixed a false describe in the source alone and
check:docscaught the generated doc still carrying the old text. Aftergen:docs, atc431c22e05:getDataConfigresolveRecordSourceConfigpackages/spec/src/ui/component.zod.ts:3226:3242:3244content/docs/references/ui/component.mdx:638-640:398-400, tree:768-770Both sides read 9 and 0 before the round. The generated diff is exactly six table rows; no map row moved.
F2 —
component.zod.ts:3545, the treedatafield JSDoc, cited two read points where the schema header at:3487already rules that:496is not a second site for the object arm. It cites:359alone now. Source comment; no artifact follows it.F3 — two citations off by one line, both re-read at the pin:
getGanttConfig'ssafeParseisObjectGantt.tsx:500(:501is theif (!result.success)beneath it), and the tree's "Not authorable" marker isObjectTree.tsx:482, not:477.Verification for this round
pnpm --filter @objectstack/spec build, thencheck:generated— exit 0, all 15 artifacts up to date includingcheck:docs, withcontent/docs/references/ui/component.mdxactually regenerated bygen:docsrather than hand-edited. Before the regeneration the same gate named that one artifact, and only it, stale.pnpm --filter @objectstack/spec test— exit 0, 482 files / 13727 tests.pnpm --filter @objectstack/spec typecheck— exit 0.check:objectui-pin-citations— exit 0, 26 asserting pin citations match53ded82bf. It verifies the sha, not the line numbers, and reports 0 anchor content assertions here: F3 was measured by hand at the pin, not caught by this gate.dispatch-gatesderives for this change set were run locally, every one exit 0; the remaining 75 are the repo-wide farm CI owns. A declared narrowing, not a silent skip.pnpm lintnarrowed to the diff, with the three readings that make the narrowing a measurement: the population is eslint's own**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}and eslint itself answers the regenerated.mdxwith "File ignored because no matching configuration was supplied", so the linted population of this diff is one file;--format jsonreports 1 file, 0 errors, 0 warnings; and no type-aware linting is configured anywhere ineslint.config.mjs(noprojectService, noparserOptions.project), so a comment-and-describe edit in one file cannot move any untouched file's verdict.Acceptance notes
Docs Drift Check, re-verified rather than waved through
The drift check flagged 6 hand-written pages. Each was re-read; none needs an edit, and the readings are here rather than implied by their absence from the diff.
content/docs/protocol/objectui/layout-dsl.mdxdoes not ride this PR — measured, not assumed. It is flagged via the symbolComponentPropsMap, which it names exactly once, at:721, and as a MECHANISM: "For the platform's own types the authoring rules dispatchComponentPropsMapand reject a misspelled prop; acustom.*type has no entry there." That sentence is still exactly true after this change — three more types now have entries, and it enumerates none. The page carries no register of the object-block family at all: no table, no list, and its only numeric completeness claim is about breakpoints (:579). The discriminating control:object-calendarandobject-formeach get 0 hits on that page, and both have carriedComponentPropsMaprows since A typo'd key inside a page component'spropertiesis accepted in silence — the props bag is a passthrough record and the SDUI props gate has no schema to dispatch forobject-*blocks #7751 landed on 2026-08-12 — so the page already omits 2 of the 6 pre-existing rows, against a positive control ofobject-metric(3),object-master-detail-form(3),object-kanban(2),object-grid(1). A page that has never tracked the row set is not a list this change makes incomplete; its### Metric Widget/### Master-Detail Forms/### Kanban Boardsections are chosen worked examples. Writing three new hand-written renderer sections would be new documentation of three renderers, which is a card, not a rider on "add three rows".content/docs/ui/views.mdx,concepts/architecture.mdx,getting-started/common-patterns.mdx,protocol/kernel/i18n-standard.mdxandui/field-grouping-and-order.mdxeach get 0 hits forComponentPropsMapand 0 forobject-map/object-gantt/object-tree. They are reached only through string literals that this PR's newOBJECT_GANTT_FLAT_CONFIG_GUIDANCEkey array happens to contain —groupByField,timeZone,colorField,startDateFieldand friends.views.mdxdocuments the LIST-VIEWganttblock (type: 'gantt'withgantt: { startDateField, … },:340-352), whose schema isListViewSchema.gantt/GanttConfigSchemainview.zod.ts— a file this diff does not touch at all, so that page's vocabulary is unmoved.content/docs/releases/; they are read-only.git diff --name-only origin/main...HEAD -- content/docs/releases/returns 0 paths, against a control of 2 paths undercontent/docs/references/in the same diff, so the zero is a reading and not an empty filter.component-reference-rail.test.tsneeds no change — the reading, not the omissionThe card names it among "the vocabulary tests that pin the row set". Measured on this branch: the file is 164 lines, mentions
ComponentPropsMap4 times, and every one of them is the single subscript['record:reference_rail']or prose about that one row (:3,:21,:33,:35).Object.keys(ComponentPropsMap)→ 0 hits; anyobject-type literal → 0 hits. Control, the same two probes oncomponent-type-vocabulary.test.ts, which genuinely does pin the row set: 6 and 8 ⇒ the zeros discriminate. All twelve of itsdescribe/itsubjects arerecord:reference_railbehaviour. It reads no property of the row SET, so nothing in it can move when threeobject-*rows land — and it passed unchanged inside the 482 green spec files above.The row-set pins that DO move with the rows are
component.test.ts(six ruled blocks to nine, plus the filter / sort / plural-filters/ optional-objectNamedoor lists, plus a new describe) andcomponent-type-vocabulary.test.ts. The reference rail that regenerates is the docs one,content/docs/references/ui/component.mdx.Out of scope for this PR, noted rather than fixed
Each with the measurement that found it:
ListMapConfigSchemadeclares no map style at all. The spec's list-view map block is strict and has neitherstylenormapStyle, whileObjectMap.tsx:365readsschema.map?.styleand objectui'sObjectMapConfigSchemadeclaresstyle.ListMapConfigSchema.safeParse({ style: '…' })is refused — pinned as a negative in this PR's own tests, because it is the reasonobject-map.mapstaysz.unknown(). An author cannot declare a map style through the spec's list-view face today. Carrier: this PR'smapvalue ratchet, whenever it is taken.object-treeis absent from the trackedsdui.manifest.json.check:react-declaration-parityprintsobject-tree: NO component in the manifest — not registered or not public, althoughplugin-tree/src/index.tsxregisters it under bothobject-treeandtree. The baseline ratchet is unaffected (a block with no baseline row cannot regress), so this PR is green either way, but the new row gets no parity comparison. Carrier: the nextsdui:manifestregeneration.pnpm check:cross-package-test-inputsis sensitive to local build state, not to this diff. It exits 1 in a worktree wherepackages/spec/dist/exists and 0 where it does not — measured here as a one-variable control, with the diff held constant and the directory restored byte-identically (216 files,dist/ui/index.mjshash unchanged). It namespackages/cli/test/init-created-files-summary.e2e.test.ts, which symlinkspackages/spec/distat:115; this PR touches neitherpackages/clinorturbo.json. TheLint & Repo Gatesjob runs it on an unbuilt tree, which is why CI is green on it.objectui#9239has moved since the card was written. The card describes it as an open, separate calendar-mirror contradiction; it isclosed completed. Nothing in this PR depends on it, andobject-calendaris untouched.53ded82b,packages/types/src/zod/objectql.zod.tsdocblock:726statesgetDataConfigis inplugin-gantt/src/ObjectGantt.tsx, and threeObjectGanttSchemadescribes repeat the name (:738,:739,:838) — while that file has 0 occurrences of it (control:ObjectMap.tsx8, and the map's own mirror describes at:641-643are correspondingly TRUE). Separately,core/src/utils/record-source.tsquotes our describes as the ruled contract at:28,:92,:95and:97and attributes the text to the map and gantt zod twins, so after this PR that quotation matches the map twin and no longer matches the gantt one. Both sites are objectui's, in objectui's repo; nothing here can fix them and the pin does not move. Handed to the seat to file against objectui rather than fixed in passing.Not touched, deliberately: the
object-chartdeliberate-absence note incomponent.zod.ts, pinned as still absent in the new tests.objectui#8348 carries
pm:blockedon this card; its remaining slice judges map / gantt / tree against these rows once this lands. Nothing here changes any objectui file.Authored by the
domain:specexecution seat, sessionsession_01KB5PFtxuy1x3dcR5gxudx6.Generated by Claude Code