Skip to content

fix(cli): respect atomic END boundaries (CLI-2405) - #6587

Open
7ttp wants to merge 3 commits into
developfrom
7ttp/cli-2405-statement-splitter-closes-a-begin-atomic-body-at-any
Open

fix(cli): respect atomic END boundaries (CLI-2405)#6587
7ttp wants to merge 3 commits into
developfrom
7ttp/cli-2405-statement-splitter-closes-a-begin-atomic-body-at-any

Conversation

@7ttp

@7ttp 7ttp commented Sep 12, 2026

Copy link
Copy Markdown
Member

TL;DR

Prevents valid BEGIN ATOMIC functions from being truncated when an identifier contains end

Prob/sol

The splitter treated end inside names such as pending as the closing END,
causing migrations to fail with SQLSTATE 42601
now fixed by:
Recognizing END only at PostgreSQL identifier boundaries in both SQL splitters

ref:

@7ttp 7ttp self-assigned this Sep 12, 2026
@7ttp
7ttp requested a review from a team as a code owner September 12, 2026 20:20

@github-actions github-actions 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.

Superseded by a newer AI review

🤖 AI Review

Five of Claude's seven findings are confirmed; two are refuted. The most significant issue is a pre-existing but real BEGIN ATOMIC splitting bug for top-level CASE expressions. The digit-before-dollar guard also diverges from PostgreSQL tokenization, while three confirmed nits concern maintainability or documentation. Codex reported no findings.

Findings

Severity Location Category Sources Claim
🟠 MAJOR apps/cli/src/command-internal/sql-split.ts:142 correctness claude A top-level CASE expression inside BEGIN ATOMIC is mistaken for the function body's closing END, causing valid SQL to be split prematurely.
🟡 MINOR apps/cli/src/command-internal/sql-split.ts:42 correctness claude The new dollar-quote guard mistakes a preceding numeric literal's digit for proof that an identifier is open, unlike PostgreSQL's lexer.
⚪ NIT apps/cli/src/command-internal/sql-split.ts:142 maintainability claude The pendingEnd identifier-continuation branch bypasses the nested state, coupling correctness to ReadyState's current identifier-rune behavior.
⚪ NIT apps/cli/src/command-internal/sql-split.ts:18 documentation claude The non-obvious PostgreSQL-specific reason for treating every code point at or above 0x80 as an identifier character is undocumented.
⚪ NIT apps/cli/src/command-internal/sql-split.ts:23 maintainability claude hasIdentifierRuneBefore leaves its two-code-unit window unexplained and handles negative offsets inconsistently with its Go counterpart.
Refuted findings (kept for transparency, not posted as review comments)
  • apps/cli/src/command-internal/sql-split.unit.test.ts:68 (test-coverage): The new identifier-before-$ behavior lacks meaningful observable regression coverage outside BEGIN ATOMIC tests.
    Refuted: The existing cases exercise the guard through observable splitter output and fail without it. A standalone example would cover the same path using malformed SQL, contrary to the trusted convention against redundant assertions.
  • apps/cli-go/pkg/parser/state.go:218 (maintainability): AtomicState's delimiter comparisons should be replaced by a separate boolean or enum because its delimiter has only two possible values.
    Refuted: The delimiter is not merely a discriminator: it is the value endsWithDelimiter must match. Adding a separate boolean would duplicate state and create a possible inconsistency without correcting any demonstrated behavior; the small string conversions are not a substantive defect.

Stats

Claude findings: 7 · Codex findings: 0 · Confirmed: 5 · Refuted: 2 · Uncertain: 0


Models: claude-opus-5 + gpt-5.6-sol · Trigger: auto · Workflow run

This review runs once per PR. A maintainer can request another with a /ai-review comment.

Comment thread apps/cli/src/command-internal/sql-split.ts Outdated
Comment thread apps/cli/src/command-internal/sql-split.ts Outdated
Comment thread apps/cli/src/command-internal/sql-split.ts
Comment thread apps/cli/src/command-internal/sql-split.ts
Comment thread apps/cli/src/command-internal/sql-split.ts
@7ttp

7ttp commented Sep 12, 2026

Copy link
Copy Markdown
Member Author

/ai-review

@github-actions github-actions 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.

🤖 AI Review

Both independent reviews completed: Claude reported six findings and Codex reported none. All six concerns are confirmed, though the comment-density issue predates this PR and the overlapping-comment bug requires malformed SQL. The most substantive issue is a regression that can leave a nested AtomicState stale and swallow subsequent statements.

Findings

Severity Location Category Sources Claim
🟡 MINOR apps/cli-go/pkg/parser/state.go:271 correctness claude A nested END-delimited AtomicState that returns nil on its confirming semicolon remains stored in the enclosing AtomicState, preventing the enclosing parenthesized state from closing.
🟡 MINOR apps/cli-go/pkg/parser/state.go:66 parity claude isBeginAtomic uses broader, differing Unicode whitespace classes in Go and TypeScript instead of the PostgreSQL lexer whitespace class introduced by this change.
🟡 MINOR apps/cli/src/command-internal/sql-split.ts:68 correctness claude isCommentsAndWhitespace and BlockState handle overlapping block-comment delimiters differently, allowing END to close a body after the FSM has treated text as statement content but the helper has consumed it as an unterminated comment.
⚪ NIT apps/cli-go/pkg/parser/state.go:51 dead-code claude Parenthesis-delimited AtomicState instances initialize and update END-specific bookkeeping that cannot affect their behavior.
⚪ NIT apps/cli/src/command-internal/sql-split.ts:220 comments claude Several newly added inline comment blocks exceed the trusted repository convention of one or two lines, while the file remains above the documented comment-density limit.
⚪ NIT apps/cli/src/command-internal/sql-split.unit.test.ts:109 test-coverage claude The TypeScript tests cover pending END only when the confirming character is a semicolon, leaving the non-semicolon and EOF paths untested.

Stats

Claude findings: 6 · Codex findings: 0 · Confirmed: 6 · Refuted: 0 · Uncertain: 0


Models: claude-opus-5 + gpt-5.6-sol · Trigger: manual · Workflow run

This review runs once per PR. A maintainer can request another with a /ai-review comment.

Comment thread apps/cli-go/pkg/parser/state.go
Comment thread apps/cli-go/pkg/parser/state.go Outdated
Comment thread apps/cli/src/command-internal/sql-split.ts
Comment thread apps/cli-go/pkg/parser/state.go Outdated
Comment thread apps/cli/src/command-internal/sql-split.ts Outdated
Comment thread apps/cli/src/command-internal/sql-split.unit.test.ts
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.

Statement splitter closes a BEGIN ATOMIC body at any identifier ending in end — the closer lacks the boundary check the opener already has

1 participant