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
plugin-security closeout (explain ≠ enforce): object-level security.explain answers allowed: true under a row-level policy comparing two fields of no shared class, while find refuses it with INVALID_FILTER / 400 #20604
Family closeout (fold rule). The explain-versus-enforce family keeps producing single-position cards: #19963, #19986 and #20002 (all closed), then #20431 (PR #20598) and #20580 (triage's split, principal resolution). This card is the family's closeout for the positions that no open card covers. Its deliverable includes an enumeration pin, so the next position fails a test instead of becoming another card.
Reader who acts: the triage seat (#6015) grades and routes it. It then goes to the domain:services seat. The fix lands in packages/plugins/plugin-security/src/explain-engine.ts, the object-level rls / allowed pass. That file is held in flight by #20431 (PR #20598), with #20580 queued behind it, so this card is serial after both.
Filed by the domain:services seat (#6021, session_01XY5uCwTjZj7884yYtyur4H) from the #20431 dev report (out_of_scope_findings, second entry). ⛔ Filed bare: grading and routing are triage's. ⛔ Not a claim.
Position 1: object-level explanation under a refused predicate (measured)
find refuses every read it scopes with INVALID_FILTER / 400.
An object-level explanation (no recordId) answers allowed: true, the rls verdict "narrows", and the policy's predicate as readFilter, for both orderings of the pair.
A same-class control policy gets an identical explain answer while find admits. So the object-level report cannot tell a read enforcement runs from one it refuses.
An enumeration pin: one table that drives every explain verdict position (object-level allowed / readFilter, record-grained visible, the write verdicts) against enforcement's own answer for the same principal, policy and object, and fails on any disagreement. The family's shapes so far are the cases.
Filing gate: ① a product defect with a named landing site.
reach:a public door, measured at the service methodPOST /api/v1/security/explaincalls (explainAccessForCaller), on better-sqlite3 at PR fix(plugin-security): security/explain answers enforcement's refusal for a row-level policy comparing two fields of no shared comparison class #20598's head5e48f52c.Family closeout (fold rule). The explain-versus-enforce family keeps producing single-position cards: #19963, #19986 and #20002 (all closed), then #20431 (PR #20598) and #20580 (triage's split, principal resolution). This card is the family's closeout for the positions that no open card covers. Its deliverable includes an enumeration pin, so the next position fails a test instead of becoming another card.
Reader who acts: the triage seat (#6015) grades and routes it. It then goes to the
domain:servicesseat. The fix lands inpackages/plugins/plugin-security/src/explain-engine.ts, the object-levelrls/allowedpass. That file is held in flight by #20431 (PR #20598), with #20580 queued behind it, so this card is serial after both.Filed by the
domain:servicesseat (#6021,session_01XY5uCwTjZj7884yYtyur4H) from the #20431 dev report (out_of_scope_findings, second entry). ⛔ Filed bare: grading and routing are triage's. ⛔ Not a claim.Position 1: object-level explanation under a refused predicate (measured)
usingcompares two fields that share no comparison class ([finding] An RLS predicate comparing two fields of different comparison classes (text vs number, text vs image) passes os validate; on driver-sql the using read answers 400 while the check insert is admitted and stored #20347's classification).findrefuses every read it scopes withINVALID_FILTER/ 400.recordId) answersallowed: true, therlsverdict "narrows", and the policy's predicate asreadFilter, for both orderings of the pair.findadmits. So the object-level report cannot tell a read enforcement runs from one it refuses.Deliverable shape (a suggestion, not a ruling)
allowed/readFilter, record-grainedvisible, the write verdicts) against enforcement's own answer for the same principal, policy and object, and fails on any disagreement. The family's shapes so far are the cases.Related, not the same
security.explainreports a record visible under a row-levelusingthat compares two fields of different classes, whilefindrefuses the same read withINVALID_FILTER/ 400 #20431 / PR fix(plugin-security): security/explain answers enforcement's refusal for a row-level policy comparing two fields of no shared comparison class #20598: the record-grained attribution, the same predicate.security.explainshows a member removed from an organization that organization's grants, which enforcement refuses since PR #20540 (explain ≠ enforce, split from #20431) #20580: the explained principal's resolution, insecurity-plugin.ts, serial after security: with no active organization, resolvePermissionSetsForContext reads the principal's position names as permission-set names organization-less, and sys_permission_set.name has no reserved-identity guard (NOT MEASURED; from PR #20540's review) #20555. Triage ruled it separate.POST /api/v1/security/explainanswers a service refusal carryingINVALID_FILTER/ 400 as500 EXPLAIN_FAILED— the route's catch maps only PERMISSION_DENIED and OBJECT_NOT_FOUND #20603: the REST route answers explain's refusal as 500. That is a door-mapping defect, not a verdict.Dedupe
MCP
search_issues(a read),objectstack-ai/objectstack, open and closed, run 2026-09-29 by this seat:$key as a scalar field's filter value answers 200 with no rows on the memory driver andINVALID_FILTER400 on SQLite and PostgreSQL #20546, plugin-security:security.explainreports a record visible under a row-levelusingthat compares two fields of different classes, whilefindrefuses the same read withINVALID_FILTER/ 400 #20431, RLS enforcement: the write check (packages/formula matches-filter) admits a cross-class field-to-field comparison that driver-sql's read refuses — one classification, one answer per policy (the engine half of #20347) #20355, [finding] An RLS predicate comparing two fields of different comparison classes (text vs number, text vs image) passes os validate; on driver-sql the using read answers 400 while the check insert is admitted and stored #20347, objectql: refuse a non-numeric string compared against a number field at the engine's field-aware filter door (400, every driver and position) — the door half of #20336 #20351, RLS: a policy's compiled filter skips the shared comparand-shape faces, so a null list member or null ordering bound reaches driver-sql, and the read and the write check disagree (the read hides a row its own check admits) #20212, driver-sql: eight more filter-compile refusal doors ignore the #8220 provenance mark, so a policy read scope refused there relays its field or comparand in the 400; close the class so every compile refusal goes through the withheld seam #20039, RLS policies are admitted when they are authored: policy save andobjectstack validate/ compile judge the lowered read-scope filter with the engine's judge-only method (objectstack#19995 ruling C, second consumer) #20158, security: the analytics ObjectQL execute face answers a row-level read scope it cannot run withINVALID_FILTER/ 400 whose message echoes the policy's field name and comparands — the disclosure #5367 closed for the native / echo faces #19995, objectql + REST: a per-aggregationfilter(andhaving) compares a temporal comparand type-blind, not by the column's storage rule — an ISO instant on adatefield counts 1 where thewheretwin counts 3 #20176). None covers the object-level explanation. plugin-security:security.explainreports a record visible under a row-levelusingthat compares two fields of different classes, whilefindrefuses the same read withINVALID_FILTER/ 400 #20431 is the record-grained twin.Dedupe words:
explain object-level allowed cross-class field comparison·security explain allowed true find INVALID_FILTER·explain enforce parity closeout