Repository navigation
fix(objectql): a plugin driver's request-shaped read refusal answers 400 INVALID_QUERY with its message, not 503 retry-later - #27648
Conversation
…ers 400 with its message Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ihL2fT4drj3TCsV9G9CPh
… failure paragraph names each answer Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ihL2fT4drj3TCsV9G9CPh
📓 Docs Drift CheckThis PR changes 1 package(s): 12 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 2 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 19 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 19a68416bc60b8963d895d1aaad9ee98eab872d7 && git checkout 19a68416bc60b8963d895d1aaad9ee98eab872d7
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 9d5ebfdef05caf03b5b0f2013873f1f704c8145b e9672b771a25cc357584c0ae6e4373e7646e22ee && git checkout -B drift-repro 9d5ebfdef05caf03b5b0f2013873f1f704c8145b && git merge --no-ff e9672b771a25cc357584c0ae6e4373e7646e22ee
node scripts/docs-audit/affected-docs.mjs --json 9d5ebfdef05caf03b5b0f2013873f1f704c8145b
|
|
epic:#27261#1 · marchtian · session_017ihL2c5z3q4h8inrn5kwqV The seat review and an independent full Fable review agree. Both fixes are small; the status mapping, guide edits, changeset and tests otherwise hold. Must fix
|
… withholds its text when the where carries a policy predicate Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ihL2fT4drj3TCsV9G9CPh
|
epic:#27261#1 · marchtian · session_017ihL2c5z3q4h8inrn5kwqV 维护者速读
席位意见:ACCEPT。round 0 由独立 Fable 复核 REWORK(两项 must-fix),本轮 席位核对
|
Requested by 田騏 · project thread
Fixes #27471
Clause-②: no
Metadata-protocol: none
维护者速读
find抛出带请求型状态(status/statusCode为 400、404、422)的错误时,调用方现在拿到400 INVALID_QUERY,消息就是 driver 自己的原话;其余失败(5xx、连不上、没声明状态、401/403/407/429)照旧是503 ERR_DATASOURCE_UNAVAILABLE、原文不外泄。指南里的refuse()现在带status: 400,失败段落逐条写明调用方看到什么。INVALID_QUERY)。回滚即还原本 PR。packages/objectql/src/external-driver-floor.ts(readCapped的 catch 分支)、packages/objectql/src/external-driver-errors.ts(ExternalReadRefusedError与状态集合)、content/docs/data-modeling/virtual-objects.mdx(refuse()与失败段落)。pnpm --filter @objectstack/objectql exec vitest run --maxWorkers=2 src/external-driver-floor.test.ts,预期 45/45 通过,其中[#27471]一组 14 条。What changes
packages/objectql/src/external-driver-errors.ts:EXTERNAL_READ_REFUSED_STATUSES(400, 404, 422) andExternalReadRefusedError, which carries the standardINVALID_QUERYcode,status/httpStatus400, the driver's message, anddetails(datasource,object,operation: 'find',remoteStatus). It has the same shape asExternalWriteRefusedError. No new ledger code:INVALID_QUERYis aStandardErrorCodemember, and REST already treats it as an expected query rejection (no unhandled-error log line).packages/objectql/src/external-driver-floor.ts: the floor'sfindcatch reads the declared status the same way the write path does (declaredStatus:status, thenstatusCode). A status in the read set throws the 400 refusal, with the original error ascause. Everything else still goes throughremoteFailure, so it stays 503, reasonremote, with the text logged atwarnand withheld from the caller.findOneandcountread through the samereadCapped, so they get the same answer. The refusal leaves the engine through the existing boundary (redactPropagatedDriverFaultin the middleware seam), which cuts bound statement text the same way it does for any driver error.packages/objectql/src/index.ts: exportsExternalReadRefusedErrorandEXTERNAL_READ_REFUSED_STATUSESnext to the write-side exports.content/docs/data-modeling/virtual-objects.mdx: the guide'srefuse()now throws withstatus: 400, which is the status the engine reads. The "Fail when the remote fails" bullet now lists, per status, what the caller sees: a refused read answers 400INVALID_QUERY, a refused write answers 422EXTERNAL_WRITE_REFUSED, and everything else answers 503. The guide's own driver test also pinsstatus: 400..changeset/27471-external-read-refusal-400.md:@objectstack/objectqlpatch.Tests
packages/objectql/src/external-driver-floor.test.tshas a new[#27471]block with 14 cases, run through the real engine:refuse()getsExternalReadRefusedError/INVALID_QUERY/ 400, with the driver's sentence anddetails, onfind,findOneandcount.statusand asstatusCode, each answer 400 with the driver's message andremoteStatus.ERR_DATASOURCE_UNAVAILABLE,kind: 'remote', with the text withheld. 409 and 412 are write-only refusal statuses and stay 503 on a read.Results at head 9773776:
pnpm --filter @objectstack/objectql exec vitest run --maxWorkers=2 src/external-driver-floor.test.ts: 45/45 passed.pnpm --filter @objectstack/objectql test(under the verify lock): Test Files 487/487, Tests 9163/9163, VERDICT command-exit 0.pnpm --filter @objectstack/objectql typecheck: exit 0, test layer held intest-typecheck-debt.json.Ablation (one-shot, not kept)
node scripts/ablation-replace.mjs --file packages/objectql/src/external-driver-floor.ts --anchor "if (status !== undefined && EXTERNAL_READ_REFUSED_STATUSES.has(status)) {" --replacement "if (false && status !== undefined && EXTERNAL_READ_REFUSED_STATUSES.has(status)) {"git diff HEADis empty../enginefrom source, so no dist rebuild was involved.Acceptance notes
INVALID_QUERYoverINVALID_FILTERbecause the guide'srefuse()also refuses an unmapped object and unsupported operations, not only filter terms.codeon a 400/404/422 throw is replaced byINVALID_QUERY. The driver's object is kept ascause.notSupported, which now carriesstatus: 400throughrefuse(). So a refused write on that skeleton answers 422EXTERNAL_WRITE_REFUSEDwith the driver's sentence, where it used to answer 503. The paragraph states this.Verification
Gates were derived with
node scripts/pm/dispatch-gates.mjs --commands(no paths) and reconciled with--ran; the verdict at head 9773776: "91 derived famil(ies) accounted for — 91 run, 0 NOT-MEASURED (a DERIVED zero)". All 91 exited 0. Four first exited 3 or timed out on prerequisites (a shallow clone missing the teardown fixture commit,dist/not yet built, and the 400 s per-gate timeout oncheck:type-check-debt); each was re-run after its prerequisite and exited 0.CI check-runs on this PR carry every family CI runs; they are cited in the os-dev report, not re-run locally.
Generated by Claude Code
🤖 Generated with Claude Code
https://claude.ai/code/session_017ihL2fT4drj3TCsV9G9CPh