@polymorphism-tech/morph-spec 7.3.0 → 7.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/CLAUDE.md +1 -1
  2. package/README.md +2 -2
  3. package/bin/morph-spec.js +22 -2
  4. package/claude-plugin.json +1 -1
  5. package/docs/CHEATSHEET.md +1 -1
  6. package/docs/QUICKSTART.md +1 -1
  7. package/framework/CLAUDE.md +10 -5
  8. package/framework/MORPH.md +31 -14
  9. package/framework/agents.json +132 -132
  10. package/framework/commands/create-umbraco-lp.md +35 -0
  11. package/framework/commands/migrate-lp-to-umbraco.md +33 -0
  12. package/framework/commands/morph-archive.md +17 -27
  13. package/framework/evals/rubrics/README.md +9 -8
  14. package/framework/hooks/README.md +2 -0
  15. package/framework/hooks/claude-code/core/enforce-phase-writes.js +115 -90
  16. package/framework/hooks/claude-code/core/gate-guard.js +160 -0
  17. package/framework/hooks/claude-code/core/protect-spec-files.js +32 -30
  18. package/framework/hooks/claude-code/core/state-sync.js +16 -36
  19. package/framework/hooks/claude-code/core/validate-completion.js +105 -0
  20. package/framework/hooks/shared/state-reader.js +302 -221
  21. package/framework/hooks/shared/state-writer.js +124 -0
  22. package/framework/rules/morph-task-tracking.md +69 -49
  23. package/framework/rules/morph-workflow.md +192 -191
  24. package/framework/skills/README.md +1 -1
  25. package/framework/skills/core/create-umbraco-lp/SKILL.md +252 -0
  26. package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +452 -0
  27. package/framework/skills/core/morph-apply/SKILL.md +69 -27
  28. package/framework/skills/core/morph-brainstorming/SKILL.md +6 -2
  29. package/framework/skills/core/morph-eval/SKILL.md +4 -5
  30. package/framework/skills/core/morph-implement/SKILL.md +51 -22
  31. package/framework/skills/core/morph-plan/SKILL.md +10 -4
  32. package/framework/skills/core/morph-proposal/SKILL.md +8 -7
  33. package/framework/skills/core/morph-review/SKILL.md +15 -8
  34. package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
  35. package/framework/skills/core/morph-standards/SKILL.md +1 -1
  36. package/framework/standards/ai-agents/setup.md +258 -244
  37. package/framework/templates/REGISTRY.json +1 -3
  38. package/framework/templates/context/CONTEXT-FEATURE.md +10 -17
  39. package/framework/templates/context/CONTEXT.md +181 -180
  40. package/framework/templates/docs/onboarding.md +122 -118
  41. package/framework/templates/docs/proposal.md +10 -0
  42. package/framework/templates/docs/spec.md +228 -228
  43. package/framework/templates/meta-prompts/parallel-workers/parallel-worker.md +80 -80
  44. package/framework/templates/meta-prompts/squad-leaders/backend-squad.md +90 -89
  45. package/framework/templates/meta-prompts/squad-leaders/frontend-squad.md +2 -1
  46. package/framework/templates/meta-prompts/squad-leaders/squad-leader.md +44 -43
  47. package/framework/templates/meta-prompts/validators/checkpoint-validator.md +107 -107
  48. package/package.json +1 -1
  49. package/src/commands/project/init.js +517 -515
  50. package/src/commands/project/update.js +415 -368
  51. package/src/commands/project/worktree.js +212 -210
  52. package/src/commands/state/advance.js +82 -0
  53. package/src/commands/state/approve.js +251 -213
  54. package/src/commands/state/archive.js +111 -0
  55. package/src/commands/validation/validate-feature.js +244 -79
  56. package/src/core/state/state-manager.js +256 -74
  57. package/src/dashboard/scanner/state-scanner.js +35 -8
  58. package/src/lib/generators/context-generator.js +12 -8
  59. package/src/lib/risk-detector.js +2 -2
  60. package/src/utils/file-copier.js +7 -0
  61. package/src/utils/hooks-installer.js +527 -516
@@ -0,0 +1,452 @@
1
+ ---
2
+ name: migrate-lp-to-umbraco
3
+ description: Migra uma landing page existente (React/Vite, Next.js estático ou HTML) para o template Umbraco-headless MORPH_Umbraco_LP_Template entregando a LP EXATAMENTE igual à origem (mesmo CSS, imagens, fontes e comportamento) + Umbraco por cima — obtenção automática do template, inventário de seções, lift-and-rewire verbatim de cada seção para módulo editável, conexão do formulário ao backend de leads e gate de paridade determinístico. Repo-agnóstica: roda em qualquer lugar, sem template nem origem pré-baixados.
4
+ version: core
5
+ when-to-invoke: ao receber instrução "use /migrate-lp-to-umbraco {projeto}" do usuário, ou quando o usuário descrever necessidade de migrar uma LP para Umbraco
6
+ user-invokable: true
7
+ cliVersion: "7.5.0"
8
+ ---
9
+
10
+ # migrate-lp-to-umbraco
11
+
12
+ ## Objetivo
13
+
14
+ Conduzir a migração de uma landing page de origem arbitrária para o stack Umbraco 17 / .NET 10 + Next.js do template `MORPH_Umbraco_LP_Template`, entregando uma LP **visual e funcionalmente idêntica à origem** (mesmo CSS, imagens, fontes, animações e comportamento) com o Umbraco embrulhando o conteúdo por cima — projeto funcional e idempotentemente seedável onde todo conteúdo editorial (textos, imagens, vídeos) fica editável no backoffice, e as credenciais de integração de leads nunca saem do backoffice.
15
+
16
+ **Princípio central — lift-and-rewire, não rebuild.** A paridade exata é garantida **por construção**: copia-se o markup/CSS/classes/assets de cada seção da origem **verbatim** para o componente do módulo, trocando apenas os literais de conteúdo (texto, `src` de mídia) por leituras do backoffice. O render é idêntico porque o markup é o mesmo; o gate de paridade (passo 6) é uma **confirmação** de que o lift foi limpo, não uma ferramenta para descobrir e remendar drift. Reescrever cada seção do zero ("rebuild-then-compare") nunca converge para "exatamente igual" — não fazer isso.
17
+
18
+ O processo é reproduzível para qualquer LP (React/Vite, Next.js estático ou HTML). A skill é **repo-agnóstica**: não depende de nenhum repo de exemplo nem do template estarem pré-baixados — ela obtém o template sozinha (passo 0).
19
+
20
+ ## Quando invocar
21
+
22
+ - Usuário pede "use /migrate-lp-to-umbraco {projeto}" ou equivalente natural ("migrar LP para Umbraco", "portar site para Umbraco headless", "rebuild no template Umbraco").
23
+ - Projeto de origem já existe (brownfield) — LP em React/Vite/Next.js/HTML.
24
+
25
+ ## Argumentos
26
+
27
+ - `{projeto}` — nome do projeto em kebab-case (ex.: `reserva-das-flores`, `lp-imobiliaria`). Se ausente, perguntar via `AskUserQuestion`.
28
+
29
+ ## Pré-condições
30
+
31
+ - **Acesso ao template** — `git` + (preferencialmente) `gh` autenticado com acesso ao repo **privado** `polymorphism-tech/MORPH_Umbraco_LP_Template`. O template **não** precisa estar pré-baixado: o passo 0 o obtém. (Para clone via `git` direto, é preciso credencial HTTPS ou chave SSH com acesso à org.)
32
+ - **Origem acessível** — em uma das duas formas (a skill suporta ambas):
33
+ - **(a) código-fonte local** da LP (React/Vite, Next.js ou HTML) — caminho de **fidelidade máxima**, pois o CSS, o markup e os assets exatos estão disponíveis para o lift verbatim.
34
+ - **(b) apenas a URL** da LP em produção — fallback: scrapear o HTML renderizado, o CSS computado e baixar todos os assets. O mesmo gate de paridade (passo 6) se aplica.
35
+ - **Docker** disponível para boot local (`docker compose`), ou .NET 10 SDK + Node para boot sem container.
36
+
37
+ ## Passo 0 — Obter o template (sempre)
38
+
39
+ A skill **sempre** garante uma cópia local do template antes de qualquer outro passo. Roda em qualquer diretório — não assume nada pré-baixado.
40
+
41
+ **Cache de referência (read-only).** Manter uma cópia canônica do template num cache estável por máquina, para leitura dos arquivos de referência (sinks, `SeedContentHandler`, `moduleRegistry`, e2e) e como base do scaffold:
42
+
43
+ - bash: `TPL="${MORPH_TEMPLATE_CACHE:-$HOME/.morph/templates}/MORPH_Umbraco_LP_Template"`
44
+ - PowerShell: `$Tpl = "$env:USERPROFILE\.morph\templates\MORPH_Umbraco_LP_Template"`
45
+
46
+ **Rotina check-local → clone → pull:**
47
+
48
+ ```bash
49
+ # Bash — obtém ou atualiza o cache do template
50
+ TPL="${MORPH_TEMPLATE_CACHE:-$HOME/.morph/templates}/MORPH_Umbraco_LP_Template"
51
+ if [ -d "$TPL/.git" ]; then
52
+ git -C "$TPL" pull --ff-only || echo "offline — usando cache existente"
53
+ else
54
+ mkdir -p "$(dirname "$TPL")"
55
+ gh repo clone polymorphism-tech/MORPH_Umbraco_LP_Template "$TPL" \
56
+ || git clone https://github.com/polymorphism-tech/MORPH_Umbraco_LP_Template.git "$TPL" \
57
+ || git clone git@github.com:polymorphism-tech/MORPH_Umbraco_LP_Template.git "$TPL"
58
+ fi
59
+ ```
60
+
61
+ ```powershell
62
+ # PowerShell — obtém ou atualiza o cache do template
63
+ $Tpl = "$env:USERPROFILE\.morph\templates\MORPH_Umbraco_LP_Template"
64
+ if (Test-Path "$Tpl\.git") {
65
+ git -C "$Tpl" pull --ff-only
66
+ } else {
67
+ New-Item -ItemType Directory -Force (Split-Path $Tpl) | Out-Null
68
+ gh repo clone polymorphism-tech/MORPH_Umbraco_LP_Template "$Tpl"
69
+ if (-not (Test-Path "$Tpl\.git")) { git clone https://github.com/polymorphism-tech/MORPH_Umbraco_LP_Template.git "$Tpl" }
70
+ if (-not (Test-Path "$Tpl\.git")) { git clone git@github.com:polymorphism-tech/MORPH_Umbraco_LP_Template.git "$Tpl" }
71
+ }
72
+ ```
73
+
74
+ Notas:
75
+ - Branch padrão do template é **`master`** — **não** fazer `git checkout` de outra branch (o template já está generalizado: doctype raiz `lpHome`, scripts `new-lp`, sinks de lead, e2e).
76
+ - `gh repo clone` é o caminho primário por ser repo **privado** (usa o token já autenticado). HTTPS/SSH são fallback.
77
+ - O cache é **somente leitura**: nunca rodar `new-lp` nem editar dentro dele — o scaffold (passo 3) trabalha sobre uma **cópia fresca**.
78
+
79
+ ## Fluxo
80
+
81
+ ### 1. Analisar a origem — capturar PARA UM LIFT VERBATIM
82
+
83
+ O objetivo desta etapa não é "entender" a LP, é **capturar tudo o que é necessário para reproduzi-la byte-a-byte**. Cada item abaixo alimenta o lift do passo 4.
84
+
85
+ **Inventário de seções** — para cada bloco visual da página, documentar:
86
+ - Nome e ordem na página.
87
+ - **Markup e classes exatos**: a árvore DOM e os nomes de classe de cada seção, como estão (não normalizar nem "limpar").
88
+ - Conteúdo textual: títulos, subtítulos, corpo, CTAs, links.
89
+ - Mídia: imagens, vídeos, posters — registrar o caminho/URL de cada um para baixar abaixo.
90
+ - **Comportamento interativo**: animação de scroll/scroll-expand, carrossel, marquee, autoplay de vídeo, hovers, mapa, máscara/validação de formulário — documentar cada um com detalhe suficiente para reproduzir idêntico.
91
+ - Dados estruturados aninhados (ex.: lista de produtos com nome+imagem+descrição, lista de depoimentos).
92
+ - **Breakpoints responsivos** e o que muda em cada um (mobile/tablet/desktop).
93
+
94
+ **Tema e CSS — copiar VERBATIM, não reinterpretar:**
95
+ - Capturar o CSS da origem como está: bloco `@theme`/tokens (variáveis `--color-*`, `--font-*`), classes custom, `@layer`, `@keyframes`, media queries. Os valores serão **portados sem alteração** no passo 4 — não arredondar cores nem aproximar espaçamentos.
96
+ - **Config do Tailwind**: portar a config/tema da origem. Tailwind v4 é CSS-based (`@theme` em `globals.css`). ⚠️ A **mesma classe utilitária renderiza diferente** se a versão ou o tema do Tailwind divergir — portar o tema da origem, **nunca** assumir o do template.
97
+
98
+ **Assets — baixar byte-a-byte e registrar checksum:**
99
+ - Baixar/copiar **todos** os assets: imagens, vídeos, posters, ícones e **fontes** (arquivos `.woff2`/`.ttf` + famílias e pesos exatos). Web-fonts são parte da fidelidade — mesma família, mesmo peso, mesmo arquivo.
100
+ - Registrar o `sha256` de cada asset (vira a base da paridade de checksum no passo 6).
101
+ - **Não reencodar nem otimizar** nenhum asset — qualquer reencode quebra a paridade.
102
+
103
+ **Formulário de captação** — campos presentes, validação no frontend, endpoint atual, integração de CRM/leads.
104
+
105
+ **Origem apenas por URL (fallback):** se não houver código-fonte, scrapear o HTML renderizado, extrair o CSS computado dos elementos e baixar todos os assets referenciados (incluindo fontes). O lift parte do markup renderizado + CSS computado.
106
+
107
+ **Exemplo ilustrativo (LP fictícia):**
108
+ - Origem: `src/App.tsx` (React/Vite) — componentes `Navbar`, `Hero`, `HorizontalScroll`, `Manifesto`, `Galeria`, `Testimonial`, `CTA`, `Footer`.
109
+ - Tema extraído do bloco `@theme` em `src/index.css`: `--color-surface`, `--color-primary`, `--color-tertiary`, etc.; tipografia (ex.) Cormorant Garamond + Jost (baixar os arquivos de fonte).
110
+ - Formulário: campos nome, e-mail, telefone + POST para servidor com integração de leads.
111
+
112
+ Produzir `docs/origem-inventario.md` no repositório destino com esta análise (incluindo a tabela de assets com `sha256`).
113
+
114
+ ### 2. Mapear origem para doctypes/módulos do template
115
+
116
+ Comparar cada seção inventariada com os módulos disponíveis no template:
117
+
118
+ | Módulo (alias uSync) | Propósito |
119
+ |---|---|
120
+ | `heroSection` | Hero genérico com título, subtítulo, imagem/vídeo de fundo e CTA |
121
+ | `diferencialSection` / `diferencialItem` | Lista de diferenciais/features com ícone e descrição |
122
+ | `testimonialSection` / `testimonialItem` | Depoimentos com nome, cargo e texto |
123
+ | `galeriaSection` | Galeria de imagens |
124
+ | `videoSection` | Bloco com vídeo embutido |
125
+ | `equipeSection` / `equipeMembro` | Equipe com foto, nome e cargo |
126
+ | `certificacoesSection` / `certificacaoItem` | Selos e certificações |
127
+ | `localizacaoSection` | Mapa ou endereço |
128
+ | `contatoSection` | Seção de formulário de captação |
129
+ | `customHtmlSection` | Bloco HTML livre (fallback para conteúdo sem módulo dedicado) |
130
+
131
+ Para cada seção da origem, determinar (na ótica do lift verbatim — fidelidade primeiro):
132
+ 1. **Reuso direto de módulo do template**: **somente** quando o markup e o CSS renderizados do módulo do template já são idênticos aos da origem. Se houver qualquer diferença visual, **não** reusar — isso introduz drift. Na dúvida, prefira lift verbatim.
133
+ 2. **Módulo do template com ajuste de campos**: o módulo serve mas precisa de propriedades extras — adicionar no uSync `.config` do módulo e no componente frontend. O markup permanece o da origem.
134
+ 3. **Módulo novo via lift verbatim (caso padrão)**: a seção vira um novo doctype + componente que **reproduz o markup/CSS/classes da origem verbatim** (ver passo 4). Criar o doctype + componente + registro no `moduleRegistry.ts`. Nomear o alias em camelCase com sufixo `Section` (ex.: `manifestoSection`, `galeriaSection`).
135
+
136
+ > Regra prática: a decisão default é **lift verbatim** (opção 3). Reusar um módulo do template (opções 1/2) só quando a paridade visual é garantida — caso contrário a LP migrada deixa de ser "exatamente igual".
137
+
138
+ Documentar decisões e justificativas em `docs/mapeamento-modulos.md`.
139
+
140
+ **Exemplo ilustrativo — módulos lifted da origem:**
141
+ - `heroSection` (lift): Hero com efeito scroll-expand + vídeo de fundo expansível — markup e animação copiados verbatim da origem.
142
+ - `brandStorySection`: Bloco editorial de história da marca com imagem e texto em colunas.
143
+ - `galeriaSection` / `galeriaItem`: Grade de itens com imagem, nome e descrição.
144
+ - `processoSection` / `processoStep`: Processo em etapas (passo a passo numerado).
145
+ - `marqueeSection`: Faixa de texto em loop (palavras-chave da marca).
146
+ - `statsSection`: Contador de métricas (anos, projetos, etc.).
147
+ - Módulos reutilizados diretamente (só porque o render bate com a origem): `testimonialSection`, `contatoSection`.
148
+
149
+ ### 3. Scaffold via new-lp
150
+
151
+ Criar o projeto destino a partir de uma **cópia fresca** do template (nunca dentro do cache do passo 0) e rodar o bootstrap nessa cópia:
152
+
153
+ ```bash
154
+ # Bash (Linux/macOS/WSL) — cópia fresca do cache para o diretório do projeto
155
+ TPL="${MORPH_TEMPLATE_CACHE:-$HOME/.morph/templates}/MORPH_Umbraco_LP_Template"
156
+ cp -r "$TPL" ./{projeto} && cd ./{projeto}
157
+ rm -rf .git && git init # desacopla do histórico do template
158
+ # --lead-integration: none | ghl | prospectpro | webhook
159
+ # --reset-db: primeiro boot limpo de um scaffold novo
160
+ ./scripts/new-lp.sh "Nome do Projeto" admin@projeto.com \
161
+ --lead-integration ghl \
162
+ --reset-db
163
+ ```
164
+
165
+ ```powershell
166
+ # PowerShell (Windows) — cópia fresca do cache para o diretório do projeto
167
+ $Tpl = "$env:USERPROFILE\.morph\templates\MORPH_Umbraco_LP_Template"
168
+ Copy-Item $Tpl ".\{projeto}" -Recurse; Set-Location ".\{projeto}"
169
+ Remove-Item .git -Recurse -Force; git init # desacopla do histórico do template
170
+ # new-lp.ps1 usa parâmetros NOMEADOS (não posicionais/--flag):
171
+ .\scripts\new-lp.ps1 -ProjectName "Nome do Projeto" -AdminEmail admin@projeto.com `
172
+ -LeadIntegration ghl -ResetDb
173
+ ```
174
+
175
+ > Alternativa: em vez de copiar do cache, fazer um clone fresco direto no diretório do projeto (`gh repo clone polymorphism-tech/MORPH_Umbraco_LP_Template {projeto}`) e então `rm -rf .git && git init`.
176
+
177
+ O script:
178
+ - Gera `.env` com `UMBRACO_ADMIN_EMAIL`, `UMBRACO_ADMIN_PASSWORD` (senha aleatória), `UMBRACO_GLOBAL_ID`, `REVALIDATE_SECRET`, `PROJECT_NAME` e `LEAD_INTEGRATION`.
179
+ - Integração de lead selecionada em `--lead-integration` (`none`/`ghl`/`prospectpro`/`webhook`). Em modo não-interativo sem a flag, assume `none`.
180
+
181
+ Nunca commitar `.env`. O cache do passo 0 permanece intacto (read-only) — todo o trabalho acontece nesta cópia.
182
+
183
+ **Smoke-boot antes de qualquer customização** — boot limpo do template para confirmar que o ambiente funciona:
184
+
185
+ ```bash
186
+ docker compose up --build
187
+ ```
188
+
189
+ Backend sobe em `http://localhost:5001`, frontend em `http://localhost:3000`. Acessar `http://localhost:3000` e confirmar que a página carrega sem erro 500. Isso elimina problemas de ambiente antes de introduzir customizações — falha precoce = horas economizadas.
190
+
191
+ **Atenção (gotcha Build do Next.js):** o Dockerfile do frontend executa `next build` na imagem — nesse momento o backend precisa estar acessível para o Next.js buscar conteúdo via Delivery API. Se o build rodar antes do backend estar pronto, o build falha com erro de fetch. O `docker compose` com `depends_on: backend` mitiga isso, mas em CI adicionar um `healthcheck` no serviço `backend` e `condition: service_healthy` no `depends_on` do `frontend`.
192
+
193
+ ### 4. Lift verbatim — portar markup, mídia e tema
194
+
195
+ **Esta é a etapa que garante a paridade exata.** Para cada seção, o trabalho é um **lift-and-rewire**, não um rebuild:
196
+
197
+ 1. **Copiar o componente da origem verbatim** para `frontend/src/components/modules/NomeSection.tsx` — mesmo JSX/HTML, mesmas classes, mesmo CSS, mesma estrutura. Não "limpar", não refatorar, não trocar libs de animação.
198
+ 2. **Trocar apenas os literais de conteúdo** (texto, `src` de imagem/vídeo, labels) por leituras do `data` prop do Umbraco. Tudo o que é layout/estilo/markup permanece igual.
199
+ 3. **Seedar** esses valores via `SeedContentHandler` para baterem com a origem (passo 4b) → o primeiro render é idêntico **por construção**; a editabilidade no backoffice fica por cima sem mudar o markup renderizado.
200
+ 4. **Copiar os assets sem reencode** (passo 4b) e **portar o CSS/tema verbatim** (passo 4c).
201
+
202
+ Os passos 4a-4d abaixo detalham cada parte. A regra que atravessa todos: **se mudou o markup ou o CSS renderizado, não é mais "exatamente igual"**.
203
+
204
+ #### 4a. Módulos novos — uSync ContentType
205
+
206
+ Para cada módulo novo identificado no passo 2, criar o arquivo `.config` em `backend/uSync/v17/ContentTypes/`. Espelhar a estrutura dos módulos existentes (ex.: `heroSection.config`):
207
+
208
+ ```xml
209
+ <!-- Exemplo: atelierSection.config -->
210
+ <?xml version="1.0" encoding="utf-8"?>
211
+ <ContentType Key="{novo-guid}" Alias="atelierSection" Level="2">
212
+ <Info>
213
+ <Name>Atelier Section</Name>
214
+ <Icon>icon-layers</Icon>
215
+ <Thumbnail>folder.png</Thumbnail>
216
+ <Description></Description>
217
+ <AllowAtRoot>False</AllowAtRoot>
218
+ <IsListView>False</IsListView>
219
+ <Variations>Nothing</Variations>
220
+ <IsElement>true</IsElement>
221
+ <Folder>Sections</Folder>
222
+ <Compositions />
223
+ <DefaultTemplate></DefaultTemplate>
224
+ <AllowedTemplates />
225
+ </Info>
226
+ <Structure />
227
+ <GenericProperties>
228
+ <GenericProperty>
229
+ <Key>{guid-prop}</Key>
230
+ <Name>Titulo</Name>
231
+ <Alias>titulo</Alias>
232
+ <Definition>0cc0eba1-9960-42c9-bf9b-60e150b429ae</Definition>
233
+ <Type>Umbraco.TextBox</Type>
234
+ <Mandatory>true</Mandatory>
235
+ <Description><![CDATA[]]></Description>
236
+ <SortOrder>0</SortOrder>
237
+ <Tab Alias="content/content">Content</Tab>
238
+ <Variations>Nothing</Variations>
239
+ </GenericProperty>
240
+ <!-- propriedades adicionais -->
241
+ </GenericProperties>
242
+ </ContentType>
243
+ ```
244
+
245
+ Cada módulo carrega suas próprias propriedades diretamente — os módulos do template não usam compositions compartilhadas para campos de seção (o `<Compositions />` é vazio nos módulos existentes; as compositions em `lpHome.config` são para SEO, cookie e analytics — composições transversais da home, não dos módulos filhos).
246
+
247
+ Para que o novo módulo apareça como opção de bloco na home, registrá-lo no DataType de Block List (`modules` em `lpHome.config`). O `<Definition>649d20e8-e4d5-42a0-9f27-28a537f9ebda</Definition>` aponta para esse DataType — adicionar o novo `ContentTypeKey` no XML do DataType em `backend/uSync/v17/DataTypes/` (arquivo correspondente) e no `SeedContentHandler` para o bloco ser incluído no seed programático.
248
+
249
+ #### 4b. Seed de conteúdo — SeedContentHandler
250
+
251
+ O `SeedContentHandler` (`backend/Infrastructure/SeedContentHandler.cs`) roda na notificação `uSyncImportCompletedNotification` — após o Umbraco importar todos os schemas — e cria a home com conteúdo inicial se ainda não existir. É **idempotente**: verifica se já há um nó raiz do tipo `lpHome` (ou alias equivalente) antes de criar.
252
+
253
+ Padrão de seed de uma seção com mídia:
254
+
255
+ ```csharp
256
+ // 1. Importar asset para a Media Library (idempotente por nome de arquivo)
257
+ var mediaItem = CreateOrGetMedia("hero-video.mp4", mediaFolder, "umbracoMediaVideo");
258
+ // mediaItem.Key é um Guid estável entre boots
259
+
260
+ // 2. Serializar referência como MediaPicker3 JSON
261
+ var mediaJson = JsonSerializer.Serialize(new[] {
262
+ new { key = Guid.NewGuid(), mediaKey = mediaItem.Key }
263
+ });
264
+
265
+ // 3. Setar na propriedade do nó de conteúdo
266
+ sectionNode.SetValue("videoFundo", mediaJson);
267
+ ```
268
+
269
+ Coloque os assets de seed em `backend/seed-assets/` (imagens, vídeos, ícones da LP de origem).
270
+
271
+ **O que vai no SeedContentHandler:** textos de inauguração, mídia local (arquivos em `seed-assets/`), ordem das seções, configuração inicial. O conteúdo fica editável no backoffice após o primeiro boot — o seed é apenas o estado inicial.
272
+
273
+ **O que NÃO vai no SeedContentHandler:** tokens de integração (GHL API Key, webhook URL). Esses ficam no nó `leadsConfig` que o operador preenche diretamente no backoffice após o boot (ver passo 5).
274
+
275
+ #### 4c. Tema — portabilidade do index.css
276
+
277
+ Copiar as variáveis de design da origem para `frontend/src/app/globals.css` no bloco `@theme`:
278
+
279
+ ```css
280
+ /* Antes (origem — index.css/CSS da LP) */
281
+ @theme {
282
+ --color-surface: #F5F0EB;
283
+ --color-primary: #8B1A1A;
284
+ --color-primary-hover: #A82020;
285
+ --color-tertiary: #1A1A1A;
286
+ --font-display: 'Cormorant Garamond', serif;
287
+ --font-body: 'Jost', sans-serif;
288
+ }
289
+
290
+ /* Depois (destino — frontend/src/app/globals.css) */
291
+ @theme {
292
+ --color-surface: #F5F0EB; /* portado diretamente */
293
+ --color-primary: #8B1A1A;
294
+ --color-primary-hover: #A82020;
295
+ --color-tertiary: #1A1A1A;
296
+ --font-display: 'Cormorant Garamond', serif;
297
+ --font-body: 'Jost', sans-serif;
298
+ }
299
+ ```
300
+
301
+ Atualizar os `<link>` de Google Fonts em `frontend/src/app/layout.tsx` para carregar as fontes corretas.
302
+
303
+ #### 4d. Componentes frontend dos módulos novos
304
+
305
+ Para cada módulo novo, criar o componente em `frontend/src/components/modules/NomeSection.tsx` **a partir do componente da origem copiado verbatim** — colar o JSX/markup/classes/CSS da origem e trocar só os literais de conteúdo por `data.*`:
306
+
307
+ ```tsx
308
+ // Padrão: componente com 'use client', recebe { data: SectionProps },
309
+ // faz cast para o tipo tipado, e lê props via data.property.
310
+ // O corpo do return é o MARKUP DA ORIGEM VERBATIM — mesmas tags, mesmas classes,
311
+ // mesma animação. Só os literais (texto, src) viram leituras de `d`.
312
+ 'use client'
313
+ import type { SectionProps, NomeSectionProps } from '@/lib/types'
314
+
315
+ type Props = { data: SectionProps }
316
+
317
+ export default function NomeSection({ data }: Props) {
318
+ const d = data as NomeSectionProps
319
+ // return ( <markup da origem, idêntico, com {d.titulo} no lugar do texto fixo> )
320
+ }
321
+ ```
322
+
323
+ Declarar o tipo correspondente em `frontend/src/lib/types.ts` com os aliases de propriedade do uSync.
324
+
325
+ Registrar o módulo em `frontend/src/components/modules/moduleRegistry.ts`:
326
+
327
+ ```ts
328
+ nomeSection: () => import('./NomeSection'),
329
+ ```
330
+
331
+ ### 5. Conectar o formulário ao backend de leads
332
+
333
+ O template usa uma arquitetura de **multi-sink**: o backend seleciona automaticamente a integração correta pelo valor de `leadIntegration` configurado no nó `leadsConfig` do backoffice.
334
+
335
+ **Sinks disponíveis no template:**
336
+
337
+ | `Key` do sink | Classe | Integração |
338
+ |---|---|---|
339
+ | `ghl` | `GhlLeadSink` | GoHighLevel CRM |
340
+ | `prospectpro` | `ProspectProLeadSink` | ProspectPRO |
341
+ | `webhook` | `WebhookLeadSink` | Webhook HTTP genérico |
342
+
343
+ O `LeadController` (`backend/Controllers/LeadController.cs`) recebe `IEnumerable<ILeadSink>` via DI e despacha para `sinks.FirstOrDefault(s => s.Key == cfg.Integration)`. Adicionar uma nova integração = implementar `ILeadSink` + uma linha no `LeadComposer.cs`.
344
+
345
+ **Configuração pós-boot (nunca em código):**
346
+
347
+ 1. Acessar o backoffice em `http://localhost:5001/umbraco`.
348
+ 2. Navegar até o nó **Leads Config** (criado automaticamente pelo `SeedContentHandler`).
349
+ 3. Preencher:
350
+ - `Lead Integration`: selecionar `ghl` / `prospectpro` / `webhook`.
351
+ - `API Key` / `Webhook URL` / campos específicos da integração.
352
+ 4. Publicar o nó.
353
+
354
+ O token nunca aparece no código-fonte nem em variáveis de ambiente — lido do cache publicado pelo `ReadConfig()` do controller via `IUmbracoContextFactory`.
355
+
356
+ **Frontend:** o componente `ContactSection` (`frontend/src/components/modules/ContactSection.tsx`) faz POST para `/api/leads` (rota do Next.js que faz thin-proxy para `{NEXT_PUBLIC_UMBRACO_URL}/api/leads`). Nenhuma credencial no frontend.
357
+
358
+ **Campos mínimos esperados pelo LeadController:** `name`, `email`, `phone`. Campos extras são aceitos no payload como propriedades livres e repassados ao sink.
359
+
360
+ **Normalização de telefone:** aplicar máscara no frontend antes do POST para garantir o formato `+55XXXXXXXXXXX` — o GHL rejeita telefones sem DDI. O template tem o helper `LeadHelpers.NormalizePhoneBR()` no backend como fallback (idempotente: preserva o `+55` se já presente), mas normalizar no frontend evita ambiguidade.
361
+
362
+ ### 6. Gate de paridade — confirmar que ficou EXATAMENTE igual
363
+
364
+ Objetivo: **provar** que a LP migrada é idêntica à origem. Com o lift verbatim (passo 4), os checks determinísticos abaixo passam **por construção** — se algum falha, é sinal de que o lift introduziu drift naquela seção; voltar e corrigir o lift, não "ajustar até parecer".
365
+
366
+ **Hierarquia do gate:** os checks **determinísticos** (6b) são o **bloqueio**. O **screenshot diff** (6c) é **corroboração secundária** — nunca o bloqueio único, porque font hinting/antialiasing diferem entre ambientes mesmo com CSS byte-idêntico.
367
+
368
+ #### 6a. Boot + checklist manual (sanidade)
369
+
370
+ ```bash
371
+ docker compose up --build
372
+ ```
373
+
374
+ Percorrer a página em `http://localhost:3000` e conferir, lado a lado com a origem: todas as seções na ordem certa, textos/mídias corretos, formulário visível, navegação e footer funcionando. Isso é só uma sanidade rápida antes dos checks automáticos.
375
+
376
+ #### 6b. Checks determinísticos (o bloqueio)
377
+
378
+ A skill **scaffolda** o harness de paridade no projeto destino (o template **não** o traz): criar `frontend/e2e/parity.spec.ts` e `frontend/compare-sections.mjs`. O harness compara `http://localhost:3000` (destino) contra a origem (URL de produção ou um build local da origem) e **falha** se qualquer dimensão divergir:
379
+
380
+ 1. **Estrutura DOM + nomes de classe** por seção — `compare-sections.mjs` extrai o esqueleto de tags+classes de cada `<section>`/`<nav>`/`<footer>` dos dois lados (agrupado por chave semântica/texto âncora) e aponta diferenças. Adaptar o array `KEYS` (`[nome, matchFn]`) aos textos âncora das seções do projeto.
381
+ 2. **Estilo computado** em elementos amostrados — para cada seção, comparar `getComputedStyle` de elementos-chave (cor, `font-family`, `font-size`, `font-weight`, paddings/margins, `border-radius`) origem × destino. Divergência = falha.
382
+ 3. **Checksum de assets** — o conjunto de `sha256` de todas as imagens/vídeos/fontes servidas pelo destino deve igualar o conjunto capturado da origem no passo 1. Asset reencode/otimizado quebra aqui (proposital).
383
+ 4. **Comportamento por interação** — uma asserção Playwright por comportamento capturado no passo 1 (scroll-expand, carrossel, marquee, autoplay de vídeo, hover, máscara/validação de telefone, submit do formulário com `/api/leads` mockado retornando `{"ok":true}`).
384
+
385
+ ```bash
386
+ cd frontend
387
+ npx playwright test # roda parity.spec.ts + smoke (home.spec.ts do template)
388
+ node compare-sections.mjs http://localhost:3000/ https://origem-em-producao.com.br/
389
+ ```
390
+
391
+ #### 6c. Screenshot diff (corroboração secundária)
392
+
393
+ Captura full-page origem × destino em múltiplos viewports (mobile/tablet/desktop). Para não gerar ruído:
394
+ - **desabilitar animações** (`prefers-reduced-motion` / CSS de teste), **aguardar as web-fonts** (`document.fonts.ready`), **congelar vídeo/carrossel** num frame fixo;
395
+ - usar **tolerância ciente de antialiasing** (ex.: `maxDiffPixelRatio` pequeno, threshold de cor).
396
+
397
+ Um diff acima da tolerância é um **alerta para investigar** (provável seção com lift incompleto), não uma reprovação automática se os checks de 6b passam.
398
+
399
+ #### 6d. Critérios de aceite
400
+
401
+ A migração é "exata" quando **todos** são verdade:
402
+ - **6b determinístico passa**: DOM+classes, estilo computado, checksum de assets e comportamento batem com a origem em todas as seções.
403
+ - **6c screenshot diff** abaixo da tolerância em todos os breakpoints (mobile/tablet/desktop).
404
+ - Todas as seções renderizam com conteúdo real (não placeholders) e na ordem da origem.
405
+ - Formulário envia lead com sucesso para a integração configurada (testar com dado real em staging; `--demo-seed` popula a home com módulos de demonstração via `SEED_DEMO_CONTENT=true`, não envia lead de teste).
406
+ - Backoffice: editar um campo de texto, publicar — a mudança reflete na página (revalidação por tag ou ISR) **sem** alterar o markup/estilo renderizado.
407
+ - Nenhuma chave de API ou token aparece em arquivo versionado.
408
+
409
+ ## Anti-padrões
410
+
411
+ - Não commitar `.env` nem nenhum arquivo com tokens ou senhas.
412
+ - Não colocar credenciais de integração em variáveis de ambiente do container — elas pertencem ao nó `leadsConfig` no backoffice.
413
+ - Não criar módulos novos com alias que conflite com os do template (verificar `lpHome.config` e os `.config` existentes antes de nomear).
414
+ - Não usar `Guid.NewGuid()` em `SeedContentHandler` para o `Key` de um `mediaKey` que deve ser estável entre boots — calcular o GUID deterministicamente a partir do nome do arquivo ou recuperar o existente com `GetByKey`.
415
+ - Não saltear o smoke-boot (passo 3) — problemas de ambiente devem ser detectados antes de portar conteúdo.
416
+ - Não reutilizar `customHtmlSection` para tudo — módulos dedicados permitem edição granular no backoffice e ISR por tag.
417
+ - **Não reinterpretar layout/CSS nem "limpar" o markup** — portar verbatim; o módulo Umbraco só embrulha o mesmo markup da origem. Rebuild = drift.
418
+ - **Não reencodar nem otimizar assets** na migração — quebra a paridade de checksum (6b) e altera o render.
419
+ - **Não assumir o tema do template** — portar o Tailwind/`@theme` (e as fontes) da origem; a mesma classe utilitária renderiza diferente entre versões/temas.
420
+ - **Não tratar o screenshot diff como gate único** — o bloqueio são os checks determinísticos (6b); o diff visual é secundário.
421
+
422
+ ## Output esperado
423
+
424
+ - `docs/origem-inventario.md` — inventário de seções, conteúdo, mídia e identidade visual da LP de origem.
425
+ - `docs/mapeamento-modulos.md` — tabela de mapeamento seção → doctype/módulo com decisão (reuso direto / ajuste / lift verbatim).
426
+ - `backend/uSync/v17/ContentTypes/*.config` — novos doctypes para os módulos lifted da origem.
427
+ - `backend/Infrastructure/SeedContentHandler.cs` — seed idempotente com textos e mídia iniciais.
428
+ - `backend/seed-assets/` — assets de seed (imagens, vídeos copiados da origem).
429
+ - `frontend/src/components/modules/*.tsx` — componentes dos módulos novos.
430
+ - `frontend/src/components/modules/moduleRegistry.ts` — atualizado com novos aliases.
431
+ - `frontend/src/lib/types.ts` — tipos TypeScript para as props dos novos módulos.
432
+ - `frontend/src/app/globals.css` — tema portado verbatim da origem (paleta + tipografia + fontes).
433
+ - `frontend/e2e/home.spec.ts` — smoke test adaptado para o projeto.
434
+ - `frontend/e2e/parity.spec.ts` — **gerado pela skill**: gate determinístico (DOM+classes, estilo computado, checksum de assets, comportamento) + screenshot diff.
435
+ - `frontend/compare-sections.mjs` — **gerado pela skill**: comparação de esqueleto estrutural origem × destino.
436
+ - `.env` gerado pelo `new-lp.sh` / `new-lp.ps1` — **não versionado** (`.gitignore`).
437
+
438
+ ## Referências
439
+
440
+ Repo do template (privado, branch `master`): `polymorphism-tech/MORPH_Umbraco_LP_Template` — obtido automaticamente no passo 0.
441
+
442
+ - `MORPH_Umbraco_LP_Template/scripts/new-lp.sh` e `new-lp.ps1` — scaffold de nova LP
443
+ - `MORPH_Umbraco_LP_Template/backend/Lead/LeadComposer.cs` — registro dos sinks no DI
444
+ - `MORPH_Umbraco_LP_Template/backend/Lead/ILeadSink.cs` — interface de integração de leads
445
+ - `MORPH_Umbraco_LP_Template/backend/Controllers/LeadController.cs` — controller público + `ReadConfig()` + dispatch
446
+ - `MORPH_Umbraco_LP_Template/backend/Lead/GhlLeadSink.cs`, `ProspectProLeadSink.cs`, `WebhookLeadSink.cs` — sinks concretos
447
+ - `MORPH_Umbraco_LP_Template/backend/Infrastructure/SeedContentHandler.cs` — seed idempotente com mídia (MediaPicker3)
448
+ - `MORPH_Umbraco_LP_Template/backend/uSync/v17/ContentTypes/lpHome.config` — doctype raiz da home (Block List `modules`)
449
+ - `MORPH_Umbraco_LP_Template/frontend/src/components/modules/moduleRegistry.ts` — registro dos módulos
450
+ - `MORPH_Umbraco_LP_Template/frontend/src/app/globals.css` — bloco `@theme` para portar o tema da origem
451
+ - `MORPH_Umbraco_LP_Template/frontend/e2e/home.spec.ts` + `playwright.config.ts` — base de e2e (estender com `parity.spec.ts`)
452
+ - `MORPH_Umbraco_LP_Template/docker-compose.yml` — orquestração backend + frontend com variáveis de ambiente
@@ -4,7 +4,7 @@ description: Orquestra a execução autônoma de tasks de uma feature morph-spec
4
4
  version: core
5
5
  when-to-invoke: após Gate 2 aprovado, ao receber instrução "use /morph-apply" ou "implementar feature"
6
6
  user-invokable: true
7
- cliVersion: "7.3.0"
7
+ cliVersion: "7.5.0"
8
8
  ---
9
9
 
10
10
  # morph-apply
@@ -15,7 +15,7 @@ Executar todas as tasks pendentes de uma feature até `done`, aplicando `morph-e
15
15
 
16
16
  ## Quando invocar
17
17
 
18
- - Após Gate 2 aprovado (verificar `.morph/state.json → features[X].approvalGates.plan === true`).
18
+ - Após Gate 2 aprovado (verificar `.morph/features/{feature}/feature.json → approvalGates.plan.approved === true`).
19
19
  - Usuário pede "use /morph-apply {feature}" ou "implementar {feature}".
20
20
 
21
21
  ## Argumentos
@@ -26,7 +26,7 @@ Executar todas as tasks pendentes de uma feature até `done`, aplicando `morph-e
26
26
 
27
27
  - `.morph/features/{feature}/2-plan/tasks.json` existe e é válido (schema check).
28
28
  - `.morph/features/{feature}/2-plan/spec.md` e `mandate.md` existem.
29
- - Gate 2 está marcado aprovado no state.json (ou trust:auto está ativo).
29
+ - Gate 2 está marcado aprovado no `feature.json` da feature (ou trust:auto está ativo).
30
30
 
31
31
  ## Fluxo
32
32
 
@@ -41,18 +41,26 @@ Executar todas as tasks pendentes de uma feature até `done`, aplicando `morph-e
41
41
 
42
42
  ### 2. Análise de DAG — decisão sequencial vs paralelo
43
43
 
44
- Construir o grafo de dependências e detectar subsets independentes.
44
+ Construir o grafo de dependências e detectar fluxos de trabalho independentes. Há duas formas de paralelismo a detectar — e a segunda é a que mais aparece na prática:
45
+
46
+ ```js
47
+ const groups = groupTasks(data); // { backend: [ids], frontend: [ids], tests: [...], infra: [...], docs: [...] }
48
+ const independentRoots = data.tasks.filter(t => t.dependencies.length === 0);
49
+ ```
45
50
 
46
51
  **Regras de decisão:**
47
52
 
48
53
  1. Se `data.tasks.length <= 3`: **sequencial** (overhead de Agent dispatch não compensa).
49
- 2. Identificar tasks **100% independentes** (`dependencies: []`):
50
- - Se `>= 3` tasks independentes existem: dispachar essas em **paralelo**, depois cair em sequencial para o resto.
51
- 3. Caso contrário: **sequencial puro** com auto-advance.
54
+ 2. **Fluxos de domínio independentes (o caso comum — backend ‖ frontend).** Use `groupTasks(data)` para separar as tasks por `group`. Dois grupos formam fluxos paralelos quando **nenhuma task de um grupo depende de uma task de outro grupo** (as cadeias só convergem, se convergirem, numa task final de integração). Se existem **≥ 2 fluxos de domínio independentes** — ex: a cadeia `backend` `T1→…→T11` e a cadeia `frontend` `T12→T13` não se cruzam até `T14` —, dispache **um sub-agent por fluxo, em paralelo**, cada um com a persona e o standard do seu domínio (ver passo 3b). Esse é exatamente o caso que a regra antiga de "≥3 raízes independentes" deixava passar (duas cadeias contam como 2 raízes, não 3).
55
+ 3. **Raízes independentes (fan-out na largura).** Identificar tasks **100% independentes** (`dependencies: []`). Se `independentRoots.length >= 3`: dispachar essas raízes em **paralelo**, depois cair em sequencial para o resto.
56
+ 4. Caso contrário: **sequencial puro** com auto-advance.
57
+
58
+ > O cap de **4 agentes simultâneos** (anti-padrão abaixo) vale para ambas as formas. Se um fluxo de domínio é uma cadeia longa, despache o **fluxo inteiro** a um sub-agent (que executa a cadeia em ordem internamente) — um agente por fluxo, não um agente por task.
52
59
 
53
- Logar a decisão:
60
+ Logar a decisão (mostre qual forma disparou):
54
61
  ```
55
- DAG analysis: 12 tasks, 4 independent → parallel batch (T1, T3, T7, T9) + sequential remainder
62
+ DAG analysis: 14 tasks, groups {backend:9, frontend:2, tests:2, infra:1}; backend ‖ frontend independentes até T14 → 2 fluxos paralelos (1 agente backend, 1 agente frontend) + T14 sequencial no fim
63
+ DAG analysis: 12 tasks, 4 raízes independentes → parallel batch (T1, T3, T7, T9) + sequential remainder
56
64
  ```
57
65
 
58
66
  ### 3a. Modo Sequencial (auto-advance)
@@ -68,39 +76,69 @@ while (true):
68
76
  updateTaskStatus(data, task.id, 'in_progress')
69
77
  writeTasksJson(tasksPath, data)
70
78
 
71
- invoke Skill(morph-implement) with task
72
-
73
- result = invoke Skill(morph-eval) with implementation output
74
-
75
- if result.score >= 8:
79
+ // Loop de correção autônomo — a barra de qualidade é >= 9 (ver MORPH.md §0).
80
+ // Entre tasks NÃO há pausa humana: score < 9 dispara re-implementação, não AskUserQuestion.
81
+ attempt = 0
82
+ best = { score: 0, output: null }
83
+ while attempt < 3:
84
+ attempt += 1
85
+ invoke Skill(morph-implement) with task
86
+ (no attempt > 1: passar o feedback priorizado do morph-eval anterior como input)
87
+ result = invoke Skill(morph-eval) with implementation output
88
+ if result.score > best.score: best = result
89
+ // Persista o score no feature.json autoritativo da feature, sob taskScores — torna o
90
+ // evalScore um signal de disco no MOMENTO da implementação (não no fim). O hook
91
+ // gate-guard.js e o Gate 3 leem dali. Edit em .morph/features/** é permitido. Grave:
92
+ // taskScores[task.id] = { lastScore: result.score, bestScore: best.score, attempts: attempt, updatedAt: <ISO> }
93
+ edit .morph/features/{feature}/feature.json com o taskScores acima
94
+
95
+ if result.score >= 9:
96
+ break
97
+
98
+ if best.score >= 9:
76
99
  updateTaskStatus(data, task.id, 'done')
77
100
  else:
78
- // forçar pausa — qualidade é guardrail, trust não ignora aqui
79
- AskUserQuestion: "Task {id} com score {score} — aceitar, reimplementar ou pular?"
80
- options: [aceitar mesmo assim, reimplementar, pular task]
101
+ // 3 tentativas sem atingir 9 — AQUI sim escala ao humano (escape definido).
102
+ // Esta é a única pausa do loop de implement, e só após esgotar o loop de correção.
103
+ registrar em recap.md: as 3 tentativas e o melhor score (best.score) com o feedback
104
+ AskUserQuestion: "Task {id} não atingiu score 9 após 3 tentativas (melhor: {best.score}) — aceitar mesmo assim, continuar tentando, ou pular?"
105
+ options: [aceitar (marca done com ressalva no recap), continuar tentando (+3 tentativas), pular task (marca blocked)]
81
106
 
82
107
  writeTasksJson(tasksPath, data)
83
108
  ```
84
109
 
110
+ > **Por que loop e não pausa:** MORPH.md §0 manda auto-avançar entre tasks. Score baixo numa task individual é um problema de qualidade que o modelo deve **corrigir sozinho**, não delegar ao humano no meio da implementação. A pausa só existe quando o loop de correção se esgota (3 tentativas) — o "escape" do modelo autônomo. O trust mode não muda esse loop: ele governa os **gates** (proposal/plan/review), não o ciclo de correção intra-task.
111
+
85
112
  ### 3b. Modo Paralelo (para o subset independente)
86
113
 
87
- Para cada task independente:
114
+ **Antes de despachar, escope cada agente ao seu domínio.** Um agente genérico sem persona nem standard não "conhece" as convenções daquele domínio — produz código fora do padrão. Para cada fluxo/task a despachar, resolva:
115
+
116
+ - **Persona:** em `agents.json`, encontre o agente cujo `domains` cobre o `group`/domínio da task (ex: `backend` → `dotnet-senior`, `frontend` → `nextjs-expert`/`ui-designer`, `database` → `ef-modeler`). Pegue o texto do campo `persona`.
117
+ - **Standard(s):** do array `standards` desse mesmo agente em `agents.json` (e/ou do `mandate.md`), selecione o(s) path(s) `.md` relevante(s) à task.
118
+
88
119
  ```
89
120
  dispatch Agent (subagent_type: "general-purpose") with prompt:
121
+ persona: <texto do campo `persona` do agente de domínio em agents.json>
90
122
  contexto: spec.md, mandate.md, task description completa, doneCriteria
123
+ standard: <path(s) .md do(s) standard(s) do domínio — leia-o(s) antes de implementar>
91
124
  instrução: |
92
- Implemente esta task isoladamente. Não modifique spec.md, mandate.md.
125
+ Adote a persona acima. Leia o(s) standard(s) indicado(s) antes de escrever código.
126
+ Implemente esta task (ou cadeia de tasks do fluxo) isoladamente.
127
+ Não modifique spec.md, mandate.md.
93
128
  Retorne:
94
129
  - sumário das mudanças
95
130
  - arquivos modificados (paths)
131
+ - standard(s) consultado(s)
96
132
  - auto-score 0-10 (rubric: completeness, correctness, mandate compliance)
97
133
  ```
98
134
 
135
+ > Este template é deliberadamente paritário com o template sequencial em `morph-implement` §4: ambos passam **persona + standard escopados**. A única diferença é que aqui múltiplos agentes rodam ao mesmo tempo, um por fluxo independente.
136
+
99
137
  Aguardar todos os agentes terminarem (Promise.all equivalente). Depois, sequencialmente:
100
138
  - Para cada output retornado:
101
139
  - Aplicar `Skill(morph-eval)`.
102
- - Se score >= 8: marcar `done`.
103
- - Se score < 8: marcar `pending` novamente com nota — será re-executada no modo sequencial.
140
+ - Se score >= 9: marcar `done`.
141
+ - Se score < 9: marcar `pending` novamente com nota — volta ao modo sequencial, onde o loop de correção (até 3 tentativas) busca o score 9.
104
142
 
105
143
  Depois do batch paralelo, executar o restante em modo sequencial (passo 3a).
106
144
 
@@ -115,25 +153,29 @@ Quando `getPendingTasks(data).length === 0`:
115
153
 
116
154
  Sinais de risco para Gate 3:
117
155
 
118
- - Score médio < 8 no review-report.
156
+ - Score médio < 9 no review-report.
119
157
  - Presença de erros não resolvidos.
120
158
  - Mudanças incidentais em standards/.morph/framework/.
121
159
 
122
160
  Mesma lógica do Gate 1/Gate 2 via `shouldPauseGate(config, signals)`:
123
161
 
162
+ **Persista a decisão no `feature.json` autoritativo da feature ANTES de apresentar ou auto-aprovar** — grave
163
+ `gateDecisions.review = { pause, reason, signals, trust, decidedAt: <ISO> }` em `.morph/features/{feature}/feature.json`
164
+ (o `signals.evalScore` aqui é o score composto do review-report; Edit em `.morph/features/**` é permitido). O hook `gate-guard.js` confere depois se a ação bateu. Sem o registro o guard não verifica.
165
+
124
166
  - Pause: `AskUserQuestion` com options `["aprovado, fechar feature", "preciso ajustar", "rollback"]`.
125
- - Auto: exibir summary do review-report e prosseguir.
167
+ - Auto: exibir summary do review-report, aprovar via `morph-spec approve {feature} review --mode auto`, e prosseguir.
126
168
 
127
169
  ### 6. Pós Gate 3
128
170
 
129
- - Atualizar `state.features[feature].status = "completed"` via state-sync (hook detecta "aprovado" em AskUserQuestion answer).
171
+ - Aprovar o Gate 3: em auto, `morph-spec approve {feature} review --mode auto`; em manual, o hook state-sync registra a resposta "aprovado" em AskUserQuestion. O gate fica gravado no `feature.json` autoritativo da feature — nunca via Edit à mão de `state.json`.
130
172
  - Sinalizar: "Feature {nome} concluída. Rode `/morph-archive {feature}` para arquivar."
131
173
  - Não arquivar automaticamente.
132
174
 
133
175
  ## Anti-padrões
134
176
 
135
177
  - Não dispachar paralelo se há deps cruzadas entre as tasks selecionadas (corrompe ordem).
136
- - Não pular `morph-eval` — silêncio em score >= 8 é o sinal correto.
178
+ - Não pular `morph-eval` — uma task só avança com score >= 9; abaixo disso, o loop de correção roda (não pausa).
137
179
  - Não reescrever spec.md/mandate.md durante implement (são read-only após Gate 2 — `protect-spec-files.js` hook bloqueia).
138
180
  - Não dispachar mais que 4 agentes em paralelo (sobrecarga de contexto + custo).
139
181
 
@@ -142,8 +184,8 @@ Mesma lógica do Gate 1/Gate 2 via `shouldPauseGate(config, signals)`:
142
184
  - Todas as tasks em `tasks.json` com status `done` ou `skipped`.
143
185
  - `.morph/features/{feature}/3-implement/recap.md` produzido por morph-implement.
144
186
  - `.morph/features/{feature}/4-review/review-report.md` produzido por morph-review.
145
- - Gate 3 marcado aprovado em `.morph/state.json` (via state-sync hook ou Edit direto).
146
- - `state.features[feature].status === "completed"`.
187
+ - Gate 3 registrado aprovado em `.morph/features/{feature}/feature.json` (autoritativo) — via `morph-spec approve` em auto, ou pelo hook state-sync no caminho manual.
188
+ - Feature com Gate 3 aprovado e pronta para `morph-spec archive` (que carimba `status: "completed"` + `archivedAt`).
147
189
 
148
190
  ## Referências
149
191