184 lines
8.7 KiB
Markdown
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.
|