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

184 lines
8.7 KiB
Markdown

# 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**
```python
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**
```bash
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**
```python
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**
```bash
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.