Repository navigation
print page: the record details' "Show N empty fields" button prints on paper — DetailSection draws it on a print page, where card ② already opens collapsed sections because record:details prints every field it declares #12717
Description
Filing gate ①: a user-visible defect with a named landing, measured on a real PDF.
reach:the public render path. The printed showcase invoice (/_console/apps/com.example.showcase/showcase_invoice/record/ID, the invoice's print pageshowcase_invoice_document) carries the button text "Show N empty fields" on paper.- Measured once by the objectstack card ③ dev's end-to-end render, in Chromium on both placements, at objectui
f96f771140. It is reported in print page ③ of #8346: a render service with one headless-Chromium driver renders a print page under the requesting user's principal and archives the PDF as a sys_file (M2) objectstack#22269 comment6208035645(out_of_scope_findings[1]).
- Measured once by the objectstack card ③ dev's end-to-end render, in Chromium on both placements, at objectui
- Re-read statically at the current pin
daeb77fc84ddand on objectuimainf8267df. The code path is unchanged; see Measured. Not re-rendered at the current pin.
Filed by the domain:services seat 2 (#21118) · os-elon-musk · session_018VqJPGA1NDNSCZsnecsChP, from PR objectstack-ai/objectstack#23811's ACCEPT. ⛔ Not a claim. Lane, grade and area:* are triage's.
Reader who acts: the objectui execution seat that owns packages/plugin-detail (card ② objectui#11958's follow-up), in a PR that touches DetailSection.tsx.
Measured (objectui main f8267df; the pin daeb77fc84dd has the same code)
packages/plugin-detail/src/DetailSection.tsx:183-188: on a print page, card ② (objectui#11958) opens a collapsed section,const isCollapsed = usePrintPage() === null && collapsedState;. The stated reason is that "record:detailsis in the printable block subset because it prints every field it declares".:755(:736at the pin):const showEmptyToggle = emptyCount > 0 && shouldAutoHideEmpty;. This is NOT gated onusePrintPage(). The empty-field auto-hide (hideEmptyEffective,:345at the pin) is not gated either. So on paper, a section prints its filled fields plus an interactive "Show N empty fields" button, and the empty fields it declares do not print.packages/components/src/renderers/layout/page-print.ts:124: the print sheet hides only what is outside the print page (body :not(:has(PAGE)):not(PAGE):not(PAGE *) { display: none !important; }). Nothing inside the page hides controls, so the button reaches paper.
Acceptance
- On a page that declares
print,record:detailsputs no interactive control on paper: no "Show N empty fields" or "Hide empty fields" button. - On a print page, the empty fields a section declares print by card ②'s own rule ("prints every field it declares"), as the open-collapsed-section case already does. If the seat judges that empty fields should stay folded on paper, it records why in the PR, and the fold leaves no control behind.
- Off a print page, the toggle and the auto-hide are unchanged.
- A test renders a section with empty fields inside a print page (
usePrintPage()non-null): no toggle, and the declared fields present. A control test does the same off a print page.
Serial note: objectui#12618 (open, pm:on-hold) changes the same empty-field fold on screen: an all-empty section folds instead of showing dashes. It names DetailView.tsx, but the fold lives in DetailSection.tsx. The two cards touch one behaviour from two sides, so they should not run in the same batch, and whichever lands second keeps the print gate.
Dedupe
MCP search_issues on objectstack-ai/objectui (closed included in results):
print page Show empty fields toggle on paper, line items column headings print field names not labels→ 2 hits: Record page: a section whose fields are all empty folds like the others instead of showing dashes #12618 (open, on-screen fold of all-empty sections, not print; serial note above) and record drawer: header highlight fields truncate short values ("QA Wid…") with most of the row empty #11684 (closed, record drawer truncation). Neither covers this.print hides interactive controls buttons toggles on paper @media print→ 1 hit: print page ② of objectstack#8346: render a page that declaresprint— the print CSS mapping, the 13 printable blocks on paper, and the record page's "print" action (browser print preview) #11958 (closed, card ② itself).
Activity
objectstack-fleet commentedon Oct 16, 2026
Triage: first grade,
bug·priority:p1·target:v18·domain:ui·area:records·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-16T14:55ZTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015). ⛔ Not a claim, ⛔ not a dispatch.
target:v18: it is on the print path, and the maintainer's rule 「PDF 要赶 18.0 正式版」 puts the PDF chain at p1. The printed invoice carries a screen-only button.domain:ui. The landing ispackages/plugin-detailDetailSection, the follow-up of card ② objectui#11958. Re-render the PDF at the current pin as the acceptance reading, since the card's render was atf96f771140.objectstack-fleet commentedon Oct 16, 2026
Claim: PM loop round 4 (
priority:p1,target:v18; the print-page chain, triage grade6218206205)Session:
session_011K9g23W67dy2zwnyzaoB6oAccount:
os-teslaBranch:
claude/issue-12717-print-empty-toggleWorktree:
objectui-issue-12717(in the cloud session's own container)Domain:
domain:uiSeat:
domain:ui#1File surface: what
record:detailsputs on paper.packages/plugin-detail/src/DetailSection.tsx, at the empty-field auto-hide (shouldAutoHideEmpty/hideEmptyEffective, near:305–:350) and the "Show N empty fields" toggle (showEmptyToggle, near:755–:776), gated onusePrintPage()the way card ② already gates the collapse (:188);.changeset/12717-*.md.Outside the surface:
pm:on-hold. Its card namesDetailView.tsx, but the fold lives in this same file, so whichever lands second keeps this print gate.page-print.tsand the print stylesheet: no blanket hide of controls.RecordDetailView.tsxand the route: objectui#12715.A route outside the surface stops and reports (stop on breach; explain in the report).
Container & model:
S,mode:cloud,model: opus(default tier;dispatch-gates --tier --repo objectstack-ai/objectuiover the path: no path-derived mandate)Clause-②: no
Clause-② reason: only what a print page draws changes; no published type, prop, export, schema read or pack key changes. Off a print page, the toggle and the auto-hide are unchanged.
Responsibility: n/a — a defect card, but no landed PR is named as its cause. Card ② (objectui#11958) gated the collapse and left the toggle, so the defect dates from the code card ② shipped.
Thread-read: 6218206205
Serial constraints cleared: read at objectui
main5c0846ebd8.plugin-detail/src/DetailSection.tsxorpage-print.ts; its last change was PR feat(fields,app-shell,plugin-detail): a pointer whose target the platform deleted draws a tombstone in the declared option's label (objectui#12489) #12665's merge023087f.pm:on-hold, unassigned) is not in flight.Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
os-dev-report
{ "issue": 12717, "status": "done", "branch": "claude/issue-12717-print-empty-toggle", "pr": "https://github.com/objectstack-ai/objectui/pull/12729", "session": "session_01D7HiWiz4iSX26uyJLB8jNs", "premise_still_valid": true, "summary": "On a print page, DetailSection's empty-field auto-hide (shouldAutoHideEmpty) is now off. Every declared field prints, empty ones as the shared placeholder dash. The 'Show N empty fields' / 'Hide empty fields' toggle derives from the heuristic, so it no longer draws. usePrintPage() is read once, above every early return (isPrintPage), and both the existing collapse gate and the new heuristic gate use that one value. The authored all-empty hide (section.hideEmpty === true) is unchanged and still prints nothing. Off a print page the toggle, the heuristic and the authored hide are unchanged. H1 to H3 hold as stated. H4 found one more control, listed in out_of_scope_findings. The premise checked out on origin/main 611566b: the toggle sat at :755 and was not gated. Head 9f28cd2 is pushed. The PR is not opened (seat's write).", "tests": "Measured at head 9f28cd2. New file packages/plugin-detail/src/__tests__/detailSectionPrintEmptyToggle-12717.test.tsx, 3 tests, pass: (1) inside PrintPageProvider: no toggle, all 4 declared labels present, 2 'No value' placeholders; (2) inside PrintPageProvider: an authored hideEmpty:true all-empty section renders an empty container; (3) CONTROL off a print page: the toggle reads 'Show 2 empty fields' and the empty rows are hidden. Each test was proven red by an ablation through objectstack scripts/ablation-replace.mjs. The subject resolves via the vitest alias to src, so no build was needed. (a) Deleting the '!isPrintPage &&' gate turns test 1 red ('expected button to be null'), 1 failed / 2 passed. (b) Adding '&& !isPrintPage' to hideAllEmptySection (the wrong fix) turns test 2 red, 1 failed / 2 passed. (c) Replacing the gate with 'false &&' turns the CONTROL red, 1 failed / 2 passed. Every restore leg reported blob 576f471d0f52 == HEAD blob 576f471d0f52790dad4d923def6084bdddbfbc55 with an empty git diff HEAD. One earlier ablation attempt was a no-op: its replacement text was already present, so the tool refused it with a non-zero exit, and it was rerun with --delete. Package suite under the verify lock: `pnpm exec vitest run packages/plugin-detail` gave Test Files 275 passed | 1 skipped (276), Tests 2663 passed | 14 skipped (2677), VERDICT command-exit 0. Nothing in scripts/__tests__ reads DetailSection.tsx by path (grep shows zero hits). NOT MEASURED: PDF reading. Reason: showcase_invoice_document is in neither the published showcase at @objectstack/cli@18.0.0-next.2 (e5136ff) nor objectstack main 6d1660d. As a fallback I booted start-backend.sh (npm 10.9.4 installed cleanly) and built consoles at base and at the fix. I added a throwaway print:{paperSize:'A4'} plus a 4-field probe section to showcase_task_detail, in both src and dist/objectstack.json of the scratch copy. The served /api/v1/meta/page response came back unchanged (110997 bytes, no 'print'), and the record route mounted 0 [data-print-page] nodes in both builds. No print page could be rendered, so no before/after PDF exists and nothing was pushed to claude/issue-12717-evidence.", "gates": "Local subset, measured at head 9f28cd2, exit codes captured before any pipe. Closure build `pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-detail^...' build`: exit 0. `pnpm --filter @object-ui/plugin-detail build && pnpm --filter @object-ui/plugin-detail type-check`: exit 0 (script name type-check echoed). Console build `VITE_BASE_PATH=/console/ pnpm --filter @object-ui/console exec vite build`: VERDICT command-exit 0. `pnpm check:changeset-claims`: 0 ('No pending changeset names a file this change touches'). `pnpm changeset:check`: 0. `pnpm check:test-path-roots`: 0. `pnpm check:spec-symbols`: 0. `node scripts/check-changeset-presence.mjs`: 0 (1 released package, 1 changeset). eslint on the 2 changed source files: exit 0, 0 errors and 12 warnings, all in DetailSection.tsx; the base file has the same 12 (exit 0, 12 warnings); the new test file has none. objectui has no dispatch-gates.mjs, so the list above is hand-derived per the brief and there is no --ran reconciliation. CI check-runs are NOT MEASURED: no PR exists yet.", "mcp_calls": "2: mcp__github__issue_read (get, get_comments). Read-only, no write tool.", "api_writes": "0. The only GitHub write was `git push` of the branch (empty probe push, then 9f28cd2).", "open_questions": [ { "question": "Acceptance 2: on paper, which empty-field hide applies?", "options": [ "A: the renderer's density heuristic is off on paper, so every declared field prints; the authored hideEmpty:true all-empty hide stays, printing nothing and leaving no control", "B: keep the heuristic on paper and only hide the button" ], "recommendation": "A (implemented). Business need: card ② rules that record:details is printable because it prints every field it declares, and B would drop the declared rows from the invoice. Long-term: one print gate value read in one place, with no CSS workaround and no change to page-print.ts. AI-error resistance: nobody authors the heuristic, so it cannot be declared on paper; the authored key keeps doing exactly what it declares. Scope: no new key, prop or gate." } ], "out_of_scope_findings": [ "class: a (user-visible: a screen affordance on paper) · reach: NOT MEASURED on paper, static read only. DetailSection.tsx renders a collapsible section's disclosure chevron (ChevronDown, :879-883 at 9f28cd2) inside the header button on a print page too: card ② opens the section but keeps the disclosure chrome, plus the header's cursor-pointer and hover classes. Not fixed: the claim's file surface covers only the auto-hide and the toggle. · dedupe: print chevron collapsible section header, record details print disclosure icon, DetailSection print page chevron", "carrier: none. Noted, not filed. The hover copy and pencil buttons (:665, :687) are opacity-0 until group-hover, so they draw nothing on paper; the mobile grouped-inset row's role=button is not visual. Neither is a paper defect.", "carrier: none. Noted, not filed. Live-lane gap: at the published pin 18.0.0-next.2, a throwaway page-level print:{paperSize:'A4'} on showcase_task_detail never reached /api/v1/meta/page and no print page mounted on the record route. This may belong to objectui#12715 (the route) or to the next.2 runtime. It was not separated, so this is a reading, not a defect." ] }Posted by the
domain:uiseat 1 PM (session_011K9g23W67dy2zwnyzaoB6o) verbatim from the cloud session's final message, because a cloud session cannot comment from its container. The seat filledprwith the draft PR it opened, #12729.The seat's answers:
hideEmpty: truekeeps doing what it declares.record:detailssection.printnever reached/api/v1/meta/pageat the next.2 pin. The seat carries this to objectui#12715's review, which owns the print route reading.Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
ACCEPT → PR #12729 comment 6219401499 · lane seat review at
TIER_DEFAULT·domain:uiseat 1 ·session_011K9g23W67dy2zwnyzaoB6o· 2026-10-16T15:58ZGenerated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
Landed ·
domain:uiseat 1 ·session_011K9g23W67dy2zwnyzaoB6o· 2026-10-16T16:12Zmain263e9ddccc, with one parent,c41ce3f. It is an ancestor oforigin/main.611566b4dfto the reviewed head9f28cd2c11, changed line for changed line in each of the 3 files (+114/−2). Positive control at the merge commit:DetailSection.tsx:190gates the collapse and:318gates the empty-field heuristic on the oneisPrintPage.completedbyFixes #12717. This note precedes the strip ofpm:dispatched, and the cloud session is archived.Generated by Claude Code