Measured at c804f0ca5 while implementing #11925. These are that card's Class C — a missing contract,
not a missing annotation — and they keep Promise< any > with a docblock, per the rule #8140 settled and
#11924 recorded. packages/spec is domain:spec's single-owner surface and read-only from the domain:cli
seat, so this is filed rather than authored.
How "no contract" was established, not assumed
Two independent instruments, both negative:
1. The route ledgers' own responseSchema field — the repo's declaration of whether a route has a named
response type (packages/client/src/route-ledger-response-schema.test.ts resolves each name against the live
@objectstack/spec/api namespace). Every one of the 17 reports responseSchema=None:
meta.getPublished [runtime] GET /meta/:type/:name/published responseSchema=None
meta.listDrafts [runtime] GET /meta/_drafts responseSchema=None
meta.getDiagnostics [rest ] GET /api/v1/meta/diagnostics responseSchema=None
meta.getReferences [rest ] GET /api/v1/meta/:type/:name/references responseSchema=None
meta.getBookTree [rest ] GET /api/v1/meta/book/:name/tree responseSchema=None
meta.getAudit [rest ] GET /api/v1/meta/:type/:name/audit responseSchema=None
meta.rollbackItem [rest ] POST /api/v1/meta/:type/:name/rollback responseSchema=None
meta.diffItem [rest ] GET /api/v1/meta/:type/:name/diff responseSchema=None
meta.migrateStored NO LEDGER ROW
packages.publish|discardDrafts|listCommits|revertCommit|rollback|export|adoptOrphans|duplicate
[runtime] … responseSchema=None
This is #3877's hole exactly as it recorded it — ~190 of 237 ledgered routes declare nothing — so a None
here is the expected reading, not an anomaly.
2. The producers themselves are untyped. The eight packages.* handlers reach the protocol service
through an any cast, so there is no declared type anywhere on the path to lift:
domains/packages.ts:660 (protocol as any).publishPackageDrafts → success(result)
domains/packages.ts:690 (protocol as any).discardPackageDrafts → success(result)
domains/packages.ts:712 (protocol as any).listCommits → success({ commits })
domains/packages.ts:735 (protocol as any).revertCommit → success(result)
domains/packages.ts:757 (protocol as any).rollbackToPackageCommit → success(result)
domains/packages.ts:808 (protocol as any).reassignOrphanedMetadata → success(result)
domains/packages.ts:838 (protocol as any).duplicatePackage → success(result)
domains/packages.ts:790 assemblePackageManifest(): Promise<Record<string, any> | null> → success(manifest)
For meta.*, the one named type that exists — StoredMigrationReport, which meta.migrateStored's own
docblock points at — lives in @objectstack/metadata-protocol, not @objectstack/spec. The client
depends on @objectstack/core and @objectstack/spec only, so reaching it would be an architecture change,
not an annotation.
⭐ One verified near-miss, recorded so the next sweep does not step in it
PackageRollbackResponse (spec/api/package-api.zod.ts:331) sits one import away from
client.packages.rollback and is the wrong type for it. It declares
{ success, restoredVersion?, message? } — a version rollback, matching that file's header
(POST /api/v1/packages/:packageId/rollback — Rollback a package). The client's rollback(id, commitId, opts) posts { commitId } and the dispatcher routes it to rollbackToPackageCommit — the ADR-0067 commit
rollback, a different operation with a different result. Binding it would compile and be false.
#11925 left a compile-time guard against exactly that substitution, in
packages/client/src/return-type-precision.test.ts, in the same shape as #8140's SearchResult guard.
What closing this needs
For each of the 17: a response schema in @objectstack/spec/api (or spec/meta), the ledger row's
responseSchema filled in so the resolver holds it, and only then the SDK annotation. That ordering is the
point — #7294 is the worked precedent, quoted in meta.publishItem's docblock: "this method resolved to
any before that, because the publish door had no declaration at all for a return type to point at."
Related: #11925, #11924, #8140, #3877.
Generated by Claude Code
Measured at
c804f0ca5while implementing #11925. These are that card's Class C — a missing contract,not a missing annotation — and they keep
Promise< any >with a docblock, per the rule #8140 settled and#11924 recorded.
packages/specisdomain:spec's single-owner surface and read-only from thedomain:cliseat, so this is filed rather than authored.
How "no contract" was established, not assumed
Two independent instruments, both negative:
1. The route ledgers' own
responseSchemafield — the repo's declaration of whether a route has a namedresponse type (
packages/client/src/route-ledger-response-schema.test.tsresolves each name against the live@objectstack/spec/apinamespace). Every one of the 17 reportsresponseSchema=None:This is #3877's hole exactly as it recorded it — ~190 of 237 ledgered routes declare nothing — so a
Nonehere is the expected reading, not an anomaly.
2. The producers themselves are untyped. The eight
packages.*handlers reach the protocol servicethrough an
anycast, so there is no declared type anywhere on the path to lift:For
meta.*, the one named type that exists —StoredMigrationReport, whichmeta.migrateStored's owndocblock points at — lives in
@objectstack/metadata-protocol, not@objectstack/spec. The clientdepends on
@objectstack/coreand@objectstack/speconly, so reaching it would be an architecture change,not an annotation.
⭐ One verified near-miss, recorded so the next sweep does not step in it
PackageRollbackResponse(spec/api/package-api.zod.ts:331) sits one import away fromclient.packages.rollbackand is the wrong type for it. It declares{ success, restoredVersion?, message? }— a version rollback, matching that file's header(
POST /api/v1/packages/:packageId/rollback — Rollback a package). The client'srollback(id, commitId, opts)posts{ commitId }and the dispatcher routes it torollbackToPackageCommit— the ADR-0067 commitrollback, a different operation with a different result. Binding it would compile and be false.
#11925 left a compile-time guard against exactly that substitution, in
packages/client/src/return-type-precision.test.ts, in the same shape as #8140'sSearchResultguard.What closing this needs
For each of the 17: a response schema in
@objectstack/spec/api(orspec/meta), the ledger row'sresponseSchemafilled in so the resolver holds it, and only then the SDK annotation. That ordering is thepoint — #7294 is the worked precedent, quoted in
meta.publishItem's docblock: "this method resolved toanybefore that, because the publish door had no declaration at all for a return type to point at."Related: #11925, #11924, #8140, #3877.
Generated by Claude Code