Skip to content

fix(types,i18n): doc comments stop citing retired @objectstack/spec symbols (#4597) - #4606

Merged
yinlianghui merged 1 commit into
mainfrom
claude/issue-4597-dangling-spec-citations
Aug 13, 2026
Merged

fix(types,i18n): doc comments stop citing retired @objectstack/spec symbols (#4597)#4606
yinlianghui merged 1 commit into
mainfrom
claude/issue-4597-dangling-spec-citations

Conversation

@yinlianghui

Copy link
Copy Markdown
Collaborator

Fixes #4597

Eight exported declarations carried a doc comment claiming alignment with an @objectstack/spec symbol that the pinned 17.0.0-rc.6 does not export. This PR measures each one, rewrites the eight comments to state the true relationship, and deletes exactly those eight entries from the CLAIM_DEBT ledger.

Comments and ledger only. No type shape, no runtime behaviour, no export changed.

The headline finding: these are retirements, not phantoms

#4597 explicitly left open "whether the spec ever exported these names", and flagged that the fix differs per case. Measured against the published registry, the answer is that all eight were real exports the protocol retired on purpose, and every local key set was faithful to the schema it named. None of them was ever a wrong citation — they are citations that expired.

That distinction changes the fix. A name that never existed wants the sentence deleted; a name the protocol retired wants the retirement recorded, so the next reader does not re-run this measurement to rediscover it.

Measurement

Arbiter for (a) is the hardened gate's own specExportNames enumeration, reused verbatim: 16 subpaths, 4834 export names in the installed @objectstack/spec@17.0.0-rc.6. All eight are absent from that set.

(c) The registry was reachable. npm view @objectstack/spec dist-tags gives latest = 16.1.0, rc = 17.0.0-rc.6 — so the installed pin is the newest published version. Nothing here is "premature, awaiting a pin bump"; there is no newer spec to bump to.

# cited symbol (a) in rc.6 (b) same meaning, other rc.6 name (c) published history
1 PluralRuleSchema absent no — only PLURAL_TO_SINGULAR / singularToPlural, string inflection helpers in spec/ui through rc.5; also in 2.0.7 and latest 16.1.0
2 DateFormatSchema absent no — zero export names contain "DateFormat"; zero files mention dateStyle/timeStyle same
3 NumberFormatSchema absent no — only AutonumberFormat* (autonumber field format strings); zero files mention minimumFractionDigits/useGrouping same
4 LocaleConfigSchema absent no — TranslationConfigSchema is app-level (defaultLocale/supportedLocales/fallbackLocale); an internal ResolveOptions carries locale+fallbackChain only same
5 FieldChangeEntrySchema absent adjacent but differentFieldChangeSchema in spec/kernel keys path/originalValue/currentValue/changedBy/changedAt: zero key overlap with the local six in spec/data through 15.1.1; gone from 16.0.0-rc.0 onward, incl. latest
6 MentionSchema absent no — zero export names contain "Mention" same
7 ReactionSchema absent no — zero names contain "Reaction"; zero .d.ts files mention emoji same
8 RecordSubscriptionSchema absent no — SubscriptionSchema (realtime transport), EventSubscriptionSchema, AppSubscriptionSchema (billing) are unrelated meanings same

Corroboration from the spec's own shipped files

Not inference — rc.6 states both retirements itself.

CHANGELOG.md, on the feed four:

@objectstack/spec/dataFeedItemSchema/FeedItem, FeedActorSchema/FeedActor, MentionSchema/Mention, ReactionSchema/Reaction, FieldChangeEntrySchema/FieldChangeEntry, FeedVisibility, RecordSubscriptionSchema/RecordSubscription, SubscriptionEventType … → removed. … reactions and threaded replies are fields on sys_comment. … FeedItemType and FeedFilterMode are kept (live UI activity-timeline config).

src/ui/i18n.zod.ts — still shipped in rc.6, no longer exported from any entrypoint — on the i18n four:

REMOVED. I18nObjectSchema / PluralRuleSchema / NumberFormatSchema / DateFormatSchema / LocaleConfigSchema — per ADR-0049 enforce-or-remove (#5055, maintainer ruling 2026-08-06 …). They had no carrier key anywhere, were unreachable in that same BFS, and were never parsed in objectstack / objectui / cloud outside this file's own tests.

The same note records the return path, which the reworded module doc now carries: localisation comes back through a new ADR, "the formatter that reads a LocaleConfig first, the vocabulary second".

Shape fidelity confirms these were honest mirrors while they lasted: SpecPluralRule matches 16.1.0's PluralRuleSchema key-for-key (key/zero/one/two/few/many/other), and the same holds for the other three.

Disposition

All eight land on the ruling's third branch — nothing under any name in the pinned spec — so each claim sentence was reworded to stop vouching for a dropped symbol while keeping what is true. No symbol could take the "bind to the real name" branch (none exists to bind to), and none takes the "await the pin bump" branch (rc.6 is already newest). 8 of 8 resolved, so this closes the card.

Two judgement calls worth review:

  1. FieldChangeEntry explicitly warns against FieldChangeSchema. It is the one near-miss in the set — same words, adjacent meaning, and a plausible re-point for the next agent. Its keys are disjoint from the local shape, so re-pointing would be wrong; the comment now says so by name, since a silent absence is what invites the mistake.
  2. Same-file collateral, deliberately included. spec-formatters.ts's module header advertised "Runtime consumers for @objectstack/spec v2.0.7 i18n types" and four // XSchema Consumer section banners; views.ts had a section banner asserting the same alignment for four of the eight, plus FeedItem's own comment citing FeedItemSchema (also removed in 16.0.0). Fixing the eight declarations while leaving those in place would have left the files self-contradictory and the planted premise intact on the same symbols. All are inside the card's two files.

FeedItem is worth calling out separately: it is not in the ledger and rule 2 cannot see it, because it references FeedItemType — a live spec import — while citing FeedItemSchema, which is gone. The tie test is symbol-agnostic, so any declaration with a tie to any spec symbol can cite a retired one and pass. Filed as an observation on the gate rather than fixed here, since scripts/** rule logic is #4592's surface.

Red-first, then green (ratchet #5)

Baseline on origin/main — green:

✅  spec alignment claims: 2 declared deliberate copies, 26 unbacked claims in 6 packages.

Comment fixes applied, ledger entries still present — red, verbatim:

❌  a spec-alignment claim has nothing behind it:

    • @object-ui/types lists 4 symbols in CLAIM_DEBT whose spec-alignment claim is gone — `FieldChangeEntry`, `Mention`, `Reaction`, `RecordSubscription`.
      Delete them from scripts/check-spec-symbol-derivation.mjs (`--claim-ledger` regenerates
      the block) so the symbol cannot re-acquire an unbacked claim silently (and close #4592 once the ledger is empty).

    • @object-ui/i18n lists 4 symbols in CLAIM_DEBT whose spec-alignment claim is gone — `SpecDateFormat`, `SpecLocaleConfig`, `SpecNumberFormat`, `SpecPluralRule`.
      Delete them from scripts/check-spec-symbol-derivation.mjs (`--claim-ledger` regenerates
      the block) so the symbol cannot re-acquire an unbacked claim silently (and close #4592 once the ledger is empty).

After the surgical deletion — green, counts dropped as predicted:

✅  spec alignment claims: 2 declared deliberate copies, 18 unbacked claims in 5 packages.

26 → 18 claims, 6 → 5 packages: the @object-ui/i18n key is now empty and removed entirely. The deletion matches --claim-ledger's regenerated block exactly.

On the reverse-verification direction — the template's before-green/after-red does not apply here, and reporting it as if it did would be false. This gate was green before (the debt was declared) and is green after (the debt shrank); the red is the intermediate state, which is precisely ratchet #5's job. Removing the fix with git checkout origin/main -- … restores the original 26 in 6 packages green, and the fix was restored sha256-verified. No git stash at any point.

Comment-only proof for the published .d.ts

Doc comments on exported declarations do land in the published .d.ts, so this is a real published-artifact change and is graded accordingly. Both packages were rebuilt with dist/ and tsbuildinfo cleared, on each side of the change:

file raw .d.ts diff comments stripped stripped sha256
packages/types/dist/views.d.ts 39 lines 0 lines 48efa09249f6418912c5cafa69744358 both sides
packages/i18n/dist/utils/spec-formatters.d.ts 70 lines 0 lines 2f5a04ba995d63fec1026b40e52c7dff both sides

Stripping re-prints each .d.ts through the TypeScript printer with removeComments. Identical output on both sides is the proof that no declaration, member, modifier or export moved — the #4604 plugin-grid precedent.

Grading: patch for @object-ui/types and @object-ui/i18n. The presence gate demands an entry for both; the published artifact genuinely changes (comment text), so the empty-frontmatter exemption would be wrong here. Never major.

Verification

  • node scripts/check-spec-symbol-derivation.mjs — green, counts above
  • Full gate battery, all PASS: check-control-bytes, check-phantom-dependencies, check-changeset-presence, check-changeset-no-major, check-changeset-fixed, check-type-check-coverage, check-lint-coverage, check-spec-symbol-derivation, check-doc-links, check-i18n-call-site-keys, check-i18n-en-drift
  • pnpm exec vitest run --maxWorkers=2 packages/i18n packages/types plus scripts/__tests__/check-spec-symbol-derivation.test.ts (the ledger's own source of truth) — 79 files / 1236 tests passed; the gate's suite 20/20 on its own run
  • turbo run type-check --filter='...@object-ui/types'77/77 tasks successful; --filter='...@object-ui/i18n'69/69. Prefix filter, i.e. each package and everything that depends on it (downstream consumers), 43 and 35 packages in scope
  • ESLint on the three touched sources: 8 warnings / 0 errors on both sides, net zero (all pre-existing no-explicit-any / unused-import in views.ts)
  • Control-byte self-scan over every touched and untracked file, beyond the gate's own surface — clean

Generated by Claude Code

…ymbols (#4597)

Eight exported declarations claimed alignment with a `@objectstack/spec` symbol
that the pinned 17.0.0-rc.6 does not export: four locale-formatting shapes in
`@object-ui/i18n` and four activity-feed shapes in `@object-ui/types`.

Measuring all eight against the published registry answered the question #4597
left open, and the answer was not "these names never existed". Every one was a
real export the protocol retired deliberately, and every local key set was
faithful to the schema it named:

  - the feed four left `@objectstack/spec/data` in the 16.0.0 major, when the
    feed surface was replaced by the data API over `sys_comment`/`sys_activity`;
  - the i18n four left `@objectstack/spec/ui` in 17.0.0-rc.6 itself (present
    through rc.5) under ADR-0049 enforce-or-remove, objectstack#5055 — no
    authorable shape carried them and nothing ever parsed them.

Each comment now records that provenance instead of vouching for a symbol the
pinned spec has dropped, and the CLAIM_DEBT ledger loses exactly those eight
entries (26 unbacked claims in 6 packages -> 18 in 5).

Comments only: the published .d.ts files differ solely in comment text, proven
by re-printing both builds with comments stripped (identical sha256).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Qqyix2QcnpUC9XeYVDzx3
@vercel

vercel Bot commented Aug 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectui Ignored Ignored Aug 13, 2026 6:40pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Main entry (gzip) 24.7 KB 350 KB
Entry file index-D__aFqth.js
Status PASS

📦 Bundle Size Report

Package Size Gzipped
app-shell (index.js) 9.56KB 3.59KB
app-shell (runtime-config.js) 7.42KB 2.32KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 8.92KB 3.41KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 1.17KB 0.53KB
auth (AuthProvider.js) 25.13KB 5.40KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.13KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.64KB 2.21KB
auth (SocialSignInButtons.js) 9.60KB 3.89KB
auth (UserMenu.js) 3.40KB 1.22KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 38.46KB 10.17KB
auth (createAuthenticatedFetch.js) 6.34KB 2.43KB
auth (index.js) 2.35KB 1.07KB
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.02KB 0.88KB
auth (useIsWorkspaceAdmin.js) 1.61KB 0.85KB
collaboration (CommentThread.js) 26.07KB 7.56KB
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.65KB 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) 489.28KB 108.46KB
core (index.js) 3.79KB 1.52KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 163.56KB 44.83KB
fields (index.js) 230.37KB 57.17KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (currency.js) 1.22KB 0.64KB
i18n (i18n.js) 4.32KB 1.77KB
i18n (index.js) 3.35KB 1.38KB
i18n (pickLocalized.js) 3.69KB 1.73KB
i18n (provider.js) 23.12KB 7.62KB
i18n (useDisplayLocale.js) 2.84KB 1.45KB
i18n (useObjectLabel.js) 27.59KB 6.63KB
i18n (useSafeTranslation.js) 7.77KB 3.13KB
layout (index.js) 38.98KB 10.85KB
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.74KB
mobile (index.js) 1.50KB 0.62KB
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) 2.53KB 0.85KB
mobile (useResponsive.js) 0.71KB 0.42KB
mobile (useResponsiveConfig.js) 1.36KB 0.63KB
mobile (useSpecGesture.js) 4.32KB 1.64KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 8.75KB 3.06KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 3.67KB 1.12KB
permissions (evaluator.js) 4.41KB 1.44KB
permissions (index.js) 0.91KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.52KB
permissions (usePermissions.js) 1.55KB 0.71KB
plugin-ai (index.js) 15.75KB 3.80KB
plugin-calendar (index.js) 46.86KB 12.91KB
plugin-charts (index.js) 62.10KB 17.67KB
plugin-chatbot (index.js) 181.21KB 43.14KB
plugin-dashboard (index.js) 121.04KB 31.57KB
plugin-designer (index.js) 212.58KB 42.83KB
plugin-detail (index.js) 239.93KB 60.01KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 114.72KB 27.70KB
plugin-gantt (index.js) 164.30KB 40.02KB
plugin-grid (index.js) 190.02KB 50.48KB
plugin-kanban (index.js) 52.74KB 14.53KB
plugin-list (index.js) 112.01KB 27.27KB
plugin-map (index.js) 18.16KB 5.81KB
plugin-markdown (index.js) 13.72KB 4.69KB
plugin-report (index.js) 41.38KB 11.09KB
plugin-timeline (index.js) 26.68KB 7.66KB
plugin-tree (index.js) 8.50KB 2.88KB
plugin-view (index.js) 84.09KB 20.56KB
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.71KB 3.53KB
providers (index.js) 0.44KB 0.22KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.67KB 2.37KB
react (LazyPluginLoader.js) 3.77KB 1.33KB
react (SchemaRenderer.js) 27.64KB 9.44KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 1.26KB 0.67KB
react (schema-input.js) 1.45KB 0.83KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 4.09KB 1.74KB
sdui-parser (index.js) 4.47KB 2.03KB
sdui-parser (parse.js) 10.04KB 2.82KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 4.69KB 1.48KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 0.99KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 0.20KB 0.18KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 0.20KB 0.18KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.87KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-retry.js) 4.32KB 2.02KB
types (index.js) 3.05KB 1.52KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 2.59KB 1.31KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
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 (spec-report.js) 5.05KB 1.93KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 0.20KB 0.18KB
types (ui-action.js) 3.40KB 1.71KB
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

@yinlianghui
yinlianghui marked this pull request as ready for review August 13, 2026 18:58
@yinlianghui
yinlianghui added this pull request to the merge queue Aug 13, 2026
Merged via the queue into main with commit 92876f0 Aug 13, 2026
21 checks passed
@yinlianghui
yinlianghui deleted the claude/issue-4597-dangling-spec-citations branch August 13, 2026 18:58
yinlianghui pushed a commit that referenced this pull request Aug 13, 2026
…anode-round2

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Qqyix2QcnpUC9XeYVDzx3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

finding(types,i18n): eight doc comments claim alignment with @objectstack/spec symbols the spec does not export

2 participants