Skip to content

DEV-1726: dialect-aware case folding for CTE name collision detection - #273

Merged
ZmeiGorynych merged 6 commits into
egor/dev-1703-comprehensive-approach-expressions-crossing-joins-on-thefrom
egor/dev-1726-dialect-aware-case-folding-for-cte-name-collision-detection
Aug 3, 2026
Merged

DEV-1726: dialect-aware case folding for CTE name collision detection#273
ZmeiGorynych merged 6 commits into
egor/dev-1703-comprehensive-approach-expressions-crossing-joins-on-thefrom
egor/dev-1726-dialect-aware-case-folding-for-cte-name-collision-detection

Conversation

@ZmeiGorynych

@ZmeiGorynych ZmeiGorynych commented Aug 3, 2026

Copy link
Copy Markdown
Member

Follow-up from DEV-1713 Stage 9 (Codex review of PR #269). Closes DEV-1726.

Problem

AliasAllocator and assert_unique_cte_names compared CTE names by exact string, but generated CTE names are emitted unquoted — so on case-folding backends, two user measure aliases differing only in case (Foo/foo) that both generate CTEs produced shifted_Foo/shifted_foo, a duplicate WITH name after the backend folds (reproduced on Postgres).

Fix

  • AliasAllocator gains folds_case: every _taken comparison folds with str.lower() (comparison only — allocated names keep the caller's case), so the second family walks to shifted_foo_2/sjoin_foo_2 and every reference follows the returned name.
  • assert_unique_cte_names folds per dialect (same signature; policy resolved internally). The belt folds regardless of quoting — deliberately over-strict on SLayer's own allocator-sanitized output, where a fold-collision always signals an allocator-bypass bug.
  • Policy lives in naming.py: CASE_FOLDING_SQLGLOT_DIALECTS + explicit KNOWN_CASE_SENSITIVE_SQLGLOT_DIALECTS (so a future dialect can't skip the decision — registry-guard-tested) + dialect_folds_case() (input strip().lower()-normalized; unknown strings stay exact).
  • One new SQLGenerator._new_allocator() factory threads the policy to all 8 former construction sites and is test-pinned as the module's only AliasAllocator construction site.

Fold-set corrections vs the issue text (evidence-backed)

  • BigQuery FOLDS: GoogleSQL's case-sensitivity table marks "aliases within a query" (which CTE names are) case-insensitive — only real table/dataset names are case-sensitive; sqlglot classifies BigQuery CASE_INSENSITIVE.
  • SQLite/DuckDB fold even QUOTED names (verified empirically: duplicate WITH table name on the quoted pair), correcting the "quoted SQLite" parenthetical.
  • MySQL/T-SQL fold deliberately despite platform/collation-dependence: folding is rename-only-safe, while not folding leaves the bug live on majority configs (Windows/macOS MySQL, default-collation SQL Server).
  • Exact: ClickHouse (case-sensitive identifiers) + unknown dialect strings (previous behavior, fail-safe).

Tests

52 new tests in tests/test_dev1726_cte_case_folding.py: fold-set membership for all 14 registry dialects + registry-fully-classified guard; allocator fold/exact/suffix-walk/lower-not-casefold semantics; belt fold/exact/quoted/nested-scope/message-content; e2e Foo/foo time_shift vehicle across all 14 dialects (exact renamed families, structural CTE-reference check, user-facing result keys survive byte-identical); cp_reset_*/cp_value_* sibling-family vehicle; single-construction-site guard. Full non-integration suite: 8337 passed.

Also includes the merge of origin/egor/dev-1703-… (Stages 4+6) into this branch, resolving the Stage 4 × Stage 9 semantic conflict per DECISIONS.md (the user-approved derived-shared-grain raise wins; the two Stage-9 Codex-F6 agreement tests split their coverage into separate queries).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Improved SQL alias and CTE naming across dialects, preventing case-related collisions while preserving public result names.
    • Enhanced handling of dotted and mixed-case identifiers, including appropriate quoting.
    • Improved naming consistency for time-shifted, aggregated, joined, and transformed queries.
  • Tests

    • Added coverage for dialect-specific case folding, CTE collisions, nested scopes, and generated SQL references.
    • Expanded validation of result-column naming across local, derived, and cross-model queries.
  • Documentation

    • Recorded approved rules for shared-grain rejection and CTE name handling.

ZmeiGorynych and others added 2 commits August 3, 2026 11:03
…oach-expressions-crossing-joins-on-the' into egor/dev-1726-dialect-aware-case-folding-for-cte-name-collision-detection

# Conflicts:
#	DECISIONS.md
AliasAllocator gains folds_case (comparison-only str.lower() folding;
allocated names keep original case) and assert_unique_cte_names folds
per dialect, so case-differing user aliases that both generate CTEs
(shifted_Foo/shifted_foo) dedup instead of colliding after the backend
folds. Policy lives in naming.py (CASE_FOLDING_SQLGLOT_DIALECTS +
KNOWN_CASE_SENSITIVE_SQLGLOT_DIALECTS + dialect_folds_case); the single
SQLGenerator._new_allocator factory threads it to all former
construction sites (test-pinned as the only one). Fold set = every
registry dialect except ClickHouse; unknown strings stay exact.

Issue-text corrections (GoogleSQL docs + sqlglot + empirics): BigQuery
FOLDS (CTE names are query aliases, case-insensitive); SQLite/DuckDB
fold even quoted names. MySQL/T-SQL fold deliberately despite
config-dependence (rename-only-safe). Belt folds regardless of quoting
— over-strict by design on allocator-sanitized output.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@linear

linear Bot commented Aug 3, 2026

Copy link
Copy Markdown

DEV-1726

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4cfc7214-f264-4ec9-9cfe-eb5258e6553d

📥 Commits

Reviewing files that changed from the base of the PR and between e826484 and a7a0c24.

📒 Files selected for processing (1)
  • slayer/sql/generator.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • slayer/sql/generator.py

📝 Walkthrough

Walkthrough

The change centralizes SQL naming policies, adds dialect-aware case-folding allocation, validates CTE name collisions, routes generator allocators through one factory, and expands regression coverage for aliases, CTEs, SQL validation, and result-key preservation.

Changes

Naming and SQL generation

Layer / File(s) Summary
Centralized naming contracts
slayer/sql/naming.py
Adds dialect classification, case-folded alias allocation, result-key and flattened-name builders, dotted-alias encoding, mixed-case identifier quoting, and scoped CTE collision validation.
Generation-wide collision-safe allocation
slayer/sql/generator.py
Adds _new_allocator and routes planned queries, transforms, aggregates, placeholders, cross-model scopes, and time-shift scopes through dialect-aware allocation.
Validation and naming regression coverage
tests/test_dev1726_cte_case_folding.py, tests/test_dev1713_naming.py, tests/dialects/conftest.py, tests/test_sql_generator.py, DECISIONS.md
Adds dialect, allocator, CTE, integration, result-key, and shared SQL-validation coverage. Documents the naming decisions.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SQLGenerator
  participant AliasAllocator
  participant CTEValidator
  SQLGenerator->>AliasAllocator: create dialect-aware allocator
  SQLGenerator->>AliasAllocator: allocate aliases and CTE names
  AliasAllocator-->>SQLGenerator: return names with preserved casing
  SQLGenerator->>CTEValidator: validate generated WITH scopes
  CTEValidator-->>SQLGenerator: return validation result or collision error
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 51.49% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the pull request's main change: dialect-aware CTE name collision detection.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch egor/dev-1726-dialect-aware-case-folding-for-cte-name-collision-detection

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

@coderabbitai coderabbitai Bot left a comment

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.

🧹 Nitpick comments (4)
tests/_engine_helpers.py (1)

33-49: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consolidate the three duplicate _assert_valid_sql implementations. All three files define an identical _assert_valid_sql helper (parse, statement-count assert, TypeErrorAssertionError re-raise, nested-WITH check). This PR had to apply the same BigQuery-carve-out removal in all three places by hand, which is exactly the kind of drift risk that duplicated test helpers create.

  • tests/_engine_helpers.py#L33-L49: keep this as the canonical _assert_valid_sql definition (it is already imported as a shared test utility module).
  • tests/dialects/conftest.py#L31-L45: remove the local copy and import _assert_valid_sql from tests/_engine_helpers.py instead.
  • tests/test_sql_generator.py#L179-L196: remove the local copy and import _assert_valid_sql from tests/_engine_helpers.py instead.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/_engine_helpers.py` around lines 33 - 49, Consolidate the duplicate
_assert_valid_sql helpers by keeping tests/_engine_helpers.py#L33-L49 as the
canonical implementation, including parsing, statement-count validation,
nested-WITH checking, and TypeError-to-AssertionError handling. Remove the local
definitions from tests/dialects/conftest.py#L31-L45 and
tests/test_sql_generator.py#L179-L196, and import and reuse the canonical helper
in both files.
slayer/engine/stage_planner.py (1)

1084-1110: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider extracting the shared saved-measure lookup.

_bare_saved_measure_name duplicates the guard clauses of _saved_model_measure_type (isinstance(scope, ModelScope) check, bare.isidentifier() check, scope.source_model.get_measure(bare) lookup). Only the returned attribute differs (.name vs .type).

Extract a shared helper that returns the matched ModelMeasure (or None), and have both callers read the field they need.

♻️ Proposed consolidation
+def _bare_saved_measure(
+    *, scope: Union[ModelScope, StageSchema], formula: str,
+) -> Optional["ModelMeasure"]:
+    """The saved ``ModelMeasure`` when ``formula`` is a bare identifier
+    matching a ``ModelMeasure.name`` on the source model, else ``None``."""
+    if not isinstance(scope, ModelScope) or scope.source_model is None:
+        return None
+    bare = formula.strip()
+    if not bare.isidentifier():
+        return None
+    return scope.source_model.get_measure(bare)
+
+
 def _saved_model_measure_type(
     *, scope: Union[ModelScope, StageSchema], formula: str,
 ) -> Optional[DataType]:
     ...
-    if not isinstance(scope, ModelScope) or scope.source_model is None:
-        return None
-    bare = formula.strip()
-    if not bare.isidentifier():
-        return None
-    saved = scope.source_model.get_measure(bare)
-    return saved.type if saved is not None else None
+    saved = _bare_saved_measure(scope=scope, formula=formula)
+    return saved.type if saved is not None else None


 def _bare_saved_measure_name(
     *, scope: Union[ModelScope, StageSchema], formula: str,
 ) -> Optional[str]:
     ...
-    if not isinstance(scope, ModelScope) or scope.source_model is None:
-        return None
-    bare = formula.strip()
-    if not bare.isidentifier():
-        return None
-    saved = scope.source_model.get_measure(bare)
-    return saved.name if saved is not None else None
+    saved = _bare_saved_measure(scope=scope, formula=formula)
+    return saved.name if saved is not None else None

Also applies to: 1113-1134

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@slayer/engine/stage_planner.py` around lines 1084 - 1110, Extract the shared
saved-measure lookup from _saved_model_measure_type and _bare_saved_measure_name
into a helper that validates ModelScope, accepts only bare identifiers, and
returns the matched ModelMeasure or None. Update both callers to use this
helper, then read .type in _saved_model_measure_type and .name in
_bare_saved_measure_name while preserving their existing fallback behavior.
tests/test_dev1713_naming.py (2)

63-66: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use the pytest tmp_path fixture instead of tempfile.mkdtemp().

tempfile.mkdtemp() creates a directory that is never removed. The engine fixture is function-scoped, so each test in TestJoinedDimensionDottedKeys and TestMultiStageNaming leaves one temp directory with a SQLite file and a YAML store behind. tmp_path gives per-test isolation and automatic cleanup.

♻️ Proposed change
 `@pytest.fixture`
-async def engine() -> AsyncIterator[SlayerQueryEngine]:
-    d = tempfile.mkdtemp()
-    db_path = os.path.join(d, "t.db")
+async def engine(tmp_path) -> AsyncIterator[SlayerQueryEngine]:
+    d = str(tmp_path)
+    db_path = os.path.join(d, "t.db")

Then drop the now-unused tempfile import.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_dev1713_naming.py` around lines 63 - 66, Update the async engine
fixture to accept pytest’s tmp_path fixture and build the database path from it
instead of calling tempfile.mkdtemp(). Remove the now-unused tempfile import
while preserving the existing per-test database setup.

486-508: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Move the imports to module scope, and prefer a behavioral assertion over source-text inspection.

Two points:

  1. The inspect and module imports sit inside the test bodies. The coding guidelines require imports at the top of files. SlayerQueryEngine is already imported at line 42, so the local re-import is redundant.
  2. assert "flat_name(" in src couples the test to source text. A refactor that keeps the delegation but renames the call site or wraps it in a helper breaks the test, while a body that inlines .replace('.', '__') and also mentions flat_name in a comment still passes. If the goal is single ownership of flattening, patching flat_name and asserting that the flattener calls it gives the same guarantee without the text dependency.
♻️ Proposed change for the import placement
+import inspect
+
 ...
-from slayer.engine.query_engine import SlayerQueryEngine
+from slayer.engine.enrichment import enrich_query
+from slayer.engine.query_engine import SlayerQueryEngine
     def test_query_as_model_delegates_to_flat_name(self) -> None:
-        import inspect
-
-        from slayer.engine.query_engine import SlayerQueryEngine
-
         src = inspect.getsource(SlayerQueryEngine._query_as_model)
         assert "flat_name(" in src, "expected _query_as_model to call flat_name()"
 
     def test_enrich_query_delegates_to_flat_name(self) -> None:
-        import inspect
-
-        from slayer.engine.enrichment import enrich_query
-
         src = inspect.getsource(enrich_query)
         assert "flat_name(" in src, "expected enrich_query to call flat_name()"

Note that both flatteners are closures, so a patch-based assertion needs the patch target in the defining module namespace. Confirm the import style at each definition site before you switch approach.

As per coding guidelines: "Use keyword arguments for functions with more than one parameter, and keep imports at the top of files."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_dev1713_naming.py` around lines 486 - 508, Move inspect and module
imports to module scope, removing the redundant local SlayerQueryEngine import
already available at file scope. Replace source-text checks in
TestLegacyFlattenerDelegation with behavioral tests that patch flat_name in each
defining module namespace and assert both closure flatteners invoke it,
preserving the single-owner flattening guarantee; follow the existing import
style and use keyword arguments for multi-parameter calls.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@slayer/engine/stage_planner.py`:
- Around line 1084-1110: Extract the shared saved-measure lookup from
_saved_model_measure_type and _bare_saved_measure_name into a helper that
validates ModelScope, accepts only bare identifiers, and returns the matched
ModelMeasure or None. Update both callers to use this helper, then read .type in
_saved_model_measure_type and .name in _bare_saved_measure_name while preserving
their existing fallback behavior.

In `@tests/_engine_helpers.py`:
- Around line 33-49: Consolidate the duplicate _assert_valid_sql helpers by
keeping tests/_engine_helpers.py#L33-L49 as the canonical implementation,
including parsing, statement-count validation, nested-WITH checking, and
TypeError-to-AssertionError handling. Remove the local definitions from
tests/dialects/conftest.py#L31-L45 and tests/test_sql_generator.py#L179-L196,
and import and reuse the canonical helper in both files.

In `@tests/test_dev1713_naming.py`:
- Around line 63-66: Update the async engine fixture to accept pytest’s tmp_path
fixture and build the database path from it instead of calling
tempfile.mkdtemp(). Remove the now-unused tempfile import while preserving the
existing per-test database setup.
- Around line 486-508: Move inspect and module imports to module scope, removing
the redundant local SlayerQueryEngine import already available at file scope.
Replace source-text checks in TestLegacyFlattenerDelegation with behavioral
tests that patch flat_name in each defining module namespace and assert both
closure flatteners invoke it, preserving the single-owner flattening guarantee;
follow the existing import style and use keyword arguments for multi-parameter
calls.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: bec582b5-656b-42d1-b03e-4db2a1196e5c

📥 Commits

Reviewing files that changed from the base of the PR and between 31f9aae and 9f6b326.

📒 Files selected for processing (23)
  • DECISIONS.md
  • slayer/engine/enrichment.py
  • slayer/engine/query_engine.py
  • slayer/engine/response_meta.py
  • slayer/engine/stage_planner.py
  • slayer/sql/dialects/_alias_mangle.py
  • slayer/sql/dialects/bigquery.py
  • slayer/sql/dialects/tsql.py
  • slayer/sql/generator.py
  • slayer/sql/naming.py
  • slayer/sql/scope_check.py
  • slayer/sql/stage_wrapper.py
  • tests/_engine_helpers.py
  • tests/dialects/conftest.py
  • tests/dialects/test__alias_mangle.py
  • tests/integration/test_notebooks.py
  • tests/parity_xfails.py
  • tests/test_dev1713_naming.py
  • tests/test_dev1726_cte_case_folding.py
  • tests/test_naming.py
  • tests/test_projection_trim.py
  • tests/test_scope_check.py
  • tests/test_sql_generator.py
💤 Files with no reviewable changes (4)
  • tests/test_projection_trim.py
  • tests/parity_xfails.py
  • tests/integration/test_notebooks.py
  • slayer/sql/dialects/_alias_mangle.py

ZmeiGorynych and others added 2 commits August 3, 2026 15:36
- S9073: split the composite belt-message assertion into two asserts.
- S7632: the time_shift emitter's suppression comment ended with the
  literal word NOSONAR, which Sonar parsed as a second malformed
  suppression tag — reworded to "sibling emitters' suppressions".
- S3776: _emit_consecutive_periods_ctes_for_planned gains the same
  cohesive-emitter suppression its siblings carry (per the documented
  sibling-emitter rationale), instead of a scattering refactor.
- CodeRabbit nitpick: the three identical _assert_valid_sql copies
  consolidate onto tests/_engine_helpers.py; tests/dialects/conftest.py
  and tests/test_sql_generator.py now import it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…oach-expressions-crossing-joins-on-the' into egor/dev-1726-dialect-aware-case-folding-for-cte-name-collision-detection

# Conflicts:
#	DECISIONS.md

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@DECISIONS.md`:
- Line 80: Update the DECISIONS.md entry so the compound modifier reads
“crossing-derived column” instead of “crossing derived column,” preserving the
surrounding wording and meaning.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6a089baf-9c63-42d2-b93a-80aacab497e7

📥 Commits

Reviewing files that changed from the base of the PR and between f66b9a8 and 5b489bb.

📒 Files selected for processing (4)
  • DECISIONS.md
  • slayer/engine/stage_planner.py
  • slayer/sql/generator.py
  • tests/test_sql_generator.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • slayer/engine/stage_planner.py
  • tests/test_sql_generator.py
  • slayer/sql/generator.py

Comment thread DECISIONS.md Outdated
…oach-expressions-crossing-joins-on-the' into egor/dev-1726-dialect-aware-case-folding-for-cte-name-collision-detection

# Conflicts:
#	DECISIONS.md
#	slayer/sql/generator.py
#	tests/test_dev1713_naming.py

@coderabbitai coderabbitai Bot left a comment

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.

🧹 Nitpick comments (1)
slayer/sql/generator.py (1)

5771-5779: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Share the generation-wide allocator here for consistency.

placeholder_allocator = self._new_allocator() builds a standalone allocator instead of reusing self._gen_allocator. Every other comparable call site in this diff (lines 4215, 5107, 6801, 8596) uses self._gen_allocator or self._new_allocator() to keep _val_<n> materialisation names unique across the whole generation (DEV-1708 Law 2).

_render_with_cross_model_plans is reachable only from generate_from_planned, which always sets self._gen_allocator before this code runs. Today this is not a live bug: _resolve_where_filter_joins_via_scope calls scope.resolve(...) without a consumer argument, so _materialize/allocate_val never fires through placeholder_scope. But the standalone allocator breaks the single-allocator invariant this PR establishes. If a future change routes a materializing resolve(..., consumer=...) call through this scope, its _val_<n> counter would restart from _val_0 and could collide with names minted by the shared self._gen_allocator elsewhere in the same generation.

Change this to self._gen_allocator or self._new_allocator() to match the pattern used at the other four sites.

♻️ Proposed fix
-                placeholder_allocator = self._new_allocator()
+                placeholder_allocator = self._gen_allocator or self._new_allocator()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@slayer/sql/generator.py` around lines 5771 - 5779, Update the allocator
initialization in _render_with_cross_model_plans to use self._gen_allocator when
available, falling back to self._new_allocator() otherwise. Keep the existing
placeholder_scope construction unchanged and preserve the shared generation-wide
allocator invariant.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@slayer/sql/generator.py`:
- Around line 5771-5779: Update the allocator initialization in
_render_with_cross_model_plans to use self._gen_allocator when available,
falling back to self._new_allocator() otherwise. Keep the existing
placeholder_scope construction unchanged and preserve the shared generation-wide
allocator invariant.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 19212933-0f31-42ca-a842-bc4f8d4adfce

📥 Commits

Reviewing files that changed from the base of the PR and between 5b489bb and e826484.

📒 Files selected for processing (4)
  • DECISIONS.md
  • slayer/sql/generator.py
  • tests/test_dev1713_naming.py
  • tests/test_sql_generator.py
💤 Files with no reviewable changes (1)
  • tests/test_sql_generator.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/test_dev1713_naming.py

…der site

CodeRabbit: placeholder_allocator now uses the `self._gen_allocator or
self._new_allocator()` form like the other four comparable sites, so a
future materializing resolve through the placeholder scope cannot
restart the _val_<n> counter and collide with names minted elsewhere
in the same generation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Aug 3, 2026

Copy link
Copy Markdown

@ZmeiGorynych
ZmeiGorynych merged commit 385d377 into egor/dev-1703-comprehensive-approach-expressions-crossing-joins-on-the Aug 3, 2026
6 checks passed
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