Uh oh!
There was an error while loading. Please reload this page.
feat(spec,client): declare the search and data.clone route response contracts (#11924) - #12203
Conversation
…ontracts (#11924) The maintainer-ruled half of the four undeclared SDK route returns (2026-08-25, decision-inbox batch 8, option A): search + data.clone are stable, server-produced shapes — declared in packages/spec exactly as produced, with conformance coverage on both the producer and the mounted route, honouring #3877's rule that no route-ledger responseSchema row is filled without conformance coverage (both rows filled in this same change). The automation.create / automation.update pair is NOT touched — it returns to the decision inbox as its own card with a consumer-survey reading first. - spec: SearchAllResponseSchema / SearchAllHitSchema + CloneDataResponseSchema in api/protocol.zod.ts (+ z.input type aliases and isomorphism pin lines); regenerated artifacts: api-surface (6 added / 0 removed), export-origins, reference docs, strictness-ledger counts; authorable-surface and json-schema.manifest shards rewritten by gen:schema as expected products. - rest: both ledger rows filled (responseSchema + coverage-naming notes); search-clone-route-schema-conformance.test.ts pins the relay half — bodies parse, answered bare (201 for clone), rows resolve to the very schema objects the suite parses with. - metadata-protocol: search-clone-schema-conformance.test.ts pins the producer half — the real searchAll / cloneData over fixture engines, safeParse plus key-set subset checks at both levels, both searchAll return statements, both snippet branches. - client: search → Promise<SearchAllResponse>; data.clone → clone<T = any>(...): Promise<CloneDataResult<T>> with the new exported CloneDataResult mirror interface; SearchAllHit / SearchAllResponse re-exported; return-type-precision pins extended in both directions. The #8140 SearchResult near-miss guard's assertions are untouched and green — only its prose note is updated (the binding it described as deliberately absent now exists). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NDGG54XF5gbTLdQzCtnaVV
…clare-search-clone-contracts
…pins (835 -> 838) The pin file asserts its own pin count and recomputes the two prose statements from the file; the three new Iso859/860/861 pins moved the count. Receipt paragraph added per the file's own convention. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NDGG54XF5gbTLdQzCtnaVV
📓 Docs Drift CheckThis PR changes 3 package(s): 12 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 3 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 130 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin dc549cb6f18b330dfc06adc1d10b4e795d71ed5c && git checkout dc549cb6f18b330dfc06adc1d10b4e795d71ed5c
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin f86839d4cd5543a0f8c7a3f4806b0d0b35a33524 94e84ec6bce650ed465bfbac1704ca971a621aca && git checkout -B drift-repro f86839d4cd5543a0f8c7a3f4806b0d0b35a33524 && git merge --no-ff 94e84ec6bce650ed465bfbac1704ca971a621aca
node scripts/docs-audit/affected-docs.mjs --json f86839d4cd5543a0f8c7a3f4806b0d0b35a33524
|
…clare-search-clone-contracts # Conflicts: # packages/spec/src/type-alias-convention.pin.test.ts
…, export-origins, docs, strictness-ledger via check:generated --fix) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NDGG54XF5gbTLdQzCtnaVV
…explicit .js extension; index instead of Array.prototype.at) check:type-check-debt re-measure went 155 -> 157 on @objectstack/rest from this PR's new test file (TS2835 missing extension, TS2550 .at under the package lib). Fixed the two new errors; ledger stays at its recorded 155. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NDGG54XF5gbTLdQzCtnaVV
…jectStackClient.search, ObjectStackClient.data.clone) This PR binds real return types to both sites, voiding their DELIBERATE Promise<any> ledger reasons; the shrink-only ledger is judged exactly, so the closed-gap entries must go in the same change (check:exported-any-returns went red on them at CI). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NDGG54XF5gbTLdQzCtnaVV
Uh oh!
There was an error while loading. Please reload this page.
Discharges the os-regen deferral recorded by the merge commit. `main` gained `SearchAllResponseSchema` / `SearchAllHitSchema` / `CloneDataResponseSchema` (#12203) while this branch was open, so the pages this branch regenerated at its fork point described a source the merged tree no longer has — which is what `check:docs` reported on the merge ref. Regenerated with `gen:schema && gen:docs` from the merged tree, never by hand. `api/protocol.mdx` gains the three new schema sections plus one nested-shape table this branch's renderer produces for the new array-of-object property, `SearchAllResponse.hits[number]`. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NDGG54XF5gbTLdQzCtnaVV
Part of #11924 — the maintainer-ruled half (2026-08-25, decision-inbox batch 8: option A). Declares the
search+data.clonepair only; theautomation.create/automation.updatepair was explicitly NOT ruled there — it returns to the decision inbox as its own card carrying a consumer-survey reading first, so #11924 remains open for the PM to disposition at acceptance. No automation route, file or docblock is touched here.(Angle-bracket generic spellings are written out in words below — the platform body sanitizer eats literal less-than fragments even inside code spans; the first stored revision of this body lost them, and this edit repairs it.)
What this does
Two of the four SDK routes #8140 had to leave as deliberate Promise-of-
anyholes get their missing contracts, declared as produced (both routes answer BARE — no{ success, data }envelope — relaying the@objectstack/metadata-protocolproducer verbatim):GET /api/v1/search→SearchAllResponseSchema/SearchAllHitSchema(+SearchAllResponse/SearchAllHittypes) in@objectstack/spec/api(packages/spec/src/api/protocol.zod.ts):{ query, hits, totalObjects, totalHits, truncated }, hits of{ object, id, title, snippet?, record }.POST /data/:object/:id/clone→CloneDataResponseSchema(+CloneDataResponse) beside its structural siblingCreateDataResponseSchema:{ object, id, sourceId, record }, answered with 201. NodroppedFieldsmember — measured: the clone producer emits none.Conformance coverage (#3877: no ledger row filled without it — filled and covered in the same change):
packages/metadata-protocol/src/search-clone-schema-conformance.test.tsdrives the REALsearchAll/cloneDataover fixture engines andsafeParses what they emit (plus key-set subset checks in the direction a plainz.objectparse is blind to, on the JSON round-trip a caller actually holds; bothsearchAllreturn statements covered;snippet's two branches measured on one body).packages/rest/src/search-clone-route-schema-conformance.test.tsdrives both real mounts, proves the bodies parse, are relayed bare and unre-shaped (201 for clone), and pins the ledger rows to the very schema objects the suite parses with (identity, not just resolvability — the discovery-gate pattern).packages/rest/src/rest-route-ledger.ts: both rows'responseSchemafilled, with notes naming the coverage.Client bindings (type-only; no request, response, unwrapping or error path changes):
searchnow returns a Promise ofSearchAllResponse;data.clonebecomes generic overT(defaultany, matching itsdata.*siblings) returning a Promise ofCloneDataResultofT— a new exported interface mirroring the spec schema besideCreateDataResult.SearchAllHit/SearchAllResponsere-exported from the client for consumers.The
SearchResultnear-miss trap (ruled: must stay pinned)SearchResult(@objectstack/spec/contracts) types the per-objectISearchService.search— hits ofscore/document— and is the WRONG type for this route. The #8140 compile-time guard inpackages/client/src/return-type-precision.test.tsis untouched in its assertions and stays green; its prose note is updated (it described the search binding as deliberately absent — Promise-of-any— which this change makes false). The new declaration was written from the producer, not from that neighbour, and two new direction-2 pins make the trap expressible at the binding: asearchresult assigned toSearchResultis a compile error, as is acreateresult read throughCloneDataResult(nosourceId).Verification
All heavy runs went through
scripts/pm/os-verify-lock.sh; exit codes captured directly (no pipes), verdict lines quoted from the gates' own output. Final union re-run at commit0968af1:@objectstack/spec: fulltestat the merge commit3c1cda7: 425/426 files, 11347/11348 tests green — the sole red was the pin file's own count self-check ("expected [ Array(838) ] to have a length of 835"), corrected per that file's receipt convention in0968af1;typecheckand the corrected pin file re-run green at0968af1(3/3). The ratchet families (check:spec-parsed-alias,check:strictness-ledger,check:merge-driver, changeset family) all re-ran green at0968af1in the gate farm below@objectstack/client:typecheck(compiles the type pins viatsconfig.test.json/check:test-typecheck) + fulltest— 25 files / 332 tests passed at0968af1@objectstack/metadata-protocol: new conformance suite — 6/6 passed at0968af1(notypecheckscript exists in that package — type-check-debt ledger; the suite runs under vitest)@objectstack/rest: new conformance suite +rest-route-ledger.conformance.test.ts— 13/13 passed at0968af1pnpm --filter @objectstack/spec check:generated— "All 14 generated artifacts are up to date" on the merged tree (batch A, merge commit) after regenerating the four proved stale pre-merge (api-surface— 6 added / 0 removed,export-origins,docs,strictness-ledger);authorable-surface/api.json+json-schema.manifest/api.jsonrewritten bygen:schemaas expected productsnode scripts/pm/dispatch-gates.mjs, no args — change set taken from merge-base by the script): 36 of 37 gates pass at0968af1(includingcheck:nul-bytes,check:spec-parsed-alias,check:cross-package-test-inputs,check:strictness-ledger,check:adr-0087-registration— the additive changeset carries no breaking declaration so no marker is owed). Deviation:check-dev-prereqsreds locally on a worktree precondition — "36 of 67 workspace packages declare an entry point under dist/ that is not on disk" (apps/account, setup, studio, …): only the targeted dependency closures were built in this worktree; the gate measures workspace built-ness, which this diff does not influence, and CI's lint job builds the workspace before running it--filter), and the twodocs-drift-check.ymlscripts (check-affected-docs/check-drift-comment) are CI-owned PR-context runs not reproduced locally. Downstream-consumer sweep for the client narrowing measured by call-site grep: zeroclient.search(/.data.clone(call sites exist outsidepackages/clientitself (downstream direction,...@objectstack/client). CI runs the full farm regardlessGenerated by Claude Code