Commit d93400f
docs(spec): the AI slot answers 501, not 404, when no AI service is mounted (#18597)
Fixes #17847
Clause-②: no
`packages/spec/src/api/protocol.zod.ts`'s AI Operations note said this
repo's dispatcher "404s `AI service is not configured`" when nothing
serves the AI slot. It has answered **501** since the shared
`capabilityUnavailable` exit landed, and the quoted body is no longer a
local string either. This PR corrects that prose and nothing else — no
runtime file is in the diff, and no status code, schema key or export
moves.
Attribution for this run, in prose so it survives any body rewrite:
produced by Claude Code, session `session_01JbZnqu8bt6YqfJsr9vaFb3`,
https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3
## The premise, re-measured — located by TEXT, not by line number
The card warns its line numbers rotted three times in one day, so the
sentence was re-located by its text against `origin/main` `e0d05538c0`
(unmoved for the life of this branch):
```
$ grep -c '404s' packages/spec/src/api/protocol.zod.ts
1
$ grep -n '404s' packages/spec/src/api/protocol.zod.ts
2791:// `buildAIRoutes()` mounted, or 404s "AI service is not configured". So these
```
Counter-side, read the same round: `packages/runtime/src/domains/ai.ts`
reaches `capabilityUnavailable(deps, 'ai')`, and
`packages/runtime/src/domains/unavailable.ts` returns
`deps.error(serviceUnavailableMessage(slot), 501)` under a docblock that
states **501 Not Implemented** in words. The defect stands, and the
premise is live.
One extra reading the card did not carry: the literal string `AI service
is not configured` survives **nowhere** in the tree except that stale
comment (`grep` over `packages/`, `content/`, `examples/`, `scripts/` —
one hit, the comment itself). So the sentence was stale in both halves:
the status AND the body it quoted.
## Every arm was measured, not copied
The card hands over its behaviour table explicitly unverified, and an
unqualified "`/ai/*` answers 501" would manufacture a second inaccurate
sentence. Each arm is pinned by
`packages/runtime/src/domains/ai-anonymous-deny-ordering.test.ts`, run
on this tree:
```
pnpm --filter @objectstack/runtime exec vitest run --maxWorkers=2 --reporter=verbose \
src/domains/ai-anonymous-deny-ordering.test.ts
Test Files 1 passed (1)
Tests 13 passed (13)
```
| arm | the case that pins it | answer |
|:--|:--|:--|
| anonymous | `GET /ai/models` → 401, not the 501 remedy sentence · `GET
/ai/agents` → 401, not the 200 empty-list courtesy | **401** first
(`ANONYMOUS_DENY_STATUS = 401`, pinned in
`core/src/security/anonymous-deny.test.ts`) |
| `GET /ai/agents` | serves `/ai/agents` as the declared envelope with
the payload relocated under `data` | **200**, `{ success: true, data: {
agents: [] } }` |
| every other `/ai/*` | 501s `/ai/models`, `/conversations`, `/usage`
and `/chat` with the remedy sentence | **501** |
| the body | keeps the 501 body string-identical to `/discovery`'s
`services.ai` message | shared `serviceUnavailableMessage` |
1 parent a6a1de4 commit d93400f
2 files changed
Lines changed: 34 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2788 | 2788 | | |
2789 | 2789 | | |
2790 | 2790 | | |
2791 | | - | |
2792 | | - | |
2793 | | - | |
| 2791 | + | |
| 2792 | + | |
| 2793 | + | |
| 2794 | + | |
| 2795 | + | |
| 2796 | + | |
| 2797 | + | |
| 2798 | + | |
| 2799 | + | |
| 2800 | + | |
| 2801 | + | |
| 2802 | + | |
| 2803 | + | |
2794 | 2804 | | |
2795 | 2805 | | |
2796 | 2806 | | |
| |||
0 commit comments