Repository navigation
Commit 0e1311d
refactor(runtime): errorFromThrown builds its answer from the one types composition (#31437)
<!-- claude-projects-attribution: {"github_login":"os-project-manager"}
-->
_Requested by **Leehom** · [project
thread](https://claude.ai/code/project/chan_01TenzsRopZj4jMbvjX8uz1X?thread=cmsg_01TenzsRopZj4jMbvjX8uz1X1nhftM2hZHHvqk2GLFyVTN)_
domain:server#3 · os-project-manager · session_01FEkQ5nBSzc6ktJyjdFcDb3
Fixes #31319
Clause-②: no (fold onto one composition, no wire change)
Metadata-protocol: none
## 维护者速读
- 改了什么:runtime 分发器对「抛出的错误」组装回答的函数
`HttpDispatcher.errorFromThrown`,不再自己逐项拼(封闭 code、引擎唯一约束的线上拼写与上下文、降级的
`declaredCode`、`userMessage`、5xx 泄露文本收回),改为调用 `@objectstack/types` 新导出的
`thrownAnswerOf`;`/actions` 门的读者 `actionsDoorAnswerOf` 的两个分支也用它。只剩一份组装。
- 为什么改:#31315 之后同一个回答有两份组装,今天一致,但没有任何东西把它们绑在一起,改一边另一边会悄悄落后(#31270–#31272
收口的就是这一类漂移)。
- 风险与回滚:线上回答不变:工单点名的四个分发器
pin(`http-dispatcher.error-leak`、`dispatcher-5xx-demoted-code-withhold`、`package-door-error-parity`、`error-envelope.conformance`)零改动全绿,runtime
全量测试全绿。`@objectstack/types` 多一个公开导出。回滚即还原本 PR。
- 先看:`packages/runtime/src/http-dispatcher.ts` 的 `errorFromThrown`(由约 40
行缩为一次调用),`packages/types/src/actions-door-answer.ts` 的
`thrownAnswerOf`,`packages/runtime/src/dispatcher-thrown-answer-tie.test.ts`。
- 两分钟验证:`pnpm --filter @objectstack/runtime exec vitest run
src/dispatcher-thrown-answer-tie.test.ts`(先 build
`@objectstack/types`),预期 7 条全绿。
- 需要你做的:无,席位落地(新增一个公开导出,落地前按惯例做一次契约复审)。
## What changes
- **`@objectstack/types`: new `thrownAnswerOf(err, fallbackStatus)` and
its `ThrownAnswer` type** (`src/actions-door-answer.ts`). It is the body
of the old private `thrownAnswer` (arms 3 and 7 of
`actionsDoorAnswerOf`), lifted out without the door's operator lines:
`status`, the closed `code` (the engine duplicate's ruled wire spelling
read off `structuredCodeAnswer`), `message` (leaky 5xx withheld),
`declaredCode` (`demotedDeclaredCode`), `userMessage`, `details`
(resolver `issues` / `fields` plus the duplicate arm's agreeing
context). `actionsDoorAnswerOf`'s arms 3 and 7 now return `{
...thrownAnswerOf(err, fallback), operatorLines }`; its answers are
unchanged.
- **`@objectstack/runtime` `HttpDispatcher.errorFromThrown`**: builds
`declaredCode` / `userMessage` extra from `thrownAnswerOf` and hands the
answer to `this.error`, which stays the one construction point for the
envelope. The private `duplicateArmContext` helper is removed with its
only caller (its job is the `armContext` term inside `thrownAnswerOf`),
and the now-unused imports go with it. The method's docblock keeps its
history; its one `{@link duplicateArmContext}` now names
`thrownAnswerOf`.
## Tests
- New `packages/runtime/src/dispatcher-thrown-answer-tie.test.ts` (7
rows), the tie pin. Each row throws the same value at the real
`/actions` door (`HttpDispatcher.handleActions`) and at the dispatcher
exit (`errorFromThrown`, at the fallback the door's arm reads: 500 for a
declared status, 400 for a rejection) and asserts equal `{ status, body
}`, then states the term the row carries: the engine duplicate
(`UNIQUE_VIOLATION` + `object` / `field` context), a producer merely
speaking `DUPLICATE_RECORD`, an unregistered code demoted to
`declaredCode`, a leaky declared 503 withheld, a `userMessage`,
`issues`, and a record `ValidationError`'s `fields`.
- After the fold the two exits cannot drift by construction (one
function), so the pin's job is to go red if a later change re-composes
either exit by hand. Ablation below shows it does.
- The four dispatcher pins the card names pass with zero edits.
## Acceptance notes
- **Why a pin as well as the fold.** The fold makes drift between these
two exits structurally impossible today. The pin is the cheap guard
against a future edit that re-inlines one term at one exit; it costs one
file.
- **Not folded: `dispatcher-plugin`'s `errorResponseBase`** (the exit
for a throw that LEAVES `dispatch()`), whose docblock already declares
that it does not carry the engine-duplicate translation. Out of this
card's surface; unchanged.
- **Worktree name.** The claim names `objectstack-issue-31319`; this ran
in the chain's existing worktree `objectstack-issue-31317` on the same
claimed branch.
- **Branch.** Rebuilt from fresh `origin/main` after #31397 merged; the
merged branch had already been deleted on GitHub, so this is a new
branch push, no force.
## Verification
Head `b8888585` (base `db502314`, the #31397 merge; `origin/main`
`383c3530` merged once before opening).
<details><summary>No wire change, suites</summary>
- The four dispatcher pins the card names, unedited, after the fold:
`http-dispatcher.error-leak.test.ts`,
`dispatcher-5xx-demoted-code-withhold.test.ts`,
`package-door-error-parity.test.ts`,
`error-envelope.conformance.test.ts` with the new tie pin: Test Files 5
passed (5), Tests 118 passed (118).
- `@objectstack/types` vitest: Test Files 38 passed (38), Tests 881
passed (881).
- `@objectstack/runtime` vitest (types from the rebuilt dist): Test
Files 560 passed (560), Tests 10323 passed, 19 skipped; lock VERDICT
command-exit 0. No existing pin edited.
- `typecheck` for `@objectstack/types` and `@objectstack/runtime`: exit
0. `eslint --no-inline-config packages/types packages/runtime`: exit 0.
- `@objectstack/mcp` not re-run: its source is untouched,
`actionsDoorAnswerOf`'s answers are unchanged and the types change is an
added export.
</details>
<details><summary>Ablation of the tie pin (ablation-replace, restored to
HEAD)</summary>
- `packages/runtime/src/http-dispatcher.ts`: `errorFromThrown` made to
drop the `userMessage` term (`&& String("ABL31319").length < 0` on its
spread), a hand-made drift at one exit. Mutation landed (anchor 1 to 0,
blob fce6d0b to 25ec094ea41b).
`dispatcher-thrown-answer-tie.test.ts`: Tests 1 failed | 6 passed (7),
the `userMessage` row, `AssertionError: expected { status: 409, body: {
…(2) } } to deeply equal { status: 409, body: { …(2) } }`. The runtime
suite reads its own `src/`, so no dist leg.
- Restore: blob == HEAD (fce6d0b), `git diff HEAD` empty, `git
status --porcelain` empty.
</details>
<details><summary>Derived gates</summary>
`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` at `b8888585`: 68 commands, each run with
`timeout 1500` and stdin from `/dev/null`, exit codes captured before
any pipe, all exit 0 on the first run (after a `@objectstack/runtime`
closure build). `dispatch-gates --ran`: 68 derived, 68 run, 0
NOT-MEASURED, 0 UNRUN. Plus the typechecks, scoped eslint and the two
full suites above. Not run locally (CI): `test:repo`, dogfood shards,
type-check lanes.
</details>
---
_Generated by [Claude
Code](https://claude.ai/code/session_01FEkQ5nBSzc6ktJyjdFcDb3)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent deac7f4 commit 0e1311d
4 files changed
Lines changed: 216 additions & 89 deletions
File tree
- .changeset
- packages
- runtime/src
- types/src
| 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 | + | |
| 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 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
20 | | - | |
| 20 | + | |
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
| |||
391 | 391 | | |
392 | 392 | | |
393 | 393 | | |
394 | | - | |
395 | | - | |
396 | | - | |
397 | | - | |
398 | | - | |
399 | | - | |
400 | | - | |
401 | | - | |
402 | | - | |
403 | | - | |
404 | | - | |
405 | | - | |
406 | | - | |
407 | | - | |
408 | | - | |
409 | | - | |
410 | | - | |
411 | | - | |
412 | | - | |
413 | | - | |
414 | | - | |
415 | | - | |
416 | | - | |
417 | | - | |
418 | | - | |
419 | | - | |
420 | | - | |
421 | | - | |
422 | | - | |
423 | | - | |
424 | | - | |
425 | | - | |
426 | | - | |
427 | | - | |
428 | | - | |
429 | | - | |
430 | | - | |
431 | 394 | | |
432 | 395 | | |
433 | 396 | | |
| |||
1240 | 1203 | | |
1241 | 1204 | | |
1242 | 1205 | | |
1243 | | - | |
| 1206 | + | |
1244 | 1207 | | |
1245 | 1208 | | |
1246 | 1209 | | |
| |||
1253 | 1216 | | |
1254 | 1217 | | |
1255 | 1218 | | |
1256 | | - | |
1257 | | - | |
1258 | | - | |
1259 | | - | |
1260 | | - | |
1261 | | - | |
1262 | | - | |
1263 | | - | |
1264 | | - | |
1265 | | - | |
1266 | | - | |
1267 | | - | |
1268 | | - | |
1269 | | - | |
1270 | | - | |
1271 | | - | |
1272 | | - | |
1273 | | - | |
1274 | | - | |
1275 | | - | |
1276 | | - | |
1277 | | - | |
1278 | | - | |
1279 | | - | |
1280 | | - | |
1281 | | - | |
1282 | | - | |
1283 | | - | |
1284 | | - | |
1285 | | - | |
1286 | | - | |
1287 | | - | |
1288 | | - | |
1289 | | - | |
1290 | | - | |
1291 | | - | |
1292 | | - | |
1293 | | - | |
1294 | | - | |
1295 | | - | |
1296 | | - | |
1297 | | - | |
1298 | | - | |
| 1219 | + | |
| 1220 | + | |
| 1221 | + | |
| 1222 | + | |
| 1223 | + | |
| 1224 | + | |
| 1225 | + | |
| 1226 | + | |
| 1227 | + | |
| 1228 | + | |
1299 | 1229 | | |
1300 | | - | |
1301 | | - | |
| 1230 | + | |
| 1231 | + | |
1302 | 1232 | | |
1303 | 1233 | | |
1304 | | - | |
| 1234 | + | |
1305 | 1235 | | |
1306 | 1236 | | |
1307 | 1237 | | |
1308 | 1238 | | |
1309 | | - | |
1310 | 1239 | | |
1311 | 1240 | | |
1312 | 1241 | | |
| |||
0 commit comments