Skip to content

Commit dc75ba8

Browse files
os-salesclaude
andauthored
Bind published response contracts for the 17 unbound client-SDK methods; retire the false PackageRollbackResponseSchema (#12038, ruling 1C·2C·3A·4A·5A) (#12848)
* spec: retire PackageRollbackResponseSchema and the rollbackPackage contract binding (#12038 3A) The schema declared a VERSION rollback ({ success, restoredVersion?, message? }) while PackageApiContracts.rollbackPackage bound it to the live POST /api/v1/packages/:packageId/rollback path, which the dispatcher serves with rollbackToPackageCommit — the ADR-0067 COMMIT rollback, a different operation with a different result. Retired through the ADR-0087 discipline: RETIRED_DEFS_BY_MAJOR entry api/PackageRollbackResponse, D3 semantic entry package-rollback-response-retired, manifest key and authorable-surface baseline lines released with their registered proof (#4725 / #4650), runtime namespace-probe pins in package-api.test.ts. PackageRollbackRequestSchema stays published as ruled; the true commit-rollback contract follows in the next commit, after this retirement per the ruling's sequencing. Co-authored-by: Claude <noreply@anthropic.com> * spec: bind the meta history/diagnostics and package lifecycle response contracts (#12038) The twelve describe-only transcriptions from the recorded ruling (1C/2C/3A/4A/5A), each transcribed from the return type its producer already declares inline: six meta.* payloads in api/protocol.zod.ts (listDrafts, getMetaDiagnostics, findReferencesToMeta, rollbackMetaItem, diffMetaItem, plus the ruling-1C opaque GetPublishedMetaItemResponseSchema), the package lifecycle family in the new api/package-lifecycle.zod.ts (discardDrafts, listCommits with the handler-minted commits wrapper, revertCommit, the true commit-rollback RollbackToPackageCommitResponseSchema, the ruling-4A fixed-keys-plus-catchall PackageExportManifestSchema, adoptOrphans, duplicate), and the resolved book tree as Zod beside its interfaces in system/book.zod.ts. Ruling 5A re-exports (PackagePublishResultSchema, ResolvedBookSchema family) land in the /api namespace the ledger resolver searches — never a second copy. meta.migrateStored stays unbound, documented (ruling 2C). Generated artifacts regenerated by the spec build. Co-authored-by: Claude <noreply@anthropic.com> * runtime/rest/client: name the #12038 response contracts in the ledgers and bind the SDK Fill responseSchema on the 18 boundable ledger rows across both ledgers, each row stating which surface's envelope it describes (the dispatcher wraps { success, data }; the REST server answers the payload bare — the three dual-mounted meta routes carry one note per surface). meta.migrateStored's two rows document the ruling-2C deliberate unbinding instead. Conformance suites land with the rows (spec api/protocol.test.ts, the new api/package-lifecycle.test.ts, system/book.test.ts — the #3877 no-row-without-conformance rule, house capture pattern). The client SDK binds 16 of the 17 methods to the published payload types (migrateStored stays any, documented per 2C; getPublished binds to unknown per 1C), replaces the four invented test mocks (getDiagnostics, getBookTree, rollbackItem, diffItem) with producer-true shapes, flips the #11925 rollback negative guard to guard the new commit-rollback truth, adds the returnTypePrecisionPins12038 type-level pins, and pins the unwrapResponse mis-unwrap hazard (survey §8.2) so no bound payload can ever declare both a boolean success and a data key. Co-authored-by: Claude <noreply@anthropic.com> * spec/docs: regenerate artifacts for the new contracts; add the #12038 changeset api-surface, export-origins, reference docs and the strictness ledger regenerated by check:generated --fix (only the artifacts it proved stale); the ResolvedBook type family re-exported on /api so the generated page's import line resolves. The changeset carries the breaking FROM-to-TO mapping and the ADR-0087 disposition (registered package-rollback-response-retired). Co-authored-by: Claude <noreply@anthropic.com> * spec: keep the package-lifecycle header inside the description corpus pins The file docblock opened at heading level 1 (the #12249 demotion pin counts exactly the 38 files that predate it) and split a code span across lines, leaving a same-directory source path as plain text for the #6484 rule. Open at level 2 and keep the span on one line; reference docs regenerated. Co-authored-by: Claude <noreply@anthropic.com> * spec/docs: satisfy the ADR-0122 alias convention and the quick-reference total for the new contracts The 13 new response types gain their Parsed aliases (check:spec-parsed-alias; all are isomorphic — no defaults or transforms — but the paired-alias route keeps the family uniform with its package-api siblings), the API Protocol quick-reference heading's M rises to the 31 pages the reference tree now publishes, and the spec artifacts are regenerated for the new type exports. Co-authored-by: Claude <noreply@anthropic.com> * spec: count the package-lifecycle module in llms.txt's schema inventory check:llms-txt (the last step of the source-gates job) went red on the new api/package-lifecycle.zod.ts: the hand-kept inventory declared 207 schemas total and 29 under api. Re-read per the gate's own rule — number AND prose: 208 / 30, with Package Lifecycle added to the api row's key-schema sampler. Gate re-derived green locally: 97 claims, 14 domains, 208 schemas. Co-authored-by: Claude <noreply@anthropic.com> * client: shrink the exported-any-returns ledger by the 15 gaps this PR closed check:exported-any-returns (Type Check - consumer gates) is exact in both directions: the #11925 entries for the newly bound meta.* and packages.* methods no longer resolve to any, so their ledger rows must be deleted. meta.migrateStored's entry stays - it remains any by the 2C ruling. Verified against the rebuilt dist: 'no NEW exported callable resolves to any: 317 callables reached, 47 ledgered site(s) still open'. Co-authored-by: Claude <noreply@anthropic.com> * spec: spell the discard-drafts capture's failure code as the ledger declares it check:error-code-casing (Lint & Repo Gates) flagged the handwritten conformance capture's code: 'item_locked' — an invented lowercase spelling. The producer propagates deleteMetaItem's refusal code verbatim, and the protection path sets 'ITEM_LOCKED' (ledger-declared, error-code-ledger.zod.ts ADR-0010 §3.3), so the capture now carries the code the route really answers. Gate and the conformance suite re-run green. Co-authored-by: Claude <noreply@anthropic.com> * merge origin/main (os-regen artifacts taken from main; regeneration follows) * spec: regenerate the merged tree's artifacts (regen-merge sync after #12849) os-regen-merge.sh step 4: gen:migration-registry rebuilds registry.ts with BOTH step-18 populations (#12849's ui-form-view-predicate-features-root-refused semantic entry beside this PR's retirement + semantic entries), the retirement's manifest and authorable-surface deletions are re-applied over main's side (the merge takes main's copy of os-regen artifacts by design; the #4725/#4650 proofs re-verify against the new base), and the full chain regenerates green: check:generated 14/14, check:llms-txt 208 schemas, the five touched spec suites, client typecheck and the resolver + unwrap pin suites all pass on the merged tree. Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent e84bbf6 commit dc75ba8

39 files changed

Lines changed: 2393 additions & 225 deletions
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
---
2+
"@objectstack/spec": minor
3+
"@objectstack/client": minor
4+
"@objectstack/runtime": patch
5+
"@objectstack/rest": patch
6+
---
7+
8+
feat(spec,client): bind published response contracts for the 17 unbound client-SDK methods; retire the false `PackageRollbackResponseSchema` (#12038, ruling 1C · 2C · 3A · 4A · 5A)
9+
10+
<!-- adr-0087: registered package-rollback-response-retired -->
11+
12+
**BREAKING** export removal, landing after the v17.0.0 cut (the lockstep
13+
launch-window convention ships it as `minor`; the prescription is registered
14+
under protocol major 18 — `RETIRED_DEFS_BY_MAJOR[18]` `api/PackageRollbackResponse`
15+
plus the D3 semantic entry `package-rollback-response-retired` — where
16+
`os migrate meta` users will look).
17+
18+
FROM → TO:
19+
20+
- `PackageRollbackResponseSchema` / `PackageRollbackResponse` /
21+
`PackageRollbackResponseParsed``RollbackToPackageCommitResponseSchema` /
22+
`RollbackToPackageCommitResponse` (`@objectstack/spec/api`). The retired
23+
schema declared a VERSION rollback (`{ success, restoredVersion?,
24+
message? }`) while the live `POST /packages/:id/rollback` route posts
25+
`{ commitId }` and answers the ADR-0067 COMMIT rollback —
26+
`{ success, revertedCommits: string[], failed: [{ commitId, error }] }`.
27+
Read `revertedCommits` / `failed`; there is no `restoredVersion`.
28+
- `PackageApiContracts.rollbackPackage`*(removed)* — it bound the
29+
wrong-operation schema to the exact live path. No route registration or
30+
SDK generation ever consumed it (zero consumers measured across
31+
objectstack, objectui and cloud; only its own unit test and the #11925
32+
compile-time guard, both updated in this PR).
33+
34+
One-line fix: replace any import of `PackageRollbackResponse(Schema)` with
35+
`RollbackToPackageCommitResponse(Schema)` and read `revertedCommits` /
36+
`failed` instead of `restoredVersion`. `PackageRollbackRequestSchema` stays
37+
published (ruled out of the retirement), bound to no route.
38+
39+
The rest of the change is additive — the recorded five-part maintainer
40+
ruling (2026-08-27) for the 17 client-SDK methods that had no published
41+
response contract:
42+
43+
- **12 describe-only transcriptions** into `@objectstack/spec/api`, each
44+
from the return type its producer already declares inline (no wire byte
45+
changes): `ListDraftsResponseSchema`, `GetMetaDiagnosticsResponseSchema`,
46+
`FindReferencesToMetaResponseSchema`, `RollbackMetaItemResponseSchema`,
47+
`DiffMetaItemResponseSchema`, `ResolvedBookSchema` (authored beside its
48+
interfaces in `system/book.zod.ts`), `DiscardPackageDraftsResponseSchema`,
49+
`ListPackageCommitsResponseSchema` (the `{ commits }` wrapper declared as
50+
the handler's own), `RevertPackageCommitResponseSchema`,
51+
`RollbackToPackageCommitResponseSchema`,
52+
`ReassignOrphanedMetadataResponseSchema`, `DuplicatePackageResponseSchema`.
53+
- **Ruling 1C**: `GetPublishedMetaItemResponseSchema` is deliberately opaque
54+
(`z.unknown()`) — the route answers an arbitrary metadata item body, never
55+
a union frozen against the type registry.
56+
- **Ruling 2C**: `meta.migrateStored` stays UNBOUND, documented at its two
57+
ledger rows and in the SDK — `StoredMigrationReport` lives in
58+
`@objectstack/metadata-protocol`, and a second declaration would drift.
59+
- **Ruling 4A**: `PackageExportManifestSchema` pins the four fixed keys
60+
(`id`, `name`, `version`, `label?`) and stays honestly open for the
61+
registry-derived plural keys.
62+
- **Ruling 5A**: `PackagePublishResultSchema` and the `ResolvedBook` family
63+
are re-exported into `@objectstack/spec/api` (the namespace the
64+
route-ledger resolver searches) — never a second copy.
65+
- The 18 boundable route-ledger rows in `@objectstack/runtime` and
66+
`@objectstack/rest` now name their `responseSchema`, each stating which
67+
surface's envelope it describes; every named schema carries conformance
68+
coverage (the #3877 rule).
69+
- The client SDK binds 16 of the 17 methods to the published payload types,
70+
replaces four invented test mocks with producer-true shapes, and pins the
71+
`unwrapResponse` mis-unwrap hazard so no bound payload can declare both a
72+
boolean `success` and a `data` key.

content/docs/getting-started/quick-reference.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ AI/ML capabilities - agents, skills, tools, MCP exposure, RAG, and cost tracking
127127
| **[Usage](/docs/references/ai/usage)** | `usage.zod.ts` | AIUsageRecord, TokenUsage | AI usage and cost tracking |
128128
| **[Solution Blueprint](/docs/references/ai/solution-blueprint)** | `solution-blueprint.zod.ts` | BlueprintObject, BlueprintApp | Blueprint format for AI app generation |
129129

130-
## API Protocol (17 of 29 schemas)
130+
## API Protocol (17 of 31 schemas)
131131

132132
REST endpoints, real-time subscriptions, and discovery.
133133

content/docs/references/api/index.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@ This section contains all protocol schemas for the api layer of ObjectStack.
2222
<Card href="/docs/references/api/export" title="Export" description="Source: packages/spec/src/api/export.zod.ts" />
2323
<Card href="/docs/references/api/http-cache" title="Http Cache" description="Source: packages/spec/src/api/http-cache.zod.ts" />
2424
<Card href="/docs/references/api/metadata" title="Metadata" description="Source: packages/spec/src/api/metadata.zod.ts" />
25+
<Card href="/docs/references/api/misc" title="Misc" />
2526
<Card href="/docs/references/api/odata" title="Odata" description="Source: packages/spec/src/api/odata.zod.ts" />
2627
<Card href="/docs/references/api/package-api" title="Package Api" description="Source: packages/spec/src/api/package-api.zod.ts" />
28+
<Card href="/docs/references/api/package-lifecycle" title="Package Lifecycle" description="Source: packages/spec/src/api/package-lifecycle.zod.ts" />
2729
<Card href="/docs/references/api/plugin-rest-api" title="Plugin Rest Api" description="Source: packages/spec/src/api/plugin-rest-api.zod.ts" />
2830
<Card href="/docs/references/api/protocol" title="Protocol" description="Source: packages/spec/src/api/protocol.zod.ts" />
2931
<Card href="/docs/references/api/query-adapter" title="Query Adapter" description="Source: packages/spec/src/api/query-adapter.zod.ts" />

content/docs/references/api/meta.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
"storage",
3434
"---More---",
3535
"error-code-ledger",
36+
"misc",
37+
"package-lifecycle",
3638
"sortability"
3739
]
3840
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
---
2+
title: Misc
3+
description: Misc protocol schemas
4+
---
5+
6+
{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */}
7+
8+
## TypeScript Usage
9+
10+
```typescript
11+
import { ResolvedBookSchema, ResolvedEntrySchema, ResolvedGroupSchema } from '@objectstack/spec/api';
12+
import type { ResolvedBook, ResolvedEntry, ResolvedGroup } from '@objectstack/spec/api';
13+
14+
// Validate data
15+
const result = ResolvedBookSchema.parse(data);
16+
```
17+
18+
---
19+
20+
## ResolvedBook
21+
22+
### Properties
23+
24+
| Property | Type | Required | Description |
25+
| :--- | :--- | :--- | :--- |
26+
| **name** | `string` || The book's machine name. |
27+
| **label** | `string` | optional | The book's display label, when it declares one. |
28+
| **groups** | `{ key: string; label: string; entries: object[] }[]` || The resolved groups, in render order. |
29+
30+
### Nested Shape: `ResolvedBook.groups[number]`
31+
32+
| Property | Type | Required | Description |
33+
| :--- | :--- | :--- | :--- |
34+
| **key** | `string` || The group's key (from the spine, or `uncategorized`). |
35+
| **label** | `string` || The group's display label. |
36+
| **entries** | `{ doc?: string; href?: string; label?: string; description?: string; … }[]` || The group's resolved entries, in render order. |
37+
38+
39+
---
40+
41+
## ResolvedEntry
42+
43+
### Properties
44+
45+
| Property | Type | Required | Description |
46+
| :--- | :--- | :--- | :--- |
47+
| **doc** | `string` | optional | Doc name, or undefined for an external link / separator. |
48+
| **href** | `string` | optional | External link target, when the entry is a link. |
49+
| **label** | `string` | optional | Display label, when one resolved. |
50+
| **description** | `string` | optional | Doc description, when one resolved. |
51+
| **badge** | `string` | optional | Badge text (e.g. "beta"), when declared. |
52+
| **icon** | `string` | optional | Icon name, when declared. |
53+
| **separator** | `boolean` | optional | True for a `---` separator node. |
54+
55+
56+
---
57+
58+
## ResolvedGroup
59+
60+
### Properties
61+
62+
| Property | Type | Required | Description |
63+
| :--- | :--- | :--- | :--- |
64+
| **key** | `string` || The group's key (from the spine, or `uncategorized`). |
65+
| **label** | `string` || The group's display label. |
66+
| **entries** | `{ doc?: string; href?: string; label?: string; description?: string; … }[]` || The group's resolved entries, in render order. |
67+
68+
### Nested Shape: `ResolvedGroup.entries[number]`
69+
70+
| Property | Type | Required | Description |
71+
| :--- | :--- | :--- | :--- |
72+
| **doc** | `string` | optional | Doc name, or undefined for an external link / separator. |
73+
| **href** | `string` | optional | External link target, when the entry is a link. |
74+
| **label** | `string` | optional | Display label, when one resolved. |
75+
| **description** | `string` | optional | Doc description, when one resolved. |
76+
| **badge** | `string` | optional | Badge text (e.g. "beta"), when declared. |
77+
| **icon** | `string` | optional | Icon name, when declared. |
78+
| **separator** | `boolean` | optional | True for a `---` separator node. |
79+
80+
81+
---
82+

content/docs/references/api/package-api.mdx

Lines changed: 2 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ DELETE /api/v1/packages/:packageId — Uninstall a package
2828
## TypeScript Usage
2929

3030
```typescript
31-
import { GetInstalledPackageRequestSchema, GetInstalledPackageResponseSchema, ListInstalledPackagesRequestSchema, ListInstalledPackagesResponseSchema, PackageApiErrorCode, PackageInstallRequestSchema, PackageInstallResponseSchema, PackagePathParamsSchema, PackageRollbackRequestSchema, PackageRollbackResponseSchema, PackageUpgradeRequestSchema, PackageUpgradeResponseSchema, ResolveDependenciesRequestSchema, ResolveDependenciesResponseSchema, UninstallPackageApiRequestSchema, UninstallPackageApiResponseSchema, UploadArtifactRequestSchema, UploadArtifactResponseSchema } from '@objectstack/spec/api';
32-
import type { GetInstalledPackageRequest, GetInstalledPackageResponse, ListInstalledPackagesRequest, ListInstalledPackagesResponse, PackageApiErrorCode, PackageInstallRequest, PackageInstallResponse, PackagePathParams, PackageRollbackRequest, PackageRollbackResponse, PackageUpgradeRequest, PackageUpgradeResponse, ResolveDependenciesRequest, ResolveDependenciesResponse, UninstallPackageApiRequest, UninstallPackageApiResponse, UploadArtifactRequest, UploadArtifactResponse } from '@objectstack/spec/api';
31+
import { GetInstalledPackageRequestSchema, GetInstalledPackageResponseSchema, ListInstalledPackagesRequestSchema, ListInstalledPackagesResponseSchema, PackageApiErrorCode, PackageInstallRequestSchema, PackageInstallResponseSchema, PackagePathParamsSchema, PackageRollbackRequestSchema, PackageUpgradeRequestSchema, PackageUpgradeResponseSchema, ResolveDependenciesRequestSchema, ResolveDependenciesResponseSchema, UninstallPackageApiRequestSchema, UninstallPackageApiResponseSchema, UploadArtifactRequestSchema, UploadArtifactResponseSchema } from '@objectstack/spec/api';
32+
import type { GetInstalledPackageRequest, GetInstalledPackageResponse, ListInstalledPackagesRequest, ListInstalledPackagesResponse, PackageApiErrorCode, PackageInstallRequest, PackageInstallResponse, PackagePathParams, PackageRollbackRequest, PackageUpgradeRequest, PackageUpgradeResponse, ResolveDependenciesRequest, ResolveDependenciesResponse, UninstallPackageApiRequest, UninstallPackageApiResponse, UploadArtifactRequest, UploadArtifactResponse } from '@objectstack/spec/api';
3333

3434
// Validate data
3535
const result = GetInstalledPackageRequestSchema.parse(data);
@@ -287,43 +287,6 @@ Rollback package request
287287
| **rollbackCustomizations** | `boolean` | optional (default: `true`) | Whether to restore pre-upgrade customizations |
288288

289289

290-
---
291-
292-
## PackageRollbackResponse
293-
294-
Rollback package response
295-
296-
### Properties
297-
298-
| Property | Type | Required | Description |
299-
| :--- | :--- | :--- | :--- |
300-
| **success** | `boolean` || Operation success status |
301-
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| …>; declaredCode?: string; message: string; userMessage?: string; … }` | optional | Error details if success is false |
302-
| **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata |
303-
| **data** | `{ success: boolean; restoredVersion?: string; message?: string }` || |
304-
305-
### Nested Shape: `PackageRollbackResponse.error`
306-
307-
| Property | Type | Required | Description |
308-
| :--- | :--- | :--- | :--- |
309-
| **code** | `Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| …>` || Error code (e.g. VALIDATION_ERROR; StandardErrorCode ∪ the ledger the serving side registers — ERROR_CODE_LEDGER for framework packages) |
310-
| **declaredCode** | `string` | optional | The producer-declared code, verbatim, when it is not a member of the closed `code` vocabulary — the open, author-authored channel (app-specific spellings; ADR-0112, #9106) |
311-
| **message** | `string` || Readable error message |
312-
| **userMessage** | `string` | optional | Producer-marked user-facing refusal text, verbatim (#9934). Present exactly when the producer opted in at throw time; consumers render it to end users and keep their generic substitution (#3821) for anything unmarked. Status-agnostic; never replaces `message`. |
313-
| **category** | `string` | optional | Error category (e.g. validation, authorization) |
314-
| **httpStatus** | `integer` | optional | HTTP status of the response carrying this error |
315-
| **details** | `any` | optional | Additional error context (e.g. field validation errors) |
316-
| **requestId** | `string` | optional | Request ID for tracking |
317-
318-
### Nested Shape: `PackageRollbackResponse.data`
319-
320-
| Property | Type | Required | Description |
321-
| :--- | :--- | :--- | :--- |
322-
| **success** | `boolean` || Whether the rollback succeeded |
323-
| **restoredVersion** | `string` | optional | Restored version |
324-
| **message** | `string` | optional | Rollback status message |
325-
326-
327290
---
328291

329292
## PackageUpgradeRequest

0 commit comments

Comments
 (0)