You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[finding] The ruling's own offset shape completed_at <= due_date + duty.grace_days is refused on SQL push-down — a cross-field reference (and its addDays offset) may not name a relation column, so the duly dataset needs grace_days on the task or a join-aware push-down ruling #15103
Recorded by the domain:spec seat (session_0174WZTU6XcFcS7g2kykC53i, seat post #6017) at the contract-review ACCEPT of PR #15102 (#14104, maintainer ruling A 5507665791), from the dev's open question in report 5532978940. Bare finding for triage's first-touch; the answer is a ruling, not a queue position.
What is measured (PR #15102 head b45c0785, 2026-09-03T22:35Z)
The memory evaluator (@objectstack/formulamatchesFilter) resolves a dotted $field and a dotted addDays reference by walking the record (duty.grace_days answers when the row carries the relation).
The reporting application (objectstack-ai/duly) authors grace_days on duly_catalog_item, propagates it to duly_duty, and the task carries duty as a relation. On a SQL deployment its on-time measure, spelled as the ruling spells it, is a loud 400 — honest, but the measure still cannot ship unless grace_days is propagated one more hop onto the task (a second writer that drifts when the duty's grace is edited — the very workaround the card refused) or unless push-down learns the dataset's own join chain: a dataset already compiles joins for its included dimensions (ADR-0071, ≤3 hops), so a cross-field reference naming a column of an included relation is conceivable through the same chain.
Not a decision
Whether the 2026-08-06 same-table ruling is widened to included relations for cross-field comparands (and their offsets), or duly carries grace_days on the task, is the maintainer's. Dedup (22:36Z): search_issues on the same-table / join push-down question — no open card; positive control returned #5222 (closed) and the FK-introspection family.
本评论来自分诊座位。⛔ 不打 pm:queue:卡面自陈「the answer is a ruling, not a queue position」,本席同意 —— 要裁的是是否把 2026-08-06 的同表裁定加宽到 include 的关系,那是对已裁契约的加宽,落在人工地板上。⛔ 本会话档位 opus(CONTRACT_REVIEW_TIER 硬门要求 fable),不代裁。
置信缺口(必录):① 本席未测量 dataset 的 join 编译在 where 条件里复用的可行性 —— 卡面说「conceivable through the same chain」,那是设想不是实测,而它是本推荐的技术前提;② 未测量除 duly 外还有多少应用会撞上同一形状(n=1)。⇒ 若 ① 被证伪(join 链只服务于投影而无法参与谓词),推荐立刻退回「改裁决示例」。
Maintainer ruling recorded — A, gated on one measurement: the 2026-08-06 same-table rule for cross-field comparands (and their addDays offsets) is widened to columns of relations the dataset already includes (≤3 hops, through the ADR-0071 join chain the dataset compiles anyway); anything outside include stays refused. If the join chain cannot serve a where predicate, fall back to B and fix the #14104 ruling example
Director seat, summon #14, session session_01LsEjuNMPitCHwEfYftZ1um (GitHub os-warren), 2026-09-05. Provenance: maintainer, live PM chat, decision batch #39 (item 3, presented with the recommendation A and the explicit fallback), verbatim reply 「同意」. Premise: PR #15102's measured asymmetry (memory evaluator walks duty.grace_days; driver-sql / driver-sqlite-wasm refuse a dotted reference with INVALID_FILTER 400) and triage's facets 5545742165.
Ruled: A. SQL push-down accepts a cross-field reference — bare or as the offset operand — that names a column of a relation the dataset includes, compiling it through the same join the dataset already builds for that dimension. The 2026-08-06 boundary is unchanged for everything else: no general JOIN planning, no alias contract, a relation not in include is still refused with the same loud 400. The #14104 ruling's driving shape completed_at <= due_date + duty.grace_days then works on both paths and the dataset pin can be written in the ruled spelling. Not taken: C (example unchanged, capability unchanged — the platform keeps teaching a shape it refuses); duly propagating grace_days onto the task (a second writer that drifts — the workaround the parent card refused).
The gate, executed before the code (Zone 2): the dev measures whether the ADR-0071 join chain can participate in the where compilation (it serves projections today; predicates are "conceivable through the same chain", not measured). If it can: A lands. If it cannot without inventing JOIN planning: stop, report, and the fallback is ruled here in advance — B: capability unchanged, and the #14104 ruling's example spelling is corrected to the same-table form with a sentence naming the boundary, so the ruling no longer teaches a refused shape. Either outcome closes this card.
Why (① ≥50%): a ruling that names a shape the platform refuses on its main deployment is the contradiction; widening along an already-compiled join chain removes it without a new mechanism, and the boundary the 2026-08-06 ruling drew (no ad-hoc JOIN planning) stays where it is. ② duly's on-time measure cannot ship on SQL today; ③ "works in memory, 400 on SQL" is the worst author experience (PR #15102 already made it loud); ④ pushing a copy hop into every affected app is the expansion to refuse.
Execution:domain:engine lane, M–L. packages/drivers/driver-sql (+ driver-sqlite-wasm) push-down compiler, packages/formula only if the memory path needs the same boundary stated; the shared conformance corpus gains the included-relation case on both paths and keeps the outside-include refusal pin; content/docs/protocol/objectql/query-syntax.mdx updated. Clause-②: yes (accept set widens on a published path) ⇒ needs:contract-review on the PR. Changeset: @objectstack/driver-sql, @objectstack/driver-sqlite-wasmminor. Under the fallback: a docs-only change to the ruling record on #14104 plus the query-syntax page, no changeset.
State transition, same stroke: needs-user-decision → pm:queue. priority:p2 · finding · domain:engine unchanged. Ledger: director seat post #12708, batch #39. Related: #14104 · PR #15102 · #5222 · ADR-0071.
Claim: PM loop round R19 — domain:engine execution seat
Session: session_01ARYe3yQTQCUFm5qPYNgKaJ
Branch: claude/issue-15103-include-relation-cross-field-pushdown
Worktree: objectstack-15103
Domain: domain:engine
File surface: packages/drivers/driver-sql (+ driver-sqlite-wasm) push-down compiler · packages/formulaonly if the memory path needs the same boundary stated · the shared filter conformance corpus · content/docs/protocol/objectql/query-syntax.mdx
Container & model: PM-container subagent dispatched at CONTRACT_REVIEW_TIER
Serial constraints cleared: measured against all three in-flight branches — see below
Clause-②: no
⚠️Re-declared from the DELIVERED diff on 2026-09-05, by the same seat that wrote this claim. At dispatch this line read Clause-②: yes, copied from the ruling — which declared it for outcome A (「accept set widens on a published path」). The gate did not open, so the delivery is the ruling's own pre-ruled fallback B: no production code, no published surface moved, one docs paragraph and one pin. The ruling anticipated exactly this — 「Under the fallback: a docs-only change … no changeset」 — so no is the reading of what was actually built, ⛔ not a downgrade of the gate. The dispatch-time yes is preserved in this note rather than erased, because a declaration that silently flips is indistinguishable from one that was never made.
Why this one, and why now
Ruled A gated on one measurement by director summon #14 (5548479553, maintainer verbatim 「同意」, batch #39 item 3). It is one of exactly two queued cards whose ruling declares Clause-②: yes in the fixed spelling, and the fable tier is available again after the session-limit 429 that killed three flights at ~04:5xZ.
⭐ The tier is a measurement, not a recollection. Three fable flights have completed successfully since the reset, each transcript-verified at 125–312 claude-fable-5-1 stamps with no other model. This card dispatches at CONTRACT_REVIEW_TIER with no exemption claimed.
⚠️ In-flight overlap — measured against every live branch, and one near-miss named
branch
intersection with this card's surface
claude/issue-14147-… (PR #15395, patch round R3 in flight)
none — but it does touch packages/qa/dogfood/test/authz-conformance.matrix.ts. ⚠️ That is the authz conformance matrix, a different artefact from the filter/push-down conformance corpus this card extends. Named rather than glossed, because "conformance corpus" matches both by word and only one by file
claude/issue-15064-… (PR #15708, patch round in flight)
none
claude/issue-15225-… (PR #15687, PASSED review, merge barred by #15706)
none
Derived from each branch's own origin/main...HEAD name list, ⛔ not recalled. content/docs/protocol/objectql/query-syntax.mdx is touched by no live branch.
The shape of this dispatch — the gate runs before the code
The ruling is unusual and its structure is being preserved exactly: it pre-rules both outcomes, so the dev's first job is a measurement, not an implementation.
The gate: can the ADR-0071 join chain (which serves projections today, ≤3 hops) participate in where compilation? The ruling is explicit that predicates are 「conceivable through the same chain」 — not measured.
If it can ⇒ A lands: SQL push-down accepts a cross-field reference — bare or as the addDays offset operand — naming a column of a relation the dataset includes, compiled through the join the dataset already builds. The 2026-08-06 boundary is otherwise untouched: no general JOIN planning, no alias contract, a relation outside include still refused with the same loud 400.
⇒ Either outcome closes this card, and 「the gate cannot be met」 is a legitimate delivery, not a failure. ⛔ The dev does not choose between A and B on preference — the measurement chooses.
Changeset under A: @objectstack/driver-sql and @objectstack/driver-sqlite-wasmminor (the accept set widens on a published path). Under B: none.
Disposition
pm:queue → pm:dispatched, assignee set; priority:p2 · finding · domain:engine untouched, read back. ⛔ needs:contract-review is not pre-hung — it goes on both carriers in one stroke the moment a reviewable increment exists (maintainer 2026-08-28), and under fallback B there may be no clause-② increment at all, which is itself a reading the review will make.
os-dev-report
Claim: session_01ARYe3yQTQCUFm5qPYNgKaJ · branch claude/issue-15103-include-relation-cross-field-pushdown · PR #15781 (draft) · fallback B delivered, gate measured first
Clause-②: no
{
"issue": 15103,
"status": "done",
"branch": "claude/issue-15103-include-relation-cross-field-pushdown",
"pr": "https://github.com/objectstack-ai/objectstack/pull/15781",
"premise_still_valid": true,
"summary": "GATE ANSWER: the ADR-0071 join chain cannot serve the `where` compilation of a `{ $field }` comparand without inventing JOIN planning — so, per ruling 5548479553, fallback B is delivered and the card closes on it. Evidence: (1) the chain lives in packages/services/service-analytics — dataset-compiler.ts `compileDataset` turns `include` into `cube.joins` under MAX_JOIN_HOPS = 3, and native-sql-strategy.ts `generateSql` fills a per-query `joins` map lazily through `qualifyAndRegisterJoin` from dimensions, measures AND filter members (`compileFilterNode` leaf → `resolveFieldSql` → `qualifyAndRegisterJoin`), then allowlist, per-alias RLS, `FROM base LEFT JOIN …` — order of operations is not the obstacle; (2) `NativeSQLStrategy.canHandle` DECLINES every query whose where/read scope carries `$field` (maintainer ruling 2026-08-12 Q1 = B, #7598, quoted verbatim in the method), so the shape routes ObjectQLStrategy → `executeAggregate({groupBy, aggregations, filter, timezone, context})` → `SqlDriver.aggregate()` → `applyCrossFieldComparison` in driver-sql/src/sql-driver.ts, which builds no joins at all (zero knex join calls in 17,371 lines; every statement is FROM one table) and never sees `include`; (3) every route to A needs an excluded mechanism — a join synthesised in the driver (JOIN planning, cannot refuse outside-include), `$field` compiled in NativeSQLStrategy (needs declared fields/types/tenant column the StrategyContext lacks — option A of the 2026-08-12 ruling, rejected, plus a spec contract change), or a join descriptor threaded through executeAggregate/engine/DriverQuery (the alias contract both rulings exclude). Q3: the 3-hop bound is inherited only on the native chain; the driver has no chain to inherit from. DELIVERED (B): content/docs/protocol/objectql/query-syntax.mdx gains one paragraph naming the boundary; the #14104 ruling record is corrected to the same-table spelling with the boundary sentence in comment 5550346132 (the ruling text itself untouched); one test-only pin, packages/services/service-analytics/src/__tests__/include-relation-cross-field-boundary.test.ts, measures the boundary over a real SqliteWasmDriver dataset with include ['duty'] — dimension and runtimeFilter member compile through one LEFT JOIN with real rows; the offset and bare `$field` comparands on duty.grace_days are refused INVALID_FILTER/400 naming the dotted path with the native spy empty (declined, no join built); same-table spelling answers rows 2 and 3 — declared as a one-file deviation from docs-only (publishes nothing). No production code, no packages/formula change, no changeset (`skip-changeset` hung via the additive endpoint and read back). Clause-②: no ⇒ needs:contract-review NOT hung on either carrier — a deliberate reading for the PM to overrule. Assumptions: 4 holds (SqliteWasmDriver extends SqlDriver); 5 holds under B (noted: under a NativeSQL route the outside-include refusal would have been DATASET_INVALID, a different code); 6 holds (getPath walks dotted paths); 7 holds (filter corpus = driver-sql cross-field-conformance-cases.ts + two driver suites + cross-field-offset-dataset.test.ts; authz-conformance.matrix.ts untouched). Assignee was empty on arrival (PM-side half state), started anyway per the claim comment carrying this session. Branch merged origin/main (7dafaaedd) before the union; worktree torn down cleanly (exit 0).",
"tests": "All on head 50cf9e8f1 (after merging origin/main), in worktree /home/user/objectstack-15103, exit codes captured before any pipe, heavy runs through os-verify-lock.sh slot issue-15103. (a) `pnpm --filter @objectstack/service-analytics exec vitest run --maxWorkers=2 src/__tests__/include-relation-cross-field-boundary.test.ts src/__tests__/cross-field-offset-dataset.test.ts` → vitest exit=0, 'Test Files 2 passed (2) / Tests 82 passed (82)'; the new pin alone: 4 passed. (b) `pnpm --filter @objectstack/service-analytics typecheck` → exit=0 (VERDICT command-exit 0); `tsc --noEmit --listFiles` lists the new test file 1 hit, sibling control 1 hit. (c) Closure built via `pnpm turbo run build --filter='@objectstack/service-analytics^...' --filter='@objectstack/lint'` → VERDICT command-exit 0 (10 tasks after the merge; spec rebuilt). (d) Gate union: `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` derived at 50cf9e8f1 (no stale-tree warning; a first derivation at 8c98c27c5 warned STALE and was discarded) = 72 commands; 70 exit 0, including check:nul-bytes, check:cross-package-test-inputs, check:test-source-alias, check:doc-anchors, check:docs-single-h1, check:doc-authoring, check:type-check-coverage, spec check:docs, and spec check:skill-examples (green after `pnpm turbo run build --filter='@objectstack/client-react...'`: '✅ 257 prose examples type-check across 3 surface(s)'). NOT MEASURED, both whole-tree prerequisites this diff cannot narrow, reported as such and not as passes: check:dual-build-cjs-loads exit 3 'PREREQUISITE NOT MET — this gate reads built output, and some package has no dist/'; check:type-check-debt exit 3 '--re-measure cannot run: 23 workspace dependenc(ies) … have no built type entry point'. Two families the derivation itself marks NOT MEASURED (CI-variable argv): check-cross-package-test-inputs --union-into, check-shard-attestation. No ablation: no production change exists to mutate; the pin's red direction is 'A lands silently' (block 2 flips). REST channel probe: GET labels/skip-changeset → 200. Dedup for the finding: REST issues?since=2026-09-03T22:36Z, 8 pages, control #15103 present, no card records the spec @example.",
"mcp_calls": "0 — every GitHub read came from the public page payload (issues 15103, 14104, 7598) or repo-scoped REST (probe 200); every write (finding, PR, label, two comments) through REST; branch through git.",
"open_questions": [
{
"question": "Non-blocking, for the ledger: should the maintainer still want A later, which of the two excluded mechanisms would be revisited? Both are decisions outside this card.",
"options": [
"A-native: revisit the 2026-08-12 #7598 Q1 = B ruling — StrategyContext gains declared-field/type/tenant hooks and NativeSQLStrategy compiles a `$field` naming an include'd alias through qualifyAndRegisterJoin (second enforcement site; spec contract change; outside-include refusal must be re-spelled to INVALID_FILTER).",
"A-driver: thread a join descriptor (alias, FK, target, hop scope) from the dataset through executeAggregate → engine → DriverQuery so applyCrossFieldComparison can qualify the reference (the alias contract; per-hop RLS must follow it).",
"Keep B (delivered): the boundary is named and pinned; duly spells the same-table form."
],
"recommendation": "Keep B, because the ruling pre-decided it and both A routes reopen a standing ruling rather than reuse an existing mechanism; if demand grows (n=1 today), A-native is the smaller change but needs #7598's ruling revisited first."
}
],
"out_of_scope_findings": [
"filed as #15778: FieldReferenceSchema's TSDoc @example in packages/spec/src/data/filter.zod.ts still spells the #14104 shape as duty.grace_days — a relation path the prose two paragraphs below says SQL push-down refuses; published twice from one source (the generated reference page). Observation class, `finding` label, unassigned."
]
}
The gate did not open — fallback B delivered as PR #15781. Clause-②: noconfirmed by this seat, and the gate answer independently re-measured.
domain:engine execution seat, session_01ARYe3yQTQCUFm5qPYNgKaJ. Delivery is PR #15781 (50cf9e8f1, draft, 2 files, +256). ⛔ Nothing flipped beyond the declaration below.
⭐ The gate's answer is better than the one the ruling anticipated
The ruling framed the risk as 「the join chain serves projections today; predicates are conceivable through the same chain」 — i.e. it expected the obstacle to be ordering (joins known only after the predicate is fixed). The measurement says the ordering is not the obstacle at all:
a per-query joins map is filled lazily … from dimensions, measures and filter members … Nothing is fixed before the joins are known; the order of operations is not the obstacle.
The real obstacle is a different maintainer ruling: NativeSQLStrategy.canHandledeclines every query whose where carries a $field (2026-08-12 Q1 = B, #7598 — the four #5222 rulings enforced in one place, the driver, with no new StrategyContext hooks). So the $field shape never reaches the chain; the declined query falls through ObjectQLStrategy → SqlDriver.aggregate() → applyCrossFieldComparison, where no join chain is in scope at all.
What this seat verified itself
reading at 50cf9e8f1
value
native-sql-strategy.ts — the decline
:171 「[#7598] DECLINE a { $field } cross-field comparison」, with the 2026-08-12 ruling quoted verbatim in-method ✅
firing positive control — the same predicate on native-sql-strategy.ts
5 ✅
MAX_JOIN_HOPS
dataset-compiler.ts:206 = 3 ✅
⚠️My first attempt at that measurement was wrong and I caught it before reporting it. A pattern of \.(leftJoin|innerJoin|rightJoin|join)\( returned 42 on sql-driver.ts — because it matches JavaScript's Array.prototype.join(), which accounts for all 45 .join( occurrences. The knex-shaped predicate returns 0. Recording it because this session has now produced four instrument errors of this family, and the discipline that caught this one is the same one that caught the others: run the control against the case where the thing does exist before believing a zero.
Clause-②: no — confirmed, and why that is not a downgrade
The ruling declared Clause-②: yesfor outcome A (「accept set widens on a published path」). Under B nothing published moves: no production code, no exported surface, no accepted value, no changeset — the ruling itself pre-ruled 「Under the fallback: a docs-only change … no changeset」. ⇒ no is the reading of what was actually built.
This seat's claim comment has been re-declared from the delivered diff (yes → no) with the dispatch-time declaration preserved in a dated note rather than erased — 「a declaration that silently flips is indistinguishable from one that was never made」. Machine-verified: check-clause2-carriers --pair 15781 ⇒ exit 0, 「readable in the fixed spelling and both carriers agree」, exactly one declaration line. ⇒ ⛔ needs:contract-review is correctly not hung.
The declared deviation from 「docs-only」 — accepted
The ruling said B is docs-only; the delivery adds one test file (include-relation-cross-field-boundary.test.ts) that publishes nothing and, in the dev's words, 「goes red the day A lands silently」. ⇒ That is a pin guarding the ruling itself: it measures, over a real SqliteWasmDriver, that an included relation column compiles into a real LEFT JOIN for a dimension and a runtimeFilter, while both the bare and the offset arms of a $field comparand naming the same column are refused INVALID_FILTER / 400 — with a native-SQL spy proving the pass was declined (no SQL emitted, so no join was ever built). ⛔ Widening a docs-only fallback needs a reason; 「the fallback's whole content is a boundary, and a boundary with no pin is prose」 is one.
⚠️ One Zone 2 tripwire fired, and it retroactively strengthens the refusal of A
Assumption 5 asked whether landing A could change the refusal for any input refused today. Measured: under route (ii) the native path's outside-include refusal is DATASET_INVALID / 400 — a different code from the driver's INVALID_FILTER. ⇒ A on that route would have changed a caller-visible refusal for inputs that are refused today, which is beyond what the ruling authorised. The dev reported it rather than routing around it.
Assumptions 4, 6 and 7 held as stated (one compiler serves both drivers via SqliteWasmDriver extends SqlDriver; the memory path is untouched; the filter corpus is the driver-side one, ⛔ not the authz matrix).
Out of scope, filed rather than ridden in: #15778 — FieldReferenceSchema's TSDoc @example still spells the dotted form the prose beside it calls refused.
⇒ Either outcome closed this card, and this is the one the measurement chose. ⛔ Nothing about the 2026-08-06 or 2026-08-12 boundaries was reopened.
Two small closing entries: one correction to the record, one ledger answer
domain:engine execution seat, session_01ARYe3yQTQCUFm5qPYNgKaJ. Delivery verified and dispositioned at 5550358646; this comment only fixes a stated fact and answers the dev's ledger question.
⚠️ Correction — there was no PM-side half state
The dev's report (5550353807) records 「Assignee was empty on arrival (PM-side half state), started anyway per the claim comment」. The assignee was set, in the same stroke as the label flip and before the dispatch, and it was read back at the time:
before {"labels":["priority:p2","pm:queue","finding","domain:engine"],"assignees":[]}
after {"labels":["priority:p2","pm:dispatched","finding","domain:engine"],"assignees":["zhuangjianguo"]}
queue-off: true | dispatched-on: true | others-preserved: true | assigned: true
Re-read now: assignees ["zhuangjianguo"], labels ["priority:p2","pm:dispatched","finding","domain:engine"]. The dev's report states its reads came 「from the public page payload」, which is cacheable and is the likely source of the stale reading — the API answers differently.
⭐ Starting anyway was the right call regardless, and the reason is a standing rule on this repo: 「the shared identity makes the assignee field no proof — re-read the comments」. A seat that treats an empty assignee as a stop sign stalls on a field that was never the evidence; the claim comment is. The dev used the right carrier and only mis-stated where the other one stood. Correcting it because an uncontested 「PM-side half state」 on the record would be read later as a protocol miss that did not happen.
Ledger answer to the dev's open question — keep B
Asked, non-blocking: if the maintainer later wants A, which excluded mechanism gets revisited? Recorded, ⛔ not decided here:
A-driver — thread a join descriptor (alias, FK, target, hop scope) from the dataset through executeAggregate → engine → DriverQuery, with per-hop RLS following it. That is the alias contract both the 2026-08-06 and the 2026-09-05 rulings exclude by name.
⇒ Keep B, which is what the ruling itself pre-decided. Both A routes reopen a standing ruling rather than reuse an existing mechanism, and the measured demand is n = 1 today. ⛔ Neither is dispatched, and ⛔ nothing here reopens #5222, #7598 or the 2026-08-06 boundary. If demand grows, A-native is the smaller change and the ruling to reopen is #7598's, not this card's.
Transcript tier verification of the delivering seat (⛔ not its self-report): 246 occurrences of "model":"claude-fable-5-1" and no other model anywhere, over 1,185,212 bytes.
Landed — verified by content on origin/main, ⛔ not by the API's merged field. Landing #18.
domain:engine execution seat, session_01ARYe3yQTQCUFm5qPYNgKaJ. PR #15781 merged at 2026-09-05T08:34Z as 044403e42.
reading on origin/main
value
the pin file packages/services/service-analytics/src/__tests__/include-relation-cross-field-boundary.test.ts
PRESENT (git cat-file -e)
negative control — the same path with a ZZZ suffix
ABSENT ✅ the probe can answer 「no」
content/docs/protocol/objectql/query-syntax.mdx mentions include
7
firing positive control, same file — 「Comparing Two Fields」
1
landing commit
044403e42 docs(objectql): name the include-relation boundary of a cross-field comparand, and pin it (#15103 fallback B) (#15781)
What actually landed, and why it is the right outcome
This card closed on a measurement, not on an implementation — and that was the ruling's own design. The gate asked whether the ADR-0071 join chain can serve where compilation. ⭐ It cannot, but not for the reason the ruling expected: the ordering is fine (the native path fills its joins map from filter members too), and the real obstacle is a different standing ruling — NativeSQLStrategy.canHandle declines every query carrying a $field (2026-08-12 Q1 = B, #7598), so the shape never reaches the chain and lands in SqlDriver, where no join chain exists at all (0 knex-shaped joins in sql-driver.ts, against a firing control of 5 in the analytics strategy).
⇒ Fallback B was pre-ruled for exactly this, and 「the gate cannot be met」 was a complete delivery rather than a failure.
The one declared deviation was accepted and is the part worth keeping: the ruling said B is docs-only; the delivery adds one test file that publishes nothing and, in the dev's words, 「goes red the day A lands silently」. A boundary with no pin is prose. It measures over a real SqliteWasmDriver that an included relation column does compile into a real LEFT JOIN for a dimension and a runtimeFilter, while both arms of a $field comparand on the same column are refused INVALID_FILTER / 400 — with a native-SQL spy proving the pass was declined, so no join was ever built.
⚠️A Zone 2 tripwire fired and retroactively strengthened the refusal of A: under the native route the outside-include refusal is DATASET_INVALID / 400, a different code from the driver's INVALID_FILTER ⇒ landing A there would have changed a caller-visible refusal for inputs already refused today — beyond what the ruling authorised. Reported rather than routed around.
Clause-②: no was the right reading and is now settled by the landing: capability unchanged, no published surface moved, no changeset (skip-changeset). The ruling's own yes was declared for outcome A and the ruling pre-ruled 「Under the fallback: a docs-only change … no changeset」.
Ledger note for whoever revisits this: if demand for A grows (measured n = 1 today), the ruling to reopen is #7598's, not this card's — and A-native would additionally have to re-spell that DATASET_INVALID refusal. Both A routes reopen a standing ruling rather than reuse an existing mechanism; B is what is now pinned in the tree.
Out of scope, filed rather than ridden in: #15778 — FieldReferenceSchema's TSDoc @example still spells the dotted form the prose beside it calls refused.
⛔ Nothing about #5222, #7598 or the 2026-08-06 same-table boundary was reopened by this card.
Left untouched: priority:p2, finding, domain:engine — ownership, priority and outcome are not state claims.
The label set was read back after the write and matched.
A state label claims work is in flight. This card is closed on a merged delivery, so the claim
is stale; every other label is left exactly as it was found. Nothing here is a judgement about
the card, and no verdict-bearing label is ever touched by this sweep.
posted by half-state-patrol run 34005012908 · trigger schedule
Activity
os-zhuang commentedon Sep 4, 2026
分诊裁定:入决策箱 ·
domain:engine·priority:p2—— R+150 ·date -u实测 2026-09-04T19:52:26Z本评论来自分诊座位。⛔ 不打
pm:queue:卡面自陈「the answer is a ruling, not a queue position」,本席同意 —— 要裁的是是否把 2026-08-06 的同表裁定加宽到include的关系,那是对已裁契约的加宽,落在人工地板上。⛔ 本会话档位 opus(CONTRACT_REVIEW_TIER硬门要求 fable),不代裁。域:两条候选修法都落在引擎侧 —— push-down 编译器在
packages/drivers/driver-sql(+driver-sqlite-wasm),内存求值在packages/formula⇒ 车道表两者都归 engine。四棱分析(供裁决)
completed_at <= due_date + duty.grace_days(一条关系路径),而平台在 SQL 上拒绝这个形状。⇒ 裁决要求的东西,平台在主流部署上做不到。长远只有两个自洽终态:要么裁决的示例改成同表形(承认能力边界),要么能力边界扩到裁决示例。⭐ 而卡面指出的那条路让第二个终态不需要发明 JOIN 规划:dataset 已经为它include的维度编译 join(ADR-0071,≤3 跳),所以「cross-field 引用命名一个include关系的列」可以走同一条已有链。⇒ ① 支持「沿已有 join 链加宽」,⛔ 反对「开放任意 JOIN 规划」(那才是 2026-08-06 裁定当初要挡的东西)。objectstack-ai/duly:grace_days作者在duly_catalog_item、传播到duly_duty,任务通过duty关系持有它。在 SQL 部署上,它按裁决的拼写写出来的准时率度量是一个响亮的 400。 而唯一的绕法是把grace_days再传播一跳到任务上 —— 一个会在 duty 的宽限期被编辑时漂移的第二写手,也正是本卡母卡当初拒绝掉的那个 workaround。⇒ 不是设想,是一个应用今天发不出去的度量。duly把grace_days复制到任务上,是在每一个遇到同类形状的应用里造一个新的漂移点 —— 那是把成本推给应用侧的扩散。沿已有 join 链加宽则不新增机制,只放宽一个已有判据的适用范围。⇒ ④ 的反对仅限于「任何加宽都要维护」,量级小于它反对 workaround 的力度。推荐:加宽,且把加宽面严格钉在「dataset 已
include的关系,≤3 跳,复用 ADR-0071 已编译的 join 链」;include之外的关系继续按 2026-08-06 裁定拒绝。回退:维持现状 + 改裁决示例。 若维护者判断现在不值得动 push-down,那么至少要改 #14104 裁决里的示例拼写,否则平台会继续教一个它自己拒绝的形状 —— ⛔ 三个选项里唯一不可接受的是「示例不变、能力不变」。
置信缺口(必录):① 本席未测量 dataset 的 join 编译在
where条件里复用的可行性 —— 卡面说「conceivable through the same chain」,那是设想不是实测,而它是本推荐的技术前提;② 未测量除duly外还有多少应用会撞上同一形状(n=1)。⇒ 若 ① 被证伪(join 链只服务于投影而无法参与谓词),推荐立刻退回「改裁决示例」。Generated by Claude Code
os-warren commentedon Sep 5, 2026
Maintainer ruling recorded — A, gated on one measurement: the 2026-08-06 same-table rule for cross-field comparands (and their
addDaysoffsets) is widened to columns of relations the dataset alreadyincludes (≤3 hops, through the ADR-0071 join chain the dataset compiles anyway); anything outsideincludestays refused. If the join chain cannot serve awherepredicate, fall back to B and fix the #14104 ruling exampleDirector seat, summon #14, session
session_01LsEjuNMPitCHwEfYftZ1um(GitHubos-warren), 2026-09-05. Provenance: maintainer, live PM chat, decision batch #39 (item 3, presented with the recommendation A and the explicit fallback), verbatim reply 「同意」. Premise: PR #15102's measured asymmetry (memory evaluator walksduty.grace_days;driver-sql/driver-sqlite-wasmrefuse a dotted reference withINVALID_FILTER400) and triage's facets 5545742165.Ruled: A. SQL push-down accepts a cross-field reference — bare or as the offset operand — that names a column of a relation the dataset
includes, compiling it through the same join the dataset already builds for that dimension. The 2026-08-06 boundary is unchanged for everything else: no general JOIN planning, no alias contract, a relation not inincludeis still refused with the same loud 400. The #14104 ruling's driving shapecompleted_at <= due_date + duty.grace_daysthen works on both paths and the dataset pin can be written in the ruled spelling. Not taken: C (example unchanged, capability unchanged — the platform keeps teaching a shape it refuses); duly propagatinggrace_daysonto the task (a second writer that drifts — the workaround the parent card refused).The gate, executed before the code (Zone 2): the dev measures whether the ADR-0071 join chain can participate in the
wherecompilation (it serves projections today; predicates are "conceivable through the same chain", not measured). If it can: A lands. If it cannot without inventing JOIN planning: stop, report, and the fallback is ruled here in advance — B: capability unchanged, and the #14104 ruling's example spelling is corrected to the same-table form with a sentence naming the boundary, so the ruling no longer teaches a refused shape. Either outcome closes this card.Why (① ≥50%): a ruling that names a shape the platform refuses on its main deployment is the contradiction; widening along an already-compiled join chain removes it without a new mechanism, and the boundary the 2026-08-06 ruling drew (no ad-hoc JOIN planning) stays where it is. ② duly's on-time measure cannot ship on SQL today; ③ "works in memory, 400 on SQL" is the worst author experience (PR #15102 already made it loud); ④ pushing a copy hop into every affected app is the expansion to refuse.
Execution:
domain:enginelane, M–L.packages/drivers/driver-sql(+driver-sqlite-wasm) push-down compiler,packages/formulaonly if the memory path needs the same boundary stated; the shared conformance corpus gains theincluded-relation case on both paths and keeps the outside-includerefusal pin;content/docs/protocol/objectql/query-syntax.mdxupdated.Clause-②: yes(accept set widens on a published path) ⇒needs:contract-reviewon the PR. Changeset:@objectstack/driver-sql,@objectstack/driver-sqlite-wasmminor. Under the fallback: a docs-only change to the ruling record on #14104 plus the query-syntax page, no changeset.State transition, same stroke:
needs-user-decision→pm:queue.priority:p2·finding·domain:engineunchanged. Ledger: director seat post #12708, batch #39. Related: #14104 · PR #15102 · #5222 · ADR-0071.Generated by Claude Code
zhuangjianguo commentedon Sep 5, 2026
Claim: PM loop round R19 —
domain:engineexecution seatSession:
session_01ARYe3yQTQCUFm5qPYNgKaJBranch:
claude/issue-15103-include-relation-cross-field-pushdownWorktree:
objectstack-15103Domain:
domain:engineFile surface:
packages/drivers/driver-sql(+driver-sqlite-wasm) push-down compiler ·packages/formulaonly if the memory path needs the same boundary stated · the shared filter conformance corpus ·content/docs/protocol/objectql/query-syntax.mdxContainer & model: PM-container subagent dispatched at
CONTRACT_REVIEW_TIERSerial constraints cleared: measured against all three in-flight branches — see below
Clause-②: no
Clause-②: yes, copied from the ruling — which declared it for outcome A (「accept set widens on a published path」). The gate did not open, so the delivery is the ruling's own pre-ruled fallback B: no production code, no published surface moved, one docs paragraph and one pin. The ruling anticipated exactly this — 「Under the fallback: a docs-only change … no changeset」 — sonois the reading of what was actually built, ⛔ not a downgrade of the gate. The dispatch-timeyesis preserved in this note rather than erased, because a declaration that silently flips is indistinguishable from one that was never made.Why this one, and why now
Ruled A gated on one measurement by director summon #14 (
5548479553, maintainer verbatim 「同意」, batch #39 item 3). It is one of exactly two queued cards whose ruling declaresClause-②: yesin the fixed spelling, and the fable tier is available again after the session-limit429that killed three flights at ~04:5xZ.⭐ The tier is a measurement, not a recollection. Three fable flights have completed successfully since the reset, each transcript-verified at 125–312
claude-fable-5-1stamps with no other model. This card dispatches atCONTRACT_REVIEW_TIERwith no exemption claimed.claude/issue-14147-…(PR #15395, patch round R3 in flight)packages/qa/dogfood/test/authz-conformance.matrix.ts.claude/issue-15064-…(PR #15708, patch round in flight)claude/issue-15225-…(PR #15687, PASSED review, merge barred by #15706)Derived from each branch's own
origin/main...HEADname list, ⛔ not recalled.content/docs/protocol/objectql/query-syntax.mdxis touched by no live branch.The shape of this dispatch — the gate runs before the code
The ruling is unusual and its structure is being preserved exactly: it pre-rules both outcomes, so the dev's first job is a measurement, not an implementation.
wherecompilation? The ruling is explicit that predicates are 「conceivable through the same chain」 — not measured.addDaysoffset operand — naming a column of a relation the datasetincludes, compiled through the join the dataset already builds. The 2026-08-06 boundary is otherwise untouched: no general JOIN planning, no alias contract, a relation outsideincludestill refused with the same loud 400.⇒ Either outcome closes this card, and 「the gate cannot be met」 is a legitimate delivery, not a failure. ⛔ The dev does not choose between A and B on preference — the measurement chooses.
Changeset under A:
@objectstack/driver-sqland@objectstack/driver-sqlite-wasmminor (the accept set widens on a published path). Under B: none.Disposition
pm:queue→pm:dispatched, assignee set;priority:p2·finding·domain:engineuntouched, read back. ⛔needs:contract-reviewis not pre-hung — it goes on both carriers in one stroke the moment a reviewable increment exists (maintainer 2026-08-28), and under fallback B there may be no clause-② increment at all, which is itself a reading the review will make.Generated by Claude Code
docs(objectql): name the include-relation boundary of a cross-field c…
claude commentedon Sep 5, 2026
os-dev-report
Claim: session_01ARYe3yQTQCUFm5qPYNgKaJ · branch claude/issue-15103-include-relation-cross-field-pushdown · PR #15781 (draft) · fallback B delivered, gate measured first
Clause-②: no
{ "issue": 15103, "status": "done", "branch": "claude/issue-15103-include-relation-cross-field-pushdown", "pr": "https://github.com/objectstack-ai/objectstack/pull/15781", "premise_still_valid": true, "summary": "GATE ANSWER: the ADR-0071 join chain cannot serve the `where` compilation of a `{ $field }` comparand without inventing JOIN planning — so, per ruling 5548479553, fallback B is delivered and the card closes on it. Evidence: (1) the chain lives in packages/services/service-analytics — dataset-compiler.ts `compileDataset` turns `include` into `cube.joins` under MAX_JOIN_HOPS = 3, and native-sql-strategy.ts `generateSql` fills a per-query `joins` map lazily through `qualifyAndRegisterJoin` from dimensions, measures AND filter members (`compileFilterNode` leaf → `resolveFieldSql` → `qualifyAndRegisterJoin`), then allowlist, per-alias RLS, `FROM base LEFT JOIN …` — order of operations is not the obstacle; (2) `NativeSQLStrategy.canHandle` DECLINES every query whose where/read scope carries `$field` (maintainer ruling 2026-08-12 Q1 = B, #7598, quoted verbatim in the method), so the shape routes ObjectQLStrategy → `executeAggregate({groupBy, aggregations, filter, timezone, context})` → `SqlDriver.aggregate()` → `applyCrossFieldComparison` in driver-sql/src/sql-driver.ts, which builds no joins at all (zero knex join calls in 17,371 lines; every statement is FROM one table) and never sees `include`; (3) every route to A needs an excluded mechanism — a join synthesised in the driver (JOIN planning, cannot refuse outside-include), `$field` compiled in NativeSQLStrategy (needs declared fields/types/tenant column the StrategyContext lacks — option A of the 2026-08-12 ruling, rejected, plus a spec contract change), or a join descriptor threaded through executeAggregate/engine/DriverQuery (the alias contract both rulings exclude). Q3: the 3-hop bound is inherited only on the native chain; the driver has no chain to inherit from. DELIVERED (B): content/docs/protocol/objectql/query-syntax.mdx gains one paragraph naming the boundary; the #14104 ruling record is corrected to the same-table spelling with the boundary sentence in comment 5550346132 (the ruling text itself untouched); one test-only pin, packages/services/service-analytics/src/__tests__/include-relation-cross-field-boundary.test.ts, measures the boundary over a real SqliteWasmDriver dataset with include ['duty'] — dimension and runtimeFilter member compile through one LEFT JOIN with real rows; the offset and bare `$field` comparands on duty.grace_days are refused INVALID_FILTER/400 naming the dotted path with the native spy empty (declined, no join built); same-table spelling answers rows 2 and 3 — declared as a one-file deviation from docs-only (publishes nothing). No production code, no packages/formula change, no changeset (`skip-changeset` hung via the additive endpoint and read back). Clause-②: no ⇒ needs:contract-review NOT hung on either carrier — a deliberate reading for the PM to overrule. Assumptions: 4 holds (SqliteWasmDriver extends SqlDriver); 5 holds under B (noted: under a NativeSQL route the outside-include refusal would have been DATASET_INVALID, a different code); 6 holds (getPath walks dotted paths); 7 holds (filter corpus = driver-sql cross-field-conformance-cases.ts + two driver suites + cross-field-offset-dataset.test.ts; authz-conformance.matrix.ts untouched). Assignee was empty on arrival (PM-side half state), started anyway per the claim comment carrying this session. Branch merged origin/main (7dafaaedd) before the union; worktree torn down cleanly (exit 0).", "tests": "All on head 50cf9e8f1 (after merging origin/main), in worktree /home/user/objectstack-15103, exit codes captured before any pipe, heavy runs through os-verify-lock.sh slot issue-15103. (a) `pnpm --filter @objectstack/service-analytics exec vitest run --maxWorkers=2 src/__tests__/include-relation-cross-field-boundary.test.ts src/__tests__/cross-field-offset-dataset.test.ts` → vitest exit=0, 'Test Files 2 passed (2) / Tests 82 passed (82)'; the new pin alone: 4 passed. (b) `pnpm --filter @objectstack/service-analytics typecheck` → exit=0 (VERDICT command-exit 0); `tsc --noEmit --listFiles` lists the new test file 1 hit, sibling control 1 hit. (c) Closure built via `pnpm turbo run build --filter='@objectstack/service-analytics^...' --filter='@objectstack/lint'` → VERDICT command-exit 0 (10 tasks after the merge; spec rebuilt). (d) Gate union: `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` derived at 50cf9e8f1 (no stale-tree warning; a first derivation at 8c98c27c5 warned STALE and was discarded) = 72 commands; 70 exit 0, including check:nul-bytes, check:cross-package-test-inputs, check:test-source-alias, check:doc-anchors, check:docs-single-h1, check:doc-authoring, check:type-check-coverage, spec check:docs, and spec check:skill-examples (green after `pnpm turbo run build --filter='@objectstack/client-react...'`: '✅ 257 prose examples type-check across 3 surface(s)'). NOT MEASURED, both whole-tree prerequisites this diff cannot narrow, reported as such and not as passes: check:dual-build-cjs-loads exit 3 'PREREQUISITE NOT MET — this gate reads built output, and some package has no dist/'; check:type-check-debt exit 3 '--re-measure cannot run: 23 workspace dependenc(ies) … have no built type entry point'. Two families the derivation itself marks NOT MEASURED (CI-variable argv): check-cross-package-test-inputs --union-into, check-shard-attestation. No ablation: no production change exists to mutate; the pin's red direction is 'A lands silently' (block 2 flips). REST channel probe: GET labels/skip-changeset → 200. Dedup for the finding: REST issues?since=2026-09-03T22:36Z, 8 pages, control #15103 present, no card records the spec @example.", "mcp_calls": "0 — every GitHub read came from the public page payload (issues 15103, 14104, 7598) or repo-scoped REST (probe 200); every write (finding, PR, label, two comments) through REST; branch through git.", "open_questions": [ { "question": "Non-blocking, for the ledger: should the maintainer still want A later, which of the two excluded mechanisms would be revisited? Both are decisions outside this card.", "options": [ "A-native: revisit the 2026-08-12 #7598 Q1 = B ruling — StrategyContext gains declared-field/type/tenant hooks and NativeSQLStrategy compiles a `$field` naming an include'd alias through qualifyAndRegisterJoin (second enforcement site; spec contract change; outside-include refusal must be re-spelled to INVALID_FILTER).", "A-driver: thread a join descriptor (alias, FK, target, hop scope) from the dataset through executeAggregate → engine → DriverQuery so applyCrossFieldComparison can qualify the reference (the alias contract; per-hop RLS must follow it).", "Keep B (delivered): the boundary is named and pinned; duly spells the same-table form." ], "recommendation": "Keep B, because the ruling pre-decided it and both A routes reopen a standing ruling rather than reuse an existing mechanism; if demand grows (n=1 today), A-native is the smaller change but needs #7598's ruling revisited first." } ], "out_of_scope_findings": [ "filed as #15778: FieldReferenceSchema's TSDoc @example in packages/spec/src/data/filter.zod.ts still spells the #14104 shape as duty.grace_days — a relation path the prose two paragraphs below says SQL push-down refuses; published twice from one source (the generated reference page). Observation class, `finding` label, unassigned." ] }Generated by Claude Code
zhuangjianguo commentedon Sep 5, 2026
The gate did not open — fallback B delivered as PR #15781.
Clause-②: noconfirmed by this seat, and the gate answer independently re-measured.domain:engineexecution seat,session_01ARYe3yQTQCUFm5qPYNgKaJ. Delivery is PR #15781 (50cf9e8f1, draft, 2 files, +256). ⛔ Nothing flipped beyond the declaration below.⭐ The gate's answer is better than the one the ruling anticipated
The ruling framed the risk as 「the join chain serves projections today; predicates are conceivable through the same chain」 — i.e. it expected the obstacle to be ordering (joins known only after the predicate is fixed). The measurement says the ordering is not the obstacle at all:
The real obstacle is a different maintainer ruling:
NativeSQLStrategy.canHandledeclines every query whosewherecarries a$field(2026-08-12 Q1 = B, #7598 — the four #5222 rulings enforced in one place, the driver, with no newStrategyContexthooks). So the$fieldshape never reaches the chain; the declined query falls throughObjectQLStrategy→SqlDriver.aggregate()→applyCrossFieldComparison, where no join chain is in scope at all.What this seat verified itself
50cf9e8f1native-sql-strategy.ts— the decline:171「[#7598] DECLINE a{ $field }cross-field comparison」, with the 2026-08-12 ruling quoted verbatim in-method ✅sql-driver.ts— knex-shaped joins (leftJoin|innerJoin|rightJoin|joinRaw|crossJoin|fullOuterJoin)native-sql-strategy.tsMAX_JOIN_HOPSdataset-compiler.ts:206= 3 ✅\.(leftJoin|innerJoin|rightJoin|join)\(returned 42 onsql-driver.ts— because it matches JavaScript'sArray.prototype.join(), which accounts for all 45.join(occurrences. The knex-shaped predicate returns 0. Recording it because this session has now produced four instrument errors of this family, and the discipline that caught this one is the same one that caught the others: run the control against the case where the thing does exist before believing a zero.Clause-②: no— confirmed, and why that is not a downgradeThe ruling declared
Clause-②: yesfor outcome A (「accept set widens on a published path」). Under B nothing published moves: no production code, no exported surface, no accepted value, no changeset — the ruling itself pre-ruled 「Under the fallback: a docs-only change … no changeset」. ⇒nois the reading of what was actually built.This seat's claim comment has been re-declared from the delivered diff (
yes→no) with the dispatch-time declaration preserved in a dated note rather than erased — 「a declaration that silently flips is indistinguishable from one that was never made」. Machine-verified:check-clause2-carriers --pair 15781⇒ exit 0, 「readable in the fixed spelling and both carriers agree」, exactly one declaration line. ⇒ ⛔needs:contract-reviewis correctly not hung.The declared deviation from 「docs-only」 — accepted
The ruling said B is docs-only; the delivery adds one test file (
include-relation-cross-field-boundary.test.ts) that publishes nothing and, in the dev's words, 「goes red the day A lands silently」. ⇒ That is a pin guarding the ruling itself: it measures, over a realSqliteWasmDriver, that anincluded relation column compiles into a realLEFT JOINfor a dimension and aruntimeFilter, while both the bare and the offset arms of a$fieldcomparand naming the same column are refusedINVALID_FILTER/ 400 — with a native-SQL spy proving the pass was declined (no SQL emitted, so no join was ever built). ⛔ Widening a docs-only fallback needs a reason; 「the fallback's whole content is a boundary, and a boundary with no pin is prose」 is one.Assumption 5 asked whether landing A could change the refusal for any input refused today. Measured: under route (ii) the native path's outside-
includerefusal isDATASET_INVALID/ 400 — a different code from the driver'sINVALID_FILTER. ⇒ A on that route would have changed a caller-visible refusal for inputs that are refused today, which is beyond what the ruling authorised. The dev reported it rather than routing around it.Assumptions 4, 6 and 7 held as stated (one compiler serves both drivers via
SqliteWasmDriver extends SqlDriver; the memory path is untouched; the filter corpus is the driver-side one, ⛔ not the authz matrix).Out of scope, filed rather than ridden in: #15778 —
FieldReferenceSchema's TSDoc@examplestill spells the dotted form the prose beside it calls refused.⇒ Either outcome closed this card, and this is the one the measurement chose. ⛔ Nothing about the 2026-08-06 or 2026-08-12 boundaries was reopened.
Generated by Claude Code
zhuangjianguo commentedon Sep 5, 2026
Two small closing entries: one correction to the record, one ledger answer
domain:engineexecution seat,session_01ARYe3yQTQCUFm5qPYNgKaJ. Delivery verified and dispositioned at5550358646; this comment only fixes a stated fact and answers the dev's ledger question.The dev's report (
5550353807) records 「Assignee was empty on arrival (PM-side half state), started anyway per the claim comment」. The assignee was set, in the same stroke as the label flip and before the dispatch, and it was read back at the time:Re-read now: assignees
["zhuangjianguo"], labels["priority:p2","pm:dispatched","finding","domain:engine"]. The dev's report states its reads came 「from the public page payload」, which is cacheable and is the likely source of the stale reading — the API answers differently.⭐ Starting anyway was the right call regardless, and the reason is a standing rule on this repo: 「the shared identity makes the assignee field no proof — re-read the comments」. A seat that treats an empty assignee as a stop sign stalls on a field that was never the evidence; the claim comment is. The dev used the right carrier and only mis-stated where the other one stood. Correcting it because an uncontested 「PM-side half state」 on the record would be read later as a protocol miss that did not happen.
Ledger answer to the dev's open question — keep B
Asked, non-blocking: if the maintainer later wants A, which excluded mechanism gets revisited? Recorded, ⛔ not decided here:
service-analytics' read-scope / Cube filter compilers still refuse$field, so a CEL field-to-field RLS rule 400s on those faces #7598 Q1 = B ruling:StrategyContextwould gain declared-field / type / tenant hooks soNativeSQLStrategycan compile a$fieldnaming anincluded alias. Smaller change, but it needs that ruling reopened first, adds a second enforcement site for the [spec] SqlDriver 将$field编译为列对列比较(cross-field comparison push-down) #5222 rulings, and would have to re-spell the outside-includerefusal fromDATASET_INVALIDtoINVALID_FILTER— a caller-visible change (this is the Zone 2 [WIP] Fix error in step four of the action run #5 tripwire that fired).executeAggregate→ engine →DriverQuery, with per-hop RLS following it. That is the alias contract both the 2026-08-06 and the 2026-09-05 rulings exclude by name.⇒ Keep B, which is what the ruling itself pre-decided. Both A routes reopen a standing ruling rather than reuse an existing mechanism, and the measured demand is n = 1 today. ⛔ Neither is dispatched, and ⛔ nothing here reopens #5222, #7598 or the 2026-08-06 boundary. If demand grows, A-native is the smaller change and the ruling to reopen is #7598's, not this card's.
Transcript tier verification of the delivering seat (⛔ not its self-report): 246 occurrences of
"model":"claude-fable-5-1"and no other model anywhere, over 1,185,212 bytes.Generated by Claude Code
zhuangjianguo commentedon Sep 5, 2026
Landed — verified by content on
origin/main, ⛔ not by the API'smergedfield. Landing #18.domain:engineexecution seat,session_01ARYe3yQTQCUFm5qPYNgKaJ. PR #15781 merged at 2026-09-05T08:34Z as044403e42.origin/mainpackages/services/service-analytics/src/__tests__/include-relation-cross-field-boundary.test.tsgit cat-file -e)ZZZsuffixcontent/docs/protocol/objectql/query-syntax.mdxmentionsinclude044403e42 docs(objectql): name the include-relation boundary of a cross-field comparand, and pin it (#15103 fallback B) (#15781)What actually landed, and why it is the right outcome
This card closed on a measurement, not on an implementation — and that was the ruling's own design. The gate asked whether the ADR-0071 join chain can serve
wherecompilation. ⭐ It cannot, but not for the reason the ruling expected: the ordering is fine (the native path fills itsjoinsmap from filter members too), and the real obstacle is a different standing ruling —NativeSQLStrategy.canHandledeclines every query carrying a$field(2026-08-12 Q1 = B, #7598), so the shape never reaches the chain and lands inSqlDriver, where no join chain exists at all (0 knex-shaped joins insql-driver.ts, against a firing control of 5 in the analytics strategy).⇒ Fallback B was pre-ruled for exactly this, and 「the gate cannot be met」 was a complete delivery rather than a failure.
The one declared deviation was accepted and is the part worth keeping: the ruling said B is docs-only; the delivery adds one test file that publishes nothing and, in the dev's words, 「goes red the day A lands silently」. A boundary with no pin is prose. It measures over a real
SqliteWasmDriverthat anincluded relation column does compile into a realLEFT JOINfor a dimension and aruntimeFilter, while both arms of a$fieldcomparand on the same column are refusedINVALID_FILTER/ 400 — with a native-SQL spy proving the pass was declined, so no join was ever built.includerefusal isDATASET_INVALID/ 400, a different code from the driver'sINVALID_FILTER⇒ landing A there would have changed a caller-visible refusal for inputs already refused today — beyond what the ruling authorised. Reported rather than routed around.Clause-②: nowas the right reading and is now settled by the landing: capability unchanged, no published surface moved, no changeset (skip-changeset). The ruling's ownyeswas declared for outcome A and the ruling pre-ruled 「Under the fallback: a docs-only change … no changeset」.Ledger note for whoever revisits this: if demand for A grows (measured n = 1 today), the ruling to reopen is #7598's, not this card's — and A-native would additionally have to re-spell that
DATASET_INVALIDrefusal. Both A routes reopen a standing ruling rather than reuse an existing mechanism; B is what is now pinned in the tree.Out of scope, filed rather than ridden in: #15778 —
FieldReferenceSchema's TSDoc@examplestill spells the dotted form the prose beside it calls refused.⛔ Nothing about #5222, #7598 or the 2026-08-06 same-table boundary was reopened by this card.
Generated by Claude Code
github-actions commentedon Sep 6, 2026
os-closed-card-sweep — machine-findable marker for this generated comment.
Removed the pm-loop state label(s) this closed card no longer claims:
pm:dispatched.044403e420, merged intomain.priority:p2,finding,domain:engine— ownership, priority and outcome are not state claims.A state label claims work is in flight. This card is closed on a merged delivery, so the claim
is stale; every other label is left exactly as it was found. Nothing here is a judgement about
the card, and no verdict-bearing label is ever touched by this sweep.
posted by half-state-patrol run 34005012908 · trigger
scheduleGenerated by Claude Code
docs(objectql): name the include-relation boundary of a cross-field c…