Uh oh!
There was an error while loading. Please reload this page.
fix(types,fields): correct three false spec-alignment claims and pin the real boundary - #7510
Merged
Merged
Conversation
…the real boundary
Three doc comments asserted that the installed `@objectstack/spec` declares a
key it in fact REFUSES BY NAME. Measured on 17.2.0, each with a control that
accepts the same payload minus the key:
SelectOptionSchema.description unrecognized_keys (shape is exactly
{label,value,color,default,visibleWhen})
FieldSchema.rows unrecognized_keys (all four of
textarea/markdown/html/richtext)
The keys stay declared and stay consumed (objectui#6153 LookupField searches an
option's `description`; objectui#6140 RichTextField reads `rows`). Only the
attribution was wrong, and it mattered: FieldSchema routes a select field's
`options` through the strict option schema, so authoring `description` on an
option fails the WHOLE field with 422 INVALID_METADATA. The comments were
inviting that write; they now name the boundary instead.
A false canonical claim is a planted premise for the next agent — the failure
class scripts/check-spec-symbol-derivation.mjs exists to prevent. It could not
see these: it reads only the comment block attached to a DECLARATION, and
validates a citation only at SYMBOL granularity. Both claims sit on MEMBERS and
dangle at the member (`SelectOptionSchema` is a live export; `.description` is
not a key of it).
No type, schema, export or runtime path changes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyCContributor
✅ Console Performance Budget
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
Size Limits
|
os-project-manager
marked this pull request as ready for review
September 3, 2026 15:45
This was referenced Sep 3, 2026
Uh oh!
There was an error while loading. Please reload this page.
os-project-manager
deleted the
claude/issue-7014-select-option-shapes
branch
September 3, 2026 16:01
This was referenced Sep 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #7014
Clause-②: no— no type, schema, export or runtime path changes. Justification in the claim comment on #7014.The card's structural diagnosis is stale — corrected here
#7014 says the gate is blind because "both rules skip any declaration without an
exportmodifier (hasExportModifier, applied once per scanner)". On today'smain(a27d153c2) that is no longer true. Both halves of the filter were removed in objectui#6291;hasExportModifiersurvives atscripts/check-spec-symbol-derivation.mjs:980with zero call sites, andscanFilecarries the literal comment// No export filter (objectui#6291).The card's conclusion is correct and survives — the class really is invisible to its own gate. It is invisible for three different, still-live reasons, set out in the report and summarised at the bottom of this body.
What this PR fixes
Three doc comments asserted the installed
@objectstack/specdeclares a key that it in fact refuses by name. Measured on@objectstack/spec@17.2.0, each paired with a control that accepts the same payload minus the key:packages/types/src/field-types.tsSelectOptionMetadata.description@objectstack/specSelectOptionSchema.description"REJECT unrecognized_keys(description); controlACCEPTpackages/types/src/field-types.tsMarkdownFieldMetadata.rows@objectstack/specFieldSchema.rows(a positive integer, authorable on exactly the multiline editor types)"REJECT unrecognized_keys(rows)on all four of textarea/markdown/html/richtext; controlACCEPTpackages/types/src/field-types.tsHtmlFieldMetadata.rows@objectstack/specFieldSchema.rowsdeclares it for the multiline editor types"packages/fields/src/widgets/LookupField.optionDescription.test.tsx@objectstack/spec'sSelectOptionSchema.description"SelectOptionSchemais.strict()over exactly{label, value, color, default, visibleWhen}— five keys, nodescription, noicon, nodisabled.The keys stay declared and stay consumed.
LookupFieldgenuinely searches an option'sdescription(objectui#6153) andRichTextFieldgenuinely readsrows(objectui#6140). Only the attribution was wrong — and it mattered in a specific way:FieldSchemaroutes a select field'soptionsthrough the strict option schema, so authoringdescriptionon an option fails the whole field:That is the same failure class already documented in
MetadataService.tsforindexed/referenceTo/formula— a designer-authored key that makesPUT /api/v1/meta/object/:namefail 422INVALID_METADATA. The comments were inviting exactly that write; they now name the boundary instead.A false canonical claim is not stale documentation — it is a planted premise for the next agent, which is the whole failure class
check-spec-symbol-derivation.mjsexists to prevent.New pin
packages/types/src/__tests__/select-option-spec-extension-7014.test.ts(15 tests) asserts the spec's option key set and each by-name refusal, every one paired with an accepting control. If the spec ever adoptsdescription/icon/disabled, the claim re-opens loudly instead of silently becoming true.Verification — all readings at head
71e7e5dbTest Files 1 passed (1)/Tests 15 passed (15)field-metadata-rows-option-description-6140,select-option-spec-parity,bulk-action-param-options,LookupField.optionDescription)Test Files 5 passed (5)/Tests 36 passed (36)type-check(@object-ui/types,@object-ui/fields)lint(both changed packages, in full)911 problems (0 errors, 911 warnings), all pre-existingcheck:spec-symbols✅ spec symbol derivation: 1344 files scanned against 4959 spec export names; 18 declared dialects, 14 untriaged collisions in 7 packages./✅ spec alignment claims: 2 declared deliberate copies, 19 unbacked claims in 5 packages.check:control-bytes✅ check-control-bytes: OK (scanned 6196 tracked text file(s); skipped 85 binary).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 amajorbump.check:dist-completeness✓ dist completeness: 7 package(s) complete (522 emitted files verified); 5 not built yet, 2 type-check-onlycheck:readme-exportsits type entry ./dist/index.d.ts is not on disk -- run pnpm build first. Needs a full 40-package build; unrelated to this diff, which touches no README and no export.Reverse verification. Implementation committed first, then the pin mutated into the world the old comments asserted — key set widened to include
description, and the refusal loop repointed atcolor(a key the spec accepts). Mutation proven on disk in both directions (injected text present ×2, removed text absent ×2, blob11a1a4bf→697a2bad). Result:Tests 2 failed | 11 passed (13)— exactly the two mutated assertions red, all 11 controls green including the wholerowsblock. Restored undertrap … EXIT INT TERMwithgit checkout HEAD -- <abs path>, and proven by state: worktree blob back to11a1a4bf= HEAD blob,git diff HEADempty,git statusclean.Which tsc leg sees the pin — measured with
--listFiles:tsc --noEmit→ 0 hits;tsc -p tsconfig.test.json→ 1 hit. The package'stype-checkscript runstsc --noEmit && tsc -p tsconfig.test.json, so CI runs both legs and the pin is inside the checked program. (The edited source filefield-types.tsis in both.)Lint narrowing, declared. Rather than the repo-wide
pnpm lint, both changed packages were linted in full — broader than the changed files, narrower than the repo. The narrowing is safe because ESLint here is not type-aware: noprojectServiceand noparserOptions.projectanywhere ineslint.config.js, so this diff cannot move the verdict on any file it does not touch. ESLint's own count over the 3 changed files: 3 linted, 0 errors, 7 warnings.check:spec-symbolsprints byte-identical output before and after this change (verified bydiff). That is the finding, not a pass. This PR removes three real false claims and the gate cannot tell. Reporting it as a green gate would be the exact failure the card warns about.It cannot see them for three independent, still-live reasons:
attachedDoc(stmt, text)). All three claims sit on members.SelectOptionMetadata's own docblock is just/** Select option */.aligns with. The real comment says bare "Aligns" — measured:findClaim(...)returnsnullon the actual text, and returns a claim on the same text with "with" inserted.SelectOptionSchemais a live spec export, so the dangling-citation precision rule (objectui#4607) does not fire, although.descriptionis not a key of it.Sizing for the ruling, since #7014's 47-vs-18 figure refers to the already-shipped export widening: a member-granularity citation check over the tree finds 3 genuinely dangling member citations — the two fixed here plus
DashboardSchema.title, filed as #7509 — once Zod's own method surface (.safeParse,.parse,.shape) is excluded, which is 22 of the 27 raw hits. Three, not thirty. Whether to build that check is a decision for the seat and is not taken in this PR.Not in this PR, on purpose
ObjectFieldInspector'spatchOptionswrites an option with nolabelwhen the label is empty (if (o.label) out.label = o.label), while the spec requireslabel. Real defect on an authoring surface, but narrowing it is a contract decision — escalated, not guessed.🤖 Generated with Claude Code
https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
Generated by Claude Code