fix(gate): match DDL by statement shape, not keyword adjacency#178
Merged
Conversation
The test-presence gate flagged Site#3539 — a pure MCP tool rename — because its DDL pattern matched the words "CREATE INDEX" inside a tool-description string literal. Stripping string literals is not an option (raw SQL lives in strings), so the DDL patterns now require statement grammar instead: an ON clause for CREATE INDEX, a column list for CREATE TABLE, AS for views, and a target identifier for ALTER/DROP. Prose mentioning DDL keywords no longer reads as a query; real DDL statements still do. Verified against Site#3539's actual GitHub patch data: the gate previously classified packages/mcp-server/src/tools/index.ts as changed data-access and emitted the untested-data-access verdict; with this change it returns null. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Query Doctor Analysis
3 queries analyzed
0 regressed · 0 improved · 0 new · 0 removed
2 pre-existing issues
SELECT "guests"."id", "guests"."session_id", "guests"."username", "guests"."avatar_path", "guests"."color", "guests"."side", "guests"."audio_recording_path", "guests"."audio_recording_public", "gue...
indexassets(event_id, inserted_at desc)
cost 31,003,449 → 1,498 (100% reduction)SELECT * FROM guest_ip_addresses WHERE ip_address = '127.0.0.1';
indexguest_ip_addresses(ip_address)
cost 154,402 → 8 (100% reduction)
Using assumed statistics (10000000 rows/table). For better results, sync production stats.
More detail → get_ci_run({ runId: "019f6205-7d9d-7583-9da1-cf0c2ae91ee8" }) · view run · docs
Member
Author
|
Regression sweep: replayed the gate (old pattern vs this PR) over the last 40 Site PRs (#3512–#3570, 261 changed files, real |
Shape-by-shape recall table for the DDL rewrite: every variant the old adjacency pattern caught still detects, plus two it missed (CREATE UNIQUE INDEX CONCURRENTLY, CREATE OR REPLACE VIEW — a word between the keywords broke adjacency). Multi-line DDL registers via the query-call shapes; CREATE TABLE AS SELECT via the select shape. The one accepted miss — a bare multi-line DDL string with no query call — is pinned as a deliberate under-fire trade-off so changing it is a decision, not an accident. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Goal
The test-presence gate should only flag PRs that actually change query code. Site#3539 — a pure MCP tool rename with zero SQL changes — got the "changes queries with no related data-layer test" warning. This PR removes that class of false positive. It is the whole fix; no follow-up step.
What
Before: any added diff line containing
CREATE INDEX/ALTER TABLE/ etc. as adjacent words classified the file as changed data-access code — including prose inside a string literal (Site#3539's tool description says "its suggested CREATE INDEX fix"). After: prose mentioning DDL keywords no longer trips the gate; real DDL statements still do.How
src/gate/test-presence.ts: the single keyword-adjacency DDL pattern becomes five statement-shaped ones —CREATE [UNIQUE] INDEX … ON,CREATE TABLE … (,CREATE [OR REPLACE] [MATERIALIZED] VIEW … AS,ALTER TABLE <ident>,DROP TABLE/INDEX/VIEW <ident>. The discriminator is the statement's own grammar (ON clause, column list, target identifier), because the alternative — stripping string literals before matching — would blind the raw-SQL patterns whose whole job is catching SQL in strings.Verified end-to-end against Site#3539's actual GitHub patch data (
pulls/3539/files): the old gate classifiespackages/mcp-server/src/tools/index.tsas data-access and emits theuntested-data-accessverdict; the patched gate returnsnull. Also confirmed against prod that the capture override could never have suppressed this flag (the run captured 0 new hashes vs its staging baseline — a rename adds no query surface), so the content heuristic is the only place this false positive can die.Known limit, unchanged by this PR: a string literal containing a full
SELECT … FROMsentence can still trip the select pattern. That shape is indistinguishable from a real raw-SQL query at the diff level; the capture-based rungs (#3502/#3503) are the durable answer there.Tests
src/gate/test-presence.test.ts: prose-with-DDL-keywords string literal → not query code (the Site#3539 line, verbatim); statement-shapedCREATE INDEX/CREATE TABLE/ALTER TABLE/DROP TABLE→ still detected; a replay of Site#3539's file set (description-string edit + two spec files + 0 new hashes) → verdict null. Existing migration/DDL-in-source tests unchanged and passing. Full suite: 302 tests / 29 files green;tsc --noEmitclean.🤖 Generated with Claude Code