Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
aabc527
chore(deps): resolve @objectstack/spec at 17.3.0 in the lockfile
os-sam Sep 5, 2026
2d11879
Merge remote-tracking branch 'origin/main' into claude/issue-7122-spe…
claude Sep 5, 2026
952d2ec
fix(app-shell,scripts): reconcile the declared-symbol surface with @o…
claude Sep 5, 2026
59ea811
test(types,plugin-form,auth): re-point the citation-stripped pins at …
claude Sep 5, 2026
dcd0dfa
chore(changeset): declare the app-shell/auth reconciliation the 17.3.…
claude Sep 5, 2026
ed37005
fix(core): re-derive the spec action-key inventory for 17.3.0's `oper…
claude Sep 5, 2026
36baa6d
docs(auth): state the preview-mode provenance without a version liter…
claude Sep 5, 2026
1546e59
chore(deps): resolve the @objectstack/* family at 17.3.0 so the spec …
os-sam Sep 5, 2026
33abf58
test(types): re-point the select-option pins at 17.3.0's authoring bo…
os-sam Sep 5, 2026
f389bec
chore(deps): collapse the postcss duplicate the first lockfile bump i…
os-sam Sep 5, 2026
339885d
Merge remote-tracking branch 'origin/main' into claude/issue-7122-spe…
claude Sep 5, 2026
9c1a1ac
wip(spec-17.3.0): parity reconciliation in progress — INCOMPLETE AND …
claude Sep 5, 2026
fa73d58
Merge remote-tracking branch 'origin/main' into claude/issue-7122-spe…
claude Sep 5, 2026
2761082
wip(spec-17.3.0): two files in progress — INCOMPLETE AND UNREVIEWED
claude Sep 5, 2026
dc82492
fix(spec-17.3.0): carry the ninth platform capability, and pin refusa…
claude Sep 5, 2026
e328e36
fix(spec-17.3.0): harvest three exemptions the contract outgrew, and …
claude Sep 5, 2026
5ac59ff
Merge remote-tracking branch 'origin/main' into claude/issue-7122-spe…
claude Sep 6, 2026
34a1578
docs(changeset): describe the 17.3.0 capability carry and the pin re-…
claude Sep 6, 2026
901c4b8
chore(budget): raise the eager-closure ceiling once, on maintainer au…
claude Sep 6, 2026
a5506fe
fix(app-shell,plugin-designer): declare the lookup guard's stricter-t…
claude Sep 6, 2026
3042e4f
test(plugin-form,console): tighten CITES_ITS_RULING, and make the fou…
claude Sep 6, 2026
bd79199
docs(changeset): grade objectui's own breaking behaviour `minor`, wit…
claude Sep 6, 2026
7be4b24
Merge remote-tracking branch 'origin/main' into claude/issue-7122-spe…
claude Sep 6, 2026
03c0e05
Merge remote-tracking branch 'origin/main' into claude/issue-7122-spe…
claude Sep 6, 2026
36d33fc
Merge origin/main into claude/issue-7122-spec-pin-17-3-0
claude Sep 6, 2026
a31c2e5
ci(live-e2e): move the backend pins to 17.3.0 with the matching showc…
claude Sep 6, 2026
3045a13
Merge origin/main into claude/issue-7122-spec-pin-17-3-0
claude Sep 6, 2026
f1e02a8
docs(plugin-list): give the view-type map its tenth member, `page`
claude Sep 6, 2026
fed2432
Merge origin/main (bdb4dbd58) — the lookup guard comes from #8076, no…
claude Sep 7, 2026
f7c4d78
chore(changeset): drop the lookup-guard declaration — this branch no …
claude Sep 7, 2026
553a6db
Merge origin/main (0fa7a9c83) — the #8137 calibration control is fixe…
claude Sep 7, 2026
d05b866
test(console): ledger the three blocks @objectstack/spec 17.3.0 adds …
claude Sep 7, 2026
7f3dd85
fix(types): raise the declared @objectstack/spec floor to ^17.3.0
claude Sep 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .changeset/7122-capability-manage-org-presentation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
'@object-ui/fields': patch
'@object-ui/i18n': patch
---

Carry `manage_org_presentation`, the ninth platform capability (objectui#7122).

`@objectstack/spec` 17.3.0 declares a ninth member of `PLATFORM_CAPABILITIES`
and the capability picker's curated set carried eight, so
`CapabilityMultiSelectField` fell back to the `sys_capability` registry's
English label for it in every locale — the exact defect objectui#6285 filed
when `manage_sharing` did the same thing.

The label is the spec artifact's own (`Manage Organization Presentation`), read
off the installed build rather than invented, and it is authored everywhere the
widget's docblock requires of any edit to that list: `useFieldTranslation.ts`
and all ten locale packs. Each non-English string is composed from that pack's
own established sibling vocabulary (`manage_org_users`,
`manage_platform_settings`) rather than machine-translated; a native review pass
is welcome on the nine, and nothing about the capability's behaviour depends on
the wording.

The parity pin is unchanged and still fails on ANY difference in either
direction, which is what made this visible before it reached a screen.
50 changes: 50 additions & 0 deletions .changeset/7122-eager-closure-ceiling-raise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
---

Raise the console eager-closure ceiling once, on explicit maintainer
authorisation, to the measured cost of `@objectstack/spec` 17.3.0
(objectui#7122). Tooling only; no package is released by this change.

Raising a gate ceiling is a gate weakening and sits on the manual floor, so it
is a human's decision. The authorisation, verbatim:

维护者 sam@objectstack.ai 于本轮明确授权:「抬上限,把 7685 弄绿」

recorded on objectui#7122 as decision batch 1 item 1 = "B + A": a one-time,
cause-recorded adjustment of exactly the measured delta, with the upstream card
filed alongside it.

**What the bytes buy — this is NOT routine growth.** The residue is
`@objectstack/spec` 17.3.0's own browser-dist growth: +292.2 KB gzip on the spec
package alone, whose measured mechanism is that 17.3.0 lengthened the Zod
`.describe()` doc strings shipped in the browser build. It is authoring
documentation prose, delivered on every page load.

**It is not duplication.** That was the larger, separate problem and it is
already fixed: resolving the spec alone to 17.3.0 shipped two copies of it, and
moving the family together in the lockfile collapsed that (−671 KB; markers
unique to 17.2.0 fell from 92.3% to 1.0% of 104, the single survivor accounted
for). No chunk entered or left the closure and the eager chunk count is
unchanged.

**The honest long-term fix is upstream**, and this ceiling is the marker for it
rather than the answer to it: a `describe()`-stripped browser build returns
~292 KB to every consumer of the spec, not just this console. Filed as
objectstack#16063, and recorded in the gate as the restore condition — when it
lands, re-measure and bring the ceiling and its baseline back down together.

Four constants move as two ceiling/baseline pairs, measured by `pnpm build`
(exit 0, 43/43) on `34a1578ef`:

| constant | from | to | headroom vs the 91,136-byte regression |
|---|---|---|---|
| `MAX_EAGER_CLOSURE_GZIP_BYTES` | 3,268,000 | 3,597,000 | 45,809 = 0.50x |
| `BASELINE.gzipBytes` | 3,222,314 | 3,551,191 | — |
| `PER_CHUNK_GZIP_CEILINGS['vendor-objectstack']` | 967,000 | 1,254,000 | 18,971 = 0.21x |
| `PER_CHUNK_BASELINE['vendor-objectstack']` | 948,461 | 1,235,029 | — |

Both ratios match the proportions the retiring pairs carried (0.50x and 0.20x),
so the gate keeps failing on a repeat of the 89 KiB regression that motivated
it. No other exemption was added, no import was made lazy, and the three
per-chunk lines that still pass — `i18n-locales`, `framework`, `ui-components` —
were left exactly as they are.
22 changes: 22 additions & 0 deletions .changeset/7122-objectstack-family-17-3-0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
'@object-ui/data-objectstack': patch
---

Reconcile `@object-ui/data-objectstack` with the `@objectstack/*` family at
17.3.0 (objectui#7122).

`@objectstack/client`, `core`, `formula` and `lint` each pin `@objectstack/spec`
EXACTLY, so resolving the spec alone to 17.3.0 left the console bundling TWO
copies of it. Moving the family with it in `pnpm-lock.yaml` collapses the
duplicate; every declared range already admitted 17.3.0, so no manifest moved.

The one source change the family bump forces is a type reconciliation, not a
behaviour change. `client.analytics.query` resolved to `Promise<any>` at 17.2.0
and resolves to `Promise<AnalyticsResult>` at 17.3.0, so the pre-envelope
branches of `aggregate`'s row-shape fallback stopped type-checking. Those
branches are read through a widened alias rather than deleted: the client's own
docblock records the runtime change behind the narrower type ("BREAKING since
objectstack#13079 — read `result.rows`, not `result.data.rows`"), and deleting
them is a runtime compatibility decision about servers older than that, not a
type repair. The alias restores exactly the compile-time latitude 17.2.0 gave
the same expression and changes no runtime byte of it.
19 changes: 19 additions & 0 deletions .changeset/7122-postcss-dedupe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
---

Dev-time only: collapse the `postcss` duplicate this branch's first lockfile
bump introduced (objectui#7122).

`aabc527cb` resolved `@objectstack/spec` to 17.3.0 and, as a side effect of that
install, re-resolved `autoprefixer`'s auto-installed `postcss` peer to 8.5.28
while `@tailwindcss/postcss` kept 8.5.26. `@object-ui/cli` depends on both and
declares `postcss` itself, so its type-check program held TWO postcss copies
with two structurally distinct `Plugin` types — and comparing
`Plugin & ExportedAPI` against `Plugin` across them exceeded the compiler's
instantiation budget: `TS2321: Excessive stack depth`, in a file this branch
never touched. `origin/main` carries one copy for that pair and is green.

The split is resolved in the lockfile only. All eight manifests that declare
`postcss` already declare `^8.5.26`, which admits 8.5.28, so no declared range
moved and no published dependency declaration differs by a byte. Empty
frontmatter is the deliberate "no release" declaration.
89 changes: 89 additions & 0 deletions .changeset/7122-spec-17-3-0-parity-reconciliation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
---
'@object-ui/types': minor
'@object-ui/components': patch
'@object-ui/cli': patch
'@object-ui/plugin-detail': patch
---

Reconcile the declared surface with `@objectstack/spec` 17.3.0 (objectui#7122).

⚠️ **`@object-ui/types` is graded `minor` for a breaking surface change.**
The exported `ObjectSchemaClientExtensions` narrows from

```ts
export interface ObjectSchemaClientExtensions { editMode?: 'modal' | 'page' }
```

to

```ts
export type ObjectSchemaClientExtensions = Record<never, never>;
```

Two breaking consequences for a consumer that names the type directly. **(1)** It
no longer declares `editMode`; the key is now carried by the spec's
`ServiceObject`, so `ObjectSchemaMetadata` still has it, but code written against
the extension type ALONE loses it. **(2)** `interface` → type alias also ends
**declaration merging**: a consumer that reopened
`declare module '@object-ui/types' { interface ObjectSchemaClientExtensions { … } }`
to add its own client-side member no longer compiles, because an alias cannot be
reopened. `minor` rather than `major` per `AGENTS.md`'s version-alignment rule —
objectui's own breaking changes are graded `minor` with the semantics stated in
the body, since any `major` in the fixed group would push all 39 packages off
`@objectstack`'s major.

**`ObjectSchema.editMode` is now the spec's.** 17.3.0 adopted the key (measured:
the accept set went 42 → 43, gained set exactly `['editMode']`, lost set empty,
declared as the same `'page' | 'modal'` union objectui carried). Its local copy
is retired from `ObjectSchemaClientExtensions`, which is what that type's own pin
prescribed for this event, leaving the client delta empty. Nothing is removed
from the product: `editMode` stays authorable and stays typed on
`ObjectSchemaMetadata`, carried by the spec's `ServiceObject` instead of by a
local member — and a published, spec-validated object document may now carry it,
which at 17.2.0 was refused by name.

**`user:profile` is retired across all three sites.** 17.3.0 dropped it from
`PageComponentType` (measured: the enum went 34 → 32 options, lost set exactly
`['user:profile', 'element:form']`, gained set empty). objectui went on knowing
it in three places, so all three moved together: the Studio palette exclusion
ledger, `PROTOCOL_COMPONENTS` in `renderers/placeholders.tsx`, and the
regenerated `known-schema-types.ts` the CLI checks schemas against. Nothing
user-reachable went with it — neither type had a renderer, `user:profile` had
only the dashed "Component Placeholder" scaffold, and the app shell's own
profile affordance is a React slot, never this block type. A page schema still
naming it now draws the loud "Unknown component type" panel rather than a silent
grey box, which is this repo's standing treatment for a type outside the
supported surface.

**`record:details` sections document the eight keys 17.3.0 added.**
`group`, `hideEmpty`, `collapsible`, `showBorder`, `defaultCollapsed`, `icon`,
`description` and `headerColor` are now declared on a section entry (4 → 12
members). Six of the eight are already honoured by `DetailSection`, so the
`sections` input description now teaches all of them, and says plainly which two
are not read here. Designer controls for them are a separate feature and are
deliberately not added.

**`@object-ui/types` raises its declared `@objectstack/spec` floor `^17.0.0` →
`^17.3.0`, and this is the second half of its `minor`.** The package's emitted
`dist/spec-report.d.ts` names `FilterCondition` from `@objectstack/spec`, which
`17.0.0` does not export, so the old range was a claim the artifact did not
support — `scripts/check-spec-range-floors.mjs` reports it as `[floor-too-low]`
and names `^17.3.0` as the lowest version carrying every symbol the package
references. Breaking for a consumer pinned below 17.3.0: it can no longer
resolve this package. That is the range stating the truth rather than a new
restriction — the artifact already required those symbols — and it is the
remedy the gate itself prescribes ("Raise that package's range to the lowest
version that exports the symbol… Do not add a tolerant re-declaration on this
side: the range is the claim, and the claim is what is wrong", objectui#5793).
`@object-ui/core` and `@object-ui/data-objectstack` already declare `^17.2.0`
and `@object-ui/plugin-detail` `^17.1.0`, so a floor above the family minimum is
this repo's normal state, not an exception.

⚠️ **Measured on both sides, because it is bump-caused rather than pre-existing
and objectui#7688 records the opposite.** The gate is a scheduled / push-to-main
workflow that cannot red a pull request, and `main` is green on it — the last
eight runs, most recently at `c2e3cee2c`. On this branch's built tree it exits 1
with CI's own `--cross-check` invocation, and exits 0 with this raise, judging
278 (subpath, symbol) pairs across 19 published packages either way. Its blocking
copy runs on the publish path, so leaving it would have surfaced as a cancelled
release rather than as a red check. The correction is recorded on objectui#7688.
49 changes: 49 additions & 0 deletions .changeset/7122-spec-17-3-0-pin-repointing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
---

Re-point the pins `@objectstack/spec` 17.3.0 moved, and harvest three
exemptions the contract outgrew (objectui#7122). Test only; no package is
released by this change.

- **The `#7496` family, 14 assertions across three files.** 17.3.0 kept every
`submitBehavior.url` refusal and its reasoning and only restated provenance as
`(ruled 2026-08-11)`. The pins asserted the citation FORM, not the citation —
objectui#7702's defect shape — so they now assert the durable property via a
documented `CITES_ITS_RULING`, which discriminates the spec's prose from a
locally hand-written sentence. Deliberately not re-pinned to the new prose
verbatim, which would move the brittleness rather than remove it.
- **`CITES_ITS_RULING` is `/\(ruled \d{4}-\d{2}-\d{2}(?: on #\d{3,})?\)/`,
and its first spelling was not good enough.** That draft was
`/\(ruled \d{4}-\d{2}-\d{2}\)|#\d{3,}/`, whose loose alternative
discriminated NOTHING — this repo's own hand-written messages routinely cite
`objectui#NNNN`, so a local sentence satisfied it, and telling those two apart
is the assertion's whole job. It was also unnecessary: measured on both
installed artifacts, 17.2.0 says `(ruled 2026-08-11 on #7496)` and 17.3.0 says
`(ruled 2026-08-11)`, so the issue number never appears outside that
parenthesis and `(ruled ` + a date already matched both. The optional
` on #NNNN` tail keeps the 17.2.0 spelling admissible without admitting a bare
local `#7122`.
- **The fourth file joined the other three.**
`packages/plugin-form/src/submitRedirect.test.ts` had been re-pointed to the
literal `'ruled 2026-08-11'` while its three siblings used the shape — the
same brittleness one word along, a date instead of an issue number, and four
files disagreeing about what the pinned property is. It now uses
`CITES_ITS_RULING` too.
- **`object-grid.defaultSort` became an ADR-0087 D2 tombstone**, so its
unpublished-key exemption, its GA-pending entry and its carve-out row are
deleted — the ninth harvest by the mechanism the eight before it were designed
to die by. The block's prose claiming a tombstone would NOT make an entry
stale is corrected; its own cited counter-example was harvested that way.
- **`OFF_SPEC_ARM_EXEMPTIONS` is now empty.** `element:number.filter` accepts
the array form (objectui#6206) and `object-grid.data` accepts the
discriminated `ViewDataSchema` object (objectui#6207) — both converged
upstream in the direction their own reasons named, with no declaration edited.
Both issues are closable as resolved-upstream.
- **Two negative pins re-derived, not inverted.** The `object-master-detail-form`
`formType` boundary now refuses what it used to admit (`invalid_value`, plus a
bespoke ADR-0001 prescription for `wizard`), and the location value schema is
now strict (`unrecognized_keys` naming the retired `latitude`/`longitude`
pair). Each pin records the new fact, keeps a control opposite it, and pins the
refusal's SHAPE. The `LocationField` fence explicitly re-derives why its
key-level assertions stay: no parse stands on the emit path, so strictness
changed the consequence of a spread regression, not the widget's exposure.
25 changes: 25 additions & 0 deletions .changeset/7122-spec-17-3-0-reconciliation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
'@object-ui/app-shell': patch
'@object-ui/auth': patch
---

Reconcile `@object-ui/app-shell` with `@objectstack/spec` 17.3.0 (objectui#7122).

`SchemaDiffEntryKind` gained an `unreachable` member in 17.3.0, and the external
datasource validation panel labels those kinds through a map that is TOTAL over
the union on purpose — so an upstream addition fails the build rather than
rendering a blank cell. That mechanism fired: the package did not compile against
17.3.0 until the kind was labelled. It now reads "Not checked — remote
unreachable", following the spec's own ruling that this kind asserts nothing
about the remote schema and must never be surfaced as "schema changed": it means
introspection could not complete, which is often transient, and labelling it like
a mismatch would tell an operator to repair a schema nobody has read.

Two internal flow-inspector types were renamed (`FlowNodeLike` →
`InspectorFlowNode` / `ScopeFlowNode`) because 17.3.0 began exporting its own
`FlowNodeLike`; neither name is in this package's published entry, so no consumer
import changes.

`@object-ui/auth`: a README sentence claiming the preview-mode prop aligns with
the spec's `PreviewModeConfig` is corrected — 17.3.0 removed that symbol. The
`previewMode` prop itself is host-supplied, unchanged, and unaffected.
8 changes: 8 additions & 0 deletions .changeset/spec-17-3-0-lockfile-bump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
---

Dev-time only: move the `@objectstack/spec` resolution in `pnpm-lock.yaml` from
17.2.0 to 17.3.0. No published package changes — every manifest's declared range
(`^17.0.0` / `^17.1.0` / `^17.2.0`) already admitted 17.3.0, so no floor moved and
no package's dependency declaration differs by a byte. Empty frontmatter is the
deliberate "no release" declaration for a change that publishes nothing.
51 changes: 44 additions & 7 deletions apps/console/src/__tests__/masterDetailFormTypeManifest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,52 @@ describe('object-master-detail-form.formType — the manifest carries the closed
},
);

it('⚠️ does NOT make the value rejected at the publish boundary (objectui#5155)', async () => {
// The other half of the honest reading. objectstack owns this schema; the
// objectui enum cannot narrow it, and a reader who stopped at the test above
// would conclude the value is now impossible to publish. It is not.
it('AND the publish boundary rejects it too, since spec 17.3.0 (objectui#5155)', async () => {
// The other half of the honest reading — and it REVERSED at
// `@objectstack/spec` 17.3.0, which is why this test now says the opposite
// of what it used to.
//
// It was written as a negative pin: objectstack owns this schema, the
// objectui enum cannot narrow it, and a reader who stopped at the manifest
// assertions above would wrongly conclude the value was impossible to
// publish. That was true and worth pinning while the boundary accepted
// `formType: 'wizzard'`. 17.3.0 closed the gap deliberately — not a
// silent narrowing: the schema answers `invalid_value` naming the two
// honoured options, and for the near-miss `'wizard'` it carries a bespoke
// prescription citing ADR-0001 and the renderer measurement behind it
// ("only the current wizard step's fields mount … so parent + details never
// save through the atomic batch").
//
// ⛔ The premise did not merely evaporate, so this is not an inverted
// assertion standing where a negative control used to. What the test owes
// its reader is the RELATIONSHIP between the two authorities, and that is
// what is pinned: the manifest diagnostic above and the publish boundary
// here now agree, and each is checked on its own so a future divergence
// fails HERE rather than reaching an author as a value that lints clean and
// then cannot be published.
const spec: any = await import('@objectstack/spec/ui');
const schema = spec.ObjectMasterDetailFormPropsSchema;
expect(schema, 'ObjectMasterDetailFormPropsSchema is not exported').toBeDefined();
expect(schema.safeParse({ objectName: 'po', details: [], formType: 'wizzard' }).success).toBe(
true,
);

// Positive control first: the boundary still admits the honoured pair, so a
// wholesale schema breakage cannot read as "the refusal works".
for (const honoured of ['simple', 'tabbed']) {
expect(
schema.safeParse({ objectName: 'po', details: [], formType: honoured }).success,
`the boundary stopped accepting the honoured value ${honoured}`,
).toBe(true);
}

const refused = schema.safeParse({ objectName: 'po', details: [], formType: 'wizzard' });
expect(refused.success).toBe(false);
if (refused.success) return;

// The SHAPE of the refusal, not just its existence: a value refusal at the
// key. `unrecognized_keys` would mean the key stopped being declared, and a
// `custom` refinement would mean it is refused by a cross-field rule rather
// than by its own vocabulary — three different facts, and only one of them
// is "the enum closed".
const own = refused.error.issues.filter((i: any) => i.path.join('.') === 'formType');
expect(own.map((i: any) => i.code)).toEqual(['invalid_value']);
});
});
Loading
Loading