Skip to content

feat(tooling): objectui consumes @objectstack/* by commit — .objectstack-sha, bump-objectstack.sh, dev and CI built from the pin (objectui#12957) - #12963

Merged
os-zhuang merged 10 commits into
mainfrom
claude/issue-12957-objectstack-sha-pin
Oct 19, 2026
Merged

os-zhuang merged 10 commits into
mainfrom
claude/issue-12957-objectstack-sha-pin

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #12957
Clause-②: no

objectui now consumes @objectstack/* by commit (ruling B on objectui#12955, comment 6248859734). .objectstack-sha pins objectstack 2c9bf9430a1198bfaa5c0de9ff4a811838c6869c (chore: version packages (next) (#23825)), the commit @objectstack/spec@18.0.0-next.3 was released from; every @objectstack/* package resolves to a build of that commit, and none resolves from npm. Seat-directed scope change (item 6): the seat moved the first pin from objectstack main 2ee5861b0f to this release commit, so the pinned build is equivalent to what npm serves today. Moving the pin to a commit that contains 586705d85d, 1e001c7df and e15897c0f1 is a separate pin-bump card, and no parity, refinement or block-config pin is edited here to absorb spec main's drift. No @objectstack/* range in any manifest moves (that is objectui#12958). Dispatched by domain:ui seat 1, session https://claude.ai/code/session_0188TsgPV8kQXfuRuKmkj2ks.

⛔ Tier H (AGENTS.md and .github/workflows/**): this stays a draft until os-zhuang or hotlong approves it.

How it resolves

  • The root package.json overrides each @objectstack/* package to file:node_modules/.cache/objectstack/NAME. scripts/objectstack-pin.mjs build (also pnpm objectstack:build) fills those directories: it fetches the pinned commit, installs only the build closure, builds, and unpacks each package exactly as pnpm pack publishes it. pnpm run setup = that build, then pnpm install --frozen-lockfile.
  • OBJECTSTACK_ROOT=TREE pnpm objectstack:build packs an already installed and built objectstack tree into the same directories instead. This is the input tooling(build-console): when the console build installs objectui at .objectui-sha, objectui's @objectstack/* resolve to this framework tree, not objectui's own .objectstack-sha build (ruling B on objectstack-ai/objectui#12955, step 3) objectstack#24306 consumes.
  • scripts/bump-objectstack.sh [SHA_OR_REF] moves the pin. It refuses a commit it cannot resolve or read before writing anything, and warns (three answers) when the commit is not on objectstack origin/main. That is the contract of objectstack's bump-objectui.sh; its changeset and SDUI-manifest steps are not copied.
  • The script refuses, loudly, when: the override set differs from the runtime closure of what objectui declares (so a pin that adds an @objectstack/* dependency stops instead of falling back to npm); a packed entry point is missing; or the lockfile does not record the dependency names a packed manifest declares.
  • The pinned checkout is hermetic. After fetching the one pinned commit, the script removes the checkout's origin remote. objectstack's spec build anchors its schema ratchets on origin/main and fetches it when it can, so with the remote in place the build of the pin was judged against wherever main was that minute: at db2b7239 it failed in 13 of 25 CI jobs, naming json-schema/api/PackageInstallManifest.json and json-schema/ui/PageRecordBinding.json, two schemas main had added after the pin. Without the remote, the spec build anchors on its committed baseline, so the build is a function of the pin. A test pins the removal; deleting the call turns it red.
  • The objectstack install and build run without objectui's npm_config_* settings (proxy, registry, CA and store settings are kept). pnpm run exports the invoking workspace's .npmrc that way, and objectui's engine-strict made pnpm objectstack:build fail with ERR_PNPM_UNSUPPORTED_ENGINE inside the objectstack tree.
  • A failed build prints its cause (for an unexpected crash, the stack) and, under GitHub Actions, the same text as an objectstack-pin error annotation, because job logs are not always readable. Cleanup of the scratch tree only warns, so it never masks the failure.

Measurements (all local, this container, pnpm 10.31.0, Node 22.22.0)

The packages (Zone 2 item 1, corrected). Seven, not six. At the pin, @objectstack/core depends on @objectstack/types. The full set is spec, core, types, client, formula, sdui-parser and lint. It was read from the pinned commit's manifests and from pnpm --filter-prod over the four roots objectui declares.

The resolution form (item 3, Zone 2 item 2). All three forms were installed against the same build:

Form Lockfile records Clean frozen install, same tree Clean frozen install, other tree
file: tarball integrity and version per tarball exit 1, ERR_PNPM_TARBALL_INTEGRITY exit 1, ERR_PNPM_TARBALL_INTEGRITY
link: directory link: only, no dependencies importing the spec fails: ERR_MODULE_NOT_FOUND for zod (pnpm installs nothing a linked package depends on) not reached
file: directory (chosen) resolution: {directory, type: directory}, with no integrity and no version exit 0 exit 0, pnpm-lock.yaml byte-identical

So the PM's tarball expectation held, and was worse than expected: a clean frozen install failed even for the same tree. link: keeps the lockfile stable but breaks at runtime, and linking a source tree instead would bring that tree's own second zod (the objectstack#21108 split). With a file: directory, the dependencies resolve from objectui's lockfile, so there is one zod. A frozen install also re-links a directory whose content changed: a marker written into a rebuilt directory reached node_modules.

Item 3, the stand-in. At the pin, I built objectstack at e5136ff10f (the 18.0.0-next.2 release commit) in a separate checkout and ran OBJECTSTACK_ROOT= that tree with objectstack-pin.mjs build. The build exited 0. Then pnpm install --frozen-lockfile exited 0, and the lockfile's sha256 was the same before and after (da56792a0bb44808…). The same held earlier against the first candidate pin 2ee5861b0f, with a stand-in at 93b4acb57ec2 (the parent of 586705d85d): build exit 0, frozen install exit 0, lockfile identical. The installed dist/ui/index.d.mts held 10 emptyState occurrences at that pin, 4 with the stand-in, and 10 again after the restore. The lockfile does not change across pins or stand-ins, because it records directories, not versions.

What a frozen install does not check. I gave a packed manifest a dependency the lockfile does not record. pnpm install --frozen-lockfile exited 0 and did not install it. That is why the build compares dependency names and refuses on any difference. I proved that refusal on the real tree: it exits 1 and names the package; its control exits 0.

Item 6, the first pin (seat-directed). I moved the pin with scripts/bump-objectstack.sh 2c9bf9430a1198bfaa5c0de9ff4a811838c6869c; pnpm install afterwards left pnpm-lock.yaml unchanged. Equivalence with npm: I ran npm pack for all seven packages at 18.0.0-next.3 and compared each with diff -rq against node_modules/.cache/objectstack. Every package.json version is 18.0.0-next.3. types, formula and sdui-parser are identical. core, client and lint differ only in package.json, by the order of dependency keys (same keys, same versions). In spec (2094 files), every JS and JSON Schema file is identical. The npm tarball carries two release-time files that the build does not produce, spec-changes.json and protocol-upgrade-guide.md; objectui reads neither (git grep exits 1, a control term exits 0). After the hermetic change, 10 declaration files (api, automation, contracts, marketplace and system, as .d.ts and .d.mts) and 2 hashed DTS chunk pairs differ. The sampled chunk (automation-api.zod) differs only in the order of union members, at the same byte length (523364): DTS emit nondeterminism, not a content difference. The pin is a strict ancestor of 586705d85d, 1e001c7df and e15897c0f1 (git merge-base --is-ancestor 2c9bf943 C exits 0 for each), so none of the three is in this pin.

Ablation: the type check reads the pinned build. I wrote a throwaway probe that imports SelectOptionKind from @objectstack/spec/data, a symbol that 18.0.0-next.3 adds, and checked it with tsc --ignoreConfig --noEmit. At the pin it exits 0. With the e5136ff10f (18.0.0-next.2) stand-in it exits 2 with TS2724 (no exported member named SelectOptionKind). After the restore it exits 0. The same shape held at the first candidate pin with an emptyState probe: exit 0, then TS2339 and exit 2 with the 93b4acb57ec2 stand-in, then exit 0. The probe was never committed. Afterwards git diff HEAD is empty and objectstack:status reads the pin. My first attempt measured nothing: tsc refused with TS5112 because a tsconfig is present. I re-ran it with --ignoreConfig.

Item 2, type check and tests at the pin. At 4bd617b0: pnpm type-check --concurrency=2, 81 of 81 tasks successful, exit 0; the scripts suite, 188 test files passed (5652 tests); pnpm type-check:scripts, exit 0. At 185772ba (the next.3 pin; later commits change only scripts/objectstack-pin.mjs and its test): packages/core, packages/types, packages/react and the spec-drift test files, 711 test files passed. The packages/app-shell suite ran in CI (all 16 shards green), not locally.

Cold build (Zone 2 item 3). I ran objectstack-pin.mjs build under the shared verify lock. These are shared-box seconds with a warm pnpm store, at the first candidate pin: 202 s in total, of which fetch 17.0 s, install 4.4 s, build 160.7 s and pack 13.9 s. A filtered install is enough: the root plus --filter-prod over the roots is 8 projects and 348 packages. Plain --filter 'X...' follows devDependencies into 36 projects; that build took 352 s. Disk: 203 MB stays in node_modules/.cache/objectstack, and about 0.9 GB of scratch is deleted after packing. A warm cache is a stamp read, and the build step returns immediately. At the next.3 pin the same build took 174 s. A fresh worktree's cold pnpm run setup took 175.7 s and added 295 MB (201 MB of it the cache). A second fresh worktree right after took 167.5 s and another 295 MB. Copying the first worktree's cache into a third and running the same command took 6.5 s (+286 MB as a copy; about 85 MB if hardlinked, an estimate). That is the evidence for the shared pin cache card; no shared cache is built here. An OBJECTSTACK_ROOT pack of an already built tree took 22.0 s. The CI numbers are in the next section.

pnpm setup (item 7). It is pnpm's own built-in command. In a probe it wrote PNPM_HOME into the shell rc and never ran the package script. pnpm run setup ran it. So everything here says pnpm run setup. I also corrected the same trap in this repository's backend runbook line.

CI (item 4)

All 17 jobs that install (docs-deploy's through vercel build), plus lockfile-dedupe, which resolves, restore node_modules/.cache/objectstack with actions/cache/restore@v6. The key is objectstack-pin-RUNNER_OS-hashFiles(.objectstack-sha, scripts/objectstack-pin.mjs). Each then runs node scripts/objectstack-pin.mjs build, which is a no-op on a hit. On a miss, the job saves the build as its last step, bounded at 2 minutes and non-fatal (objectui#6577, objectui#7048). An unchanged pin never rebuilds. A script edit counts as a recipe change and rebuilds once. Every job pays the cold build on the first run of a new pin.

Measured at 4bd617b0: 23 jobs built cold in 71 to 125 s (median 111 s); at 1fa4f1de, 25 jobs took 109 to 151 s (median 138 s). Two jobs restored a build an earlier run of this PR had saved: Build Docs (restore 3 s, build 0 s) and Test shard 15/16 (restore 2 s, build 0 s). The save step took 0 to 2 s, and the install after the build 4 to 8 s. Whether main saves the cache is NOT MEASURED: main has no .objectstack-sha until this merges, so its first push run afterwards misses and saves under main's scope, which PR runs can restore. The Actions cache API is not readable from here, so the cache entries were not listed.

Because of turbo.json globalDependencies (.objectstack-sha and the build's stamp), a pin bump invalidates replayed turbo verdicts. It also widens the type-check fast path to the whole workspace, because select-type-check-scope.mjs reads that list. Without this, a bump PR would type-check zero packages and replay main's cached verdicts. performance-budget.yml now triggers on .objectstack-sha.

The lockfile and pin gates (item 5)

  • check-lockfile-integrity: rule 1 (an @objectstack/* version moving backward) is retired. The lockfile carries no @objectstack/* version any more, so the rule could never fire again. The identity it guarded is .objectstack-sha, and the build refuses any package that is not overridden. Rule 2 (a package gaining a physical copy) is kept: a registry copy beside the pinned build is exactly what it names. The tests pin that sample and the peer fork in its pinned-build form.
  • check-lockfile-dedupe: adapted. The pinned build is a named precondition, checked before pnpm runs. With the build present: VERDICT deduped, exit 0, lockfile unchanged.
  • check-installed-pin-claims: adapted. Face A follows the lockfile's file: resolution to the version the directory's manifest declares. An absent build is a named conflict. Gate: exit 0.
  • The live-e2e backend pin (ci-cd-pipeline-doc.test.ts, finding(ci): e2e/live/ci/backend.env pins OBJECTSTACK_VERSION=17.0.0-rc.2 while the lockfile resolves 17.2.0 — the live-e2e lane has been smoke-testing an unmatched pair for two minor versions #7689): adapted the same way. The page now states the gap this leaves (see the acceptance notes).
  • check-spec-range-floors is unchanged. It fetches each declared floor from the registry and never reads the installed tree. check-spec-symbol-derivation reads the installed spec, which is now the pin: exit 0.
  • No new gate.

Files beyond the claim's file surface (named, not silent)

  • turbo.json: the two globalDependencies entries above.
  • scripts/dependabot-merge-gate.mjs: one prose string that described the retired rule.
  • README.md, CONTRIBUTING.md, QUICK_REFERENCE.md, scripts/setup.sh, content/docs/guide/console.md, content/docs/utilities/runner.mdx: a clean checkout starts with pnpm run setup. A bare pnpm install without the build fails (ERR_PNPM_LINKED_PKG_DIR_NOT_FOUND / ENOENT).
  • content/docs/guide/ci-cd-pipeline.md: its tests require each section to name every command its jobs run, and the live-e2e sentence moved.
  • Tests that assumed one cache per job, an exact action-ref list, or no continue-on-error in shadcn-check.yml: turbo-cache-save-bound, report-turbo-cache, check-action-ref-convention, shadcn-check-report, render-budget-comment.

Acceptance notes

  • Dependabot (not changed here). Dependabot's npm updates regenerate the lockfile without the pinned build. Locally, pnpm install --lockfile-only without the build exits 1 with ERR_PNPM_LINKED_PKG_DIR_NOT_FOUND. Whether Dependabot's sandbox fails the same way is NOT MEASURED; its next npm run after the merge is the first reading.
  • apps/console/vercel.json installs with pnpm install --frozen-lockfile on Vercel, which would now need the pin first. No Vercel status appears on recent main commits, so it was left alone.
  • The live-e2e lane still runs the published backend at OBJECTSTACK_VERSION. The console is now built from the pinned commit, whose version string only moves at an objectstack release. The two match by number, not by commit. The page says so, and nothing here closes it.
  • e2e/live/ci/backend.env's header still says the version is "resolved in pnpm-lock.yaml". The lockfile now resolves the pinned build, whose manifest carries that version.
  • objectstack's own AGENTS.md and examples/README.md document pnpm setup for first-time setup. That runs pnpm's built-in command, not the script. This is reported on the card, not changed here.
  • Seat answer, Q1 (Dependabot): observe first. The seat reads Dependabot's first npm run after the merge, and if it fails it files the follow-up then, with option A (a scheduled in-repo update workflow that runs pnpm run setup first) as the default. Nothing changes in this PR.
  • Seat answer, Q2 (shared pin cache): A. The seat files it as its own card, per the maintainer's 「如果需要共享缓存,你就开卡」. Nothing changes in this PR.
  • Seat answer, Q3 (file-surface extensions): A, accepted as is.

维护者速读(草稿)


Generated by Claude Code

…ectstack-sha pins

.objectstack-sha pins objectstack main 2ee5861b0f (it contains 586705d85d,
1e001c7df and e15897c0f1). scripts/objectstack-pin.mjs builds the seven
packages the workspace resolves (spec, core, types, client, formula,
sdui-parser, lint) at that commit and packs each into
node_modules/.cache/objectstack/<name>; the root manifest overrides every
@objectstack/* package to that directory with file:, so the lockfile records
directory resolutions and no @objectstack/* package resolves from npm.
`pnpm run setup` builds then installs frozen; OBJECTSTACK_ROOT packs an
existing objectstack tree into the same directories instead.

Claude-Session: https://claude.ai/code/session_0188TsgPV8kQXfuRuKmkj2ks
Co-authored-by: Claude <noreply@anthropic.com>
…ad the pinned build

- scripts/bump-objectstack.sh moves .objectstack-sha. It refuses a commit it
  cannot resolve or read before writing anything, and warns (three answers)
  when the commit is not on objectstack origin/main -- the refusal and
  warning contract of objectstack's bump-objectui.sh.
- objectstack-pin.mjs refuses when the lockfile does not record the
  dependency names the build declares (a frozen install links a directory
  dependency without re-reading its manifest), and builds in a short scratch
  path (tsx's IPC socket path overflowed under a long one).
- check-lockfile-integrity: rule 1 (an @objectstack/* version moving
  backward) is retired; the lockfile carries no @objectstack/* version now.
  Rule 2 still names a registry copy beside the pinned build.
- check-lockfile-dedupe: the pinned build is a named precondition.
- check-installed-pin-claims and the live-e2e backend pin follow the
  pinned build's file: resolution to the version its manifest declares.
- turbo.json hashes .objectstack-sha and the build stamp, so a pin bump
  invalidates cached verdicts and widens the type-check scope.

Claude-Session: https://claude.ai/code/session_0188TsgPV8kQXfuRuKmkj2ks
Co-authored-by: Claude <noreply@anthropic.com>
…ctstack build; AGENTS.md and the setup docs name the pin

- Each of the 18 jobs that install (or, in lockfile-dedupe, resolve)
  restores node_modules/.cache/objectstack from a cache keyed by
  .objectstack-sha and the script that builds it, runs
  `node scripts/objectstack-pin.mjs build` (a no-op on a hit), and saves it as
  its last step only when it built it -- bounded and non-fatal, per
  objectui#6577/#7048. An unchanged pin never rebuilds.
- performance-budget.yml triggers on .objectstack-sha (the bundle moves with
  the pin); its and lockfile-dedupe.yml's filters list the new script.
- AGENTS.md: a dependency and lockfile section (the pin, the bump, the
  stand-in, the frozen-install caveat), `pnpm run setup` in the worktree rule
  and the local dev runbook.
- README, CONTRIBUTING, QUICK_REFERENCE, scripts/setup.sh and two docs pages:
  a clean checkout starts with `pnpm run setup`.
- Tests that assumed one cache per job, an exact action-ref list, or no
  continue-on-error in shadcn-check now read the pinned build's steps too;
  ci-cd-pipeline.md names the new command in every section that runs it.

Claude-Session: https://claude.ai/code/session_0188TsgPV8kQXfuRuKmkj2ks
Co-authored-by: Claude <noreply@anthropic.com>
…uilt-in `pnpm setup`

`pnpm setup` runs pnpm's own built-in command (it writes PNPM_HOME into the
shell rc) and never reaches the workspace's `setup` script; `pnpm run setup`
does. Measured on objectui#12957 in a throwaway workspace.

Claude-Session: https://claude.ai/code/session_0188TsgPV8kQXfuRuKmkj2ks
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 75 chunks) 3170.9 KB 3744.1 KB
Main entry chunk (gzip) 80.5 KB 350 KB
Entry file index-DWiXfMkf.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) 21.41KB 7.88KB
app-shell (runtime-config.js) 24.52KB 8.48KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 45.59KB 12.03KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 20.67KB 6.12KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.74KB 3.94KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.62KB 0.83KB
auth (authStyles.js) 5.27KB 1.86KB
auth (createAuthClient.js) 42.84KB 11.66KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
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.26KB 8.03KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (commentAuthorship.js) 1.39KB 0.78KB
collaboration (index.js) 1.93KB 0.85KB
collaboration (useCollaborationTranslation.js) 6.50KB 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) 612.39KB 149.02KB
core (index.js) 10.18KB 4.04KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 248.83KB 69.44KB
fields (index.js) 291.72KB 74.47KB
i18n (LocalizationContext.js) 2.92KB 1.42KB
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.52KB 2.39KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 36.87KB 9.88KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 41.33KB 11.96KB
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) 15.35KB 5.51KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.82KB 2.38KB
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.04KB 3.92KB
plugin-calendar (index.js) 55.04KB 16.10KB
plugin-charts (index.js) 85.06KB 23.39KB
plugin-chatbot (index.js) 230.81KB 54.29KB
plugin-dashboard (index.js) 147.53KB 39.95KB
plugin-designer (index.js) 233.95KB 50.08KB
plugin-detail (index.js) 266.04KB 70.50KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 181.16KB 46.84KB
plugin-gantt (index.js) 178.46KB 45.13KB
plugin-grid (index.js) 272.87KB 75.68KB
plugin-kanban (index.js) 63.37KB 19.51KB
plugin-list (index.js) 139.82KB 36.04KB
plugin-map (index.js) 27.17KB 9.00KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 46.66KB 13.13KB
plugin-timeline (index.js) 39.31KB 11.88KB
plugin-tree (index.js) 15.27KB 5.40KB
plugin-view (index.js) 94.68KB 24.36KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 12.07KB 3.68KB
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) 125.37KB 41.04KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.71KB 2.11KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.07KB 1.30KB
sdui-parser (index.js) 7.30KB 3.12KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.81KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 23.87KB 7.83KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
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) 1.13KB 0.65KB
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) 5.78KB 2.70KB
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 (node-slots.js) 7.18KB 2.34KB
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 (product-blocks.js) 0.20KB 0.19KB
types (record-approval-decision.js) 0.20KB 0.20KB
types (record-components.js) 0.20KB 0.19KB
types (record-panels.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) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.26KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.48KB 3.50KB
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

…commit; the objectstack install reads its own npm config

Seat-directed scope change on objectui#12957 (item 6 amended): the first pin
is 2c9bf9430a, the commit @objectstack/spec@18.0.0-next.3 was released from,
so the pinned build reproduces what objectui resolved from npm and CI proves
the mechanism with no contract drift. Moved with scripts/bump-objectstack.sh;
`pnpm install` leaves pnpm-lock.yaml unchanged. Moving to a commit with
586705d85d, 1e001c7df and e15897c0f1 is a separate pin-bump card.

objectstack-pin.mjs no longer passes this repository's npm_config_* settings
to pnpm in the objectstack tree: `pnpm run` exports objectui's
engine-strict=true, which refused the objectstack install through
`pnpm objectstack:build` while the direct `node` call installed.

Claude-Session: https://claude.ai/code/session_0188TsgPV8kQXfuRuKmkj2ks
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

ℹ️ Console Performance Budget — not measured

This run did not produce a console bundle to measure, so there is no pass/fail verdict for the performance budget.

This is not a budget violation. Nothing was measured — the numbers a real violation would carry are simply absent.

Step Outcome
Build packages skipped
Check console performance budget skipped

See the workflow run for details.

No package size report: it is only generated from a complete package build, so a partial one is never shown.

…ation

The fetch, install and build output of the objectstack tree goes to a log in
the build's scratch directory; a failure carries that log's last lines, and
under GitHub Actions the refusal is also printed as an `::error::`
annotation. 8 of 25 jobs on 185772b failed the build step about 40 s in,
and the job log -- the only place their cause was -- is not readable from
the checks API.

Claude-Session: https://claude.ai/code/session_0188TsgPV8kQXfuRuKmkj2ks
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

ℹ️ Console Performance Budget — not measured

This run did not produce a console bundle to measure, so there is no pass/fail verdict for the performance budget.

This is not a budget violation. Nothing was measured — the numbers a real violation would carry are simply absent.

Step Outcome
Build packages skipped
Check console performance budget skipped

See the workflow run for details.

No package size report: it is only generated from a complete package build, so a partial one is never shown.

…ver masks it

On c659d23, 13 of 25 cold jobs failed the build step about 50 s in with no
annotation, so the failure was not a refusal: an exception escaped. The CLI
now writes any failure, refusal or crash with its stack, synchronously to
stderr and as a GitHub annotation; removing the scratch tree is retried and
only warns.

Claude-Session: https://claude.ai/code/session_0188TsgPV8kQXfuRuKmkj2ks
Co-authored-by: Claude <noreply@anthropic.com>
…s build is a function of the pin

objectstack's spec build anchors its schema ratchets on origin/main and
fetches it when it can. With the remote in place, building the
18.0.0-next.3 commit was judged against wherever main was that minute: it
built earlier and then failed in 13 of 25 CI jobs on db2b723 once main had
added two schemas (the annotation named them). With no remote the spec
build anchors on the commit's own committed baseline ("origin/main is not
resolvable in this build environment").

Claude-Session: https://claude.ai/code/session_0188TsgPV8kQXfuRuKmkj2ks
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 75 chunks) 3161.7 KB 3744.1 KB
Main entry chunk (gzip) 80.5 KB 350 KB
Entry file index-HGGPbgG9.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) 21.41KB 7.88KB
app-shell (runtime-config.js) 24.52KB 8.48KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 45.59KB 12.03KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 20.67KB 6.12KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.74KB 3.94KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.62KB 0.83KB
auth (authStyles.js) 5.27KB 1.86KB
auth (createAuthClient.js) 42.84KB 11.66KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
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.26KB 8.03KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (commentAuthorship.js) 1.39KB 0.78KB
collaboration (index.js) 1.93KB 0.85KB
collaboration (useCollaborationTranslation.js) 6.50KB 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) 612.39KB 149.02KB
core (index.js) 10.18KB 4.04KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 248.83KB 69.44KB
fields (index.js) 291.72KB 74.47KB
i18n (LocalizationContext.js) 2.92KB 1.42KB
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.52KB 2.39KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 36.87KB 9.88KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 41.33KB 11.96KB
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) 15.35KB 5.51KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.82KB 2.38KB
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.04KB 3.92KB
plugin-calendar (index.js) 55.04KB 16.10KB
plugin-charts (index.js) 85.06KB 23.39KB
plugin-chatbot (index.js) 230.81KB 54.29KB
plugin-dashboard (index.js) 147.53KB 39.95KB
plugin-designer (index.js) 233.95KB 50.08KB
plugin-detail (index.js) 266.04KB 70.50KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 181.16KB 46.84KB
plugin-gantt (index.js) 178.46KB 45.13KB
plugin-grid (index.js) 272.87KB 75.68KB
plugin-kanban (index.js) 63.37KB 19.51KB
plugin-list (index.js) 139.82KB 36.04KB
plugin-map (index.js) 27.17KB 9.00KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 46.66KB 13.13KB
plugin-timeline (index.js) 39.31KB 11.88KB
plugin-tree (index.js) 15.27KB 5.40KB
plugin-view (index.js) 94.68KB 24.36KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 12.07KB 3.68KB
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) 125.37KB 41.04KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.71KB 2.11KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.07KB 1.30KB
sdui-parser (index.js) 7.30KB 3.12KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.81KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 23.87KB 7.83KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
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) 1.13KB 0.65KB
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) 5.78KB 2.70KB
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 (node-slots.js) 7.18KB 2.34KB
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 (product-blocks.js) 0.20KB 0.19KB
types (record-approval-decision.js) 0.20KB 0.20KB
types (record-components.js) 0.20KB 0.19KB
types (record-panels.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) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.26KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.48KB 3.50KB
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: 4bd617b0af9220dc6357da9e234582b3ce9d547a
Local-runs: none
Scope: AGENTS.md, .github/workflows/changeset-release.yml, .github/workflows/ci.yml, .github/workflows/docs-deploy.yml, .github/workflows/lint.yml, .github/workflows/live-e2e.yml, .github/workflows/lockfile-dedupe.yml, .github/workflows/lockfile-integrity.yml, .github/workflows/node-esm-load-gate.yml, .github/workflows/performance-budget.yml, .github/workflows/published-dist-gate.yml, .github/workflows/repo-gates.yml, .github/workflows/shadcn-check.yml, .github/workflows/spec-range-floors.yml + .objectstack-sha, package.json, turbo.json, pnpm-lock.yaml (its @objectstack/* keys), scripts/objectstack-pin.mjs, scripts/bump-objectstack.sh, scripts/check-lockfile-integrity.mjs, scripts/check-lockfile-dedupe.mjs, scripts/check-installed-spec-pin-claims.mjs, scripts/dependabot-merge-gate.mjs, scripts/setup.sh, content/docs/guide/ci-cd-pipeline.md, scripts/tests/objectstack-pin.test.ts, scripts/tests/bump-objectstack.test.ts, scripts/tests/check-lockfile-integrity.test.ts, scripts/tests/check-lockfile-dedupe.test.ts, scripts/tests/check-installed-spec-pin-claims.test.ts, scripts/tests/ci-cd-pipeline-doc.test.ts, scripts/tests/render-budget-comment.test.ts, scripts/tests/report-turbo-cache.test.ts, scripts/tests/shadcn-check-report.test.ts, scripts/tests/turbo-cache-save-bound.test.ts, scripts/tests/check-action-ref-convention.test.ts; read unchanged at the head: scripts/check-governed-queue-guard.mjs (the register), scripts/select-type-check-scope.mjs, and the four workflows that install nothing (board-snapshot, dependabot-auto-merge, merge-queue-head-patrol, required-check-set-patrol). Lane remainder, the lane seat's ACCEPT at TIER_DEFAULT: README.md, CONTRIBUTING.md, QUICK_REFERENCE.md, content/docs/guide/console.md, content/docs/utilities/runner.mdx.

Inputs: card objectui#12957 (body; comments 6248917934 claim, 6250606447 item-6 amendment, 6250846209 triage pointer, 6251605870 os-dev-report), decision card objectui#12955 (body and ruling 6248859734, letter B), PR #12963 (body, 42-file list, net diff from merge-base b5153f44 to the head), and the 36 check-runs on the head: 33 success, 3 skipped (Test (coverage), Test (coverage shard), dependabot, none of which has a pull_request leg for this PR), 0 pending. Nothing was built, run or re-run; GitHub was read with REST GETs and the head with git show after a fetch.

① Derived judgments

  1. Accept set: every @objectstack/* package resolves from the pinned build and none from npm — right. The root manifest overrides seven names (spec, core, types, client, formula, sdui-parser, lint) to file:node_modules/.cache/objectstack/NAME; checkOverrideSet in scripts/objectstack-pin.mjs refuses an override set that is not EQUAL to the runtime closure of the four names the workspace declares (a declared name with no override, a closure member with no override, an override nothing reaches), and readOverrides refuses any @objectstack/* override that is not the pinned-build form. the real tree in objectstack-pin.test.ts pins it on the committed manifest. The card and ruling said six packages; the diff reads seven (core depends on types at the pin) — following the tree over the card is right, and the PR body names the correction.
  2. The lockfile carries no @objectstack/* version — right. At the head pnpm-lock.yaml holds zero keys of the form @objectstack/NAME@DIGIT and exactly the seven @objectstack/NAME@file:node_modules/.cache/objectstack/NAME keys; its diff touches only those resolutions. This is the fact the retired rule and the adapted gates below rest on.
  3. CI accept set: every job that installs restores the pinned build first — right, and verified at the head rather than from the PR body. The 16 pnpm install --frozen-lockfile lines across ten workflows (ci.yml seven jobs; changeset-release, lint, live-e2e, node-esm-load-gate, performance-budget, published-dist-gate, repo-gates, shadcn-check, spec-range-floors one each), docs-deploy's vercel build, and lockfile-dedupe's pnpm dedupe --check are each preceded in their own job by actions/cache/restore@v6 then node scripts/objectstack-pin.mjs build, and followed by a bounded (timeout-minutes: 2), non-fatal, miss-only actions/cache/save@v6 under the key objectstack-pin-OS-hashFiles(.objectstack-sha, scripts/objectstack-pin.mjs). The four other workflows that mention pnpm install do so only in a comment saying they never run it. A step's if: follows its job's existing gate (steps.relevant.outputs.should_run, steps.docs-changes.outputs.should_run, needs.test-coverage.result, !cancelled()), so no job installs where it did not before. Two-speed rule 1 holds: an unchanged pin never rebuilds (a hit is a stamp read), and the cold build is paid once per new pin per job. One named limitation, not a defect: the key omits the override set, so an override change under an unchanged pin and script restores the old cache, judgeStamp rebuilds (correct), and the save step is skipped because cache-hit is true — every job then rebuilds until the pin or the script moves. A follow-up may add the root manifest to hashFiles; nothing here is wrong.
  4. The hermetic checkout — right. checkoutPin fetches exactly the pinned commit, verifies rev-parse HEAD equals the pin, then removes origin; the pinned checkout is hermetic pins the removal over a throwaway upstream. This makes the build a function of the pin alone; the cause it works around (objectstack's spec build fetching origin main to anchor its schema ratchets while building a fixed commit) is an objectstack defect, escalated in ③, not absorbed here.
  5. The nested install reads objectstack's own npm config — right. objectstackEnv drops every npm_config_* variable pnpm run exported from objectui's .npmrc (the measured failure was engine-strict reaching the objectstack install) and keeps the machine's proxy, registry, CA, strict-ssl and store settings; pinned by its test.
  6. The lockfile-vs-build refusal — right, and its ordering is deliberate. A frozen install links a file: directory but resolves its dependencies from the lockfile alone (measured on the PR), so assertLockfileRecordsBuild compares every packed manifest's dependency NAMES with the snapshots: entry and refuses with the remedy (pnpm install). It runs after the cache is written on purpose, so the remedy can read the build. Names only, not ranges — stated in the header; a range that moved under the same name is a known blind spot, acceptable because the frozen lockfile still pins what is installed.
  7. Item 5, the gates (a rule and its gate read as one):
    • check-lockfile-integrity rule 1 (an @objectstack/* version moving backward) retired — right: with no version in the lockfile (judgment 2) the rule had nothing to order; the identity it guarded is now the one-line .objectstack-sha, which merges as text. Rule 2 (a physical copy gained) is kept and now names a registry copy beside the pinned build; the self-test and sampleA in its test are rewritten to that shape, and sampleB still goes red on zod 2 to 3 with no version moving. lockfile-integrity.yml's header and the NOT_A_GATE prose in scripts/dependabot-merge-gate.mjs say the same thing — three carriers, one statement.
    • check-lockfile-dedupe adapted — right: pinnedBuildMissing is read before pnpm is spawned, and an absent build is a cannot-run reading that names the cause, never a deduped verdict; lockfile-dedupe.yml restores the build before the check and its path filter gains scripts/objectstack-pin.mjs. It need not gain .objectstack-sha: the check reads pnpm-lock.yaml, and a pin whose packages change their dependency names is refused until the lockfile is rewritten (judgment 6), which triggers the workflow.
    • check-installed-spec-pin-claims face A adapted — right: a file: resolution is followed to the version the directory's manifest declares; an absent build answers a value no claim can equal and so becomes a named conflict, never an empty face. The header says what the version now means (the release string the pinned commit carries, not the commit), and the live-e2e backend pin in ci-cd-pipeline-doc.test.ts is adapted the same way, with the page stating the version-vs-commit gap.
    • check-spec-range-floors unchanged (it reads the registry, never the installed tree) — right. No new gate — right.
  8. turbo.json and the fast path — right. globalDependencies gains .objectstack-sha and the build's stamp, so a pin bump invalidates replayed verdicts; scripts/select-type-check-scope.mjs reads every globalDependencies entry (read at the head), so a bump PR type-checks the whole workspace instead of replaying main's cache. performance-budget.yml triggers on both paths — right, a bump moves the bundle without touching the lockfile.
  9. The tests that moved with the workflows — right. report-turbo-cache and turbo-cache-save-bound select the .turbo/cache save by path now that a job carries two saves; shadcn-check-report gap 3 reads continue-on-error per step and allows it only on a cache save; render-budget-comment counts five !cancelled() conditions and adds the script to the runtime closure; check-action-ref-convention lists the two new refs. Repo Gates (which carries the action-ref convention check) is success.
  10. AGENTS.md (governed) — every claim of the new hunks read against the cited code, all right. The 「依赖与锁文件」 section: the override form (judgment 1); pnpm run setup equals objectstack:build then pnpm install --frozen-lockfile (root scripts); pnpm setup is pnpm's built-in and never runs the script (a CLI command shadows a script of the same name); the bump contract (refuses an unresolvable or unreadable commit before writing — rev-parse --verify then log -1 ahead of the single write; warns with three answers when off origin/main; seven cases in bump-objectstack.test.ts drive the shipped bytes); the OBJECTSTACK_ROOT stand-in with an unchanged lockfile (the stand-in tests pack through the real pnpm pack and the stamp is never mistaken for the pin); the lockfile rule (judgment 6); and the override-set refusal (judgment 1). The stale-install line (pnpm objectstack:status), the worktree line (pnpm run setup in a new tree — a bare install fails without the build), the local-dev line, and the backend-stack line (objectstack's root package.json has setup: pnpm install && pnpm --filter @objectstack/spec build, so pnpm run setup is the spelling that runs it there too) are each true at the head. The section points at the script header for the mechanism instead of restating it (commandment 9). No model identifier, no bare line address.
  11. The first pin — right under the seat's amendment. .objectstack-sha is 2c9bf9430a1198bfaa5c0de9ff4a811838c6869c, chore: version packages (next) (#23825); packages/spec/package.json at that commit reads 18.0.0-next.3 (REST read). The compare API answers ahead_by 106, behind_by 0 for pin to main, and ahead_by 72 / 73 / 76, behind_by 0 for pin to 586705d85d / 1e001c7df / e15897c0f1 — so the pin is on main and a strict ancestor of all three. That satisfies ruling B (.objectstack-sha pins an objectstack main commit) and the amended item 6 (comment 6250606447: the next.3 release commit, equivalence with npm proved by the dev), and it does NOT satisfy the card body's original item 6 — by the seat's own order, with the pin-bump card named as the follow-up. The dev's diff -rq equivalence reading is the dev's; it is not re-derived here.
  12. Public surface: none moves — right. The root manifest is private; no packages/*/src, no apps/console source, no manifest range, no export, prop, key or schema changes; what the published packages build against is a build of the release commit npm already serves.
  13. Tier and landing — right as the PR stands. GOVERNED_SURFACES in scripts/check-governed-queue-guard.mjs carries six rows with no tiers; AGENTS.md and .github/workflows/** are two of them, so this PR lands only on a latest-decisive APPROVED review by an account in GOVERNED_APPROVERS (Tier H in objectstack's vocabulary). The PR is a draft with auto_merge null and zero reviews; Governed Surface Queue Guard is success on the pull_request leg by design. This record is the contract-tier review of record; it is not the approval, and no seat supplies that approval.

② Semver level

No .changeset/*.md is in the file list and none is owed: objectui's declaration rule (scripts/check-changeset-presence.mjs, enforced by changeset-presence.yml) asks for one only when a fixed-group package's published source or one of its eight publish-contract fields moved, and none did — the diff is root config, scripts/, .github/, docs and tests. The gate verdicts on the head are Changeset Declaration success, Changeset Claim Re-read success, Changeset Fixed Group Check success. The PR body carries Clause-②: no and the claim carries Clause-②: no with the reason (no export, prop, key or schema of a published package moves); neither carries a (widening) or (narrowing) arm. Right: nothing publishes, so no bump level is declared, and the no line is the honest one. The lockfile change is a resolution change, not a published-range change (objectui#12958 owns the ranges).

③ Boundary flags

  • Dev deviation 1 (local packages/app-shell full suite not measured): closed — Test (shard 1/16) through Test (shard 16/16) and Test are success on the head.
  • Dev deviation 2 / open_questions Q3 (files beyond the claim's surface: turbo.json, one prose string in scripts/dependabot-merge-gate.mjs, README.md, CONTRIBUTING.md, QUICK_REFERENCE.md, scripts/setup.sh, three docs pages, five script tests, two path filters; the lockfile-integrity.yml header comment belongs here too): answered A by the seat in the PR body; each is forced by the change (a clean checkout following the old text fails on the missing build directory, or a pinned test goes red). Accepted.
  • open_questions Q1 (Dependabot's npm updates regenerate the lockfile without the build; its sandbox NOT MEASURED): answered by the seat — observe the first post-merge Dependabot npm run; on a failure file the follow-up with option A as the default. Owner: the seat, after landing.
  • open_questions Q2 (shared pin cache card): answered A by the seat, to be filed as the seat's own card per the maintainer's 「如果需要共享缓存,你就开卡」. Owner: the seat.
  • Out-of-scope finding, escalated to the seat for an objectstack card: packages/spec/scripts/build-schemas.ts fetches origin main during a build and judges the commit's published set against it, so a released commit's spec build is not reproducible from a clone with a newer origin/main (13 of 25 jobs failed at db2b7239 on this PR). Worked around here by the hermetic checkout (judgment 4); the producer-side defect is objectstack's and stays open until a card carries it.
  • Out-of-scope finding, escalated to the seat for an objectstack card (governed there): objectstack's AGENTS.md and examples/README.md document pnpm setup as the first-time command, which runs pnpm's built-in; pnpm run setup is the spelling that runs the script. Reported on the card by the dev, not changed here — right, that file is objectstack's Tier H surface.
  • Cross-repo landing order: objectstack's .objectui-sha must not pass this merge until tooling(build-console): when the console build installs objectui at .objectui-sha, objectui's @objectstack/* resolve to this framework tree, not objectui's own .objectstack-sha build (ruling B on objectstack-ai/objectui#12955, step 3) objectstack#24306 (open) lands, and the triage pointer (comment 6250846209) names cloud's .objectui-sha and objectstack-ai/cloud#3023 as a second consumer of the same OBJECTSTACK_ROOT input. The PR body names the objectstack half only; the seat carries both constraints at the two sibling pins. Escalated, not a diff defect.
  • Not exercised on this head: the pin steps in jobs with no pull_request leg (changeset-release, docs-deploy through vercel build, node-esm-load-gate, published-dist-gate, spec-range-floors, shadcn-check) and in ci.yml's test-coverage / coverage-report (skipped on a PR). They carry the same step template as the ten jobs that ran green; the first main run after the merge is their reading and the first main-scoped cache save, which the PR body marks NOT MEASURED. The seat watches that run.
  • Acceptance notes carried, none blocking: apps/console/vercel.json installs frozen on Vercel and would need the pin first (no Vercel status on recent main); e2e/live/ci/backend.env's header still says the version is resolved in the lockfile; the live-e2e lane matches the backend by version string, not by commit (the page says so); spec DTS emit differs in union-member order between builds (JS and JSON identical).
  • Pending check-runs: none. All 36 concluded.
  • The pin-bump card (move the pin past 586705d85d, 1e001c7df, e15897c0f1 and absorb the 15 drift cases in 5 files the dev measured): named by the seat in comment 6250606447 as the next card; objectui#12932, Studio 变更 drawer: on publish, offer 补默认值 per new field that carries a default, through the protocol's opt-in backfill (ruling A on cloud#2924) #12929 and approvals B1 closing card (ruling C on objectui#12438): the inbox opens a request on the served sys_approval_request page where the side sheet is, deletes the sheet, and lists each retired pin against its user report #12484 unblock through it, not through this PR.

Implemented-by: claude/issue-12957-objectstack-sha-pin
Reviewed-by: session_0188TsgPV8kQXfuRuKmkj2ks

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 — ACCEPT · domain:ui seat 1 · session_0188TsgPV8kQXfuRuKmkj2ks · 2026-10-18T15:37Z

Reviewed on GitHub at head 4bd617b0af9220dc6357da9e234582b3ce9d547a, against claim 6248917934 on objectui#12957, as amended by the seat's item 6 (6250606447). It executes ruling B (6248859734) on objectui#12955.

  1. Shape. The PR is a draft against main and opens with Fixes #12957. The assignee is sunhaolin. It changes 42 files, +2700 / −317. check-governed-queue-guard --test reads GOVERNED: AGENTS.md and .github/workflows/** (Tier H).
  2. Contract review. CONTRACT_REVIEW_TIER PASS on this head (6251765296). Its scope is the governed hits, read together with the scripts, the lockfile and the docs they cite.
  3. Lane remainder, reviewed here at TIER_DEFAULT. These files are README.md, CONTRIBUTING.md, QUICK_REFERENCE.md, content/docs/guide/console.md and content/docs/utilities/runner.mdx.
    • Each replaces the first-time pnpm install with pnpm run setup, which builds @objectstack/* at the pin and then installs.
    • CONTRIBUTING.md names the pin and the bump. QUICK_REFERENCE.md keeps pnpm install for after the build exists. runner.mdx warns that deleting node_modules deletes the pinned build.
    • Every sentence matches scripts/objectstack-pin.mjs and the root setup script at the head.
  4. Gates. There are 36 check-runs on this head: 33 success and 3 skipped (coverage and dependabot). Clause-②: no: no published package's export, prop, key or schema moves, and no manifest range moves (objectui#12958 owns ranges).
  5. Item 6, as the seat amended it. The first pin is 2c9bf9430a, the @objectstack/spec@18.0.0-next.3 release commit. The dev compared the pinned build with the npm next.3 tarballs:
  6. Open questions, the seat's answers:
    • Q1 (Dependabot): the seat reads the first npm run after merge, and files a follow-up (default A) if it fails.
    • Q2 (shared pin cache): filed as objectui#12972 under the maintainer's 「如果需要共享缓存,你就开卡」.
    • Q3 (surface extensions): accepted.
  7. Out of scope, filed:
  8. Landing order, held by the seat. objectstack's .objectui-sha must not move past this merge until tooling(build-console): when the console build installs objectui at .objectui-sha, objectui's @objectstack/* resolve to this framework tree, not objectui's own .objectstack-sha build (ruling B on objectstack-ai/objectui#12955, step 3) objectstack#24306 lands. cloud's .objectui-sha must not move past it until objectstack-ai/cloud#3023 lands.
  9. Landing. Tier H: ⛔ the PR stays a draft until an APPROVED review by os-zhuang or hotlong is on it. Then the seat makes it ready and arms auto-merge, and the merge queue lands it.
    • On MERGED, the seat posts the landing note and strips pm:dispatched.
    • The seat then reads the first main run, for the pin steps in jobs with no pull-request leg and for the first cache save on main.

VERDICT: ACCEPT


Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review October 18, 2026 23:55
@os-zhuang
os-zhuang enabled auto-merge October 18, 2026 23:55
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 76 chunks) 3166.0 KB 3744.1 KB
Main entry chunk (gzip) 80.5 KB 350 KB
Entry file index-CxYvnMBl.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 (buildIdentity.js) 0.80KB 0.49KB
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 21.41KB 7.88KB
app-shell (runtime-config.js) 24.52KB 8.48KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 45.59KB 12.03KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 20.67KB 6.12KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.74KB 3.94KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.62KB 0.83KB
auth (authStyles.js) 5.27KB 1.86KB
auth (createAuthClient.js) 42.84KB 11.66KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
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.26KB 8.03KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (commentAuthorship.js) 1.39KB 0.78KB
collaboration (index.js) 1.93KB 0.85KB
collaboration (useCollaborationTranslation.js) 6.50KB 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) 613.07KB 149.18KB
core (index.js) 10.18KB 4.04KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 248.83KB 69.44KB
fields (index.js) 292.36KB 74.70KB
i18n (LocalizationContext.js) 2.92KB 1.42KB
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.52KB 2.39KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 36.87KB 9.88KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 41.33KB 11.96KB
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) 15.35KB 5.51KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.82KB 2.38KB
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.04KB 3.92KB
plugin-calendar (index.js) 55.04KB 16.10KB
plugin-charts (index.js) 85.06KB 23.39KB
plugin-chatbot (index.js) 233.19KB 54.79KB
plugin-dashboard (index.js) 147.53KB 39.95KB
plugin-designer (index.js) 233.95KB 50.08KB
plugin-detail (index.js) 266.29KB 70.61KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 181.16KB 46.84KB
plugin-gantt (index.js) 178.46KB 45.13KB
plugin-grid (index.js) 271.30KB 75.32KB
plugin-kanban (index.js) 63.37KB 19.51KB
plugin-list (index.js) 140.49KB 36.24KB
plugin-map (index.js) 27.17KB 9.00KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 46.66KB 13.13KB
plugin-timeline (index.js) 39.31KB 11.88KB
plugin-tree (index.js) 15.27KB 5.40KB
plugin-view (index.js) 94.68KB 24.36KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 12.07KB 3.68KB
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) 126.45KB 41.40KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.71KB 2.11KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.07KB 1.30KB
sdui-parser (index.js) 7.30KB 3.12KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.81KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 23.87KB 7.83KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
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) 1.13KB 0.65KB
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) 5.78KB 2.70KB
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 (node-slots.js) 7.18KB 2.34KB
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 (product-blocks.js) 0.20KB 0.19KB
types (record-approval-decision.js) 0.20KB 0.20KB
types (record-components.js) 0.20KB 0.19KB
types (record-panels.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) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.26KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.48KB 3.50KB
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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd configuration dependencies documentation Improvements or additions to documentation tests

Projects

None yet

3 participants