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
[A of #7929] a spec-declared provenance mark set at both read-scope merge boundaries, so the driver can restore the author-facing cross-field diagnostic without re-disclosing policy #8220
This is "A" of the maintainer ruling of 2026-08-12 on #7929 (comment 5266067250, verbatim 「接受你的全部建议。」 — adopting "B now, A next"). B landed in #8198 (merged a5dcb74, closing #7929 and #7988). This card is the sanctioned follow-up, not a new proposal.
⛔ Filed unassigned — claim it before writing code, per the repo's claim discipline.
Why A exists
B stopped driver-sql's cross-field INVALID_FILTER refusal from echoing its operands, for every caller, because the driver genuinely cannot tell an administrator's predicate from an author's. Measured on both merge boundaries: the read scope arrives as a bare FilterCondition in where, DriverQuery is Omit<QueryAST, 'object'> with no provenance slot, and the only thing that crosses (context) says who is asking, never which subtree they did not write.
The accepted cost, stated plainly in B's changeset: an author debugging their own cross-field filter now gets the redacted message too. Their diagnostic is relocated to the server log, not destroyed. A is what gives it back — behind a real mark rather than a guess.
What A has to build
A provenance mark declared in packages/spec. Declared, not conventional — the whole point is that the driver may trust it because the contract defines it.
Set at BOTH merge boundaries, or the fix is half-live:
plugin-security's CRUD injection — the ast.where = ast.where ? { $and: [ast.where, scoped] } : scoped merge around security-plugin.ts:2198;
driver-sql consumes it: a marked (policy-authored) subtree keeps B's redaction; an unmarked, author-written filter gets its full diagnostic back — both columns, the operator, the list index, the boundary reason.
⚠️ The invariant that must not regress — fail closed
An unmarked or ambiguous predicate must default to WITHHELD. The mark is permission to reveal, never a requirement to prove secrecy. A driver-side guess at provenance is precisely the shape triage rejected on #7929, and an inverted default would silently restore the original disclosure — including the sentence naming which column is the object's tenant-isolation column. Any design where "the mark is missing" lands on the disclosing branch is wrong, however convenient.
⚠️ One pin A is expected to REWRITE — it is not a regression
packages/runtime/src/cross-field-refusal-operand-withhold.test.ts contains a byte-equality assertion: an author-written $field filter and a policy-injected one must produce identical messages. That pin is the strongest available statement of "the driver cannot tell them apart" — which is exactly the fact A is chartered to change.
Whoever implements A must rewrite that assertion deliberately, and say so in the changeset. ⛔ Do not treat it as a failing test to make green by weakening it, and ⛔ do not delete it — replace it with its successor: marked and unmarked now differ, and the unmarked-by-default case still withholds. Left unexplained, this pin reads like a bug to the next agent who runs the suite.
An author's own cross-field filter names its columns again; a policy-injected one does not; an unmarked one does not; and all three are pinned at the two real merge boundaries with a real driver, not a mock.
This is "A" of the maintainer ruling of 2026-08-12 on #7929 (comment
5266067250, verbatim 「接受你的全部建议。」 — adopting "B now, A next"). B landed in #8198 (mergeda5dcb74, closing #7929 and #7988). This card is the sanctioned follow-up, not a new proposal.⛔ Filed unassigned — claim it before writing code, per the repo's claim discipline.
Why A exists
B stopped
driver-sql's cross-fieldINVALID_FILTERrefusal from echoing its operands, for every caller, because the driver genuinely cannot tell an administrator's predicate from an author's. Measured on both merge boundaries: the read scope arrives as a bareFilterConditioninwhere,DriverQueryisOmit<QueryAST, 'object'>with no provenance slot, and the only thing that crosses (context) says who is asking, never which subtree they did not write.The accepted cost, stated plainly in B's changeset: an author debugging their own cross-field filter now gets the redacted message too. Their diagnostic is relocated to the server log, not destroyed. A is what gives it back — behind a real mark rather than a guess.
What A has to build
packages/spec. Declared, not conventional — the whole point is that the driver may trust it because the contract defines it.plugin-security's CRUD injection — theast.where = ast.where ? { $and: [ast.where, scoped] } : scopedmerge aroundsecurity-plugin.ts:2198;service-analytics' read-scope merge (ObjectQLStrategy.withReadScope).driver-sqlconsumes it: a marked (policy-authored) subtree keeps B's redaction; an unmarked, author-written filter gets its full diagnostic back — both columns, the operator, the list index, the boundaryreason.An unmarked or ambiguous predicate must default to WITHHELD. The mark is permission to reveal, never a requirement to prove secrecy. A driver-side guess at provenance is precisely the shape triage rejected on #7929, and an inverted default would silently restore the original disclosure — including the sentence naming which column is the object's tenant-isolation column. Any design where "the mark is missing" lands on the disclosing branch is wrong, however convenient.
packages/runtime/src/cross-field-refusal-operand-withhold.test.tscontains a byte-equality assertion: an author-written$fieldfilter and a policy-injected one must produce identical messages. That pin is the strongest available statement of "the driver cannot tell them apart" — which is exactly the fact A is chartered to change.Whoever implements A must rewrite that assertion deliberately, and say so in the changeset. ⛔ Do not treat it as a failing test to make green by weakening it, and ⛔ do not delete it — replace it with its successor: marked and unmarked now differ, and the unmarked-by-default case still withholds. Left unexplained, this pin reads like a bug to the next agent who runs the suite.
Scope notes
applySystemFieldsinjects platform anchors intoexternalobjects the platform provisions no storage for — three consumers have now independently re-derived "that column is not really there" #7865 provenance marker" in the context of injected anchors on external objects. I have not confirmed whether that marker generalises to read-scope filter subtrees; it may be an unrelated mechanism. Read it first — a second, parallel provenance concept inpackages/specwould be worse than either alone.driver-tursocarries its own copy of the refusal (RemoteTransport.uncompilableComparand), fixed in fix(driver-sql,driver-turso): a cross-field$fieldrefusal stops naming the two columns it compared (#7929, #7988) #8198;driver-sqlite-wasminherits fromSqlDriver. A has the same three-driver surface.Done means
An author's own cross-field filter names its columns again; a policy-injected one does not; an unmarked one does not; and all three are pinned at the two real merge boundaries with a real driver, not a mock.