SQL read/write classifier fails closed on valid reads (`//`, typed `TIMESTAMPTZ` literals, `NOT GLOB`, CREATE+SELECT) and reports a misleading "user rule" error

Fechada
#1,488 0 comentários 0 reações 0 responsáveis Ver no GitHub

Mantenedores costumam responder em até 1 dia

Ninguém assumiu esta issue ainda.

Avaliação

Dificuldade
4/5
Tempo estimado
3-5 dias
Facilidade para iniciantes
35/100
Tipo de issue
Bug
Clareza
Razoavelmente clara
Status de atividade
Ativa
Stack de tecnologia
sql, typescript
Domínio
databases

Direção de pesquisa

Start in packages/opencode/src/altimate/tools/sql-classify.ts, at classifyAndCheck, classifyFallback and isScratchSafeWrite, then check how sql-execute.ts maps a write classification to sql_execute_write. Add tests that classify each listed construct (//, NOT GLOB, typed TIMESTAMPTZ literals, CREATE ... AS SELECT followed by SELECT) as a read, and check that a parse failure produces a distinct message. Done means those cases pass and the unparseable-statement denial text is snapshotted.

Escrita pelo modelo de indexação a partir do texto da issue.

Descrição

Problem

When the parser cannot read a statement, classifyAndCheck classifies it as a write. The analyst config denies writes, and the model sees only "The user has specified a rule which prevents you from using this specific tool call". Nothing says the statement was actually a parse failure on a valid read, so models rewrite blindly or switch to slower workarounds.

Mechanism

  • classifyAndCheck falls back to classifyFallback, which returns "write" when the parser throws (packages/opencode/src/altimate/tools/sql-classify.ts:131, :172-193). sql_execute then asks for sql_execute_write (sql-execute.ts:113-121), which the analyst agent denies (packages/opencode/src/agent/agent.ts:254).
  • isScratchSafeWrite requires every statement to be a write (sql-classify.ts:226-271), so CREATE TABLE ... AS SELECT ...; SELECT ... in one call is refused.
  • Parser gaps on pure reads (probed against the bundled parser): DuckDB integer division //; SQLite NOT GLOB; FILTER (...) variants; alias names at and match; PIVOT; typed literals such as TIMESTAMPTZ '2023-05-02 00:00:00+00'. The same queries with /, or with ::timestamptz casts, classify as reads.

Evidence

  • 17 of 17 queries containing // were denied; 4 containing GLOB.
  • 90 refusals of pure SELECT/WITH statements in one set of sessions: 87 contain a typed TIMESTAMPTZ '...' literal, 0 of 2,676 allowed queries on the same warehouses do (inferred from this split; not yet reproduced in a unit test).
  • 31 denied scratch CREATE ... AS SELECT batches with a trailing SELECT.
  • 28 of 32 denials in one set of sessions were avoidable, at about 3.4-3.8 s per lost turn (about 600 s total); 23 generations had every call refused.
  • The refusals pushed models onto a scratch-to-scratch sql_materialize path (45 calls, 728 s, including 4 helper crashes) and blocked a session-setting workaround for expression depth limits (see the many-table issue).

Impact

Time and cost; no direct answer loss (affected sessions recovered), but the risk of abandoning a correct approach is real.

Proposed fix

  • Report parser failures as their own message: "could not prove this is read-only: parser error at col N; rewrite or split the statement".
  • Teach the dialect lexer/parser //, GLOB, PIVOT, typed literals (TIMESTAMPTZ, TIMESTAMP, DATE, INTERVAL '...').
  • When the parse fails but the statement starts with SELECT/WITH and masked code has no write keyword, run on a read-only connection.
  • Accept scratch-safe writes followed by reads and return the last result set.

Acceptance check

Regression tests classifying each of the listed constructs as read, a CREATE ...; SELECT ... scratch batch accepted, and a snapshot of the new denial message for a genuinely unparseable statement.

Linguagem predominante
TypeScript
Estrelas
818
Forks
126
Merge médio
1d 21h
PRs com merge (30d)
70

Preparar o ambiente

Abrir no Codespaces

Inicia o contêiner de desenvolvimento do projeto no navegador, com a sua própria conta do GitHub.

Primeiros passos

  1. Leia a issue inteira e depois o guia de contribuição do projeto.
  2. Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
  3. Faça um fork do repositório e trabalhe em uma branch.
  4. Abra um pull request que referencie o número da issue.

Mais de AltimateAI/altimate-code

Todas as issues de AltimateAI/altimate-code

Issues semelhantes

Mais issues de TypeScript

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.