# Decision Record - VM-Owned Stateful Core Contract ## Status Accepted ## Contexto O runtime ja possui intrinsics VM-owned read-only (input), mas faltava um contrato canonico para recursos VM-owned stateful. Sem esse contrato, cada dominio novo tende a divergir em: - referencia/handle; - lifecycle; - shape de ABI por operacao; - politica de fault/status; - validacao de verifier/disasm. ## Decisao ### 1. Fronteira host-backed permanece inalterada - `HOSTCALL`/`SYSCALL` continuam sendo o caminho host-backed. - Esta decisao nao introduz redesign de host boundary. ### 2. Modelo canonico de recurso stateful - Recurso stateful VM-owned e representado por `HeapRef`. - Validade da referencia segue `index + generation` (anti-stale). - Nao sera introduzido, nesta etapa, um modelo paralelo de handle numerico tipado. ### 3. Lifecycle minimo obrigatorio Todo dominio stateful deve explicitar: - `create`; - `read/query`; - `update`; - `destroy`. ### 4. Forma de invocacao - O caminho de execucao permanece `INTRINSIC `. - Nao ha tabela adicional de pre-load para VM-owned stateful. - IDs finais continuam versionados por operacao. ### 5. Metadata canonica por operacao intrinsic stateful Cada operacao deve declarar, no minimo: - `arg_slots`; - `ret_slots`; - `effect` (read/create/update/destroy); - `determinism`; - `may_allocate`; - `cost_hint`. ### 6. Fault model para VM-owned stateful - `Trap` para erro estrutural (shape de chamada invalido, stale handle, kind invalido). - `status` para falha operacional de dominio. - `Panic` apenas para inconsistencia interna do runtime. ### 7. GC/lifetime e aliasing - Recursos stateful vivem na heap VM e seguem roots normais de GC. - `destroy` existe para encerramento explicito quando o dominio exigir. - Multipla referencia para o mesmo recurso nao muda semantica de ownership; validade segue regras de `HeapRef`. ### 8. Verifier/toolchain/disasm - Verifier deve validar assinatura (`arg_slots`/`ret_slots`) e identidade da operacao. - Disasm deve expor identidade canonica (nome + versao), nao apenas id numerico. - Mudanca breaking exige nova versao da operacao. ### 9. Compatibilidade binaria - Mesma versao de operacao nao muda contrato de slots nem efeito. - Operacao inexistente/incompativel deve falhar em carga/verificacao. ## Estado Atual do Frontend PBS (Studio) Estado observado: - SDK interface ja modela VM-owned builtin surfaces com `declare builtin type` + `IntrinsicCall`. - Lowering ja emite `CALL_INTRINSIC` e pipeline ja converte para opcode `INTRINSIC`. Lacunas relevantes para stateful: - resolucao de intrinsic no frontend ainda e indexada por `sourceMethodName` simples; - ids de intrinsic no frontend ainda usam `hash(canonicalName#version)` como placeholder. Direcao exigida por esta decisao: - resolucao de intrinsic deve considerar identidade canonica sem ambiguidade de receiver; - ids finais de intrinsic devem vir de registry canonico FE/backend/runtime, nao de hash provisoria. ## Exemplos (Ilustrativos, nao normativos) ### Exemplo A - Surface de SDK para random stateful na PBS ```text [BuiltinType(name = "random", version = 1)] declare builtin type Random() { [IntrinsicCall(name = "new", version = 1)] fn new(seed: int) -> RandomRng; } [BuiltinType(name = "random.rng", version = 1)] declare builtin type RandomRng() { [IntrinsicCall(name = "next", version = 1)] fn next() -> int; [IntrinsicCall(name = "destroy", version = 1)] fn destroy() -> int; // status } [BuiltinConst(target = "random", name = "global", version = 1)] declare const Random: Random; ``` ### Exemplo B - Uso em userland PBS ```text import { Random } from @sdk:random; fn tick() -> void { let rng = Random.new(12345); let a = rng.next(); let b = rng.next(); let _s = rng.destroy(); } ``` ### Exemplo C - Contraste de lowering ```text CALL_INTRINSIC random.new@1 CALL_INTRINSIC random.rng.next@1 CALL_INTRINSIC random.rng.destroy@1 ``` No bytecode final: ```text INTRINSIC INTRINSIC INTRINSIC ``` ## Consequencias ### Positivas - cria base unica para dominios stateful VM-owned; - evita proliferacao de protocolos ad hoc por servico; - preserva fronteira host-backed atual; - prepara random como primeiro consumidor sem redesenho posterior. ### Custos - exige evolucao de registry/identity de intrinsic no frontend/backend; - exige endurecimento de verifier/disasm para contrato stateful; - exige disciplina de versionamento por operacao. ## Follow-up Obrigatorio - agenda `011-vm-owned-stateful-core.md` deve ser considerada fechada por esta decisao; - agenda `012-vm-owned-random-service.md` passa a ser o primeiro consumidor desta base; - specs `16`/`16a` devem absorver o contrato stateful quando a implementacao ficar estavel.