Repository navigation
showcase: the invoice print page's line-items table prints the raw field names description / quantity / unit_price / amount as its headings — its record:line_items columns declare no label, and that block draws a column exactly as declared #23985
Copy link
Copy link
Closed
Labels
area:filesFiles — upload, download, signed URLs, access derived from the parent recordFiles — upload, download, signed URLs, access derived from the parent recordbugSomething isn't workingSomething isn't workingdomain:servicespriority:p1High: required for production / M2High: required for production / M2target:v18
Description
Filing gate ①: a user-visible defect in the reference app, with a named landing.
reach:the public render path. The printed showcase invoice (the invoice's print pageshowcase_invoice_document) heads its line-items table with field names, not labels.- Measured once on the real PDF by the objectstack card ③ dev's end-to-end render, in Chromium on both placements. 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) #22269 comment
6208035645(out_of_scope_findings[1]), where it was first routed to objectui card ②. - That routing is corrected here: the renderer does what the contract declares. The landing is this repo's showcase page.
Filed by the domain:services seat 2 (#21118) · os-elon-musk · session_018VqJPGA1NDNSCZsnecsChP, from PR #23811's ACCEPT. ⛔ Not a claim. Lane, grade and area:* are triage's.
Blocked-by: #23811
Reader who acts: the next execution seat that takes an examples/app-showcase card. The page is added by PR #23811. If a contract change is preferred over a showcase edit, the reader is instead the domain:spec seat; see the second option below.
Measured
- At PR feat(service-print): print a record's print page to a PDF in headless Chromium as the requesting user, and archive it on the record #23811's head
5a16f29db9:examples/app-showcase/src/ui/pages/invoice-document.page.ts:60readscolumns: [{ name: 'description' }, { name: 'quantity' }, { name: 'unit_price' }, { name: 'amount' }]. These are identity-only columns, with nolabel. - The contract, at the head and on
origin/main:packages/spec/src/ui/component.zod.ts:2494,RecordLineItemsProps.columns. It reads: "Unlike the master-detail carriers, this block does NOT hydrate a column from the child object's field: declarelabel,typeandoptionsyourself — an identity-only{ name }column is a text cell headed by its name." - The renderer at the pin
daeb77fc84dddoes exactly that:packages/fields/src/widgets/GridField.tsx:1005and:1313draw{c.label || c.name}. The same header serves the screen. That is a static reading; it was not measured on screen. - The contrast in the same file: the master-detail carrier
showcase_invoice.lines.inlineColumns(examples/app-showcase/src/data/objects/invoice.object.ts, around:248-256) is identity-only on purpose. There,hydrateColumnsfillslabelfrom the child field, "so labels stay translatable".record:line_itemshas no such step. - The invoice line's fields do carry labels:
descriptionisDescription, andunit_priceisUnit Price(invoice.object.ts). The zh-CN bundle translates onlyservice_startonshowcase_invoice_line.
Acceptance
One of two, and the PR names which:
- Showcase. The page's four columns declare
label, and the printed headings read as labels.- Say in the PR whether the zh-CN print can translate them. The page's header is bilingual, and a literal
labelis not translated unless the bundle can key it. If it cannot, say so in the PR rather than leave a mixed-language sheet unexplained.
- Say in the PR whether the zh-CN print can translate them. The page's header is bilingual, and a literal
- Contract, if the spec seat prefers it.
record:line_itemshydrates an identity-only column from the child object's field, as the master-detail carriers do. That widensRecordLineItemsProps.columns's describe, and becomes an objectui renderer change behind it. It is spec-lane work with its own card, and this card closes into it.
In either case: a test or a dogfood assertion that the invoice print page's line-items headings are labels.
Dedupe
- MCP
search_issueson objectstack-ai/objectui,record:line_items column headings show field name instead of field label→ 0 hits. - MCP
search_issueson objectstack-ai/objectui,print page Show empty fields toggle on paper, line items column headings print field names not labels→ 2 hits, neither covering it: [finding] the built-CLI refusal says "every boot below times out"; measured, the child exits 2 immediately and the boot rejects onexit#12618 (open, an on-screen empty-field fold) and rest: an UNDECLARED hook refusal answers 500 on/analytics/dataset/querywhere the same refusal answers 400 on/data— the route's fallback arm treats a business refusal as a server fault #11684 (closed). - MCP
search_issueson objectstack-ai/objectstack,showcase invoice print page line items column labels record:line_items headings field names→ 0 hits. - MCP
search_issueson objectstack-ai/objectstack,record:line_items hydrate column label from child object field like master-detail inlineColumns→ 0 hits.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
area:filesFiles — upload, download, signed URLs, access derived from the parent recordFiles — upload, download, signed URLs, access derived from the parent recordbugSomething isn't workingSomething isn't workingdomain:servicespriority:p1High: required for production / M2High: required for production / M2target:v18
Activity
objectstack-fleet commentedon Oct 16, 2026
Triage: first grade,
bug·priority:p1·target:v18·domain:services·area:files·pm:blockedon PR #23811 · triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-16T17:54ZTriage seat (objectstack-wide, seat post #6015). ⛔ Not a claim, ⛔ not a dispatch.
target:v18: the printed invoice heads its table with field names. The maintainer's rule 「PDF 要赶 18.0 正式版」 puts the PDF chain at p1.Blocked-by: #23811stands.record:line_itemscolumns their labels, in both locales the showcase ships. The renderer draws whatRecordLineItemsProps.columnsdeclares. Changing the contract so an unlabelled column derives its field's label is a spec change of its own. ⛔ It is not this card. If the claimant judges the contract should change, it files thatdomain:speccard under the self-split rule.domain:services:examples/*belongs to the subsystem it exercises, here the print service (service-print).objectstack-fleet commentedon Oct 17, 2026
Unlock:
pm:blocked→pm:queue· PR #23811 merged · triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-17T02:03ZTriage seat (objectstack-wide, seat post #6015). ⛔ Not a claim, ⛔ not a dispatch.
b15f8a1997(2026-10-17T01:01Z), and 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) #22269 closedcompleted.origin/main50ccfa6697:examples/app-showcase/src/ui/pages/invoice-document.page.ts:60still readscolumns: [{ name: 'description' }, { name: 'quantity' }, { name: 'unit_price' }, { name: 'amount' }].target:v18(「PDF 要赶 18.0 正式版」),domain:services, and the scope of the first grade (6221505080): labels on the four columns in both showcase locales, ⛔ no contract change.Generated by Claude Code
objectstack-fleet commentedon Oct 17, 2026
Claim: PM loop round 1 of this seat's second term · 2026-10-17T02:55Z
Session:
session_018VqJPGA1NDNSCZsnecsChP(the dispatching seat; the dev runsmode:subagentin this session's container and shares its session ID, so its identity is the branch)Account:
os-elon-musk(the seat's linked user, asGET /useranswers it; the card's assignee from this act)Branch:
claude/issue-23985-invoice-line-item-labelsWorktree:
objectstack-issue-23985Domain:
domain:servicesSeat:
domain:services#2(seat post #21118)File surface (at
origin/mainc1c0a90942or later; stop on a breach and explain it in the report):examples/app-showcase/src/ui/pages/invoice-document.page.ts: the fourrecord:line_itemscolumns (:60) gain theirlabel;examples/app-showcase/src/system/translations/**), only if the zh-CN print can key those labels the way the showcase's other page labels are translated;examples/app-showcase/test/that the line-items headings are labels, never the raw field names.Exclusions:
packages/spec/**, not objectui's renderer (triage's scope,6221505080). If the dev judges the contract should hydrate labels, it says so in the report; it does not file or build that card.invoice.object.ts'sinlineColumns, which are identity-only on purpose.@objectstack/example-showcaseis"private": true, so the PR carriesskip-changeset.Container & model:
S: four labels on one page plus a pin ⇒ S,mode:subagent,model: opus(TIER_DEFAULT;dispatch-gates --tiernames no path-derived mandate)Clause-②: no. An example app's column headings change. No export, type or accept set moves.
Responsibility:
examples/app-showcase (this lane; the example exercises service-print): the printed invoice heads its line items with labels | the renderer draws what RecordLineItemsProps.columns declares, unchanged | every reader of the showcase invoice's printThread-read: 6228273334
Serial constraints cleared: no open PR or in-flight claim touches
examples/app-showcase/src/ui/pages/(open-PR read now: only PR chore: version packages (next) #23825, the version PR). This seat has nothing else in flight.Premise to falsify first: on
origin/main,invoice-document.page.ts:60declares identity-only columns, and a printed or on-screen render heads themdescription/quantity/unit_price/amount.Generated by Claude Code
objectstack-fleet commentedon Oct 17, 2026
os-dev-report
{ "issue": 23985, "status": "done", "branch": "claude/issue-23985-invoice-line-item-labels", "pr": "https://github.com/objectstack-ai/objectstack/pull/24139", "session": "session_018VqJPGA1NDNSCZsnecsChP (subagent; shares the dispatching seat's session id, so the identity is the branch)", "premise_still_valid": true, "summary": "Premise confirmed on origin/main c1c0a90942. invoice-document.page.ts:60 declared four identity-only record:line_items columns, and objectui at pin f8267df93a heads a column with c.label || c.name: LineItemsPanel passes columns through applyColumnPermissions only, with no hydration. Acceptance option 1 (Showcase): the four columns now declare the invoice line fields' own labels (Description, Qty, Unit Price, Amount), and a new pin holds them. zh-CN cannot translate them. InlineGridColumnSchema.label is z.string(), so there is no inline locale map. translatePage overlays only PAGE_COMPONENT_COPY_KEYS onto properties.KEY, so no bundle key reaches properties.columns[i].label. The labels are therefore literal English, and the PR says so; the bundle is untouched. Points to note: (1) The dispatch said to put skip-changeset in the PR body, but Check Changeset reads the LABEL live, not the body. I applied the label with label-write.mjs and stated it in the body. (2) The claim's full Clause-② line was copied verbatim; it begins with 'Clause-②: no'. (3) The harness asked for a model-named commit trailer. The model-free pair from AGENTS.md was used instead. (4) No browser render on this head. The pin holds the declared metadata, which the renderer draws verbatim. The diff stayed inside the claim's file surface. The worktree was removed without --force, and no process is left running.", "tests": "All on head 0de6f72ee4. origin/main is still c1c0a90942, so the pre-PR merge was a no-op. Closure build: turbo run build --filter='@objectstack/example-showcase^...' --concurrency=2 under os-verify-lock gave 62/62 successful, VERDICT command-exit 0. New pin alone: pnpm --filter @objectstack/example-showcase exec vitest run --maxWorkers=2 test/invoice-document-line-items.test.ts gave Test Files 1 passed (1), Tests 3 passed (3). Full showcase: pnpm --filter @objectstack/example-showcase test gave Test Files 35 passed (35), Tests 427 passed (427). typecheck (tsc --noEmit) exited 0, VERDICT command-exit 0, and tsc --listFiles includes the new test (count 1). Ablation, one leg, through scripts/ablation-replace.mjs in wrap mode on the committed fix. The columns array was put back to today's identity-only line. Landing: anchor 1 → 0, blob 1e5578e84b55 → c9acb7dcda24. Result: Tests 1 failed | 2 passed (3), with: column 'description' must declare its heading: expected undefined to be 'Description'. Restore: blob after restore == blob at HEAD (1e5578e84b55), and git diff HEAD is empty. Independently re-checked with git hash-object against HEAD: and a clean git status --porcelain. Direction: red, as expected. The page is imported by a relative source path, so no dist sits on the path and no rebuild leg applies.", "gates": "Derivation: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, on tree objectstack-ai/objectstack at 0de6f72ee4, gave 42 commands. All 42 were run in sequence, each exit captured before any pipe. --ran gave '42 derived famil(ies) accounted for — 42 run, 0 NOT-MEASURED' (exit 0). Every final reading is exit 0. pnpm check:dual-build-cjs-loads first exited 3, PREREQUISITE NOT MET: nine packages outside the showcase closure had no dist. check:type-check-debt, later in the sequence, built every package. The real command was rerun and exited 0: '111 published require entry point(s) across 69 package(s) load'. pnpm check:i18n-coverage: OK (14 config(s), 621 baselined untranslated string(s), none new). check:dts-closure and check:sourcemap-no-sources-content were rerun after the full build and exited 0 again, over 75 and 72 packages. No export moved, so check-platform-checklist does not apply. CI at report time, head 0de6f72ee4, 40 check-runs: 11 success, 10 skipped, 19 in_progress. in_progress: Build Core; Test Core 1/6 to 6/6; Governed Surface Queue Guard; Lint · ESLint / CI, release & engine gates / PM dispatch-gates / docs & code guards / repo & tooling gates / scoped · slot lookup & corpus; Type Check · consumer gates / debt ledger / source gates / workspace; Check Changeset (one run skipped on the label, one in_progress). success: Lint · scoped · query-options erasure, Lint · scoped · tooling self-tests, Dogfood Regression Gate, Check Documentation Links, the claim and single-writer guards, the Part-of guard, Auto Label, Check PR Size, filter. Not waited on, per the dispatch contract.", "mcp_calls": "0", "api_writes": "3 relay dispatches. Each is POST /repos/objectstack-ai/objectstack/dispatches with the session token, executed by fleet-write.yml as objectstack-fleet[bot]. (1) pr_create: POST /repos/objectstack-ai/objectstack/pulls (draft) and POST /repos/objectstack-ai/objectstack/issues/24139/assignees [os-elon-musk], run 38998697633; the body read back byte-identical, 8020/8020. (2) labels_add via scripts/pm/label-write.mjs: POST /repos/objectstack-ai/objectstack/issues/24139/labels [skip-changeset], run 38998746462; read back size/s, tests, skip-changeset. (3) This os-dev-report via scripts/pm/post-stamped.mjs: POST /repos/objectstack-ai/objectstack/issues/23985/comments. Also 2 git pushes, which are not REST: the empty-branch probe, then 0de6f72ee4.", "open_questions": [ { "question": "Should record:line_items carry zh-CN column headings through a contract change (card option 2)? Or does this literal-English showcase fix close the matter?", "options": [ "A — No contract change. This PR is the whole fix, and a zh-CN print keeps English line-items headings under translated section headings. Cost: nothing now. The mixed-language sheet remains, and the PR explains it.", "B — record:line_items hydrates an identity-only column from the child field (label, type, options), as the master-detail carriers do. This needs a widened describe on RecordLineItemsProps.columns, an objectui LineItemsPanel change and a pin bump. Labels would then translate through the existing objects.CHILD.fields.F.label keys, with no new translation face. Cost: a spec-lane card, an objectui change and a cross-repo landing, about M.", "C — Tighten the contract: refuse at publish a record:line_items column that declares no label. This is a schema narrowing (Clause-② narrowing, breaking). It makes the trap loud but translates nothing. Cost: S in spec, plus migration text." ], "recommendation": "A, with B named as the route if a zh-CN printed invoice becomes a v18 requirement. Business need, measured on origin/main c1c0a90942: record:line_items has 2 producers in this repo, both showcase pages. Only the invoice page was identity-only, and it is fixed here. No external user is named, so translated headings on this one sheet are the whole pull. Long-term soundness: B is the better architecture (one child-collection concept with one behaviour, and labels follow their fields). C adds a rule and still does not translate. AI-error proofing: today an AI that copies the identity-only form (which the InlineGridColumnSchema JSDoc calls recommended) onto record:line_items gets silent field-name headings. B removes that structurally, C makes it loud, and A leaves only the describe text as a warning. Startup restraint: B is a capability widening with a cross-repo cost for one sheet, and C is a new refusal with no named victim, so both default to no. The axes conflict (AI-error proofing favours B, restraint favours A), so this is a maintainer call." } ], "out_of_scope_findings": [] }Generated by Claude Code
objectstack-fleet commentedon Oct 17, 2026
ACCEPT → PR #24139 comment
6229092921·domain:servicesseat 2 ·session_018VqJPGA1NDNSCZsnecsChP· 2026-10-17T03:33Z. Lands through the merge queue once its last CI shard is green. Filed from the review: #24140.Generated by Claude Code
objectstack-fleet commentedon Oct 17, 2026
Landed ·
domain:servicesseat 2 (#21118) ·os-elon-musk·session_018VqJPGA1NDNSCZsnecsChP· 2026-10-17T03:55Z.Landed: PR #24139 (
Fixes #23985) merged through the merge queue as5c92b01304. That commit is onorigin/main(git merge-base --is-ancestor). Timeline:merged2026-10-17T03:55Z. ACCEPT6229092921.origin/mainexamples/app-showcase/src/ui/pages/invoice-document.page.ts: the fourrecord:line_itemscolumns declareDescription/Qty/Unit Price/Amountexamples/app-showcase/test/invoice-document-line-items.test.ts(the pin)What a reader sees: the printed showcase invoice heads its line items with labels, not field names. In zh-CN the headings stay English, because no
record:line_itemsheading can be translated today; that platform gap is #24140.pm:dispatchedis cleared and the assignee is released in this act.Generated by Claude Code