Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .changeset/analytics-read-scope-compile-failed-500.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -67,7 +67,12 @@ the disclosure question to be re-decided message by message).
`@objectstack/service-analytics` (ADR-0112 D3) and typed as
`RegisteredErrorCode` at the constructor, so an unregistered code is a compile
error. It is legible on the wire through the sibling `/analytics/query` exit,
which puts a thrown `err.code` in `error.details.code` (#3842).
which puts a thrown `err.code` at **`error.code`** (#3842) — read it there.
`errorResponseBase` only stages the code inside a `details` object;
`buildApiError` then runs `splitSemanticCode`, which promotes it into the
declared `error.code` field and drops the now-empty `details`, so the key is
omitted from the body and `error.details.code` is never present:
`{"success":false,"error":{"code":"READ_SCOPE_COMPILE_FAILED","message":"Internal server error","httpStatus":500}}`.

**Which inputs are refused did not change.** No refusal condition moved: nothing
that used to lower now throws, and nothing that used to throw now lowers. That is
Expand Down
23 changes: 20 additions & 3 deletions packages/services/service-analytics/src/read-scope-sql.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -123,9 +123,26 @@ import { likePattern, LIKE_ESCAPE_CHAR } from './like-pattern.js';
* remove; the route keys on the DECLARATION instead.
*
* The code is what a machine reads: `dispatcher-plugin.errorResponseBase`, the
* sibling `/analytics/query` exit, puts a thrown `err.code` in
* `error.details.code` (#3842), so `READ_SCOPE_COMPILE_FAILED` is legible there
* without anyone parsing prose.
* sibling `/analytics/query` exit, puts a thrown `err.code` on the wire at
* `error.code` (#3842), so `READ_SCOPE_COMPILE_FAILED` is legible there without
* anyone parsing prose.
*
* ⚠️ At `error.code` — NOT `error.details.code`, which is where this note
* pointed until #6123 corrected it. `errorResponseBase` only STAGES the code in
* a `details` object; `buildApiError` then runs `splitSemanticCode`
* (`@objectstack/runtime`, `src/error-envelope.ts:117`), which PROMOTES it into
* the declared `ApiErrorSchema` field and returns the now-empty `details` as
* `undefined` — so the key is omitted from the body and `error.details.code` is
* never present to read. The measured 500 body is exactly:
*
* ```json
* {"success":false,"error":{"code":"READ_SCOPE_COMPILE_FAILED",
* "message":"Internal server error","httpStatus":500}}
* ```
*
* Pinned end-to-end in `@objectstack/runtime`'s
* `analytics-query-read-scope-withhold.test.ts`, which asserts the code at
* `error.code` against a real `AnalyticsService` on a real mounted route.
*
* ⚠️ Deliberately NOT a 4xx of any flavour, including a 422. Option A on the
* decision card was `READ_SCOPE_INVALID` / 422 ("not your fault, not a crash");
Expand Down
Loading