Skip to content

[finding] service-analytics is a second filter emitter that still refuses $field — a CEL rule that now pushes down on the drivers still 400s through the analytics faces #7604

Description

@os-zhuang

Reported by the dev seat while implementing #5222 (PR #7582), filed by the spec-lane PM as its own card per that PR's scope boundary. Recording, not claiming.

The residue

#5222 landed cross-field push-down ({ $field: 'col' } → a real column reference) in driver-sql, closing the split where one CEL permission/RLS rule behaved differently depending on whether the query reached a database. service-analytics has its own independent filter emittersread-scope-sql and filter-normalizer — each carrying its own mirrored comparand gate, and both still refuse $field.

So the split is narrowed, not closed: a CEL rule containing a field-to-field comparison now works through the ObjectQL/driver path and still answers 400 when lowered through the analytics faces.

Why it was correctly left out of #5222

That issue's maintainer rulings (2026-08-06) are about the driver: same-table columns only, declared-only enumeration, tenant-isolation column forbidden as a referent, federated tables refused. Nothing in them speaks to the analytics emitters, and #5222's dev seat declined to widen a security-relevant acceptance surface in a second subsystem as a side effect — the right call.

Note the envelope difference already recorded in #5222's blast-radius sweep: read-scope-sql refuses with READ_SCOPE_COMPILE_FAILED / 500 rather than INVALID_FILTER / 400, deliberately, because it is compiling an RLS read scope. Any disposition here has to say what that path should do — a 500 on a rule the drivers now execute is a worse split than the 400.

What a card here would have to decide

  1. Do the analytics emitters implement $field under the same four constraints [spec] SqlDriver 将 $field 编译为列对列比较(cross-field comparison push-down) #5222 adopted (same-table, declared-only, tenant column forbidden, federated refused), or do they stay refusing by design because an analytics read scope is a different trust boundary?
  2. If they implement: is the constraint set shareable, or does each emitter re-derive it? [spec] SqlDriver 将 $field 编译为列对列比较(cross-field comparison push-down) #5222 deliberately kept its corpus out of packages/spec/src/data so it would not enrol every driver in conformance DEBT — the same reasoning needs re-running for a second consumer.
  3. If they keep refusing: READ_SCOPE_COMPILE_FAILED / 500 should probably become a loud, documented refusal rather than a compile failure, so the rule author learns the rule is unsupported here instead of seeing a server error.

Natural lane: domain:spec for the acceptance decision (precedent: #5222 itself, #7464). Reference implementation and the constraint arguments: PR #7582.

Refs: #5222, #5041, PR #7582, ADR-0015, ADR-0112.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions