Files
GTI_GERENCIADOR_FISCAL/docs/superpowers/plans/2026-09-16-firebird-discovery.md
T

8.7 KiB

Firebird Discovery Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Executar discovery reproduzível e estritamente read-only do banco Firebird disponível, documentando ambiente, schema, produto, tributação, imagens, incrementalidade, riscos, mapping e fingerprint.

Architecture: Um coletor local terá uma camada de validação que aceita somente consultas SELECT/metadados e um adaptador de conexão que não expõe operações de escrita. O relatório será gerado a partir de resultados do MCP Firebird e, quando possível, do coletor local; nenhuma tabela auxiliar, migration ou alteração será feita no banco.

Tech Stack: Python 3, driver Firebird disponível no ambiente somente se já instalado, pytest, SQL de RDB$/INFORMATION_SCHEMA compatível com Firebird.

Global Constraints

  • O banco deve ser tratado como read-only.
  • São proibidos INSERT, UPDATE, DELETE, ALTER, CREATE, DROP, TRUNCATE, migrations, triggers, procedures, alteração de índices/constraints, criação de usuário e modificação de permissões.
  • Não executar testes destrutivos contra o banco real.
  • Não armazenar senhas ou secrets em arquivos, logs ou documentação.
  • Não iniciar API fiscal, API de imagens, serviço Windows, atualização de produtos ou scheduler de produção.
  • Achados devem ser classificados como CONFIRMADO, INFERIDO ou NÃO CONFIRMADO.

Task 1: Preparar base e contrato read-only

Files:

  • Create: src/gti_discovery/__init__.py
  • Create: src/gti_discovery/read_only.py
  • Create: tests/test_read_only.py
  • Create: pyproject.toml
  • Create: .env.example
  • Create: CLAUDE.md

Interfaces:

  • Produces validate_read_only(sql: str) -> str, que retorna SQL normalizado ou lança ValueError.

  • Produces ReadOnlyConnection, com método execute(sql: str, params: tuple = ()) e sem métodos de escrita.

  • Step 1: Write the failing tests

import pytest
from gti_discovery.read_only import validate_read_only

def test_accepts_select_and_with_queries():
    assert validate_read_only(" SELECT * FROM RDB$DATABASE ") == "SELECT * FROM RDB$DATABASE"
    assert validate_read_only("WITH x AS (SELECT 1 AS n FROM RDB$DATABASE) SELECT n FROM x")

@pytest.mark.parametrize("sql", ["INSERT INTO X VALUES (1)", "UPDATE X SET A=1", "DELETE FROM X", "CREATE TABLE X(A INT)", "ALTER TABLE X ADD A INT", "DROP TABLE X", "TRUNCATE TABLE X", "EXECUTE PROCEDURE P"])
def test_rejects_write_or_side_effect_sql(sql):
    with pytest.raises(ValueError):
        validate_read_only(sql)
  • Step 2: Run test to verify it fails

Run: python -m pytest tests/test_read_only.py -q Expected: FAIL because the package and validator do not exist.

  • Step 3: Implement the minimal guard

Normalize whitespace, remove one trailing semicolon, reject multiple statements, comments and any first keyword other than SELECT or WITH. Reject side-effect keywords anywhere in the statement, including procedure execution. ReadOnlyConnection.execute must call the validator before delegating to the driver connection.

  • Step 4: Run test to verify it passes

Run: python -m pytest tests/test_read_only.py -q Expected: PASS.

  • Step 5: Commit
git add src tests pyproject.toml .env.example CLAUDE.md
git commit -m "feat: add read-only discovery foundation"

If Git is still unavailable, record the exact blocker and do not initialize or commit without explicit authorization.

Task 2: Coletar metadados e fingerprint

Files:

  • Create: src/gti_discovery/collector.py
  • Create: src/gti_discovery/fingerprint.py
  • Create: tests/test_fingerprint.py

Interfaces:

  • collect_metadata(connection) -> dict executes only predefined read-only queries.

  • build_fingerprint(metadata: dict) -> str returns a stable SHA-256 digest over sorted relevant metadata.

  • Step 1: Write tests for stable fingerprints and changes

from gti_discovery.fingerprint import build_fingerprint

def test_fingerprint_is_order_independent():
    a = {"tables": [{"name": "A", "columns": ["ID", "NAME"]}]}
    b = {"tables": [{"columns": ["ID", "NAME"], "name": "A"}]}
    assert build_fingerprint(a) == build_fingerprint(b)

def test_relevant_schema_change_changes_fingerprint():
    a = {"tables": [{"name": "A", "columns": ["ID"]}]}
    b = {"tables": [{"name": "A", "columns": ["ID", "NCM"]}]}
    assert build_fingerprint(a) != build_fingerprint(b)
  • Step 2: Run tests and verify failure

Run: python -m pytest tests/test_fingerprint.py -q Expected: FAIL because fingerprint functions do not exist.

  • Step 3: Implement collection

Use Firebird system metadata for database info, relations, fields, keys, indexes, foreign keys, triggers, procedures/packages/events where exposed. Include table counts and approximate row counts only when safely available. Redact values and credentials from serialized output. Query a minimal masked sample only for candidate product tables.

  • Step 4: Implement canonical fingerprinting

Canonicalize JSON recursively with sorted object keys and deterministic list ordering for tables, columns, keys, indexes, relations and relevant engine/type metadata; hash UTF-8 canonical JSON with SHA-256. Expose classification helper returning SCHEMA_SUPPORTED, SCHEMA_CHANGED or SCHEMA_UNKNOWN based on an allowlisted expected fingerprint and missing/ambiguous product mapping.

  • Step 5: Run tests

Run: python -m pytest tests -q Expected: PASS.

  • Step 6: Commit
git add src/gti_discovery/collector.py src/gti_discovery/fingerprint.py tests
git commit -m "feat: collect Firebird metadata and fingerprints"

Task 3: Execute discovery against the available database

Files:

  • Create: artifacts/ output files only if explicitly safe and non-sensitive
  • Modify: docs/DATABASE_DISCOVERY.md
  • Modify: docs/SCHEMA_MAPPING.md

Interfaces:

  • Uses the Firebird MCP read-only tools and collector contracts from Tasks 1-2.

  • Step 1: Capture environment metadata

Collect Firebird version, database identity without secrets, charset/collation, timezone when detectable, approximate size, relation count, engines, and relevant configuration.

  • Step 2: Enumerate schema relationships

Inspect all candidate tables/columns for product, stock, barcode, fiscal, company/branch, image/file/attachment and audit concepts; document PKs, FKs, indexes, nullability, defaults and apparent relationships.

  • Step 3: Confirm product and fiscal semantics with minimal samples

Select only masked, non-sensitive columns and a very small sample. Never select credentials, customer data, free-form secrets or full BLOB values. Mark names without direct evidence as INFERIDO or NÃO CONFIRMADO.

  • Step 4: Inspect operational objects

List and describe relevant triggers, procedures, packages and events. Check replication/cache indicators only where readable; explicitly document unavailable evidence.

  • Step 5: Write the two discovery documents

Record actual findings and uncertainties, including no-write evidence, images alternatives A/B/C, incremental processing options, risks and future decisions. Do not propose fiscal automation yet.

  • Step 6: Run offline safety tests and review outputs

Run: python -m pytest tests -q Expected: PASS; manually verify no password, connection string secret, raw BLOB or unnecessary personal data appears in docs/artifacts.

Task 4: Update project state and final verification

Files:

  • Create: docs/AI_PROJECT_STATE.md

  • Modify: CLAUDE.md if needed

  • Step 1: Record current state

State that this workspace contains the Firebird discovery target, that no ERP writes were performed, which artifacts exist, and what remains blocked or undecided. Keep it current rather than diary-like.

  • Step 2: Verify prohibited SQL is absent from executable discovery paths

Run: rg -n --glob '!docs/superpowers/plans/**' '\\b(INSERT|UPDATE|DELETE|ALTER|CREATE|DROP|TRUNCATE)\\b' src tests Expected: only intentional rejection tests/guard literals, with no executable write path.

  • Step 3: Run final tests and inspect repository status

Run: python -m pytest tests -q; then git status --short --branch, git diff --check, and git log -5 --oneline when Git is available.

  • Step 4: Create one final commit

Stage only mission files and create one clear final commit if the repository exists. If no Git repository exists, report commit: não criado, diretório sem .git and do not claim a clean Git status.