Repository navigation
fix(types): an undeclared hook abort answers HOOK_ABORTED on package publish and the runtime /actions doors - #27898
Conversation
…s that read resolveThrownHttpError resolveThrownHttpError now answers UNDECLARED_HOOK_REFUSAL_CODE for a sandboxed body's refusal that declared no code, at a 4xx status, so POST /api/v1/packages/publish and the runtime /actions doors answer the code /api/v1/data has answered since HOOK_ABORTED landed, instead of the VALIDATION_ERROR their 400 derives. A declared code is kept. The constant is declared beside the resolver; sandboxBusinessMessage moves to its own module so the resolver reads it without an import cycle. The package's exported names are unchanged. The pins that held VALIDATION_ERROR on those doors are flipped on purpose. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4d1iG6EQSWf7veWbAar
📓 Docs Drift CheckThis PR changes 1 package(s): 1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
What this run could not see
Coarse fallback — 9 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 14226c7c3aaf2863d577fccbce27197724cd8b2b && git checkout 14226c7c3aaf2863d577fccbce27197724cd8b2b
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 04740b7c9f55e3c6f69fa65ec0b467732366fe17 9a34ac1b8a9aa5c70f587631b179c2352b6e3f5a && git checkout -B drift-repro 04740b7c9f55e3c6f69fa65ec0b467732366fe17 && git merge --no-ff 9a34ac1b8a9aa5c70f587631b179c2352b6e3f5a
node scripts/docs-audit/affected-docs.mjs --json 04740b7c9f55e3c6f69fa65ec0b467732366fe17
|
|
domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL 维护者速读
席位意见:ACCEPT。 席位核对Head-sha:
|
Requested by Elon · project thread
Fixes #27672
Clause-②: no
Metadata-protocol: none
维护者速读
/actions两类门现在也答HOOK_ABORTED,与/api/v1/data一致,不再答VALIDATION_ERROR。onErrorabort answers the data door with a code-less 400; give it a ledgered ADR-0112 code (#27508 code half) #27597 只让/data答HOOK_ABORTED,其它从resolveThrownHttpError取码的门仍按 400 推导,客户端按码分支时得先知道是哪个门。packages/types/src/thrown-http-error.ts(undeclaredHookAbort一段)、packages/types/src/data-error-classification.ts(搬出sandboxBusinessMessage)、packages/runtime/src/domains/actions-undeclared-hook-abort-code.test.ts。pnpm --filter @objectstack/runtime exec vitest run src/domains/actions-undeclared-hook-abort-code.test.ts,预期 7 个全绿。What changes
resolveThrownHttpError(@objectstack/types) now answersUNDECLARED_HOOK_REFUSAL_CODE(HOOK_ABORTED) for a sandboxed body's refusal that declared no code, at a 4xx status. It is the one constant/api/v1/datahas read since error codes: an undeclared hookonErrorabort answers the data door with a code-less 400; give it a ledgered ADR-0112 code (#27508 code half) #27597, now declared beside the resolver;sandboxRefusalCodeFieldsreads the same constant./data:POST /api/v1/packages/publish(@objectstack/rest,sendThrownError) and the runtime/actionsdoors (errorFromThrown). No route source changes; both already call the resolver.sandboxBusinessMessage(with its privateisScriptFaultMessage) moved verbatim topackages/types/src/sandbox-business-message.ts:data-error-classification.tsimportsthrown-http-error.ts, so the resolver could not read it from there without a cycle.data-error-classification.tsre-exports it, so@objectstack/typesexports the same names as before. The platform-checklist anchor for it follows the move.code; unregistered →declaredCodebeside the derivedcode);declaredCodestays absent for an undeclared abort; a non-sandbox producer, a crash, and a sandboxed refusal resolved at a 5xx answer as before.Tests
packages/types/src/thrown-http-error-undeclared-hook-abort.test.ts(resolver, §1 the card, §2 controls),packages/rest/src/package-door-undeclared-hook-abort-code.test.ts(publish door),packages/runtime/src/domains/actions-undeclared-hook-abort-code.test.ts(/actions: an action body's throw, a hook abort relayed through an action body, a declared 4xx status; controls).VALIDATION_ERRORtoHOOK_ABORTED, each with a[#27672] FLIPPEDnote: the publish row ofrest-write-route-hook-refusal-sentence.ledger.test.ts; the four rows ofactions-hook-refusal-sentence.ledger.test.ts;nested-hook-refusal-is-a-rejection.test.ts("matches /data", which it does again); the thrown-Error control insandbox-plain-object-throw-client-sentence.test.ts;throw ''andthrow Object.create(null)insandbox-unreadable-rejection-door.test.ts.Acceptance notes
resolveThrownHttpErrorinpackages/rest/src/error-response.ts; it is defined inpackages/types/src/thrown-http-error.ts(rest imports it). The fix is there, per the ruling ("resolveThrownHttpErroranswersHOOK_ABORTED"); the seat amended the claim's file surface.logUnexpectedRouteError(rest: a hook onError abort answers the data door with a 400 that carries no error code, and the server logs it as an unhandled SandboxError #27508) is untouched.classifyDataError(an abort whoseSandboxErrorinstance was lost, noinnerMessage) keeps answering the constant throughsandboxRefusalCodeFields, because the resolver has no marker to read there.Verification
Ablation (resolver arm removed, types rebuilt) → restore
/datapins staying green; runtime (5 touched files) 11 failed / 21 passed. Every control stayed green.Suites on the final tree (after merging main)
@objectstack/types: Test Files 32 passed, Tests 817 passed.@objectstack/rest: Test Files 353 passed, Tests 7025 passed | 350 skipped.@objectstack/runtime: Test Files 484 passed, Tests 8784 passed | 19 skipped.@objectstack/metadata-protocol21822 passed | 26 skipped,@objectstack/service-automation2795 passed,@objectstack/plugin-hono-server448 passed,@objectstack/cloud-connection758 passed. No pin moved there.Gates
node scripts/pm/dispatch-gates.mjs --ran: 64 derived families accounted for — 63 run (exit 0), 1 NOT MEASURED:pnpm check:dual-build-cjs-loadsexit 3 (needs every package's dist; CI builds the whole tree).pnpm lint: exit 0.check-governed-merges --teston the touched paths: NOT governed.Generated by Claude Code
🤖 Generated with Claude Code
https://claude.ai/code/session_016WV4d1iG6EQSWf7veWbAar