You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Record discussion: the header shows a comment count of 0 above "You don't have permission to view comments" #27820
Filing gate: ③ triage-directed split. Triage on #27520 (6495077487) said: 「Each row is either taken, with its own card where it needs code」. This card is row 2.
Business reason: a member who may not read a record's comments sees Discussion (0) right above the refusal. The count states something the member cannot know and the server did not say: that there are no comments. They may conclude nobody has discussed the record, when the discussion is only hidden from them.
Reader who acts: domain:ui (@object-ui/plugin-detail, the record page's discussion panel).
Duplicate search: search_issues "Discussion count shown when comments cannot be read permission" → #27703 (mention picker, row 1 of the same parent; a different defect), #24864 and #19607 (closed, unrelated). New.
What happens (row 2 of #27520, 18.3.0 RC walkthrough at c4c515ad)
Member, desktop, Projects → Website Relaunch, a record whose comments the member may not read. The header reads Discussion (0) directly above "You don't have permission to view comments on this record."
Mechanism (read on origin/main, not reproduced here)
The refusal line is detail.commentsAccessDenied in ui/packages/plugin-detail/src/RecordActivityTimeline.tsx ~L356.
The Discussion title is drawn in RecordChatterPanel.tsx (~L165, ~L232) and DetailView.tsx (~L2025). The count that sits beside it is computed from the loaded comment list, which is empty when the read is refused. Measure which one draws (0) on the record page.
Expected
When the comments cannot be read, the header shows no count: just Discussion, or the same header the panel draws with no count. When the comments can be read, the count is unchanged, including (0) for a readable record that has none.
Acceptance
One measured repro on current main first, naming the component that draws the count.
A test with a refused comment read: the header shows no count and the refusal line still shows.
Controls: a readable record with 0 comments shows (0); one with 3 shows (3).
Claim: PM loop round 1
Session: session_01Utp6CbDAucNyQ4UtzCJKyh
Account: os-bill
Branch: claude/project-thread-prnv6p (the card thread's designated push branch, the recorded platform exception to claude/issue-<n>-<slug>)
Worktree: objectstack-issue-27820
Domain: domain:ui
Seat: domain:ui#4
File surface: ui/packages/plugin-detail/src/ (the component that draws the discussion count and the panel that knows the comment read was refused), tests beside, root .changeset/; ⛔ RecordDetailView.tsxapiHandler (in-flight PR #27793) (stop on breach; explain in the report)
Container & model: S, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier on 2a0b37bb: no path-derived mandate), effort: medium
Clause-②: no
Metadata-protocol: none
Responsibility: when the comment read is refused the discussion header shows no count, the refusal line stays; readable records keep their count incl. (0); pinned with controls and an ablation
Thread-read: none
Premise: holds
Serial constraints cleared: none — #27793 touches RecordDetailView apiHandler only (excluded)
Dispatched 2026-10-30T00:50Z to a card thread of the seat's project; the order lives in the project. ⛔ The thread posts no claim and writes no assignee.
{
"issue": 27820,
"status": "done",
"branch": "claude/project-thread-prnv6p",
"pr": "https://github.com/objectstack-ai/objectstack/pull/27844",
"head": "64fcb00fadcfe52ef2c4639506055d2654a26fc9",
"session": "session_01Utp6Cagj5WeiH9xGApkpYm (card thread; seat session_01Utp6CbDAucNyQ4UtzCJKyh)",
"premise_still_valid": true,
"summary": "Measured on main 359e935d: the (0) is RecordActivityTimeline's heading count (filtered.length), mounted by RecordChatterPanel with the Discussion title on both paths; DetailView's tab draws no count. The heading now draws the count only when neither activityDenied nor commentsDenied is set (the existing host signal that draws the refusal line, no new permission check), and RecordChatterPanel's collapsed toggle reads the existing detail.openDiscussion key instead of 'Show Discussion (0)' under the same condition. Readable feeds keep their count, (0) included.",
"tests": "pnpm --dir ui exec vitest run --reporter=verbose packages/plugin-detail/ under os-verify-lock: VERDICT command-exit 0, Test Files 339 passed / 1 skipped, Tests 3085 passed / 18 skipped (on 97c4beb7; 64fcb00f changes only the new test's item type). pnpm --filter @object-ui/plugin-detail run type-check: exit 0 at 64fcb00f; new file 7/7. Ablation: fix committed, both src files restored to 359e935d (activity-count marker 1->0, showLabel 3->0 on disk), new file: exit 1, 4 failed / 3 passed (refused cases red: expected 'Discussion(0)' to be 'Discussion'; controls green); restored via git checkout HEAD, git diff HEAD empty.",
"gates": "local: dispatch-gates --commands derived 34 at 64fcb00f, all 34 exit 0 (incl. node scripts/check-sdui-manifest.mjs); --ran reconciliation: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. ui pnpm check:new-line-citations: 0 new. CI check-runs on 64fcb00f at report time: in_progress (Check Changeset, Lint x9, Type Check x4, Governed Surface Queue Guard, PR-body guards); opt-in jobs skipped.",
"line_budget": "4 files, +155 / -5 (under the 3000 human-merge threshold)",
"files_changed": [
".changeset/27820-discussion-count-refused-read.md",
"ui/packages/plugin-detail/src/RecordActivityTimeline.tsx",
"ui/packages/plugin-detail/src/RecordChatterPanel.tsx",
"ui/packages/plugin-detail/src/__tests__/RecordChatterPanel.refusedReadCount-27820.test.tsx"
],
"deviations": [
"Bounded in-place fix, same class, same files: a refused ACTIVITY read also withholds the count, and the collapsed toggle drops its (0) via the existing detail.openDiscussion key; Clause-② stays no, no i18n key added. Declared in the PR's Acceptance notes.",
"Harness after-PR assignee/reviewer step skipped per the order (no assignees, no review request).",
"Harness attribution reminder asks for a model-named Co-Authored-By trailer; commits carry the model-free pair per AGENTS.md instead."
],
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"mcp_calls": "0 GitHub MCP calls",
"api_writes": "2 — relay pr_create (POST pulls, #27844); this report comment via post-stamped (POST issues/27820/comments)",
"open_questions": [],
"out_of_scope_findings": []
}
Activity
objectstack-fleet commentedon Oct 30, 2026
domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh
Claim: PM loop round 1
Session:
session_01Utp6CbDAucNyQ4UtzCJKyhAccount:
os-billBranch:
claude/project-thread-prnv6p(the card thread's designated push branch, the recorded platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-27820Domain:
domain:uiSeat:
domain:ui#4File surface:
ui/packages/plugin-detail/src/(the component that draws the discussion count and the panel that knows the comment read was refused), tests beside, root.changeset/; ⛔RecordDetailView.tsxapiHandler(in-flight PR #27793) (stop on breach; explain in the report)Container & model:
S,mode:thread,model: TIER_DEFAULT(dispatch-gates --tieron2a0b37bb: no path-derived mandate),effort: mediumClause-②: no
Metadata-protocol: none
Responsibility: when the comment read is refused the discussion header shows no count, the refusal line stays; readable records keep their count incl. (0); pinned with controls and an ablation
Thread-read: none
Premise: holds
Serial constraints cleared: none — #27793 touches RecordDetailView apiHandler only (excluded)
Dispatched 2026-10-30T00:50Z to a card thread of the seat's project; the order lives in the project. ⛔ The thread posts no claim and writes no assignee.
Generated by Claude Code
objectstack-fleet commentedon Oct 30, 2026
domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh
os-dev-report
{ "issue": 27820, "status": "done", "branch": "claude/project-thread-prnv6p", "pr": "https://github.com/objectstack-ai/objectstack/pull/27844", "head": "64fcb00fadcfe52ef2c4639506055d2654a26fc9", "session": "session_01Utp6Cagj5WeiH9xGApkpYm (card thread; seat session_01Utp6CbDAucNyQ4UtzCJKyh)", "premise_still_valid": true, "summary": "Measured on main 359e935d: the (0) is RecordActivityTimeline's heading count (filtered.length), mounted by RecordChatterPanel with the Discussion title on both paths; DetailView's tab draws no count. The heading now draws the count only when neither activityDenied nor commentsDenied is set (the existing host signal that draws the refusal line, no new permission check), and RecordChatterPanel's collapsed toggle reads the existing detail.openDiscussion key instead of 'Show Discussion (0)' under the same condition. Readable feeds keep their count, (0) included.", "tests": "pnpm --dir ui exec vitest run --reporter=verbose packages/plugin-detail/ under os-verify-lock: VERDICT command-exit 0, Test Files 339 passed / 1 skipped, Tests 3085 passed / 18 skipped (on 97c4beb7; 64fcb00f changes only the new test's item type). pnpm --filter @object-ui/plugin-detail run type-check: exit 0 at 64fcb00f; new file 7/7. Ablation: fix committed, both src files restored to 359e935d (activity-count marker 1->0, showLabel 3->0 on disk), new file: exit 1, 4 failed / 3 passed (refused cases red: expected 'Discussion(0)' to be 'Discussion'; controls green); restored via git checkout HEAD, git diff HEAD empty.", "gates": "local: dispatch-gates --commands derived 34 at 64fcb00f, all 34 exit 0 (incl. node scripts/check-sdui-manifest.mjs); --ran reconciliation: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. ui pnpm check:new-line-citations: 0 new. CI check-runs on 64fcb00f at report time: in_progress (Check Changeset, Lint x9, Type Check x4, Governed Surface Queue Guard, PR-body guards); opt-in jobs skipped.", "line_budget": "4 files, +155 / -5 (under the 3000 human-merge threshold)", "files_changed": [ ".changeset/27820-discussion-count-refused-read.md", "ui/packages/plugin-detail/src/RecordActivityTimeline.tsx", "ui/packages/plugin-detail/src/RecordChatterPanel.tsx", "ui/packages/plugin-detail/src/__tests__/RecordChatterPanel.refusedReadCount-27820.test.tsx" ], "deviations": [ "Bounded in-place fix, same class, same files: a refused ACTIVITY read also withholds the count, and the collapsed toggle drops its (0) via the existing detail.openDiscussion key; Clause-② stays no, no i18n key added. Declared in the PR's Acceptance notes.", "Harness after-PR assignee/reviewer step skipped per the order (no assignees, no review request).", "Harness attribution reminder asks for a model-named Co-Authored-By trailer; commits carry the model-free pair per AGENTS.md instead." ], "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm", "mcp_calls": "0 GitHub MCP calls", "api_writes": "2 — relay pr_create (POST pulls, #27844); this report comment via post-stamped (POST issues/27820/comments)", "open_questions": [], "out_of_scope_findings": [] }Report taken 2026-10-30T01:44Z.
objectstack-fleet commentedon Oct 30, 2026
domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh
ACCEPT → PR #27844 comment 6513071997 · 2026-10-30T01:58Z
Generated by Claude Code