Skip to content

approvals: a principal holding N of a step's approver slots — the chip's ×N and the eligible-approver count need the copy that reconciles them #27615

Closed

Description

@objectstack-fleet

domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh

Filing gate: ① user-visible UX defect, an out-of-scope finding of the in-flight #27502 (card thread report 6499712026), filed by the seat as ruling 6499914328 item 7 directs (domain:ui · area:workflow · S). Not part of #27502's PR.

Business reason

Who: every approver (and submitter) reading a pending approval whose step lets one person hold several approver slots. What happens today: on the approval request page, before the decision, the pending step reads Waiting on Dev Admin ×3 beside "1 eligible approver", with nothing explaining the ×3 (found in the 18.3.0 RC walkthrough, #27377 W3-UX, on #27502). Both numbers are correct readings of the request row, but side by side they look contradictory, and a reader cannot tell whether one person or three must still act.

Where (read at origin/main)

  • ui/packages/app-shell/src/views/RecordApprovalsPanel.tsx approverChips (~L147): collapses the slots one principal holds into one chip with a ×N count. The same function draws the business record's approvals panel.
  • ui/packages/app-shell/src/views/approval-progress/eligibleApprovers.ts eligibleApproverCount (~L33, objectui#12781): counts distinct principals; RecordApprovalsPanel.tsx ~L398 reads it.
  • Why the stock walkthrough always shows it: examples/app-showcase/src/security/seed-approval-demo.ts (header, ~L10–37) routes the committee node to the positions manager / finance / legal and assigns the dev-seeded admin to all three.

Acceptance

  • When one principal holds several of a step's slots, the chip and the eligible count read as one story (e.g. the chip names what the ×N counts, or the count line says the person holds N slots); the wording is this card's to decide.
  • No new widget, dialog or hook: copy on the existing chip / count line, in the ui language packs, pinned by a test on a principal holding several slots.

Reader who acts

The domain:ui seat whose area holds approval pages (seat 4, #26620) or the one triage names.

reach

Public door: the console approval request page for the showcase EXP-DEMO request ("High-Value Expense — Committee Quorum") signed in as the seeded admin (repro steps on #27502).

Dedupe

Search API is unavailable from this session; read instead: the 500 most recently created issues (open and closed) by title, grep eligible approver|approver slot|×[0-9N]|chip.*count|approverChips → 0 hits. No duplicate.

Links back: #27502


Generated by Claude Code

Activity

  1. added
    bugSomething isn't working
    area:workflowApprovals and automation — the work that runs without a person driving it
    on Oct 29, 2026
  2. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: 审批与自动化 | none | P②

    Triage: p2 · domain:ui · area:workflow · 2026-10-29T15:16Z

    ⛔ Not a claim.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh

    Claim: PM loop round 1
    Session: session_01Utp6CbDAucNyQ4UtzCJKyh
    Account: os-bill
    Branch: claude/project-thread-j9w213 (this seat thread's designated push branch for its in-seat subagent dev, the recorded platform exception to claude/issue-<n>-<slug>)
    Worktree: objectstack-issue-27615
    Domain: domain:ui
    Seat: domain:ui#4
    File surface: ui/packages/app-shell/src/views/RecordApprovalsPanel.tsx (chip copy only), ui/packages/app-shell/src/views/approval-decision/ApprovalDecisionPanel.tsx (chip copy only), ui/packages/app-shell/src/views/approval-progress/DecisionProgressIndicator.tsx (count line copy only), ui/packages/i18n/src/locales/* (the approvals copy keys, all packs), tests beside, root .changeset/ (stop on breach; explain in the report)
    Container & model: S, mode:subagent, model: TIER_DEFAULT (dispatch-gates --tier on 50d05cb1: no path-derived mandate), effort: medium
    Clause-②: yes (widening) — expected: the reconciling copy is a new key in the published @object-ui/i18n packs (lane rule, precedent #25908/#27480); the seat owes a TIER_DEFAULT declaration review before landing. If the change only edits existing values, the dev reports it and the seat amends to no.
    Metadata-protocol: none
    Responsibility: make the ×N chip and the "N eligible approver(s)" line read as one story when one principal holds several slots of a step; copy only, no new widget/dialog/hook; pinned by a test on a principal holding several slots
    Thread-read: 6500636553
    Premise: holds
    Serial constraints cleared: #27502 (PR #27635) merged 16:13Z, the serial constraint triage named; no open PR touches the surface (read 18:3xZ)

    Dispatched 2026-10-29T18:24Z to an in-seat subagent of the seat thread (S). ⛔ The subagent posts no claim and writes no assignee.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh

    os-dev-report

    Reported 2026-10-29T19:26Z.

    {
      "issue": 27615,
      "status": "done",
      "branch": "claude/project-thread-j9w213",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/27699",
      "pr_number": 27699,
      "head_sha": "0f72297edaa4feececc50a7a1c7077d531cc36f5",
      "session": "session_01Utp6CbDAucNyQ4UtzCJKyh",
      "premise_still_valid": true,
      "i18n_key_added": true,
      "clause_2": "yes (widening): new count family approvalsInbox.approverSlots in all ten @object-ui/i18n packs; no existing value edited",
      "summary": "The pending-approver chip on the record approvals panel and on the approval request page drew a bare xN when one principal holds several slots, beside an eligible-approver count that counts that person once. It now draws the pack's words (en 'holds 3 approver slots', zh '兼任 3 个审批席位') from a new count family approvalsInbox.approverSlots, added to all ten packs with each language's plural categories (same set as progressEligible). Neither count changes; no widget, dialog or hook. Mechanism assumptions measured and held: approverChips collapses by (label, detail, group); both panels rendered the bare count; eligibleApproverCount counts distinct addresses.",
      "tests": "On merged head 0f72297e: pnpm --dir ui exec vitest run --maxWorkers=2 packages/app-shell/src/views/RecordApprovalsPanel packages/app-shell/src/views/approval-decision/ packages/app-shell/src/views/approval-progress/ packages/i18n/ -> Test Files 106 passed (106), Tests 1499 passed | 13 skipped (1512), lock VERDICT command-exit 0. New pins: 2 cases in RecordApprovalsPanel.eligibleApprovers-12781.test.tsx, 3 in ApprovalDecisionPanel.eligibleApprovers-12781.test.tsx (incl. zh), run verbose and passing. Two existing assertions moved from the bare count to the family's base row. Ablation per panel via scripts/ablation-replace.mjs (old xN render restored on the committed file): RecordApprovalsPanel 2 failed | 4 passed, ApprovalDecisionPanel 3 failed | 4 passed; both restores proven blob == HEAD and git diff HEAD empty. Type-check: pnpm turbo run type-check --filter=@object-ui/app-shell --filter=@object-ui/i18n on 0f72297e -> 65/65 tasks successful, lock VERDICT command-exit 0 (both tsc programs per package).",
      "gates": "Local, on 0f72297e: dispatch-gates --commands --repo objectstack-ai/objectstack derived 34 commands (list identical before and after the main merge); each run with exit captured before any pipe, all 34 exit 0, including node scripts/check-sdui-manifest.mjs :: exit 0, node scripts/check-sdui-manifest.mjs --self-test :: exit 0, pnpm --dir ui exec vitest run scripts/ :: exit 0 (169 files passed). Reconciliation dispatch-gates --ran: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. Outside the derived list: pnpm check:changeset-fixed :: exit 0; ui check:i18n-keys :: exit 0, check:i18n-drift :: exit 0, check:i18n-dead-keys :: exit 0, check:new-line-citations :: exit 0 (these four on 76839d57, pre-merge). CI on PR head 0f72297e at report time: 15 completed (success/skipped), 18 in_progress; not awaited per os-dev.",
      "line_budget": "17 files, +188 / -5 vs origin/main after merge (dispatch-gates human-merge threshold 3000: under)",
      "files_changed": [
        ".changeset/27615-approver-slots-chip.md",
        "ui/packages/app-shell/src/views/RecordApprovalsPanel.tsx",
        "ui/packages/app-shell/src/views/RecordApprovalsPanel.test.tsx",
        "ui/packages/app-shell/src/views/RecordApprovalsPanel.eligibleApprovers-12781.test.tsx",
        "ui/packages/app-shell/src/views/approval-decision/ApprovalDecisionPanel.tsx",
        "ui/packages/app-shell/src/views/approval-decision/ApprovalDecisionPanel.test.tsx",
        "ui/packages/app-shell/src/views/approval-decision/ApprovalDecisionPanel.eligibleApprovers-12781.test.tsx",
        "ui/packages/i18n/src/locales/{en,zh,ja,ko,de,fr,es,pt,ru,ar}.ts"
      ],
      "deviations": [
        "Test scope narrowed as the seat directed: approvals views (RecordApprovalsPanel*, approval-decision/, approval-progress/) plus the whole ui/packages/i18n suite; the full @object-ui/app-shell vitest suite is CI's (Test UI).",
        "File surface: two existing test files beside the panels (RecordApprovalsPanel.test.tsx, ApprovalDecisionPanel.test.tsx) were edited because they asserted the bare count; covered by the claim's 'tests beside'. DecisionProgressIndicator.tsx was not changed: the count line keeps its copy, the chip carries the reconciling words.",
        "Conflict named, dispatch followed: os-dev says the PR body's first line is Fixes #n and bans dev-written HTML comments; the dispatch (and seat precedent PR 27653) puts the seat signature first and the claude-projects attribution comment on line 2. Treated as the platform-attribution exception; stored body read back identical (8709 bytes). The report comment likewise leads with the signature line (post-stamped's requirement), with os-dev-report on its own line after it.",
        "Commit trailers use the AGENTS.md model-free pair (Claude-Session + Co-authored-by: Claude), not the harness reminder's model-named Co-Authored-By.",
        "A mistyped background command wrote two empty files outside the repo, /cmds2.txt and /ran2.txt; their removal was refused by a safety check, so they are left for a person to delete.",
        "One extra gate rerun: the derived list was run once on 76839d57 and again in full on the merged head 0f72297e; the report cites the merged-head run."
      ],
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "mcp_calls": "0",
      "api_writes": "2 — POST /repos/objectstack-ai/objectstack/dispatches (fleet-write relay, op pr_create -> PR 27699, draft, no assignees, no reviewers); POST /repos/objectstack-ai/objectstack/issues/27615/comments (this report, via post-stamped). git push is not a REST write.",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: none · noted, not filed — approverChips keys a chip by (label, detail, group), so two distinct addresses that resolve to one identical name with no group also collapse into one chip with a count beside an eligible count of 2; pre-existing, read-only inference, not reproduced; in the PR's Acceptance notes."
      ]
    }
  5. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh

    os-dev-report

    Rework delta, reported 2026-10-29T19:47Z.

    {
      "issue": 27615,
      "status": "done",
      "round": "rework 1 (CI Test UI 16/16 red on 0f72297e)",
      "branch": "claude/project-thread-j9w213",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/27699",
      "head_sha": "5f52f80c",
      "session": "session_01Utp6CbDAucNyQ4UtzCJKyh",
      "summary": "The console served-page test still pinned the bare count ('Ada Lovelace×3'). It now expects the en pack's approverSlots plural row at 3 and also asserts no '×3' on the page; the case keeps its intent (named once, with a count, id printed nowhere). A grep of ui/ (apps, packages, e2e; tests and source) for approver-chip ×N pins found no other one: the remaining × hits are comments, unrelated widgets (InboxPopover notification groups, chatbot steps, designer sizes) or this PR's own negative assertions.",
      "tests": "On 5f52f80c: pnpm --dir ui exec vitest run --maxWorkers=2 apps/console/src/services/approvalRequestsDataSource.servedPageApprovers-12482.test.tsx packages/app-shell/src/views/RecordApprovalsPanel packages/app-shell/src/views/approval-decision/ packages/app-shell/src/views/approval-progress/ packages/i18n/ -> Test Files 107 passed (107), Tests 1506 passed | 13 skipped (1519), lock VERDICT command-exit 0. Type-check: pnpm turbo run type-check --filter=@object-ui/console -> 70/70 tasks successful, lock VERDICT command-exit 0 (console tsconfig includes src, so the test file is compiled).",
      "gates": "dispatch-gates --commands on 5f52f80c derives the same 34-command list as on 0f72297e. Rerun on 5f52f80c for the changed test file: pnpm check:cross-package-test-inputs :: exit 0, pnpm check:test-source-alias :: exit 0, pnpm check:nul-bytes :: exit 0, pnpm check:undeclared-dep-imports :: exit 0, ui check:new-line-citations :: exit 0. The other derived families are unaffected by a test-only edit and were green on 0f72297e. CI on 5f52f80c not awaited.",
      "files_changed": [
        "ui/apps/console/src/services/approvalRequestsDataSource.servedPageApprovers-12482.test.tsx"
      ],
      "deviations": [
        "New head 5f52f80c (fast-forward push on top of 0f72297e, no force).",
        "File surface widened, with the seat's approval: ui/apps/console/src/services/approvalRequestsDataSource.servedPageApprovers-12482.test.tsx (@object-ui/console), a test that pinned the old bare count. It is the same class as the two app-shell tests already moved.",
        "The first round's local scope (approvals views + i18n) missed this console pin: the narrowed run did not include ui/apps/console."
      ],
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "mcp_calls": "0",
      "api_writes": "1 — POST /repos/objectstack-ai/objectstack/issues/27615/comments (this delta report, via post-stamped). git push is not a REST write.",
      "open_questions": [],
      "out_of_scope_findings": []
    }
  6. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh

    ACCEPT → PR #27699 comment 6506973363 · 2026-10-29T19:59Z


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Labels

area:workflowApprovals and automation — the work that runs without a person driving itbugSomething isn't workingdomain:uipm:dispatchedpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions