Skip to content

feat(app-shell): the served approval request page names who the pending step waits on (objectui#12482) - #12497

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-12482-approver-names
Oct 15, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-12482-approver-names

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #12482
Clause-②: no. The panel draws more of the bound row it already reads; no type, prop, export, page node or spec declaration changes.

What changes

The decision panel (record:approval_decision), which objectstack's served sys_approval_request_detail page already mounts in its actions slot, now draws a "Waiting on" row between the tally and the decisions. Each pending approver is one chip:

  • the server's own name for a user id (pending_approver_names, from the same approvals get the page reads);
  • for a position:NAME slot the server left unnamed, the position's registry label, with the people who hold it;
  • the countersign group the slot fills (pending_approver_groups, on a per_group node), as · Finance;
  • one person holding several quorum slots is one chip with a count (Ada Lovelace ×3, objectui#12077's case); two people sharing a name in two groups stay two chips;
  • an id nothing can name keeps the identity formatter's middle-truncated face (zzUnre…z123), the face the inbox's sheet draws for it. Every raw slot stays in the chip's title, on hover only.

The drawing reuses app-shell's one approver-naming path, the one the business record's approvals panel already draws its chips with: approverChips over approverDisplay, and useApproverDirectory for references the server left unnamed. Files: packages/app-shell/src/views/approval-decision/ApprovalDecisionPanel.tsx (+ its test), one console test, one changeset. ApprovalsInboxPage (the sheet) is not touched (ADR-0060 rule 3), and nothing is exported.

Fit before build (the ruling's item 2), measured

  • The block that carries the face is the one the page already has. record:approval_decision is a declared spec type with an empty strict props row, and the panel reads the bound request row. At objectstack 57994c311f the approvals get serves pending_approvers, pending_approver_names (the service's display enrichment) and, on a per_group node, pending_approver_groups (set beside decision_progress). The spec's approval-service contract declares both name maps as display enrichment. So the face needs no spec row, no page edit and no new block.
  • DecisionProgressIndicator cannot carry it without a contract change. It draws a tally, and its own docblock says a caller renders it only when the tally is present. A first_response node carries no decision_progress, so the indicator is not drawn there at all, while that node's approver is still waiting. The sheet and the business record's approvals panel both draw the tally and the names as two parts under two gates (tally present; pending request with at least one slot). The panel does the same. approval-progress/** is unchanged.

The PM's mechanism assumptions, measured

  • A1 holds. The panel already holds the row: it read pending_approvers for the eligible count before this change.

  • A2 holds, with the cost named. A slate the get named whole costs 0 extra requests (pinned). A position: slot the server left unnamed costs:

    • the metadata store's ensureType('position'), one GET /api/v1/meta/position per session, shared with every other reader of the store;
    • the staffing leg: one sys_user_position find, plus one sys_user find when the seat has holders;
    • team: and department: slots: one find per directory object.

    All reads are $in-batched, once per slate per page session, through a module cache the decision buttons on the same request share. So at most 3 reads per page, whatever the number of approvers. Per approver: none. The sheet's own path reads only ensureType('position'). The app-shell path also names the seat's holders, as the business record's panel already does.

  • A3: the sheet's face is matched; its "and N more" form does not exist. The sheet draws its "Waiting on" row on a pending request with a slot:

    • one chip per (name, group);
    • the server name first, then the identity formatter (a position's registry label or prettified name, Role: X, an email as is, a long id middle-truncated);
    • the group as · G, duplicates as ×N, first-seen order, raw ids in title.

    The sheet has no "and N more" form. Its only "more" strings are the list's load-more. So nothing of that shape is matched.

  • A4 is false on the served page: no raw approver id is printed there today. The served page's Details tab is a bare record:details. Since objectui#12433 that draws the object's highlightFields minus the strip's fields, which leaves record_id alone. pending_approvers is not a highlight field. Measured on the real RecordDetailView over ApprovalRecordReads, before this change, with a three-slot slate: the approver ids appear 0 times on the served page. The "More details" print objectui#12077 measured is the synthesized page, used when no page is served: the same probe there prints the ids 3 times, and the decision panel is not mounted on that page.

    The spec declares pending_approvers as Field.textarea, a comma-separated slot store that mixes user ids, position: and role: refs and emails, not a user reference. So "draw the field by name" does not apply, and on the served page there is nothing to hide.

Pins

  • ApprovalDecisionPanel.test.tsx, a new describe block covering:

    • two same-name people in two groups;
    • one person in three quorum slots;
    • a position's registry label and holder;
    • CONTROL: the server's name wins and nothing is asked;
    • CONTROL: an unnamed id is middle-truncated;
    • CONTROL: no pending approvers;
    • CONTROL: a decided request names no one;
    • a first_response node with no tally still names its approver.
  • apps/console/src/services/approvalRequestsDataSource.servedPageApprovers-12482.test.tsx: the served page, copied whole, on the real RecordDetailView under the console's ApprovalRecordReads, with only the transport, the console adapter and the metadata store doubled. It pins:

    • named approvers with groups and a position label;
    • no pending approver id printed anywhere on the page;
    • objectui#12077's three-slot case;
    • no directory read for a server-named slate;
    • CONTROL: no pending approvers;
    • CONTROL: an unresolvable id drawn as the sheet draws it.

    It lives in apps/console because the routed source it mounts is console code.

Ablation (one-shot, not kept)

The fix was committed first (233965379b). The script mutated ApprovalDecisionPanel.tsx, dropping the PendingApprovers element for a marker comment:

  • the anchor count went 1 to 0 and the marker count 0 to 1;
  • 10 pins went red: the 6 naming pins in the panel suite and the 4 in the served-page suite;
  • 17 stayed green: the controls (no slots, a decided request, no directory read) and the suites' pre-existing tests.

Restore: git checkout HEAD -- the path, then a blob-hash match against HEAD, with git diff HEAD empty, under a trap on EXIT, INT and TERM. No build sits between: the root vitest config aliases every @object-ui specifier to source, so the pins read the edited file.

Gates (local subset; the full farm is CI's)

All local readings are at 233965379b (the branch head), with each exit code captured before any pipe.

  • Dependency closure build: pnpm turbo run build --filter='@object-ui/console^...' --concurrency=2, run so the type-checks read built declarations. Exit 0; 34 tasks, 28 of them cache hits.
  • pnpm --filter @object-ui/app-shell type-check (tsc --noEmit && tsc -p tsconfig.test.json): exit 0. The test project's include glob, src/**/*.test.tsx, covers the panel's suite. That is read off the glob, not counted with --listFiles.
  • apps/console tsc --noEmit --listFiles: exit 0. The new pin is in the file list (1 hit).
  • vitest, one run, 47 files, 391 tests, all passed, exit 0:
    • approval-decision/ and approval-progress/;
    • every approvalRequestsDataSource.* suite and AppContent.approvalRecordReads;
    • all of apps/console/src/pages/system/, which holds the ApprovalsInboxPage.* pins, run as the CONTROL;
    • RecordApprovalsPanel*, the two RecordDetailView approval suites, global-page-blocks.render, DeclaredActionsBar.overrideAffordance, useApproverDirectory.contractEnvelope-5945 and approverIdentity*.
  • Census and ratchet tests whose subject the diff touches, one run, 18 files, 696 tests, all passed, exit 0:
    • in app-shell: product-neutral-renderer.ratchet, no-component-any-cast, no-refresh-key-remount, adr0054-ratchet, defaults-maps-mirror-en-pack, writeRefusalCensus-11583;
    • in i18n and components: ariaLabelLiteralCensus-12145, machineLocaleCensus-9909, dead-pack-keys-retired-8754, iconOnlyButtonCensus-12143;
    • script suites: check-i18n-call-site-keys, the three check-vi-mock-*, one-authority-per-exported-name-6273, check-control-bytes;
    • registration: registry-inputs-spec-parity, record-approval-decision-arm-12342.
  • Check scripts, each exit 0:
    • check:control-bytes and check:new-line-citations (0 new citations);
    • check:i18n-keys and check:i18n-drift;
    • the three check:vi-mock-* and check:test-path-roots;
    • check:changeset-claims and check:pending-changeset-literals;
    • check:handler-key-reads, check:metadata-write-doors and check:unreferenced-sources;
    • check-changeset-no-major, -overwrite, -presence and -fixed.
  • eslint on the three changed source and test files: exit 0, no findings.
  • Left to CI, not run here:
    • pnpm lint, repo-wide;
    • the pnpm test shards;
    • Bundle Analysis (the eager closure needs a full console build);
    • check:sdui-registration-pins, which reads a full build;
    • check:i18n-designer-parity (no label was added and no pack changed).

Acceptance notes

  • Out of this face, measured, not filed (for the seat): the submitter's raw id. On the served page the highlights strip prints submitter_id, declared Field.lookup('sys_user'), as the bare id. The approvals get serves the id plus submitter_name, never an expansion. The strip made no label read: findOne was never called, no sys_user read was made, and the served submitter_name was not shown.
    • This holds before and after this change.
    • Measured in the harness on the real RecordDetailView under ApprovalRecordReads, not on a live server.
    • The landing site is the seat's call: the get route serving the lookup expanded, or the lookup display reading a served name. A consumer-side reshape in the routed source would be the tolerant fallback AGENTS.md #0.1 refuses.
    • The served-page pin here asserts approver ids only.
  • The synthesized page still prints the slot store under "More details" (objectui#12077's original reading), on hosts that serve no sys_approval_request_detail page. This face does not reach it: the panel is not mounted there. The fix would be producer-side (the object's declaration) or a route-scoped hide, both off this surface.
  • The tally's "N eligible approver(s)" counts slots, not people: one person in three quorum slots reads "3 eligible approver(s)" beside one ×3 chip. The sheet and the business record's panel count the same way, and the count's meaning (slots or people) is not declared anywhere. Noted, not changed.
  • The chip markup is now drawn in two app-shell places from one approverChips output: this panel and the business record's approvals panel (outside this card's file surface). The closing card that retires the sheet is the natural place to fold them into one.

Generated by Claude Code

…ng step waits on (objectui#12482)

The decision panel (`record:approval_decision`), which objectstack's served
`sys_approval_request_detail` page already mounts, draws a "Waiting on" row:
each pending approver named through app-shell's one approver-naming path
(`approverChips` over the row's `pending_approver_names` and
`pending_approver_groups`, and `useApproverDirectory` for a reference the
server left unnamed), with a position's registry label and the countersign
group each slot fills. One person in several quorum slots is one chip with a
count (objectui#12077's case); an id nothing can name keeps the identity
formatter's middle-truncated face, as the inbox's sheet draws it.

No page edit, no spec row, no prop and no export: the panel reads the row it
is bound to. `DecisionProgressIndicator` does not carry the names because it
is drawn only with a tally, and a first_response node has none.

Pins: the panel's own suite, and the served page on the real
RecordDetailView over the console's routed approvals source.

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

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 70 chunks) 3082.5 KB 3119.4 KB
Main entry chunk (gzip) 73.3 KB 350 KB
Entry file index-9NEFK0c1.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.90KB 7.67KB
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.62KB 0.83KB
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.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) 594.75KB 143.42KB
core (index.js) 10.18KB 4.04KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 254.55KB 71.19KB
fields (index.js) 282.89KB 72.11KB
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.67KB 11.85KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.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.94KB 16.05KB
plugin-charts (index.js) 84.97KB 23.36KB
plugin-chatbot (index.js) 201.72KB 48.07KB
plugin-dashboard (index.js) 143.88KB 38.88KB
plugin-designer (index.js) 233.95KB 50.08KB
plugin-detail (index.js) 262.16KB 69.28KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 179.38KB 46.59KB
plugin-gantt (index.js) 178.36KB 45.08KB
plugin-grid (index.js) 261.92KB 72.66KB
plugin-kanban (index.js) 53.23KB 16.71KB
plugin-list (index.js) 127.76KB 32.64KB
plugin-map (index.js) 27.07KB 8.96KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 46.66KB 13.13KB
plugin-timeline (index.js) 39.21KB 11.85KB
plugin-tree (index.js) 15.07KB 5.33KB
plugin-view (index.js) 93.05KB 23.86KB
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.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 (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

Seat ACCEPT: objectui PR #12497 at 233965379b · domain:ui seat 1 · session_01JZnppgHRp4sREcouhkQYDB · 2026-10-15T13:42Z

Verdict: ACCEPT. Reviewed against the claim 6191476739 on objectui#12482, the dev report on that card, and ruling 6190549995 on objectui#12438 (letter C, items 1–3).

No contract-review face applies:

  • Clause-②: no;
  • no type, prop, export, page node or spec row changes;
  • no published schema and no governed path.

The review of record is this seat's reading plus CI.

  • Shape: draft; base main; assignee sunhaolin. Line 1 is Fixes #12482; line 2 is Clause-②: no. 4 files, +625/−7. It merges cleanly with today's main.
  • Fit before build (the ruling's item 2), measured and honoured:
    • The served page already mounts record:approval_decision, a declared type with an empty strict props row. The bound row carries pending_approvers, pending_approver_names and, on a per_group node, pending_approver_groups. So the face is objectui-only: no spec row and no plugin-approvals page edit.
    • DecisionProgressIndicator (A3) stays unchanged, for a measured reason: it draws only with a tally, and a first_response node has none, so it could not name that node's approvers without a contract change.
    • The names reuse app-shell's one approver-naming path: approverChips / approverDisplay / useApproverDirectory, the path the business record's approvals panel already uses. Nothing new is invented, and the block stays product-neutral (ADR-0060 rule 2).
  • Read in the diff:
    • ApprovalDecisionPanel.tsx adds a module-internal PendingApprovers. On a pending request with at least one slot, it draws one chip per approver: the server's name, a position's registry label, the countersign group, and ×N for one person in N quorum slots. The raw slot appears on hover only.
    • The directory is asked only for references the server left unnamed, so a server-named slate costs 0 reads, and a page costs at most 3, never one per approver.
    • The label reuses the existing approvalsInbox.waitingOn key, so no i18n key is added.
  • Pins:
    • 8 panel cells: two same-name people in two groups; three quorum slots → one chip ×3; a position slot's label and holder. CONTROLs: the server name wins, with no directory read; an unnamed id is middle-truncated as the sheet draws it; no pending approvers; a decided request; a first_response node with no tally.
    • Served-page pins: the served page copied whole, on the real RecordDetailView under the console's ApprovalRecordReads. They cover the named approvers with group and position, no pending-approver id in the page text, and objectui#12077's three-slot case.
    • Ablation: dropping the element turned all 10 naming pins red, and the controls stayed green.
    • Union: 47 files and 391 tests passed, plus 18 census files with 696 tests.
  • Deviations accepted:
    • One test-only file outside the claimed surface, apps/console/src/services/approvalRequestsDataSource.servedPageApprovers-12482.test.tsx. The served-page pin must mount the console's routed approvals source; no console production code changed.
    • The base moved to caac3b24ee.
  • The card's acceptance, as the seat reads it:
  • Out of scope, one line each:
    • The submitter's bare id → objectui#12498.
    • The synthesized fallback page's 'More details' prints pending_approvers raw → Acceptance notes. The served page ships with the object in plugin-approvals, so a host with the object has the page.
    • The tally counts slots, not people → Acceptance notes. No contract declares which, and the sheet counts the same way.
    • The chip markup drawn in two app-shell places → carried by the closing card objectui#12484.

Landing: ready and auto-merge once every check on 233965379b is green or an expected skip. Its merge closes objectui#12482 and unblocks face 2, objectui#12483.


Generated by Claude Code

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

Projects

None yet

2 participants