Repository navigation
refactor(app-shell,data-objectstack): one authority each for MetadataTypeStatus and UserDataAdapter (objectui#6349, batch 9) - #12076
Conversation
…TypeStatus and UserDataAdapter (objectui#6349, batch 9) Two of batch 9's three KNOWN_COLLISIONS rows were one thing declared twice, so each converges by re-pointing app-shell at the package it already depends on: - MetadataTypeStatus: @object-ui/react's declaration is the one authority; app-shell's MetadataProvider re-exports it. Same four words on both sides. - UserDataAdapter: @object-ui/data-objectstack's declaration is the one authority and takes app-shell's contract notes; app-shell's UserStateAdapters re-exports it. Identical members on both sides. The app-shell root still publishes both names. The two ledger rows leave KNOWN_COLLISIONS (13 to 11). AppShellProps stays: its rename would remove a name that a type-checked doc reads through the app-shell entry. Refs objectui#6349 Claude-Session: https://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8 Co-authored-by: Claude <noreply@anthropic.com>
…ck (objectui#6349) Both patch: the app-shell root still publishes MetadataTypeStatus and UserDataAdapter with the same shapes, and data-objectstack's change is doc comments only. Refs objectui#6349 Claude-Session: https://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8 Co-authored-by: Claude <noreply@anthropic.com>
… (objectui#6349, batch 9)
The multi-line import with a trailing comma made tsc emit
`{ MetadataCtx, useMetadata, }` once the type-only specifiers were elided,
so the emitted JS differed from base by one comma. On one line the emitted
MetadataProvider.js is byte-identical to base again.
Refs objectui#6349
Claude-Session: https://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8
Co-authored-by: Claude <noreply@anthropic.com>
✅ 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
|
…ps become MinimalAppShellProps (objectui#6349, batch 9) Option A of the claim amendment on objectui#6349 (comment 6092402348). app-shell's AppShellProps (sidebar, header, footer, children, className) and layout's (sidebar, navbar, children, className, defaultOpen, branding, rightRail) are the props of two different components, and re-pointing app-shell's name at layout's does not compile. app-shell's declaration now spells MinimalAppShellProps and the app-shell root publishes that name in place of AppShellProps; layout keeps the general name. The two AppShell components keep their names. - docs/ARCHITECTURE.md: the two blocks that imported the type from @object-ui/app-shell now name MinimalAppShellProps. - layout's three tests that warn about app-shell's props name it. - The AppShellProps row leaves KNOWN_COLLISIONS (11 to 10). - The app-shell changeset becomes minor, with a breaking note naming the migration (TS2305 on the old import). Refs objectui#6349 Claude-Session: https://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8 Co-authored-by: Claude <noreply@anthropic.com>
✅ 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
|
Contract reviewServed-tier: Isolated, read-only review of PR objectui#12076 (batch 9 of objectui#6349) at the head above. Inputs: card #6349's body and all 39 comments (the batch 9 claim ① Derived judgments
Rename completeness, own census at the head ref ( Ledger. File surface, 13 files, all on claim Gates = the check-runs on ② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS |
Refs #6349 (batch 9)
Clause-②: yes
Batch 9 of the one-authority burn-down, on claim
6092135020(seatdomain:ui#3, sessionhttps://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8). (Round 1.) Two of the claim's three rows converge, soKNOWN_COLLISIONSgoes from 13 rows to 11. Both were one thing declared twice, so app-shell re-points at the package it already depends on. Types, comments and changeset prose only: no runtime behaviour changes, and no emitted JavaScript changes.(Round 1, answered in round 2 above.) The third row,
AppShellProps, is stopped with measured options (see "The stopped row"). It is two meanings, and its only workable rename removes a name that a type-checked document reads through the@object-ui/app-shellentry. That is the claim's stop condition, so this PR leaves the row in the ledger untouched and the seat decides.Round 2 (head
3e1e1375a): all three rows convergeBrought up to round 2 by the seat (
domain:uiseat 3). The round-1 text below is kept and marked where round 2 supersedes it.AppShellProps: ruled A by the seat's claim amendment6092402348on objectui#6349, under the card's remedy and batch 5's precedent, with the maintainer's veto window open. app-shell's declaration is nowMinimalAppShellProps, published at the app-shell root in place ofAppShellProps. layout keeps the general name.docs/ARCHITECTURE.md's two blocks follow, and the three layout tests' comments and one failure message name the new type.AppShellvalue names stay.KNOWN_COLLISIONS: 13 → 10 rows.AppShellPropsout andMinimalAppShellPropsin, members identical; that swap is the only change to the name set. react, data-objectstack and layout are unchanged..jsor.cssfile differs.@object-ui/app-shellminor, with a breaking note naming the migration (AppShellProps→MinimalAppShellProps, TS2305 on the old import);@object-ui/data-objectstackpatch. ⛔ Nomajor.3e1e1375a:check:doc-snippets: 785 of 785 blocks judged, 0 failed.check:readme-exportsis OK;type-check:scriptsexit 0;6092685938on this PR, PASS.This PR has no closing keyword. The card stays open for later batches.
What each converged row was (measured on base
d758f2f2)The member lists come from one TypeScript program over each package's BUILT root entry (
exports["."].types), with dist rebuilt for each tree.MetadataTypeStatus: one status declared twice, so app-shell re-points at react.packages/react/src/context/AppShellContext.tsx'idle','loading','ready','error'MetadataContextValue.getTypeStatusreturnsexport *ofcontextpackages/app-shell/src/providers/MetadataProvider.tsxMetadataProvidercarries; the provider is what implementsgetTypeStatusThe two unions are identical. app-shell depends on
@object-ui/reactand already importsMetadataTypeStatusfrom it inuseObjectPresence, so react's declaration is the one authority.MetadataProvider.tsxnow imports the type from@object-ui/reactand re-exports it, and the app-shell root still publishes the name.UserDataAdapter: one contract declared twice, so app-shell re-points at data-objectstack.packages/data-objectstack/src/userState.tsT:load()returns a Promise ofT[],save(items: T[])returns a Promise ofvoidcreateObjectStackUserStateAdapterreturnspackages/app-shell/src/context/UserStateAdapters.tsxUserStateAdaptersProviderinjects anduseUserStateAdapterhands outThe members are identical, and
ConsoleShellattaches adapters built bycreateObjectStackUserStateAdapterto the registry, so both ends already speak one contract. app-shell depends on@object-ui/data-objectstack, and the reverse edge would be a package cycle, so data-objectstack's declaration is the one authority. It takes app-shell's contract notes as JSDoc (safe to call concurrently, never throw, degrade to localStorage), so the declaration that remains still documents the contract.UserStateAdapters.tsximports it and re-exports it, and the app-shell root still publishes the name.Published surface, base vs head
One TypeScript program per tree over the built root entries of app-shell, react, data-objectstack and layout. Each head marker was read in dist before measuring, and the base tree was built from the three touched source files at base (restored afterwards with blob equality to HEAD).
MetadataTypeStatusresolves to react's declaration and itsUserDataAdapterto data-objectstack's: the same symbol, not a structural copy. The member lists are identical on base and head.providers/MetadataProvider.d.tsandcontext/UserStateAdapters.d.ts, and data-objectstackindex.d.tsandindex.d.cts(JSDoc only). No.js,.cjsor.cssfile differs, so no first-load bytes move.MetadataProvider.jswith one extra comma, because a multi-line import that ended in a type-only specifier and a trailing comma kept that comma after tsc elided the type specifiers. The third commit puts the import back on one line, and the rebuiltMetadataProvider.jsis byte-identical to base.The stopped row:
AppShellProps(round 1; ruled A in6092402348and implemented in round 2)Measured on base and head (this PR does not touch either site).
packages/app-shell/src/types.tssidebar?,header?,footer?,children,className?AppShellcontainer (header, body and footer, no routing). The exampleexamples/byo-backend-consolemounts it, and the root README, app-shell's README anddocs/ARCHITECTURE.mdteach itdocs/ARCHITECTURE.md, which imports the type in two blocks thatcheck:doc-snippetscompiles (no fragment marker on the page)packages/layout/src/AppShell.tsxsidebar?,navbar?,children,className?,defaultOpen?,branding?,rightRail?ConsoleLayoutcomposescontent/docs/layout/app-shell.mdxandcontent/docs/guide/layout.mddocument it; seven layout test files name it, and three of them read its key list out of the source by name to pin those docsThey share
sidebar,childrenandclassName.headerandfooterexist only on app-shell's;navbar,defaultOpen,brandingandrightRailonly on layout's.@objectstack/spec17.7.0 has 0 files namingAppShellProps. Three layout test files already warn that app-shell exports a differentAppShellProps(two of them that it declaresheader), so that layout's docs stop teaching aheaderprop layout never had (objectui#4817).ablation-replace): app-shell'stsc --noEmitexits 2 with 2 errors, TS2339 forheaderand TS2339 forfooterin app-shell'sAppShell. The unmutated control exits 0 with 0 errors. So this is two meanings, not drift.MinimalAppShellPropsand published at the app-shell root instead, four nestedablation-replacelegs): app-shell builds, andcheck:doc-snippetsjudges 785 of 785 blocks with 2 failed, both indocs/ARCHITECTURE.md: TS2305,Module '"@object-ui/app-shell"' has no exported member 'AppShellProps'.Every leg was restored blob-equal to HEAD and app-shell dist was rebuilt.Options:
AppShellProps(258 = 258 names).MinimalAppShellPropsfollows the component's own JSDoc ("Minimal layout container");BasicAppShellPropsfollows its README entry. It needsdocs/ARCHITECTURE.md(the two blocks) on the file surface, and re-points the layout test comments that say app-shell exports a differentAppShellProps. app-shellminorwith a breaking note; an external import of the old name fails loudly (TS2305, measured).AppShelland its props. They are live (the example app and three docs), and removing a component is outside "types and comments only".Changesets
6349-batch9-app-shell.mdminor(round 2)AppShellPropsleaves the root andMinimalAppShellPropstakes its place, with a breaking note naming the migration.MetadataTypeStatusandUserDataAdapterstay, each now a re-export.6349-batch9-data-objectstack.mdpatchUserDataAdapter.react and layout are not touched, so they get no changeset. (Round 1: nothing published moved, so no package took
minor. Round 2: the app-shell root swaps one name, so app-shell takesminor.)Clause-②: yesstands for the batch: theAppShellPropsrow, once ruled, moves a published name. ⛔ Nomajor.Gates
Heavy runs went through
os-verify-lock. All runs are at headfbf9e70bfunless they say otherwise; the first two commits carry the same sources except the one-line import.pnpm exec vitest run scripts/__tests__/one-authority-per-exported-name-6273.test.ts: exit 0,Tests 11 passed (11). The ledger has 11 rows.pnpm exec vitest run --maxWorkers=2overpackages/app-shell/src/context/,packages/app-shell/src/providers/, the four app-shell tests elsewhere that importUserDataAdapterorMetadataTypeStatusor the adapters module (useTrackRouteAsRecent,sharedUserFeeds.activityGate-7476,useNavigationSync,UnifiedSidebar.pinnedOrder-12059) plusconsoleUserPreferenceBudget,packages/data-objectstack/and the gate: exit 0,Test Files 117 passed (117),Tests 1443 passed (1443).pnpm --filter PKG type-checkfor@object-ui/app-shell,@object-ui/data-objectstack,@object-ui/reactand@object-ui/console(the console importsMetadataTypeStatusfrom app-shell), thenpnpm type-check:scripts: each exit 0, 0error TSlines.tsconfig.scripts.jsonlists the gate file.check:doc-snippets: 785 of 785 blocks judged, 0 failed, after its own scoped build.check:readme-exports: OK, 582 of 582 self-imports real.check:control-bytes,check:test-path-roots,check:changeset-claims,check:pending-changeset-literals,check:spec-symbols,check:new-line-citations(0 new),check-changeset-presence(3 source files of 2 released packages, 2 changesets),check-changeset-no-major,check-changeset-fixedandcheck-changeset-overwrite.pnpm exec eslinton the four touched TS files: 0 errors. The 65 warnings sit on unchanged code and match base rule by rule in each file.git merge-treeagainstmaind758f2f2is clean.mainhas not moved since the base.Not run locally:
Reverse verification
Every leg went through
ablation-replacein wrap mode, with predictions written before any leg ran. The gate reads source text, so no dist leg applies. Each leg landed on disk (anchor count 1 to 0, blob changed) and was restored with blob equal to HEAD and an emptygit diff HEAD; the tree had 0 porcelain lines after the run.MetadataTypeStatusrow put backTests 1 failed, 10 passed;no longer collides at:lists app-shell'sMetadataProvider.tsxand react'sAppShellContext.tsxUserDataAdapterrow put backUserStateAdapters.tsxand data-objectstack'suserState.tsMetadataTypeStatusagain instead of re-exporting itMetadataTypeStatus — a NEW colliding name: a type declaration in each of the two filesUserDataAdapteragain instead of re-exporting itUserDataAdapter — a NEW colliding name: an interface declaration in each of the two filesTests 11 passed (11)The failing test in every leg is "declares no name twice outside the named, shrinking baseline".
Acceptance notes
AppShellPropsforMinimalAppShellPropson the app-shell root (258 = 258). Otherwise, both re-pointed names were already on the app-shell root and stay there; the authorities were already on the react and data-objectstack roots.SharedFeedStatusdoc insharedUserFeeds.tsand theHomeInboxStatusdoc inuseHomeInbox.tsciteMetadataTypeStatusas living inproviders/MetadataProvider. That module still exports the name, now as a re-export, so the pointer still resolves; the declaration itself is react's.AppShell. Component names are outside this gate's bound (type-level names only), and theAppShellPropsruling may want to say whether the component follows the props.render()return type in app-shell'sErrorBoundary.d.tswith its union members in a different order from the incremental base build; the incremental head rebuild matched base. Same members either way, a declaration file only, and no source change answers to it.Generated by Claude Code