feat(client)!: remove the ai namespace — three methods, none of which ever worked (#3718) - #3736
Merged
Merged
Conversation
…projects.listTemplates` (#3718, #3702) Four public methods, every one of them building a URL that NO server in any repo has ever mounted. All four 404ed from the release that shipped them: client.ai.nlq -> POST /api/v1/ai/nlq client.ai.suggest -> POST /api/v1/ai/suggest client.ai.insights -> POST /api/v1/ai/insights client.projects.listTemplates -> GET /api/v1/cloud/templates The three `ai.*` were declared in `DEFAULT_AI_ROUTES` — which has no runtime consumer, only the spec's own test reads it — and typed as optional protocol methods (`aiNlq?` …) nothing implements. `listTemplates` targeted a control-plane route that never existed; templates are a filtered `sys_package` view. All four were found by the #3563 audit's cross-repo guards, which match the URL each SDK method BUILDS against the routes each surface MOUNTS: `listTemplates` by the control-plane ledger (#3655), the three `ai.*` by the AI ledger (#3718), both living in `cloud` because that is the only repo where the mounted route set and the SDK are both in scope. REMOVED, NOT DEPRECATED. A typed method that always throws is worse than no method: it costs a runtime round-trip to discover, where absence is a compile error. No working code can break, because there was no working behaviour. Lands in the v17 major `@objectstack/client` is already taking. That is the right window for removing public API — not a reason to defer it. Also removed: the `AI_PLANE` prefix exemption added to the capstone hours ago. With no method targeting `/api/v1/ai/`, an exemption there is a hole with nothing to cover. The wildcard-only bound stays 0 and now reaches 0 with nothing exempted to get there. The four AI tests in `client.test.ts` are replaced rather than deleted. They were the exact shape this audit family keeps finding behind green suites: mock `fetch`, assert the URL the client BUILT, never assert anything answered it — so they passed for three endpoints that did not exist. The replacement asserts the one thing worth defending: the namespace is gone and must not return without a route behind it. `Ai{Nlq,Suggest,Insights}{Request,Response}` stay re-exported straight from `@objectstack/spec/api`, so anyone holding those types keeps them; retiring the spec-side declarations is a separate change. Docs corrected in the same pass: `client-sdk.mdx` carried three copy-pasteable examples that 404ed, and `plugin-endpoints.mdx` had the AI surface INVERTED — it tabled the three phantom routes and explicitly denied `/ai/chat`, which is mounted. It now lists the 12 routes service-ai really serves. FOLLOW-UP REQUIRED IN `cloud`, and it cannot be done before this merges: `UNMOUNTED_CLIENT_METHODS` and `UNMOUNTED_AI_CLIENT_METHODS` pin these exact four methods as existing-but-unmounted. When cloud's `.objectstack-sha` moves past this commit, those guards go red — correctly, by design — and the pins must be emptied in the same PR as the pin bump. client: 173 passed (13 files), tsc --noEmit clean, build 27/27. Co-Authored-By: Claude <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
GitHub Actions never fired for this branch — zero workflow runs across every workflow, only the Vercel check appeared. Close/reopen did not wake it either. An empty commit forces a `synchronize` event so the breaking change in this PR is actually verified rather than merged on an untested branch. Co-Authored-By: Claude <noreply@anthropic.com>
…k-surface # Conflicts: # packages/client/src/index.ts
…oved listTemplates While this branch sat un-CI'd, #3702 landed on main independently and removed `projects.listTemplates` with near-identical reasoning. That was the merge conflict: both sides deleted the method and left a comment in its place. Took main's wording. So this PR no longer removes four methods, it removes three. The changeset said four; it now says what the diff does. Co-Authored-By: Claude <noreply@anthropic.com>
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 13 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
ai namespace and projects.listTemplates (#3718, #3702)ai namespace — three methods, none of which ever worked (#3718)
os-zhuang
marked this pull request as ready for review
July 28, 2026 02:37
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Resolves the removal half of #3718.
Three methods, none of which ever worked
client.ai.nlqPOST /api/v1/ai/nlqDEFAULT_AI_ROUTES, which has no runtime consumer — only the spec's own test reads it;aiNlq?is an optional protocol method nothing implementsclient.ai.suggestPOST /api/v1/ai/suggestclient.ai.insightsPOST /api/v1/ai/insightsFound by the AI route ledger (#3718, in
cloud, whereservice-ailives), which reads the tablebuildAIRoutes()returns and matches the SDK's URLs against it.The two sets are disjoint. The real AI surface is 12 routes —
chat,chat/stream,complete,models,status,effective-model, and sixconversationsroutes. The SDK expressed none of them.Removed, not deprecated
A typed method that always throws is worse than no method: it costs a runtime round-trip to discover, where absence is a compile error. No working code can break, because there was no working behaviour.
On the major bump: I hesitated, then checked
.changeset/—@objectstack/clientis already taking a major on the v17 train. So this is not forcing a major, it is landing a breaking removal in the window already open for one, which is when it should land.Expressing the real surface is tracked on #3718 as new API, not a rename of this one. For chat,
useChat()(@ai-sdk/react) already speaks the Data Stream ProtocolPOST /api/v1/ai/chatserves.Two things removed that I had added hours earlier
AI_PLANEcapstone exemption (from test(client,runtime): the last wildcard was wrong evidence, not weak — AI ratchet 3 → 0 (#3718) #3727). With no method targeting/api/v1/ai/, an exemption there is a hole with nothing to cover. The wildcard-only bound stays0and now reaches 0 with nothing exempted to get there.client.test.ts— replaced, not deleted. They were the exact shape this audit keeps finding behind green suites: mockfetch, assert the URL the client built, never assert that anything answered it. They passed against three endpoints that did not exist. The replacement asserts the one thing worth defending — the namespace is gone and must not return without a route behind it.Types kept
Ai{Nlq,Suggest,Insights}{Request,Response}are still re-exported straight from@objectstack/spec/api, so anyone holding those types keeps them. Retiring the spec-side declarations (DEFAULT_AI_ROUTES, the optional protocol methods) is a separate change.Docs
client-sdk.mdxcarried three copy-pasteable examples that 404ed.plugin-endpoints.mdxhad the AI surface inverted — it tabled the three phantom routes and explicitly denied/ai/chat, which is mounted. It now lists the 12 real ones.cloud, which cannot be done before this mergesUNMOUNTED_AI_CLIENT_METHODSpins these exact three methods as existing-but-unmounted. When cloud's.objectstack-shamoves past this commit, that guard goes red — correctly, by design — and the pin must be emptied in the same PR as the bump.That coupling is the ledgers working: an SDK surface change forces the control plane to acknowledge it. Flagging it so the next pin bump isn't surprised. (The pin moved three times during this session alone.)
Why this PR had no CI for an hour
It had a merge conflict, so GitHub could not compute the merge ref and never fired
pull_requestworkflows — zero runs, while Vercel (a different integration) fired on every push. I chased the trigger config instead of checkingmergeable_state: "dirty", which was sitting in the API response the whole time. Noted here because "CI never started" and "CI failed" look identical from a distance and are diagnosed in completely different places.Tests
@objectstack/client— 122 passed on the merged tree (client.test.ts+client-url-conformance.test.ts); full package 173 passed before the merge.🤖 Generated with Claude Code
https://claude.ai/code/session_01K35y3ovfWtCkBHYFCqUfAt