diff --git a/docs/studio/agendas/Pack Wizard in Assets Workspace Agenda.md b/docs/studio/agendas/Pack Wizard in Assets Workspace Agenda.md new file mode 100644 index 00000000..c656b7b8 --- /dev/null +++ b/docs/studio/agendas/Pack Wizard in Assets Workspace Agenda.md @@ -0,0 +1,227 @@ +# Pack Wizard in Assets Workspace Agenda + +Status: Open +Domain Owner: `docs/studio` +Cross-Domain Impact: `docs/packer` + +## Problem + +O workspace `Assets` já reserva a action area para `Pack`, mas ainda não existe uma discussão fechada sobre o fluxo exato desse comando no Studio. + +O pedido atual não é apenas adicionar um botão. +O `Pack` precisa abrir um modal que funcione como wizard operacional do empacotador e deixe claro: + +- o resumo do que será empacotado; +- a validação obrigatória antes do build; +- a regra de bloqueio quando existirem diagnostics em assets incluídos; +- o progresso da geração do artefato; +- e o resumo final do resultado. + +Sem essa agenda, há risco de misturar decisão de UX com semântica de packer e de implementar um modal visualmente correto, mas operacionalmente fraco. + +## Context + +O estado atual já sugere várias restrições importantes: + +1. o `Assets` workspace define `Pack` como ação global de workspace, não como ação do asset selecionado; +2. a spec do Studio já separa `Pack` do fluxo de staged mutations sensíveis; +3. a spec do packer define `assets.pa` como artefato runtime autoritativo, com `asset_table` determinística e baseada apenas nos assets incluídos no build set atual; +4. o packer já trata diagnostics como parte do modelo operacional, então o Studio não deve inventar uma semântica paralela de validação; +5. o usuário precisa de feedback de progresso e de falha com drill-down por asset, não apenas logs. + +Artefatos e referências já relevantes: + +- `docs/studio/specs/4. Assets Workspace Specification.md` +- `docs/packer/specs/4. Build Artifacts and Deterministic Packing Specification.md` +- `docs/packer/specs/5. Diagnostics, Operations, and Studio Integration Specification.md` +- `docs/packer/pull-requests/PR-08-assets-pa-and-companion-artifact-emission.md` + +Nota de nomenclatura: + +- a spec vigente usa `assets.pa` como nome canônico do artefato; +- esta agenda deve seguir `assets.pa`, mesmo que a conversa operacional use `asset.pa` informalmente. + +## Current Code Context + +O contexto atual no código Studio é suficiente para ancorar a discussão: + +- o botão `Pack` foi introduzido na action bar do workspace em `prometeu-studio/src/main/java/p/studio/workspaces/assets/AssetWorkspace.java`; +- o workspace já possui região inline de progresso, painel de logs e integração com eventos do packer; +- ainda não existe wizard de pack nem API explícita de `pack` em `PackerWorkspaceService`. + +Isso significa que o fluxo precisa ser decidido primeiro e depois propagado para: + +- contrato da API do packer; +- eventos operacionais de progresso; +- modelagem de resultado; +- e shell/modal do Studio. + +## Options + +### Option A - Single modal with one primary action + +Abrir um modal com resumo inicial e um único botão `Pack`. +Ao confirmar, o Studio valida, empacota e mostra sucesso ou falha no mesmo corpo, sem etapas explícitas de wizard. + +### Option B - Multi-step wizard with explicit operational phases + +Abrir um wizard com fases claras: + +1. `Summary` +2. `Validation` +3. `Packing` +4. `Result` + +Cada fase deixa explícito o estado operacional atual e evita que o usuário perca contexto entre bloqueio, execução e resultado. + +### Option C - Split flow with preflight modal plus separate progress dialog + +Abrir um modal curto para resumo e validação. +Se tudo passar, fechar esse modal e abrir outro diálogo dedicado só ao progresso e resultado do pack. + +## Tradeoffs + +- Option A é mais rápida de implementar, mas colapsa estados diferentes demais em uma única superfície e tende a virar um modal ambíguo. +- Option A também dificulta explicar por que o pack foi bloqueado e o que exatamente falhou por asset. +- Option B exige mais estrutura de estado, mas deixa o fluxo didático, previsível e alinhado ao pedido de wizard empacotador. +- Option B também facilita mapear cada fase para contratos distintos do packer: preflight, validação, execução e resultado. +- Option C separa bem responsabilidades visuais, mas fragmenta a experiência e pode parecer que o usuário saiu de um fluxo para entrar em outro. +- Option C ainda aumenta o custo de coordenação de foco, fechamento e recuperação de erro. + +## Recommendation + +Adotar `Option B` como baseline. + +O `Pack` deve abrir um wizard modal de workspace, owner do Studio na apresentação e owner do packer na semântica operacional. + +### Recommended Flow + +#### 1. Summary + +O wizard abre em um resumo do build atual. +Esse resumo deve mostrar pelo menos: + +- quantidade de assets registrados e incluídos no build atual; +- quantidade de assets excluídos ou fora do build set; +- indicação de que o output canônico será `assets.pa`; +- indicação de que a `asset_table` seguirá a ordem determinística por `asset_id`, conforme spec; +- artefatos companion previstos quando aplicável. + +Regras: + +- assets não incluídos no build não entram no pack; +- assets não registrados também não entram no pack; +- o resumo deve deixar explícito que a operação trabalha sobre o build set atual, não sobre todo o workspace. + +#### 2. Validation + +A segunda fase deve executar uma validação explícita sobre os assets incluídos no build. + +Baseline recomendado: + +- qualquer diagnostic bloqueante em asset incluído falha a validação e impede o início do pack; +- a tela deve mostrar resumo agregado e amostragem por asset do que falhou; +- a UI deve permitir drill-down por asset sem despejar log cru como explicação principal; +- se houver warnings não bloqueantes, eles podem ser exibidos, mas não devem impedir o `Pack`. + +Modelo didático mínimo da tela: + +- topo com contagem de assets validados, aprovados e bloqueados; +- lista por asset com status; +- ao selecionar ou expandir um asset, mostrar diagnostics relevantes daquele asset. + +A responsabilidade pela classificação do que bloqueia ou não deve permanecer no packer. +O Studio apenas consome e apresenta essa classificação. + +#### 3. Packing + +Se a validação passar, o wizard entra em fase de execução. + +Essa fase deve ser não editável e orientada a progresso. + +Regras: + +- mostrar barra de progresso com atualização contínua; +- mostrar texto curto da etapa atual; +- manter o usuário no mesmo modal até conclusão, falha ou cancelamento suportado por contrato; +- deixar explícito que o pack está montando `assets.pa` e a `asset_table` conforme as specs vigentes; +- logs detalhados podem existir em área secundária, mas não substituem o indicador principal de progresso. + +Semântica recomendada: + +- o packer expõe eventos ou snapshots de progresso por operação; +- o Studio mapeia isso para uma barra de progresso e rótulos humanos; +- o wizard não deve inferir progresso a partir de timers artificiais. + +#### 4. Result + +Ao concluir, o wizard deve mostrar um resumo final do resultado. + +O resumo deve cobrir: + +- status final: sucesso parcial ou falha; +- quantidade de assets efetivamente empacotados; +- artefatos emitidos; +- duração da operação; +- falhas ou avisos finais, quando existirem. + +Se houver falha depois de a validação ter passado, a tela final deve diferenciar: + +- falha de validação; +- falha de execução/geração; +- e falha de persistência/emissão. + +### Contract Direction + +Para a próxima onda de decisão, o contrato recomendado é separar pelo menos três responsabilidades no packer: + +1. `preflight summary` do build set atual; +2. `validation` do build set com bloqueios agregados por asset; +3. `pack execution` com progresso estruturado e resultado final. + +O Studio deve orquestrar essas fases no wizard, mas não redefinir: + +- quais assets entram no build set; +- o que conta como diagnostic bloqueante; +- a ordem da `asset_table`; +- ou o que exatamente compõe `assets.pa`. + +### UI Direction + +O wizard deve ser operacional, não um formulário tradicional. + +Direção recomendada: + +- stepper simples no topo ou lateral; +- corpo central com conteúdo da fase; +- ações de navegação controladas pelo estado operacional; +- `Next` bloqueado quando a validação falhar; +- `Pack` disponível apenas quando a fase de validação estiver limpa; +- `Close` ou `Done` só ao final, ou em estados seguros de abortar. + +## Open Questions + +1. O packer deve expor `summary`, `validate` e `pack` como chamadas separadas ou uma única operação com fases internas observáveis? +2. O pack bloqueia apenas por diagnostics `blocking` ou também por certos warnings elevados a gate de build? +3. A amostragem por asset na fase de validação deve mostrar todos os diagnostics do asset ou apenas os bloqueantes por padrão? +4. O wizard deve permitir exportar ou copiar o resumo de falhas para facilitar correção fora do modal? +5. Existe cancelamento real suportado pelo packer durante a fase `Packing`, ou o primeiro wave deve tratar a operação como não cancelável? +6. O resultado final deve listar também os companion artifacts ou isso fica para drill-down secundário? +7. O build set do `Pack` neste fluxo é estritamente `registered + included`, ou existe necessidade futura de variantes de pack profile? + +## Suggested Next Step + +O próximo passo correto é converter esta agenda em uma `decision` owner de `docs/studio`, com propagação explícita para `docs/packer`. + +Essa decision deve fechar: + +1. o shape do wizard e suas fases; +2. o gate de validação baseado em diagnostics dos assets incluídos; +3. o contrato mínimo de API/eventos que o packer precisa expor para suportar o wizard; +4. a distinção entre falha de validação e falha de execução; +5. o vocabulário canônico do resultado final em torno de `assets.pa` e `asset_table`. + +Depois disso, o trabalho deve ser decomposto em pelo menos dois planos: + +1. um `PR/plan` em `docs/packer` para summary, validation, pack execution, progress e result contract; +2. um `PR/plan` em `docs/studio` para shell do wizard, fases, binding de progresso e tela de resultado. diff --git a/prometeu-studio/src/main/java/p/studio/utilities/i18n/I18n.java b/prometeu-studio/src/main/java/p/studio/utilities/i18n/I18n.java index 61b72927..21ce9acf 100644 --- a/prometeu-studio/src/main/java/p/studio/utilities/i18n/I18n.java +++ b/prometeu-studio/src/main/java/p/studio/utilities/i18n/I18n.java @@ -81,6 +81,7 @@ public enum I18n { ASSETS_NAVIGATOR_TITLE("assets.navigator.title"), ASSETS_NAVIGATOR_ACTION_REFRESH("assets.navigator.action.refresh"), ASSETS_NAVIGATOR_ACTION_ADD("assets.navigator.action.add"), + ASSETS_NAVIGATOR_ACTION_PACK("assets.navigator.action.pack"), ASSETS_SEARCH_PROMPT("assets.search.prompt"), ASSETS_FILTER_UNREGISTERED("assets.filter.unregistered"), ASSETS_FILTER_DIAGNOSTICS("assets.filter.diagnostics"), diff --git a/prometeu-studio/src/main/java/p/studio/workspaces/assets/AssetWorkspace.java b/prometeu-studio/src/main/java/p/studio/workspaces/assets/AssetWorkspace.java index dfdfcc2f..89647c90 100644 --- a/prometeu-studio/src/main/java/p/studio/workspaces/assets/AssetWorkspace.java +++ b/prometeu-studio/src/main/java/p/studio/workspaces/assets/AssetWorkspace.java @@ -82,7 +82,8 @@ public final class AssetWorkspace extends Workspace { private HBox createActionBar() { final var refreshButton = createRefreshButton(); final var addAssetButton = createAddAssetButton(); - final var workspaceActionBar = new HBox(8, refreshButton, addAssetButton); + final var packButton = createPackButton(); + final var workspaceActionBar = new HBox(8, refreshButton, addAssetButton, packButton); workspaceActionBar.setAlignment(Pos.CENTER_LEFT); workspaceActionBar.getStyleClass().add("assets-workspace-action-bar"); return workspaceActionBar; @@ -113,6 +114,16 @@ public final class AssetWorkspace extends Workspace { return addAssetButton; } + private Button createPackButton() { + final var packButton = new Button(); + packButton.textProperty().bind(Container.i18n().bind(I18n.ASSETS_NAVIGATOR_ACTION_PACK)); + packButton.getStyleClass().addAll( + "studio-button", + "studio-button-secondary", + "assets-workspace-action-button"); + return packButton; + } + private void openAddAssetWizard() { if (root.getScene() == null) { return; diff --git a/prometeu-studio/src/main/resources/i18n/messages.properties b/prometeu-studio/src/main/resources/i18n/messages.properties index be791464..bac36f5b 100644 --- a/prometeu-studio/src/main/resources/i18n/messages.properties +++ b/prometeu-studio/src/main/resources/i18n/messages.properties @@ -71,6 +71,7 @@ workspace.assets=Assets assets.navigator.title=Asset Navigator assets.navigator.action.refresh=Refresh assets.navigator.action.add=Add Asset +assets.navigator.action.pack=Pack assets.search.prompt=Search assets by name or path assets.filter.unregistered=Unregistered assets.filter.diagnostics=Diagnostics diff --git a/test-projects/main/.studio/activities.json b/test-projects/main/.studio/activities.json index fe0a8219..68e37859 100644 --- a/test-projects/main/.studio/activities.json +++ b/test-projects/main/.studio/activities.json @@ -398,6 +398,106 @@ "message" : "Asset scan started", "severity" : "INFO", "sticky" : false +}, { + "source" : "Assets", + "message" : "7 assets loaded", + "severity" : "SUCCESS", + "sticky" : false +}, { + "source" : "Assets", + "message" : "Asset scan diagnostics updated.", + "severity" : "INFO", + "sticky" : false +}, { + "source" : "Assets", + "message" : "Discovered asset: bla", + "severity" : "INFO", + "sticky" : false +}, { + "source" : "Assets", + "message" : "Discovered asset: one-more-atlas", + "severity" : "INFO", + "sticky" : false +}, { + "source" : "Assets", + "message" : "Discovered asset: ui_atlas", + "severity" : "INFO", + "sticky" : false +}, { + "source" : "Assets", + "message" : "Discovered asset: one-more-atlas", + "severity" : "INFO", + "sticky" : false +}, { + "source" : "Assets", + "message" : "Discovered asset: bbb2", + "severity" : "INFO", + "sticky" : false +}, { + "source" : "Assets", + "message" : "Discovered asset: ui_atlas", + "severity" : "INFO", + "sticky" : false +}, { + "source" : "Assets", + "message" : "Discovered asset: Bigode", + "severity" : "INFO", + "sticky" : false +}, { + "source" : "Assets", + "message" : "Asset scan started", + "severity" : "INFO", + "sticky" : false +}, { + "source" : "Assets", + "message" : "7 assets loaded", + "severity" : "SUCCESS", + "sticky" : false +}, { + "source" : "Assets", + "message" : "Asset scan diagnostics updated.", + "severity" : "INFO", + "sticky" : false +}, { + "source" : "Assets", + "message" : "Discovered asset: bla", + "severity" : "INFO", + "sticky" : false +}, { + "source" : "Assets", + "message" : "Discovered asset: one-more-atlas", + "severity" : "INFO", + "sticky" : false +}, { + "source" : "Assets", + "message" : "Discovered asset: ui_atlas", + "severity" : "INFO", + "sticky" : false +}, { + "source" : "Assets", + "message" : "Discovered asset: one-more-atlas", + "severity" : "INFO", + "sticky" : false +}, { + "source" : "Assets", + "message" : "Discovered asset: bbb2", + "severity" : "INFO", + "sticky" : false +}, { + "source" : "Assets", + "message" : "Discovered asset: ui_atlas", + "severity" : "INFO", + "sticky" : false +}, { + "source" : "Assets", + "message" : "Discovered asset: Bigode", + "severity" : "INFO", + "sticky" : false +}, { + "source" : "Assets", + "message" : "Asset scan started", + "severity" : "INFO", + "sticky" : false }, { "source" : "Assets", "message" : "Excluded asset in build: ui/sound", @@ -2398,104 +2498,4 @@ "message" : "Asset scan diagnostics updated.", "severity" : "INFO", "sticky" : false -}, { - "source" : "Assets", - "message" : "Discovered asset: bla", - "severity" : "INFO", - "sticky" : false -}, { - "source" : "Assets", - "message" : "Discovered asset: one-more-atlas", - "severity" : "INFO", - "sticky" : false -}, { - "source" : "Assets", - "message" : "Discovered asset: ui_atlas", - "severity" : "INFO", - "sticky" : false -}, { - "source" : "Assets", - "message" : "Discovered asset: one-more-atlas", - "severity" : "INFO", - "sticky" : false -}, { - "source" : "Assets", - "message" : "Discovered asset: bbb2", - "severity" : "INFO", - "sticky" : false -}, { - "source" : "Assets", - "message" : "Discovered asset: ui_atlas", - "severity" : "INFO", - "sticky" : false -}, { - "source" : "Assets", - "message" : "Discovered asset: Bigode", - "severity" : "INFO", - "sticky" : false -}, { - "source" : "Assets", - "message" : "Asset scan started", - "severity" : "INFO", - "sticky" : false -}, { - "source" : "Assets", - "message" : "Excluded asset in build: recovered/atlas2", - "severity" : "SUCCESS", - "sticky" : false -}, { - "source" : "Assets", - "message" : "7 assets loaded", - "severity" : "SUCCESS", - "sticky" : false -}, { - "source" : "Assets", - "message" : "Asset scan diagnostics updated.", - "severity" : "INFO", - "sticky" : false -}, { - "source" : "Assets", - "message" : "Discovered asset: bla", - "severity" : "INFO", - "sticky" : false -}, { - "source" : "Assets", - "message" : "Discovered asset: one-more-atlas", - "severity" : "INFO", - "sticky" : false -}, { - "source" : "Assets", - "message" : "Discovered asset: ui_atlas", - "severity" : "INFO", - "sticky" : false -}, { - "source" : "Assets", - "message" : "Discovered asset: one-more-atlas", - "severity" : "INFO", - "sticky" : false -}, { - "source" : "Assets", - "message" : "Discovered asset: bbb2", - "severity" : "INFO", - "sticky" : false -}, { - "source" : "Assets", - "message" : "Discovered asset: ui_atlas", - "severity" : "INFO", - "sticky" : false -}, { - "source" : "Assets", - "message" : "Discovered asset: Bigode", - "severity" : "INFO", - "sticky" : false -}, { - "source" : "Assets", - "message" : "Asset scan started", - "severity" : "INFO", - "sticky" : false -}, { - "source" : "Assets", - "message" : "Included asset in build: bigode", - "severity" : "SUCCESS", - "sticky" : false } ] \ No newline at end of file