prometeu-studio/discussion/workflow/agendas/AGD-0023-studio-play-stop-shipper-phase-1.md

133 lines
8.7 KiB
Markdown

---
id: AGD-0023
ticket: studio-play-stop-cartridge-flow
title: Play/Stop integration agenda for build/pack freshness-gated runtime preparation
status: in_progress
created: 2026-04-06
resolved: 2026-04-06
decision: DEC-0020
tags: [studio, play-stop, build, pack, compiler, packer, manifest]
---
## Pain
O botão `Play` do Studio hoje só alterna estado visual no shell.
Ele ainda não aciona um fluxo operacional real para preparar um conjunto executável de artefatos em `build/`.
Isso deixa o shell com uma affordance de execução sem pipeline correspondente e sem um contrato claro entre:
- Studio shell,
- compiler build,
- compiler,
- packer,
- e a pasta `build/` do projeto.
## Context
Domain owner: `studio`.
Subdomínios referenciados: `compiler`, `packer`, `runtime`.
Já existe um `ShipperWorkspace` no Studio e ele hoje chama `BuilderPipelineService.INSTANCE.build(...)`, mas esse fluxo atual é apenas um scratch inicial.
Na prática, hoje ele está compilando bytecode e não deve ser tratado como o contrato definitivo de preparação de runtime do produto.
O objetivo desta agenda não é fechar um pipeline de shipping nem materializar um `cartridge/` separado.
O escopo desta wave é estritamente o mínimo necessário para o botão `Play` conseguir preparar artefatos rodáveis em `build/`:
1. compilar o PBX necessário;
2. executar o packer necessário;
3. manter ou regenerar os artefatos de `build/` conforme frescor;
4. gerar `manifest.json` em `build/`.
Essa agenda trata apenas da preparação dos artefatos em `build/`.
A execução `runtime run cartridge` ou equivalente apontando para `build/` fica em agenda separada dentro da mesma discussion.
## Open Questions
- [x] O `Play` deve reutilizar exatamente o mesmo pipeline já acionado pelo `ShipperWorkspace`, ou deve haver um service/application layer dedicado para o shell chamar e o workspace apenas consumir?
- Resposta proposta: `Play` não deve reaproveitar o scratch atual do `ShipperWorkspace`; ele deve orquestrar chamadas explícitas de `build` e `pack`, cada uma com sua própria política de frescor.
- [x] Os artefatos rodáveis desta wave devem viver em `cartridge/` separado ou no próprio `build/`?
- Resposta proposta: nesta wave o artifact root runnable deve ser `build/`; não há necessidade de materializar um `cartridge/` separado se o runtime pode consumir o mesmo contrato diretamente de `build/`.
- [x] Quem decide se é necessário recompilar ou repackar quando o usuário aperta `Play`?
- Resposta proposta: nesta wave, `Play` sempre chama `build` e `pack`; a política fina de drift/freshness fica explicitamente adiada para uma segunda etapa. Quando essa segunda etapa existir, cada domínio será owner de sua própria política de frescor.
- [x] Onde deve viver o controle fino de frescor e drift para os artefatos produzidos?
- Resposta proposta: quando a wave de drift existir, o controle fino viverá em arquivos dedicados por domínio sob `.studio/`, começando por `asset-workspace.json` e `editor-workspace.json`, separados do snapshot principal de restauração.
- [x] O `manifest.json` runtime-facing deve ser derivado do `prometeu.json` do projeto com normalização adicional do Studio, ou copiado quase diretamente com apenas os campos estritamente runtime-facing?
- Resposta proposta: o `manifest.json` deve ser sempre gerado de forma determinística em `build/`, a partir do build corrente e do owner metadata do projeto, sem cópia por conveniência.
- [x] Como o shell distinguirá falha de build, falha de pack e falha de manifest para refletir estado útil no `Play/Stop`?
- Resposta proposta: para o `Play`, basta distinguir `success` e `failed`; logs detalhados das operações devem acompanhar o resultado. `build` falhando bloqueia `pack`, e `manifest` só roda depois do sucesso do build/pack desta wave.
## Options
### Option A - `Play` sempre chama `build` e `pack`, e drift fica para uma wave posterior
- **Approach:** Fazer o shell chamar explicitamente `build` e `pack` em toda execução de `Play`; nesta wave não há reuse por drift/freshness, apenas execução determinística com logs e geração final de `manifest.json`.
- **Pro:** Destrava a integração do `Play` com o menor contrato correto, sem antecipar um sistema de freshness ainda não normatizado.
- **Con:** Pode refazer trabalho desnecessário em execuções sucessivas até a wave de drift existir.
- **Maintainability:** Boa, porque mantém o `Play` simples agora e deixa a otimização para uma agenda própria depois.
### Option B - `Play` inspeciona artefatos existentes e decide por conta própria se pode seguir
- **Approach:** O shell observa presença ou timestamps de artefatos em `build/` e tenta inferir se basta reutilizar o que já existe.
- **Pro:** Menos modelagem inicial de metadata e contratos.
- **Con:** Move para o shell uma inteligência que pertence aos domínios de compiler e packer, além de abrir espaço para reuse incorreto sob drift parcial do workspace.
- **Maintainability:** Fraca, porque o `Play` vira owner implícito de políticas que não são dele.
## Discussion
O ponto central aqui não é apenas "rodar compile + packer".
O problema real é separar claramente:
- a orquestração do `Play`,
- a responsabilidade de `build`,
- a responsabilidade de `pack`,
- e a futura política de frescor de cada artefato.
Se o `Play` inferir por conta própria se precisa rebuildar ou repackar, o shell passa a absorver conhecimento que pertence a outros domínios.
Isso cria uma fronteira errada: o shell deixa de ser apenas o caller de operações e passa a ser o árbitro de drift do projeto.
Ao mesmo tempo, modelar agora um sistema fino de drift adicionaria complexidade antes da própria integração básica do `Play` existir.
Por isso, esta agenda fecha a wave 1 com execução sempre explícita e adia a otimização de freshness para uma agenda própria.
O contrato mais limpo é:
1. `Play` pede `build`;
2. `build` executa e retorna `success` ou `failed`, acompanhado de logs;
3. `Play` pede `pack`;
4. `pack` executa e retorna `success` ou `failed`, acompanhado de logs;
5. `manifest.json` é sempre regenerado em `build/` a partir do build corrente e dos metadados do projeto;
6. `Play` só verifica sucesso ou falha dessas operações antes de seguir para a execução.
Os constraints já visíveis no repositório reforçam esse recorte:
- o compiler atual escreve `build/program.pbx`;
- o packer atual escreve `build/assets.pa` e companions de tooling, e o spec do packer afirma explicitamente que cartridge assembly não pertence ao domínio `packer`;
- os projetos de teste já mostram `build/` contendo `program.pbx`, `assets.pa` e companions;
- `ProjectLocalStudioSetup` já está carregado na `StudioProjectSession`, então o shell já possui o owner correto para coordenar preparation + future run sem precisar deduzir drift por presença oportunista de arquivo.
Isso torna a fronteira recomendada mais concreta:
1. `build/` é o artifact root runnable desta wave;
2. compiler e packer continuam donos de seus artefatos dentro de `build/`;
3. `Play` não usa presença de arquivo como regra de validade;
4. drift e freshness ficam explicitamente fora do escopo desta wave e poderão viver em arquivos dedicados por domínio sob `.studio/`;
5. o shell avança apenas quando `build`, `pack` e `manifest` reportarem sucesso.
A recomendação inicial desta agenda é:
1. fazer `Play` chamar explicitamente `build` e `pack`;
2. manter `build` e `pack` como operações domain-owned com logs e resultado binário de sucesso/falha nesta wave;
3. adiar o controle fino de drift/freshness para uma agenda própria posterior;
4. promover `build/` como artifact root runnable desta wave;
5. gerar `manifest.json` em `build/` sempre a partir do build corrente;
6. tratar o resultado de cada operação como contrato explícito para o `Play`, sem heurística oportunista baseada apenas em presença de arquivo.
## Resolution
Próximo passo sugerido: fechar uma decision de `studio` que trave o fluxo de preparação do `Play/Stop` com estas amarras normativas já explícitas:
1. `Play` é apenas o orquestrador de `build`, `pack` e `manifest`;
2. nesta wave, `build` sempre executa quando chamado pelo `Play`;
3. nesta wave, `pack` sempre executa quando chamado pelo `Play`, e só é chamado se `build` tiver sucesso;
4. o artifact root runnable desta wave é `build/`, não `cartridge/`;
5. `manifest.json` é sempre gerado deterministicamente em `build/`, a partir do build corrente, e não copiado por conveniência;
6. freshness e drift ficam fora do escopo desta wave e, quando tratados, usarão arquivos dedicados por domínio sob `.studio/`, como `asset-workspace.json` e `editor-workspace.json`;
7. `Play` só segue adiante quando as operações necessárias reportarem sucesso.