Repository navigation
Commit 2af790f
spec(ui): record:details
Fixes #25511
Clause-②: no
Metadata-protocol: semantic
## What this changes
The `record:details` section key `hideEmpty`
(`packages/spec/src/ui/component.zod.ts`, the
`RecordDetailsProps.sections[]` object form) gets a new `describe()`
text. It implements ruling C on objectstack-ai/objectui#13386 (batch #7
item 4, the maintainer's 「objectui 三个都同意」, 2026-10-23T16:08:53Z):
- **Default (key omitted, or `true`): unchanged.** An all-empty section
renders nothing at all: no heading, no skeleton.
- **`false`, read-only mode:** an all-empty section renders its heading
plus one fold row that counts the empty fields and reveals them on
request. This is the same fold a partly-filled section uses.
- **`false`, edit mode:** unchanged. Every field renders as an editable
row.
No key, shape or default changes. The renderer change is objectui's
(`DetailSection`); objectstack-ai/objectui#13386 carries `Blocked-by:`
this card and remains open.
| | Before | After |
|---|---|---|
| `describe()` | Hide this section's empty fields (renderer default: on
— and a section whose fields are ALL empty then renders nothing at all:
no heading, no skeleton). Set `false` to render empty rows, keeping the
section's label skeleton on an all-empty record (e.g. a brand-new one).
| Whether this section disappears when ALL its fields are empty
(renderer default: on — it then renders nothing at all: no heading, no
skeleton). Set `false` to keep it on an all-empty record (e.g. a
brand-new one): in read-only mode it renders its heading plus one fold
row that counts the empty fields and reveals them on request — the same
fold a partly-filled section uses; in edit mode it renders every field
as an editable row. |
Files:
- `packages/spec/src/ui/component.zod.ts`: the describe string, plus one
docblock paragraph above it recording the re-ruled `false` rendering and
that the key governs only the all-empty case. The docblock's existing
text is about the default and the pre-declaration history, so it stays
as it was.
- `content/docs/references/ui/component.mdx`: regenerated with
`gen:docs`. `check:generated` named it as the only stale artifact. The
shipped `json-schema/ui/RecordDetailsProps.json` (gitignored, in
`files[]`) carries the new text after a build.
- `.changeset/25511-hide-empty-describe.md`: `@objectstack/spec`
`minor`, with both declaration lines.
Landing: the measured producer is the one the card named,
`component.zod.ts` at `:1440`. No other producer of this text exists
(`git grep` for the old phrases finds only the generated mdx, a test
comment and the release-owned `CHANGELOG.md`).
## Two wording calls
1. **The fold label is not quoted.** The card writes the row as "N empty
fields · Show". The ruling's text is 「N 个空字段 · 展开」, and what it rules is
"the same fold the mixed sections use". objectui's English label for
that fold is "Show {{count}} empty fields" (`detail.showEmptyFields`,
`packages/i18n/src/locales/en.ts` at objectui `7981384`). Quoting "N
empty fields · Show" would contradict "the same fold", and quoting
objectui's string would pin a label the spec does not own. So the text
says what the row does: it counts the empty fields and reveals them on
request.
2. **The lead changed from "Hide this section's empty fields" to
"Whether this section disappears when ALL its fields are empty".** Under
C, both values hide an all-empty section's empty rows in read-only mode
(`true` drops the section, `false` folds the rows), so the old lead no
longer told the two values apart. The key never governed a partly-filled
section's empty rows either: the renderer's own fold handles those
whatever the key says (objectui#7129 Q2-C). The default sentence keeps
its meaning; only its grammar follows the new lead.
## Verification
All readings were taken on head `0ed74f8840` (the merge of `origin/main`
`e649c2d91e`; the branch delta against `origin/main` is exactly the
three files above).
- `pnpm --filter @objectstack/spec build`: lock VERDICT command-exit 0.
The build left no tracked file changed (`authorable-surface.base.json`
untouched).
- `pnpm --filter @objectstack/spec check:generated`, before
regeneration: exit 1, `✗ 1 of 14 artifact(s) stale:
content/docs/references/**`. After `gen:docs`, on the final head: `✓ All
14 generated artifacts are up to date`.
- `pnpm --filter @objectstack/spec test`: `Test Files 714 passed (714)`,
`Tests 21687 passed | 1 todo (21688)`. `pnpm --filter @objectstack/spec
typecheck` (tsc, scripts typecheck, test typecheck): exit 0. Lock
VERDICT command-exit 0.
- Gates: `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived 107 commands from this diff. Each
was run with its exit code captured before any pipe: 106 exited 0. One,
`pnpm check:dual-build-cjs-loads`, exited 3 (`PREREQUISITE NOT MET —
this gate reads built output, and some package has no dist/`), so it is
NOT MEASURED. It needs every workspace package built, and only the spec,
lint, objectql, client, client-react and formula closures were built
(targeted build; declared narrowing). CI's `Lint & Repo Gates` runs it.
Reconciliation: `✓ dispatch-gates --ran: 107 derived famil(ies)
accounted for — 106 run, 1 NOT-MEASURED (0 DERIVED from a recorded exit
3, 1 claimed).` Selected verdict lines: `check:generated` `✓ All 14
generated artifacts are up to date`; `check:docs` `✅ 227 generated files
in sync with packages/spec`; `check:api-surface` `public API surface +
factory signatures unchanged ✓`; `check:doc-authoring` clean (9559
describe strings read); `check:nul-bytes` OK;
`check-adr-0087-registration` `this PR adds no declared-breaking
changeset (1 non-breaking changeset(s) seen)`.
- Local-only `check:dev-prereqs`: its self-test passes, but the scan
exits 1 with `✗ The workspace is not built — 1 unmet precondition` (33
of 70 packages have no `dist/`, same targeted-build cause). NOT
MEASURED. The spec build's own stamp (`✓
packages/spec/dist/.build-input-hash`) and `check:generated`'s
declaration-stamp match show `packages/spec/dist` is current.
- No ablation or reverse verification. The diff changes describe text
and generated docs only, and no test pins that text.
## Acceptance notes
- **The renderer lags the text until objectstack-ai/objectui#13386
lands.** Until then, a `false` all-empty section still renders empty
rows in read-only mode. The ruling orders it this way (spec text first,
renderer second).
- **The default in edit mode** (noted, not filed; carrier: none).
objectui renders every row of an all-empty section in edit mode for the
default too (`hideAllEmptySection` requires `!isEditing`,
`DetailSection.tsx` at objectui `7981384`). The default sentence says
"renders nothing at all" with no mode qualifier, as the card asked. No
author writes wrong metadata because of it.
- **A stale test comment** (noted, not filed; carrier: none).
`packages/spec/src/ui/component.test.ts` at about line 636 still calls
`false` "the only spelling that keeps a section's label skeleton on an
all-empty record". That file is outside the claim's file surface, and no
assertion depends on the wording.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01PC4NPXPgPmpDRG9DdDnyXT)_
---------
Co-authored-by: Claude <noreply@anthropic.com>hideEmpty: false — in read-only mode an all-empty section renders its heading plus one fold row; describe() says so (#25612)1 parent f7b0298 commit 2af790f
3 files changed
Lines changed: 30 additions & 2 deletions
File tree
- .changeset
- content/docs/references/ui
- packages/spec/src/ui
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1697 | 1697 | | |
1698 | 1698 | | |
1699 | 1699 | | |
1700 | | - | |
| 1700 | + | |
1701 | 1701 | | |
1702 | 1702 | | |
1703 | 1703 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1436 | 1436 | | |
1437 | 1437 | | |
1438 | 1438 | | |
| 1439 | + | |
| 1440 | + | |
| 1441 | + | |
| 1442 | + | |
| 1443 | + | |
| 1444 | + | |
| 1445 | + | |
| 1446 | + | |
| 1447 | + | |
| 1448 | + | |
| 1449 | + | |
1439 | 1450 | | |
1440 | | - | |
| 1451 | + | |
1441 | 1452 | | |
1442 | 1453 | | |
1443 | 1454 | | |
| |||
0 commit comments