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 boolean comparand is judged only at the engine door: the RLS compile seam and analytics NativeSQL pass a string against a declared boolean field as written (the family of #21333) #21376
Filing gate: ① a defect family with named positions, class (b), a Seam: the spec's boolean comparand verdict, which PR #21372 adds, is consumed by the engine's field-aware filter door alone. Two compilers that build filters outside that door skip it.
Position 1:reach: the security exception, because a row-level policy's exclusion is not applied. It was measured in-process, not over HTTP.
Position 2:reach: a public door, measured.
Filed by domain:engine#1 (seat post #6367, session_017xfMoEjKUuSh2xYB8sCozp) from #21333's dev report 5948452642 (out_of_scope_findings 1 and 2). PR #21372's at-tier contract review 5948769828 (③) judged both reach readings sufficient and one family card the right carrier. Reader who acts: triage grades and routes. Both positions are in domain:services packages. ⛔ Not a claim.
The family
#21333 (PR #21372, not yet merged at this filing) makes the engine judge a comparand against a declared boolean / toggle field (or a formula returning boolean):
true / false pass as written;
1 / 0, "1" / "0" and "true" / "false" narrow to the boolean they name;
any other string is refused INVALID_FILTER / 400.
The verdict and its words are a new @objectstack/spec/data contract (filter-boolean-comparand-declared-type.ts). Every filter that reaches engine.find / aggregate / update / delete passes through it. The two compilers below build their filters themselves, so a string against a boolean column reaches the driver as written. On SQLite (SqlDriver) a stored boolean is 1 / 0, and the string 'true' equals neither.
service-analytics' NativeSQL strategy. It compiles a dataset's runtimeFilter (and the analytics where) to SQL itself, past the engine door. Measured by the dev through POST /api/v1/analytics/dataset/query: RestServer's route handler over AnalyticsServicePlugin's own composition on SqlDriver (SQLite), NativeSQL answering, two rows. Results:
SKILL.md 〈升级与决策〉, meta-criterion ②: one operation, two implementations, and behaviour that differs ⇒ the side with governance (the engine door) wins, and the other side is rebound to it.
Scope for whoever takes it (⛔ not a ruling)
Position 1: the RLS compile seam runs the spec's boolean verdict beside its number arm. It refuses through the existing refused-comparand route (read: deny sentinel; write: 403), and narrows a canonical spelling copy-on-write.
Position 2: the NativeSQL compiler runs the same verdict on runtimeFilter and the analytics where. It refuses 400 and narrows, as the engine door does.
Pins:
each table row above answers the engine-door column;
the string-negation RLS cell hides the true row;
the controls (true, 1) are unchanged.
Clause-②: no (narrowing), as read today: no new export is expected. The claim measures that.
Filing gate: ① a defect family with named positions, class (b), a Seam: the spec's boolean comparand verdict, which PR #21372 adds, is consumed by the engine's field-aware filter door alone. Two compilers that build filters outside that door skip it.
reach:the security exception, because a row-level policy's exclusion is not applied. It was measured in-process, not over HTTP.reach:a public door, measured.Filed by
domain:engine#1(seat post #6367,session_017xfMoEjKUuSh2xYB8sCozp) from #21333's dev report 5948452642 (out_of_scope_findings1 and 2). PR #21372's at-tier contract review 5948769828 (③) judged both reach readings sufficient and one family card the right carrier. Reader who acts: triage grades and routes. Both positions are indomain:servicespackages. ⛔ Not a claim.The family
#21333 (PR #21372, not yet merged at this filing) makes the engine judge a comparand against a declared
boolean/togglefield (or aformulareturning boolean):true/falsepass as written;1/0,"1"/"0"and"true"/"false"narrow to the boolean they name;INVALID_FILTER/ 400.The verdict and its words are a new
@objectstack/spec/datacontract (filter-boolean-comparand-declared-type.ts). Every filter that reachesengine.find/aggregate/update/deletepasses through it. The two compilers below build their filters themselves, so a string against a boolean column reaches the driver as written. On SQLite (SqlDriver) a stored boolean is1/0, and the string'true'equals neither.Positions
The RLS compile seam.
packages/plugins/plugin-security/src/rls-compiler.ts: thecompileCelToFilteroutput, which the security middleware ANDs into the read after the caller-filter door. Measured by the dev withSecurityPlugin's real middleware over a realObjectQLonSqlDriver(SQLite), as a member, over two rows (one true, one false), at PR fix(objectql)!: a string comparand against a boolean field is narrowed to its boolean, or refused 400, at the engine filter door #21372's head:usingcomparing the boolean field with the boolean literaltrueshows the true row (the control);'true'shows no row;!=) shows BOTH rows. The exclusion the author wrote is not applied: fail-open on read.'yes') shows no row, silently.No in-repo producer writes such a predicate (git grep over
examples,packagesandskills: 0). The seam already runs the number arm of the same family since7aab75920(formula: retire F7's whole-day copy (lteBound in matches-filter.ts) now that the RLS write check judges the stored form (#21109, PR #21235); its direct-call cases move to the storage-form lowering #21242):narrowPolicyNumberComparandsinjudgeCompiledComparands. The boolean arm is its twin.service-analytics' NativeSQL strategy. It compiles a dataset'sruntimeFilter(and the analyticswhere) to SQL itself, past the engine door. Measured by the dev throughPOST /api/v1/analytics/dataset/query:RestServer's route handler overAnalyticsServicePlugin's own composition onSqlDriver(SQLite), NativeSQL answering, two rows. Results:runtimeFilter{ flag: true }{ flag: "true" }{ flag: { $ne: "true" } }{ flag: "yes" }INVALID_FILTER{ flag: 1 }Governing text
packages/spec/src/data/filter-boolean-comparand-declared-type.ts(PR fix(objectql)!: a string comparand against a boolean field is narrowed to its boolean, or refused 400, at the engine filter door #21372): the accepted set, the verdict and its words. It is one grammar, shared with the record validator's write side (record-validator.ts's boolean arm).Scope for whoever takes it (⛔ not a ruling)
refused-comparandroute (read: deny sentinel; write: 403), and narrows a canonical spelling copy-on-write.runtimeFilterand the analyticswhere. It refuses 400 and narrows, as the engine door does.true,1) are unchanged.Clause-②: no (narrowing), as read today: no new export is expected. The claim measures that.Dedupe
Through
mcp__github__search_issues, repo-scoped, open and closed, and a scan of all 150 open issues by title and body:ExpressionInputSchemaslot an engine evaluates (formulaexpression, validation / hook / sharingcondition,visibleWhen…) still accepts anast-only or blank-sourceenvelope #15811, finding: after the #7598 Q1=B ruling, a read scope with a driver-refused field reference answers 400 from the driver — which cuts across #5367's attribution argument on that one path #7929);whereskips the shared comparand-TYPE face, so a plain-object / Map / oversized-bigint comparand is bound as JSON text on the native path while the FilterArray spelling and the engine refuse 400 #20035 (the object-formwhereand the shared comparand-TYPE face), service-analytics: the NativeSQL read-scope compiler and the/analytics/sqlecho compile two scope shapes the shared comparand faces refuse (plain-object comparand under$eq, null member in$in): one scope, two answers across faces #20018, service-analytics:$icontainswith an empty comparand answers every non-NULL row on the analytics where and read-scope compilers, where FILTER_TEXT_CASES declares it refused (INVALID_FILTER) and driver-sql refuses it #20068 and service-analytics: the NativeSQL execute face and the /analytics/sql echo bind a read-scope filter placeholder ({current_user_id}, an unknown {token}) as a literal string, where the ObjectQL face resolves it — one scope, different rows across faces #20075;whereskips the shared comparand-shape face's other arms ($innull member,$gt: null, null/blank$betweenbound, scalar$in) that the FilterArray spelling refuses 400 #20010, [finding] service-analytics read scope: compileScopedFilterToSql applies no whole-day upper bound and binds a temporal comparand as written, so an RLS $lte on a bare day drops the rest of that day in NativeSQL analytics #20733;None covers either position.
Dedupe words:
boolean comparand RLS seam·using predicate string 'true'·NativeSQL runtimeFilter boolean·analytics where boolean narrowing·boolean declared-type door outside engineGenerated by Claude Code