--- id: AGD-0024 ticket: studio-play-stop-cartridge-flow title: Play/Stop integration agenda for runtime execution from build using project runtime setup status: in_progress created: 2026-04-06 resolved: 2026-04-06 decision: DEC-0021 tags: [studio, runtime, play-stop, build, process, project-setup] --- ## Pain Mesmo depois que o Studio conseguir preparar `build/`, o botão `Play` continuará incompleto sem um contrato claro para executar o runtime configurado no projeto contra esse artifact root. Hoje o caminho do runtime já existe em `.studio/setup.json` via `ProjectLocalStudioSetup.prometeuRuntimePath`, mas esse valor ainda não participa de nenhuma execução real no shell. Sem essa definição, o `Play/Stop` corre o risco de virar: - um botão que prepara `build/` mas não executa nada; - ou um launcher improvisado, sem owner claro para processo, logs, lifecycle e falhas. ## Context Domain owner: `studio`. Subdomínios referenciados: `runtime`. O Studio já carrega `ProjectLocalStudioSetup` na `StudioProjectSession`. Portanto o runtime configurado por projeto já está disponível para consumo em runtime de aplicação. Após a decisão `DEC-0020`, esta agenda passa a assumir explicitamente que: - `Play` prepara `build/` como artifact root runnable; - `manifest.json` é gerado em `build/`; - não há `cartridge/` separado nesta wave. O comando desejado pelo usuário é conceitualmente: `runtime run build` usando o runtime configurado no projeto atual. Esta agenda não rediscute preparação de `build/`. Ela assume a saída de `DEC-0020` como pré-condição e foca no segundo passo do `Play`: iniciar, observar e interromper o processo de runtime. Também há um constraint de UX desta wave: - ao apertar `Play`, o usuário deverá ser levado para o futuro `DebuggerWorkspace`, mesmo que essa surface ainda não esteja construída; - até essa surface existir, os logs do runtime precisarão "ficar voando", isto é, viver provisoriamente fora do destino final pretendido; - a etapa de `pack` usada por `Play` deve preservar seu ciclo de validação antes da execução do runtime; - os logs de `build` e `pack` também devem convergir para o destino do debugger, porque é nessa surface que o usuário verá falhas de compilação, validação ou packing durante o fluxo do `Play`. Também há um constraint de escopo nesta wave: - checks adicionais de preflight antes do `build`, como arquivos do editor ainda não salvos, não entram agora; - quando essa wave futura existir, ela deverá bloquear o `Play` antes do `build` com erro explícito, em vez de ser tratada como detalhe implícito de runtime. ## Open Questions - [x] O `Play` deve falhar imediatamente quando `prometeuRuntimePath` estiver ausente, ou o shell deve oferecer algum repair path explícito antes de abortar? - Resposta proposta: nesta wave, o `Play` deve falhar imediatamente com erro explícito quando `prometeuRuntimePath` estiver ausente, inválido, inexistente ou não executável; repair path guiado fica para uma wave posterior. - [x] O Studio deve executar o runtime diretamente pelo binário configurado, ou por um wrapper/comando fixo resolvido a partir desse path? - Resposta proposta: o Studio deve executar como processo externo o binário configurado em `ProjectLocalStudioSetup.prometeuRuntimePath`, apontando para `build/` e usando o subcomando `run` nesta wave; uma futura wave de debugger poderá trocar esse subcomando para `debug`. - [x] O `Stop` deve encerrar apenas o processo de runtime ativo iniciado pelo shell atual, ou também limpar algum estado transitório adicional no Studio? - Resposta proposta: `Stop` deve encerrar apenas o processo de runtime ativo iniciado pelo `Play` atual; não deve limpar estado transitório adicional além do lifecycle desse processo. - [x] Onde os logs de stdout/stderr do runtime devem viver nesta primeira wave: activity feed, shipper logs, uma surface dedicada, ou combinação mínima dessas superfícies? - Resposta proposta: o destino final dos logs deve ser o futuro `DebuggerWorkspace`, e o `Play` deve navegar para essa surface ao iniciar a execução; até ela existir, stdout/stderr e também os logs de `build`/`pack` ficam provisoriamente em uma solução transitória desacoplada, enquanto o Activity Feed recebe apenas eventos resumidos de início, sucesso de término e falha. - [x] Como o shell deve serializar múltiplos cliques em `Play`: ignorar enquanto já está rodando, reiniciar, ou encadear stop + rerun? - Resposta proposta: enquanto já houver runtime ativo iniciado pelo shell atual, cliques adicionais em `Play` devem ser ignorados até o processo sair ou o usuário apertar `Stop`. - [x] O `pack` usado pelo `Play` pode empacotar diretamente, ou deve preservar o ciclo de validação antes da execução do runtime? - Resposta proposta: o `pack` usado pelo `Play` deve preservar seu ciclo de validação antes da execução; se a validação bloquear o pack, o runtime não deve iniciar. - [x] Checks extras antes do `build`, como arquivos não salvos no editor, entram nesta wave? - Resposta proposta: não; preflight adicional de `build`, incluindo arquivos ainda não salvos, fica explicitamente para uma wave posterior e não altera o contrato desta agenda. - [x] A execução da agenda 24 deve validar explicitamente a existência de `build/manifest.json` antes do spawn, ou isso fica implícito pelo sucesso da preparação? - Resposta proposta: isso fica implícito pelo sucesso da preparação definida em `DEC-0020`; a agenda 24 não adiciona check redundante de existência de `manifest.json` antes do spawn. ## Options ### Option A - Play/Stop controla um processo único de runtime do projeto ativo - **Approach:** O shell resolve o runtime configurado no `ProjectLocalStudioSetup`, executa diretamente o binário configurado contra `build/` como processo do projeto ativo, mantém handle desse processo e usa `Stop` para encerrar exatamente esse processo. - **Pro:** O comportamento do botão fica simples, previsível e diretamente alinhado ao modelo visual de toggle. - **Con:** Exige que o Studio introduza ownership explícito de processo, logs e cleanup, em vez de só alternar estado visual. - **Maintainability:** Boa, porque o shell passa a ter um contrato único de execução por projeto e um lifecycle claro. ### Option B - Play delega a execução ao workspace ou a um launcher externo sem handle direto no shell - **Approach:** O shell apenas dispara uma ação indireta e considera-se "running" sem possuir o processo como first-class state próprio. - **Pro:** Menor acoplamento inicial entre shell e camada de processo. - **Con:** O `Stop` fica semanticamente fraco ou enganoso, porque o shell não controla de verdade o processo que diz estar executando. - **Maintainability:** Fraca, porque o toggle visual deixa de corresponder ao lifecycle real da execução. ## Discussion O ponto mais importante desta agenda é alinhar o significado de `Stop`. Se o shell não possui o processo de runtime como state explícito, o botão vira só uma fantasia visual. Como o runtime path já é project-local setup carregado na sessão, o Studio já tem o owner certo para resolver o binário configurado. O que falta é explicitar o contrato operacional: 1. validar que o runtime configurado existe e é executável; 2. executar `build`; 3. executar a validação de `pack`; 4. executar `pack` somente quando a validação permitir; 5. enviar os logs de `build` e `pack` para a surface de debugger/logs da execução; 6. rodar como processo externo o runtime configurado contra `build/` no contexto do projeto ativo, usando `run` nesta wave; 7. capturar stdout/stderr; 8. refletir running/stopped/failure no shell; 9. interromper o processo correto quando o usuário apertar `Stop`. A execução do runtime nesta agenda confia no contrato de preparação anterior. Portanto, esta wave não introduz preflight redundante para verificar novamente a existência de `build/manifest.json` antes do spawn. A recomendação inicial desta agenda é: 1. fazer o shell ser owner de um único runtime-process handle por projeto ativo; 2. resolver o comando a partir de `ProjectLocalStudioSetup.prometeuRuntimePath`; 3. falhar de forma explícita quando o runtime do projeto estiver ausente ou inválido; 4. definir `Stop` como término do processo iniciado pelo `Play` atual, e não como reset genérico de UI; 5. ignorar novo `Play` enquanto o processo atual ainda estiver rodando; 6. preservar a validação de pack antes do pack efetivo na preparação do `Play`; 7. tratar o futuro `DebuggerWorkspace` como destino canônico da execução e dos logs de runtime, `build` e `pack`; 8. enquanto o `DebuggerWorkspace` não existir, manter stdout/stderr e logs de preparação em uma solução transitória, usando o Activity Feed apenas para sinais resumidos de lifecycle; 9. deixar checks extras de preflight antes do `build`, como arquivos não salvos, fora desta wave; 10. fixar `run` como o subcomando de execução desta wave, deixando `debug` para uma futura wave de debugger; 11. confiar no sucesso da preparação anterior sem adicionar preflight redundante de `manifest.json` antes do spawn. ## Resolution Próximo passo sugerido: fechar uma decision de `studio` que defina ownership de processo para `Play/Stop`, preserve o ciclo de validação + pack antes da execução do runtime, fixe a execução como processo externo do runtime configurado usando `run` contra `build/`, trate o `DebuggerWorkspace` como destino futuro da sessão de execução e explicite que checks extras de preflight do `build` ficam para uma wave posterior.