Skip to content

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

Closed

Description

@objectstack-fleet

Filing gate ①: a user-visible defect with a named landing, measured on a real PDF.

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:details is in the printable block subset because it prints every field it declares".
  • :755 (:736 at the pin): const showEmptyToggle = emptyCount > 0 && shouldAutoHideEmpty;. This is NOT gated on usePrintPage(). The empty-field auto-hide (hideEmptyEffective, :345 at 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

  1. On a page that declares print, record:details puts no interactive control on paper: no "Show N empty fields" or "Hide empty fields" button.
  2. 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.
  3. Off a print page, the toggle and the auto-hide are unchanged.
  4. 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):

Activity

  1. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade, bug · priority:p1 · target:v18 · domain:ui · area:records · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-16T14:55Z

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015). ⛔ Not a claim, ⛔ not a dispatch.

    • Why p1 + 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.
    • Lane: domain:ui. The landing is packages/plugin-detail DetailSection, 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 at f96f771140.
  2. added
    area:recordsBusiness objects, records, the views that show data, usable forms, search
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    and removed on Oct 16, 2026
  3. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 4 (priority:p1, target:v18; the print-page chain, triage grade 6218206205)
    Session: session_011K9g23W67dy2zwnyzaoB6o
    Account: os-tesla
    Branch: claude/issue-12717-print-empty-toggle
    Worktree: objectui-issue-12717 (in the cloud session's own container)
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: what record:details puts 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 on usePrintPage() the way card ② already gates the collapse (:188);
    • tests beside it, and one .changeset/12717-*.md.

    Outside the surface:

    • The on-screen fold of an all-empty section: objectui#12618, pm:on-hold. Its card names DetailView.tsx, but the fold lives in this same file, so whichever lands second keeps this print gate.
    • page-print.ts and the print stylesheet: no blanket hide of controls.
    • RecordDetailView.tsx and 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/objectui over 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 main 5c0846ebd8.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    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:ui seat 1 PM (session_011K9g23W67dy2zwnyzaoB6o) verbatim from the cloud session's final message, because a cloud session cannot comment from its container. The seat filled pr with the draft PR it opened, #12729.

    The seat's answers:

    • The open question: A, as implemented. The renderer's own heuristic is off on paper, and the authored hideEmpty: true keeps doing what it declares.
    • The chevron finding: the seat files it as its own card. It is the same file and the same print-path defect class, and its reach is the printed record:details section.
    • The live-lane reading: a throwaway page-level print never reached /api/v1/meta/page at the next.2 pin. The seat carries this to objectui#12715's review, which owns the print route reading.
    • The PDF reading Triage asked for: NOT MEASURED, because the invoice print page is not in the published showcase. The seat's ACCEPT records that acceptance gap.

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #12729 comment 6219401499 · lane seat review at TIER_DEFAULT · domain:ui seat 1 · session_011K9g23W67dy2zwnyzaoB6o · 2026-10-16T15:58Z


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:ui seat 1 · session_011K9g23W67dy2zwnyzaoB6o · 2026-10-16T16:12Z

    • Merged: PR fix(plugin-detail): a detail section on a print page prints every declared field and no "Show N empty fields" button #12729 landed through the merge queue as main 263e9ddccc, with one parent, c41ce3f. It is an ancestor of origin/main.
    • Verified by content: the merge commit's own diff equals the PR's diff from its merge-base 611566b4df to the reviewed head 9f28cd2c11, changed line for changed line in each of the 3 files (+114/−2). Positive control at the merge commit: DetailSection.tsx:190 gates the collapse and :318 gates the empty-field heuristic on the one isPrintPage.
    • Card: closed completed by Fixes #12717. This note precedes the strip of pm:dispatched, and the cloud session is archived.
    • Carried: the disclosure chevron on paper is objectui#12732. The PDF re-render stays NOT MEASURED until a print page exists in the published showcase.

    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:recordsBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p1target:v18

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions