Repository navigation
fix(objectql): the nested-relation condition refusal prints its route inside the client cap - #27531
Conversation
…ide the client cap Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L6bhgXcN9HaZYSEUdJWEjw
… inside the client cap Every reason of relationConditionRefusalMessage now reads head, short reason, route, then "NOT applied" and any reasoning. The head names the column by its type after the path, and both shared heads (describeKeys, describeObject) name the first key and count the rest, so the no-operator-object refusal's stress fixture keeps its route inside the cut too. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L6bhgXcN9HaZYSEUdJWEjw
Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L6bhgXcN9HaZYSEUdJWEjw
Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L6bhgXcN9HaZYSEUdJWEjw
…lation-refusal-route-first
…lation-refusal-route-first
📓 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 — 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 758592682ba496fa71ed542a2a8e37a637d1c34e && git checkout 758592682ba496fa71ed542a2a8e37a637d1c34e
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 57c51aab4d2f63293676e9412daed8a5fc54c1bc 2eb99b8ab084ba5e002946acdae297eb03e92d72 && git checkout -B drift-repro 57c51aab4d2f63293676e9412daed8a5fc54c1bc && git merge --no-ff 2eb99b8ab084ba5e002946acdae297eb03e92d72
node scripts/docs-audit/affected-docs.mjs --json 57c51aab4d2f63293676e9412daed8a5fc54c1bc
|
|
domain:server#1 · os-sales · session_01L6bhgXcN9HaZYSEUdJWEjw 维护者速读(席位终稿)
席位核对 — ACCEPT ·
|
Requested by Sales · project thread
Fixes #27351
Clause-②: no
Metadata-protocol: none
Skills-docs: none (kind
none, no narrowing arm; noskills/**file touched)维护者速读
where里拒收嵌套关联条件(第二层关联、带点的键、空对象、未声明的键、未注册的关联对象)时,报错文字改为"位置 + 简短原因 + 该怎么写 + 未执行 + 补充原因";两类拒收的开头只列条件里的第一个键并计数其余键。$in写法);长名字下 fix(objectql): the no-operator-object refusal prints its route inside the client cap #27350 的无运算符对象拒收也仍有 6 行被截。INVALID_FILTER、状态 400、500 字符截断都不变;回滚即 revert 本 PR。packages/objectql/src/relation-filter-lowering.ts(relationConditionRefusalMessage五个分支与describeKeys)、packages/objectql/src/no-operator-object-door.ts(describeObject)、packages/objectql/src/relation-condition-prescription-cap.test.ts。pnpm --filter @objectstack/objectql exec vitest run src/relation-condition-prescription-cap.test.ts src/no-operator-object-prescription-cap.test.ts,预期 2 个文件 20/20 通过。What changes
packages/objectql/src/relation-filter-lowering.ts,relationConditionRefusalMessage: every reason now reads head, short reason, route, then "The filter was NOT applied." and any reasoning, so the route sits inside the 499 characters a client reads (CLIENT_MESSAGE_MAX,@objectstack/types, unchanged).…, and 'KEY' holds a condition of its own: one level only. Read 'TARGET' with { "KEY": { … } }, then match its ids: ROUTE. The filter was NOT applied. 'KEY' is itself a TYPE field of the related object 'TARGET'.at PATH, beneath the lookup field): the head already names the field twice (filter on 'FIELD' … at PATH.FIELD). The route names the field only in its spelling (then match its ids:,Match ids you hold:,or test for a value:).an $or of { "FIELD": { "$contains": ID } }, one per id(was{ "FIELD": { "$contains": ID } } for one id, an $or of those for several).idsRouteis shared, so the cap refusal (relationFilterCapError) prints the same spelling.describeKeyshere anddescribeObjectinno-operator-object-door.ts(keys "region", and 2 more, was three keys listed). This closes the residue PR fix(objectql): the no-operator-object refusal prints its route inside the client cap #27350 recorded on the no-operator-object refusal's stress fixture, which the triage ruling asked to be measured in this PR.INVALID_FILTER/ 400, the envelope, the cap and the truncation, and the phrases other packages' tests read (names no field of the related object,'KEY' is itself a lookup field of the related object 'X',is a dotted path: the condition reaches one level only,{ "FIELD": { "$null": false } },{ "FIELD": { "$in": [ID, …] } },The filter was NOT applied.).Tests
relation-condition-prescription-cap.test.ts: for each of the five reasons, on three fixtures, the refusal is read throughmapDataErroras a client reads it. The test requires400+INVALID_FILTER, the whole route in the client text, the route ahead of "NOT applied", and the route ending by the fixture's limit. The card's fixture (21-character object and field, 16-character target, three keys, nested$and/$or) has a limit of 459, which is 40 inside the cut. The stress fixture (27-character object and target, 32-character field, four 11- to 15-character keys, three-deep path), single- and multi-valued, has a limit of 499. That makes 15 tests.no-operator-object-prescription-cap.test.tsgains a stress block: every kind at every position it is refused, on a 27-character object and target, 32-character fields, a four-key object, andaggregations[12].filterwith a three-deep path. The route must end by 499.engine-nested-relation-lowering.test.tsnow assertsat PATH, beneath the (lookup|tree) field, and.protocol-explicit-filter-field-gate.test.tsnow asserts… at where.owner_id, beneath the lookup field,.Package runs (head 2eb99b8, after merging origin/main f57eddc)
pnpm --filter '@objectstack/objectql...' build, thenpnpm --filter @objectstack/objectql typecheck(tsc +check:test-typecheckOK), thenpnpm --filter @objectstack/objectql test: Test Files 484 passed (484), Tests 9104 passed (9104). Thenpnpm --filter @objectstack/rest exec vitest run --maxWorkers=2 src/data-nested-object-door.test.ts src/data-no-operator-object-door.test.ts: 10 passed, 20 skipped (the live PostgreSQL / MySQL cells, with no env here; the SQLite cell ran, and it asserts the second-level, empty and undeclared words and routes on the REST body). The lock printedVERDICT command-exit 0.npx eslint --no-inline-config packages/objectql: exit 0.Ablation (fix committed first; each leg through scripts/ablation-replace.mjs)
relationConditionRefusalMessage's head-and-switch span was replaced by itscf218eed1text, which restores the old order. The anchor went from 1 to 0 and the blob from2f1d2a495ff1tob8031a3df929. Result:relation-condition-prescription-cap.test.tshad 15 failed (15). Examples: "the route ends at 496; the limit is 459" (the card's second-level reason);expected 303 to be greater than 420(the card's unregistered reason, where "NOT applied" comes before the route); "the client text holds the whole route" on the stress rows. After restore the blob equals HEAD andgit diff HEADis empty.describeObjectwas set back to listing three keys. The anchor went from 1 to 0 and the blob fromc06bf275a4efto4584cc487e38. Result:no-operator-object-prescription-cap.test.tshad 1 failed | 4 passed (5): the stress block, where the client text no longer holdsMove the condition to 'where', or f…. After restore the blob equals HEAD andgit diff HEADis empty.The tests import the subject by a relative
srcpath, so nodistbuild sits between the test and the edit.Verification — route offsets before and after
Measured with
tsxthroughnarrowNumberComparands/narrowHavingNumberComparandsand read the way a client reads it. "Before" is atcf218eed1's two producer files and "after" is this head. cut means the route ends past 499.Nested-relation condition refusal (where)
No-operator-object refusal, stress fixture (the #27350 residue)
Acceptance notes
aggregations[12].filterends at 498, 1 inside the cut. On the relation stress fixture the multi-valued rows end at 477–479. The card-sized fixtures keep 40+ characters of margin, and so does fix(objectql): the no-operator-object refusal prints its route inside the client cap #27350's own fixture. A longer fixture still could be cut. The next lever would be the per-kind route words, not the head, which now names one key.idsRouteis shared. The meaning is the same, and the cap test's{ "owners": { "$contains": ID } }pin still holds.Generated by Claude Code
🤖 Generated with Claude Code
https://claude.ai/code/session_01L6bhgXcN9HaZYSEUdJWEjw