Skip to content

Fix T-SQL bracket-quoted identifiers producing mangled labels - #2723

Open
ayushcodes10 wants to merge 13 commits into
Graphify-Labs:v8from
ayushcodes10:fix-2712-tsql-bracket-labels
Open

Fix T-SQL bracket-quoted identifiers producing mangled labels#2723
ayushcodes10 wants to merge 13 commits into
Graphify-Labs:v8from
ayushcodes10:fix-2712-tsql-bracket-labels

Conversation

@ayushcodes10

Copy link
Copy Markdown
Contributor

tree-sitter-sql has no grammar token for T-SQL [bracket] quoting: each bracket lands as its own ERROR node, one byte short of the real pair, so [dbo].[Alpha] reads back as the label dbo].[Alpha instead of dbo.Alpha. Rewrite bracket-quoted identifiers to backtick-quoted ones before parsing (a form the grammar already handles cleanly), then strip the synthetic backticks back out for display. Guards against misfiring on Postgres/MySQL array-type syntax (text[], numeric(10)[3]).

Fixes #2712.

@graphify-labs graphify-labs 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.

Graphify reviewed this change.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).

Formal verification. No changes could be formally verified in this run.


Graphify review — findings

This PR adds T-SQL bracket-identifier handling to the SQL extractor in graphify/extractors/sql.py. It introduces two helpers — _debracket_tsql, which rewrites [bracket]-quoted identifiers into backtick-quoted ones before parsing (skipping strings/comments and array-type syntax), and _strip_backtick_parts, which strips that synthetic quoting back out for display labels — plus wiring in extract_sql (a debracketed flag, _clean_name/_ident wrappers) so object references and names are read through the cleaning path. The extractor is only debracketed when the source contains no existing backtick. The test file tests/test_multilang.py adds several new SQL tests covering clean bracket labels, foreign-key reference resolution by clean name, and array-type non-corruption. The changed-symbols list also references many other multilang tests (Go, Rust, TS) and rationale entries, though the shown diff centers on SQL extraction and its new tests.

No blocking issues surfaced. 5 lower-confidence candidates did not survive cross-model review.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 269 functions depend on the 115 functions this change touches.

Health — this change adds coupling hotspots:

  • worse: extract_sql() — 12 callers, 9 callees
  • worse: walk() — 1 callers, 9 callees

Verification — 269 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 126 function(s) in the blast radius were not formally verified this run

Formal verification

Could not verify: Could not verify extract\_sql.

The verifier did not have enough to check extract\_sql, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set

· 1 grounded finding(s) anchored inline below; 1 more finding(s) on lines outside this diff (see the check run).

Comment thread graphify/extractors/sql.py
@ayushcodes10

Copy link
Copy Markdown
Contributor Author

@safishamsi this PR's CI run is waiting on approval (first-time contributor gate) — could you approve the workflow run when you get a chance? Happy to address any review feedback in the meantime.

tree_sitter_sql has no grammar rule for a bracket delimited identifier,
so [dbo].[Orders] lands in ERROR nodes and comes out with a mangled
label like dbo].[Orders instead of dbo.Orders. Backtick quoting
already parses cleanly, so the source is rewritten before parsing and
the synthetic backticks are stripped again for display.

Upstream has since landed its own ERROR recovery for routine names
(CREATE FUNCTION/PROCEDURE), matched by a shared regex plus a masked
whole file scan. Since this rewrite runs before that scan, a
bracketed routine name never reaches it as a bracket anymore, only as
a backtick, so the shared regex and its masking scan are extended to
also recognize backtick delimited names. Without that a bracketed
routine would go from a recovered (if ugly) node to no node at all,
a regression this change must not introduce.

Guards against misfiring on array type and array literal syntax that
also uses square brackets (int[], numeric(10)[3], ARRAY[1,2,3]), and
against a bracket span that swallows a comment marker.

Fixes Graphify-Labs#2712.
@ayushcodes10
ayushcodes10 force-pushed the fix-2712-tsql-bracket-labels branch from 0c8b40e to f821303 Compare September 5, 2026 23:32
@ayushcodes10

Copy link
Copy Markdown
Contributor Author

Rebased onto current v8. Upstream landed its own TSQL routine recovery (#3164) in the meantime, which shares the same ERROR node masked scan approach this PR relies on for the bracket rewrite to stay compatible. Reworked the debracketing so it composes with that instead of duplicating it: the shared routine recovery regex and its masking scan now also recognize the backtick form a bracketed name becomes once rewritten, so a bracketed routine keeps recovering (this PR's job is the clean label, not the recovery itself). Verified against the original #2712 repro plus the full existing TSQL test suite, all green.

@graphify-labs graphify-labs 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.

Graphify reviewed this change.

Worth a look — the grounded gate found no coupling regressions or blocking issues, but 1 advisory finding(s) below merit a look before merge.

Formal verification. 1 change(s) alter behavior, breaking input(s) attached.

Behavior changes: \_scan\_sql changes behavior, here is the input that shows it.

The verifier found a concrete input on which \_scan\_sql behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"text":"''"\}, the old code produced \('', \[\]\) but the new code produces \(' ', \[\]\). Paste that input straight into a regression test.


Graphify review — findings

Rewrites T-SQL bracket-quoted identifiers ([dbo].[Orders]) to backtick-quoted form via _debracket_tsql before parsing, so extract_sql gets a clean AST through the grammar's existing MySQL-dialect path instead of dropping the statement into error recovery — fixing mangled labels and tables lost behind broken foreign keys. _clean_name/_strip_backtick_parts undo the rewrite for display labels and recovered names, but only when the file was actually debracketed, leaving genuine MySQL backtick names alone. Bracket spans that read as array markers (int[], ARRAY[1,2,3]), are empty, purely numeric, or contain a comment opener are left untouched, and both _scan_sql and the _ROUTINE_RECOVERY_RX recovery scan now accept backtick-delimited identifiers so a bracketed routine name still recovers to a node in an error-bearing file.

Worth a look

  • Bracket-quoted T-SQL routine labels and IDs changed in extract_sql outputgraphify/extractors/sql.py:829 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 339 functions depend on the 159 functions this change touches.

Health — this change adds coupling hotspots:

  • new: extract_sql() — 24 callers, 11 callees
  • new: dispatch_command() — 2 callers, 124 callees
  • new: walk() — 1 callers, 9 callees
  • new: test_poisoned_manifest_is_healed() — 0 callers, 6 callees

Verification — 339 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 171 function(s) in the blast radius were not formally verified this run

Formal verification

Behavior changes: \_scan\_sql changes behavior, here is the input that shows it.

The verifier found a concrete input on which \_scan\_sql behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"text":"''"\}, the old code produced \('', \[\]\) but the new code produces \(' ', \[\]\). Paste that input straight into a regression test.

Could not verify: Could not verify extract\_sql.

The verifier did not have enough to check extract\_sql, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set

· 1 grounded finding(s) anchored inline below; 3 more finding(s) on lines outside this diff (see the check run).

return ".".join(parts)


def extract_sql(path: Path, content: str | bytes | None = None) -> dict:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Health regressionextract_sql()

fans out to 11 callees (efferent coupling); 24 callers depend on it (afferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

@ayushcodes10

Copy link
Copy Markdown
Contributor Author

@safishamsi rebased onto the latest v8 and all checks are green now — ready for review whenever you get a chance.

_clean_name gated on a single file wide debracketed flag, so once ANY
bracket span in a file got rewritten to backtick form, every
backtick-quoted name in that same file had its backticks stripped for
display, including a genuinely backtick-quoted MySQL name completely
unrelated to the T-SQL bracket span that triggered the rewrite.

_debracket_tsql now returns the byte range spans it actually rewrote,
in the rewritten source's own coordinates, and _clean_name only
un-rewrites a name whose own byte range overlaps one of those spans.
A name read off a tree-sitter node carries its own start/end byte
naturally; the whole file regex fallback has no node, so its
character offsets into the decoded source are converted to byte
offsets first, since the decoded string and the byte-level spans can
diverge once the file contains any multi byte character.

Fixes Graphify-Labs#2721.
@ayushcodes10

Copy link
Copy Markdown
Contributor Author

Investigated the bot's findings and fixed a real one: _clean_name (used to un-rewrite a debracketed name for display) was gated on a single file wide flag, so once ANY bracket span in a file got rewritten, every backtick-quoted name in that same file had its backticks stripped, including a genuinely backtick-quoted MySQL name completely unrelated to the T-SQL bracket span that triggered the rewrite. Reworked it to track the actual byte range spans _debracket_tsql rewrote and only un-rewrite a name that overlaps one of them, verified against a mixed T-SQL bracket plus genuine MySQL backtick file (now keeps both correctly).

Also checked the other two lower confidence findings on this PR:

  • Numeric bracket quoted identifiers not being debracketed: real but narrow, the numeric content check is what correctly excludes nested array literal elements like ARRAY[[1],[2]] (which the preceding character check alone would miss), at the cost of a genuinely numeric-only T-SQL identifier (exceedingly rare, goes against essentially every naming convention). Leaving as a documented trade off rather than risk a more complex heuristic for an unconfirmed real world case.
  • The reproduced _scan_sql behavior change claim: ran the exact reported input against unmodified upstream and got the identical output on both sides, so this does not correspond to an actual regression, looks like a verifier artifact.

@graphify-labs graphify-labs 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.

Graphify reviewed this change.

Worth a look — the grounded gate found no coupling regressions or blocking issues, but 2 advisory finding(s) below merit a look before merge.

Formal verification. 1 change(s) alter behavior, breaking input(s) attached.

Behavior changes: \_scan\_sql changes behavior, here is the input that shows it.

The verifier found a concrete input on which \_scan\_sql behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"text":"''"\}, the old code produced \('', \[\]\) but the new code produces \(' ', \[\]\). Paste that input straight into a regression test.


Graphify review — findings

Adds a source-rewriting pass to the SQL extractor that converts T-SQL bracket-quoted identifiers ([dbo].[Orders]) into backtick-quoted ones before parsing, so tree_sitter_sql takes its normal AST path instead of dropping whole statements into ERROR recovery — fixing mangled labels and tables lost behind broken foreign keys. _debracket_tsql rewrites only bracket spans that read as identifiers (leaving array markers like int[], empty/numeric content, and comment-bearing spans alone) and records the inserted spans, and _clean_name un-rewrites a name only when its byte range overlaps one of those spans, so a genuine MySQL backtick identifier elsewhere in the same file keeps its backticks. Also extends routine-recovery scanning and _scan_sql to recognize backtick-delimited identifiers, so a bracket-named CREATE PROCEDURE in an error-bearing file still recovers a node rather than vanishing.

Worth a look

  • Debracketing rewrites bracket identifiers inside dollar-quoted PL/pgSQL bodiesgraphify/extractors/sql.py · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
  • Regex table recovery skips debracketed T-SQL identifiersgraphify/extractors/sql.py:820 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 343 functions depend on the 163 functions this change touches.

Health — this change adds coupling hotspots:

  • new: extract_sql() — 25 callers, 11 callees
  • new: dispatch_command() — 2 callers, 124 callees
  • new: walk() — 1 callers, 9 callees
  • new: test_poisoned_manifest_is_healed() — 0 callers, 6 callees

Verification — 343 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 175 function(s) in the blast radius were not formally verified this run

Formal verification

Behavior changes: \_scan\_sql changes behavior, here is the input that shows it.

The verifier found a concrete input on which \_scan\_sql behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"text":"''"\}, the old code produced \('', \[\]\) but the new code produces \(' ', \[\]\). Paste that input straight into a regression test.

Could not verify: Could not verify extract\_sql.

The verifier did not have enough to check extract\_sql, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set

· 1 grounded finding(s) anchored inline below; 3 more finding(s) on lines outside this diff (see the check run).

return ".".join(parts)


def extract_sql(path: Path, content: str | bytes | None = None) -> dict:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Health regressionextract_sql()

fans out to 11 callees (efferent coupling); 25 callers depend on it (afferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Exclude two cases the grammar or the scanner cannot handle safely: a
bracket span containing a literal dot, which tree_sitter_sql still
splits on even inside a backtick pair, and single/double quoted
string content past its first line, which the scanner used to treat
as ordinary source once it hit a newline before finding the real
closing quote.
@ayushcodes10

Copy link
Copy Markdown
Contributor Author

Investigated the latest bot findings on this PR (matching 38259c8).

Confirmed real, fixed in d8e6939:

  1. A bracket span whose content contains a literal dot (e.g. [My.Table]) came out corrupted after rewriting to backtick form. Root cause is in tree_sitter_sql's own grammar, not this Python code: dumping the AST for the rewritten source shows the grammar splits My.Table into My (a malformed identifier with an empty closing backtick child), a bare . qualifier token, Table, and a dangling stray backtick landing in its own ERROR node. No amount of escaping on this end can round trip that. Fix: _debracket_tsql now refuses to rewrite a bracket span whose content holds a dot, leaving it as plain, un-rewritten bracket text (the same fallback behavior that existed before this PR).

  2. _debracket_tsql's single and double quote scanning stopped at the first newline unconditionally, even when the string was not actually closed there. That meant a still-open multi-line string (dynamic SQL split across lines, say) had its later lines scanned as ordinary source, so bracket-like content on a later line got mistaken for a real identifier and rewritten, corrupting the string. Confirmed empirically: _debracket_tsql(b"SET @sql = 'first line\n[NotAnIdentifier] second line';\n") rewrote the bracket inside the still-open string. Fix: the scan now follows a quoted string to its real closing quote across newlines, matching how the engines actually read one. A string that genuinely never closes just consumes the rest of the file this way, which only means nothing past it gets debracketed, same as before this PR existed.

Both fixes have regression tests and are propagated through the whole stack (#2723/#2722/#2721/#2724).

Already covered by an earlier comment on this PR: the "numeric bracket identifiers not debracketed" finding (accepted, documented trade off) and the reproduced _scan_sql behavior claim (verified as a tooling artifact against unmodified upstream).

A dollar quoted span ($$ ... $$ or $tag$ ... $tag$) is opaque body
text, not SQL, so bracket like content inside it was being mistaken
for a real bracket identifier and rewritten. Skip the whole span
instead, the same way a string or comment already is.

@graphify-labs graphify-labs 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.

Graphify reviewed this change.

Worth a look — the grounded gate found no coupling regressions or blocking issues, but 2 advisory finding(s) below merit a look before merge.


Graphify review — findings

Adds T-SQL bracket-quoted identifier support to the SQL extractor by rewriting [dbo].[Orders] into backtick-quoted names via _debracket_tsql before parsing, so statements that previously fell into tree_sitter_sql's error recovery (mangling labels and dropping whole tables behind broken foreign keys) now take the normal AST path. Records the byte spans it rewrote and un-rewrites names only where they overlap those spans (_clean_name/_strip_backtick_parts), so a genuine MySQL backtick name elsewhere in the same file keeps its backticks; bracket spans that read as array markers, contain a dot, embed a comment opener, or are empty/numeric are left un-rewritten as before. Extends _scan_sql and the routine-recovery regex to accept backtick-delimited identifiers so a bracket-named routine in an error-bearing file still recovers to a node instead of vanishing.

Worth a look

  • Existing backtick-quoted identifiers are rewritten when they contain bracketsgraphify/extractors/sql.py:390 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
  • PostgreSQL ARRAY literals with whitespace are rewritten as identifiersgraphify/extractors/sql.py:390 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 347 functions depend on the 167 functions this change touches.

Health — this change adds coupling hotspots:

  • new: extract_sql() — 26 callers, 11 callees
  • new: dispatch_command() — 2 callers, 124 callees
  • new: walk() — 1 callers, 9 callees
  • new: test_poisoned_manifest_is_healed() — 0 callers, 6 callees

Verification — 347 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 179 function(s) in the blast radius were not formally verified this run

· 1 grounded finding(s) anchored inline below; 3 more finding(s) on lines outside this diff (see the check run).

return ".".join(parts)


def extract_sql(path: Path, content: str | bytes | None = None) -> dict:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Health regressionextract_sql()

fans out to 11 callees (efferent coupling); 26 callers depend on it (afferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

@ayushcodes10

Copy link
Copy Markdown
Contributor Author

Follow up on the two remaining findings from the last bot review (matching 38259c8):

Confirmed real, fixed in ab1f115: a PostgreSQL dollar quoted PL/pgSQL body ($$ ... $$ or $tag$ ... $tag$) is opaque body text, not SQL to debracket, but _debracket_tsql had no handling for it at all. Bracket like text anywhere inside such a body (SELECT [NotReallyBracketIdent]; inside a function) was mistaken for a real bracket identifier and rewritten to backtick form, corrupting the body. Confirmed empirically before the fix, both for the untagged $$ and tagged $tag$ forms. Fix: the scan now skips a dollar quoted span whole, the same way it already skips a string or comment. Regression test added for both forms.

Investigated and found to be pre existing, out of scope for this PR: the regex table recovery finding (sql.py around line 820, the Firebird COMPUTED BY fallback at CREATE\s+TABLE\s+([\w$]+)\s*\(). That regex only ever matched a bare unquoted name; it never handled a bracket or backtick quoted one, before or after this stack's changes. Confirmed via git history predating #2712. Not something this PR's debracketing introduced or regressed.

@graphify-labs graphify-labs 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.

Graphify reviewed this change.

Worth a look — the grounded gate found no coupling regressions or blocking issues, but 1 advisory finding(s) below merit a look before merge.

Formal verification. 1 change(s) alter behavior, breaking input(s) attached.

Behavior changes: \_scan\_sql changes behavior, here is the input that shows it.

The verifier found a concrete input on which \_scan\_sql behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"text":"''"\}, the old code produced \('', \[\]\) but the new code produces \(' ', \[\]\). Paste that input straight into a regression test.


Graphify review — findings

Adds T-SQL bracket-identifier support to the SQL extractor: _debracket_tsql rewrites [dbo].[Orders]-style quoted names to backtick-quoted ones before parsing so the grammar takes its normal AST path instead of dropping statements into ERROR recovery (fixing mangled labels and tables lost behind broken foreign keys), while carefully leaving array markers (int[], ARRAY[...]), dotted names it can't round-trip, and content inside strings, comments, and dollar-quoted bodies untouched. Tracks the byte spans it inserted so _strip_backtick_parts un-rewrites only those identifiers for display labels and recovered names, never a genuine MySQL backtick name elsewhere in the file. Extends _scan_sql and the routine-recovery regex to treat backtick-delimited identifiers the same as double-quoted and bracketed ones, so a bracket-named routine in an error-bearing file still recovers a node rather than vanishing.

Worth a look

  • extract_sql changes public node labels/ids for T-SQL bracket identifiersgraphify/extractors/sql.py:506 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 349 functions depend on the 169 functions this change touches.

Health — this change adds coupling hotspots:

  • new: extract_sql() — 26 callers, 11 callees
  • new: dispatch_command() — 2 callers, 124 callees
  • new: walk() — 1 callers, 9 callees
  • new: test_poisoned_manifest_is_healed() — 0 callers, 6 callees

Verification — 349 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 181 function(s) in the blast radius were not formally verified this run

Formal verification

Behavior changes: \_scan\_sql changes behavior, here is the input that shows it.

The verifier found a concrete input on which \_scan\_sql behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"text":"''"\}, the old code produced \('', \[\]\) but the new code produces \(' ', \[\]\). Paste that input straight into a regression test.

Could not verify: Could not verify extract\_sql.

The verifier did not have enough to check extract\_sql, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set

· 1 grounded finding(s) anchored inline below; 3 more finding(s) on lines outside this diff (see the check run).

return ".".join(parts)


def extract_sql(path: Path, content: str | bytes | None = None) -> dict:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Health regressionextract_sql()

fans out to 11 callees (efferent coupling); 26 callers depend on it (afferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

A MySQL backtick quoted identifier had no dedicated scan branch, so
its content was walked like ordinary source. A bracket like
substring inside one read as a real TSQL bracket identifier and got
rewritten in place, producing doubled and orphaned backticks. Skip a
backtick span whole, honoring a doubled backtick as an escaped
literal one the same way this function writes it.
@ayushcodes10

Copy link
Copy Markdown
Contributor Author

Follow up on this round's bot finding (matching aadd5f6):

Confirmed real, fixed: a genuine MySQL backtick-quoted identifier that happens to contain bracket-like text (like `[weird]name`) had no dedicated scan branch in _debracket_tsql at all, so its content was walked character by character like ordinary source. The embedded [weird] read as a real T-SQL bracket identifier and got rewritten right there inside the existing backtick span, producing doubled and orphaned backticks (`[weird]name` -> \`weird\`name\, badly corrupted). Confirmed empirically before the fix. _debracket_tsql now skips a backtick-quoted span whole, the same way it already skips a string, comment, or dollar-quoted body, honoring a doubled backtick inside the span as an escaped literal one. Regression test added, including a doubled-backtick case to confirm the scan doesn't stop early on the escape.

@graphify-labs graphify-labs 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.

Graphify reviewed this change.

Worth a look — the grounded gate found no coupling regressions or blocking issues, but 1 advisory finding(s) below merit a look before merge.

Formal verification. 1 change(s) alter behavior, breaking input(s) attached.

Behavior changes: \_scan\_sql changes behavior, here is the input that shows it.

The verifier found a concrete input on which \_scan\_sql behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"text":"''"\}, the old code produced \('', \[\]\) but the new code produces \(' ', \[\]\). Paste that input straight into a regression test.


Graphify review — findings

Adds T-SQL bracket-quoted identifier support to the SQL extractor by rewriting [dbo].[Orders] to backtick-quoted names before parsing (_debracket_tsql), so statements that previously fell into tree_sitter_sql ERROR recovery — mangling labels and dropping whole tables behind broken foreign keys — now take the normal AST path. The rewrite is span-tracked so a downstream reader un-rewrites only the identifiers that came from a bracket, leaving genuine MySQL backtick names untouched, and skips string/dollar-quoted/comment/backtick regions to avoid corrupting their contents; bracket spans that read as array markers, or that hold a dot, comment opener, or purely numeric content, are left as plain brackets. Extends _scan_sql and the routine-recovery regex to also honor backtick-delimited names so a bracketed CREATE PROCEDURE in an error-bearing file still recovers a node instead of vanishing.

Worth a look

  • Debracketing rewrites valid ARRAY constructors when whitespace precedes '['graphify/extractors/sql.py:419 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 351 functions depend on the 171 functions this change touches.

Health — this change adds coupling hotspots:

  • new: extract_sql() — 26 callers, 11 callees
  • new: dispatch_command() — 2 callers, 124 callees
  • new: walk() — 1 callers, 9 callees
  • new: test_poisoned_manifest_is_healed() — 0 callers, 6 callees

Verification — 351 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 183 function(s) in the blast radius were not formally verified this run

Formal verification

Behavior changes: \_scan\_sql changes behavior, here is the input that shows it.

The verifier found a concrete input on which \_scan\_sql behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"text":"''"\}, the old code produced \('', \[\]\) but the new code produces \(' ', \[\]\). Paste that input straight into a regression test.

Could not verify: Could not verify extract\_sql.

The verifier did not have enough to check extract\_sql, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set

· 1 grounded finding(s) anchored inline below; 3 more finding(s) on lines outside this diff (see the check run).

return ".".join(parts)


def extract_sql(path: Path, content: str | bytes | None = None) -> dict:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Health regressionextract_sql()

fans out to 11 callees (efferent coupling); 26 callers depend on it (afferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

A bracket span containing a literal backtick cannot be represented
by rewriting to backtick form: the grammar treats the first
backtick of the doubled escape this function would write as the
closing delimiter rather than an escape, truncating the identifier
and leaving the rest as a stray ERROR node.

Also stop rewriting a PostgreSQL ARRAY constructor when whitespace
separates the keyword from its bracket (ARRAY [1, 2, 3]). The
preceding character check only looked one character back, which is
a space in that shape rather than the keyword, so the array literal
read as an identifier and got rewritten.
@ayushcodes10

Copy link
Copy Markdown
Contributor Author

Follow up on this round's bot finding (matching d638043):

Confirmed real, fixed: "Debracketing rewrites valid ARRAY constructors when whitespace precedes '['". PostgreSQL allows a space between ARRAY and its bracket constructor (ARRAY [1, 2, 3]); the preceding-character check that tells an array marker apart from a bracket-quoted identifier only looked at the single character right before '[', which in that shape is the space, not the ARRAY keyword. Confirmed empirically before the fix: SELECT ARRAY [1, 2, 3]; was rewritten to SELECT ARRAY `1, 2, 3`;. Fixed by looking back past a run of spaces or tabs for a bare ARRAY word before falling through to the identifier check. Regression test added, including a check that an ordinary whitespace-preceded bracket identifier (the common case) still gets rewritten.

@graphify-labs graphify-labs 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.

Graphify reviewed this change.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).

Formal verification. 1 change(s) alter behavior, breaking input(s) attached.

Behavior changes: \_scan\_sql changes behavior, here is the input that shows it.

The verifier found a concrete input on which \_scan\_sql behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"text":"''"\}, the old code produced \('', \[\]\) but the new code produces \(' ', \[\]\). Paste that input straight into a regression test.


Graphify review — findings

Rewrites T-SQL bracket-quoted identifiers ([dbo].[Orders]) into backtick-quoted ones before parsing via the new _debracket_tsql, so the normal tree_sitter_sql AST path handles them instead of dropping into error recovery that mangled labels and lost tables behind broken foreign keys. Skips rewriting for spans that aren't real identifiers — array markers like int[]/ARRAY[...], empty/numeric content, comment openers, dots or literal backticks the grammar can't round-trip — and steps over string, dollar-quoted, comment, and existing backtick spans so their contents aren't corrupted, falling back to the un-rewritten bracket in every excluded case. Extends _scan_sql and _ROUTINE_RECOVERY_RX to recognize backtick-delimited names too, so a bracket-named routine in an error-bearing file still recovers a node after debracketing.

No blocking issues surfaced. 12 lower-confidence candidates did not survive cross-model review.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 355 functions depend on the 175 functions this change touches.

Health — this change adds coupling hotspots:

  • new: extract_sql() — 26 callers, 11 callees
  • new: dispatch_command() — 2 callers, 124 callees
  • new: walk() — 1 callers, 9 callees
  • new: test_poisoned_manifest_is_healed() — 0 callers, 6 callees

Verification — 355 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 187 function(s) in the blast radius were not formally verified this run

Formal verification

Behavior changes: \_scan\_sql changes behavior, here is the input that shows it.

The verifier found a concrete input on which \_scan\_sql behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"text":"''"\}, the old code produced \('', \[\]\) but the new code produces \(' ', \[\]\). Paste that input straight into a regression test.

Could not verify: Could not verify extract\_sql.

The verifier did not have enough to check extract\_sql, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set

· 1 grounded finding(s) anchored inline below; 3 more finding(s) on lines outside this diff (see the check run).

return ".".join(parts)


def extract_sql(path: Path, content: str | bytes | None = None) -> dict:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Health regressionextract_sql()

fans out to 11 callees (efferent coupling); 26 callers depend on it (afferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

src_text decoded with errors=replace, which collapses every invalid
byte to one U+FFFD that re encodes to 3 bytes, permanently inflating
every offset _clean_regex_name computes past an invalid byte
anywhere earlier in the file. A routine recovered only through the
regex fallback then had its overlap check miss every real debracket
span, so a name debracketing did touch kept its backticks in the
final label. Decode with surrogateescape instead, which round trips
losslessly, and sanitize a name on the way out in case its own
content carried one of those escaped bytes, since a label is not
meant to hold a lone surrogate.
@ayushcodes10

Copy link
Copy Markdown
Contributor Author

The byte-offset fix for invalid UTF-8 bytes described on #2724 (src_text decoding with errors="replace" corrupting _clean_regex_name's offset math, confirmed and fixed with a regression test) lands on this base branch, now at 2df0b46.

@graphify-labs graphify-labs 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.

Graphify reviewed this change.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).

Formal verification. 1 change(s) alter behavior, breaking input(s) attached.

Behavior changes: \_scan\_sql changes behavior, here is the input that shows it.

The verifier found a concrete input on which \_scan\_sql behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"text":"''"\}, the old code produced \('', \[\]\) but the new code produces \(' ', \[\]\). Paste that input straight into a regression test.


Graphify review — findings

Rewrites T-SQL bracket-quoted identifiers ([dbo].[Orders]) into backtick-quoted form before parsing via new _debracket_tsql, so tree_sitter_sql handles them on its normal AST path instead of dropping the surrounding statement into ERROR recovery and mangling labels or losing tables. Only genuine identifier brackets are rewritten — array markers (int[], ARRAY[…]), comment-bearing or dotted/backtick-bearing content, and text inside strings, dollar-quoted bodies, and existing backtick spans are left alone, falling back to plain un-rewritten brackets when a shape can't round-trip. Extends the routine-recovery scan and _scan_sql masking to accept backtick-quoted names too, since a bracketed routine name only survives as a backtick by the time recovery runs.

No blocking issues surfaced. 15 lower-confidence candidates did not survive cross-model review.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 357 functions depend on the 177 functions this change touches.

Health — this change adds coupling hotspots:

  • new: extract_sql() — 27 callers, 11 callees
  • new: dispatch_command() — 2 callers, 124 callees
  • new: walk() — 1 callers, 9 callees
  • new: test_poisoned_manifest_is_healed() — 0 callers, 6 callees

Verification — 357 functions in the blast radius were not formally verified this run (proofs are advisory here).

Health delta baseline: last indexed commit 67f99bd (diverged from this PR's base — delta is approximate).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 189 function(s) in the blast radius were not formally verified this run

Formal verification

Behavior changes: \_scan\_sql changes behavior, here is the input that shows it.

The verifier found a concrete input on which \_scan\_sql behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"text":"''"\}, the old code produced \('', \[\]\) but the new code produces \(' ', \[\]\). Paste that input straight into a regression test.

Could not verify: Could not verify extract\_sql.

The verifier did not have enough to check extract\_sql, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set

· 1 grounded finding(s) anchored inline below; 3 more finding(s) on lines outside this diff (see the check run).

return ".".join(parts)


def extract_sql(path: Path, content: str | bytes | None = None) -> dict:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Health regressionextract_sql()

fans out to 11 callees (efferent coupling); 27 callers depend on it (afferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

The ARRAY keyword lookback only skipped spaces and tabs, so ARRAY
followed by a newline then its bracket (SQL treats all whitespace
between tokens the same way) still read as a bracket quoted
identifier and got rewritten. Skip any whitespace kind, not just
spaces and tabs.
@ayushcodes10

Copy link
Copy Markdown
Contributor Author

Follow up on this round's bot finding (matching b73259a):

Confirmed real, fixed: the ARRAY-keyword lookback added earlier this round only skipped spaces and tabs, so ARRAY followed by a newline then its bracket (SQL treats all whitespace between tokens the same way, so ARRAY\n[1, 2, 3] is just as valid as ARRAY [1, 2, 3]) still read as a bracket-quoted identifier and got rewritten. Reproduced empirically before the fix. Now skips any whitespace kind (space, tab, newline, carriage return), not just spaces and tabs. Regression test added, including a mixed-whitespace case.

@graphify-labs graphify-labs 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.

Graphify reviewed this change.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).

Formal verification. 1 change(s) alter behavior, breaking input(s) attached.

Behavior changes: \_scan\_sql changes behavior, here is the input that shows it.

The verifier found a concrete input on which \_scan\_sql behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"text":"''"\}, the old code produced \('', \[\]\) but the new code produces \(' ', \[\]\). Paste that input straight into a regression test.


Graphify review — findings

Adds T-SQL bracket-quoted identifier support to the SQL extractor via a new _debracket_tsql pre-parse pass that rewrites [dbo].[Orders] into backtick quoting the grammar already understands, so these statements take the normal AST path instead of falling into error recovery that mangled labels and dropped tables. Distinguishes quoted identifiers from array markers (int[], ARRAY[1,2,3]), and leaves brackets un-rewritten when the content is empty, numeric, or holds a ., a backtick, or a comment opener — cases the grammar can't round-trip — while skipping over string, dollar-quoted, backtick, and comment spans so their contents aren't corrupted. Extends _scan_sql and _ROUTINE_RECOVERY_RX to treat backtick-delimited names as recoverable routine names, since a bracketed routine reaches recovery already rewritten to backticks and would otherwise yield no node at all.

No blocking issues surfaced. 12 lower-confidence candidates did not survive cross-model review.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 359 functions depend on the 179 functions this change touches.

Health — this change adds coupling hotspots:

  • new: extract_sql() — 27 callers, 11 callees
  • new: dispatch_command() — 2 callers, 124 callees
  • new: walk() — 1 callers, 9 callees
  • new: test_poisoned_manifest_is_healed() — 0 callers, 6 callees

Verification — 359 functions in the blast radius were not formally verified this run (proofs are advisory here).

Health delta baseline: last indexed commit 67f99bd (diverged from this PR's base — delta is approximate).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 191 function(s) in the blast radius were not formally verified this run

Formal verification

Behavior changes: \_scan\_sql changes behavior, here is the input that shows it.

The verifier found a concrete input on which \_scan\_sql behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"text":"''"\}, the old code produced \('', \[\]\) but the new code produces \(' ', \[\]\). Paste that input straight into a regression test.

Could not verify: Could not verify extract\_sql.

The verifier did not have enough to check extract\_sql, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set

· 1 grounded finding(s) anchored inline below; 3 more finding(s) on lines outside this diff (see the check run).

return ".".join(parts)


def extract_sql(path: Path, content: str | bytes | None = None) -> dict:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Health regressionextract_sql()

fans out to 11 callees (efferent coupling); 27 callers depend on it (afferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Unlike a string or dollar quoted span, a backtick span must not
cross a newline: a name does not span lines in practice, so an
unclosed backtick is far more likely a stray character than a
genuine multi line identifier. Scanning past a newline for one let
one accidental, unmatched backtick anywhere in the file silently
swallow everything after it, disabling debracketing for the rest of
the file. A backtick that does not close on its own line is now
left as an ordinary character, matching how _scan_sql treats an
unterminated delimited identifier.
A regex recovered name whose own content carried one of src_text's
surrogate escaped invalid bytes was sanitized via
encode(errors=replace).decode(), but that handler turns a lone
surrogate into a bare question mark, not the U+FFFD every other
invalid byte path in this module produces. Replace it explicitly
instead so the placeholder character stays consistent.
@ayushcodes10

Copy link
Copy Markdown
Contributor Author

Two fixes from this round (matching 3b61aa5): the backtick-scan line-scoping fix and the U+FFFD-vs-"?" placeholder consistency fix, both described in detail on #2721.

@graphify-labs graphify-labs 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.

Graphify reviewed this change.

Worth a look — the grounded gate found no coupling regressions or blocking issues, but 1 advisory finding(s) below merit a look before merge.

Formal verification. 1 change(s) alter behavior, breaking input(s) attached.

Behavior changes: \_scan\_sql changes behavior, here is the input that shows it.

The verifier found a concrete input on which \_scan\_sql behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"text":"''"\}, the old code produced \('', \[\]\) but the new code produces \(' ', \[\]\). Paste that input straight into a regression test.


Graphify review — findings

Adds _debracket_tsql, which rewrites T-SQL bracket-quoted identifiers ([dbo].[Orders]) into backtick-quoted ones before parsing so the grammar takes its normal AST path instead of falling into error recovery, fixing mangled labels and tables silently lost behind broken foreign keys. Restricts rewriting to bracket spans that actually read as identifiers — leaving array markers (int[], ARRAY[...]), empty/numeric content, comment-openers, and dotted or backtick-bearing names as plain un-rewritten brackets (the prior fallback) since those can't round-trip — while skipping over single/double-quoted strings, dollar-quoted bodies, and genuine backtick names so their contents aren't corrupted. Extends the routine-recovery scan and _scan_sql to accept and preserve backtick-delimited identifiers, since a recovered bracketed routine name now arrives already rewritten to a backtick name.

Worth a look

  • surrogateescape decode may crash when text is re-encoded for offset mathgraphify/extractors/sql.py · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 363 functions depend on the 183 functions this change touches.

Health — this change adds coupling hotspots:

  • new: extract_sql() — 28 callers, 11 callees
  • new: dispatch_command() — 2 callers, 124 callees
  • new: walk() — 1 callers, 9 callees
  • new: test_poisoned_manifest_is_healed() — 0 callers, 6 callees

Verification — 363 functions in the blast radius were not formally verified this run (proofs are advisory here).

Health delta baseline: last indexed commit 67f99bd (diverged from this PR's base — delta is approximate).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 195 function(s) in the blast radius were not formally verified this run

Formal verification

Behavior changes: \_scan\_sql changes behavior, here is the input that shows it.

The verifier found a concrete input on which \_scan\_sql behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"text":"''"\}, the old code produced \('', \[\]\) but the new code produces \(' ', \[\]\). Paste that input straight into a regression test.

Could not verify: Could not verify extract\_sql.

The verifier did not have enough to check extract\_sql, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set

· 1 grounded finding(s) anchored inline below; 3 more finding(s) on lines outside this diff (see the check run).

return ".".join(parts)


def extract_sql(path: Path, content: str | bytes | None = None) -> dict:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Health regressionextract_sql()

fans out to 11 callees (efferent coupling); 28 callers depend on it (afferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

This loop scanned raw src_text directly, unlike its sibling
routine/view recovery loops which scan the masked output _scan_sql
already produces, and ran unconditionally rather than only on files
that already failed to parse. A CREATE TABLE ... REFERENCES ... shape
sitting inside a single quoted string literal, dynamic SQL text never
executed as DDL, fabricated a real edge between two unrelated tables
that merely share names with the string content, in any file
including a completely clean one. Compute the mask unconditionally,
before this loop, and reuse it for the routine/view recovery loops
below instead of computing it twice.
@ayushcodes10

Copy link
Copy Markdown
Contributor Author

Investigated this round's bot finding on this PR ("surrogateescape decode may crash when text is re-encoded for offset math") -- verified with a battery of adversarial invalid-byte inputs (500 consecutive invalid bytes, overlong encodings, raw continuation bytes, invalid bytes inside a debracketed identifier's own content) through the full extract_sql pipeline: no crash, no corruption. surrogateescape's whole design is a lossless, crash-free round trip for exactly this scenario. No code change made.

Also fixed here (propagated from the base branch, now at ababa65): the Firebird CREATE TABLE/REFERENCES fallback fabricating edges from string literal content, described in detail on #2724.

@graphify-labs graphify-labs 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.

Graphify reviewed this change.

Worth a look — the grounded gate found no coupling regressions or blocking issues, but 2 advisory finding(s) below merit a look before merge.

Formal verification. 1 change(s) alter behavior, breaking input(s) attached.

Behavior changes: \_scan\_sql changes behavior, here is the input that shows it.

The verifier found a concrete input on which \_scan\_sql behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"text":"''"\}, the old code produced \('', \[\]\) but the new code produces \(' ', \[\]\). Paste that input straight into a regression test.


Graphify review — findings

Adds a T-SQL bracket-quoting preprocessor _debracket_tsql that rewrites [dbo].[Orders]-style identifiers into backtick-quoted names before parsing, so tree_sitter_sql handles them on the normal AST path instead of dropping whole statements into error recovery; it skips array markers (int[], ARRAY[...]), string/dollar-quoted/backtick spans, and leaves un-rewritable shapes (embedded ., literal backticks, comment openers) as plain brackets, returning the inserted backtick spans so a downstream reader only un-rewrites bracket-derived names. Extends _scan_sql and _ROUTINE_RECOVERY_RX to accept backtick-quoted routine names during recovery, since a bracketed CREATE PROCEDURE name now arrives already rewritten to backticks. Also normalizes lone surrogates in identifier names to U+FFFD via _LONE_SURROGATE_RX to match the rest of the extractor's invalid-byte placeholder.

Worth a look

  • _debracket_tsql return type changed from bytes to tuplegraphify/extractors/sql.py · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
  • Firebird REFERENCES fallback matches against masked source but reads name from masked textgraphify/extractors/sql.py · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 367 functions depend on the 187 functions this change touches.

Health — this change adds coupling hotspots:

  • new: extract_sql() — 30 callers, 11 callees
  • new: dispatch_command() — 2 callers, 124 callees
  • new: walk() — 1 callers, 9 callees
  • new: test_poisoned_manifest_is_healed() — 0 callers, 6 callees

Verification — 367 functions in the blast radius were not formally verified this run (proofs are advisory here).

Health delta baseline: last indexed commit 67f99bd (diverged from this PR's base — delta is approximate).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 199 function(s) in the blast radius were not formally verified this run

Test selection

Test selection

3 of 255 test file(s) selected (1%) via static blast radius.

  • tests/test_extract.py — impact
  • tests/test_multilang.py — impact, changed-test
  • tests/test_pg_introspect.py — impact

Selection is safe under the controlled-regression assumption; always-run tests + a periodic full run are the backstops. Advisory — it never changes the check verdict.

Formal verification

Behavior changes: \_scan\_sql changes behavior, here is the input that shows it.

The verifier found a concrete input on which \_scan\_sql behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"text":"''"\}, the old code produced \('', \[\]\) but the new code produces \(' ', \[\]\). Paste that input straight into a regression test.

Could not verify: Could not verify extract\_sql.

The verifier did not have enough to check extract\_sql, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set

· 1 grounded finding(s) anchored inline below; 3 more finding(s) on lines outside this diff (see the check run).

return ".".join(parts)


def extract_sql(path: Path, content: str | bytes | None = None) -> dict:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Health regressionextract_sql()

fans out to 11 callees (efferent coupling); 30 callers depend on it (afferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

A name's own byte range could overlap a debracketed span even when
only one of its dotted parts was actually touched, for example a
schema debracketed alongside a genuinely backtick quoted table name
in the same reference. The un rewrite step stripped every part once
the whole name overlapped anywhere, so the untouched part's
backticks got stripped too. Both callers now check and strip per
part.
@ayushcodes10

Copy link
Copy Markdown
Contributor Author

The per-dotted-part backtick-stripping fix described in detail on #2721 is propagated here too, now at f8774f1.

@graphify-labs graphify-labs 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.

Graphify reviewed this change.

Worth a look — the grounded gate found no coupling regressions or blocking issues, but 2 advisory finding(s) below merit a look before merge.

Formal verification. 1 change(s) alter behavior, breaking input(s) attached.

Behavior changes: \_scan\_sql changes behavior, here is the input that shows it.

The verifier found a concrete input on which \_scan\_sql behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"text":"''"\}, the old code produced \('', \[\]\) but the new code produces \(' ', \[\]\). Paste that input straight into a regression test.


Graphify review — findings

Adds _debracket_tsql, which rewrites T-SQL bracket-quoted identifiers ([dbo].[Orders]) to backtick-quoted form before parsing so tree_sitter_sql's normal AST path handles them instead of dropping the statement into error recovery (fixing mangled labels and tables lost behind broken foreign keys); it skips single/double-quoted strings, dollar-quoted bodies, and genuine backtick spans, and leaves brackets untouched when the content isn't a legal identifier (empty, numeric, contains a comment opener, a dot, or a literal backtick). Extends _scan_sql and _ROUTINE_RECOVERY_RX to treat backtick-delimited names the same as double-quoted and bracketed ones, since a recovered bracketed routine name now arrives as a backtick after debracketing. Returns the inserted-span coordinates so a downstream reader can un-rewrite only bracket-derived identifiers and leave real MySQL backtick names alone.

Worth a look

  • Dollar-quoted span skip not implemented in _debracket_tsql despite documented behaviorgraphify/extractors/sql.py · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
  • _strip_backtick_parts mis-tracks byte offset for multibyte identifier partsgraphify/extractors/sql.py · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 369 functions depend on the 189 functions this change touches.

Health — this change adds coupling hotspots:

  • new: extract_sql() — 31 callers, 11 callees
  • new: dispatch_command() — 2 callers, 124 callees
  • new: walk() — 1 callers, 9 callees
  • new: test_poisoned_manifest_is_healed() — 0 callers, 6 callees

Verification — 369 functions in the blast radius were not formally verified this run (proofs are advisory here).

Health delta baseline: last indexed commit 67f99bd (diverged from this PR's base — delta is approximate).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 201 function(s) in the blast radius were not formally verified this run

Test selection

Test selection

3 of 255 test file(s) selected (1%) via static blast radius.

  • tests/test_extract.py — impact
  • tests/test_multilang.py — impact, changed-test
  • tests/test_pg_introspect.py — impact

Selection is safe under the controlled-regression assumption; always-run tests + a periodic full run are the backstops. Advisory — it never changes the check verdict.

Formal verification

Behavior changes: \_scan\_sql changes behavior, here is the input that shows it.

The verifier found a concrete input on which \_scan\_sql behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"text":"''"\}, the old code produced \('', \[\]\) but the new code produces \(' ', \[\]\). Paste that input straight into a regression test.

Could not verify: Could not verify extract\_sql.

The verifier did not have enough to check extract\_sql, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set

· 1 grounded finding(s) anchored inline below; 3 more finding(s) on lines outside this diff (see the check run).

return b".".join(out_parts)


def extract_sql(path: Path, content: str | bytes | None = None) -> dict:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Health regressionextract_sql()

fans out to 11 callees (efferent coupling); 31 callers depend on it (afferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

A bracket quoted identifier containing a literal dot is left as
plain bracket text since the grammar cannot represent it via
backtick quoting either way. Confirmed this is a tree_sitter_sql
grammar limitation independent of any rewriting: feeding a raw,
untouched multi part bracket reference straight to the parser
reproduces the same leak. Its own error recovery for such a span
sometimes groups the opening bracket into the object_reference node
while the matching one lands in a separate sibling ERROR node this
reader never visits, leaking a stray character into the name. Strip
an excess opener or closer unconditionally, since two dot containing
parts joined by a dot can leak one even when neither part was ever
debracketed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qfdzgbA5KedGEjD1AayNh

@graphify-labs graphify-labs 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.

Graphify reviewed this change.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).

Formal verification. 1 change(s) alter behavior, breaking input(s) attached.

Behavior changes: \_scan\_sql changes behavior, here is the input that shows it.

The verifier found a concrete input on which \_scan\_sql behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"text":"''"\}, the old code produced \('', \[\]\) but the new code produces \(' ', \[\]\). Paste that input straight into a regression test.


Graphify review — findings

No blocking issues surfaced.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 371 functions depend on the 191 functions this change touches.

Health — this change adds coupling hotspots:

  • new: extract_sql() — 32 callers, 11 callees
  • new: dispatch_command() — 2 callers, 124 callees
  • new: walk() — 1 callers, 9 callees
  • new: test_poisoned_manifest_is_healed() — 0 callers, 6 callees

Verification — 371 functions in the blast radius were not formally verified this run (proofs are advisory here).

Health delta baseline: last indexed commit 67f99bd (diverged from this PR's base — delta is approximate).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 203 function(s) in the blast radius were not formally verified this run

Test selection

Test selection

3 of 255 test file(s) selected (1%) via static blast radius.

  • tests/test_extract.py — impact
  • tests/test_multilang.py — impact, changed-test
  • tests/test_pg_introspect.py — impact

Selection is safe under the controlled-regression assumption; always-run tests + a periodic full run are the backstops. Advisory — it never changes the check verdict.

Formal verification

Behavior changes: \_scan\_sql changes behavior, here is the input that shows it.

The verifier found a concrete input on which \_scan\_sql behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"text":"''"\}, the old code produced \('', \[\]\) but the new code produces \(' ', \[\]\). Paste that input straight into a regression test.

Could not verify: Could not verify extract\_sql.

The verifier did not have enough to check extract\_sql, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set

· 1 grounded finding(s) anchored inline below; 3 more finding(s) on lines outside this diff (see the check run).

return b".".join(out_parts)


def extract_sql(path: Path, content: str | bytes | None = None) -> dict:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Health regressionextract_sql()

fans out to 11 callees (efferent coupling); 32 callers depend on it (afferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

@ayushcodes10

Copy link
Copy Markdown
Contributor Author

Investigated this round's bot findings on this PR.

"Dollar-quoted span skip not implemented in _debracket_tsql despite documented behavior" -- checked directly: the skip is implemented (the $DOLLAR_QUOTE_TAG_RX branch added earlier this round) and tested against a battery of shapes -- a tagged dollar-quote, an underscore-led tag, a bare $$, an unterminated dollar-quote (correctly consumes to EOF), a dollar sign used as a positional parameter ($1, correctly NOT treated as a dollar-quote opener since it doesn't start with a letter/underscore), and a mismatched inner tag inside an outer dollar-quoted span (correctly finds the real matching closer, not the decoy). All behaved correctly. Likely a stale restatement from before this round's push. No code change made.

"_strip_backtick_parts mis-tracks byte offset for multibyte identifier parts" -- checked directly: the function works entirely in byte-space (splits raw bytes on b".", tracks byte lengths of each part), never mixing character and byte offsets, which is exactly why this class of bug can't occur in it. Verified with CJK characters, a 4-byte emoji character, multi-byte content both before and after a debracketed part in the same dotted reference, and multi-byte content combined with invalid-UTF-8-byte padding that shifts surrounding offsets -- all produced correct, uncorrupted labels through both the tree-walk (_clean_name) and regex-fallback (_clean_regex_name) code paths. No code change made.

The stray-bracket-leak fix described in detail on #2721 is also fixed here, now at 54a70d4 (this is the base branch where _clean_name lives).

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.

T-SQL: bracket-quoted identifiers keep their brackets — [dbo].[Customer] becomes the label dbo].[Customer, so no lookup by real name matches

1 participant