prometeu-runtime/docs/runtime/decisions/011-assets-pa-autocontained-runtime-contract.md
2026-03-24 13:40:53 +00:00

254 lines
9.2 KiB
Markdown

# Decision Record - `assets.pa` Autocontained Runtime Contract
## Status
Accepted
## Contexto
A agenda `023-asset-packer-runtime-facing-contract.md` existia para fechar a fronteira runtime-facing do packer de assets sem misturar essa discussao com o `shipper` do `.pmc`.
O ponto de partida atual do runtime ainda e fragmentado:
- `manifest.json` carrega `asset_table` e `preload`;
- `assets.pa` contem apenas os bytes packed de payload;
- o loader le `assets.pa` inteiro para memoria;
- o `AssetManager` mantem esse blob inteiro residente.
Ao mesmo tempo, a direcao desejada para o projeto ja esta clara:
- o `packer` continua responsavel por produzir o artefato de assets;
- o `shipper` continua responsavel por publicar `manifest.json` e montar o cart final;
- o runtime deve consumir um `assets.pa` autocontido;
- `asset_table`, `preload` e payload mantem o mesmo conteudo semantico atual;
- o que muda e onde esses artefatos vivem e como o runtime os carrega.
O alvo de hardware do PROMETEU e um handheld de baixo custo. Portanto, manter o blob inteiro de assets em RAM como regra geral nao e um baseline aceitavel.
## Decisao
### 1. `assets.pa` passa a ser o contrato runtime-facing de assets
O contrato primario de assets consumido pelo runtime passa a ser o proprio `assets.pa`.
`manifest.json` deixa de ser a superficie primaria para:
- `asset_table`;
- `preload`.
O runtime continua agnostico a como o `packer` e o `shipper` produzem artefatos auxiliares.
### 2. `assets.pa` v1 e um binario autocontido
`assets.pa` v1 deve ser estruturado como:
```text
[prelude binario fixo]
[header JSON]
[payload binario]
```
O prelude binario fixo v1 contem, no minimo:
- `magic`
- `schema_version`
- `header_len`
- `payload_offset`
Campos opcionais permitidos no prelude v1:
- `flags`
- `reserved`
- `header_checksum`
### 3. O header JSON carrega `asset_table` e `preload`
O header JSON de `assets.pa` e a estrutura que carrega:
- `asset_table`
- `preload`
Essa decisao nao redefine o conteudo semantico dessas estruturas.
Portanto:
- `AssetEntry` permanece a fonte de verdade para identidade, codec, metadata e offsets;
- `PreloadEntry` permanece um insumo de boot;
- o payload packed continua representando os bytes frios dos assets.
### 4. Offsets da `asset_table` sao relativos ao payload
Os `offset`s de `asset_table` permanecem relativos ao inicio da regiao de payload, nao ao inicio do arquivo inteiro.
Isso preserva a semantica atual do runtime e evita contaminar `AssetEntry` com detalhes do envelope externo.
O runtime resolve cada slice como:
```text
payload_base + entry.offset
```
### 5. Lifecycle de `preload` e `asset_table` no runtime
O runtime deve tratar essas duas estruturas de forma diferente:
- `preload` e dado transitorio de boot;
- `asset_table` e a fonte da verdade para resolucao e carregamento de assets.
Contrato operacional:
1. o runtime materializa `manifest.json`;
2. se `Capability::Asset` estiver presente, o runtime exige `assets.pa` valido imediatamente;
3. o runtime abre `assets.pa`, le o prelude e o header JSON;
4. o runtime materializa `asset_table` em memoria;
5. o runtime usa `preload` na fase de boot;
6. apos o boot, `preload` pode ser descartado;
7. `asset_table` permanece viva enquanto o cart estiver rodando.
### 6. Falha antecipada quando `Capability::Asset` exigir `assets.pa`
Cart sem `assets.pa` continuam validos.
Mas, se o `manifest.json` declarar `Capability::Asset`, a ausencia de `assets.pa` deve falhar o mais cedo possivel, antes da fase de preload.
Essa falha pertence ao bootstrap do cart, nao ao lifecycle de `asset.load`.
### 7. Leitura de payload deve ser sob demanda
O runtime nao deve manter o payload inteiro de `assets.pa` residente em memoria como comportamento baseline.
O contrato de leitura do runtime passa a ser baseado em uma primitiva equivalente a:
```text
open_slice(offset, size)
```
Essa primitiva abre uma view limitada para um asset dentro da regiao de payload.
### 8. Pipeline canonico de carregamento de asset
O caminho canonico de carregamento passa a ser:
```text
ROM -> open_slice -> CODEX/decode -> Bank
```
ou, quando o CODEX exigir materializacao temporaria:
```text
ROM -> open_slice -> blob temporario em memoria -> CODEX/decode -> Bank
```
O runtime nunca deve materializar o `assets.pa` inteiro apenas para suportar carregamento de asset.
### 9. `OP_MODE` de consumo do payload
O runtime deve encapsular o modo operacional de consumo do payload por asset.
Esse `OP_MODE` escolhe entre:
- leitura direta da ROM via view limitada;
- materializacao temporaria do slice em memoria.
Direcao v1:
- o `OP_MODE` e derivado do `codec`/CODEX por padrao;
- hint explicito adicional so deve ser introduzido se algum codec real admitir mais de um modo operacional viavel.
### 10. Artefatos auxiliares do packer continuam permitidos
O `packer` pode continuar emitindo artefatos auxiliares para o `shipper`, por exemplo:
- `asset_table.json`;
- relatorios de build;
- hashes;
- inventarios.
Mas esses artefatos:
- sao derivados;
- nao substituem o header interno de `assets.pa`;
- nao definem o contrato runtime-facing.
## Rationale
Esta decisao fecha a ambiguidade central da agenda `023` sem reabrir a semantica do dominio `asset`.
Ela foi escolhida porque:
- separa claramente `packer` e `shipper`;
- reduz dependencia de metadata de asset espalhada em `manifest.json`;
- preserva o shape semantico atual de `asset_table`, `preload` e payload;
- melhora a adequacao do runtime para hardware barato;
- evita carregar o blob inteiro em RAM;
- permite que codecs com diferentes necessidades de IO operem sobre a mesma fronteira de leitura.
O uso de prelude binario pequeno + header JSON foi adotado porque:
- permite localizar o header com custo fixo;
- mantem o header facil de produzir, inspecionar e depurar;
- evita transformar o payload em estrutura textual;
- reduz complexidade editorial no v1.
## Invariantes / Contrato
- `assets.pa` e o contrato runtime-facing de assets.
- `asset_table` e `preload` deixam de ser contrato primario de runtime no `manifest.json`.
- `asset_table` e carregada do header de `assets.pa` e permanece viva durante toda a execucao do cart.
- `preload` e carregado do header de `assets.pa`, usado no boot e descartavel apos a inicializacao.
- payload offsets em `AssetEntry` sao relativos ao inicio da regiao de payload.
- o runtime deve falhar cedo se `Capability::Asset` exigir `assets.pa` e o artefato nao existir.
- o runtime nao deve manter o `assets.pa` inteiro em RAM como baseline.
- o runtime deve expor leitura sob demanda por slice.
- `OP_MODE` de consumo do slice e resolvido pelo runtime a partir do `codec`/CODEX, salvo decisao futura em contrario.
- auxiliares do `packer` para o `shipper` nao tem autoridade normativa sobre o runtime.
## Impactos
### Specs
- `13-cartridge.md` deve mover `asset_table` e `preload` para dentro do contrato de `assets.pa`.
- `15-asset-management.md` deve descrever `assets.pa` como artefato autocontido, separar lifecycle de `preload` e `asset_table`, e registrar offsets relativos ao payload.
- `16-host-abi-and-syscalls.md` so precisa ser tocada se a superficie host/runtime de inicializacao de assets mudar de forma observavel.
### Runtime
- `cartridge_loader.rs` deve deixar de ler `assets.pa` inteiro para `Vec<u8>` como baseline.
- `cartridge.rs` deve parar de tratar `asset_table` e `preload` como dados vindos do `manifest`.
- o bootstrap deve checar cedo a presenca de `assets.pa` quando `Capability::Asset` estiver declarada.
- o `AssetManager` deve manter `asset_table` viva, aplicar `preload` no boot e ler payload por slice sob demanda.
- a leitura atual baseada em `Arc<RwLock<Vec<u8>>>` deve evoluir para uma origem de leitura por ROM/view/slice.
### Shipper / Packer
- o `packer` deve produzir `assets.pa` com prelude + header JSON + payload.
- o `shipper` continua livre para consumir auxiliares JSON, mas deve tratar `assets.pa` como artefato de verdade para assets.
- o `manifest.json` publicado pelo `shipper` deixa de carregar `asset_table` e `preload` como contrato primario de runtime.
### Firmware / Boot
- a etapa de carga do cart deve abrir `assets.pa`, extrair header e decidir falha cedo antes de preload.
- preload deixa de ser atributo editorial do manifest e passa a ser insumo interno do artefato de assets.
## Referencias
- `../specs/13-cartridge.md`
- `../specs/15-asset-management.md`
- `../agendas/008-packed-cartridge-loader-pmc.md`
- `../../../studio/docs/packer/Prometeu Packer.md`
- `../../crates/console/prometeu-hal/src/cartridge_loader.rs`
- `../../crates/console/prometeu-hal/src/cartridge.rs`
- `../../crates/console/prometeu-drivers/src/asset.rs`
## Propagacao Necessaria
- criar PR/plan para atualizar specs `13` e `15`;
- criar PR/plan de codigo para:
- mudar o loader de cart para abrir header de `assets.pa`;
- mover `asset_table`/`preload` para a leitura do binario de assets;
- introduzir leitura sob demanda por slice;
- remover o baseline de payload inteiro residente;
- falhar cedo quando `Capability::Asset` exigir `assets.pa` ausente;
- agenda `023-asset-packer-runtime-facing-contract.md` deve ser considerada fechada e removida da lista de agendas ativas;
- agenda `008-packed-cartridge-loader-pmc.md` passa a depender desta decisao como base do artefato de assets.