Skip to content

Commit fb110c2

Browse files
committed
feat(release): apply 4a's ui/ half on the merged tree (objectstack#25711)
With ui/ on main (#25825), the objectui side of the release lane lands as tree edits instead of a patch file: - README step 2: the pin, the dist-injection probes, objectui's release lane, its Changesets config, the QUICK_REFERENCE release sync (17c) and the nested pull_request_template.md are deleted; objectui's 65 pending changesets stay under ui/ for #25831; - 4a-ui-side.patch applied under ui/ (git apply --check exit 0 on this tree), then deleted; scripts/ui-import/README.md now records what was applied; - the SDUI manifest is regenerated from ui/ for the merged tree (107 -> 106 components; objectui#13449 retired html), from the patch the 4b PR 2a thread measured. check-changeset-fixed, check:lockstep-package-count, check:sdui-lockstep and check-sdui-manifest (--self-test and the run) exit 0. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0149BHSXfCdQywGaLdpRAtWe
1 parent e2db258 commit fb110c2

55 files changed

Lines changed: 794 additions & 16906 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎scripts/sdui-manifest.record.json‎

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,54 @@
11
{
22
"//": [
33
"Provenance record for the repo-root `sdui.manifest.json` (ADR-0080; #12924 wiring ruling 2026-08-29).",
4-
"The artefact is objectui's public-tier component manifest, generated from objectui's BUILT tree at the",
5-
"commit `.objectui-sha` pins (`modulesRoot` below, materialised by `pnpm objectui:build`) by",
6-
"scripts/gen-sdui-manifest-node.mjs, the one producer (ruling 丙 on #17735). Same enumeration as objectui's",
7-
"apps/console/dev/manifest-dump.tsx: eager-import the 16 registry modules, ComponentRegistry.getPublicConfigs(),",
8-
"manifestFromConfigs from @objectstack/sdui-parser. `objectuiWorkspaceVersion` is read from that tree's",
9-
"@object-ui/core/package.json — the pinned commit's own declaration, never an npm tarball's.",
10-
"`scripts/check-sdui-manifest.mjs` holds this record equal to the artefact and to the live pin:",
11-
"a pin bump without regeneration goes RED there — that is the anti-rot half of the freshness gate.",
12-
"Regenerate + re-record: pnpm objectui:build && node scripts/gen-sdui-manifest-node.mjs"
4+
"The artefact is the console's public-tier component manifest, generated from THIS tree's registry by",
5+
"scripts/gen-sdui-manifest-node.mjs, the one producer (ruling 丙 on #17735): it builds the registry packages under",
6+
"ui/packages/, then enumerates them from `inTree.modulesRoot` exactly as ui/apps/console/dev/manifest-dump.tsx",
7+
"does: eager-import the 16 registry modules, ComponentRegistry.getPublicConfigs(), manifestFromConfigs from",
8+
"@objectstack/sdui-parser. `inTree.registrySourcesSha256` digests those packages' src/ as the index holds them;",
9+
"`scripts/check-sdui-manifest.mjs` recomputes it, so a registry source edit without regeneration goes RED there.",
10+
"`inTree.objectuiWorkspaceVersion` is provenance, not a verdict (#25712). Pin-keyed fields, where present, say the",
11+
"artefact is byte-identical to the one generated at that pin.",
12+
"Regenerate + re-record: node scripts/gen-sdui-manifest-node.mjs"
1313
],
14-
"objectuiSha": "b41ed7f68956c8cfda21bc790548361af81b09ac",
1514
"source": "built-tree",
16-
"modulesRoot": ".cache/objectui-b41ed7f68956/apps/console",
17-
"objectuiWorkspaceVersion": "18.1.0",
1815
"generator": "scripts/gen-sdui-manifest-node.mjs",
1916
"generatedAt": "2026-10-25",
20-
"sha256": "d1fde278ffd643900aba9e8fcf834d35a9c345246709f1667ae71618eaad109c",
21-
"components": 107
17+
"sha256": "1f6e1ccb925a678eaa393f9091dfc7d0285e4e3626e0a5c61a5474687debabb7",
18+
"components": 106,
19+
"inTree": {
20+
"modulesRoot": "ui/apps/console",
21+
"objectuiWorkspaceVersion": "18.1.0",
22+
"registryPackages": [
23+
"ui/packages/components",
24+
"ui/packages/core",
25+
"ui/packages/data-objectstack",
26+
"ui/packages/fields",
27+
"ui/packages/i18n",
28+
"ui/packages/mobile",
29+
"ui/packages/permissions",
30+
"ui/packages/plugin-calendar",
31+
"ui/packages/plugin-charts",
32+
"ui/packages/plugin-dashboard",
33+
"ui/packages/plugin-detail",
34+
"ui/packages/plugin-form",
35+
"ui/packages/plugin-gantt",
36+
"ui/packages/plugin-grid",
37+
"ui/packages/plugin-kanban",
38+
"ui/packages/plugin-list",
39+
"ui/packages/plugin-map",
40+
"ui/packages/plugin-markdown",
41+
"ui/packages/plugin-report",
42+
"ui/packages/plugin-timeline",
43+
"ui/packages/plugin-tree",
44+
"ui/packages/plugin-view",
45+
"ui/packages/providers",
46+
"ui/packages/react",
47+
"ui/packages/react-runtime",
48+
"ui/packages/sdui-parser",
49+
"ui/packages/types"
50+
],
51+
"registrySources": 922,
52+
"registrySourcesSha256": "35ef1abd88b0011a06bfc895b3091d1f8ecf319c3f78d2bfb0d9feb4e53f3bbe"
53+
}
2254
}

‎scripts/ui-import/4a-ui-side.patch‎

Lines changed: 0 additions & 1620 deletions
This file was deleted.

‎scripts/ui-import/README.md‎

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,17 @@ their own changes after the cutover.
3838

3939
# ui-import: the objectui side of the release-lane merge (objectstack#25711)
4040

41-
`4a-ui-side.patch` is the `ui/` half of sub-issue 4a of objectstack#25677: it removes
41+
This is the record of the `ui/` half of sub-issue 4a of objectstack#25677. It removed
4242
objectui's pin on objectstack (`.objectstack-sha`, `.objectstack-pin/`, the scripts that
4343
read them), the dist-injection Vite probes, objectui's own release lane and its own
44-
Changesets config. It is a patch file and not tree edits because `ui/` does not exist on
45-
`main` until the subtree PR of sub-issue 5 lands; it is applied in that cutover window,
46-
right after the subtree PR, together with the root half of 4a.
44+
Changesets config. While `ui/` did not exist on `main` it was carried as a patch file,
45+
`4a-ui-side.patch`. In the cutover sitting, right after the subtree PR (objectstack#25825)
46+
landed on `main` (`fd40831416`), 4a's own PR (objectstack#25745) applied it as tree edits
47+
together with the root half of 4a, and deleted the patch file in the same commit.
4748

48-
## What it changes
49+
## What it changed
4950

50-
Deleted (step 2 below; the patch carries only modifications and additions, so the
51-
deleted files' lines are not repeated here):
51+
Deleted (step 2 below):
5252

5353
- the pin: `.objectstack-sha`, `.objectstack-pin/` (7 packed manifests),
5454
`scripts/bump-objectstack.sh`, `scripts/objectstack-pin.mjs`,
@@ -68,7 +68,7 @@ deleted files' lines are not repeated here):
6868
`quick-reference-current-release-4143` pin. Its only release-path caller was
6969
`changeset-release.yml`, deleted above.
7070

71-
Changed by the patch:
71+
Changed (step 3 below):
7272

7373
- `scripts/vite-single-zod.ts` (new): the single-zod build guard, moved out of the deleted
7474
spec probe because it runs in every console build. `apps/console/vite.config.ts` drops
@@ -96,9 +96,9 @@ Changed by the patch:
9696
`quick-reference-commands-4149.test.ts`: their pin, release-lane and release-sync
9797
rows.
9898

99-
## Apply
99+
## How it was applied
100100

101-
From the monorepo root, on the tree the subtree PR produced:
101+
From the monorepo root, after `git merge origin/main` brought the subtree in:
102102

103103
```sh
104104
# 1. Not here: objectui's 65 pending ui/.changeset/*.md stay under ui/ for the
@@ -132,15 +132,17 @@ git rm -r -q --ignore-unmatch -- \
132132
ui/scripts/__tests__/vite-objectstack-client-dist.test.ts \
133133
ui/scripts/__tests__/vite-objectstack-spec-dist.test.ts
134134

135-
# 3. The modifications and the three new files.
136-
git apply --directory=ui --check scripts/ui-import/4a-ui-side.patch
137-
git apply --directory=ui scripts/ui-import/4a-ui-side.patch
135+
# 3. The modifications and the three new files: `git apply --directory=ui` of
136+
# 4a-ui-side.patch, deleted in the same commit.
137+
138+
# 4. The SDUI manifest regenerated from ui/ for the merged tree (107 -> 106
139+
# components; objectui#13449 retired `html`): sdui.manifest.json and
140+
# scripts/sdui-manifest.record.json, from the patch the 4b PR 2a thread measured.
138141
```
139142

140-
The patch is written against the verification branch head `9e37acd126` (objectstack#25697,
141-
the run 8 tree: objectui `main` imported under `ui/` plus the adaptations). Before the
142-
cutover, run step 3's `--check` against the final tree and regenerate the patch if it
143-
fails (sub-issue 5 owns that re-check).
143+
The patch was written against the verification branch head `9e37acd126` (objectstack#25697,
144+
the run 8 tree) and re-checked with `git apply --check` on the cutover heads `1c0d02eda4`
145+
and `c04b36dcb9` and on `main` at `fd40831416` before it was applied.
144146

145147
## Verify
146148

‎sdui.manifest.json‎

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1603,7 +1603,7 @@
16031603
"name": "sections",
16041604
"type": "array",
16051605
"of": "object",
1606-
"description": "Field groups rendered as the detail body, in order. Every entry is an OBJECT — `{ name?, label?, columns?, fields }` — a bare section-id string is NOT accepted (the spec retired that spelling in objectstack#5611, and the renderer reads name/label/fields off each entry, so a string entry renders no fields at all). `fields` are the field names shown in this section, in order — required unless `group` supplies the members instead (the spec refuses a section carrying neither, and refuses one carrying both). `label` is the section heading; omit it for an untitled, borderless section. `name` is a stable snake_case identifier and the i18n anchor — the heading resolves through objects.<object>._sections.<name>.label, so a section without a name shows its authored label in every locale. `columns` (1-4) is THIS section's field-grid width; omit it and the renderer derives the width. Authoring `sections` at all makes it the only source of the detail body; omit it and the body falls back to the object's highlightFields. @objectstack/spec 17.3.0 declares eight more member keys on an entry, and this renderer honours all eight: `icon` (a Lucide name on the section header), `description` (sub-heading copy under the heading), `collapsible` and `defaultCollapsed` (a foldable section and its initial state), `showBorder` (force the Card wrapper on or off, overriding the heading-derived default) and `headerColor` (a header tint from the shared palette) through DetailSection, plus `group` — the ADR-0085 §5 REFERENCE form, the alternative to enumerating `fields`. `{ group: 'contact_info' }` inherits the object's `fieldGroups` entry with that key: its members (every visible field pointing at it, in declaration order), its presentation (label, icon, description, collapse) and its `visibleWhen` all come from the group, so the section restates none of it — the predicate is evaluated against the bound record exactly as the entry form evaluates it, and a group it hides renders nothing (a `visibleWhen` written on a section itself is refused by the spec and not read: gate the group and reference it) and the spec refuses those keys beside `group`; `columns`, `showBorder` and `headerColor` stay yours because they are how THIS page lays the section out. A `group` naming no declared group renders nothing and is reported to the console (`@objectstack/lint` flags it as `page-section-group-unknown`). `hideEmpty` is the eighth, and it decides whether an ALL-empty section exists: it defaults to on, so a section whose fields are every one of them empty renders nothing at all — no heading, no skeleton — and `hideEmpty: false` is the spelling that keeps that heading and its label skeleton on a brand-new record. It decides ONLY the all-empty case; the empty rows of a section that still has a filled one belong to DetailSection's auto-hide heuristic plus the reader's show-empty toggle, which no authored value overrides in either polarity (objectui#7129 Q2-C), and inline-edit mode renders the section either way so its fields stay reachable. Restored under objectui#8603 (maintainer 2026-09-15) after objectui#7129 retired it on the premise, since falsified upstream, that the spec refused the key. None of the eight has a designer control yet; they are authorable in source mode only, tracked as a deferred feature. @objectstack/spec 18 declares a ninth, `count` (`{ field }`): the renderer fills the heading's `{{ count }}` hole with how many values that multi-value field holds on the current record — `{ name: 'tagging', label: '{{ count }} tags', count: { field: 'tags' }, fields: ['tags'] }` reads `3 tags` when three are selected. An absent or empty value counts 0; `count` changes only the heading, never whether the section renders, so with `hideEmpty` on an all-empty section is still absent. The hole is filled after the heading is translated, so each locale of an inline label map and a translated objects.<object>._sections.<name>.label write the same `{{ count }}`. The spec refuses `count` beside `group`, on a section with no `label`, and on a label with no hole; a heading on a section without `count` prints as written. Like the eight, `count` has no designer control yet."
1606+
"description": "Field groups rendered as the detail body, in order. Every entry is an OBJECT — `{ name?, label?, columns?, fields }` — a bare section-id string is NOT accepted (the spec retired that spelling in objectstack#5611, and the renderer reads name/label/fields off each entry, so a string entry renders no fields at all). `fields` are the field names shown in this section, in order — required unless `group` supplies the members instead (the spec refuses a section carrying neither, and refuses one carrying both). `label` is the section heading; omit it for an untitled, borderless section. `name` is a stable snake_case identifier and the i18n anchor — the heading resolves through objects.<object>._sections.<name>.label, so a section without a name shows its authored label in every locale. `columns` (1-4) is THIS section's field-grid width; omit it and the renderer derives the width. Authoring `sections` at all makes it the only source of the detail body; omit it and the body falls back to the object's highlightFields. @objectstack/spec 17.3.0 declares eight more member keys on an entry, and this renderer honours all eight: `icon` (a Lucide name on the section header), `description` (sub-heading copy under the heading), `collapsible` and `defaultCollapsed` (a foldable section and its initial state), `showBorder` (force the Card wrapper on or off, overriding the heading-derived default) and `headerColor` (a header tint from the shared palette) through DetailSection, plus `group` — the ADR-0085 §5 REFERENCE form, the alternative to enumerating `fields`. `{ group: 'contact_info' }` inherits the object's `fieldGroups` entry with that key: its members (every visible field pointing at it, in declaration order), its presentation (label, icon, description, collapse) and its `visibleWhen` all come from the group, so the section restates none of it — the predicate is evaluated against the bound record exactly as the entry form evaluates it, and a group it hides renders nothing (a `visibleWhen` written on a section itself is refused by the spec and not read: gate the group and reference it) and the spec refuses those keys beside `group`; `columns`, `showBorder` and `headerColor` stay yours because they are how THIS page lays the section out. A `group` naming no declared group renders nothing and is reported to the console (`@objectstack/lint` flags it as `page-section-group-unknown`). `hideEmpty` is the eighth, and it decides whether an ALL-empty section exists: it defaults to on, so a section whose fields are every one of them empty renders nothing at all — no heading, no skeleton — and `hideEmpty: false` is the spelling that keeps the section on a brand-new record: in read-only mode as its heading plus one fold row that counts the empty fields and reveals them on request (the same fold a partly-filled section uses, objectui#13386), in edit mode as every field an editable row. It decides ONLY the all-empty case; the empty rows of a section that still has a filled one belong to DetailSection's auto-hide heuristic plus the reader's show-empty toggle, which no authored value overrides in either polarity (objectui#7129 Q2-C), and inline-edit mode renders the section either way so its fields stay reachable. Restored under objectui#8603 (maintainer 2026-09-15) after objectui#7129 retired it on the premise, since falsified upstream, that the spec refused the key. None of the eight has a designer control yet; they are authorable in source mode only, tracked as a deferred feature. @objectstack/spec 18 declares a ninth, `count` (`{ field }`): the renderer fills the heading's `{{ count }}` hole with how many values that multi-value field holds on the current record — `{ name: 'tagging', label: '{{ count }} tags', count: { field: 'tags' }, fields: ['tags'] }` reads `3 tags` when three are selected. An absent or empty value counts 0; `count` changes only the heading, never whether the section renders, so with `hideEmpty` on an all-empty section is still absent. The hole is filled after the heading is translated, so each locale of an inline label map and a translated objects.<object>._sections.<name>.label write the same `{{ count }}`. The spec refuses `count` beside `group`, on a section with no `label`, and on a label with no hole; a heading on a section without `count` prints as written. Like the eight, `count` has no designer control yet."
16071607
},
16081608
{
16091609
"name": "fields",
@@ -3738,17 +3738,6 @@
37383738
}
37393739
]
37403740
},
3741-
"html": {
3742-
"type": "html",
3743-
"namespace": "ui",
3744-
"inputs": [
3745-
{
3746-
"name": "html",
3747-
"type": "string",
3748-
"description": "Raw HTML content"
3749-
}
3750-
]
3751-
},
37523741
"h1": {
37533742
"type": "h1",
37543743
"namespace": "ui",

‎ui/.changeset/config.json‎

Lines changed: 0 additions & 60 deletions
This file was deleted.

‎ui/.github/pull_request_template.md‎

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)