Skip to content

PR#1 (C): escrita falha LOUD em vez de no-op silencioso#524

Closed
adm01-debug wants to merge 3 commits into
mainfrom
fix/c-loud-writes
Closed

PR#1 (C): escrita falha LOUD em vez de no-op silencioso#524
adm01-debug wants to merge 3 commits into
mainfrom
fix/c-loud-writes

Conversation

@adm01-debug
Copy link
Copy Markdown
Owner

@adm01-debug adm01-debug commented May 30, 2026

Contexto

Bridge OFF (edge_external_db_bridge: enabled=false, rollout=100 → REST nativo 100%) + rest-native cobrindo só SELECT = toda ESCRITA (insert/update/delete/upsert/batch_insert) por invokeExternalDb/invokeExternalDbSingle/invokeExternalDbDelete retornava {records:[],count:0} silenciosamente. A UI dizia "salvo/excluído com sucesso" sem persistir — corrupção silenciosa.

Simulação (73.728 cenários): estado ATUAL = 34.560 perdas silenciosas; com este PR (C) = 0, sem quebrar leitura (INV3=0) nem brecha de segurança (INV2=0).

Mudanças

  • WriteUnavailableError (tipado) + helper isWriteOperation().
  • invokeExternalDb: escrita com bridge OFF / kill-switch / CORS agora lança em vez de retornar vazio. Leitura mantém vazio silencioso (REST nativo é o caminho real).
  • invokeExternalDbDelete: lança em vez de return silencioso.
  • reportSilentEmpty('write_bridge_off') preservado antes do throw.
  • index.ts exporta os novos símbolos.

Auditoria

Os 12 callers de escrita estão todos em try/catch/useMutation com toast.error(error.message) → throw vira erro honesto, sem rejeições não-tratadas.

Validação local

tsc --noEmit: 0 erros nos arquivos tocados. Draft proposital — aguardando CI (build Vite + testes).

Série: #1 (C) → #2/#3 (A: escrita REST nativo + RLS) → #4 (aposentar bridge).


Summary by cubic

Escritas passam a usar REST nativo (PostgREST + RLS) nas tabelas whitelisted e, quando não for possível, falham em voz alta em vez de no-op silencioso — eliminando “salvo/excluído com sucesso” sem persistência. Leituras continuam retornando vazio quando o caminho real é REST nativo.

  • New Features

    • Caminho de escrita REST nativo com 6 guardas: sem update/delete sem id/filtro, sempre na tabela base (nunca views), select-back, remap EN→PT no payload/filtros, whitelist por tabela, e erros propagados.
    • Fast-path de escrita em invokeExternalDb e invokeExternalDbDelete; se a tabela/op não for elegível, cai para a bridge; sem retry em escrita. Novos exports: isRestNativeWriteEligible, executeRestNativeWrite, tryExecuteRestNativeWrite. Testes cobrindo o Plano A.
    • Merge com main preserva a telemetria do caminho vivo (recordBridgeCall) e registra hits de kill-switch (recordKillSwitchHit).
  • Bug Fixes

    • Novo WriteUnavailableError e helper isWriteOperation.
    • Com bridge OFF, kill-switch ativo ou erro de CORS/rede, escrita agora lança WriteUnavailableError em vez de retornar vazio; select mantém retorno vazio.
    • invokeExternalDbDelete deixa de no-op silencioso e também lança. Exporta WriteUnavailableError/isWriteOperation em index.ts.

Written for commit 6637d48. Summary will update on new commits.

Review in cubic

…cioso

Com a bridge OFF (REST nativo 100%) e o REST nativo cobrindo apenas SELECT,
toda operação de ESCRITA (insert/update/delete/upsert/batch_insert) roteada por
invokeExternalDb/invokeExternalDbSingle/invokeExternalDbDelete retornava vazio
silenciosamente — a UI reportava "salvo/excluído com sucesso" sem persistir nada
(corrupção silenciosa).

Mudanças:
- Novo WriteUnavailableError (tipado) + helper isWriteOperation().
- invokeExternalDb: escrita com bridge OFF ou erro CORS/kill-switch agora LANÇA
  WriteUnavailableError em vez de retornar {records:[],count:0}. Leitura mantém
  o retorno vazio silencioso (REST nativo é o caminho real).
- invokeExternalDbDelete: idem — lança em vez de return silencioso.
- Telemetria reportSilentEmpty('write_bridge_off') preservada antes do throw.
- Barrel index.ts exporta WriteUnavailableError e isWriteOperation.

Auditoria: os 12 callers de escrita estão todos em try/catch/useMutation com
toast.error(error.message) — o throw vira erro honesto e visível, sem rejeições
não-tratadas. Type-check (tsc --noEmit) limpo nos arquivos tocados.

Stopgap reversível enquanto PR#2/#3 (A: escrita REST nativo + RLS) reintroduzem
o caminho de escrita real.
@vercel
Copy link
Copy Markdown

vercel Bot commented May 30, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
we-dream-big Error Error May 30, 2026 5:01pm

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 30, 2026

Warning

Review limit reached

@adm01-debug, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 40 minutes and 31 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ff886824-9a8b-4550-a7c6-fd2239fb3de7

📥 Commits

Reviewing files that changed from the base of the PR and between 19ba024 and 6637d48.

📒 Files selected for processing (5)
  • src/lib/external-db/__tests__/rest-native-write.test.ts
  • src/lib/external-db/bridge.ts
  • src/lib/external-db/index.ts
  • src/lib/external-db/rest-native.ts
  • tests/lib/bridge.test.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/c-loud-writes

Comment @coderabbitai help to get the list of available commands and usage tips.

@supabase
Copy link
Copy Markdown

supabase Bot commented May 30, 2026

This pull request has been ignored for the connected project doufsxqlfjyuvxuezpln because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@adm01-debug adm01-debug marked this pull request as ready for review May 30, 2026 16:52
Copilot AI review requested due to automatic review settings May 30, 2026 16:52
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

* feat(external-db): PR#2 (A) — caminho de ESCRITA via PostgREST nativo

Estende o rest-native para insert/update/delete/upsert/batch_insert, com as 6
guardas do Plano A:
- A1 sessão autenticada → delegada ao RLS (supabase-js anexa o JWT).
- A2 update/delete SEM filtro/id → proibido (proteção contra mutação em massa).
- A3 escrita SEMPRE na tabela BASE (WRITE_TABLE_ALIASES), nunca na view v_*_public
  read-only — NÃO reusa TABLE_ALIASES de leitura.
- A4 `.select()` de volta; insert OK com select-back vazio (RLS de SELECT) ainda é sucesso.
- A5 remap EN→PT no payload e filtros (COLUMN_ALIASES_BY_TABLE), evita 400.
- Sem retry em escrita (evita insert/upsert duplicado); erro real PROPAGA LOUD.

Novos exports: isRestNativeWriteEligible, executeRestNativeWrite, tryExecuteRestNativeWrite.
Whitelist de escrita = as 13 tabelas base usadas pelos 12 hooks de admin.

Testes: src/lib/external-db/__tests__/rest-native-write.test.ts — 12 casos cobrindo
todas as 6 guardas + elegibilidade + propagação LOUD + batch array remap.

* feat(external-db): PR#2 (A) — fia o write fast-path no invokeExternalDb + delete

- invokeExternalDb: novo WRITE fast-path (isRestNativeWriteEligible →
  tryExecuteRestNativeWrite) logo após o READ fast-path. Sucesso retorna; erro de
  RLS/validação PROPAGA LOUD; tabela/op não-elegível cai no WriteUnavailableError.
- invokeExternalDbDelete: roteia REST nativo (RLS) primeiro; fallback bridge; senão LOUD.
- bridge.test.ts: os 3 testes de contrato da bridge passam a usar tabela
  NÃO-whitelisted (audit_logs) — onde a bridge continua sendo o caminho — preservando
  a intenção (o caminho REST nativo é coberto por rest-native-write.test.ts). Também
  corrige 2 falhas pré-existentes no arquivo (string de acento + chave auth duplicada).

tsc --noEmit limpo; vitest: bridge.test.ts + __tests__/ = 32/32 verdes.
Depende do PR#3 (RLS WITH CHECK) para a escrita efetivamente persistir; sem ele,
a escrita falha LOUD (honesto), nunca silenciosa.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR changes the external DB bridge write behavior so writes no longer degrade to silent empty/no-op results when the bridge is disabled or unreachable, while preserving read fallback behavior.

Changes:

  • Adds isWriteOperation() and typed WriteUnavailableError.
  • Throws WriteUnavailableError for write operations when bridge is OFF, kill-switched, or affected by CORS/network failures.
  • Re-exports the new helper/error from the external-db barrel.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

File Description
src/lib/external-db/bridge.ts Adds write-operation detection, typed write-unavailable errors, and loud failure paths for writes/deletes.
src/lib/external-db/index.ts Exports the new bridge helper and error type.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +52 to +53
`Escrita indisponível: '${operation}' em '${table}' não pôde ser persistida ` +
`(bridge OFF ou inacessível). Nenhum dado foi alterado.`,
Comment on lines +43 to +45
* tenha sido persistido (corrupção silenciosa). Os callers (mutations / try-catch)
* já exibem `toast.error` a partir de `error.message`, então este erro tipado
* transforma o no-op silencioso em falha honesta e visível.

if (!bridgeEnabled) {
if (options.operation !== 'select') {
if (isWriteOperation(options.operation)) {
…to do #524

O #526 (telemetria recordBridgeCall no caminho vivo) entrou no main e tocou
bridge.ts nas mesmas regiões do PR#1. Este commit reescreve bridge.ts/index.ts
com o conteúdo do main atual (toda a telemetria do #526 intacta) + os edits do
PR#1 por cima, em regiões distintas:

- WRITE_OPERATIONS + isWriteOperation + WriteUnavailableError (novos).
- invokeExternalDb: escrita com bridge OFF agora THROW (após reportSilentEmpty +
  recordCall + recordKillSwitchHit do #526). Leitura segue vazia.
- ramos KillSwitchActiveError/CORS: escrita THROW (telemetria preservada).
- invokeExternalDbDelete: THROW em vez de no-op silencioso.
- index.ts: exporta WriteUnavailableError e isWriteOperation.

Resultado: as regiões do #526 ficam idênticas ao main → merge 3-way sem conflito.
tsc --noEmit limpo. (As 2 falhas de bridge.test.ts são pré-existentes no main —
mock sem logger.debug e asserção com acento — e são corrigidas no PR#2.)
@adm01-debug adm01-debug deleted the fix/c-loud-writes branch May 30, 2026 17:05
adm01-debug added a commit that referenced this pull request May 30, 2026
…atual (#524)

Rebase sobre o main atual (inclui #526, telemetria recordBridgeCall) para
eliminar o conflito do #524. Branch recriada a partir do main + este \u00fanico commit.

- WRITE_OPERATIONS + isWriteOperation + WriteUnavailableError (novos).\n- invokeExternalDb: escrita com bridge OFF/kill-switch/CORS agora THROW
  (ap\u00f3s reportSilentEmpty + recordCall + recordKillSwitchHit do #526);
  leitura segue retornando vazio.\n- invokeExternalDbDelete: THROW em vez de no-op silencioso.\n- index.ts: exporta WriteUnavailableError e isWriteOperation.

Toda a telemetria do #526 preservada (7x recordCall). tsc --noEmit limpo.
Escopo do PR#1 = apenas bridge.ts + index.ts (rest-native writes + testes ficam no PR#2/#525).
adm01-debug added a commit that referenced this pull request May 30, 2026
…E + testes

Re-land do PR#2 (estava órfão após o rebase do #524/#529). rest-native.ts =
main atual (telemetria #526 intacta) + seção WRITE (Plano A) anexada:
executeRestNativeWrite/tryExecuteRestNativeWrite/isRestNativeWriteEligible com
as 6 guardas (A1 RLS, A2 anti-mutação-em-massa, A3 tabela base nunca view,
A4 select-back vazio=sucesso, A5 remap EN→PT, sem retry/LOUD). + rest-native-write.test.ts (12 casos).
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.

2 participants