@polymorphism-tech/morph-spec 10.1.1 → 10.5.2
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.
- package/README.md +3 -7
- package/bin/morph-spec.js +10 -41
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +1 -4
- package/docs/QUICKSTART.md +1 -1
- package/framework/MORPH.md +1 -1
- package/framework/agents.json +1 -2
- package/framework/commands/morph-archive.md +1 -1
- package/framework/commands/morph-preflight.md +3 -4
- package/framework/docs/CLI.md +45 -22
- package/framework/evals/review-checklist.md +5 -5
- package/framework/hooks/README.md +2 -2
- package/framework/hooks/claude-code/core/heavy-gate.js +21 -2
- package/framework/hooks/claude-code/core/validate-completion.js +0 -35
- package/framework/hooks/shared/e2e-check.js +44 -7
- package/framework/hooks/shared/heavy-command.js +12 -1
- package/framework/hooks/shared/heavy-config.js +12 -0
- package/framework/hooks/shared/host-services.js +9 -6
- package/framework/hooks/shared/next-step.js +12 -8
- package/framework/phases.json +4 -4
- package/framework/rules/plan-grammar.md +4 -1
- package/framework/schemas/config.schema.json +59 -1
- package/framework/schemas/feature.schema.json +15 -0
- package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
- package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
- package/framework/skills/core/morph-apply/SKILL.md +8 -5
- package/framework/skills/core/morph-apply/references/hotfix.md +1 -1
- package/framework/skills/core/morph-apply/references/machine.md +3 -2
- package/framework/skills/core/morph-apply/references/review.md +9 -7
- package/framework/skills/core/morph-plan/SKILL.md +7 -6
- package/framework/skills/core/morph-plan/references/critique.md +1 -1
- package/framework/skills/core/morph-uiux/SKILL.md +2 -2
- package/framework/templates/IDE-SNIPPETS.md +262 -262
- package/framework/templates/code/dotnet/abstractions/api-endpoint.cs +7 -7
- package/framework/templates/code/dotnet/feature/request.cs.hbs +4 -4
- package/framework/templates/code/dotnet/feature/response.cs.hbs +4 -4
- package/framework/templates/code/sql/ai-agents/pgvector-embeddings-migration.sql.template +91 -91
- package/framework/templates/docs/plan.md +2 -1
- package/framework/templates/examples/design-system-examples.md +0 -3
- package/framework/templates/frontend/nextjs/client-component.tsx.hbs +26 -26
- package/framework/templates/frontend/nextjs/tsconfig.json.hbs +26 -26
- package/framework/templates/infrastructure/docker/Dockerfile.template +58 -58
- package/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -38
- package/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -48
- package/framework/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +45 -45
- package/framework/templates/infrastructure/github/actions/health-check/action.yml.hbs +27 -27
- package/framework/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +59 -59
- package/framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +39 -39
- package/framework/templates/state.template.json +17 -17
- package/framework/templates/ui/design-system.css +226 -226
- package/package.json +1 -1
- package/src/commands/project/doctor.js +0 -1
- package/src/commands/project/heavy.js +13 -0
- package/src/commands/state/approve.js +9 -109
- package/src/commands/state/report-check.js +44 -2
- package/src/commands/validation/verify.js +57 -7
- package/src/core/state/state-manager.js +0 -24
- package/src/dashboard/app/main.jsx +13 -13
- package/src/dashboard/vite.config.js +24 -24
- package/src/lib/heavy/cleanup.js +8 -2
- package/src/lib/heavy/gate.js +24 -1
- package/src/lib/heavy/reclaim.js +107 -0
- package/src/lib/heavy/watchdog.js +46 -0
- package/src/lib/next-step.js +1 -0
- package/src/lib/plan/checks.js +1 -1
- package/src/lib/plan/critique.js +23 -3
- package/src/lib/procs/prune.js +23 -1
- package/src/lib/review-confirmation.js +67 -0
- package/src/lib/review-reports.js +1 -0
- package/src/lib/risk-detector.js +2 -2
- package/src/lib/tasks/test-nodes.js +10 -0
- package/src/lib/tasks/test-runner.js +37 -43
- package/src/lib/telemetry/telemetry-reader.js +1 -2
- package/src/lib/telemetry/verify-event.js +7 -0
- package/src/lib/validators/verify-cache.js +63 -0
- package/src/lib/validators/verify-runner.js +131 -26
- package/src/lib/verify/affected.js +141 -0
- package/src/lib/verify/detached.js +154 -0
- package/src/utils/agents-installer.js +2 -2
- package/src/utils/hooks-installer.js +0 -20
- package/bin/validate.js +0 -212
- package/framework/hooks/claude-code/__pycache__/statusline.cpython-313.pyc +0 -0
- package/framework/templates/.idea/morph-templates.xml +0 -92
- package/framework/templates/.vscode/morph-templates.code-snippets +0 -186
- package/src/commands/observability/telemetry.js +0 -60
- package/src/commands/validation/validate-feature.js +0 -337
|
@@ -10,23 +10,23 @@ Por que fresco: o que você sabe da implementação é o ponto cego que eles exi
|
|
|
10
10
|
|
|
11
11
|
## 2. Prova da suíte — uma rodada
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
A rodada afetada do §3 da `SKILL.md`, verde, é o que abre o dispatch. A completa vem depois dos relatórios (§6), uma vez só: assim uma correção do Gate 3 não paga duas rodadas cheias, e o que a completa encontrar ainda passa pela confirmação.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
`flaky` no resultado do verify → a lista vai ao verificador. Com `e2eChecks`, `morph-spec e2e status {feature} --json` → `baseUrl` vai ao verificador.
|
|
16
16
|
|
|
17
17
|
## 3. Dispatch — os três na mesma resposta
|
|
18
18
|
|
|
19
|
-
`morph-spec report-check {feature} --before-eval --json` tira a foto da árvore e diz `reviewModels.verifier.model` (opus com prompt/modelo ou mídia)
|
|
19
|
+
`morph-spec report-check {feature} --before-eval --json` tira a foto da árvore e diz `reviewModels.verifier.model` (opus com prompt/modelo ou mídia), `reviewModels.security.required` e, em `gate3`, `base`, `sha`, `flaky` e `e2eChecks`. `e2eChecks` não vazio sem `baseUrl`: suba a stack com `morph-spec e2e up {feature}` antes do dispatch; `Cn` sem stack é pendência sua, não rodada de FIX. O revisor calcula o próprio blast radius (`morph-spec graph diff --base {base} --json`, `graph affected`; sem grafo, `git grep`).
|
|
20
20
|
|
|
21
21
|
Despache **sem nome** no dispatch (com nome, o `agent_type` que o hook `test-budget` lê vira o nome e o guard não reconhece o papel). `chore`: só o revisor (∥ segurança).
|
|
22
22
|
|
|
23
23
|
```
|
|
24
24
|
Agent (subagent_type: "morph-verifier", model: {reviewModels.verifier.model}):
|
|
25
|
-
feature; o conteúdo de 2-plan/checks.json; baseUrl
|
|
25
|
+
feature; o conteúdo de 2-plan/checks.json; baseUrl; gate3.flaky, se houver;
|
|
26
26
|
reset entre fluxos: `morph-spec e2e reset {feature}`; 1-design/mockups.md se existir;
|
|
27
27
|
grave .morph/features/{feature}/4-review/verifier.md
|
|
28
28
|
Agent (subagent_type: "morph-reviewer"):
|
|
29
|
-
feature, base, sha
|
|
29
|
+
feature, base, sha;
|
|
30
30
|
grave .morph/features/{feature}/4-review/reviewer.md
|
|
31
31
|
Agent (subagent_type: "morph-security"): ← só com security.required
|
|
32
32
|
feature, base, sha, reviewModels.security.reasons;
|
|
@@ -43,12 +43,14 @@ Não rode build nem teste enquanto um agente está `running`. Com todos de volta
|
|
|
43
43
|
|
|
44
44
|
## 5. Bloqueadores
|
|
45
45
|
|
|
46
|
-
O avaliador também erra: **reproduza cada bloqueador antes de editar**. Não se reproduz → é nota sua no `report.md`, e o próximo dispatch de confirmação recebe a contra-evidência. Confirmado → corrija, commite, `verify {feature}
|
|
46
|
+
O avaliador também erra: **reproduza cada bloqueador antes de editar**. Não se reproduz → é nota sua no `report.md`, e o próximo dispatch de confirmação recebe a contra-evidência. Confirmado → corrija, commite, `verify {feature} --affected`, foto `--before-eval` nova.
|
|
47
47
|
|
|
48
|
-
Confirmação = **dispatch novo**
|
|
48
|
+
Confirmação = **dispatch novo** só dos papéis em `gate3.redispatch`, com o `sha` novo e o escopo da rodada: quem abriu bloqueadores confirma só esses (verificador: "confirme só C2, C5"); os outros julgam só o delta `{sha anterior}..{sha novo}`. Papel com SHIP limpo não volta se o delta ficar nos arquivos citados pelos bloqueadores ou em teste; a segurança, se o delta não tocar caminho sensível. Ninguém reavalia a feature inteira. O relatório é append-only e vale o último `**Verdict:**`; o `approve` recusa quando o código andou depois de um `**Reviewed-SHA:**`, salvo esse caso, com quem abriu bloqueador confirmando o `HEAD`.
|
|
49
49
|
|
|
50
50
|
## 6. Gate 3
|
|
51
51
|
|
|
52
|
+
**A rodada completa:** com os relatórios sem bloqueador, `morph-spec verify {feature} --ci --json --detach` em `run_in_background` (sem CI, roda local e diz por quê; repetir o comando retoma a rodada). É a única. Sem `--filter`, sempre, e sem `--affected`: verde filtrado é verde sobre código não testado, e é ela que o gate lê. `reason: "stamp-reused"` = nada andou desde o último verde: vale. Saída `CI rodando` → espere a notificação. `fail` → corrija (CI: `gh run view <id> --log-failed`) e siga o §5, porque a correção é código que ninguém revisou. Nó `e2e` em `skip` → o `gate-check` decide se dispensa (`classifyE2eSkip`, em `risk-detector.js`: docker indisponível pausa sozinho).
|
|
53
|
+
|
|
52
54
|
`morph-spec gate-check {feature} review [--json]` lê os relatórios, a cobertura dos `Cn` e os demais sinais. Forçar passagem apesar da pausa: `morph-spec gate-decision {feature} review --pause false --reason "…"`.
|
|
53
55
|
|
|
54
56
|
Pausa com `resolver: "session"` não é pergunta: faça o que a `reason` diz e rode o `gate-check` de novo. Verify vermelho ou velho → corrija e `verify {feature}`; e2e pulado a pedido → `verify {feature}` sem `--skip-e2e`; bloqueador ou `Cn` não provado → §5; relatório ausente ou sem seção → dispatch. Vira `human` sozinho depois de `FIX_ATTEMPTS` verify vermelhos seguidos ou rodadas de review: a disputa é do usuário.
|
|
@@ -4,7 +4,7 @@ description: Leva um pedido ou o link de uma issue ao plano aprovado — roteia
|
|
|
4
4
|
version: core
|
|
5
5
|
when_to_use: Use quando uma feature, bug ou chore começar ("/morph-plan {feature}", "/morph-plan <link da issue>", "vamos planejar X"), ou ao retomar uma feature cujo gate plan ainda não foi aprovado
|
|
6
6
|
user-invocable: true
|
|
7
|
-
cliVersion: "10.
|
|
7
|
+
cliVersion: "10.5.2"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-plan
|
|
@@ -44,13 +44,13 @@ Entra na árvore só o que muda escopo, comportamento ou arquitetura e a varredu
|
|
|
44
44
|
|
|
45
45
|
## 4. Reuso
|
|
46
46
|
|
|
47
|
-
Por conceito central (entidade, DTO, componente, hook, helper): `morph-spec graph explain <nome> --json` e `graph affected <nome> --uses-only --json` (`--uses-only`: o grep conta herança como uso). Sem grafo, `grep -rn` e anote que a contagem veio do grep. O veredito vai na tabela `## Reuso`.
|
|
47
|
+
Por conceito central que o plano pretende criar (entidade, DTO, componente, hook, helper): `morph-spec graph explain <nome> --json` e `graph affected <nome> --uses-only --json` (`--uses-only`: o grep conta herança como uso). Sem grafo, `grep -rn` e anote que a contagem veio do grep. O veredito vai na tabela `## Reuso`.
|
|
48
48
|
|
|
49
49
|
## 5. plan.md
|
|
50
50
|
|
|
51
51
|
O `create` escreveu o esqueleto; a gramática completa chega pela rule `plan-grammar` quando você abre o `plan.md`; o resto em `morph-spec plan-check --help`. O que importa:
|
|
52
52
|
|
|
53
|
-
- **`Resultado buscado:`** uma linha em `## Problema`: o estado depois, o que muda, para quem e como se percebe. É contra ela que a `morph-apply` decide se uma descoberta invalida o plano.
|
|
53
|
+
- **`Resultado buscado:`** uma linha em `## Problema`: o estado depois, o que muda, para quem e como se percebe; o objetivo por trás do pedido, nunca o pedido reescrito. Medível, leva um número específico e difícil: alvo pequeno se atinge ajustando, alvo duro obriga a repensar. É contra ela que a `morph-apply` decide se uma descoberta invalida o plano e que o revisor lê as notas do Gate 3.
|
|
54
54
|
- **`## Cenários` é a definição de pronto.** Cada `Cn` é um comportamento observável que o verificador do Gate 3 vai **executar** contra a app — escreva-o como um fluxo de usuário ou uma regra que dá para disparar. `prova:` `teste` (com `risco:`) | `e2e` | `eval` | `manual` | `leitura`. Sem risco, `leitura`.
|
|
55
55
|
- **`degrau:`** quando o `Cn` não se desfaz com revert: `migrar` (toda migration, aditiva ou não: drop, rename, backfill, coluna nova) ou `irreversível` (apaga dado que alguém lê, quebra contrato externo). Sem a linha, `refazer`. Esses dois degraus pausam o gate do plano para o usuário, e o Gate 3 pausa em migration sem degrau, em arquivo de contrato (`openapi`, `.proto`) sem `irreversível`, e no bloqueador `irreversivel` do revisor.
|
|
56
56
|
- **`## Padrões assumidos`**: todo valor de baixo risco que você decidiu sem perguntar, numerado `1.`…`N.`, com o valor. É o que tira a pergunta trivial da entrevista: o usuário veta por número. Auth, credencial, permissão, pagamento e apagar dado nunca entram: são pergunta.
|
|
@@ -60,7 +60,8 @@ O `create` escreveu o esqueleto; a gramática completa chega pela rule `plan-gra
|
|
|
60
60
|
- **`## Arquitetura`**: onde entra, o que conversa com o quê, edge cases técnicos. Gera imagem ou vídeo por IA → cite aqui o standard (`ai-agents-modalities-image-gen`, `ai-agents-media-video`, `ai-agents-media-pipeline`): é a citação que arma as provas de mídia do Gate 3, e o `plan-check` recusa o plano que fala em mídia gerada sem ela (falso positivo: a linha `Mídia gerada: não`).
|
|
61
61
|
|
|
62
62
|
**Contrato de implementação**: o que quem implementa precisa e o código não diz.
|
|
63
|
-
- **
|
|
63
|
+
- **Profundidade** (`feature`, antes de fechar os cenários; plano pequeno, §6, dispensa): uma linha para cada, sem aumentar o escopo: o que um profissional da área faria aqui que o pedido não pede; a matéria-prima mais crua de que ele partiria (export de produção, log, trace, nunca o resumo); o método e a ferramenta dele; o que, além de você e do verificador, mostra que está certo. Troque o substantivo por um verbo ("painel" → "fazer o dono decidir em 30 segundos") e pergunte que campo faz esse verbo melhor: importe o método dele, nunca a voz. O que sobrar vira `Cn`, instrumento ou `## Fora de escopo`.
|
|
64
|
+
- **Instrumentos:** o que falta para provar sozinho, perguntado antes do gate: onde o problema aparece, o contexto para entendê-lo e a bancada onde reproduzir e provar (ferramenta, acesso, dado, ambiente). Prova que só existe depois do deploy se diz aqui, antes do gate; "nenhuma lacuna" vale.
|
|
64
65
|
- **Verificação de runtime:** o stack sobe por `morph-spec e2e up {feature}`: app sem dependência (dados no `localStorage`, só APIs externas) sobe só por `e2e.hostServices` (build + start + health, sem compose); com dependência (banco, fila) o compose do projeto sobe ela, e criá-lo entra no plano; os fluxos que o verificador navega, nos verbos dos cenários; base URL `process.env.PLAYWRIGHT_BASE_URL ?? \`http://localhost:${process.env.PORT ?? 3000}\``, compose com `"${PORT:-3000}:3000"` e sem `container_name` (standard `infrastructure/docker/local-compose-isolation`). App de build caro no Docker também sobe como processo do host por `e2e.hostServices`, ao lado do compose das dependências. Login: `e2e.auth` (`mode: seed|storageState|bypass|none`, `seedCommand`, credenciais num `.env.e2e` gitignored) — **`mode` é obrigatório sempre que houver `seedCommand`**, sem ele o seed fica inerte. Estado limpo entre fluxos: o `e2e reset` recria os volumes de dados do stack da feature (`morph-{f}_*`); volume com `name:` fixo é compartilhado com o stack de desenvolvimento, e aí o reset recusa até existir `e2e.resetCommand`. Biblioteca pura: registre a dispensa e o porquê.
|
|
65
66
|
- **Baseline é um COMANDO, nunca um número** (`npm test`, `dotnet test`): número cravado está errado na primeira mudança. `expectedCount` (só `node-test`/`evals`) sai de `morph-spec verify {feature} --record-baseline`, nunca digitado. Sem `project.stack`/`project.tests` no `config.json`, a `morph-apply` os declara a partir destes comandos.
|
|
66
67
|
- **Pré-requisito é um PREDICADO, nunca um SHA literal:** "`git merge-base --is-ancestor origin/main HEAD` sai 0".
|
|
@@ -71,7 +72,7 @@ Plano bom cabe em duas páginas. `morph-spec plan-check {feature}` até zero err
|
|
|
71
72
|
|
|
72
73
|
Cria ou altera UI → `morph-spec advance {feature} --design` (sempre por ele, nunca criando `1-design/` à mão: o `--design` semeia o `mockups.md`) e `Skill(morph-uiux)` depois do gate; senão `advance {feature}` leva a implement. Decidido uma vez, aqui.
|
|
73
74
|
|
|
74
|
-
Antes do gate, em `feature` e `bug`: a crítica em contexto fresco de `references/critique.md` (o `gate-check` cobra o `2-plan/critica.md` do plano atual).
|
|
75
|
+
Antes do gate, em `feature` e `bug`: a crítica em contexto fresco de `references/critique.md` (o `gate-check` cobra o `2-plan/critica.md` do plano atual). Plano pequeno dispensa, e quem decide é o código: rode o `gate-check` primeiro; sem sinal `plan-critique`, não despache. Pequeno = até 3 cenários, todos `prova: teste` ou `leitura`, sem `degrau` e sem mídia gerada.
|
|
75
76
|
|
|
76
77
|
`morph-spec gate-check {feature} plan [--json]`. Entrevista que zerou a árvore já é a aprovação do usuário: não repause, salvo a pausa de `signal: "rung"`, que vence e pergunta nomeando cada `Cn` e o seu degrau. Encerrada antes, com nós em `## Fora de escopo`: `morph-spec gate-decision {feature} plan --pause true --reason "entrevista encerrada com nós abertos" --signals '{"discoveryMode":"interview"}'`, e a pergunta do gate lista esses nós.
|
|
77
78
|
|
|
@@ -79,7 +80,7 @@ Antes do gate, em `feature` e `bug`: a crítica em contexto fresco de `reference
|
|
|
79
80
|
- `resolver === "human"` → abra `2-plan/plan.html` no navegador do usuário (`start`/`open`/`xdg-open`; o `plan-check` o gera), o entendimento (problema, fora de escopo, cenários, riscos) e `AskUserQuestion`, header "Gate plano": `"Gate do plano — Plano de {feature} aprovado?"` com `"aprovado, prosseguir" | "preciso ajustar" | "cancelar feature"`; a pergunta lista `## Padrões assumidos` para veto por número; só a decisão sensível que você tomou sozinho vira pergunta antes, na forma de `references/interview.md` (`## Forma da pergunta`). Headless: `morph-spec approve {feature} plan --approver <quem>`.
|
|
80
81
|
- `pause === false` → uma linha e `morph-spec advance {feature}` (ou `--design`).
|
|
81
82
|
|
|
82
|
-
Aprovado: "Plano aprovado.
|
|
83
|
+
Aprovado: "Plano aprovado.", com `## Padrões assumidos` numerado, e siga direto com `Skill(morph-apply)`, sem esperar resposta. Veto, a qualquer momento: `## Errata` com "Padrão N vetado: <valor novo>"; a implementação segue a errata. Rodou `stack-set` nesta sessão: pare em "Plano aprovado. Rode `/morph-apply {feature}` numa sessão nova", porque as rules de domínio só carregam no início de uma sessão.
|
|
83
84
|
|
|
84
85
|
## 7. Deltas por tipo
|
|
85
86
|
|
|
@@ -15,7 +15,7 @@ Nunca a conversa, as respostas da entrevista nem o seu resumo do plano ou do ped
|
|
|
15
15
|
> `premissa` (o plano afirma algo do código que o código desmente: arquivo, símbolo, contagem, flag);
|
|
16
16
|
> `contradicao` (duas partes do plano se negam);
|
|
17
17
|
> `decisao` (o plano escolhe um valor ou um caminho sem dizer, e o usuário pode querer outro);
|
|
18
|
-
> `cenario` (um `Cn` que nenhuma asserção ou passo no navegador consegue provar);
|
|
18
|
+
> `cenario` (um `Cn` que nenhuma asserção ou passo no navegador consegue provar, ou um `e2e` que confere o controle na tela em vez de disparar a ação até o efeito);
|
|
19
19
|
> `desvio` (o plano não resolve o pedido, sem ADR ou `## Fora de escopo` que diga por quê).
|
|
20
20
|
> Sem `description`, ou com um link que não abre, pule `desvio` e diga isso numa linha depois da tabela.
|
|
21
21
|
> Estilo, nome e "eu faria diferente" não entram. Sem achado, escreva "Nenhum achado." no lugar da tabela, mantendo o título e o `**Plan-Hash:**`.
|
|
@@ -4,7 +4,7 @@ description: Conduz a fase de UI/UX de uma feature com plano aprovado — render
|
|
|
4
4
|
version: core
|
|
5
5
|
when_to_use: Use quando o ramo de design for tomado (morph-spec advance {feature} --design), antes de /morph-apply
|
|
6
6
|
user-invocable: true
|
|
7
|
-
cliVersion: "10.
|
|
7
|
+
cliVersion: "10.5.2"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-uiux
|
|
@@ -22,7 +22,7 @@ A régua de sistema e de estética chega sozinha: a rule `ui-design` carrega qua
|
|
|
22
22
|
|
|
23
23
|
## 2. Opções — o usuário escolhe vendo, não lendo
|
|
24
24
|
|
|
25
|
-
Para cada tela nova
|
|
25
|
+
Ajuste em tela existente pula esta seção: uma passagem do protótipo (§3) basta. Para cada tela nova, `1-design/opcoes/{tela}.html`: **uma página com 2 ou 3 direções distintas**, alternáveis por abas, cada uma com:
|
|
26
26
|
|
|
27
27
|
- o conceito em uma frase e o que a torna memorável, no topo da aba;
|
|
28
28
|
- desktop (1280) e celular (390) lado a lado em moldura de aparelho, com conteúdo realista (nunca lorem ipsum nem métrica inventada);
|