#270: comment-bearing / CTE-reprojected / cross-dialect count-scalar prune gaps (plan) - #272
Conversation
…TE-reprojected / cross-dialect)
📝 WalkthroughWalkthroughManifest-ingested ChangesManifest custom SQL pruning
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
Comment |
There was a problem hiding this comment.
Pull request overview
This PR closes the remaining #270 follow-up gaps from #267’s Quality Gate by making manifest-ingested compiled SQL more robust across comments, dialect parsing, and scalar/CTE edge cases, while preserving the existing adapter/engine contracts (no new enums/flags/audit schema changes).
Changes:
- Strip
--//* */comments in the prune compiler forfrom_manifestcustom SQL (including verified sample rewrites) so execution-time strict validation can succeed and audit records reflect what actually ran. - Add compiler-side live-dialect parse refusal (
parses_under_dialect) and threadadapter.dialect().nameinto manifest ingest to eliminate ingest/compile dialect drift. - Extend
is_row_returningto detect provably one-row CTE/derived-table re-projections of collapsing aggregates (depth-capped, conservative bailouts), and adjust count-scalar compose to prevent trailing-comment suffix swallowing.
Reviewed changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
src/signalforge/prune/compiler.py |
Strips comments for manifest-ingested custom SQL, refuses bodies unparseable under the live dialect, and hardens count-scalar compose with newlines. |
src/signalforge/ingest/_compiled_sql.py |
Exposes strip_sql_comments, adds parses_under_dialect, and implements conservative CTE/derived-table one-row detection via build_scope. |
src/signalforge/cli/prune_existing.py |
Builds an un-entered adapter earlier to thread the live dialect into read_manifest_tests, reusing the same adapter instance for pruning. |
tests/prune/test_engine.py |
Asserts audit + in-memory compiled_sql record the stripped bytes for comment-bearing manifest bodies. |
tests/prune/test_compiler.py |
Pins comment stripping, dialect refusal ordering, and the count-scalar newline compose behavior. |
tests/prune/test_compiler_fakesnow.py |
Adds Snowflake-specific pin for live-dialect parse refusal behavior. |
tests/prune/test_compiler_databricks.py |
Adds Databricks-specific pin for live-dialect parse refusal behavior. |
tests/ingest/test_manifest_tests.py |
Verifies CTE-reprojected count scalars are skip-recorded (existing skip reason). |
tests/ingest/test_compiled_sql.py |
Adds a broad must-fire/must-not-fire matrix for the CTE one-row classifier; tests parses_under_dialect + strip_sql_comments. |
tests/cli/test_prune_existing.py |
Validates live-dialect threading into ingest and ensures adapter is entered exactly once and is the same instance passed to pruning. |
tests/cli/test_e2e_bigquery_ingested_sample.py |
Adds gated live BigQuery e2e certs for comment-bearing execution and count-scalar restructure execution. |
plans/super/270-count-scalar-prune-gaps.md |
Adds/updates the detailed plan and decisions for #270 implementation and testing. |
docs/prune-ops.md |
Documents comment-bearing execution and live-dialect refusal behavior. |
docs/ingest-ops.md |
Documents CTE-reprojected count handling, live dialect threading, and tests-dir count semantics. |
CHANGELOG.md |
Records the user-visible behavior changes introduced by #270. |
.claude/rules/*.md |
Updates repository rules/memory to reflect #270’s landed behavior and constraints. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 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 @.claude/rules/ingest-layer.md:
- Line 141: Fix the invalid Markdown paragraph starts by rewording the
issue-reference sentences: in .claude/rules/ingest-layer.md lines 141-141 and
.claude/rules/prune-engine.md lines 272-272, prefix the sentence with “Issue” so
it begins “Issue `#270` closed...”; in docs/prune-ops.md lines 355-356, keep the
sentence as a normal paragraph, such as “Before `#270`, the story above stopped at
ingest...”.
In `@src/signalforge/ingest/_compiled_sql.py`:
- Around line 289-306: Update _scope_produces_exactly_one_row to reject
row-generating projection and lateral-view shapes before recursing into child
scopes. Detect generator expressions such as explode(...) and LATERAL VIEW
constructs, return False for those cases, and preserve the existing reducer,
join, source, pivot, sample, and recursive checks.
In `@tests/cli/test_e2e_bigquery_ingested_sample.py`:
- Around line 467-550: Update the injected test setup and verdict assertions in
the scenario using always_pass_ids and the corresponding later test block:
capture the unique ID returned for every injected candidate, index prune
decisions by test_anchor, and assert each candidate’s exact expected decision,
reason, and failure count instead of aggregate >= 1 checks. Preserve the
existing comment-stripping and clean-exit assertions while validating the
always-pass candidates as dropped with zero failures and the engineered
violation as kept with at least one failure.
In `@tests/cli/test_prune_existing.py`:
- Around line 1521-1528: Extend the assertions in the test covering the wired
unknown dialect so every test entry’s explanation includes the live-dialect
parse-refusal text. Keep the existing test_entries, tier, and flagged_count
assertions, and use the explanation field from each entry to verify the compiler
gate specifically caused the kept-uncertain result.
- Around line 1417-1466: The test’s factory currently records only the most
recently created adapter, so duplicate constructions can go undetected. Update
the factory and assertions around _make_warehouse_adapter to retain every
BigQueryAdapter instance, then assert exactly one was created while preserving
the existing identity and single-enter checks.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: b2ccb51f-72fd-4103-be0a-9f656100f516
📒 Files selected for processing (19)
.claude/rules/business-rule-tests.md.claude/rules/ingest-layer.md.claude/rules/prune-engine.md.claude/rules/warehouse-adapters.mdCHANGELOG.mddocs/ingest-ops.mddocs/prune-ops.mdplans/super/270-count-scalar-prune-gaps.mdsrc/signalforge/cli/prune_existing.pysrc/signalforge/ingest/_compiled_sql.pysrc/signalforge/prune/compiler.pytests/cli/test_e2e_bigquery_ingested_sample.pytests/cli/test_prune_existing.pytests/ingest/test_compiled_sql.pytests/ingest/test_manifest_tests.pytests/prune/test_compiler.pytests/prune/test_compiler_databricks.pytests/prune/test_compiler_fakesnow.pytests/prune/test_engine.py
- Guard the CTE one-row classifier against row-generating projections (explode/posexplode/inline/unnest) and LATERAL VIEW before recursing (+2 tests). - Assert each engineered e2e candidate's exact verdict by its body predicate (the merge-gate tests) instead of >=1 aggregate checks; re-certified live. - no-double-enter test: track all adapter constructions, assert len==1. - dialect-refusal test: assert the parse-refusal reason text, not only the tier. - Fix MD018 (#270 line-starts) in 3 markdown files.
PR Review Summary (CodeRabbit)All 5 comments were real issues — fixed inline (no false positives, no deferrals). Fixes in Fixed (5 items)
False Positives (0 items)Invariants re-verified after the fixes: #268 fixtures byte-unchanged ( |
Summary
Super plan for #270 — the four follow-up gaps from #267's Quality Gate in the prune-dbt-compiled-tests path.
Phase: detailing (awaiting approval)
Base:
dev(atf0bb1a6, after #154 / #267 / #268)Stories: 6 implementation + Quality Gate + Patterns & Memory
Decisions: 6 (DEC-001…006)
What the plan resolves
--comment eats the closingWHERE(masked today only by the adapter's--reject; unmasked by fixing G3).kept-without-evidence(correctness); CLI threads the liveadapter.dialect().nameinto ingest (signal).is_row_returningbranch skip-records provable one-row bodies, bailing conservatively to row-returning on any filter/join so dbt-expectations'validation_errorsshell (which always has aWHERE) is never misclassified.--tests-dirasymmetry) — documented as deliberate;from_manifest=Falsehand-authored tests keep dbt semantics.Standing locks held
No new
DropReason(5),SkipReason(3), error class, CLI flag, orCandidateTestvariant; sqlglot importers stay 2; audit schema stays 4; live BigQuery e2e is the merge gate.Plan document
See
plans/super/270-count-scalar-prune-gaps.md.Next steps
🤖 Generated with Claude Code
https://claude.ai/code/session_01N21jLMPyeo31JDtmXgkDQ7
Summary by CodeRabbit
Bug Fixes
prune-existingnow consistently uses the active warehouse dialect throughout processing.Documentation