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,INFERIDOouNÃ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çaValueError. -
Produces
ReadOnlyConnection, com métodoexecute(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) -> dictexecutes only predefined read-only queries. -
build_fingerprint(metadata: dict) -> strreturns 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.mdif 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.