prometeu-runtime/docs/runtime/agendas/025-cartridge-manifest-entrypoint-removal-and-runtime-protocol.md

145 lines
7.5 KiB
Markdown

# 025-cartridge-manifest-entrypoint-removal-and-runtime-protocol
Status: Closed
Domain Owner: `runtime`
Cross-Domain Impact: `compiler/PBS`, `firmware`, `loader`, `VM`, `spec 13`
Resolution: materialized as [`../decisions/025-cartridge-manifest-entrypoint-removal-and-runtime-protocol.md`](../decisions/025-cartridge-manifest-entrypoint-removal-and-runtime-protocol.md)
## Contexto
O runtime atual ainda modela `entrypoint` como metadado autoritativo vindo de `manifest.json`.
Esse contrato aparece hoje em mais de uma camada:
- `CartridgeManifest.entrypoint`;
- `CartridgeDTO.entrypoint`;
- `Cartridge.entrypoint`;
- `VirtualMachineRuntime::initialize_vm(...)`, que repassa esse valor para a VM;
- `VirtualMachine::initialize(program_bytes, entrypoint)`, que resolve boot por string nominal, índice numérico ou fallback implícito para a primeira função;
- `VirtualMachine::prepare_call(entrypoint)`, que também aceita string nominal ou índice e cai em `0` como fallback local.
Ao mesmo tempo, a direção nova do compiler/PBS é diferente:
- o compiler publica um wrapper sintético como entrypoint físico do artefato;
- esse wrapper deve ocupar o índice físico `0`;
- o boot deixa de ser escolha configurável em manifesto e passa a ser protocolo fixo do executável.
Isso cria conflito direto entre o contrato atual do runtime e a direção desejada do artefato compilado.
Além disso, a spec vigente ainda normatiza `entrypoint` como campo obrigatório em [`13-cartridge.md`](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/docs/runtime/specs/13-cartridge.md).
## Problema
Precisamos decidir se o runtime deve remover `entrypoint` do contrato do cartucho e endurecer o boot para um protocolo fixo em que a função inicial válida é sempre `func_id = 0`.
O ponto principal nao e apenas remover um campo JSON.
A agenda precisa fechar quem tem autoridade sobre o boot do cartucho:
- se o manifesto continua escolhendo callable inicial;
- ou se o artefato compilado passa a carregar esse contrato de forma estrutural e obrigatoria.
## Pontos Criticos
### Fatos observados
- o loader de diretorio hoje falha sem `manifest.json`, mas nao valida nenhum protocolo de boot alem de desserializar `entrypoint`;
- a VM aceita tres formas de boot no init: string vazia, indice numerico textual e nome de export;
- `prepare_call()` tem fallback local para `0`, o que mantem comportamento implicito mesmo fora do boot inicial;
- o runtime system ainda rastreia `current_entrypoint`, reforcando que a escolha de callable continua exposta como estado;
- a spec atual do cartucho ainda descreve `entrypoint` como obrigatorio.
### Riscos
- manter `entrypoint` no manifesto preserva autoridade duplicada entre runtime e compiler;
- aceitar nome de export, indice textual e fallback vazio enfraquece determinismo e piora observabilidade de erro;
- deixar compatibilidade transitoria mal definida cria zona cinzenta entre cartucho legado e protocolo novo;
- endurecer o protocolo sem erro canonico claro pode produzir falhas opacas de bootstrap.
### Tradeoffs
- remover `entrypoint` simplifica o contrato e centraliza a autoridade no artefato, mas exige propagacao coordenada em spec, loader, system e VM;
- manter compatibilidade temporaria reduz friccao de migracao, mas prolonga um contrato que ja ficou estruturalmente errado;
- rejeitar manifestos legados cedo reduz ambiguidade, mas pode bloquear artefatos intermediarios durante a virada de pipeline.
### Hipoteses que precisam ser assumidas explicitamente
- o compiler/PBS realmente consegue garantir `func_id = 0` como wrapper fisico estavel do programa publicado;
- exports nominais continuam existindo para linking, debug ou introspection, mas deixam de participar da autoridade de boot;
- o runtime nao precisa mais expor escolha textual de entrypoint depois da migracao.
## Opcoes
### Opcao A - Manter `entrypoint` no manifesto como autoridade de boot
O runtime continua lendo `manifest.json` e escolhendo o callable inicial por string ou indice textual.
Consequencia:
- preserva o modelo atual;
- continua divergindo da direcao do compiler;
- mantem duplicidade de autoridade e superficie de erro desnecessaria.
### Opcao B - Remover `entrypoint` do manifesto e migrar o boot para protocolo fixo em `func_id = 0`
O loader deixa de carregar `entrypoint`, a VM endurece o init para boot protocolar e o runtime deixa de rastrear entrypoint textual como parte do contrato.
Consequencia:
- o artefato compilado vira a unica autoridade de boot;
- o manifesto volta a ser metadata de pacote, nao controle de execucao;
- exige plano de transicao explicito para cartuchos legados.
### Opcao C - Manter `entrypoint` apenas como compatibilidade, mas ignorar no runtime novo
O manifesto antigo continua aceito por algum tempo, porem `entrypoint` vira campo sem efeito operacional.
Consequencia:
- reduz quebra imediata;
- mas preserva ambiguidade documental e risco de produtores continuarem emitindo dado morto.
## Sugestao / Recomendacao
Adotar `Opcao B`, sem compatibilidade transitoria normativa no runtime.
Direcao recomendada:
1. o contrato final do cartucho remove `entrypoint` de `manifest.json`;
2. o boot do programa passa a ser sempre protocolar em `func_id = 0`;
3. `CartridgeManifest`, `CartridgeDTO` e `Cartridge` deixam de carregar `entrypoint`;
4. `VirtualMachine::initialize(...)` deve endurecer para init sem parametro textual de entrypoint;
5. `VirtualMachineRuntime` deixa de rastrear `current_entrypoint` como estado de boot;
6. exports nominais continuam permitidos para linking/introspection, mas deixam de participar do boot;
7. cartucho que nao oferecer funcao valida em `0` deve falhar com erro canonico de inicializacao, sem fallback implicito para outra funcao.
Compatibilidade recomendada:
- o runtime nao deve manter compatibilidade para cartuchos legados baseados em `entrypoint`;
- a unica excecao pratica do ciclo atual e manter o stress test rodando ate a propagacao correspondente no gerador;
- essa excecao nao muda o contrato final e nao deve virar regra normativa de runtime.
## Perguntas Resolvidas
1. Compatibilidade transitoria:
nao deve existir no runtime como contrato. A migracao deve ser feita no producer pipeline. A excecao pragmatica do ciclo e apenas nao quebrar o stress test antes da propagacao do gerador correspondente.
2. Erro canonico:
a falha de boot protocolar em `func_id = 0` deve reutilizar `VmInitError::EntrypointNotFound`, agora com semantica endurecida para "entrypoint protocolar ausente ou invalido".
3. `prepare_call()`:
o endurecimento obrigatorio desta agenda cobre o boot do cartucho. A eventual permanencia ou remocao de exports nominais em `prepare_call()` para chamadas nao relacionadas a boot fica fora do fechamento arquitetural desta agenda e pode ser tratada em ciclo separado, desde que nao preserve autoridade textual de boot.
4. Dependencia de `current_entrypoint`:
o codigo atual nao revela dependencia host/debug relevante alem do proprio caminho de boot do runtime. O estado existe hoje para alimentar `vm.prepare_call(&self.current_entrypoint)` e para testes associados, nao como contrato externo autonomo.
## Criterio para Encerrar
Esta agenda ja possui definicao suficiente para virar `decision`, com os seguintes pontos fechados:
- contrato final de `manifest.json` sem `entrypoint`;
- ausencia de compatibilidade normativa no runtime para cartuchos legados;
- contrato da VM e do runtime para boot fixo em `func_id = 0`;
- reutilizacao de `VmInitError::EntrypointNotFound` como erro canonico;
- e propagacao minima esperada para `spec 13`, loader, system, VM e testes.