Skip to content

feat(app-shell): metadata-admin reads /meta/types allowEnvironmentOverlay; the read-only banners name OS_METADATA_WRITABLE (objectui#12141) - #12168

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-12141-allow-environment-overlay
Oct 12, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-12141-allow-environment-overlay

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #12141

Clause-②: yes

Landing order

This pull request merges first. objectstack-ai/objectstack#22340 S2 (PR objectstack-ai/objectstack#22874, held as a draft for the pin round) then bumps .objectui-sha to this merge. That is ruling Q1 A / Q2 A (6073921182): one landing for the server rename, this companion and the pin, and the order the S2 seat review restates (6112246741).

  • Between the two merges, objectui main reads a field the server does not write yet. The bundled console is unaffected, because its pin stays where it is until S2.
  • There is no dual read of the two names, and no fallback to the old one anywhere in this diff.
  • Cloud: triage 6109764647 records the pin-pair rule on objectstack-ai/cloud#2709. Cloud's .objectui-sha may pass this merge only in the same commit that moves its framework pin to a commit carrying S2.

What changes

The rename. RichMetadataTypeEntry.allowOrgOverride is now allowEnvironmentOverlay, and so is the member resolveResourceConfig takes and returns. Both are exported from the package entry, so the published type surface moves; hence Clause-②: yes and a minor changeset with the breaking semantics stated (this repo's release model, no major). Every reader now reads the new name:

  • the editor's write gates: canWriteByType and the designer auto-on effect in ResourceEditPage;
  • the permission matrix's type and artifact tiers in PermissionMatrixEditor (only its overlay-flag reads and the comments beside them; the cross-lane declaration is on [epic] ADR-0131 — total organization ownership: no NULL organization_id (v18 line) objectstack#15194, 6115259878);
  • the type list's create gate (ResourceListPage), the embedded item editor's read-only gate, the directory's writable count, its "Writable only" filter and its tile badge (DirectoryPage), and the page header badge (PageShell's WritabilityBadge);
  • prose in BuilderLanding, PicklistPreview, useMetadata and registry, and content/docs/guide/console.md.

The renamed member carries a doc comment that names the wire field, its meaning under ADR-0131 D6, and that no other name is read.

The carried banner remedy (triage 6109764647). engine.edit.readOnlyTypeBanner told an admin to set OBJECTSTACK_METADATA_WRITABLE and to "flip {override} in the registry". The server reads only OS_METADATA_WRITABLE: objectstack main reads it in envWritableMetadataTypes, with an empty legacy list. The registry is a TypeScript literal in @objectstack/spec that no deployment edits.

  • The banner now draws OS_METADATA_WRITABLE as its code token. It says what the hatch opens: the type's items that no package ships, never an item a package ships.
  • The {override} placeholder and the registry flip are gone, in English and Chinese.
  • The badge and label tooltips for a hatch-elevated type (DirectoryPage's tile and PageShell's header badge) name OS_METADATA_WRITABLE with the same reach. They no longer name the legacy env var.
  • Why the reach is stated: objectstack main applies the hatch to the runtime-only intent only (ADR-0131 D6). Its own refusal sentence names the hatch to say it does not open a managed item. A banner that offered the hatch unqualified on a packaged item would send the operator to a door the server keeps shut.

Same defect class, fixed in place: the permission matrix hints. This diff edits the two perm.readOnly* hints anyway, to rename the key inside them.

  • perm.readOnly.artifact.hint is shown only for a set a code package ships. It offered "ask an operator for the documented OS_METADATA_WRITABLE escape hatch" as a route, and that route does not open such a set (above). It now says the hatch does not open a set a package ships. Cloning, redeploying the source and a new runtime set are unchanged.
  • perm.readOnly.hint (a type with no runtime write channel) keeps the hatch as a remedy and states its reach.
  • The two tests that pinned the hatch as a route now pin the new sentence instead (PermissionMatrixEditor.artifactTier and PermissionMatrixEditor.cloneToCustomize). The second also asserts that the old route wording is absent.
  • The bounded in-place conditions all hold: the defect class is this card's; the shape is pinned by the server's own sentence; both files are in the claim's surface; and no new verification surface is added.

Not changed, as this seat ruled: the artifact-tier gate's logic. It still reads the flag alone; see the finding below.

Premise checks (measured on d2500d8)

  • H1: the readers were 11 non-test files (10 under views/metadata-admin/ plus studio-design/BuilderLanding.tsx), 49 hits. The field was also named in 59 test files (114 hits). StudioHomePage.tsx is gone. The rename touched exactly 71 files: those, plus the docs page.
  • H2: the export was confirmed on the built closure. dist/index.d.ts re-exports RichMetadataTypeEntry and resolveResourceConfig. After the build, useMetadata.d.ts and registry.d.ts carry allowEnvironmentOverlay and no allowOrgOverride.
  • H3: confirmed. The strings live in the designer table (views/metadata-admin/i18n.ts, en and zh) and in the two tooltips. packages/i18n has none of them.
  • H4: confirmed. Nothing reads the old name.

Verification (final head 2c38817)

  • Dependency closure: turbo run build --filter='@object-ui/app-shell^...' --concurrency=2, 28 of 28 tasks successful. pnpm --filter @object-ui/app-shell build passed, with dist completeness 1062 files verified.
  • pnpm --filter @object-ui/app-shell type-check (it echoes tsc --noEmit && tsc -p tsconfig.test.json; the second project includes every src/**/*.test.tsx): exit 0.
  • Targeted vitest over every test file this diff touches or adds, 61 files: 20 files with 120 tests passed, and 41 files with 212 tests passed. The two new files and four of the edited ones were re-run on 2c38817: 6 files, 70 tests passed.
  • New pins:
    • ResourceEditPage.environmentOverlay-12141: for each of view, dashboard, report, translation and email_template, a packaged item is editable when served the field (both flags true, as S2's registry declares them), and the same item without the field stays locked. Negative control: api, without overlay or runtime create, stays read-only. Its banner names OS_METADATA_WRITABLE and no registry flip, in en and zh.
    • DirectoryPage.environmentOverlay-12141: the tiles and the header badge for the five types; a hatch-elevated agent, whose only open door is the overlay flag, is badged writable and counted; api and the field-less agent are read-only and not counted.
  • Ablation: four mutations through ablation-replace (literal anchors, the landing checked on disk, a trap that restores, and a restore proven by HEAD blob hash with git diff HEAD empty):
    • the artifact arm of canWriteByType reading the old name: 5 failed of 12, the five positive cases;
    • WritabilityBadge reading the old name: 6 failed of 10;
    • the directory's writable count reading the old name: 1 failed of 10;
    • the banner token printing the legacy env var: 2 failed of 12, en and zh.
      All four turned red in the expected direction, and each restore was blob-equal.
  • Gates, all exit 0 at 2c38817: check-changeset-presence, check-changeset-no-major, check:changeset-claims, check:pending-changeset-literals, check:control-bytes, check:new-line-citations (0 new), check:phantom-deps, check:i18n-keys, check:i18n-drift (3 designer en values changed, 3 zh followed), check:i18n-designer-parity, docs:check-links, check:doc-fences, check:test-path-roots, and check:vi-mock-specifiers / -inherit / -override-shape.
  • Lint, narrowed to the 72 changed TypeScript files and run as the package's own eslint . runs (no type-aware linting is configured, and no custom rule reads another file, so the verdict on an untouched file cannot move): 72 files, 0 errors, 176 warnings. All of the warnings were already there, and the two new test files have none.
  • NOT MEASURED: check:eager-closure, because it needs the full console build, which CI's performance-budget job owns. The diff adds 328 net bytes, uncompressed, of shipped strings to the designer table (en and zh together).

Acceptance notes (observed; not filed)

  • The hatch value is wider than what it opens (out of scope by this seat's ruling).
    • A probe render, not committed, used an agent entry the hatch elevates (allowEnvironmentOverlay: true, overrideSource: 'env', no runtime create) and a packaged item. The editor offers Edit.
    • objectstack main refuses that save: the hatch admits the runtime-only intent only, and ADR-0131 D6 seals managed content. That is read from the server source, not measured live.
    • The S2 describe of the field says the elevation never opens a managed item.
    • Whether the artifact tier should also read overrideSource is this lane's call. It is reported to the seat.
  • The landing UI copy (engine.studio.landing.*) and some comments still say "org overlay" after ADR-0131 D6 retired the per-org axis. That is wording only.
  • PermissionMatrixEditor's type-gate comment carries three stale cross-file line addresses. They were left alone because this diff touches only that file's overlay-flag reads, as the cross-lane declaration states.
  • PermissionMatrixEditor.cloneToCustomize's refused-save fixture quotes a pre-D6 server sentence (an escape-hatch remedy the server no longer prints). It is a fixture of the client showing the server's words, so it was left as is.

Generated by Claude Code

…Overlay`; the read-only banner names `OS_METADATA_WRITABLE` and no registry flip (objectui#12141)

The server renames the type entry's overlay flag (objectstack-ai/objectstack#22340
S2). Every reader in the metadata-admin designer and Studio now reads the new
name, with no fallback to the old one, and `RichMetadataTypeEntry` and
`resolveResourceConfig` carry the renamed member.

The read-only type banner named an env var the server does not read and offered
a registry flip nobody can perform; it now names `OS_METADATA_WRITABLE` with the
hatch's reach (ADR-0131 D6). The permission matrix's artifact hint no longer
offers the hatch for a packaged set, which the hatch does not open.

Claude-Session: https://claude.ai/code/session_016djJF12Qt14ejKR5Vjt4sK
Co-authored-by: Claude <noreply@anthropic.com>
…owEnvironmentOverlay`, with the hatch tooltip naming `OS_METADATA_WRITABLE` (objectui#12141)

Claude-Session: https://claude.ai/code/session_016djJF12Qt14ejKR5Vjt4sK
Co-authored-by: Claude <noreply@anthropic.com>
…to `allowEnvironmentOverlay` (objectui#12141)

Claude-Session: https://claude.ai/code/session_016djJF12Qt14ejKR5Vjt4sK
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation tests package: app-shell labels Oct 12, 2026
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 291 chunks) 3177.4 KB 3204.6 KB
Main entry chunk (gzip) 74.1 KB 350 KB
Entry file index-DRjqAH2E.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) 20.05KB 7.41KB
app-shell (runtime-config.js) 22.59KB 7.89KB
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) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 41.19KB 11.12KB
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.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
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) 588.48KB 141.70KB
core (index.js) 10.18KB 4.04KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 241.78KB 67.52KB
fields (index.js) 276.26KB 70.32KB
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) 40.26KB 11.71KB
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) 54.31KB 15.86KB
plugin-charts (index.js) 84.72KB 23.27KB
plugin-chatbot (index.js) 201.72KB 48.07KB
plugin-dashboard (index.js) 144.20KB 38.95KB
plugin-designer (index.js) 233.77KB 50.02KB
plugin-detail (index.js) 250.93KB 66.24KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 177.74KB 46.01KB
plugin-gantt (index.js) 178.63KB 45.19KB
plugin-grid (index.js) 255.50KB 71.02KB
plugin-kanban (index.js) 53.23KB 16.71KB
plugin-list (index.js) 122.82KB 31.24KB
plugin-map (index.js) 27.24KB 9.03KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 39.21KB 11.85KB
plugin-tree (index.js) 15.07KB 5.33KB
plugin-view (index.js) 92.11KB 23.27KB
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) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
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.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
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 (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 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: 2c38817d0aa0a8532fa2ba3d66e643e56fff0714
Local-runs: none

Read: card objectui#12141 (body and all four comments: triage 6109764647, deferral 6110270326, claim 6115250926, dev report 6115575587), PR #12168 (body, 74-file list, net diff against main at the head), the head's check-runs (two readings in this act), and the two objectstack records the card cites (6073921182, 6112246741). objectui AGENTS.md and packages/app-shell/src/index.ts were read at the head for the rules applied below. Nothing was built, run or re-run.

① Derived judgments

The diff: 74 files, +634 / -181. Eleven non-test readers (ten under packages/app-shell/src/views/metadata-admin/, plus studio-design/BuilderLanding.tsx), 59 test files renamed one to one, two new test files, one docs line, one changeset. Each change the diff implies, judged:

  1. The wire accept-set moves whole, no dual read — right. The client reads entries[].allowEnvironmentOverlay and nothing reads allowOrgOverride. Counted on the diff text: 164 removed lines name the old key, 184 added lines name the new one; the five added lines that still spell the old key are all in the changeset's FROM/TO and history prose. No ?? or || fallback to the old name anywhere. That is ruling Q2 A (6073921182: no dual-spelling window) and the card's own prohibition, kept.
  2. The published surface change is exactly the one declared — right. RichMetadataTypeEntry (exported, index.ts:466 at the head) loses allowOrgOverride and gains allowEnvironmentOverlay, same optional boolean; resolveResourceConfig (exported, index.ts:436) renames the same member on its server-entry parameter and its return type. Nothing else exported moves. This is the Clause-② change, judged in ②.
  3. Every write gate reads the new field, logic otherwise unchanged — right. ResourceEditPage: canWriteByType (createMode, artifact and org-authored arms) and the designer auto-on cw; PermissionMatrixEditor: canWriteByType and lockedByArtifactTier; ResourceListPage: typeWritable; EmbeddedItemEditor: readOnly; DirectoryPage: writableCount, the "Writable only" filter and the tile badge; PageShell: WritabilityBadge. Each is a one-name substitution; the artifact arm still reads the flag alone (③ item 1). Type Check is success on this head, which is the compile proof that no typed reader of the old name remains.
  4. The banner remedy — right, and the done-when's third line is met. engine.edit.readOnlyTypeBanner (en and zh) drops the {override} placeholder and the registry flip; the split regex in ResourceEditPage drops {override} to match; {flag} renders OS_METADATA_WRITABLE. Placeholders stay equal across en and zh ({flag}, {type}). The hatch tooltips on DirectoryPage's tile and PageShell's badge name OS_METADATA_WRITABLE with its ADR-0131 D6 reach. The legacy OBJECTSTACK_ spelling appears in added lines only inside not.toContain assertions and the changeset's history sentence.
  5. The perm.readOnly* hints — right as a bounded in-place fix. perm.readOnly.hint keeps the hatch as a remedy and states its reach; perm.readOnly.artifact.hint withdraws the hatch as a route for a set a package ships. Both follow the card's own premise (a hatch-elevated type's managed items stay sealed, ADR-0131 D6) on lines the rename had already rewritten; PermissionMatrixEditor.artifactTier and .cloneToCustomize now pin the new sentence and the old route's absence. Scope reading in ③ deviation 2.
  6. The new pins carry the done-when's test with its negative control — right. ResourceEditPage.environmentOverlay-12141: each of view, dashboard, report, translation, email_template opens a packaged item when served the field and stays locked without it (so allowRuntimeCreate: true alone opens no packaged item and no other name is read); api stays read-only, its banner names OS_METADATA_WRITABLE with no registry flip, en and zh. DirectoryPage.environmentOverlay-12141: the five tiles and the header badge; a hatch-elevated agent (overlay flag its only open door) badged writable and counted, "Writable only (6)" of seven; api and the field-less agent read-only and uncounted.
  7. Cross-lane boundary on PermissionMatrixEditor.tsx held — right. Its hunks are the overlay-flag reads and the comments beside them; the epic feat: Setup catalog pages read the registry (editable under single, read-only under a wall); assignment pages stay data pages; pickers list the registry (objectstack ADR-0131 D3/D7) #7611 C9 sys_capability read is untouched, as the claim's declaration promised.
  8. History comments took the new name — accepted on the card's terms, noted. Headers and comments narrating objectui#4446, objectstack#6483 and ee58392e1 now say allowEnvironmentOverlay where the name of their time was allowOrgOverride. The card's done-when requires git grep allowOrgOverride over packages/**/src to answer 0, which forces this; the changeset's FROM/TO line is where the old name lives. (S2's seat review 6112246741 asked the opposite of one objectstack history comment, under a different done-when; not re-adjudicated here.)
  9. One docs line renames the key but keeps "org overlay" beside it — wording drift, not the done-when's. content/docs/guide/console.md now reads "an org overlay ... (allowEnvironmentOverlay)". Same class as the dev's third out-of-scope finding; ③ carries it.
  10. Governance and size — right. No governed path in the file list (Governed Surface Queue Guard success); 815 changed lines; head repository equals base repository, so not a fork PR. The pending .changeset/11808-readonly-package-card.md keeps the old key as history, per the card; Changeset Claim Re-read success.

Check-runs on the head, as read in this act (second reading, later than the first): 42 runs. 30 success (among them Lint, Type Check, Build & E2E, Test (dist pins), Changeset Bump Policy, Changeset Declaration, Changeset Fixed Group Check, Changeset Claim Re-read, Governed Surface Queue Guard, Line Citation Gate); 3 skipped (the coverage matrix placeholder, Test (coverage), dependabot); 8 in_progress (Test (shard 1/8) through (shard 8/8)), which are not passes at this reading; 1 failure, Spec Main Shape Gate. That gate's own annotations attribute the red to packages/app-shell/src/views/metadata-admin/previews/flow-node-refs.ts:145, TS2367 ("value" versus "flow-template"), compiled against objectstack-ai/objectstack@9963322fe8b6. That file is not among this PR's 74 files; the workflow's header states its subject is the drift between the two repositories' main branches, moving when no file here changes, and that the context is requirable but not required. So the red is objectstack main's shape moving under objectui main, not this diff's, and it will stand on every objectui PR until a sibling card moves flow-node-refs.ts. The job log itself was not readable through this act's channel (the log redirect answered Forbidden); the annotations are the reading.

② Semver level

  • Changeset .changeset/12141-allow-environment-overlay.md: @object-ui/app-shell: minor. The body states BREAKING, the FROM allowOrgOverride TO allowEnvironmentOverlay mapping, the one-line migration (rename the member; its value is unchanged), the server precondition (a server carrying objectstack#22340 S2) and the failure mode against an older server. Right. objectui AGENTS.md at the head, line 272: 「objectui 自身的破坏性变更也标 minor(在正文里写清 breaking 语义即可)」, enforced by scripts/check-changeset-no-major.mjs; Changeset Bump Policy, Changeset Declaration and Changeset Fixed Group Check are success on this head. No other released package changes; docs and tests are not published surface; skip-changeset does not apply.
  • Clause-②: yes (PR body, and the changeset body's closing paragraph): right. A member of an exported type and of an exported function's parameter and return moves, so the published surface changes and this review is owed; the line corrects triage's no (6109764647), as the deferral note and the claim already did. One precision note: the closed-pair arm is omitted. A removed member is the (narrowing) arm under the declaration grammar, and S2 declared yes (narrowing) for the same rename on the objectstack side. The changeset body already carries the BREAKING statement and the migration that arm exists to force, and objectui's declaration gate passed, so the level and the consumer-facing text are complete; the line is one arm short. A body-only edit the adopting seat may make at adoption; it moves no level.

③ Boundary flags

Dev report 6115575587: open_questions is empty. Six deviations and four out_of_scope_findings, each answered or escalated:

Deviations

  1. Two new test files outside the claim's enumerated list. Answered: the card's done-when requires exactly this test (each write gate keyed on the new field, with a negative-control type); the files sit in the claim's directory, carry the card number, and no other claim can hold them. Accepted; the surface's intent is kept.
  2. Bounded in-place fix of the perm.readOnly* hints beyond the pure rename. Answered: the lines were already rewritten by the rename; the old route (ask an operator for the hatch to open a packaged set) contradicts the card's own premise and the rule against advertising a capability the runtime does not deliver; both files are in the claim's surface; the two pins moved with it; the artifact-tier gate logic is untouched. Accepted as bounded; stated in the PR body and the report, as required.
  3. Reach wording on the banner and tooltips beyond the done-when minimum. Answered: it states what the card itself says the hatch opens; en and zh move together. Accepted.
  4. Model-free commit trailers instead of the harness trailer. Answered: that is the attribution rule; not a property of the diff. Noted.
  5. A probe test created and deleted, never committed. Answered: the file list carries no such file. Accepted.
  6. Worktree and private refs removed; a remote-tracking ref left in the objectstack checkout. Housekeeping, read-only. Accepted.

Out-of-scope findings

  1. The hatch value is wider than what it opens: the artifact tier reads the flag alone, so a hatch-elevated type's packaged item offers Edit and the server refuses the save with 403. Escalated to the adopting seat, to file as its own card. The card leaves "whether this gate should read more than the flag" to this lane; the defect is pre-existing and loud, outside this done-when, so it does not hold this PR. It is reproducible (the dev's probe render) and the finding is already written in filing shape with dedupe words, so it belongs in a card, not only in acceptance notes. The card should name both halves of the seam: the client could read overrideSource beside the flag, or the wire could stop reporting true for a type whose managed items the hatch never opens; which half moves is the cross-layer question.
  2. Stale cross-file line addresses in PermissionMatrixEditor's type-gate comment. Answered: pre-existing; the cross-lane declaration limits this diff to the flag reads; Line Citation Gate reports 0 new citations. Carrier named (epic feat: Setup catalog pages read the registry (editable under single, read-only under a wall); assignment pages stay data pages; pickers list the registry (objectstack ADR-0131 D3/D7) #7611 C9). Accepted.
  3. "org overlay" wording in the landing copy and comments after ADR-0131 D6 retired the per-org axis. Answered: wording, not this card's. Escalated as a wording follow-up card for the objectui lane, because this diff's own console.md line (① item 9) is one instance it touched and left. Not blocking; objectstack's S3 covers only its own governed text.
  4. cloneToCustomize's refused-save fixture quotes a pre-D6 server sentence, key renamed inside it. Answered: the assertion is that the client shows the server's words verbatim, so the fixture's fidelity to current server prose is not what it pins; the rename inside it is forced by the done-when grep. Accepted as fixture drift; noted.

Flags this review adds

  • Spec Main Shape Gate red on the head — attributed in ① to flow-node-refs.ts:145 against objectstack@9963322fe8b6, outside this diff; nothing in this PR moves it, and its header says the context is not in the required set. The seat reads its ruleset, not this record, for what the queue requires.
  • Landing order — this PR merges first; S2 (objectstack#22874, draft for the pin round) then bumps .objectui-sha to the merge; cloud's pin-pair rule stands (triage 6109764647). The window in which objectui main reads a field the server does not yet write is the ruled Q2 A shape; the bundled console keeps its pin until S2. Right.
  • Draft state and the eight test shards — the PR is a draft; the eight shards were in_progress at this reading. The landing is the owning seat's act once they complete success; this record does not stand in for that green.

Implemented-by: claude/issue-12141-allow-environment-overlay
Reviewed-by: session_016djJF12Qt14ejKR5Vjt4sK

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Spec Main Shape Gate red: not this PR's · domain:ui seat 1 · session_016djJF12Qt14ejKR5Vjt4sK · 2026-10-12T00:44Z

  • The failure: packages/app-shell/src/views/metadata-admin/previews/flow-node-refs.ts:145, TS2367 ("value" versus "flow-template"), compiled against objectstack 9963322fe8b6.
  • Why it is not this PR's: that file is not in this PR's diff. The gate was green on base d2500d8 at 22:58Z. objectstack-ai/objectstack PR #22883 (9fdb12752c) merged at 23:06Z and retired the flow-template role.
  • The fix: objectui#12170 is the anchor card, claimed and dispatched by this seat. Once it merges, the seat syncs this PR with main through the relay, and the gate re-runs then. Nothing is re-run before that, because a re-run would compile the same merge ref.

Generated by Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 291 chunks) 3177.4 KB 3204.6 KB
Main entry chunk (gzip) 74.1 KB 350 KB
Entry file index-CQ77-fgT.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) 20.05KB 7.41KB
app-shell (runtime-config.js) 22.59KB 7.89KB
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) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 41.19KB 11.12KB
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.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
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) 588.48KB 141.70KB
core (index.js) 10.18KB 4.04KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 241.78KB 67.52KB
fields (index.js) 276.26KB 70.32KB
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) 40.26KB 11.71KB
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) 54.31KB 15.86KB
plugin-charts (index.js) 84.72KB 23.27KB
plugin-chatbot (index.js) 201.72KB 48.07KB
plugin-dashboard (index.js) 144.20KB 38.95KB
plugin-designer (index.js) 233.77KB 50.02KB
plugin-detail (index.js) 250.93KB 66.24KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 177.74KB 46.01KB
plugin-gantt (index.js) 178.63KB 45.19KB
plugin-grid (index.js) 255.50KB 71.02KB
plugin-kanban (index.js) 53.23KB 16.71KB
plugin-list (index.js) 122.82KB 31.24KB
plugin-map (index.js) 27.24KB 9.03KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 39.21KB 11.85KB
plugin-tree (index.js) 15.07KB 5.33KB
plugin-view (index.js) 92.11KB 23.27KB
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) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
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.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
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 (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 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
objectstack-fleet Bot marked this pull request as ready for review October 12, 2026 01:48
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 12, 2026
Merged via the queue into main with commit e531116 Oct 12, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-12141-allow-environment-overlay branch October 12, 2026 02:06
zhuangjianguo pushed a commit to objectstack-ai/objectstack that referenced this pull request Oct 12, 2026
…, carries objectui#12141); re-measure the spec's pin citations

`.objectui-sha` 4997995022f8 -> e5311165a8d6, the merge of
objectstack-ai/objectui#12168: objectui main from that commit on reads the
`GET /meta/types` field under its new name, `allowEnvironmentOverlay`.

The 55 asserting pin citations in packages/spec/src (49 hand-written, 6 in
the generated migrations registry) are re-measured over the objectui diff
4997995022f8..e5311165a8d6 (287 paths, 24 commits): five cited files changed
(ObjectGrid.tsx, data-table.tsx, form.tsx, record-related-list.tsx,
data-objectstack/src/index.ts) and every cited line in them moved or held
byte-identical; each record carries a hop sentence, and the anchors that
moved are re-pointed in the records' at-this-pin text. The six migration
entries' corpus counts are re-taken with git grep -o -F (8506 tracked
files). check:objectui-pin-citations --verify-anchors: 55 asserting citations
match, 13 anchor content assertions verified at e5311165a.

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

Labels

documentation Improvements or additions to documentation package: app-shell tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

metadata-admin reads /meta/types allowEnvironmentOverlay (the server renames allowOrgOverride, objectstack#22340 S2)

2 participants