# Library Symbols — Feature Design Document

## 1. Visão Geral

Sistema de importação e resolução de símbolos de bibliotecas externas (ex: Borland OWL, MFC, Qt, .NET BCL). O parser consome dumps de símbolos (formato TurboDump inicialmente), armazena-os como referência autoritativa, e cruza automaticamente com os resultados de análise estática para resolver imports opacos (ordinais) em nomes semânticos.

A informação resolvida é injetada no pipeline de embeddings (pgvector) e na construção de contexto do chat RAG, melhorando dramaticamente a qualidade das respostas do LLM.

**Fase atual (1):** Parser TurboDump + integração completa com AI/RAG. Sem sessões de chat temático (Fase 2 futura).

## 2. Arquitetura

```
┌──────────────────────────────────────────────────────────────────┐
│                       LIBRARY UPLOAD FLOW                        │
│                                                                  │
│  POST /libraries/upload                                          │
│    │  {parserType, rawContent, libraryName, aliases[]}           │
│    ▼                                                             │
│  LibraryService.parseAndStore()                                  │
│    ├─ LibrarySymbolParser (interface)                            │
│    │   └─ TurboDumpParser  ←  implementação atual                │
│    │   └─ DefFileParser   ←  futuro                             │
│    │   └─ MapFileParser   ←  futuro                             │
│    ├─ Cria Library entity                                        │
│    ├─ Cria LibraryAlias entities (mapeamento DLL ↔ library)      │
│    ├─ Chama parser.parse() → List<ParsedSymbol>                  │
│    └─ Salva LibrarySymbol entities em lote                      │
└──────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────┐
│                   SYMBOL RESOLUTION FLOW                         │
│                                                                  │
│  StaticAnalysisCompletedEvent (disparado após IDA/Ghidra)        │
│    ▼                                                             │
│  SymbolResolutionService.resolveImports(analysisId)              │
│    ├─ Carrega todos os StaticImport do analysis                  │
│    ├─ Para cada import com ordinal != 0:                         │
│    │   ├─ Busca LibraryAlias pelo campo dll do import            │
│    │   ├─ Se encontrado: busca LibrarySymbol por (library, ordinal)│
│    │   └─ Se encontrado: atualiza StaticImport.resolvedName      │
│    │                     e StaticImport.librarySymbolId           │
│    └─ Loga estatísticas: quantos imports resolvidos              │
└──────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────┐
│                     AI / RAG ENRICHMENT                          │
│                                                                  │
│  EmbeddingChunkBuilder                                           │
│    ├─ buildImportChunks(): inclui resolvedName + className       │
│    ├─ buildMetadataChunk(): inclui Library Diagnostics section   │
│    └─ buildFunctionChunkContent(): callees resolvidos via OWL    │
│                                                                  │
│  ChatContextBuilder                                              │
│    ├─ buildSystemPrompt(): inclui [LIBRARY CONTEXT] seção        │
│    └─ detectFunctionReferences(): busca por classes/métodos OWL  │
└──────────────────────────────────────────────────────────────────┘
```

## 3. Modelo de Dados

### 3.1 Tabelas Novas

#### `library`
| Coluna | Tipo | Descrição |
|--------|------|-----------|
| `id` | UUID PK | Identificador |
| `name` | VARCHAR(255) NOT NULL | Nome da biblioteca (ex: "Borland OWL 2.52") |
| `description` | TEXT | Descrição opcional (ex: "Object Windows Library for Borland C++") |
| `created_at` | TIMESTAMPTZ NOT NULL | Data de criação |

#### `library_alias`
| Coluna | Tipo | Descrição |
|--------|------|-----------|
| `id` | UUID PK | Identificador |
| `library_id` | UUID FK → library(id) ON DELETE CASCADE | Biblioteca pai |
| `alias` | VARCHAR(255) NOT NULL | Nome do DLL/arquivo no import table (ex: "OWLWI", "owl252.dll") |
| `UNIQUE(library_id, alias)` | | Um alias pertence a uma única biblioteca |

#### `library_symbol`
| Coluna | Tipo | Descrição |
|--------|------|-----------|
| `id` | UUID PK | Identificador |
| `library_id` | UUID FK → library(id) ON DELETE CASCADE | Biblioteca pai |
| `module_name` | VARCHAR(255) NOT NULL | Módulo original (ex: "Owl252" do TurboDump) |
| `class_name` | VARCHAR(500) | Classe C++ (nulo para funções livres) |
| `symbol_name` | VARCHAR(500) NOT NULL | Nome completo do símbolo (ex: "TButtonGadget::Paint(TDC*)") |
| `ordinal` | INTEGER NOT NULL | Número ordinal de importação |
| `symbol_type` | VARCHAR(50) | Tipo: CONSTRUCTOR, DESTRUCTOR, METHOD, FUNCTION, STATIC_MEMBER |
| `parameters` | VARCHAR(1000) | Assinatura dos parâmetros (extraído do nome) |
| `category` | VARCHAR(100) | Categoria (ex: "UI/Gadget", "Core/Application", "Graphics/Bitmap") |
| `created_at` | TIMESTAMPTZ NOT NULL | Data de criação |

Índices: `idx_library_symbol_library_ordinal ON library_symbol (library_id, ordinal)`
          `idx_library_symbol_class ON library_symbol (class_name) WHERE class_name IS NOT NULL`

### 3.2 Tabela Alterada

#### `static_import` (adições)
| Coluna | Tipo | Descrição |
|--------|------|-----------|
| `library_symbol_id` | UUID FK → library_symbol(id) ON SET NULL | Símbolo de biblioteca que corresponde a este import |
| `resolved_name` | VARCHAR(500) | Nome resolvido (ex: "TButtonGadget::Paint(TDC*)") |

Índice: `idx_static_import_library_symbol ON static_import (library_symbol_id) WHERE library_symbol_id IS NOT NULL`

## 4. Fluxo de Dados Detalhado

### 4.1 Upload da Biblioteca

```
POST /libraries/upload
Content-Type: application/json

{
  "name": "Borland OWL 2.52",
  "description": "Object Windows Library for Borland C++ 5.0",
  "parserType": "TURBO_DUMP",
  "aliases": ["OWLWI", "owl252.dll", "Owl252"],
  "rawContent": "Turbo Dump Version 5.0.1..."
}
```

1. `LibraryService.parseAndStore()` recebe o request
2. Busca um `LibrarySymbolParser` pelo `parserType` (pode ser um Map<String, LibrarySymbolParser> ou via qualifier annotation)
3. Cria `Library` entity e salva
4. Cria `LibraryAlias` entities para cada alias
5. Chama `parser.parse(rawContent, libraryId)` → `List<ParsedSymbol>`
6. Salva `LibrarySymbol` entities em batch (500 por vez)
7. Retorna `LibraryResponse` com contagem de símbolos

### 4.2 Resolução de Import Symbols

Após a análise IDA/Ghidra completar, o `StaticAnalysisCompletedEvent` é publicado. O listener `SymbolResolutionListener` (ou `SymbolResolutionService`) escuta o evento:

1. Carrega `StaticImport` para o `analysisId`
2. Para cada import com `ordinal != 0`:
   a. Busca `LibraryAlias` onde `alias ILIKE dll` (case-insensitive)
   b. Se encontrado, busca `LibrarySymbol` por `(library_id, ordinal)`
   c. Se encontrado, atualiza `StaticImport.librarySymbolId` e `resolvedName`
3. Loga: `Resolved 152/200 imports (76%) for analysis <id>`
4. Opcional: publica um evento `SymbolsResolvedEvent` para notificar downstream

Alternativamente, se o listener não for viável (timing), o `StaticAnalysisHandler` chama `symbolResolutionService.resolveImports(analysisId)` no final do `process()`.

### 4.3 Enriquecimento de Embedding Chunks

#### Import Chunks
```java
// Antes
"[IMPORT] OWLWI.ord_75 @ 0x00405A00"

// Depois (com library symbol resolvido)
"[IMPORT] OWLWI.TButtonGadget::Paint(TDC*) @ 0x00405A00 " +
"  Library: Borland OWL 2.52 | Class: TButtonGadget | Method: Paint"
```

#### Metadata Chunk — Nova seção [LIBRARY DIAGNOSTICS]
```
[LIBRARY DIAGNOSTICS]
Framework: Borland OWL 2.52 (Object Windows Library)
Detected classes (15): TApplication, TFrameWindow, TButtonGadget, TBitmap,
  TControlBar, TChooseColorDialog, TChooseFontDialog, TClipboard, TBrush,
  TDC, TCursor, TBitSet, TCharSet, TCommonDialog, TControlGadget
Category distribution: UI/Gadget (6), Core/Application (3), Graphics (4),
  UI/Window (2)
Architecture: Event-driven GUI, message dispatch via TEventHandler::Find()
```

#### Function Chunks
No `buildFunctionChunkContent()`, ao listar callees, se o callee for um import com `resolvedName`:
```java
// Antes
"Callees: sub_401000, ordinal_75, ordinal_67"

// Depois
"Callees: sub_401000, TButtonGadget::Paint [OWL/ord75], TButtonGadget::TButtonGadget [OWL/ord67]"
```

### 4.4 Enriquecimento do System Prompt

```java
// Antes
String.format("""
  [BINARY OVERVIEW]
  Filename: %s
  Format: %s
  Architecture: %s
  Compiler: %s
  """, ...);

// Depois
String.format("""
  [BINARY OVERVIEW]
  Filename: %s
  Format: %s
  Architecture: %s
  Compiler: Borland C++

  [LIBRARY CONTEXT]
  This binary links against Borland OWL 2.52 (Object Windows Library), a
  C++ framework for Windows GUI applications. Key classes detected:
  %s

  OWL uses a message-driven architecture similar to MFC. Windows messages
  are routed through TEventHandler response tables. Common patterns:
  - TFrameWindow is the main application window
  - TButtonGadget handles button controls with Paint() for WM_PAINT
  - Dialogs extend TCommonDialog via TChooseColorDialog/TChooseFontDialog
  - Graphics use TDC (Device Context wrapper) with TBrush/TPen/TBitmap

  When analyzing functions that call OWL imports, consider the OWL class
  hierarchy and event dispatch model to infer the function's role.
  """, ..., libraryDiagnostics);
```

## 5. API REST

### 5.1 Endpoints

| Método | Path | Descrição |
|--------|------|-----------|
| `POST` | `/libraries/upload` | Upload de um dump de símbolos de biblioteca |
| `GET` | `/libraries` | Listar todas as bibliotecas carregadas |
| `GET` | `/libraries/{id}` | Detalhes de uma biblioteca |
| `DELETE` | `/libraries/{id}` | Remover uma biblioteca e seus símbolos |
| `GET` | `/libraries/{id}/symbols` | Listar símbolos (com paginação, filtro por nome/ordinal) |
| `POST` | `/analysis/{analysisId}/resolve-symbols` | Forçar resolução de símbolos (debug) |

### 5.2 DTOs

```java
// Request
public record LibraryUploadRequest(
    @NotBlank String name,
    String description,
    @NotBlank String parserType,
    @NotEmpty List<String> aliases,
    @NotBlank String rawContent
) {}

// Response
public record LibraryResponse(
    UUID id, String name, String description, int symbolCount,
    int aliasCount, Instant createdAt
) {
    public static LibraryResponse from(Library lib) { ... }
}

public record LibrarySymbolResponse(
    UUID id, String moduleName, String className, String symbolName,
    int ordinal, String symbolType, String parameters, String category
) {
    public static LibrarySymbolResponse from(LibrarySymbol sym) { ... }
}
```

### 5.3 ImportResponse (estendido)

```java
public record ImportResponse(
    UUID id, String dll, String name, String address, int ordinal,
    // Novos campos opcionais:
    String resolvedName,    // nulo se não resolvido
    String libraryName,     // nulo se não resolvido
    String className,       // nulo se não for método de classe
    UUID librarySymbolId    // nulo se não resolvido
) {
    public static ImportResponse from(StaticImport imp) {
        var sym = imp.getLibrarySymbol();
        return new ImportResponse(
            imp.getId(), imp.getDll(), imp.getName(), imp.getAddress(),
            imp.getOrdinal(),
            imp.getResolvedName(),
            Objects.nonNull(sym) ? sym.getLibrary().getName() : null,
            Objects.nonNull(sym) ? sym.getClassName() : null,
            imp.getLibrarySymbolId()
        );
    }
}
```

## 6. Parser Architecture

### 6.1 Interface

```java
package ai.decompile.analysis.service.parser;

import java.util.List;

public interface LibrarySymbolParser {
    /** Identificador único do formato (ex: "TURBO_DUMP", "DEF_FILE") */
    String getFormatName();

    /** Valida se o conteúdo é compatível com este parser */
    boolean canParse(String rawContent);

    /** Parseia o conteúdo e retorna símbolos para association com libraryId */
    List<ParsedSymbol> parse(String rawContent);
}

/** Registro intermediário entre parser e serviço */
public record ParsedSymbol(
    String moduleName,
    String className,
    String symbolName,
    int ordinal,
    String symbolType,
    String parameters,
    String category
) {}
```

### 6.2 TurboDumpParser

Implementação concreta para o formato do utilitário `TDUMP.EXE` da Borland:

**Formato de entrada:**
```
000020 THEADR  TAppDictionary::TAppDictionary()
00003E COMENT  Purge: Yes, List: Yes, Class: 160 (0A0h)
    Dynamic link import (IMPDEF)
      Imported by: ordinal
      Internal Name: TAppDictionary::TAppDictionary()
      Module Name: Owl252
      ordinal: 2
000069 MODEND
```

**Lógica de parsing:**
1. Divide o texto por blocos delimitados por `MODEND`
2. Para cada bloco:
   - Extrai `symbolName` da linha `THEADR`
   - Extrai `moduleName` do campo `Module Name:`
   - Extrai `ordinal` do campo `ordinal:`
   - Se não encontrar `ordinal:` ou o bloco não for `IMPDEF`, pula
   - Classifica `symbolType`:
     - Contém `::~` → `DESTRUCTOR`
     - Contém `::` e termina em `()` sem `~` → `CONSTRUCTOR`
     - Contém `::` → `METHOD`
     - Sem `::` → `FUNCTION`
   - Extrai `className` do trecho antes de `::`
   - Extrai `parameters` dos parênteses após o nome do método
   - Classifica `category` por prefixo de classe:
     ```
     TApp, TModule, TStatus, TXCompatibility → Core/Application
     TFrame, TWindow, TDialog, TClipboard → UI/Window
     TButton, TGadget, TControl, TSlider → UI/Control
     TBitmap, TPalette, TDib, TIcon, TDC → Graphics
     TBrush, TPen, TFont → Graphics/Drawing
     TColor → Graphics/Color
     TCursor → UI/Cursor
     TBitSet, TCharSet → Core/DataTypes
     default → Core/Other
     ```

### 6.3 Registro de Parsers

```java
@Component
@RequiredArgsConstructor
public class LibrarySymbolParserRegistry {
    // Spring injeta todos os beans LibrarySymbolParser
    private final Map<String, LibrarySymbolParser> parsers;

    // Construtor monta o mapa formatName → parser
    public LibrarySymbolParserRegistry(List<LibrarySymbolParser> parserList) {
        this.parsers = parserList.stream()
            .collect(Collectors.toMap(
                LibrarySymbolParser::getFormatName,
                Function.identity()));
    }

    public LibrarySymbolParser get(String formatName) {
        var parser = parsers.get(formatName);
        if (Objects.isNull(parser)) {
            throw new IllegalArgumentException(
                "No parser found for format '" + formatName + "'. " +
                "Available: " + parsers.keySet());
        }
        return parser;
    }

    public List<String> getAvailableFormats() {
        return List.copyOf(parsers.keySet());
    }
}
```

## 7. Estrutura de Código

```
src/main/java/ai/decompile/analysis/
├── model/
│   ├── entity/
│   │   ├── Library.java              (novo)
│   │   ├── LibraryAlias.java         (novo)
│   │   ├── LibrarySymbol.java        (novo)
│   │   └── StaticImport.java         (modificado: +resolvedName, +librarySymbolId, +librarySymbol)
│   ├── repository/
│   │   ├── LibraryRepository.java         (novo)
│   │   ├── LibraryAliasRepository.java    (novo)
│   │   └── LibrarySymbolRepository.java   (novo)
│   └── dto/
│       ├── LibraryResponse.java           (novo)
│       ├── LibrarySymbolResponse.java     (novo)
│       ├── LibraryUploadRequest.java      (novo)
│       └── ImportResponse.java            (modificado)
├── service/
│   ├── parser/
│   │   ├── LibrarySymbolParser.java       (novo - interface)
│   │   ├── ParsedSymbol.java              (novo - record)
│   │   ├── LibrarySymbolParserRegistry.java (novo)
│   │   └── TurboDumpParser.java           (novo)
│   ├── LibraryService.java                (novo)
│   ├── SymbolResolutionService.java       (novo)
│   └── AnalysisService.java              (modificado: chama resolution após saveResult)
├── event/
│   └── SymbolsResolvedEvent.java          (novo, opcional)
└── controller/
    └── LibraryController.java             (novo)

src/main/resources/db/migration/
├── V021__create_library_tables.sql        (novo)
└── V022__alter_static_import_library.sql  (novo)

src/main/java/ai/decompile/ai/service/
├── EmbeddingChunkBuilder.java             (modificado: enriquecido com library info)
└── ChatContextBuilder.java                (modificado: system prompt + context enriquecido)
```

## 8. Casos de Teste

### 8.1 TurboDumpParser

| Teste | Entrada | Esperado |
|-------|---------|----------|
| Construtor de classe | `TAppDictionary::TAppDictionary()` | type=CONSTRUCTOR, class=TAppDictionary |
| Destrutor | `TBitmap::~TBitmap()` | type=DESTRUCTOR, class=TBitmap |
| Método com parâmetros | `TDC::SelectObject(const TPen*)` | type=METHOD, class=TDC, params=const TPen* |
| Método sem parâmetros | `TBitSet::IsEmpty()` | type=METHOD, params=null |
| Função livre | `NColors(unsigned short)` | type=FUNCTION, className=null |
| Bloco sem ordinal | Qualquer não-IMPDEF | Ignorado (não retorna símbolo) |
| Parser chamado 2x | Conteúdo com 1854 IMPDEF | 1854 símbolos retornados |

### 8.2 SymbolResolutionService

| Teste | Setup | Esperado |
|-------|-------|----------|
| Match por ordinal + alias | Import(dll="OWLWI", ordinal=75), LibrarySymbol(ordinal=75, library=L1), Alias("OWLWI"→L1) | resolvedName = "TButtonGadget::Paint(TDC*)" |
| Ordinal zero (nomeado) | Import(ordinal=0) | Não resolvido (pula) |
| Alias não encontrado | Import(dll="UNKNOWN", ordinal=5) | Não resolvido |
| Ordinal não encontrado | Import(dll="OWLWI", ordinal=9999) | Não resolvido |
| Sem bibliotecas carregadas | Nenhuma Library no banco | Nenhum import resolvido |
| Case insensitive alias | Import(dll="owlwi"), Alias("OWLWI") | Resolvido |

### 8.3 EmbeddingChunkBuilder (enriquecido)

| Teste | Setup | Esperado |
|-------|-------|----------|
| Import com resolvedName | StaticImport com resolvedName="TDC::Paint(TDC*)" | Chunk content contém o resolvedName |
| Metadata com library diagnostics | Library + LibrarySymbol carregados | Seção [LIBRARY DIAGNOSTICS] presente |
| Function callees resolvidos | Function com xrefs para imports resolvidos | Callee list mostra class::method [OWL] |

## 9. Rollout e Rollback

- **Nova feature, sem quebra de compatibilidade**: migration adiciona colunas nullable ao `static_import`
- **Sem bibliotecas carregadas**: comportamento idêntico ao atual (resolvedName = null, nenhum chunk afetado)
- **Rollback**: reverter migrations V021 e V022, remover código novo (as APIs novas simplesmente não existiriam mais)
