Repository navigation
Commit c23cfb3
feat(spec)!: split the assembled-stage package API declarations off ./api into @objectstack/spec/api-assembled (#20052)
Fixes #18576
Clause-②: yes (narrowing)
Ruling `5714238181` (batch #145 item 1, letter **B**, 「同意,其他也同意」): split
`./api` so the browser-facing half no longer carries the
assembled-package (datasource/driver) declarations. This PR does the
export-usage measurement first, finds that no objectui consumer uses a
moved name, and then makes the cut.
## Patch round 1 (after the at-tier PASS `5824354899` on `4c6babc4ae`)
Its non-blocking recommendations, and nothing else. Head is now
`12822df4fb`.
- **Clause-② arm.** The spec changeset's line and line 2 of this body
now read `Clause-②: yes (narrowing)`. The diff widens one surface (the
new `./api-assembled`) and narrows another (13 names leave `./api`),
which is the `yes (narrowing)` combination in
`scripts/pm/clause2-line.mjs`. `check-adr-0087-registration` now reads
the changeset as `[BREAKING+bang+clause-②-narrowing]`. The client
changeset carries no Clause line and needs none: its published types are
unchanged, and only their import specifier moved.
- **Stale pointers the cut made false**, each fixed at the source:
- `packages/spec/browser-reachable-entries.json`: the `./api` row's
`notAnOutlier` now says one of **sixteen** unjudged entries (the
ledger's `unjudged` array holds 16). The fifteen/twelve/fourteen figures
of its weight scan are anchored to the tree that scan ran on, and
`./api-assembled` is named as the sixteenth, not in that scan. No gate
reads this prose: `check-browser-reachable-entries.ts` reads only the
section keys.
- `packages/spec/src/kernel/package-registry.zod.ts`:
`AssembledInstalledPackageSchema` is cited at
`../api/package-api-assembled.zod.ts`.
- `packages/spec/src/api/package-lifecycle.zod.ts`:
`PackageApiContracts.rollbackPackage` is cited at
`./package-api-assembled.zod.ts`. The same header also said the
route-ledger resolver looks names up "only in `@objectstack/spec/api`",
which is false since the split, and now names both entries.
`content/docs/references/api/package-lifecycle.mdx` was regenerated by
`gen:schema` + `gen:docs`.
- Found by the extra sweep: `packages/spec/src/api/index.ts` (the
book-tree re-export comment said the resolver "searches only
`@objectstack/spec/api`", now both entries). Also
`packages/spec/src/api/package-api.zod.ts`, which had two `{@link
InstalledPackageAtEitherStageSchema}` references to a symbol no longer
in that file's scope; they are now a code span plus the sibling file.
- Reviewed and left: the `responseSchema` field docs of the rest, auth,
i18n and storage route ledgers say names resolve against
`@objectstack/spec/api` exports. That is still true of every row they
hold, and they name no moved symbol. The historical migration-registry
entries and `.changeset/*` stock record the past and were not edited.
- **CI red on the intermediate push `05383b5e9c`, fixed:** `Type Check ·
source gates` failed `check:docs` with
`content/docs/references/api/package-lifecycle.mdx (out of date)`. That
was the pointer edit landing before its page was regenerated.
`12822df4fb` carries the generated page, and `check:docs` answers `226
generated files in sync with packages/spec`.
## 1. Export-usage measurement (first deliverable)
objectui at `62597c5880`, which **is** the pinned `.objectui-sha`
(`62597c588072636e9c30ea35b3d89b1e46fd765d`). Every non-test `import …
from '@objectstack/spec/api'` / `import('@objectstack/spec/api')` in
objectui:
| objectui file | kind | names | declaring module in spec | reaches the
datasource/driver tree? |
| --- | --- | --- | --- | --- |
| `core/src/utils/column-sortability.ts` | value + type |
`FIELD_UNSORTABLE_VIRTUAL_TYPE`, `FIELD_SORTABLE_UNPROVISIONED_ANCHOR`;
types `FieldSortability`, `ObjectSortability` | `api/sortability.zod.ts`
| no (closure 50 modules, no stack/datasource/driver) |
| `data-objectstack/src/metadata-client.ts` | value + type |
`GetMetaItemLayeredResponseSchema`; types `GetMetaItemLayeredResponse`,
`PublishPackageDraftsResponse`, `RuntimeAuthoringIssue` |
`api/protocol.zod.ts` | no (closure 79) |
| `app-shell/src/views/metadata-admin/clientValidation.ts` | dynamic
value | `ApiEndpointSchema` | `api/endpoint.zod.ts` | no (closure 29) |
| `plugin-chatbot/src/usePendingActions.ts` | type only |
`ApproveAiPendingActionResponse`, `RejectAiPendingActionResponse` |
`api/protocol.zod.ts` | no |
| `react/src/utils/error-message.ts` | type only | `ApiError` |
`api/contract.zod.ts` | no |
| `types/src/data.ts` | type only | `ExportJobStatus`, `ExportFormat`,
`ImportJobStatus`, `ImportRowResult`, `ImportWriteMode` |
`api/export.zod.ts` | no |
Re-scan beyond the card's six: two more type-only sites —
`data-objectstack/src/index.ts` (`ApiError`) and `types/src/index.ts`
(`export type * as API from '@objectstack/spec/api'`, a type-only
namespace re-export). The card called all six "value imports"; three of
them are type-only and cost a bundle nothing.
**Which `./api` names pull the tree.** An esbuild metafile walk of every
module `src/api/index.ts` re-exports: exactly one, `package-api.zod.ts`,
reached `stack.zod` → `data/datasource.zod` → nine `data/driver/*`
modules, through one import (`RecordStagePackageBodySchema`). Inside it,
exactly five declarations need that import:
`AssembledInstalledPackageSchema`,
`InstalledPackageAtEitherStageSchema`,
`ListInstalledPackagesResponseSchema`,
`GetInstalledPackageResponseSchema`, and `PackageApiContracts` (which
names the two responses). **None of them is imported anywhere in
objectui** (0 hits across the whole objectui tree; control
`GetMetaItemLayeredResponseSchema`: 14 files).
Stop conditions: neither fired. No objectui site imports a moved name,
so no objectui import changes and no `@object-ui/*` API change is needed
for the six sites to keep resolving. One transitive note:
`@object-ui/types`'s type-only `API` namespace loses the moved names
when the pin bumps. objectui itself reads none of them through it.
## 2. The cut
- `src/api/package-api.zod.ts` → the five declarations (and their `X` /
`XParsed` types) move verbatim to
`src/api/package-api-assembled.zod.ts`. `package-api.zod.ts` no longer
imports `../stack.zod`.
- New entry **`@objectstack/spec/api-assembled`**
(`src/api-assembled/index.ts`, one `export *`), carrying the `browser`
condition (its graph still reaches the pg URL grammar, so it gets the
existing `swapServerOnlyGrammarArm` twin). `./api` **drops** its
`browser` condition: nothing in its graph links a server-only module any
more, and `tsup.config.ts` says the conditioned list must equal the
poisoned set.
- **Name, against the existing subpaths.** Every other subpath is one
protocol domain (`./data`, `./api`, …) plus one fine-grained hyphenated
entry (`./meta-spelling`). This one is a *packaging* split of the API
protocol, named by the property that sets its members apart: they carry
the **assembled** package body. `api-` keeps it next to `./api` in every
listing. It is not called `server`: the browser-reachability gate still
requires it to be bundler-feasible (its browser condition), and the
browser SDK's `.d.ts` imports a type from it, so "server-only" would be
a claim nothing enforces.
- The protocol **category** did not change.
`scripts/lib/split-entries.ts` declares `api-assembled` as a split entry
of `api`, so JSON Schema ids stay `api/NAME` (the published
`json-schema/api/` ids are unchanged; `json-schema.manifest/`,
`authorable-surface/`, `declaration-map/` byte-identical). `build-docs`
spells the page's import line from the entry that exports it,
`declaration-map` joins the split entry's origins into its home, and a
missing `json-schema/api-assembled/` is a declared state that expires if
the tree stops matching.
- In-repo importers of the moved names, all moved here:
`packages/client/src/index.ts` (type import),
`packages/client/src/return-type-precision.test.ts`,
`packages/runtime/src/domains/packages-read-delete-response-conformance.test.ts`,
`packages/spec/src/api/package-api.test.ts`. The route-ledger
`responseSchema` field (`packages/runtime/src/route-ledger.ts`) now
names an export of either API entry, and its resolver test resolves
against both. It also pins that the two entries share no name.
`examples/**` and `apps/**`: 0 importers.
**Does an existing import path stop resolving? Yes.** The 13 names (5
declarations plus their types) no longer resolve from
`@objectstack/spec/api`. That is **major** in the ruling's terms. Under
the launch-window convention (`check-changeset-no-major`) it ships as
`@objectstack/spec` **minor** with a **BREAKING** banner, a FROM → TO
table, and one ADR-0087 marker (`registered api-assembled-entry-split`,
a new D3 semantic entry; an import path is not metadata, so there is no
D2 conversion). `@objectstack/client` gets a `patch`, because its
published `.d.ts` now imports the type from the new entry. Runtime
publishes nothing changed: its built `dist/` holds 0 occurrences of the
edited ledger text, against the positive control `HttpDispatcher` in 4
files.
## 3. Size proof
Base `fc6ddb87a4` vs head `12822df4fb` (the consumer probes read
byte-identically at `5f845af5c4`), both built from source. esbuild
0.28.2, `platform: browser`, conditions `browser` + `import`, minified,
gzip -9, spec resolved through its `exports` map:
| probe | base gzip | head gzip | delta |
| --- | ---: | ---: | ---: |
| objectui `core/src/utils/column-sortability.ts`, bundled as-is |
311,124 | 166,529 | **−46.5%** |
| `metadata-client.ts`'s value import, verbatim | 311,182 | 166,616 |
−46.5% |
| `clientValidation.ts`'s dynamic `import()`, verbatim (pulls the whole
namespace) | 391,171 | 327,732 | −16.2% |
| whole `./api` namespace (contrast) | 387,421 | 324,465 | −16.3% |
| `./api` entry bundle (esm) | 612,813 | 469,800 | −23.3% |
`./api` source graph: 171 → 120 modules. The stack, datasource and
driver modules went from 11 to 0. `pg-connection-string` is linked 4× in
the base node bundle and 0× in the head. For history, #17535 measured
the regression as 132,121 → 261,221 on the narrowest consumer. The
remaining gap to 166,529 is the rest of `./api` growing since then, not
the assembled tree. The `browser-reachable-entries.json` `./api` weight
row is **replaced** with these readings, and its ablation was re-taken
at `5f845af5c4`: 2 problems (zod ×2), down from 4 (zod ×2 plus
`pg-connection-string` ×2).
## 4. Verification (head `12822df4fb`)
Gates were derived by `dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` at `12822df4fb`: 126 families, the same set
as round 0. All 126 were run on that head with exit codes recorded, and
`--ran` answered `126 derived famil(ies) accounted for — 126 run, 0
NOT-MEASURED (a DERIVED zero …)`. All 126 exited 0;
`check:pm-dispatch-gates` took 933.7s (1925 self-test cases). The
dist-reading gates ran against a full `turbo run build
--filter='./packages/*' --filter='./packages/*/*'` of this head (72
tasks). Highlights:
- `check:docs`: `226 generated files in sync with packages/spec`, which
is the CI red on `05383b5e9c`, fixed. `check:generated`,
`check:api-surface`, `check:export-origins`, `check:declaration-map`,
`check:authorable-surface`, `check:browser-reachable-entries` (5
browser-conditioned subpaths, positive control held),
`check:entry-nameability`, `check:dual-source-exports`,
`check:exported-any`, `check:llms-txt`, `check:skill-examples`: exit 0.
- `check:dual-build-cjs-loads`, `check:published-files`,
`check:lean-entry-closure`, `check:docs-spec-enumerations`,
`check:quick-reference-counts`, `check:type-check-debt`,
`check:nul-bytes`: exit 0.
- `check-adr-0087-registration --base origin/main`:
`.changeset/18576-api-assembled-entry-split.md
[BREAKING+bang+clause-②-narrowing] registered
api-assembled-entry-split`. `check-changeset-no-major`: `This diff
introduces no major bump`.
- Tests at this head: `@objectstack/spec` local project 534 files /
15665 passed. Spec repo project 30 of 31 files / 492 tests passed (the
31st is under NOT MEASURED). The client (7) and runtime (17) targeted
tests and the spec/client/runtime typechecks were green at `4c6babc4ae`;
this round changes no code they compile (comments, prose, a ledger
string, one generated page).
- **Pin + ablation** (round 0, `5f845af5c4`; this round touches neither
the pin nor the graph). `src/api/api-entry-graph.pin.test.ts` turned
red, 2 failed and 2 passed, when `src/api/index.ts` re-exported
`./package-api-assembled.zod`. Restored blob `404586349b` equals HEAD.
- **Reverse verification** (round 0, rebuilt `.d.ts`).
`ListInstalledPackagesResponseSchema` from `/api` fails with `TS2724 …
Did you mean 'InstallPackageResponseSchema'?`. From `/api-assembled` it
compiles with 0 diagnostics.
- PR mergeability read at `12822df4fb`: `mergeable: true`. Main moved
about 20 commits, touching `packages/spec` (including the generated
`src/migrations/registry.ts`) but none of the lines this diff owns, so
the branch was not merged. CI's merge ref covers it.
NOT MEASURED, declared to CI: `scripts/build-schemas-check-mode.test.ts`
(spec repo project). This round it queued three times and never acquired
the shared verify lock (3 × 540s, other seats' suites and builds held
it). In round 0 it did not finish inside the foreground window. This
round's diff does not touch `build-schemas.ts` or anything it reads.
## Acceptance notes
- The objectui half (move the six sites nowhere, since none uses a moved
name; bump the pin after the spec release) is the spec seat's card at
release time, per the ruling. It is not opened here.
- `cloud` is NOT MEASURED (not attached). Its consumers of the 13 moved
names are unknown.
- Main moved during the work. The only overlap with this derivation is
`scripts/engine-double-contract.pinned.json` (unrelated to this diff),
so the branch was not merged. CI's merge ref covers it.
---
_Generated by [Claude
Code](https://claude.ai/code/session_019c3Hi6ZMU1p6m6aA6Bz45d)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 9b8c74c commit c23cfb3
43 files changed
Lines changed: 1530 additions & 718 deletions
File tree
- .changeset
- content/docs
- deployment
- getting-started
- references
- api
- packages
- client/src
- runtime/src
- domains
- spec
- api-surface
- export-origins
- scripts
- lib
- src
- api-assembled
- api
- kernel
- migrations
- entries/semantic
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| 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 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
344 | 344 | | |
345 | 345 | | |
346 | 346 | | |
347 | | - | |
| 347 | + | |
348 | 348 | | |
349 | 349 | | |
350 | 350 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
126 | 126 | | |
127 | 127 | | |
128 | 128 | | |
129 | | - | |
| 129 | + | |
130 | 130 | | |
131 | 131 | | |
132 | 132 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
27 | 27 | | |
28 | 28 | | |
29 | 29 | | |
| 30 | + | |
30 | 31 | | |
31 | 32 | | |
32 | 33 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
| 37 | + | |
37 | 38 | | |
38 | 39 | | |
39 | 40 | | |
| |||
0 commit comments