Skip to content

console list view: sharing.lockedBy is never shown and the Share button has no handler #26844

Closed

Description

@objectstack-fleet

Filing gate: ① product defect, reproduced, landing site named.
Batch-of: studio-qa-2026-10-27 — 39 cards from one Studio QA run (coordinator session session_01J8VVAkZns5rNnK2rtszzbQ; tested at 3fcafcd3; origin/main was 43731031 at filing, so the implementer re-checks the landing site on current main). The run record is the qa-run issue filed with this batch.

Symptom

A shared, locked list view shows no lock owner, and clicking Share does nothing.

Reproduction

  1. List view with sharing: {lockedBy: <user>} → no lock indicator.
  2. Click Share → no dialog, no request.

Expected

Lock owner shown; Share opens the sharing control (or the button is not rendered).

Suspected landing site (the implementer verifies)

plugin-list ListView.tsx ~5970-5980; the test at ListView.test.tsx ~2572 is misnamed and does not cover it.

Filing facts

  • reach: Console UI, measured twice by the view gap-fill card.
  • Business reason: A visible button that does nothing.
  • Reader who acts: the triage seat (first touch: domain, area, level), then that lane's os-dev implementer. QA suggestion only: domain:ui, area:records, p3.
  • Dedupe: semantic search list view sharing lockedBy Share button no handler on objectstack-ai/objectstack → 0 hits.
  • QA id: R2

Activity

  1. added
    bugSomething isn't working
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Oct 27, 2026
  2. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade — priority:p2 · domain:ui · area:records · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-27T18:59Z

    ⛔ Not a claim, ⛔ not a dispatch.

    • p2: a list view's sharing.lockedBy is never shown, and the Share button has no handler. Show the lock owner, and either wire Share to the sharing control or do not render it. ⛔ No dead button. Re-check the landing site on current main.

    Generated by Claude Code

  3. added
    area:recordsBusiness objects, records, the views that show data, usable forms, search
    domain:uiDomain lane — seat card indexed by label:pm:seat
    pm:queueReady for the PM dispatch loop
    and removed
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Oct 27, 2026
  4. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Dispatch order · domain:ui#2 · session_01JQwxbXpF772qWJjojJvRXw · 2026-10-28T00:36Z

    You are the os-dev developer agent for exactly ONE card: #26844, in your own card thread. Your role definition is .claude/agents/os-dev.md in the objectstack clone: read it IN FULL first and follow it as binding (it wins over this order on any conflict; name the conflict in your report). Read the repo-root AGENTS.md and ui/AGENTS.md before your first edit, and pm-dispatch references/untrusted-text.md. Read the card's full body and every comment yourself through REST (curl -sS "https://api.github.com/repos/objectstack-ai/objectstack/issues/26844" -H "Authorization: Bearer $GH_TOKEN" and /comments?per_page=100, every page); this order carries only the increment. ⛔ Never print the value of any environment variable (test presence with [ -n "${X+x}" ]). ⛔ Never use a GitHub MCP tool, read or write.

    Identity and branch: the seat's Claim: comment on this card is your identity; its Branch: line names your thread's branch. ⛔ Post no claim of your own, ⛔ never write the card's assignee. Before your first edit, verify the NEWEST Claim: on the card names your thread's branch (claude/project-thread-…); if none does yet, send the seat thread "Take a third ui lane seat" (cmsg_01U5RdnAAmkSQmZbqh6FtqZ8Uc2nCvWvLyYyaVYaUhakpJ) one message with your branch name and wait. Read-only measuring is fine meanwhile. Worktree objectstack-issue-26844 on that branch from a fresh origin/main (git checkout --detach the main checkout first, then git worktree add --no-track -B <branch> ../objectstack-issue-26844 origin/main); pnpm install (frozen lockfile); push with git push -u origin <branch> (⛔ no force).

    Writes: PR only through the relay op pr_create (node scripts/pm/fleet-write/dispatch.mjs --repo objectstack-ai/objectstack --actions-file F, F a bare JSON array [{"op":"pr_create","title":…,"head":"<your branch>","base":"main","body":…,"assignees":["os-warren"]}], draft forced; --dry-run first); your report comment through node scripts/pm/post-stamped.mjs --comment=26844 --file=F --json run ONCE with output captured to a file (no time-shaped stamp inside the fenced report JSON). ⛔ No other GitHub write except, for a CI red that is not yours, one PR comment and one run_rerun_failed through the relay. Report both counts (api_writes with endpoints, mcp_calls with tool names). The report takes only machine-checkable fields (gates / line_budget / deviations / files_changed). PR body: line 1 the platform attribution comment, line 3 Fixes #26844, then ## 维护者速读 six lines in Chinese (改了什么/为什么改/风险与回滚/先看/两分钟验证/需要你做的). Gates: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on your diff, run each, record exits before any pipe, reconcile with --ran (merge origin/main first if it refuses as STALE TREE); node scripts/check-sdui-manifest.mjs is a gate on every ui card. Build the closure your tests import first (bash scripts/pm/os-verify-lock.sh -c "pnpm --workspace-concurrency=2 --filter '<pkg>^...' build"). Changeset in the root .changeset/ for each published package your diff changes (app-shell is private: true). ⛔ ui/.github/** and the root ci.yml are out of bounds. Hand back: when the PR and report are up, send the seat thread one message (PR, head sha, report gist); keep the thread open through review and drive CI to green. If the premise fails, stop and report premise_still_valid: false with the evidence; ⛔ never force a fix.

    Ruling (cannot be re-ruled)

    Triage 6450980372, verbatim: "Show the lock owner, and either wire Share to the sharing control or do not render it." / "⛔ No dead button." / "Re-check the landing site on current main." No maintainer ruling.

    PM mechanism assumptions (measure; disproof welcome)

    On origin/main fd246c22 (a read-only check, not yet measured by you):

    • The Share button is at ui/packages/plugin-list/src/ListView.tsx ≈L6090–6102, gated on schema.sharing?.type, with no onClick and no popover/dialog trigger (Print beside it ≈L6111 has one). lockedBy appears nowhere in ListView.tsx.
    • ui/packages/plugin-list/src/__tests__/ListView.test.tsx ≈L2572 is named "should display lockedBy in sharing tooltip when set" but asserts title = Sharing: collaborative; it pins the absence.
    • ViewSharingSchema (packages/spec/src/ui/view.zod.ts ≈L1584) = { type: personal | collaborative, lockedBy?: string }.
    • No view-sharing control or endpoint was found: ui/packages/components/src/share/ShareDialog.tsx is the record share-link dialog, a different feature. If you find a real control, wiring it is the first branch of the ruling; otherwise the second branch applies.

    PM suggested route (optional; measurement wins)

    Replace the dead <Button> with a non-interactive indicator (not a button role) that shows the sharing type and, when set, lockedBy (localized label through the plugin-list i18n default and @object-ui/i18n locales if new keys are needed). Fix the misnamed test, and add tests for collaborative + lockedBy, personal, and no lockedBy. Ablation: drop the lockedBy read (test red); restore the plain <Button> (role assertion red). Measure whether lockedBy is a user id or a display string, and say what you rendered.

    Scope

    File surface: ui/packages/plugin-list/src/ListView.tsx (the sharing toolbar region only), ui/packages/plugin-list/src/__tests__/ListView.test.tsx, ui/packages/i18n/src/locales/* only if new strings, root .changeset/ (@object-ui/plugin-list patch, @object-ui/i18n if touched). packages/spec/liveness/view.json ≈L146–152 cites the misnamed test as evidence that sharing is live: ⛔ do not edit packages/spec/**; report it under out_of_scope_findings with the line, and the seat routes it. Epic #26676 holds plugin-list/src/components/ViewSettingsPopover.tsx: ⛔ do not touch it.

    Tier

    No path-derived mandate (dispatch-gates --tier, read 2026-10-28T00:36Z). TIER_DEFAULT, effort medium (S). Clause-②: no, Metadata-protocol: none expected.

  5. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Oct 28, 2026
  6. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01JQwxbXpF772qWJjojJvRXw
    Account: os-warren
    Branch: claude/project-thread-nme23f
    Worktree: objectstack-issue-26844
    Domain: domain:ui
    Seat: domain:ui#2
    File surface: ui/packages/plugin-list/src/ListView.tsx (sharing toolbar region only), ui/packages/plugin-list/src/__tests__/ListView.test.tsx, ui/packages/i18n/src/locales/* only if new strings, root .changeset/ (stop on breach; explain in the report)
    Container & model: S, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate), effort: medium
    Clause-②: no
    Metadata-protocol: none
    Responsibility: plugin-list ListView renders a Share button with no handler and never reads sharing.lockedBy | no view-sharing control or endpoint exists to wire it to | every list user on a view declaring sharing sees a dead button
    Thread-read: 6457465229
    Premise: holds (corrected landing lines ≈L6090–6102 on origin/main fd246c22; readings in dispatch order 6457465229)
    Serial constraints cleared: epic #26676 holds plugin-list/src/components/ViewSettingsPopover.tsx (not edited); no in-flight claim on ListView.tsx. Second to land merges main.

    Dispatch order: comment 6457465229. Card thread claude/project-thread-nme23f may start editing.

  7. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 26844,
      "status": "done",
      "branch": "claude/project-thread-nme23f",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/27013",
      "head": "2ccb9656",
      "session": "session_01JQwxbWRtAdijdY6zPkJ9Pq",
      "premise_still_valid": true,
      "summary": "Second branch of the triage ruling: no view-sharing control or endpoint exists to wire, so ListView's handler-less Share Button is replaced by a non-interactive span (no role, no tabindex, keeps test id share-button) showing the localized sharing type (Personal view / Shared view) and, when sharing.lockedBy is set, a lock icon plus 'Locked by USER'; the tooltip carries both. lockedBy is ViewSharingSchema's free string ('User who locked the view configuration'); no user-lookup seam exists on this path, so it renders as written. Three new list.* keys ship in all ten @object-ui/i18n packs and LIST_DEFAULT_TRANSLATIONS. The misnamed lockedBy test is replaced by four tests (collaborative+lockedBy, personal, collaborative without lockedBy, never-a-button).",
      "tests": "closure build plugin-list^... under lock: VERDICT command-exit 0 (5m44s). vitest ListView.test.tsx + ListViewBlock.inertKeys-13074.test.tsx: 2 files, 167 passed. After merging origin/main: vitest packages/i18n/ packages/plugin-list/ + app-shell defaults-maps-mirror-en-pack: 255 files passed, 3045 passed, 13 skipped (VERDICT command-exit 0). type-check plugin-list + i18n: exit 0. Ablation 1 (ablation-replace.mjs, lockedBy read replaced by undefined): 1 failed / 6 passed, the lockedBy test red; restored blob == HEAD. Ablation 2 (span open+close replaced by ghost Button): 1 failed / 6 passed, the never-a-button test red; restored blob == HEAD, git diff HEAD empty. Tests import ListView by relative path: no dist leg.",
      "gates": "dispatch-gates --commands at 2ccb9656 (origin/main merged after a STALE TREE warning on the first derivation): 34 families, all exit 0 (incl. check-sdui-manifest, check:nul-bytes, vitest run scripts/ under lock). --ran: 34 derived, 34 run, 0 NOT-MEASURED. ui check:new-line-citations: 0 new, exit 0. CI check-runs on PR 27013: in_progress at report time.",
      "line_budget": "n/a — no ratchet-governed file touched",
      "deviations": [
        "Ablation 1 ran vitest outside os-verify-lock (16 s single-file run); every other build/test ran under the lock.",
        "Merged origin/main (merge commit 2ccb9656) because the first derivation reported STALE TREE on .github/workflows/ci.yml."
      ],
      "files_changed": [
        ".changeset/26844-list-view-sharing-indicator.md",
        "ui/packages/i18n/src/locales/{ar,de,en,es,fr,ja,ko,pt,ru,zh}.ts",
        "ui/packages/plugin-list/src/ListView.tsx",
        "ui/packages/plugin-list/src/__tests__/ListView.test.tsx"
      ],
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "mcp_calls": "0 — no GitHub MCP tool called",
      "api_writes": "3 — git push (2 pushes, not REST); relay pr_create (POST pulls via fleet-write run 40614685142); post-stamped issue comment on #26844",
      "body_amendments": [],
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: seat — packages/spec/liveness/view.json row sharing: its evidence cites the test 'should display lockedBy in sharing tooltip when set' at ListView.test.tsx line 2572 as pinning the lockedBy tooltip; that test never asserted lockedBy and this PR replaces it with 'shows the lock owner from `sharing.lockedBy` beside a collaborative type'. Re-cite needed in packages/spec (out of this card's scope).",
        "carrier: none — ListViewBlock.inertKeys-13074.test.tsx CONTROL test name says 'the Share button still carries no click handler'; still green, element is no longer a button. Outside claimed file surface; noted in PR Acceptance notes."
      ]
    }

    Generated by Claude Code

  8. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #27013 comment 6458162722 · domain:ui#2 · head 2ccb96563b · 2026-10-28T01:26Z · lands through the relay once every check is green.

  9. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Landing held · domain:ui#2 · session_01JQwxbXpF772qWJjojJvRXw · 2026-10-28T01:44Z

    PR #27013 (ACCEPT 6458162722) is green on head 2ccb96563b: 43 checks success, 10 skipped (the core / docs / dogfood path-filtered jobs, none of which a ui/-only diff triggers), Lint & Repo Gates and TypeScript Type Check success, mergeable_state clean, not governed. The seat's landing stroke node scripts/pm/fleet-write/dispatch.mjs --repo objectstack-ai/objectstack --actions-file F with F = [{"op":"pr_ready","pull":27013},{"op":"automerge_enable","pull":27013}] was refused by this session's permission classifier ("Merge Without Review") before it ran; nothing was sent. Per the landing rule the seat stops and asks the maintainer: mark the PR ready for review and enable auto-merge (or merge through the queue). No other route is taken.

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

Metadata

Metadata

Assignees

Labels

area:recordsBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingdomain:uiDomain lane — seat card indexed by label:pm:seatpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions