Skip to content

Commit 32ccb23

Browse files
os-zhuangclaude
andauthored
feat(spec,core,runtime,docs)!: ADR-0112 batch 1 — one error-code vocabulary, SCREAMING_SNAKE, schema-enforced (#3841) (#3988)
* feat(spec,core,runtime,docs)!: ADR-0112 batch 1 — one error-code vocabulary, SCREAMING_SNAKE, schema-enforced (#3841) - Rename all 53 StandardErrorCode members to SCREAMING_SNAKE in place; HttpStatusErrorCodeMap (#3842's designated sweep point) follows, so derived wire codes change case (permission_denied -> PERMISSION_DENIED). - Add ERROR_CODE_LEDGER (spec/api/error-code-ledger.zod.ts): 130+ service codes registered per owning package, harvested from every non-test emitter; ErrorCode = StandardErrorCode ∪ registered. - Tighten ApiErrorSchema.code from z.string() to ErrorCode — the envelope conformance suites now assert values, not just shape. - Widen FieldErrorSchema.code to z.string() (ADR-0112 D6): field-level codes are a separate vocabulary; #3977 owns its catalog. - ANONYMOUS_DENY_CODE 'unauthenticated' -> 'UNAUTHENTICATED' (promoted into error.code on the dispatcher surface, so it must be catalogued). - Rewrite error-catalog.mdx to the two-tier model and lock its headings to the enum with a new spec test; update the error-handling guides. - Regenerate json-schema manifest, api-surface, docs references. Batches 2 (lowercase emitter sweep) and 3 remain per the ADR's Rollout. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MaSQn77TT5fUgHK9CesaDK * docs: regenerate contract reference after timeout revert; fix stale derived-code casing in api index Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MaSQn77TT5fUgHK9CesaDK * docs(api): derived-code examples in the API overview follow ADR-0112 casing Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MaSQn77TT5fUgHK9CesaDK * docs,skills: regenerate skill reference indexes; docs examples follow ADR-0112 casing check:skill-refs and check:skill-examples gates — the skill reference index derives from spec schemas (new error-code-ledger page), and the prose-example compiler caught one remaining lowercase member literal. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MaSQn77TT5fUgHK9CesaDK --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 347f460 commit 32ccb23

44 files changed

Lines changed: 1185 additions & 462 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
"@objectstack/spec": minor
3+
"@objectstack/core": minor
4+
"@objectstack/runtime": minor
5+
---
6+
7+
feat(spec,core,runtime)!: ADR-0112 batch 1 — one error-code vocabulary, SCREAMING_SNAKE, schema-enforced (#3841)
8+
9+
Settles #3841 per ADR-0112: the top-level `error.code` vocabulary is
10+
SCREAMING_SNAKE, in two tiers.
11+
12+
- **`StandardErrorCode` members renamed in place** (`validation_error`
13+
`VALIDATION_ERROR`, all 53). Breaking for importers that branch on the old
14+
lowercase members; the type name and member *meanings* are unchanged.
15+
- **New `ERROR_CODE_LEDGER`** (`@objectstack/spec/api`): service-specific codes
16+
(`AUTH_REQUIRED`, `VALIDATION_FAILED`, `ATTACHMENT_DOWNLOAD_DENIED`, …) are
17+
registered per owning package. `ErrorCode` = standard ∪ registered.
18+
- **`ApiErrorSchema.code` is now `ErrorCode`**, not `z.string()` — an
19+
unregistered code fails parse, so the envelope conformance suites assert
20+
values, not just shape.
21+
- **`FieldErrorSchema.code` widened to `z.string()`** (ADR-0112 D6): field-level
22+
codes are a separate vocabulary the enum never described; #3977 owns its real
23+
catalog.
24+
- **Derived codes changed case on the wire**: `standardErrorCodeForHttpStatus`
25+
now yields SCREAMING members (`permission_denied``PERMISSION_DENIED`,
26+
`method_not_allowed``METHOD_NOT_ALLOWED`, …) — this map was #3842's
27+
designated one-file sweep point for exactly this decision.
28+
- **`ANONYMOUS_DENY_CODE` is `'UNAUTHENTICATED'`** (was `'unauthenticated'`) —
29+
the promoted code on anonymous-denied requests and the REST `enforceAuth`
30+
body change spelling with it.
31+
32+
`error-catalog.mdx` and the error-handling guides are rewritten to the single
33+
vocabulary; a spec test now locks the catalog page's headings to the enum so
34+
they cannot drift apart again. Remaining lowercase emitters (cloud-connection,
35+
plugin-auth envelope codes, metadata-protocol, …) are the batch-2 sweep.

content/docs/api/client-sdk.mdx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ All errors follow a standardized format:
511511
try {
512512
await client.data.create('todo_task', { subject: '' });
513513
} catch (error) {
514-
console.error(error.code); // 'validation_error'
514+
console.error(error.code); // 'VALIDATION_ERROR'
515515
console.error(error.category); // 'validation'
516516
console.error(error.httpStatus); // 400
517517
console.error(error.retryable); // false
@@ -554,15 +554,15 @@ field-anchored".
554554

555555
| Code | HTTP | Category | Retryable | Description |
556556
|:-----|:-----|:---------|:----------|:------------|
557-
| `validation_error` | 400 | validation | No | Input validation failed |
558-
| `invalid_query` | 400 | validation | No | Malformed query expression |
559-
| `unauthenticated` | 401 | authentication | No | Authentication required |
560-
| `permission_denied` | 403 | authorization | No | Insufficient permissions |
561-
| `resource_not_found` | 404 | not_found | No | Resource does not exist |
562-
| `rate_limit_exceeded` | 429 | rate_limit | Yes | Too many requests |
563-
| `internal_error` | 500 | server | Yes | Unexpected server error |
564-
| `service_unavailable` | 503 | server | Yes | Service temporarily unavailable |
565-
| `not_implemented` | 501 | server | No | Service not installed (plugin missing) |
557+
| `VALIDATION_ERROR` | 400 | validation | No | Input validation failed |
558+
| `INVALID_QUERY` | 400 | validation | No | Malformed query expression |
559+
| `UNAUTHENTICATED` | 401 | authentication | No | Authentication required |
560+
| `PERMISSION_DENIED` | 403 | authorization | No | Insufficient permissions |
561+
| `RESOURCE_NOT_FOUND` | 404 | not_found | No | Resource does not exist |
562+
| `RATE_LIMIT_EXCEEDED` | 429 | rate_limit | Yes | Too many requests |
563+
| `INTERNAL_ERROR` | 500 | server | Yes | Unexpected server error |
564+
| `SERVICE_UNAVAILABLE` | 503 | server | Yes | Service temporarily unavailable |
565+
| `NOT_IMPLEMENTED` | 501 | server | No | Service not installed (plugin missing) |
566566

567567
---
568568

0 commit comments

Comments
 (0)