Measured while implementing #12181 (the deleteItem carrier half), on origin/main at 87042b5de. Reported rather than folded in: #12181's ruling is scoped to the request-side carriers, and correcting a published return type is an accept-set change of its own.
What was measured
Both deleteItem declarations in packages/client/src/index.ts (the unscoped ObjectStackClient.meta and the environment-scoped ScopedEnvironmentClient.meta twin) declare:
Promise<{type: string;name: string;deleted: boolean}>The door answers something else entirely. DELETE /meta/:type/:name ends with res.json(result) where result is deleteMetaItem's return, and both the implementation (packages/metadata-protocol/src/protocol.ts) and the contract (DeleteMetaItemResponseSchema, packages/spec/src/api/protocol.zod.ts) declare:
{ success: boolean; reset?: boolean; message?: string; seq?: number; projectionApplied?: …}There is no type, no name, and no deleted on any branch of the response. Driven end to end against a real RestServer + real ObjectStackProtocolImplementation + real sys_metadata tables (the harness added in #12181's PR), a successful reset answers { success: true, reset: true, message: 'Customization overlay deleted — view/… reset to artifact default. [seq=…]' }.
Why it is worth a card
The declared shape is not merely imprecise, it is uninhabited: a first-party caller who branches on the documented deleted flag reads undefined — falsy — on every reset, including the ones that really deleted a row. The truthful signal is reset, and the "nothing was there" case (success: true, reset: false) is exactly the one a caller most wants to distinguish. The types compile, so nothing surfaces this; the SDK's own tests had to cast through any to read the real fields.
DeleteMetaItemResponse is already exported from @objectstack/spec, so this is a declaration catch-up (the #11679 shape, one layer up) rather than a new contract.
Scope note
Both declarations carry the same wrong shape, so a fix must land on both — the same twin-divergence trap #12181 and #11713 record. Narrowing a published return type is a breaking change to anyone who wrote .deleted; the ruling would need to decide between correcting the type outright and declaring the response the spec already declares.
Related: #12181 (the request-side carriers on this same method), #11679 (the same declared-vs-sent gap on DeleteMetaItemRequest), and packages/client/src/return-type-precision.test.ts.
Measured while implementing #12181 (the
deleteItemcarrier half), onorigin/mainat87042b5de. Reported rather than folded in: #12181's ruling is scoped to the request-side carriers, and correcting a published return type is an accept-set change of its own.What was measured
Both
deleteItemdeclarations inpackages/client/src/index.ts(the unscopedObjectStackClient.metaand the environment-scopedScopedEnvironmentClient.metatwin) declare:The door answers something else entirely.
DELETE /meta/:type/:nameends withres.json(result)whereresultisdeleteMetaItem's return, and both the implementation (packages/metadata-protocol/src/protocol.ts) and the contract (DeleteMetaItemResponseSchema,packages/spec/src/api/protocol.zod.ts) declare:There is no
type, noname, and nodeletedon any branch of the response. Driven end to end against a realRestServer+ realObjectStackProtocolImplementation+ realsys_metadatatables (the harness added in #12181's PR), a successful reset answers{ success: true, reset: true, message: 'Customization overlay deleted — view/… reset to artifact default. [seq=…]' }.Why it is worth a card
The declared shape is not merely imprecise, it is uninhabited: a first-party caller who branches on the documented
deletedflag readsundefined— falsy — on every reset, including the ones that really deleted a row. The truthful signal isreset, and the "nothing was there" case (success: true, reset: false) is exactly the one a caller most wants to distinguish. The types compile, so nothing surfaces this; the SDK's own tests had to cast throughanyto read the real fields.DeleteMetaItemResponseis already exported from@objectstack/spec, so this is a declaration catch-up (the #11679 shape, one layer up) rather than a new contract.Scope note
Both declarations carry the same wrong shape, so a fix must land on both — the same twin-divergence trap #12181 and #11713 record. Narrowing a published return type is a breaking change to anyone who wrote
.deleted; the ruling would need to decide between correcting the type outright and declaring the response the spec already declares.Related: #12181 (the request-side carriers on this same method), #11679 (the same declared-vs-sent gap on
DeleteMetaItemRequest), andpackages/client/src/return-type-precision.test.ts.