Skip to content

feat(types)!: ObjectMapConfigSchema is strict, so objectui validate refuses an undeclared map key (objectui#5157) - #10997

Merged
objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/issue-5157-map-config-strict-a
Sep 28, 2026
Merged

objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/issue-5157-map-config-strict-a

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #5157
Clause-②: yes — a published schema's accept set narrows: an undeclared key inside an object-map node's map block stops validating.
Ruling-ref: 5328158731 (B, the map block only) and 5871202958 (batch #238 item 2, letter A, maintainer 「同意」 2026-09-28T13:48Z)

Fix round 1 (bf4797f85f and d5c28d4da2, following contract review 5873208537):

  • the markdown-test-inputs ledger entry for the new pin (CI's Test (shard 1/8));
  • the runtime wording in the plugin-map README and docs page (a latitudeFieId typo draws the "Map configuration required" refusal, not a map);
  • the two docblocks that were stale since objectui#8169;
  • the changeset's "no diagnostic anywhere", corrected because a TypeScript author's compiler did name the key.

No code line moved.

Implemented by the domain:ui seat 2 dispatch, session https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN, claim comment 5872032029.

What changed

  • ObjectMapConfigSchema (packages/types, zod/objectql.zod.ts) closes with .strict(). ObjectMapSchema.map is this object, so the declared face, the runtime check ObjectMap runs and the validate face now share one accept set. .shape is unchanged: the same eight keys, so ObjectMap's FLAT_MAP_CONFIG_KEYS (derived from .shape minus style, seven keys) and the view flatten whitelists (hand-listed, pinned against .shape) see the same keys as before.
  • packages/plugin-map/src/ObjectMap.tsx is not changed. Its existing safeParse of the block now fails on an undeclared key, and the existing console.warn names the key.
  • Docs: the plugin-map README, the plugin-map docs page and the types README now say the map block is closed. No sentence anywhere said the block tolerated unknown keys, or that validate accepted them. The types README said the whole rendering face, every named mirror included, is tolerant, so it now names the map block as a closed sub-block on that face.
  • Changeset: '@object-ui/types': minor. It states the narrowing and the measured breakage, which is none.
  • ⛔ No other component sub-block is touched (the ruling's standing condition).

Pins: red on base, green on head

"Base" here means the head tree with .strict() ablated. The ablation used ablation-replace.mjs (objectstack origin/main copy): anchor }).strict(); went x1 to x0, and the blob went 7ef2545fa19c to 4d0b11cad207. The restore was proven by blob == HEAD (7ef2545fa19c) and an empty git diff HEAD. The pins resolve @object-ui/types/zod through the root vitest alias to packages/types/src/zod/index.zod.ts, so no dist/ is involved.

Pin File Base Head
(ii) safeValidateSchema refuses the typo block: exactly one issue, unrecognized_keys at map, keys latitudeFieId object-map-config-strict-5157.test.ts ❌ ✅
(ii) ObjectMapSchema refuses it at the same path same ❌ ✅
(ii) ObjectMapConfigSchema refuses it, naming the key at the block root same ❌ ✅
(ii) the same node one level down, inside a div's children, is refused same ❌ ✅
(ii) control: the clean block validates, alone and nested same ✅ ✅
.shape still declares the same eight keys; every declared key together parses same ✅ ✅
(iii) the sweep: 20 blocks, each parsed as a map block and validated inside an object-map node (40 rows) same ✅ ✅
(i) runtime: the typo block (which also binds locationField) renders the map and places the marker the declared keys bind ObjectMap.strictConfigWarn-5157.test.tsx ✅ ✅
(i) runtime: [ObjectMap] Invalid map configuration is warned, and its arguments name latitudeFieId same ❌ ✅
(i) control: a clean block warns nothing about its configuration same ✅ ✅

Run totals: base Tests 5 failed / 46 passed (51), head Tests 51 passed (51). Exactly the four (ii) refusal rows went red, plus the runtime warn row. That fifth red is expected. At base the typo parses clean, so the warning never fires, and that silence is the card's own symptom. The runtime row that is green on both sides is the render half. The pin's map still draws, with no throw, because its fixture also binds locationField. The card's own latitudeFieId typo alone leaves no coordinate binding, so it draws the "Map configuration required" refusal (objectui#8169) rather than a map.

The sweep (iii)

I re-derived the population with git ls-tree plus a git grep for a map key. It covers objectui examples / apps / content at 40c076fc2d and objectstack examples / apps at 3cf6449389. I reconciled every hit by hand, and I did not reuse the old report's list.

  • objectui: 18 blocks. content/docs/plugins/plugin-map.mdx has 13 brace-literal blocks plus the mapConfig variable in its TypeScript Support section. content/docs/fields/location.mdx has 1. The schema-catalog plugin-map JSON has 3 (event-venue-finder, real-time-delivery-tracking, store-locator-map). The one other grep hit is a catalog entry keyed map (id / meta / schema), which is not a config block.
  • objectstack: 2 blocks, both titleField + locationField: the app-showcase task.view.ts map list view, and task-map-marker-title.test.ts. The other hits are a translations label, the view keyed map, and a comment, none of them a config block.
  • Result: 20 of 20 use declared keys only, so no block is newly refused. The population is held as the SWEEP fixture, with each row naming its source by path and a quoted anchor, never a line address. The fixture header says the population is a snapshot. The three catalog entries are also re-read live and validated whole by ObjectMap.catalogRecordSource-6939.test.tsx, which is green on head.

The nested-document measurement

Measured with the built CLI (packages/cli/dist/cli.js) against built @object-ui/types, on fixtures from the seat's scratchpad. For base, I rebuilt @object-ui/types with .strict() ablated. A dist preflight read the ObjectMapConfigSchema closer in dist/zod/index.zod.js as });, and afterwards I restored and rebuilt, and the closer read }).strict(); again.

objectui validate, root typo node: head exits 1:

1. Unrecognized key: "latitudeFieId"
   Path: map
   Code: unrecognized_keys

base exits 0 with ✓ Schema is valid!.

objectui validate, the same node inside a div's children: head exits 1. The top-level issue is generic, but the arm detail printed under it names the key:

1. Invalid input
   Path: children
   Code: invalid_union
   ...
   1.6 [arm 1/6] Unrecognized key: "latitudeFieId"
       Path: children → 0 → map
       Code: unrecognized_keys

That is 1 of 10 arm sub-lines. The other nine are the non-matching arms (expected object / string / number / boolean / null). base exits 0 with ✓ Schema is valid! and Children: 1.

objectui check (advisory) over a directory holding the root typo, the nested typo, a root typo that also carries className, and the clean node exits 0 on both sides:

  • head lists only the root typo file, under ⚠️ 1 file carries a registered ObjectUI component type but did not validate as an ObjectUI schema, then prints ✓ All checks passed.
  • base lists nothing and prints ✓ All checks passed.
  • check validates only to recognise a file. A root that carries a structural key (children, className, …) is admitted without being validated, so the nested typo and the className typo stay invisible to check. The command's own description sends the verdict to objectui validate.

⇒ The rendered refusal names the key at both depths, so under the ruling's condition this needs no follow-up card. The noise around the nested line is recorded in the Acceptance notes.

Gates

Everything below is at head d68b1086ed. Test runs went through os-verify-lock.sh, and every verdict line is quoted from that run.

  • Tests: pnpm exec vitest run --maxWorkers=2 packages/types/ packages/cli/ plus the 31 test files outside those packages that read ObjectMapConfigSchema / ObjectMapSchema / FLAT_MAP_CONFIG_KEYS or author an object-map (found with git grep), plus examples/schema-catalog/test/. Result: Test Files 358 passed (358), Tests 9311 passed (9311).
  • pnpm exec vitest run --maxWorkers=2 packages/plugin-map/ plus the new types pin: Test Files 34 passed (34), Tests 243 passed (243).
  • pnpm --filter @object-ui/types type-check, @object-ui/plugin-map type-check and @object-ui/cli type-check: VERDICT command-exit 0. Both new test files are in their package's tsconfig.test.json (--listFilesOnly, 1 hit each). The plugin-map^... dependency closure was built first.
  • The strict-twin and mirror-parity pins (strict-authoring-face-8345.test.ts, zod-mirror-parity.test.ts) are inside the types run above, and green.
  • check-changeset-presence: ✅ 3 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s).
  • check-changeset-no-major: ✅ No changeset declares a major bump.
  • check-changeset-overwrite: ✅ No pre-existing changeset was modified or deleted.
  • check:changeset-claims (report-only) exits 0. It lists 22 pending changesets that name a file this change touches. I re-read the seven that mention map, strip or tolerance, and none describes ObjectMapConfigSchema's accept set.
  • check:pending-changeset-literals: ✅.
  • check:new-line-citations: VERDICT new-cross-file-line-citations: 0 new citation(s).
  • check:control-bytes: ✅ OK. A self-scan of the changed files for control bytes found none.
  • check:spec-symbols: ✅.
  • check-doc-links: Links are valid across 17 scan roots.
  • check:doc-fences, check:doc-types, check-prompt-component-keys, check:test-path-roots, check:vi-mock-specifiers: all ✅.
  • Governed-surface test on the changed paths: ✅ NOT GOVERNED.
  • ESLint on the three changed TS files with --no-inline-config --format json: 0 errors, 0 warnings on the two new pins. The one warning in objectql.zod.ts predates this change. This is a narrowed run: the config enables no type-aware linting, so this diff cannot move another file's verdict. The repo-wide lint is CI's.
  • Eager closure: @object-ui/types/zod is not in the console's eager closure. The console build's own guard printed [plugin assert-types-zod-stays-lazy] ... 1 chunk(s) holding the validators, none in the eager closure, and pnpm check:eager-closure reads ✅ Console eager closure is 3103.9 KB gzipped ... (budget: 3104.5 KB, headroom: 0.6 KB). That is the same reading the dispatch quoted, so the delta is 0.0 KB at the gate's precision.
  • git merge-tree --write-tree origin/main HEAD against a fresh origin/main f667c1df97 exits 0 (clean). None of the four commits that landed since the base touch these files.
  • NOT MEASURED: check:doc-snippets / check:doc-examples. Reason: they compile against every built package. This diff adds no code fence and changes no TypeScript declaration, so CI's run is the reading.

Acceptance notes

  • The dispatch expected the runtime pin (i) to be green on base. Measured, only its render half is. Its warn half is red on base, because the tolerant schema never fails the safeParse, so nothing is warned. The ablation above shows it.
  • The dispatch said FLAT_MAP_CONFIG_KEYS stays at 8 keys. .shape has 8 keys. FLAT_MAP_CONFIG_KEYS filters out style and has 7, before and after.
  • Nested diagnostics: the key is named, but as sub-line 1.6 of 10 under a generic invalid_union, and nine of those lines describe arms that were never candidates. That is a readability note on the CLI's arm printer, not a missing diagnostic. I filed no card.
  • objectui check admits a file whose root carries a structural key without validating it, so no depth of map typo in such a file reaches check. It is advisory by its own description. Recorded, not filed.
  • The docblock of warnOnTopLevelStyleUrl in ObjectMap.tsx still says @objectstack/spec list-view schemas "declare no map block at all". On spec 17.4.0, ListViewSchema declares map, and it refuses latitudeFieId with unrecognized_keys at map. That is a stale comment in a file this change does not touch. Noted, not fixed here, and no carrier.
  • Siblings with the same shape (a declared config sub-block that does not close) exist, for example the object-calendar node's calendar block (spec-derived, kept .passthrough()) and plain z.object config schemas such as SortConfigSchema, DrillDownConfigSchema and ReportExportConfigSchema. Not measured and not touched: the standing condition keeps generalisation out of this card.

Generated by Claude Code

…red map key is refused

`ObjectMapSchema.map` is this object, so `safeValidateSchema` (and
`objectui validate` with it) now refuses a `map` block carrying an undeclared
key with an `unrecognized_keys` issue at `map` that names the key, while
`ObjectMap` keeps rendering and warns through its existing `safeParse` channel.
`.shape` is unchanged.

Pins: the validate face (red without `.strict()`), the runtime face (renders
and the warning names the key), and the pre-landing sweep of every `map` block
found in authored metadata, held as a fixture.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN
A `'@object-ui/types': minor` changeset that states the narrowing: `objectui
validate` refuses an undeclared `map` key by name, `objectui check` stays
advisory, and the runtime keeps rendering and warning. The plugin-map README,
the plugin-map docs page and the types README say the block is closed.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN
@github-actions github-actions Bot added documentation Improvements or additions to documentation package: types plugin tests labels Sep 28, 2026
@github-actions

github-actions Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 22 pending changeset(s) describe a file this change touches

Their bodies publish verbatim into the CHANGELOG at the next release, so this is a request to re-read them against your diff — addressed here because you are the one seat that can answer it without re-deriving anything.

⛔ Nothing here blocks, and nothing here is a verdict on your change. This gate exits 0, is not a required context, and judges name resolution, never meaning: it asked whether a pending body names a file you touched. "Is this sentence still true?" is the one question it will not answer, and the one you are being asked to answer.

.changeset/10393-retire-bare-map-key.md

  • names plugins/plugin-map.mdx → content/docs/plugins/plugin-map.mdx — edited by this change

    The @object-ui/plugin-map README now describes one registered type, and its sentence claiming a bare array under data reaches the in-memory adapter is corrected: a bare array under data is not a record source on the map (objectui#8348), so inline rows belong under staticData. The same false claim is corrected on the two docs pages that carried it, plugins/plugin-map.mdx and fields/location.mdx.

.changeset/5903-objectgantt-declared-keys.md

  • names src/zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    Both halves move together. The TS declaration (packages/types/src/objectql.ts) and its zod mirror (src/zod/objectql.zod.ts) gain the same ten keys at the same requiredness — all optional — and no KnownDrift entry is added. navigation is taken from @objectstack/spec's NavigationConfigSchema by reference rather than restated, matching ObjectGridSchema.navigation.

.changeset/6940-rowactions-boolean-mirror.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    The list view's same-named rowActions in zod/objectql.zod.ts — z.array(z.string()), the legacy bare-name action list on ObjectGridSchema — is a different key that is correct as it stands, is in parity with its own TS twin (rowActions?: string[]), and is not touched.

.changeset/7113-chart-data-model.md

  • names objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    .extend() with a NEW key still works and preserves the fold and the refinement; .optional(), z.discriminatedUnion, z.toJSONSchema and safeValidateSchema are all unaffected. Nothing in this repository calls the throwing combinators on either const, and the published surface already ships refined mirrors (objectql.zod.ts, complex.zod.ts, form.zod.ts, app.zod.ts), so the class is not new — but it is a real behaviour change on a published export and it belongs in the release note rather than in a reviewer's file.

.changeset/7200-object-form-section-style-keys-undeclared.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    The authored-metadata type now agrees with @objectstack/spec, whose FormSectionSchema is a strict object declaring neither key, and with the ruling's rationale (maintainer 2026-09-01, verbatim): "retire the reads … Declaring the keys was weighed and not adopted: it would formally invite free Tailwind strings into authored metadata, the exact class the boundary exists to keep out." A ?: never tombstone was not used: ObjectFormSection has no zod mirror (ObjectFormSchema in zod/objectql.zod.ts does not declare sections), so there is no parse door to refuse at, and a tombstone is still a declaration in completion and in the published .d.ts.

.changeset/7265-types-user-filter-field-derives.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    zod/objectql.zod.ts declared two schemas under names @objectstack/spec/ui already exports. They were triaged separately, by reading their sites, and went different ways.

.changeset/7322-object-kanban-group-by-limit.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    Breaking for authored metadata: ObjectKanbanSchema.groupField is RETIRED (objectui#7322, ADR-0049 enforce-or-remove), and the two keys the object-kanban renderer actually reads — groupBy and limit — are now DECLARED and validated on both published faces: the TypeScript interface in objectql.ts and the Zod mirror in zod/objectql.zod.ts.

.changeset/7352-drill-down-config-mirror.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    DrillDownConfigSchema is the zod mirror of DrillDownConfig, and both declarations that carry drillDown reference it — ChartSchema (zod/data-display.zod.ts) and ObjectDataTableSchema (zod/objectql.zod.ts) — so the published validator under @object-ui/types/zod reads the key for the first time (objectui#7352).

.changeset/7363-objectql-union-arms.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    ObjectGallerySchema and ObjectDataTableSchema are members of ObjectQLComponentSchema on both faces — the TS union in objectql.ts and the zod union in zod/objectql.zod.ts — so AnyComponentSchema, and with it validateSchema / safeValidateSchema / objectui validate, has an arm for object-gallery and object-data-table nodes (objectui#7363).

.changeset/7917-export-breadcrumb-object-tree-zod-schemas.md

  • names objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    AnyComponentSchema declares 107 node component types. 105 of them could be named on the ./zod barrel — ButtonSchema.safeParse(node), which is what a designer, a form builder or a targeted test needs. The arms declaring type: 'breadcrumb' (navigation.zod.ts) and type: 'object-tree' (objectql.zod.ts) could not: both were already export const in their own module, but index.zod.ts — the package's only zod entry point — did not re-export them, so the schemas existed, were maintained, and were applied by the union while no consumer could name them.

.changeset/8221-retire-legacy-string-sort.md

  • names content/docs/plugins/plugin-map.mdx → content/docs/plugins/plugin-map.mdx — edited by this change

    Director ruling, decision batch Release v0.2.1 with changeset automation #77 (2026-09-07), option B. Three faces disagreed about one key: @object-ui/core implemented the string clause on purpose (sort-query.ts, docblock and all), content/docs/plugins/plugin-map.mdx taught it as sort?: string | SortConfig[], and the html tier answered type-mismatch for it because all seven sort registrations publish type: 'array' alone — while @objectstack/spec refuses the string outright on element-record-picker. Option A (per-block string arms) was rejected by name: it would make one key mean different things on different blocks.

.changeset/8478-describe-line-addresses.md

.changeset/8735-objectql-mirror-docblocks-not-defaulted.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    Correct four zod/objectql.zod.ts docblocks that described the behaviour objectui#8317 removed. Since that change the zod mirrors strip imported @objectstack/spec defaults at this package's import boundary, but the docblocks on HttpRequestSchema, ListColumnSchema, SelectionConfigSchema and PaginationConfigSchema still said, in the present tense, that method, prefix.type, type and pageSize are defaulted on parse — the opposite of what each export does. Each now says the key is declared and accepted but NOT defaulted on parse.

.changeset/8801-object-kanban-allow-collapse-retired.md

  • names packages/types/src/zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    • the declarations retired here — packages/types/src/objectql.ts and its mirror packages/types/src/zod/objectql.zod.ts; - the pins that assert the retirement — object-kanban-allow-collapse-retired-8801.test.ts and bare-kanban-node-key-retired-8802.test.ts; - a comment in packages/types/src/zod/complex.zod.ts, recording that the deleted retiredZeroReadKanbanKey helper once carried this spelling on the SIBLING arm; - one row of content/docs/api/schema-reference.md; - the .changeset/ release notes that discuss it — this one, the two historical entries covering the sibling arm's own spelling, and objectui#9629's note recording the correction to this paragraph.

.changeset/8885-object-chart-drilldown-title-compareto.md

  • names packages/types/src/zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    ObjectChart.tsx reads all three off schema, and until now neither published copy declared any of them: not the TS interface (packages/types/src/objectql.ts) and not the zod mirror (packages/types/src/zod/objectql.zod.ts). They rode BaseSchema's index signature / .passthrough() and arrived unvalidated. drillDown was the sharpest case — this component's registry inputs advertise it to the designer palette, and @objectstack/spec publishes ChartDrillDownSchema for exactly this carrier, so an author was offered a key that neither published shape mentioned.

.changeset/8913-object-kanban-columns-declared.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    What moved. ObjectKanbanSchema gains columns on both halves that move together — the TypeScript interface (objectql.ts) and its Zod mirror (zod/objectql.zod.ts). Retiring the bare kanban node type key (objectui#8802) removed the only face that judged a lane, and object-kanban had never declared the key, so it rode BaseSchema's [key: string]: any / .passthrough(): read by the renderer at three sites, named by no published face.

.changeset/8990-object-kanban-groupby-optional.md

  • names packages/types/src/zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    @objectstack/spec declares the key optional — groupBy: z.string().optional() on ObjectKanbanPropsSchema — while this package required it on the TypeScript declaration (packages/types/src/objectql.ts) and on the Zod mirror (packages/types/src/zod/objectql.zod.ts). objectui was therefore narrower than the protocol on a published key: ObjectKanbanSchema.safeParse and safeValidateSchema refused an object-kanban node the protocol accepts, and such a node could not be annotated with its own type.

.changeset/8992-user-actions-collapse-and-docblock.md

  • names objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    objectql.zod.ts's UserActionsSchema read stripImportedDefaults(Spec).extend({ group, hideFields, rowColor }), an extension that existed only because @objectstack/spec did not declare those three keys while normalizeListViewSchema folded objectui's legacy showGroup / showHideFields / showColor onto them. The protocol adopted all three in 17.3.0 (objectui#5435's ruling), so the extension is now a second local copy of a protocol declaration — the shape two faces start drifting from — and it collapses into the plain by-reference re-export its own note always said it would become.

.changeset/9309-object-gallery-filter-destination-typed.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    ObjectGallerySchema.filter is typed as the destination its own docblock names — QueryParams['$filter'] — on both faces, the TS interface in objectql.ts and the zod mirror in zod/objectql.zod.ts (objectui#9309).

.changeset/9511-record-id-is-a-string.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    The three authorable keys, each on BOTH faces. ObjectFormSchema.recordId (objectql.ts + zod/objectql.zod.ts), DetailViewSchema.resourceId (views.ts + zod/views.zod.ts) and DetailSchema.resourceId (crud.ts + zod/crud.zod.ts). ⚠️ The crud pair is DetailSchema, not DetailViewSchema, and it reaches the same renderer — not by symbol but by data flow: plugin-detail registers the 'detail' node type onto DetailView. A read that follows TypeScript symbols alone finds two keys and is incomplete.

.changeset/9549-tree-filter-declared.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    ObjectTreeSchema.filter is declared on both faces, in the shape objectui#9309 settled for ObjectGallerySchema.filter: QueryParams['$filter'] by indexed access on the TS interface in objectql.ts, and the same two-arm union (array first) on the zod mirror in zod/objectql.zod.ts (objectui#9549).

.changeset/9606-object-kanban-card-title.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    Both published faces of the object-kanban arm now name the key: the zod mirror ObjectKanbanSchema in zod/objectql.zod.ts and its TypeScript twin, the ObjectKanbanSchema interface in objectql.ts. Both declare it OPTIONAL, at the same requiredness the other face uses, so the two faces accept and refuse the same documents. (Located and cited by SYMBOL: line addresses in zod/objectql.zod.ts have drifted before, and this change is itself about a drifted mirror.)

Read the paragraph, not the line: both false halves of the objectui#8617 claim sat in one paragraph, and correcting either alone would have left it asserting the same wrong thing.

If a claim did go false, correct the body. That is precedented and prose-only, frontmatter untouched; check-changeset-overwrite.mjs will report the correction as its own case 2 ("correcting a declaration on purpose … legitimate"), which is the intended shape — one gate asks for the read, the other records the write.

Not covered, stated so nobody reads this as more: a born-false claim that spells no line address at all (objectui#9495 coordinated one by ORDINAL — "a grep finds that member first" — and deciding that means reading what the sentence means), a claim spelled as a symbol or a package rather than a backticked file name, and a file named ambiguously.

Compared the checked-out tree with 4b742f41d (merge-base with origin/main): 7 file(s) changed outside .changeset/, read against 1701 pending declaration(s) that publish a body (2303 pending in total). · run

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3104.0 KB 3104.5 KB
Main entry chunk (gzip) 149.8 KB 350 KB
Entry file index-DYpVls0T.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.58KB 6.17KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.17KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
auth (createAuthenticatedFetch.js) 8.52KB 3.45KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.13KB 7.95KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 558.92KB 133.97KB
core (index.js) 9.93KB 3.94KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 227.62KB 63.16KB
fields (index.js) 261.01KB 66.28KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.35KB 9.18KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.32KB 11.09KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.53KB 4.89KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.25KB 2.17KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.01KB 3.93KB
plugin-calendar (index.js) 51.96KB 14.83KB
plugin-charts (index.js) 84.09KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 137.83KB 36.71KB
plugin-designer (index.js) 215.78KB 44.42KB
plugin-detail (index.js) 233.49KB 61.79KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 161.21KB 41.41KB
plugin-gantt (index.js) 170.35KB 42.19KB
plugin-grid (index.js) 228.33KB 62.59KB
plugin-kanban (index.js) 48.43KB 15.11KB
plugin-list (index.js) 115.86KB 28.64KB
plugin-map (index.js) 22.90KB 7.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.17KB 12.20KB
plugin-timeline (index.js) 31.07KB 9.15KB
plugin-tree (index.js) 11.21KB 3.89KB
plugin-view (index.js) 89.44KB 22.41KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.81KB 3.58KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 119.16KB 39.05KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.03KB 1.86KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 7.50KB 3.05KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.16KB 2.71KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 18.27KB 6.22KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 3.83KB 1.49KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.26KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 17.15KB 6.32KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

…kdown-input ledger

`object-map-config-strict-5157.test.ts` names `content/docs/fields/location.mdx`
and `content/docs/plugins/plugin-map.mdx` as provenance on its sweep fixture
rows and opens neither, so it is recorded with an empty `reads` and both pages
under `notRead`. The declared entries, and so what `--list` / `--changed`
answer for any path, are unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: d68b1086edb8429b9c5e999ed54d156aa2216db4

① Derived judgments

1. The change matches the ruling: PASS.

  • The diff adds exactly one .strict(), on the closer of ObjectMapConfigSchema. It changes no .passthrough() or .strip() and closes no other object.
  • .shape is unchanged at 8 keys. ObjectMap.tsx is not in the diff.
  • Parse sites I found at head with git grep (non-test code):
    • ObjectMap.tsx getMapConfig: ObjectMapConfigSchema.safeParse. On failure it calls console.warn and returns the raw {...config}. It warns and never throws.
    • safeValidateSchema (AnyComponentSchema.safeParse), in two places:
      • objectui validate prints the issues and exits 1.
      • objectui check uses it only to recognise a file. A root object-map with no structural key moves to the advisory "did not validate" list, and the command still exits 0.
      • Both are authoring-time refusals, which the ruling covers.
    • @object-ui/types/zod validateSchema (AnyComponentSchema.parse): this throws, but it has no caller in packages, apps or examples; it appears only in a README example. A third-party caller is on the validate face, which the ruling covers.
    • StrictAnyComponentSchema (the objectui#5250 twin): it already refused this typo on base (dev report H2) and has no consumer outside tests. Re-deriving an already-closed object changes nothing, and no twin test touches object-map.
    • @object-ui/core validateSchema (the dev-mode validation in SchemaRenderer) imports no zod face, so it is unaffected. vscode-extension does not import the types zod face either.
    • Stored and named views:
      • ListView (resolveListMapConfig) and ObjectView (pickFlatMapConfig) pass only flat keys through hand-listed whitelists and never emit a map key. A view's map block therefore never reaches the strict parse, so stored views are not refused at runtime.
      • No member of ListViewSchema or ObjectViewSchema references ObjectMapConfigSchema.
    • Parity pins:
      • zod-mirror-parity registers the pair by name only.
      • The two mapFlatten pins read .shape and parse a block of declared keys only.
      • None of them reads the unknown-key policy, so all are unaffected.

2. The sweep: PASS. I re-derived it with git grep.

  • objectui main 4b742f41d2 (examples, apps, content):
    • plugin-map.mdx has 13 brace blocks plus the mapConfig variable, so 14.
    • location.mdx has 1.
    • The schema-catalog has 3 JSON blocks.
    • That makes 18, and every fixture row matches its source block key for key.
  • objectstack: I re-fetched main at bea6d2ea3b, which is newer than the fixture's 3cf6449389. It still has the same 2 blocks. One is on the named view map in task.view.ts, so a named-view block is included. The objectui population has no view-type map config.
  • Outside the ruled population, packages/plugin-map/README.md carries 3 blocks. All use declared keys only, so nothing needs to change.
  • Result: 20 of 20 clean.

3. The pins, judged by reading: PASS.

  • (ii) The 4 refusal rows are red on base, because the tolerant parse succeeds, and green on head. They assert the exact issue: unrecognized_keys at [map], keys [latitudeFieId]. The clean control is lit on both sides.
  • (i) The warn row serialises the warn's arguments and asserts that latitudeFieId is among them, so the key is named. It is red on base because no warning fires. The dev's deviation from the order ("green on base") is correct. The render row and the no-warn control are lit.
  • (iii) The 40 rows are green on both sides by design: they hold a population, and an 18/2 count guards against a vacuous fixture. The dev's ablation, 5 of 51 rows red, matches this reading.
  • The ruling's "FLAT_MAP_CONFIG_KEYS … (8 keys)" mixes up .shape (8 keys) with FLAT_MAP_CONFIG_KEYS (7, because it drops style). Both are unchanged by construction, and the dev's pin on the 8 .shape keys is correct.

4. BLOCKER: CI is red. Test (shard 1/8) failed, and so did the aggregate Test check.

  • The failing test is scripts/__tests__/markdown-test-inputs.test.ts. Its audit reports unadjudicated-test for packages/types/src/__tests__/object-map-config-strict-5157.test.ts: it "reads markdown the ledger does not describe (content/docs/fields/location.mdx, content/docs/plugins/plugin-map.mdx)".
  • The cause is the SWEEP rows, which name those two documents as provenance strings. The dev's local gate list never ran scripts/__tests__.
  • Fix: add this entry to ADJUDICATED in scripts/markdown-test-inputs.mjs, in path order:
  // objectui#5157. The SWEEP fixture names these documents as the provenance of
  // hand-transcribed `map` blocks; the test opens neither.
  [
    'packages/types/src/__tests__/object-map-config-strict-5157.test.ts',
    { reads: [], notRead: ['content/docs/fields/location.mdx', 'content/docs/plugins/plugin-map.mdx'] },
  ],

5. Rendering of the nested refusal.

  • objectui validate names the key: arm sub-line 1.6 of 10, at children → 0 → map. That meets the ruling's bar, so no readability follow-up is owed for validate.
  • objectui check prints the file and type "object-map" but never the key, at any depth.
    • A nested typo, or any file whose root carries a structural key, never reaches its validation step. It exits 0 with "All checks passed".
    • By the ruling's letter ("if the rendered message does not name the key, that is a follow-up card"), check meets that condition. The dev recorded it as "not filed".
    • The seat should file one follow-up card for objectui check, not for validate's arm printer, after this lands and not in this PR.
    • The ruling's premise that check refuses holds only for a root object-map with no structural key.

6. Docs and changeset: wording defects (blocking; fix in the same commit as item 4).

  • a. packages/plugin-map/README.md and content/docs/plugins/plugin-map.mdx both say "At runtime the map still renders". That is false for the example the same sentence names.
    • latitudeFieId in place of latitudeField leaves the block with no coordinate binding. hasCoordinateBinding needs locationField or the lat/lng pair.
    • So ObjectMap renders the "Map configuration required" refusal (objectui#8169). Each file documents that refusal in its very next section.
    • The runtime pin only draws a map because it also sets locationField.
    • Replacement text:
      • README: "At runtime ObjectMap does not throw: it renders from the declared keys and warns [ObjectMap] Invalid map configuration in the console, naming the same key; the undeclared key is never read. A typo that leaves the block with no coordinate binding, as latitudeFieId does, therefore draws the "Map configuration required" refusal below rather than a map."
      • mdx: "At runtime ObjectMap does not throw: it renders from the declared keys, and the console warns [ObjectMap] Invalid map configuration, naming the same key. A typo that leaves the block with no coordinate binding, as latitudeFieId does, draws the refusal described under "An unconfigured map refuses" rather than a map."
  • b. The objectql.zod.ts docblock says "…this object stripped it, parsed clean, and the map rendered empty with no diagnostic." That has been stale since objectui#8169: on base the typo already draws the refusal.
    • Replacement: "…this object stripped it and parsed clean, and nothing named it: the card's typo drew the generic "Map configuration required" refusal (objectui#8169), which names the key the author meant, not the one they wrote."
    • The plugin-map pin's docblock has the same stale claim. Replace "the card's symptom was an empty map and a quiet console" with "the card's symptom was a quiet console: no warning named the key".
  • c. The changeset says "and no diagnostic anywhere named it". That is false for a TypeScript author: the closed ObjectMapConfig interface makes the typo a compile error that names the key, as this PR's own docblock says. It is also false for the published strict twin.
    • Replacement: "and neither objectui validate nor the runtime named it (only a TypeScript author's compiler did)."
    • Every other changeset sentence checks out:
      • an undeclared key is now refused instead of stripped;
      • at the root, unrecognized_keys at map and exit 1;
      • nested, invalid_union at children, with the arm detail naming the key at children → 0 → map;
      • the check bucket behaviour matches isObjectUiSchemaFile;
      • the runtime warns and does not throw;
      • .shape is unchanged;
      • measured breakage is 0, with the snapshot caveat stated.
  • d. The packages/types/README.md change is accurate, and the rest of the paragraph stays true (a node stays tolerant; the twin is derived). "Refused by both faces" names the two zod faces, not the renderer. Nothing in the diff claims the runtime refuses.
  • Optional, not blocking: in the README and mdx, "at map" holds for a root node. A nested node reports under invalid_union at children, with the key in the arm detail.

7. No generalisation: PASS. Only the one closer changed. The siblings (the calendar block, SortConfigSchema, DrillDownConfigSchema, ReportExportConfigSchema) appear in the Acceptance notes only.

② Semver level

minor, Clause-②: yes. This is correct.

③ Boundary flags

Implemented-by: claude/issue-5157-map-config-strict-a
Reviewed-by: session_014mXUNuFomfj24w7s1pZzhN

VERDICT: FAIL

To land, the PR needs:

  • (1) the ADJUDICATED ledger entry from ①.4, so that Test (shard 1/8) goes green;
  • (2) the replacement wording in ①.6a to c, in the README, the mdx, the objectql.zod.ts docblock, the plugin-map pin's docblock and the changeset.

Separately, the seat should file the objectui check follow-up card from ①.5 after this lands.

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3104.0 KB 3104.5 KB
Main entry chunk (gzip) 149.8 KB 350 KB
Entry file index-DYpVls0T.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.58KB 6.17KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.17KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
auth (createAuthenticatedFetch.js) 8.52KB 3.45KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.13KB 7.95KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 558.92KB 133.97KB
core (index.js) 9.93KB 3.94KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 227.62KB 63.16KB
fields (index.js) 261.01KB 66.28KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.35KB 9.18KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.32KB 11.09KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.53KB 4.89KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.25KB 2.17KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.01KB 3.93KB
plugin-calendar (index.js) 51.96KB 14.83KB
plugin-charts (index.js) 84.09KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 137.83KB 36.71KB
plugin-designer (index.js) 215.78KB 44.42KB
plugin-detail (index.js) 233.49KB 61.79KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 161.21KB 41.41KB
plugin-gantt (index.js) 170.35KB 42.19KB
plugin-grid (index.js) 228.33KB 62.59KB
plugin-kanban (index.js) 48.43KB 15.11KB
plugin-list (index.js) 115.86KB 28.64KB
plugin-map (index.js) 22.90KB 7.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.17KB 12.20KB
plugin-timeline (index.js) 31.07KB 9.15KB
plugin-tree (index.js) 11.21KB 3.89KB
plugin-view (index.js) 89.44KB 22.41KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.81KB 3.58KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 119.16KB 39.05KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.03KB 1.86KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 7.50KB 3.05KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.16KB 2.71KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 18.27KB 6.22KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 3.83KB 1.49KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.26KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 17.15KB 6.32KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

…at named it before

A `latitudeFieId` typo leaves the block with no coordinate binding, so
`ObjectMap` draws the "Map configuration required" refusal (objectui#8169),
not a map. The plugin-map README and docs page now say the component does not
throw, renders from the declared keys and warns naming the key, and that a
binding-less typo draws that refusal; both qualify "at `map`" as the root-node
answer. The schema docblock, the runtime pin's docblock and the changeset no
longer describe the pre-#8169 empty map, and the changeset says what did name
the key before (only a TypeScript author's compiler). Frontmatter unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3104.0 KB 3104.5 KB
Main entry chunk (gzip) 149.8 KB 350 KB
Entry file index-DYpVls0T.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.58KB 6.17KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.17KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
auth (createAuthenticatedFetch.js) 8.52KB 3.45KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.13KB 7.95KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 558.92KB 133.97KB
core (index.js) 9.93KB 3.94KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 227.62KB 63.16KB
fields (index.js) 261.01KB 66.28KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.35KB 9.18KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.32KB 11.09KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.53KB 4.89KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.25KB 2.17KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.01KB 3.93KB
plugin-calendar (index.js) 51.96KB 14.83KB
plugin-charts (index.js) 84.09KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 137.83KB 36.71KB
plugin-designer (index.js) 215.78KB 44.42KB
plugin-detail (index.js) 233.49KB 61.79KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 161.21KB 41.41KB
plugin-gantt (index.js) 170.35KB 42.19KB
plugin-grid (index.js) 228.33KB 62.59KB
plugin-kanban (index.js) 48.43KB 15.11KB
plugin-list (index.js) 115.86KB 28.64KB
plugin-map (index.js) 22.90KB 7.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.17KB 12.20KB
plugin-timeline (index.js) 31.07KB 9.15KB
plugin-tree (index.js) 11.21KB 3.89KB
plugin-view (index.js) 89.44KB 22.41KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.81KB 3.58KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 119.16KB 39.05KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.03KB 1.86KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 7.50KB 3.05KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.16KB 2.71KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 18.27KB 6.22KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 3.83KB 1.49KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.26KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 17.15KB 6.32KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: d5c28d4da2f2560b5045ed1ec4a98e585321e8dc

This is an in-seat delta review of fix round 1: d68b1086ed to d5c28d4da2, two commits. I checked it against record 5873208537 (FAIL: the CI ledger entry and three wording defects; the code, pins, sweep and semver passed).

① Derived judgments

  • Scope: 6 files, +33 −11. The only line changes outside prose are one ADJUDICATED ledger entry and comment-only docblocks. The .strict() closer and every pin assertion are byte-identical to the reviewed head.
  • ①.4, the ledger: in place (bf4797f85f). object-map-config-strict-5157.test.ts is adjudicated with reads: [] and notRead for location.mdx and plugin-map.mdx, the reviewer's exact form, with a reason comment: the two paths are provenance strings, and the test opens neither page. The dev reports --audit: "106 candidate test files, all adjudicated". markdown-test-inputs.test.ts passes at head (3 files, 76 tests with the two pins).
  • ①.6a, the runtime wording: in place in the plugin-map README and the docs page. Both now say ObjectMap does not throw, renders from the declared keys and warns naming the key, and that a latitudeFieId typo, which leaves no coordinate binding, draws the "Map configuration required" refusal. The optional root-node qualifier for "at map" is also taken.
  • ①.6b, the docblocks: in place. The objectql.zod.ts docblock names the objectui#8169 refusal, and the plugin-map pin's docblock says "a quiet console: no warning named the key".
  • ①.6c, the changeset: in place. It now says "neither objectui validate nor the runtime named it (only a TypeScript author's compiler did)". The frontmatter is byte-identical.
  • The PR body: the seat rewrites the pin-(i) row and the render-half sentence at landing to say the pin's fixture also binds locationField, which is why it draws.
  • Commit trailers are the model-free Claude pair.

② Semver level

minor and Clause-②: yes hold, unchanged from 5873208537.

③ Boundary flags

  • CI: this record posts only after every check at d5c28d4da2 is final and green, Test (shard 1/8) included. The landing queue gates on it and re-runs git merge-tree against current main.
  • Follow-up owed (record 5873208537, ①.5): objectui check never prints the refused key, at any depth, and a nested typo or a root carrying a structural key never reaches its validation step. The seat files one card after this lands. It is not in this PR.
  • Landing: ready, auto-merge, and needs:contract-review removed.

Implemented-by: claude/issue-5157-map-config-strict-a
Reviewed-by: session_014mXUNuFomfj24w7s1pZzhN

VERDICT: PASS

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 28, 2026 15:48
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 28, 2026
Merged via the queue into main with commit d6d8fb9 Sep 28, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-5157-map-config-strict-a branch September 28, 2026 16:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation package: types plugin tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Decision] ObjectMapConfigSchema 要不要 .strict() —— 类型面的保证只保护 TS 作者,而 AI 产出的 metadata 恰恰不带类型

2 participants