prometeu-runtime/docs/specs/pbs/files/PRs para Junie.md
2026-03-24 13:40:24 +00:00

956 lines
24 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Prometeu — PR Plan (Arena-Driven) para um LSP Completo
---
# **PR-00.X — Reorganização estrutural do workspace (préArena / préLSP)**
> **Objetivo macro:** separar *modelo/ABI*, *execução*, *kernel* e *tooling* antes de qualquer refator arena-driven.
>
> **Regra de ouro:** nenhuma mudança de comportamento. Apenas **movimentação de código + ajuste de dependências**.
>
> **Modelo final alvo:**
>
> * `prometeu-bytecode` ✅ (fica)
> * `prometeu-abi` ✅ (novo — ex-`prometeu-core` sem execução)
> * `prometeu-vm` ✅ (novo)
> * `prometeu-kernel` ✅ (novo)
> * `prometeu-runtime-desktop` ✅ (fica)
> * `prometeu-compiler` ✅ (fica)
> * `prometeu` (CLI) ✅ (fica agregando)
---
> **Meta do Nilton / Junie workflow**: PRs extremamente prescritivos. A Junie só implementa; você revisa o design **antes** do código.
>
> **Regra de ouro:** cada PR abaixo vem com:
>
> 1. Arquivos/alvos exatos
> 2. Estruturas e assinaturas obrigatórias
> 3. Esquemas JSON (quando aplicável)
> 4. Testes (golden + unit)
> 5. Critérios de aceite “binário” (passou/não passou)
---
## Estado atual (confirmado pelo repo)
Workspace (Archive.zip) tem crates:
* `prometeu/`
* `prometeu-bytecode/`
* `prometeu-core/`
* `prometeu-compiler/` (bin `src/main.rs`, deps: `serde`, `serde_json`, `anyhow`, `clap`, e família `oxc_*`).
**Saída atual existente:** `symbols.json` (schema_version 0), exportando símbolos por projeto, com `decl_span` em `line/col` e paths absolutos. (Vamos evoluir isso no PR-07.)
---
## Visão de arquitetura alvo
### Camadas
1. **FileDB**: texto, URI/path, line-index, snapshots.
2. **Lexer/Parser**: produz **AstArena** (NodeId + spans por nó).
3. **Binder/Resolver**: produz **SymbolArena** + índices (def/ref).
4. **Typecheck**: produz **TypeArena** + facts (node→type, symbol→type).
5. **Analysis Export**: `analysis.json` (full) + `symbols.json` (leve e estável).
6. **LSP Server**: consome `AnalysisDb` e responde requests.
### IDs padronizados (newtypes)
* `FileId(u32)`
* `NodeId(u32)`
* `NameId(u32)` (interner)
* `SymbolId(u32)`
* `TypeId(u32)`
* `ProjectId(u32)`
* `ModuleId(u32)`
### Invariantes
* AST é **imutável** após construção (normativo na spec PBS).
* Nenhuma fase expõe referências diretas entre nós; apenas **IDs**.
* IDs externos são aceitos, mas sempre passam por **validate/resolve** (API checked).
---
# Templates prescritivos para PR (usar em TODAS)
## Template de descrição (copiar/colar)
* **Motivação:**
* **Mudança de modelo de dados:**
* **APIs novas / alteradas:**
* **Arquivos tocados:**
* **Testes adicionados/atualizados:**
* **Riscos & rollback:**
* **Checklist de aceite (binário):**
## Regras para Junie (para reduzir vai-e-volta)
1. Não “inventar design”. Se algo não estiver especificado, **criar TODO** e parar.
2. Não mudar formatação/estilo fora do escopo.
3. Todo novo tipo público precisa de doc-comment curta e exemplo.
4. Toda mudança de JSON precisa:
* `schema_version` bump (se não for backward)
* teste de snapshot
5. Cada PR deve deixar `cargo test` verde.
---
# PRs (detalhados)
## PR-00 — Infra: crates de análise + lsp (estrutura do workspace)
**Branch:** `pr-00-analysis-lsp-foundations`
### Decisão travada (LSP)
* **Biblioteca escolhida:** `tower-lsp`
* **Motivo:** reduzir boilerplate, acelerar MVP e minimizar vai-e-volta. Cancelamento/incremental será feito **por cima** (tasks async + cancel tokens).
### Objetivo
Adicionar crates novas sem mexer no pipeline existente.
### Entregas obrigatórias
1. **Novo crate:** `prometeu-analysis/`
* `Cargo.toml` (library)
* `src/lib.rs`
2. **Novo crate:** `prometeu-lsp/`
* `Cargo.toml` (bin)
* `src/main.rs`
3. Workspace root: ajustar `Cargo.toml` (se existir no root) para incluir members.
### Dependências (fixas)
* `prometeu-analysis`: `serde`, `serde_json`
* `prometeu-lsp`:
* `tower-lsp = "0.20"` (ou versão estável atual)
* `tokio` (full)
* `prometeu-analysis` (path)
### Esqueleto obrigatório (`prometeu-lsp/src/main.rs`)
```rust
use tower_lsp::{LspService, Server};
use tokio::sync::RwLock;
use std::sync::Arc;
#[derive(Default)]
struct AnalysisDb {
// FileDB, AstArena, SymbolArena, TypeArena, Diagnostics
}
struct Backend {
db: Arc<RwLock<AnalysisDb>>,
}
#[tower_lsp::async_trait]
impl tower_lsp::LanguageServer for Backend {
async fn initialize(&self, _: tower_lsp::lsp_types::InitializeParams)
-> tower_lsp::jsonrpc::Result<tower_lsp::lsp_types::InitializeResult> {
Ok(tower_lsp::lsp_types::InitializeResult {
capabilities: tower_lsp::lsp_types::ServerCapabilities {
text_document_sync: Some(tower_lsp::lsp_types::TextDocumentSyncCapability::Kind(
tower_lsp::lsp_types::TextDocumentSyncKind::FULL,
)),
// Declaramos capacidades desde já para evitar churn posterior.
definition_provider: Some(true.into()),
document_symbol_provider: Some(true.into()),
workspace_symbol_provider: Some(true.into()),
hover_provider: Some(true.into()),
references_provider: Some(true.into()),
rename_provider: Some(tower_lsp::lsp_types::OneOf::Left(true)),
completion_provider: Some(tower_lsp::lsp_types::CompletionOptions {
resolve_provider: Some(false),
trigger_characters: Some(vec![".".into(), ":".into()]),
..Default::default()
}),
semantic_tokens_provider: Some(
tower_lsp::lsp_types::SemanticTokensServerCapabilities::SemanticTokensOptions(
tower_lsp::lsp_types::SemanticTokensOptions {
legend: tower_lsp::lsp_types::SemanticTokensLegend {
// preenchido no PR-12
token_types: vec![],
token_modifiers: vec![],
},
full: Some(tower_lsp::lsp_types::SemanticTokensFullOptions::Bool(true)),
range: None,
..Default::default()
},
),
),
..Default::default()
},
..Default::default()
})
}
async fn initialized(&self, _: tower_lsp::lsp_types::InitializedParams) {}
}
#[tokio::main]
async fn main() {
let stdin = tokio::io::stdin();
let stdout = tokio::io::stdout();
let (service, socket) = LspService::new(|_| Backend { db: Arc::new(RwLock::new(AnalysisDb::default())) });
Server::new(stdin, stdout, socket).serve(service).await;
}
```
### Contrato exato do AnalysisDb (travado)
> **Regra:** o LSP nunca recalcula segurando `RwLock` por muito tempo. Toda análise pesada roda fora do lock e depois faz swap.
Criar arquivo: `prometeu-lsp/src/analysis_db.rs`
```rust
use std::sync::Arc;
use tokio::sync::RwLock;
use tokio_util::sync::CancellationToken;
use prometeu_analysis::FileDB;
#[derive(Default)]
pub struct AnalysisDb {
pub file_db: FileDB,
// Os campos abaixo serão conectados conforme PR-03/04/05 (podem começar como None)
// pub ast: Option<AstArena>,
// pub symbols: Option<SymbolArena>,
// pub types: Option<TypeArena>,
// pub diagnostics: Vec<Diagnostic>,
/// Incrementa a cada rebuild concluído com sucesso
pub revision: u64,
/// Cancel token do último rebuild em progresso (se houver)
pub active_rebuild: Option<CancellationToken>,
}
pub type SharedDb = Arc<RwLock<AnalysisDb>>;
```
No `main.rs`, **substituir** o `AnalysisDb` local pelo import acima (ou manter local e delegar, mas sem duplicar).
### Modelo de cancelamento e coalescing (travado)
> Objetivo: quando chegam múltiplos `didChange` em sequência, cancelar o rebuild anterior e rodar apenas o último.
Adicionar dependência fixa em `prometeu-lsp/Cargo.toml`:
* `tokio-util`
Criar arquivo: `prometeu-lsp/src/rebuild.rs`
```rust
use tokio_util::sync::CancellationToken;
use crate::analysis_db::SharedDb;
/// Solicita rebuild do projeto (coarse). Cancela rebuild anterior se em progresso.
/// Implementação inicial: apenas cria task e retorna.
pub async fn request_rebuild(db: SharedDb) {
// 1) lock curto: cancelar token anterior e instalar token novo
// 2) spawn task: roda análise fora do lock
// 3) lock curto: se token não cancelado, swap estado + revision++
}
```
Regras obrigatórias:
1. `request_rebuild` deve:
* cancelar `active_rebuild` anterior (se existir)
* instalar um token novo
* `tokio::spawn` uma task de rebuild
2. A task deve checar `token.is_cancelled()` em pontos seguros:
* antes de começar
* após parsing
* após resolver
* após typecheck
3. O lock (`RwLock`) deve ser segurado apenas:
* para trocar `active_rebuild`
* para aplicar o resultado final
### Critérios de aceite
* `cargo build -p prometeu-lsp` ok
* LSP inicializa em VS Code/Neovim sem crash
* Nenhuma feature além do declarado
---
## Política fixa de cancelamento e rebuild (tower-lsp)
### Objetivo
Garantir que edições rápidas não gerem backlog de análises e evitar race conditions.
### Decisão travada
* Usar `tokio_util::sync::CancellationToken`
* **Um token por rebuild**
* Qualquer `didChange`:
1. Cancela o rebuild anterior
2. Cria novo token
3. Agenda nova task de análise
### Estruturas obrigatórias
```rust
use tokio_util::sync::CancellationToken;
struct AnalysisController {
current: Option<CancellationToken>,
}
```
### Regras
* Nunca segurar `RwLock<AnalysisDb>` durante parsing/resolver/typecheck.
* Fluxo correto:
1. Clonar snapshot dos textos (FileDB)
2. Soltar lock
3. Rodar análise pesada
4. Re-adquirir lock e substituir estado
* Tasks devem checar `token.is_cancelled()` entre fases (parse / bind / type).
### Critérios de aceite
* Digitar rapidamente não acumula tasks.
* Apenas o último estado publica diagnostics.
---
## Contrato fechado do AnalysisDb (fonte de verdade do LSP)
### Objetivo
Eliminar ambiguidade sobre o que vive no estado compartilhado.
### Estrutura obrigatória
```rust
#[derive(Default)]
pub struct AnalysisDb {
pub files: FileDB,
pub ast: Option<AstArena>,
pub symbols: Option<SymbolArena>,
pub types: Option<TypeArena>,
pub type_facts: Option<TypeFacts>,
pub diagnostics: Vec<Diagnostic>,
}
```
### Regras
* `AnalysisDb` **nunca** armazena estado parcialmente válido.
* Se uma fase falhar:
* `ast/symbols/types` podem ficar `None`
* `diagnostics` deve estar preenchido
* LSP handlers **não** rodam análise: apenas leem `AnalysisDb`.
### Leitura segura
* Todos os handlers (`definition`, `hover`, `references`, etc.) devem:
* adquirir `db.read()`
* lidar com `Option::None` retornando `null` / resposta vazia
### Escrita segura
* Apenas a task de rebuild escreve no `AnalysisDb`.
* Escrita sempre substitui o estado inteiro (swap lógico).
### Critérios de aceite
* Nenhum handler pode panic por `None`.
* Rebuild substitui estado de forma atômica (do ponto de vista do LSP).
---
# Série PR-00.X — Reestruturação de crates (Arena-Driven + LSP-ready)
> **Objetivo da série PR-00.X:** reorganizar o workspace em crates com fronteiras claras, **sem alterar comportamento**, preparando o terreno para o Prometeu Arena-Driven (compiler/analysis) e um LSP completo depois.
>
> **Novo layout alvo (travado):**
>
> * `prometeu-bytecode` (fica)
> * `prometeu-abi` (novo nome para o atual `prometeu-core` depurado) = **types + model + protocols** (sem execução)
> * `prometeu-vm` (novo) = execução da VM
> * `prometeu-kernel` (novo) = OS + FS + syscalls (implementa interface para a VM)
> * `prometeu-runtime-desktop` (fica) = host desktop
> * `prometeu-compiler` (fica)
> * `prometeu` (CLI) (fica)
>
> **Regra de ouro:** 1 PR = 1 fronteira. Nada de mover tudo de uma vez.
>
> **Regras para Junie (serie 00.X):**
>
> 1. **Não mudar lógica**; apenas mover, ajustar imports, e deixar testes verdes.
> 2. Se algo exigir mudança de API pública, criar `TODO(PR-00.Y)` e parar.
> 3. Sempre manter o workspace compilável a cada PR.
---
## PR-00.3 — Extrair `prometeu-kernel` (OS + FS + syscalls)
**Branch:** `pr-00-3-prometeu-kernel`
### Objetivo
Mover `prometeu_os/*` + `fs/*` (e qualquer dispatcher de syscalls) para `crates/prometeu-kernel/`.
### Passos prescritivos
1. Criar crate `crates/prometeu-kernel/`.
2. Mover:
* `crates/prometeu-core/src/prometeu_os/**``crates/prometeu-kernel/src/**`
* `crates/prometeu-core/src/fs/**``crates/prometeu-kernel/src/fs/**`
3. Garantir que o kernel **depende** de:
* `prometeu-abi`
* `prometeu-vm`
4. Garantir que a VM chama syscalls via interface implementada pelo kernel.
5. Manter shim temporário no `prometeu-core` (se existir): `pub mod prometeu_os { pub use prometeu_kernel::*; }`
### Critérios de aceite
* `cargo test` verde.
* Sem mudança comportamental (mesmo conjunto de syscalls e traps).
---
## PR-00.4 — Depurar `prometeu-core`: remover execução e virar apenas compat layer
**Branch:** `pr-00-4-deprecate-prometeu-core`
### Objetivo
Eliminar o conteúdo executável restante do `prometeu-core`, deixando-o como reexport/compat por um curto período.
### Passos
* `hardware` e `firmware/hub` ficam onde estiverem por enquanto (podem virar PR-00.5/00.6 se necessário)
* `prometeu-core` passa a reexportar:
* `prometeu-abi`
* `prometeu-vm`
* `prometeu-kernel`
### Critérios
* Zero imports internos `crate::virtual_machine` etc. fora da facade.
---
## PR-00.5 — (Opcional) Extrair `prometeu-firmware` (hub/boot)
**Branch:** `pr-00-5-prometeu-firmware`
### Objetivo
Mover `firmware/*` + `prometeu_hub/*` para `crates/prometeu-firmware/`.
### Critérios
* runtime desktop depende de `prometeu-firmware`.
---
## PR-00.6 — Remover `prometeu-core` e migrar consumidores
**Branch:** `pr-00-6-remove-prometeu-core`
### Objetivo
Apagar `prometeu-core` após migração total.
### Critérios
* Nenhum crate depende de `prometeu-core`.
---
## PR-01 — FileDB + LineIndex (base do LSP e spans)
**Branch:** `pr-01-filedb`
### Objetivo
Criar uma base de arquivos com IDs estáveis na sessão e conversão offset<->(line,col).
### Arquivos / módulos
* `prometeu-analysis/src/file_db.rs`
* `prometeu-analysis/src/span.rs`
* `prometeu-analysis/src/ids.rs`
* `prometeu-analysis/src/lib.rs` (re-exports)
### Estruturas obrigatórias
```rust
// prometeu-analysis/src/ids.rs
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
pub struct FileId(pub u32);
// prometeu-analysis/src/span.rs
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct Span {
pub file: FileId,
pub start: u32, // byte offset
pub end: u32, // byte offset, exclusive
}
// prometeu-analysis/src/file_db.rs
pub struct FileDB {
// map uri->id, id->uri/text/line_index
}
pub struct LineIndex {
// stores line start offsets
}
```
### Regras
* Spans são **byte offsets UTF-8** (`start` inclusive, `end` exclusive) — alinhado ao Canonical Addenda.
* `LineIndex` deve lidar com `
` (LF). (CRLF pode ser normalizado na entrada.)
### APIs obrigatórias
```rust
impl FileDB {
pub fn upsert(&mut self, uri: &str, text: String) -> FileId;
pub fn file_id(&self, uri: &str) -> Option<FileId>;
pub fn uri(&self, id: FileId) -> &str;
pub fn text(&self, id: FileId) -> &str;
pub fn line_index(&self, id: FileId) -> &LineIndex;
}
impl LineIndex {
pub fn offset_to_line_col(&self, offset: u32) -> (u32, u32);
pub fn line_col_to_offset(&self, line: u32, col: u32) -> Option<u32>;
}
```
### Testes obrigatórios
* `tests/file_db_line_index.rs` (unit)
* roundtrip offset->(l,c)->offset
* bordas (start/end, EOF)
### Critérios de aceite
* Testes passam.
* Nenhuma mudança no output do `prometeu-compiler` ainda.
---
## PR-02 — NameInterner (NameId) e eliminação de String no hot path
**Branch:** `pr-02-name-interner`
### Objetivo
Trocar identificadores em AST/resolver de `String` para `NameId`.
### Arquivos
* `prometeu-analysis/src/interner.rs`
* Ajustar frontend PBS no `prometeu-compiler` (ver lista de toques abaixo).
### Estruturas obrigatórias
```rust
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
pub struct NameId(pub u32);
pub struct NameInterner {
// bidirectional: string->id, id->string
}
```
### APIs obrigatórias
```rust
impl NameInterner {
pub fn new() -> Self;
pub fn intern(&mut self, s: &str) -> NameId;
pub fn resolve(&self, id: NameId) -> &str;
}
```
### Regras
* Interner é **session-local**.
* `resolve` deve retornar `&str` estável (armazenar `String` internamente).
### Touch points no `prometeu-compiler`
* Onde hoje existe `String` como nome de símbolo, token de identifier, etc:
* AST nodes de `Ident`
* Resolver scopes: `HashMap<NameId, _>`
### Testes
* Unit: intern/resolve, dedup
* Golden: manter comportamento de resolver/diags
### Critérios de aceite
* Redução de `String` em estruturas hot (resolver)
* Build e testes ok.
---
## PR-03 — AST Arena (NodeId) para PBS
**Branch:** `pr-03-ast-arena`
### Objetivo
Refatorar o AST PBS (atualmente recursivo) para uma arena `Vec` com `NodeId`.
### Alvos no repo
* `prometeu-compiler/src/frontends/pbs/*` (localizar AST/parser atuais)
### Estruturas obrigatórias
```rust
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
pub struct NodeId(pub u32);
pub struct AstArena {
pub nodes: Vec<NodeKind>,
pub spans: Vec<prometeu_analysis::Span>,
pub roots: Vec<NodeId>,
}
pub enum NodeKind {
File { imports: Vec<NodeId>, decls: Vec<NodeId> },
Import { /* ... */ },
FnDecl { name: NameId, /* ... */, body: NodeId },
// ... (conforme canonical AST do PBS)
}
```
### Regras
* `AstArena::push(kind, span) -> NodeId` sempre faz append.
* `spans.len() == nodes.len()` sempre.
### APIs obrigatórias
```rust
impl AstArena {
pub fn push(&mut self, kind: NodeKind, span: Span) -> NodeId;
pub fn kind(&self, id: NodeId) -> &NodeKind;
pub fn span(&self, id: NodeId) -> Span;
}
```
### Testes obrigatórios
* Parser golden tests: comparar JSON canonical (se você já tem) ou snapshots equivalentes.
* Unit: invariantes (push mantém alinhamento).
### Critérios de aceite
* Nenhum `Box<Node>` em AST PBS.
* Resolver e typechecker passam a consumir NodeId.
---
## PR-04 — SymbolArena + índices (defs/refs) + node→symbol
**Branch:** `pr-04-symbol-arena-index`
### Objetivo
Criar `SymbolArena` e índices para features de LSP sem traversal pesado.
### Estruturas obrigatórias
```rust
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
pub struct SymbolId(pub u32);
pub enum SymbolKind { Type, Value, Service, Function /* etc */ }
pub struct Symbol {
pub name: NameId,
pub kind: SymbolKind,
pub exported: bool,
pub module: ModuleId,
pub decl_span: Span,
}
pub struct SymbolArena { pub symbols: Vec<Symbol> }
pub struct DefIndex { /* HashMap<(ModuleId, NameId, Namespace), SymbolId> */ }
pub struct RefIndex { /* Vec<Vec<Span>> by SymbolId */ }
pub struct NodeToSymbol { /* Vec<Option<SymbolId>> by NodeId */ }
```
### APIs obrigatórias
* `insert_symbol(...) -> SymbolId` (falha se duplicate, com diag E_RESOLVE_DUPLICATE_SYMBOL)
* `record_ref(symbol_id, span)`
* `bind_node(node_id, symbol_id)`
### Testes
* Duplicate symbol
* Undefined identifier
* Visibility violations
* Determinismo (mesma input → mesma ordem IDs, quando possível)
---
## PR-05 — TypeArena + TypeFacts (node→type, symbol→type)
**Branch:** `pr-05-type-arena-facts`
### Objetivo
Dar base para hover, completion e erros de tipo.
### Estruturas obrigatórias
```rust
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
pub struct TypeId(pub u32);
pub enum TypeKind {
Primitive { name: NameId },
Struct { sym: SymbolId },
Optional { inner: TypeId },
Result { ok: TypeId, err: TypeId },
Array { inner: TypeId, len: Option<u32> },
// ... conforme v0
}
pub struct TypeArena { pub types: Vec<TypeKind> }
pub struct TypeFacts {
pub node_type: Vec<Option<TypeId>>, // index by NodeId
pub symbol_type: Vec<Option<TypeId>>, // index by SymbolId
}
```
### APIs obrigatórias
* `intern_type(TypeKind) -> TypeId` (dedup opcional; documentar)
* `set_node_type(NodeId, TypeId)`
* `set_symbol_type(SymbolId, TypeId)`
### Testes
* Hover type display snapshots.
---
## PR-06 — Diagnostics canonizados (E_* / W_*)
**Branch:** `pr-06-diagnostics`
### Objetivo
Diagnósticos estáveis e serializáveis, alinhados ao Canonical Addenda (codes).
### Estruturas obrigatórias
```rust
pub enum Severity { Error, Warning }
pub struct Diagnostic {
pub severity: Severity,
pub code: String,
pub message: String,
pub span: Span,
pub related: Vec<(String, Span)>,
}
```
### Regras
* Codes conforme Canonical Addenda (E_PARSE_*, E_RESOLVE_*, E_TYPE_*).
### Testes
* Golden diag JSON determinístico.
---
## PR-07 — Export: `symbols.json` v1 + `analysis.json` v0
**Branch:** `pr-07-analysis-export`
### Objetivo
Separar índice leve (`symbols.json`) e export completo (`analysis.json`).
### Símbolos (novo formato recomendado)
* **IMPORTANTE:** parar de gravar paths absolutos (usar URI relativo ao projeto quando possível).
`symbols.json` v1 (schema_version=1):
* `projects[]`:
* `project` (string)
* `project_dir` (string) (pode ficar absoluto por enquanto)
* `symbols[]`:
* `symbol_id` (u32) **OU** string estável atual (mantém compat)
* `name` (string)
* `kind` (string)
* `exported` (bool)
* `module_path` (string)
* `decl_span`: `{ file_uri, start:{line,col}, end:{line,col} }`
`analysis.json` (schema_version=0):
* `file_table`: [{file_id:u32, uri:string}]
* `symbols`: [{symbol_id:u32, name_id:u32, kind, exported, module_id, decl_span}]
* `refs`: [{symbol_id:u32, spans:[Span]}]
* `types`: [{type_id:u32, kind:...}]
* `facts`: { node_type: [...], symbol_type: [...] }
* `diagnostics`: [Diagnostic]
### Testes
* Snapshot de ambos JSONs.
---
## PR-08 — LSP MVP (diagnostics + symbols + goto definition)
**Branch:** `pr-08-lsp-mvp`
### Objetivo
LSP funcional mínimo usando `AnalysisDb` (em memória), recompilando quando arquivo muda.
### Features
* `initialize`
* `didOpen`/`didChange`/`didClose`
* `publishDiagnostics`
* `documentSymbol` / `workspaceSymbol`
* `definition`
### Regras
* `didChange`: por enquanto full-text (simplifica)
* Rebuild: coarse (projeto inteiro) inicialmente
### Testes
* Test harness: abrir doc e pedir definition.
---
## PR-09 — LSP: references + rename
**Branch:** `pr-09-lsp-refs-rename`
### Objetivo
Baseado em RefIndex e NodeToSymbol.
### Features
* `references`
* `prepareRename`
* `rename`
### Regras de segurança
* Não renomear se símbolo não-resolvido.
* Não renomear se span em comentário/string.
---
## PR-10 — LSP: hover + signatureHelp
**Branch:** `pr-10-lsp-hover-sighelp`
### Features
* `hover`: type + docstring (docstring opcional por enquanto)
* `signatureHelp`: para call nodes (se parser já marca)
---
## PR-11 — LSP: completion
**Branch:** `pr-11-lsp-completion`
### Buckets
* locals em scope (se você tiver scope facts)
* symbols do módulo
* exports importados
* members via type facts
---
## PR-12 — LSP: semantic tokens + highlights
**Branch:** `pr-12-lsp-semantic`
---
## PR-13 — LSP: formatting + code actions (opcional)
**Branch:** `pr-13-lsp-actions`
---
## PR-14 — Incremental analysis + cancelation
**Branch:** `pr-14-incremental`
---
## PR-15 — Debug map (pc→span) + integração com traps
**Branch:** `pr-15-debug-map`
---
---
# Sequência recomendada (travada)
1. PR-00.1 (`prometeu-abi` + compat)
2. PR-00.2 (`prometeu-vm`)
3. PR-00.3 (`prometeu-kernel`)
4. PR-00.4 (depurar `prometeu-core`)
5. PR-00.5 (opcional firmware)
6. PR-00.6 (remover core)
> Após PR-00.X, iniciar a trilha Arena-Driven (PR-01..PR-07) no compiler/analysis.