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

8.7 KiB

id ticket title status created resolved decision tags
AGD-0023 studio-play-stop-cartridge-flow Play/Stop integration agenda for build/pack freshness-gated runtime preparation in_progress 2026-04-06 2026-04-06 DEC-0020
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

  • 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.
  • 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/.
  • 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.
  • 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.
  • 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.
  • 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.