Skip to content

fix(ai): reject ignored analytics filter scopes - #723

Merged
izadoesdev merged 2 commits into
stagingfrom
codex/insights-query-contract
Sep 5, 2026
Merged

fix(ai): reject ignored analytics filter scopes#723
izadoesdev merged 2 commits into
stagingfrom
codex/insights-query-contract

Conversation

@izadoesdev

@izadoesdev izadoesdev commented Sep 5, 2026

Copy link
Copy Markdown
Member

Fresh investigations supplied event/error filter targets that the query compiler silently discarded, so tool results described a narrower cohort than the SQL actually selected. Remove unsupported scope options from the model-facing filter schema, reject invalid CTE/HAVING scopes in the compiler, and expose each builder's accepted selectors, outputs, and default order. Results now carry their filter/date scope and explicitly distinguish query rows from a complete population.

Validation: 348 focused query/tool tests, 100 batch-executor tests, and 229 insights tests passed. Repository lint and all 33 typecheck/build tasks passed. Tests use synthetic data. Scope is query correctness and discoverability; no storage migrations, production cleanup, or model-policy changes. No dependencies or known ownership overlaps.


Summary by cubic

Rejects unsupported analytics filter scopes so tool results always match the SQL cohort, and exposes builder contracts so models can construct valid queries.

  • Filter targets and having selectors are rejected with clear public errors instead of being silently discarded, including for trait filters.
  • discover_query_types now returns each builder's allowed and required filters, operators, output fields, and default order, and flags builders with undocumented ordering or output schema so models omit orderBy instead of guessing.
  • get_data results include the applied filter/date scope and distinguish returned rows from the query row count.

Written for commit 80a5214. Summary will update on new commits.

Review in cubic

@vercel

vercel Bot commented Sep 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
dashboard Ready Ready Preview Sep 5, 2026 4:21pm UTC
databuddy-status Ready Ready Preview Sep 5, 2026 4:21pm UTC
documentation Ready Ready Preview Sep 5, 2026 4:21pm UTC

@coderabbitai

coderabbitai Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Team

Run ID: 75bc4ce9-7090-4221-9fde-de2aafcf0dc0

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 8 files

Architecture diagram
sequenceDiagram
    participant Model as AI Model
    participant Discover as discover_query_types Tool
    participant GetData as get_data Tool
    participant Compiler as SimpleQueryBuilder
    participant TraitFilter as Trait Filters Resolver
    participant DB as Analytics Database

    Note over Model,DB: Query Discovery & Validation Flow

    Model->>Discover: discover_query_types(search)
    Discover->>Discover: Enumerate QueryBuilders
    Discover-->>Model: Builder contracts (allowedFilters, operators, outputFields, defaultOrder, requiredFilters)

    Model->>GetData: get_data({queries: [{type, filters, orderBy}]})

    GetData->>GetData: Resolve website context & dates
    GetData->>GetData: Validate query schema (strict filter objects)

    alt Filter has target or having
        GetData-->>Model: Error - reject invalid filter scope
    else Filter is trait field
        GetData->>TraitFilter: resolveRequestTraitFilters()
        TraitFilter->>TraitFilter: Check for target/having on trait filters
        alt Trait filter has target/having
            TraitFilter-->>GetData: Throw TraitFilterError
            GetData-->>Model: Error - trait filters must select rows
        else Valid trait filter
            TraitFilter->>DB: Resolve trait segment
            DB-->>TraitFilter: Segment cohort
            TraitFilter-->>GetData: Row-level trait filters
        end
    else Standard row filter
        GetData->>Compiler: compile() with filters
        Compiler->>Compiler: Validate filter targets against CTEs
        alt Invalid target or having on custom SQL
            Compiler-->>GetData: Throw "Filter target not permitted" / "Having filters not supported"
            GetData-->>Model: Public error (sanitized)
        else Valid filter scope
            Compiler->>Compiler: Build SQL with WHERE clause
            Compiler-->>GetData: Compiled query + params
            GetData->>DB: Execute SQL
            DB-->>GetData: Query rows (up to 1000)
            GetData->>GetData: Truncate to 20 rows, track rowCount
            GetData-->>Model: Result with filters, dates, returnedRows, rowCount, truncated flag
        end
    end
Loading

Shadow auto-approve: would not auto-approve because issues were found.

Re-trigger cubic

Comment thread packages/ai/src/ai/tools/discover-query-types.ts Outdated
Comment thread packages/ai/src/ai/tools/discover-query-types.ts Outdated
@unkey-deploy

unkey-deploy Bot commented Sep 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Unkey Deploy

Name Status Preview Inspect Updated (UTC)
links (preview) Ready Visit Preview Inspect Sep 5, 2026 4:20pm

@izadoesdev izadoesdev left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed query compilation, trait resolution, tool validation, result scope and discovery metadata. Unsupported filter targets and HAVING cannot silently broaden an agent cohort. Custom SQL discovery now distinguishes undocumented ordering/output columns from a known unordered aggregate. Recent errors and session metrics have verified explicit metadata; unannotated custom builders remain explicitly unknown.

The existing batch-executor signature test caught a metadata column-order mismatch during review; it was corrected before pushing. Focused tests, the full 27-task pre-push suite, root lint and all 33 type/build tasks pass. Rebased on current staging after #724 without conflicts.

@dosubot

dosubot Bot commented Sep 5, 2026

Copy link
Copy Markdown

📄 Knowledge review

✏️ Suggested updates

1 page suggestion needs review.

Page Library Status
Query Filtering by User Traits Databuddy's Space 🟡 Review
📝 Query Filtering by User Traits
@@ -303,6 +303,18 @@
 
 ***
 
+### Invalid filter scopes
+
+Trait filters can only be used to select rows in the query. Passing a trait filter with `target` or `having` scope options throws:
+
+```
+Trait filters must select rows, without target or having.
+```
+
+The `target` scope is reserved for filtering within a specific CTE (common table expression), and `having` scopes filter aggregated results — neither is supported for trait filtering. This validation happens in the query compiler before trait segment resolution [[6]](https://github.com/databuddy-analytics/Databuddy/pull/723).
+
+***
+
 ### Summary of error messages
 
 | Condition | Error message |
@@ -311,6 +323,7 @@
 | Builder does not allow `profile_id` | `"Trait filters are not supported for {name}"` |
 | Segment exceeds 10,000 profiles | `"Trait segment exceeds 10000 profiles — narrow the filter."` |
 | Unsupported operator | `"Trait filters do not support the {op} operator."` |
+| Trait filter uses `target` or `having` scope | `"Trait filters must select rows, without target or having."` |
 | `resolveTraitSegment` throws any other error | The error message is forwarded as-is |
 
 ## Implementation Details

Accept · Edit · Decline


Leave Feedback Ask Dosu about Databuddy Add Dosu to your team

@izadoesdev
izadoesdev merged commit 0b54347 into staging Sep 5, 2026
21 checks passed
@izadoesdev
izadoesdev deleted the codex/insights-query-contract branch September 5, 2026 16:23
@greptile-apps

greptile-apps Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR tightens model-facing analytics filters, rejects unsupported compiler scopes, adds builder discovery metadata, and returns query-scope and row-count information with get_data.

  • Removes target and having from the AI tool's filter schema.
  • Rejects unsupported CTE, HAVING, and trait-filter scopes instead of silently discarding them.
  • Exposes filter, output, and ordering contracts through query discovery.
  • Adds result scope and truncation metadata.
  • Discovery currently overstates filter support for custom-SQL builders that do not consume generated filter conditions.

Confidence Score: 4/5

The PR is not yet safe to merge because discovery can direct callers to apply filters that an uptime builder silently ignores.

The scope rejection and result metadata are consistent with their intended contracts, but the new discovery contract exposes global filters for uptime_time_series even though its custom SQL never applies generated filter conditions, allowing incorrect unfiltered analytics results.

Files Needing Attention: packages/ai/src/ai/tools/discover-query-types.ts

Important Files Changed

Filename Overview
packages/ai/src/ai/tools/discover-query-types.ts Adds rich builder contracts, but advertises global filters for custom-SQL builders that can silently ignore them.
packages/ai/src/ai/tools/get-data.ts Rejects unsupported model-facing filter properties and reports query scope, row counts, and truncation.
packages/ai/src/query/simple-builder.ts Rejects invalid target and custom-SQL HAVING filters before compilation.
packages/ai/src/query/trait-filters.ts Prevents trait resolution from silently discarding target or HAVING scope.
packages/ai/src/query/builders/errors.ts Documents the output schema and effective ordering of recent error queries.
packages/ai/src/query/builders/sessions.ts Documents session metric outputs and correctly marks the aggregate as unordered.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  D[discover_query_types] --> C[Builder contract]
  C --> M[Model constructs get_data request]
  M --> V[Validate filter field and scope]
  V --> Q[Compile named query]
  Q --> S[Custom or standard SQL]
  S --> R[Rows plus scope and truncation metadata]
  C -. overstated global filters .-> U[uptime_time_series]
  U -. filterConditions omitted .-> R
Loading

Reviews (1): Last reviewed commit: "fix(ai): disclose incomplete query disco..." | Re-trigger Greptile

function listAllTypes(): DiscoveredType[] {
function listAllTypes() {
return Object.entries(QueryBuilders).map(([name, config]) => ({
allowedFilters: allowedFilterFields(config),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Discovery overstates filter support

Discovery advertises every global analytics filter for every builder, but uptime_time_series does not consume filterConditions. A model following this contract can submit an advertised filter such as country; validation accepts it, but the custom SQL applies only site and timestamp predicates. The result therefore contains unfiltered uptime data even though the requested scope appears to have been applied.

Knowledge Base Used: Analytics query engine

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant