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 page v3: an empty body table collapses to one line that reads 「暂无相关记录 偏离 新建」 — the empty text before the table's own title #29944
Filing gate: ① user-visible defect, reproduced in the browser on @objectstack 18.3.0 (hotclm 18.3 upgrade pass; hotclm decision-box batch 11, maintainer 「同意」 2026-11-03T16:16:59Z).
Symptom. hotclm's contract page has six body tables. When one is empty (here 偏离 / Deviations, 0 rows) it is not drawn like its siblings (header row with title, count and 新建 above the table). It collapses to a single bordered line whose text reads, left to right, 「暂无相关记录 偏离 + 新建」: the empty-state sentence first, the table's title after it, in italic grey. Read aloud it says "no related records deviations new". The same happens to the renewals card when it is a body table (「合同 0 暂无相关记录」).
Expected. An empty body table keeps its header (title, 0, 新建) and shows the empty state under it — the shape the non-empty tables and the pre-18.3 record:related_list both draw.
Evidence: /mnt/project-files/hotclm-objectstack-18-3-upgrade/02-detail-counsel-4.png (bottom of the details column). Platform version: 18.3.0.
Read fresh. On 18.3.0, an empty v3 body table collapses to one line, with the empty text before the table's own title (「暂无相关记录 偏离 新建」). Layout only, so p3.
Claim: PM loop round 1 · 2026-11-05T07:29Z
Session: session_01Utp6Cb5R6JDdfyvtj3dPR2 (seat); dev = card thread session_01Utp6CXft9FMzbd2ggz2oyp
Account: os-bill
Branch: claude/project-thread-eh0f41 (harness-pinned card thread branch; the claude/issue-N-slug convention does not apply to a project card thread)
Worktree: objectstack-issue-29944
Domain: domain:ui
Seat: domain:ui#2
File surface: ui/packages/plugin-detail/src/RelatedListEmptyFold.tsx, ui/packages/plugin-detail/src/RelatedList.tsx / the record:related_list renderer only where the fold is wired, their tests, one root .changeset/ (stop on breach; explain in the report)
Container & model: S–M, not mechanical, mode:thread, model: default tier (opus) — dispatch-gates --tier: no path-derived mandate, effort: high
Clause-②: no
Metadata-protocol: none
Responsibility: n/a — UI defect/enhancement in ui/** owned by this lane; no platform path covers it; reached by every console/Studio user
Thread-read: 6610284527
Premise: holds (RelatedListEmptyFold.tsx #25895 stack rule keys on the DOM parent; folded line :304 reads the empty sentence; body-table fold not yet reproduced by the seat, the thread measures first)
Serial constraints cleared: seat 1 #30122 (PR #30342) edits plugin-detail recordTimelineStream.ts and timeline renderers: disjoint, merge main before the PR
{
"issue": 29944,
"status": "done",
"branch": "claude/project-thread-eh0f41",
"pr": "https://github.com/objectstack-ai/objectstack/pull/30378",
"session": "session_01Utp6CXft9FMzbd2ggz2oyp",
"premise_still_valid": true,
"summary": "Measured: the seat's mechanism holds. The record page draws its body tables as siblings in one container (RecordPageColumns drawNodes over the details column; page:tabs for the Details tab), so the #25895 fold, keyed by the DOM parent, took them for a Related tab stack and folded an empty one into its one-line form, empty sentence first. Fix: record-related-list reads RecordBodyTablesContext and a body table (its object.field id in the set, outside the related column) answers foldable: false; RelatedList's card face draws an empty body table's sentence under the header (data-body-table-empty) instead of inline, header keeps title, 0, the enlarge control and New. decideEmptyFold, the Related tab and the related column's empty-panels line are unchanged; no new authoring key.",
"tests": "Head 4b04fd97. New top-level describe in ui/packages/plugin-detail/src/renderers/__tests__/record-related-list.emptyFold-25895.test.tsx (2 cases: body table keeps header with sentence under it; CONTROL Related tab stack under a body-table context still folds). RED on main sources (three source files restored to 13c0c5ba): Tests 1 failed | 7 passed (8), failing on expect(fold()).toBeNull(). GREEN: 119 files (116 plugin-detail files naming RelatedList / record:related_list / related-list / RecordPageColumns / the empty sentence, plus 3 app-shell files asserting the sentence or New): Test Files 118 passed | 1 skipped (119), Tests 1016 passed | 8 skipped (1024), lock VERDICT command-exit 0. ABLATION via scripts/ablation-replace.mjs (tests import src, no build): leg 1 drop !bodyTable from foldable -> red (fold drawn); leg 2 inline sentence back for body tables -> red (sentence in header); leg 3 under-header block off -> red (sentence not found); each restored, blob == HEAD, git diff HEAD empty. A first leg-1 attempt was refused by the tool before running (replacement text already occurred), re-run with a distinct replacement. TYPE-CHECK: pnpm exec turbo run type-check --filter=@object-ui/plugin-detail --concurrency=2, Tasks 52 successful, 52 total, VERDICT command-exit 0. LINT: pnpm lint in ui/packages/plugin-detail exit 0, 0 errors; per-file warnings on the 3 source files equal main's (102/17/1), test file 0.",
"gates": "Local derived set on head 4b04fd97 (dispatch-gates --commands, 5 paths vs merge base 8589756a): 35 commands, all exit 0, captured before any pipe (list: /mnt/project-files/ui-seat2/29944-gates-ran.txt and the PR body). dispatch-gates --ran: 'Run reconciliation — 35 derived, 35 run, 0 NOT-MEASURED, 0 UNRUN' (derived zero, all 35 carry an exit code). check-sdui-manifest: present and intact, 106 components (in the derived set). ui check:new-line-citations: 0 new citation(s), exit 0. CI check-runs on #30378: in_progress at report time, not awaited (os-dev.md).",
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
"line_budget": "108 insertions, 10 deletions across 5 files (diff vs origin/main merge base)",
"files_changed": [
".changeset/29944-body-table-empty-keeps-header.md",
"ui/packages/plugin-detail/src/RelatedList.tsx",
"ui/packages/plugin-detail/src/RelatedListEmptyFold.tsx",
"ui/packages/plugin-detail/src/renderers/record-related-list.tsx",
"ui/packages/plugin-detail/src/renderers/__tests__/record-related-list.emptyFold-25895.test.tsx"
],
"deviations": [
"Expected wording: the card says the empty state goes under the header, 'the shape ... the pre-18.3 record:related_list' draws. Measured on published @object-ui/plugin-detail@18.2.0: the pre-18.3 empty card wrote the sentence INLINE in its header row. Followed the under-the-header half for body tables only; every other list keeps the inline sentence. Stated in the PR's Acceptance notes.",
"Card header gained a data-related-list-head attribute (test hook, mirrors the panel face's data-related-panel-head).",
"Commit trailer pair is model-free per AGENTS.md; the harness asked for a model-named Co-Authored-By, not used."
],
"mcp_calls": "3 — mcp__github__issue_read (get) x1, mcp__github__issue_read (get_comments) x2; no write tool",
"api_writes": "2 — repository_dispatch to the fleet-write relay for pr_create (#30378, draft, no assignees, no labels); this os-dev-report comment via post-stamped. git push x3 (not REST).",
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": []
}
Landed · 2026-11-05T11:48Z · PR #30378 merged as 346142015 through the merge queue (seat ACCEPT on the merged head; landing authorized by the maintainer in the seat thread, 11:29Z). Card state: closed. pm:dispatched removed.
Activity
objectstack-fleet commentedon Nov 3, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: first-touch audit · p3 ·
domain:ui·pm:queue· 2026-11-03T16:59Z⛔ Not a claim.
Generated by Claude Code
objectstack-fleet commentedon Nov 5, 2026
domain:ui#2 · os-bill · session_01Utp6Cb5R6JDdfyvtj3dPR2
Claim: PM loop round 1 · 2026-11-05T07:29Z
Session:
session_01Utp6Cb5R6JDdfyvtj3dPR2(seat); dev = card threadsession_01Utp6CXft9FMzbd2ggz2oypAccount:
os-billBranch:
claude/project-thread-eh0f41(harness-pinned card thread branch; theclaude/issue-N-slugconvention does not apply to a project card thread)Worktree:
objectstack-issue-29944Domain:
domain:uiSeat:
domain:ui#2File surface:
ui/packages/plugin-detail/src/RelatedListEmptyFold.tsx,ui/packages/plugin-detail/src/RelatedList.tsx/ therecord:related_listrenderer only where the fold is wired, their tests, one root.changeset/(stop on breach; explain in the report)Container & model:
S–M, not mechanical,mode:thread,model: default tier (opus) — dispatch-gates --tier: no path-derived mandate,effort: highClause-②: no
Metadata-protocol: none
Responsibility:
n/a — UI defect/enhancement in ui/** owned by this lane; no platform path covers it; reached by every console/Studio userThread-read: 6610284527
Premise: holds (RelatedListEmptyFold.tsx #25895 stack rule keys on the DOM parent; folded line :304 reads the empty sentence; body-table fold not yet reproduced by the seat, the thread measures first)
Serial constraints cleared: seat 1 #30122 (PR #30342) edits plugin-detail recordTimelineStream.ts and timeline renderers: disjoint, merge main before the PR
Dispatch order:
/mnt/project-files/ui-seat2/dispatch-29944.md(project files).objectstack-fleet commentedon Nov 5, 2026
domain:ui#2 · os-bill · session_01Utp6Cb5R6JDdfyvtj3dPR2
os-dev-report
{ "issue": 29944, "status": "done", "branch": "claude/project-thread-eh0f41", "pr": "https://github.com/objectstack-ai/objectstack/pull/30378", "session": "session_01Utp6CXft9FMzbd2ggz2oyp", "premise_still_valid": true, "summary": "Measured: the seat's mechanism holds. The record page draws its body tables as siblings in one container (RecordPageColumns drawNodes over the details column; page:tabs for the Details tab), so the #25895 fold, keyed by the DOM parent, took them for a Related tab stack and folded an empty one into its one-line form, empty sentence first. Fix: record-related-list reads RecordBodyTablesContext and a body table (its object.field id in the set, outside the related column) answers foldable: false; RelatedList's card face draws an empty body table's sentence under the header (data-body-table-empty) instead of inline, header keeps title, 0, the enlarge control and New. decideEmptyFold, the Related tab and the related column's empty-panels line are unchanged; no new authoring key.", "tests": "Head 4b04fd97. New top-level describe in ui/packages/plugin-detail/src/renderers/__tests__/record-related-list.emptyFold-25895.test.tsx (2 cases: body table keeps header with sentence under it; CONTROL Related tab stack under a body-table context still folds). RED on main sources (three source files restored to 13c0c5ba): Tests 1 failed | 7 passed (8), failing on expect(fold()).toBeNull(). GREEN: 119 files (116 plugin-detail files naming RelatedList / record:related_list / related-list / RecordPageColumns / the empty sentence, plus 3 app-shell files asserting the sentence or New): Test Files 118 passed | 1 skipped (119), Tests 1016 passed | 8 skipped (1024), lock VERDICT command-exit 0. ABLATION via scripts/ablation-replace.mjs (tests import src, no build): leg 1 drop !bodyTable from foldable -> red (fold drawn); leg 2 inline sentence back for body tables -> red (sentence in header); leg 3 under-header block off -> red (sentence not found); each restored, blob == HEAD, git diff HEAD empty. A first leg-1 attempt was refused by the tool before running (replacement text already occurred), re-run with a distinct replacement. TYPE-CHECK: pnpm exec turbo run type-check --filter=@object-ui/plugin-detail --concurrency=2, Tasks 52 successful, 52 total, VERDICT command-exit 0. LINT: pnpm lint in ui/packages/plugin-detail exit 0, 0 errors; per-file warnings on the 3 source files equal main's (102/17/1), test file 0.", "gates": "Local derived set on head 4b04fd97 (dispatch-gates --commands, 5 paths vs merge base 8589756a): 35 commands, all exit 0, captured before any pipe (list: /mnt/project-files/ui-seat2/29944-gates-ran.txt and the PR body). dispatch-gates --ran: 'Run reconciliation — 35 derived, 35 run, 0 NOT-MEASURED, 0 UNRUN' (derived zero, all 35 carry an exit code). check-sdui-manifest: present and intact, 106 components (in the derived set). ui check:new-line-citations: 0 new citation(s), exit 0. CI check-runs on #30378: in_progress at report time, not awaited (os-dev.md).", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "line_budget": "108 insertions, 10 deletions across 5 files (diff vs origin/main merge base)", "files_changed": [ ".changeset/29944-body-table-empty-keeps-header.md", "ui/packages/plugin-detail/src/RelatedList.tsx", "ui/packages/plugin-detail/src/RelatedListEmptyFold.tsx", "ui/packages/plugin-detail/src/renderers/record-related-list.tsx", "ui/packages/plugin-detail/src/renderers/__tests__/record-related-list.emptyFold-25895.test.tsx" ], "deviations": [ "Expected wording: the card says the empty state goes under the header, 'the shape ... the pre-18.3 record:related_list' draws. Measured on published @object-ui/plugin-detail@18.2.0: the pre-18.3 empty card wrote the sentence INLINE in its header row. Followed the under-the-header half for body tables only; every other list keeps the inline sentence. Stated in the PR's Acceptance notes.", "Card header gained a data-related-list-head attribute (test hook, mirrors the panel face's data-related-panel-head).", "Commit trailer pair is model-free per AGENTS.md; the harness asked for a model-named Co-Authored-By, not used." ], "mcp_calls": "3 — mcp__github__issue_read (get) x1, mcp__github__issue_read (get_comments) x2; no write tool", "api_writes": "2 — repository_dispatch to the fleet-write relay for pr_create (#30378, draft, no assignees, no labels); this os-dev-report comment via post-stamped. git push x3 (not REST).", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [] }objectstack-fleet commentedon Nov 5, 2026
domain:ui#2 · os-bill · session_01Utp6Cb5R6JDdfyvtj3dPR2
Landed · 2026-11-05T11:48Z · PR #30378 merged as
346142015through the merge queue (seat ACCEPT on the merged head; landing authorized by the maintainer in the seat thread, 11:29Z). Card state:closed.pm:dispatchedremoved.