Skip to content

fix(react): the withholding console line names an element, not a navigation entry - #13306

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-13303-withholding-copy
Oct 21, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-13303-withholding-copy

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #13303

Clause-②: no

What

The 'withholding' consequence paragraph of the shared visibility diagnostic (GATE_KIND_COPY.withholding in packages/react/src/utils/visibilityDiagnostic.ts) was written for the app-shell navigation visible gate (objectui#12700) and said "a navigation entry whose predicate cannot be evaluated is WITHHELD". The page:tabs item gate (objectui#13286) and a page node's visibleWhen / visible / visibleOn (objectui#13299) report through the same paragraph, so an author whose block or tab was withheld was told that a navigation entry was.

The paragraph now reads the same on all three surfaces:

The element was treated as its safe default, which on THIS gate is the
one that BITES: an element whose visibility predicate cannot be evaluated
is WITHHELD - not drawn - until it can be, so a missing element may be
this fault rather than a gate that said no.

The line keeps its shape: the prefix (UNRESOLVABLE_VISIBILITY_PREFIX), the line breaks, the hyphen style of the other gates' copy, and the "WITHHELD - not drawn" clause. The PredicateGateKind docblock's 'withholding' entry now lists the three gates that report through it.

Route: the surface-neutral copy, the card's first route. The second route ("the reporter takes the surface from its caller") would add a parameter to reportUnresolvableVisibilityPredicate and formatUnresolvableVisibilityMessage, both published exports of @object-ui/react. The neutral sentence reads right for a navigation entry, a page:tabs item and a page node, so no signature, export, type member or PredicateGateKind member moved. The gates' verdicts are untouched.

Measured at the head: formatUnresolvableVisibilityMessage(..., 'withholding') called with each caller's own arguments (element:probe-13299 with visibleWhen; page:tabs with visibleWhen; app-shell:visible with visible and the app-shell tier) prints the paragraph above, byte for byte, between the Reason: line and that tier's advice paragraph.

Pins

  • SchemaRenderer.disabledGateFaultDiagnostic.test.tsx: VISIBILITY_TAIL was the only pin that asserted the navigation wording. It checked the whole consequence and advice string with endsWith, and it keeps checking the whole new string.
  • SchemaRenderer.nodeVisibilityFailClosed-13299.test.tsx, row (a): the console line for a faulting page node (element:probe-13299, production and development builds) now also asserts not.toMatch(/navigation|\bentry\b/i). This is the acceptance pin.
  • The other pins of the withholding line read only WITHHELD or WITHHELD - not drawn, which the new copy keeps, so none changed: SchemaRenderer.concealmentGateFaultDiagnostic, SchemaRenderer.visibleWhenRecordBinding, components' page-node-visibility-fail-closed-13299 and page-tabs-visible-when-fail-closed-13286, app-shell's navigationVisibility-12700 and UnifiedSidebar.navCanPermissions-12700.
  • Re-grep after the change, whole tree: git grep for "navigation entry whose predicate", "missing entry may be" and "The entry was treated" gives 0 hits each (exit 1). Control: "missing element may be" gives 2 hits (the source and the pin).

Tests, at head 8625ff893

All runs went through the shared verify lock, from the repo root.

  • The named family (SchemaRenderer.concealmentGateFaultDiagnostic, SchemaRenderer.disabledGateFaultDiagnostic, SchemaRenderer.nodeVisibilityFailClosed-13299, visibilityDiagnostic.adviceTier): Test Files 4 passed (4), Tests 84 passed (84).
  • Consumer sweep, every test file that reads the diagnostic line (git grep -l for UNRESOLVABLE_VISIBILITY_PREFIX, visibilityDiagnostic or app-shell:visible over test files; 21 files across react, components, app-shell and console): Test Files 21 passed (21), Tests 288 passed (288).
  • Ablation (one-shot, nothing kept): ablation-replace.mjs put the old navigation copy back (anchor 1 to 0, blob 29e7a2cce1a9 to 1bbd67872431) and ran the disabled-gate, node-visibility and concealment files: Tests 3 failed | 61 passed (64). Red: and the visibility gate still prints its own copy (the VISIBILITY_TAIL check) and row (a) in both builds (expected '[ObjectUI] A visibility predicate cou…' not to match /navigation|\bentry\b/i). The concealment file stayed green as the control, because both copies carry WITHHELD - not drawn. Restore: blob back to 29e7a2cce1a9, equal to the HEAD blob, and git diff HEAD empty. There is no dist step: the subject is reached through relative source imports.

Gates

  • pnpm --filter @object-ui/react type-check (tsc --noEmit && tsc -p tsconfig.test.json; the test project lists both changed test files), after the @object-ui/react^... closure build: exit 0.
  • pnpm --filter @object-ui/react lint: exit 0, 0 errors, no warning in a changed file.
  • pnpm check:new-line-citations: exit 0, 0 new citations. pnpm check:control-bytes: exit 0. node scripts/check-changeset-presence.mjs: exit 0. node scripts/check-changeset-no-major.mjs: exit 0.
  • Left to CI: the full packages/react directory and the rest of pnpm test, and the repo-wide lint.

Changeset: .changeset/13303-withholding-copy.md, @object-ui/react patch.

Acceptance notes

  • packages/react/src/index.ts re-exports PredicateGateKind under a comment that still describes 'withholding' only as the app-shell's fail-closed navigation gate. That comment became incomplete with objectui#13286 and objectui#13299, not with this change, and it is outside this claim's file surface, so it is left as it is. Carrier: none.
  • The line's first row still names each subject as node "TYPE": the app-shell's constant app-shell:visible, and for a tab the page:tabs container whose item was withheld. Every gate kind shares that row, and the card names only the consequence paragraph, so it is unchanged here. Not filed.

Generated by Claude Code

…gation entry

The 'withholding' consequence paragraph of the shared visibility
diagnostic was written for the app-shell navigation gate and said "a
navigation entry whose predicate cannot be evaluated is WITHHELD". The
page:tabs item gate and a page node's SHOW legs report through the same
paragraph, so an author whose block or tab was withheld was told a
navigation entry was. The paragraph now says "an element whose
visibility predicate cannot be evaluated is WITHHELD", true on all three
surfaces; the PredicateGateKind docblock lists the three gates. The
whole-string pin moves with it, and the page-node pin asserts the line
names no navigation surface.

Claude-Session: https://claude.ai/code/session_014MXhk1yjWh37d634hLy3p7
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · ACCEPT · objectui#13303 · PR #13306 · domain:ui#1 · session_014MXhk1yjWh37d634hLy3p7 · 2026-10-21T07:33Z

Head 8625ff8937. Reviewed against the claim 6310406961 and the dev report 6310612266 on objectui#13303, read on GitHub rather than from the report. No contract-review record is owed: the claim and the PR body read Clause-②: no. The diff changes the text of a console diagnostic and a docblock. No export, signature, type member or PredicateGateKind member moves.

  1. Shape: draft PR against main. The body's first line is Fixes #13303, the only closing keyword. Assignee huangyiirene. 4 files, +48 / −19:
    • visibilityDiagnostic.ts (the 'withholding' paragraph, its table comment, and the PredicateGateKind docblock);
    • two pins;
    • one @object-ui/react patch changeset.
      Not Tier H.
  2. The Expected, read in the diff:
    • The paragraph now reads "The element was treated as its safe default … an element whose visibility predicate cannot be evaluated is WITHHELD - not drawn - until it can be, so a missing element may be this fault rather than a gate that said no."
    • It keeps the prefix, the \n breaks, the hyphen style and the WITHHELD - not drawn clause the concealment pin reads.
    • The docblock lists the three gates that report through it: the navigation visible gate (objectui#12700), the page:tabs item gate (objectui#13286), and a page node's declared visibleWhen / visible / visibleOn (objectui#13299).
    • The card's other route (the reporter takes the surface from its caller) was not taken, because it would move a published signature. That follows the brief's H1.
  3. One widening, accepted: the paragraph's opening "The entry was treated" became "The element was treated", because "entry" is the navigation noun. The paragraph is the card's subject, so this stays in scope.
  4. Pins:
    • SchemaRenderer.disabledGateFaultDiagnostic's VISIBILITY_TAIL still asserts the whole string, now the new one.
    • SchemaRenderer.nodeVisibilityFailClosed-13299 row (a) adds not.toMatch(/navigation|\bentry\b/i) on the page-node line in both builds. That is the acceptance pin.
    • No assertion is weakened.
    • A whole-tree re-grep for "navigation entry whose predicate", "missing entry may be" and "The entry was treated" reads 0 each.
  5. Ablation:
    • The old copy restored gives 3 failed | 61 passed (64): the tail pin and row (a) in both builds. The concealment file is the green control.
    • The restore was proved by blob hash and an empty git diff HEAD.
    • The consumer sweep (21 files across react, components, app-shell and console, which reach the reporter) passes, 288 tests.
    • The dev printed the line for all three callers at the head, and the same paragraph appears on each.
  6. Gates: the dev's local runs at the head, all exit 0:
    • the @object-ui/react closure build, type-check and lint (0 errors);
    • check:new-line-citations, check:control-bytes, changeset presence and no-major;
    • the governed queue guard: not governed.
      The flip waits for every check-run on this head to be green or an expected skip, and for the PR to be free of conflicts.
  7. Out-of-scope findings, noted and not filed:
    • the comment over the PredicateGateKind re-export in packages/react/src/index.ts still describes 'withholding' as the navigation gate only;
    • the line's first row names each subject by its node type.
      Both are in the PR's Acceptance notes.
  8. Landing: not Tier H, and no contract-review face is hit.

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 77 chunks) 3225.0 KB 3744.1 KB
Main entry chunk (gzip) 81.2 KB 350 KB
Entry file index-CjY56gDG.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.90KB
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) 617.54KB 150.58KB
core (index.js) 10.18KB 4.04KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 252.96KB 70.67KB
fields (index.js) 294.97KB 75.45KB
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.40KB 12.01KB
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.56KB 16.21KB
plugin-charts (index.js) 86.06KB 23.66KB
plugin-chatbot (index.js) 238.47KB 56.30KB
plugin-dashboard (index.js) 147.53KB 39.95KB
plugin-designer (index.js) 233.95KB 50.08KB
plugin-detail (index.js) 267.56KB 71.11KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 186.64KB 48.54KB
plugin-gantt (index.js) 178.46KB 45.13KB
plugin-grid (index.js) 276.74KB 76.89KB
plugin-kanban (index.js) 64.49KB 19.83KB
plugin-list (index.js) 149.81KB 39.28KB
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.54KB 24.33KB
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) 129.13KB 42.23KB
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
objectstack-fleet Bot marked this pull request as ready for review October 21, 2026 07:45
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 21, 2026
Merged via the queue into main with commit 601c406 Oct 21, 2026
37 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-13303-withholding-copy branch October 21, 2026 07:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Visibility fault console line calls a withheld page node or tab "a navigation entry"

2 participants