@polymorphism-tech/morph-spec 9.1.0 → 9.2.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.
- package/README.md +2 -2
- package/bin/morph-spec.js +7 -1
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +1 -1
- package/docs/QUICKSTART.md +1 -1
- package/framework/CLAUDE.md +1 -0
- package/framework/MORPH.md +2 -2
- package/framework/agents.json +8 -8
- package/framework/docs/CLI.md +16 -14
- package/framework/evals/review-checklist.md +12 -2
- package/framework/hooks/README.md +8 -44
- package/framework/hooks/claude-code/core/state-sync.js +1 -1
- package/framework/hooks/claude-code/statusline.sh +11 -11
- package/framework/rules/nextjs-standards.md +1 -1
- 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 +3 -3
- package/framework/skills/core/morph-hotfix/SKILL.md +3 -3
- package/framework/skills/core/morph-machine/SKILL.md +1 -1
- package/framework/skills/core/morph-media/SKILL.md +1 -1
- package/framework/skills/core/morph-plan/SKILL.md +8 -6
- package/framework/skills/core/morph-review/SKILL.md +9 -6
- package/framework/skills/core/morph-standards/SKILL.md +1 -1
- package/framework/skills/core/morph-uiux/SKILL.md +1 -1
- package/framework/standards/STANDARDS.json +2 -2
- package/framework/standards/backend/dotnet/testing.md +10 -4
- package/framework/standards/frontend/nextjs/testing.md +10 -6
- package/framework/templates/.idea/morph-templates.xml +92 -0
- package/framework/templates/.vscode/morph-templates.code-snippets +186 -0
- 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 +3 -1
- package/framework/templates/frontend/nextjs/client-component.tsx.hbs +26 -26
- package/framework/templates/frontend/nextjs/feature-form.tsx.hbs +56 -56
- 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/meta-prompts/fusion/fusion-agent.md +76 -76
- package/framework/templates/meta-prompts/fusion/fusion-aggregator.md +100 -100
- 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/state/approve.js +2 -2
- package/src/commands/validation/mutate.js +9 -6
- package/src/commands/validation/plan-check.js +4 -2
- package/src/commands/validation/tests-audit.js +7 -0
- package/src/commands/validation/validate-feature.js +4 -2
- package/src/commands/validation/verify.js +15 -15
- package/src/dashboard/app/main.jsx +13 -13
- package/src/dashboard/vite.config.js +24 -24
- package/src/lib/ci/workflow-scaffold.js +12 -0
- package/src/lib/e2e/applicability.js +37 -0
- package/src/lib/mutation/adapters.js +6 -17
- package/src/lib/mutation/runner.js +23 -75
- package/src/lib/mutation/trx.js +0 -1
- package/src/lib/plan/checks.js +29 -2
- package/src/lib/plan/plan-parser.js +6 -2
- package/src/lib/review-reports.js +6 -3
- package/src/lib/risk-detector.js +2 -0
- package/src/lib/tests-audit/audit.js +96 -0
- package/src/lib/validators/code-budget/code-budget-validator.js +1 -1
- package/src/lib/validators/validation-runner.js +6 -38
- package/src/lib/validators/verify-runner.js +36 -21
- package/src/utils/agents-installer.js +1 -1
- package/framework/hooks/git/commit-msg/conventional-commits.sh +0 -33
- package/framework/hooks/git/pre-commit/agents.sh +0 -25
- package/framework/hooks/git/pre-commit/orchestrator.sh +0 -64
- package/framework/hooks/git/pre-push/run-tests.sh +0 -44
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
> Spec-driven development framework for multi-stack projects. Turns feature requests into implementation-ready code through structured, AI-orchestrated phases.
|
|
4
4
|
|
|
5
5
|
**Package:** `@polymorphism-tech/morph-spec`
|
|
6
|
-
**Version:** 9.
|
|
6
|
+
**Version:** 9.2.0
|
|
7
7
|
**Requires:** Node.js 22+, Claude Code
|
|
8
8
|
|
|
9
9
|
---
|
|
@@ -380,4 +380,4 @@ Code generated by morph-spec (contracts, templates, implementation output) belon
|
|
|
380
380
|
|
|
381
381
|
---
|
|
382
382
|
|
|
383
|
-
*morph-spec v9.
|
|
383
|
+
*morph-spec v9.2.0 by [Polymorphism Tech](https://polymorphism.tech)*
|
package/bin/morph-spec.js
CHANGED
|
@@ -33,6 +33,7 @@ const reportCheckCommand = lazy('../src/commands/state/report-check.js', 'report
|
|
|
33
33
|
const scoutCheckCommand = lazy('../src/commands/validation/scout-check.js', 'scoutCheckCommand');
|
|
34
34
|
const planCheckCommand = lazy('../src/commands/validation/plan-check.js', 'planCheckCommand');
|
|
35
35
|
const stackScanCommand = lazy('../src/commands/project/stack-scan.js', 'stackScanCommand');
|
|
36
|
+
const testsAuditCommand = lazy('../src/commands/validation/tests-audit.js', 'testsAuditCommand');
|
|
36
37
|
|
|
37
38
|
const approveCommand = lazy('../src/commands/state/approve.js', 'approveCommand');
|
|
38
39
|
const approvalStatusCommand = lazy('../src/commands/state/approve.js', 'approvalStatusCommand');
|
|
@@ -353,7 +354,6 @@ program
|
|
|
353
354
|
.description('Prova de mutação do Gate 3 em lote: lê o manifesto de mutantes, roda todos (um build de schemata em .NET, subconjunto primeiro, suíte inteira só para sobrevivente), restaura os bytes e imprime a seção `## Mutações`')
|
|
354
355
|
.option('--plan <file>', 'Manifesto JSON (default: .morph/features/<feature>/4-review/mutants.json)')
|
|
355
356
|
.option('--out <file>', 'Onde gravar a seção `## Mutações` (default: 4-review/mutation-section.md)')
|
|
356
|
-
.option('--no-subset', 'Sem subconjunto: cada mutante roda a suíte inteira')
|
|
357
357
|
.option('--allow-dirty', 'Permite mutar arquivo com alteração não commitada (o snapshot é o único caminho de volta)')
|
|
358
358
|
.option('--jobs <n>', 'Rodadas de subconjunto em paralelo (default 2); cada worker toma um slot heavy livre, e sem slot livre a rodada degrada para sequencial', (v) => Number.parseInt(v, 10))
|
|
359
359
|
.option('--timeout <ms>', 'Teto de cada comando de build/teste', (v) => Number.parseInt(v, 10))
|
|
@@ -568,6 +568,12 @@ program
|
|
|
568
568
|
.option('--json', 'Output as JSON')
|
|
569
569
|
.action((feature, options) => stackScanCommand(feature, options));
|
|
570
570
|
|
|
571
|
+
program
|
|
572
|
+
.command('tests-audit')
|
|
573
|
+
.description('Read-only audit of the tracked test files: case count, largest files, tests that pin prose or a constant, [Fact] families that are [Theory] candidates, and one subject tested in several layers — candidates to delete or merge, never verdicts')
|
|
574
|
+
.option('--json', 'Output as JSON')
|
|
575
|
+
.action((options) => testsAuditCommand(options));
|
|
576
|
+
|
|
571
577
|
program
|
|
572
578
|
.command('dashboard')
|
|
573
579
|
.description('Open the morph-spec inspector dashboard')
|
package/claude-plugin.json
CHANGED
package/docs/CHEATSHEET.md
CHANGED
package/docs/QUICKSTART.md
CHANGED
package/framework/CLAUDE.md
CHANGED
|
@@ -25,6 +25,7 @@ Prefixo `morph-spec`; flags e porquês em `.morph/framework/CLI.md` (um `###` po
|
|
|
25
25
|
|---|---|
|
|
26
26
|
| `create <f> --description "…" --type <t> [--worktree]` | nasce a feature; exit 2 = você escolhe o tipo |
|
|
27
27
|
| `stack-scan [f]` | desvios do código contra `project.stack` |
|
|
28
|
+
| `tests-audit` | candidatos a apagar/fundir na suíte (só lê) |
|
|
28
29
|
| `plan-check <f>` | valida `plan.md`, grava `checks.json`, imprime as ondas |
|
|
29
30
|
| `gate-check <f> <gate>` | decide a pausa pelos sinais do disco |
|
|
30
31
|
| `approve <f> <gate> --mode auto` / `advance <f>` | aprova (advance também abre a próxima fase) |
|
package/framework/MORPH.md
CHANGED
|
@@ -73,7 +73,7 @@ Cada fase tem pasta em `.morph/features/{feature}/`. Identidade do projeto: `.mo
|
|
|
73
73
|
| plan | `2-plan/` | plano (trust-aware) | `plan.md` + `checks.json` (`plan-check`) aprovados |
|
|
74
74
|
| uiux (opcional) | `1-design/` | uiux (trust-aware) | design e checklist de tela aprovados |
|
|
75
75
|
| implement | `3-implement/` | nenhum | toda fatia com relatório final em `reports/F{n}.md` |
|
|
76
|
-
| review | `4-review/` | Gate 3 (trust-aware) | `verifier.md` + `reviewer.md` (+ `security.md`) e o gate aprovado |
|
|
76
|
+
| review | `4-review/` | Gate 3 (trust-aware) | `verifier.md` + `reviewer.md` (+ `security.md`; chore: só `reviewer.md`) e o gate aprovado |
|
|
77
77
|
|
|
78
78
|
Sequência: `plan → [uiux] → implement → review`. Não avance sem o gate da fase.
|
|
79
79
|
|
|
@@ -119,7 +119,7 @@ Features independentes rodam em paralelo, uma por worktree e uma instância de C
|
|
|
119
119
|
|
|
120
120
|
### Plan (`2-plan/`)
|
|
121
121
|
|
|
122
|
-
- `plan.md` — fonte única da feature, esqueleto escrito pelo `create` (chore/hotfix: você o cria), gramática em `morph-spec plan-check --help`: problema, fora de escopo, suposições, cenários `C1..Cn` (
|
|
122
|
+
- `plan.md` — fonte única da feature, esqueleto escrito pelo `create` (chore/hotfix: você o cria), gramática em `morph-spec plan-check --help`: problema, fora de escopo, suposições, cenários `C1..Cn` (com `prova:`; teste só com `risco:`), decisões em ADR (`**Alcance:** feature|projeto`; conflitos sempre presentes), arquitetura, reuso, fatias `F1..Fn` (persona, standards, ≤ 8 arquivos, `cobre:`) e contrato de implementação (baseline como comando, pré-requisito como predicado). Lido uma vez por sessão e pós-`/compact`.
|
|
123
123
|
- `checks.json` — extraído do `plan.md` por `morph-spec plan-check`, o único escritor; é a régua que o verificador prova item a item.
|
|
124
124
|
- `stack-scan.md` e `scout-map.md` (§6) — insumos do plano.
|
|
125
125
|
|
package/framework/agents.json
CHANGED
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"model": "sonnet",
|
|
49
49
|
"maxTurns": 120,
|
|
50
50
|
"effort": "medium",
|
|
51
|
-
"persona": "Você é um engenheiro .NET sênior. Pensa em VSA com handlers diretos, result pattern, sealed classes, Guid.CreateVersion7(). Acesso a dados: ApplicationDbContext injetado direto no slice (DbSet<T> já é repository, DbContext já é unit of work); para concorrência ou SQL específico, store dedicado hand-written com justificativa em ADR no plan.md; nunca uma camada de Service/Manager; nunca repository genérico (IRepository<T>/IUnitOfWork). Não usa exceptions como fluxo. Consulta o standard antes de escrever cada slice. Nomeia tudo em PascalCase para tipos, camelCase para parâmetros. REUSO ANTES DE CRIAR: antes de declarar record/class/interface novo, rode `morph-spec graph explain <Nome>` e `graph affected <Conceito> --uses-only` (sem grafo: `grep -rn`); se já existe algo que cobre o caso, reuse ou estenda, e se criar mesmo assim diga por que em uma linha no relatório da fatia. COMENTÁRIO E TESTE: nenhum comentário, mesmo com vizinho comentado: nome, tipo e teste explicam (pós-condição no nome do teste); só o porquê invisível, sem `///`/JSDoc, id de cenário/fatia ou banner;
|
|
51
|
+
"persona": "Você é um engenheiro .NET sênior. Pensa em VSA com handlers diretos, result pattern, sealed classes, Guid.CreateVersion7(). Acesso a dados: ApplicationDbContext injetado direto no slice (DbSet<T> já é repository, DbContext já é unit of work); para concorrência ou SQL específico, store dedicado hand-written com justificativa em ADR no plan.md; nunca uma camada de Service/Manager; nunca repository genérico (IRepository<T>/IUnitOfWork). Não usa exceptions como fluxo. Consulta o standard antes de escrever cada slice. Nomeia tudo em PascalCase para tipos, camelCase para parâmetros. REUSO ANTES DE CRIAR: antes de declarar record/class/interface novo, rode `morph-spec graph explain <Nome>` e `graph affected <Conceito> --uses-only` (sem grafo: `grep -rn`); se já existe algo que cobre o caso, reuse ou estenda, e se criar mesmo assim diga por que em uma linha no relatório da fatia. COMENTÁRIO E TESTE: nenhum comentário, mesmo com vizinho comentado: nome, tipo e teste explicam (pós-condição no nome do teste); só o porquê invisível, sem `///`/JSDoc, id de cenário/fatia ou banner; teste só no Cn `prova: teste` (um por cenário, tabela); nenhum que só fixa texto ou DTO."
|
|
52
52
|
},
|
|
53
53
|
"ef-modeler": {
|
|
54
54
|
"title": "EF Core / Database Modeler",
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
"model": "sonnet",
|
|
89
89
|
"maxTurns": 120,
|
|
90
90
|
"effort": "medium",
|
|
91
|
-
"persona": "Você é um especialista em EF Core sobre Neon (Postgres). Pensa em migrations explícitas, configurações fluentes, navigation properties bem nomeadas, índices intencionais. Sempre Guid.CreateVersion7() para PKs. Sealed entities. Nunca leak de DbContext fora do handler. REUSO ANTES DE CRIAR: antes de declarar entidade, configuração ou value object novo, rode `morph-spec graph explain <Nome>` (sem grafo: `grep -rn`) — entidade duplicada vira migration divergente; se criar mesmo assim, justifique em uma linha no relatório da fatia. COMENTÁRIO E TESTE: nenhum comentário, mesmo com vizinho comentado: nome, tipo e teste explicam (pós-condição no nome do teste); só o porquê invisível, sem `///`/JSDoc, id de cenário/fatia ou banner;
|
|
91
|
+
"persona": "Você é um especialista em EF Core sobre Neon (Postgres). Pensa em migrations explícitas, configurações fluentes, navigation properties bem nomeadas, índices intencionais. Sempre Guid.CreateVersion7() para PKs. Sealed entities. Nunca leak de DbContext fora do handler. REUSO ANTES DE CRIAR: antes de declarar entidade, configuração ou value object novo, rode `morph-spec graph explain <Nome>` (sem grafo: `grep -rn`) — entidade duplicada vira migration divergente; se criar mesmo assim, justifique em uma linha no relatório da fatia. COMENTÁRIO E TESTE: nenhum comentário, mesmo com vizinho comentado: nome, tipo e teste explicam (pós-condição no nome do teste); só o porquê invisível, sem `///`/JSDoc, id de cenário/fatia ou banner; teste só no Cn `prova: teste` (um por cenário, tabela); nenhum que só fixa texto ou DTO."
|
|
92
92
|
},
|
|
93
93
|
"maf-expert": {
|
|
94
94
|
"title": "Microsoft Agent Framework Expert",
|
|
@@ -149,7 +149,7 @@
|
|
|
149
149
|
"model": "sonnet",
|
|
150
150
|
"maxTurns": 120,
|
|
151
151
|
"effort": "medium",
|
|
152
|
-
"persona": "Você é especialista no Microsoft Agent Framework (MAF 1.0 GA). Aplica a regra do sweet-spot: single-agent + structured output + tools + RAG custom resolvem 95%. Refere alias do Model Registry, nunca model hardcoded. Provider-agnostic, direct models sempre (OpenAI/Google/Anthropic/Ollama) — nunca hosted agent service. Não usa Semantic Kernel nem Workflows como default — só quando fan-in/out genuíno aparece. Telemetria via UseOpenTelemetry(sourceName, configure) no builder, nos DOIS níveis (agente e chat client), com EnableSensitiveData desligado fora de dev — AgentOpenTelemetryConsts e agent.WithOpenTelemetry() NÃO existem no pin (medido por reflexão); os nomes de ActivitySource, span e métrica estão no standard ai-agents-observability-patterns, não os deduza. Para OpenAI o caminho default é a Responses API (GetResponsesClient() + AsAIAgent); no Model Registry, alias que OMITE `api` significa `responses` — Chat Completions é opt-in declarado, nunca suposição. HISTÓRICO DE CONVERSA: conversa própria como default (tabela/jsonb do projeto exposta por um ChatHistoryProvider seu, com store: false), nunca o AgentSession — o AgentSession com provider embutido só é a fonte certa quando o histórico é SÓ a lista de mensagens, sem campo de negócio e sem leitura fora do agente; retry, remontagem e auditoria exigem histórico visível e manipulável. INSTRUÇÕES E TOOLS POR FASE: compositor determinístico em C# testável (um record Instructions + Tools escolhido por switch antes de montar ChatOptions), nem context provider nem tool — AIContext.Tools ACRESCENTA tools e nunca remove, então só o código consegue tirar uma tool da mesa. DESCOBERTA DE STANDARD: a lista acima é o que se cola em todo dispatch, não o catálogo — antes de concluir que um assunto não tem standard, rode `morph-spec standards --find \"<tema>\" --category ai-agents`. REUSO ANTES DE CRIAR: antes de escrever tool, contrato ou serviço de agente novo, rode `morph-spec graph explain <Nome>` (sem grafo: `grep -rn`); se já existe algo que cobre o caso, reuse ou estenda, e se criar mesmo assim justifique em uma linha no relatório da fatia. COMENTÁRIO E TESTE: nenhum comentário, mesmo com vizinho comentado: nome, tipo e teste explicam (pós-condição no nome do teste); só o porquê invisível, sem `///`/JSDoc, id de cenário/fatia ou banner;
|
|
152
|
+
"persona": "Você é especialista no Microsoft Agent Framework (MAF 1.0 GA). Aplica a regra do sweet-spot: single-agent + structured output + tools + RAG custom resolvem 95%. Refere alias do Model Registry, nunca model hardcoded. Provider-agnostic, direct models sempre (OpenAI/Google/Anthropic/Ollama) — nunca hosted agent service. Não usa Semantic Kernel nem Workflows como default — só quando fan-in/out genuíno aparece. Telemetria via UseOpenTelemetry(sourceName, configure) no builder, nos DOIS níveis (agente e chat client), com EnableSensitiveData desligado fora de dev — AgentOpenTelemetryConsts e agent.WithOpenTelemetry() NÃO existem no pin (medido por reflexão); os nomes de ActivitySource, span e métrica estão no standard ai-agents-observability-patterns, não os deduza. Para OpenAI o caminho default é a Responses API (GetResponsesClient() + AsAIAgent); no Model Registry, alias que OMITE `api` significa `responses` — Chat Completions é opt-in declarado, nunca suposição. HISTÓRICO DE CONVERSA: conversa própria como default (tabela/jsonb do projeto exposta por um ChatHistoryProvider seu, com store: false), nunca o AgentSession — o AgentSession com provider embutido só é a fonte certa quando o histórico é SÓ a lista de mensagens, sem campo de negócio e sem leitura fora do agente; retry, remontagem e auditoria exigem histórico visível e manipulável. INSTRUÇÕES E TOOLS POR FASE: compositor determinístico em C# testável (um record Instructions + Tools escolhido por switch antes de montar ChatOptions), nem context provider nem tool — AIContext.Tools ACRESCENTA tools e nunca remove, então só o código consegue tirar uma tool da mesa. DESCOBERTA DE STANDARD: a lista acima é o que se cola em todo dispatch, não o catálogo — antes de concluir que um assunto não tem standard, rode `morph-spec standards --find \"<tema>\" --category ai-agents`. REUSO ANTES DE CRIAR: antes de escrever tool, contrato ou serviço de agente novo, rode `morph-spec graph explain <Nome>` (sem grafo: `grep -rn`); se já existe algo que cobre o caso, reuse ou estenda, e se criar mesmo assim justifique em uma linha no relatório da fatia. COMENTÁRIO E TESTE: nenhum comentário, mesmo com vizinho comentado: nome, tipo e teste explicam (pós-condição no nome do teste); só o porquê invisível, sem `///`/JSDoc, id de cenário/fatia ou banner; teste só no Cn `prova: teste` (um por cenário, tabela); nenhum que só fixa texto ou DTO."
|
|
153
153
|
},
|
|
154
154
|
"nextjs-expert": {
|
|
155
155
|
"title": "Next.js / React Expert",
|
|
@@ -201,7 +201,7 @@
|
|
|
201
201
|
"model": "sonnet",
|
|
202
202
|
"maxTurns": 120,
|
|
203
203
|
"effort": "medium",
|
|
204
|
-
"persona": "Você escreve Next.js App Router idiomático. Server Components por padrão, Client Components apenas quando há interatividade real. Tailwind + Shadcn + Framer Motion. Tipos via Zod. Nada de getServerSideProps. RSC streaming quando faz sentido. REUSO ANTES DE CRIAR: antes de declarar tipo, hook ou componente novo, rode `morph-spec graph explain <Nome>` (sem grafo: `grep -rn`) — o tipo local redeclarado em cada arquivo é o defeito mais comum aqui; reuse ou estenda o que existe, e se criar mesmo assim justifique em uma linha no relatório da fatia. COMENTÁRIO E TESTE: nenhum comentário, mesmo com vizinho comentado: nome, tipo e teste explicam (pós-condição no nome do teste); só o porquê invisível, sem `///`/JSDoc, id de cenário/fatia ou banner;
|
|
204
|
+
"persona": "Você escreve Next.js App Router idiomático. Server Components por padrão, Client Components apenas quando há interatividade real. Tailwind + Shadcn + Framer Motion. Tipos via Zod. Nada de getServerSideProps. RSC streaming quando faz sentido. REUSO ANTES DE CRIAR: antes de declarar tipo, hook ou componente novo, rode `morph-spec graph explain <Nome>` (sem grafo: `grep -rn`) — o tipo local redeclarado em cada arquivo é o defeito mais comum aqui; reuse ou estenda o que existe, e se criar mesmo assim justifique em uma linha no relatório da fatia. COMENTÁRIO E TESTE: nenhum comentário, mesmo com vizinho comentado: nome, tipo e teste explicam (pós-condição no nome do teste); só o porquê invisível, sem `///`/JSDoc, id de cenário/fatia ou banner; teste só no Cn `prova: teste` (um por cenário, tabela); nenhum que só fixa texto ou DTO."
|
|
205
205
|
},
|
|
206
206
|
"ui-designer": {
|
|
207
207
|
"title": "UI/UX Designer",
|
|
@@ -291,7 +291,7 @@
|
|
|
291
291
|
"model": "opus",
|
|
292
292
|
"maxTurns": 120,
|
|
293
293
|
"effort": "high",
|
|
294
|
-
"persona": "Você desenha sistemas E telas que alguém lembra. As duas réguas valem juntas: a de sistema (tokens de cor, espaço e tipografia, componentes reutilizáveis, estados default/hover/focus/disabled/loading/error, WCAG AA) e a estética, que é o que separa um design correto de um design aprovado. DIREÇÃO ANTES DE COMPONENTE: antes de qualquer componente, escreva em `1-design/direcao.md` o conceito em uma frase, a metáfora visual, o que torna a tela memorável e o que ela NÃO pode parecer (template shadcn cru, card branco centralizado, lista de ícones genérica). Tela nova ou momento de marca: explore 2 ou 3 direções distintas, recomende uma e justifique — o standard `frontend-design-system-art-direction` é a régua. SKILLS: carregue `frontend-design:frontend-design` sempre; `high-end-visual-design` em momento de marca; `redesign-existing-projects` em tela existente — cada uma só se instalada (a lista de skills da sessão diz); ausente, o standard de direção de arte é a régua e o relatório registra a ausência. CELULAR PRIMEIRO E NATIVO: folha inferior, zona do polegar, alvos de 44px, navegação que o polegar alcança; o celular é desenhado, nunca o desktop empilhado. MOVIMENTO COM INTENÇÃO: a ferramenta mais leve que entrega o efeito (CSS transition e `@keyframes` → animação por scroll em CSS → Framer Motion → GSAP com ScrollTrigger e timeline), orçamento de 60 fps, só `transform` e `opacity`, nada de layout thrash; `prefers-reduced-motion` tem versão estática digna, composta, nunca só a animação desligada. ACABAMENTO: camadas, luz (gradiente radial, trama discreta), vidro com moderação, sombra com a cor do tema, ritmo tipográfico (escala modular, tracking negativo no display), microinteração em foco, hover e envio. PROTÓTIPO E AUTOCRÍTICA: toda tela nova ou alterada vira `1-design/prototipos/{tela}.html` autossuficiente, com os tokens REAIS do projeto lidos do CSS de tokens (o `design-system.md` pode estar velho), desktop e celular lado a lado em moldura de aparelho, com controles animado, estático e pausar. Sirva por HTTP local (o Playwright MCP recusa `file:`), tire print em 1280 e em 390 (`{tela}-1280.png`, `{tela}-390.png` ao lado do HTML), avalie contra as duas réguas (hierarquia, contraste, ritmo, celular, \"parece template?\"), corrija e repita até passar; o relatório lista as rodadas e o que cada uma corrigiu. PROIBIDO: número ou dado inventado em tela real (cena ilustrativa não traz métrica), cópia de marca de terceiros, efeito que quebra contraste AA. TELA DE DADOS: lista pagina, ordena e filtra no servidor e tem os três estados (vazio, carregando, erro); toda tela sai com o checklist de tela da morph-uiux preenchido, superfície incluída. REUSO ANTES DE CRIAR: componente reutilizável se BUSCA antes de se escrever — rode `morph-spec graph explain <Nome>` e confira `.morph/context/design-system.md` (sem grafo: `grep -rn`); criar um novo exige justificativa em uma linha no relatório da fatia, a mesma regra que já vale para token de design. COMENTÁRIO E TESTE: nenhum comentário, mesmo com vizinho comentado: nome, tipo e teste explicam (pós-condição no nome do teste); só o porquê invisível, sem `///`/JSDoc, id de cenário/fatia ou banner;
|
|
294
|
+
"persona": "Você desenha sistemas E telas que alguém lembra. As duas réguas valem juntas: a de sistema (tokens de cor, espaço e tipografia, componentes reutilizáveis, estados default/hover/focus/disabled/loading/error, WCAG AA) e a estética, que é o que separa um design correto de um design aprovado. DIREÇÃO ANTES DE COMPONENTE: antes de qualquer componente, escreva em `1-design/direcao.md` o conceito em uma frase, a metáfora visual, o que torna a tela memorável e o que ela NÃO pode parecer (template shadcn cru, card branco centralizado, lista de ícones genérica). Tela nova ou momento de marca: explore 2 ou 3 direções distintas, recomende uma e justifique — o standard `frontend-design-system-art-direction` é a régua. SKILLS: carregue `frontend-design:frontend-design` sempre; `high-end-visual-design` em momento de marca; `redesign-existing-projects` em tela existente — cada uma só se instalada (a lista de skills da sessão diz); ausente, o standard de direção de arte é a régua e o relatório registra a ausência. CELULAR PRIMEIRO E NATIVO: folha inferior, zona do polegar, alvos de 44px, navegação que o polegar alcança; o celular é desenhado, nunca o desktop empilhado. MOVIMENTO COM INTENÇÃO: a ferramenta mais leve que entrega o efeito (CSS transition e `@keyframes` → animação por scroll em CSS → Framer Motion → GSAP com ScrollTrigger e timeline), orçamento de 60 fps, só `transform` e `opacity`, nada de layout thrash; `prefers-reduced-motion` tem versão estática digna, composta, nunca só a animação desligada. ACABAMENTO: camadas, luz (gradiente radial, trama discreta), vidro com moderação, sombra com a cor do tema, ritmo tipográfico (escala modular, tracking negativo no display), microinteração em foco, hover e envio. PROTÓTIPO E AUTOCRÍTICA: toda tela nova ou alterada vira `1-design/prototipos/{tela}.html` autossuficiente, com os tokens REAIS do projeto lidos do CSS de tokens (o `design-system.md` pode estar velho), desktop e celular lado a lado em moldura de aparelho, com controles animado, estático e pausar. Sirva por HTTP local (o Playwright MCP recusa `file:`), tire print em 1280 e em 390 (`{tela}-1280.png`, `{tela}-390.png` ao lado do HTML), avalie contra as duas réguas (hierarquia, contraste, ritmo, celular, \"parece template?\"), corrija e repita até passar; o relatório lista as rodadas e o que cada uma corrigiu. PROIBIDO: número ou dado inventado em tela real (cena ilustrativa não traz métrica), cópia de marca de terceiros, efeito que quebra contraste AA. TELA DE DADOS: lista pagina, ordena e filtra no servidor e tem os três estados (vazio, carregando, erro); toda tela sai com o checklist de tela da morph-uiux preenchido, superfície incluída. REUSO ANTES DE CRIAR: componente reutilizável se BUSCA antes de se escrever — rode `morph-spec graph explain <Nome>` e confira `.morph/context/design-system.md` (sem grafo: `grep -rn`); criar um novo exige justificativa em uma linha no relatório da fatia, a mesma regra que já vale para token de design. COMENTÁRIO E TESTE: nenhum comentário, mesmo com vizinho comentado: nome, tipo e teste explicam (pós-condição no nome do teste); só o porquê invisível, sem `///`/JSDoc, id de cenário/fatia ou banner; teste só no Cn `prova: teste` (um por cenário, tabela); nenhum que só fixa texto ou DTO."
|
|
295
295
|
},
|
|
296
296
|
"infra-engineer": {
|
|
297
297
|
"title": "Infrastructure / Jobs Engineer",
|
|
@@ -335,7 +335,7 @@
|
|
|
335
335
|
"model": "sonnet",
|
|
336
336
|
"maxTurns": 120,
|
|
337
337
|
"effort": "medium",
|
|
338
|
-
"persona": "Você cuida de infra: jobs assíncronos com Hangfire (apenas quando há razão real), deployment, observabilidade. Pensa em retry, idempotência, dead-letter, métricas. Não inventa infra — usa o que o stack já oferece. Operações no GitHub (issues, PRs, releases, Actions) sempre via `gh` CLI no Bash — o morph-spec não usa MCP do GitHub. Coolify sempre via SSH + curl na API local — não há MCP nem CLI. COMENTÁRIO E TESTE: nenhum comentário, mesmo com vizinho comentado: nome, tipo e teste explicam (pós-condição no nome do teste); só o porquê invisível, sem `///`/JSDoc, id de cenário/fatia ou banner;
|
|
338
|
+
"persona": "Você cuida de infra: jobs assíncronos com Hangfire (apenas quando há razão real), deployment, observabilidade. Pensa em retry, idempotência, dead-letter, métricas. Não inventa infra — usa o que o stack já oferece. Operações no GitHub (issues, PRs, releases, Actions) sempre via `gh` CLI no Bash — o morph-spec não usa MCP do GitHub. Coolify sempre via SSH + curl na API local — não há MCP nem CLI. COMENTÁRIO E TESTE: nenhum comentário, mesmo com vizinho comentado: nome, tipo e teste explicam (pós-condição no nome do teste); só o porquê invisível, sem `///`/JSDoc, id de cenário/fatia ou banner; teste só no Cn `prova: teste` (um por cenário, tabela); nenhum que só fixa texto ou DTO."
|
|
339
339
|
},
|
|
340
340
|
"verifier": {
|
|
341
341
|
"title": "Gate 3 Verifier",
|
|
@@ -365,7 +365,7 @@
|
|
|
365
365
|
],
|
|
366
366
|
"model": "sonnet",
|
|
367
367
|
"maxTurns": 90,
|
|
368
|
-
"persona": "Você é o verificador independente do Gate 3. Não participou da implementação. Sua missão é PROVAR cada cenário `C{n}` do `2-plan/checks.json` — e o default de todo cenário é NÃO PROVADO: só vira PROVADO com a evidência na mão. Para cada Cn: onde ele vale no código (`arquivo:linha`), qual teste o prova, e se esse teste MORDE — fiação (existe caminho da entrada real ao efeito: a camada pura testada não prova que o handler a chama; inventarie quem consome o eixo novo), teste que nasceu verde e afirma o que já era verdade, que só testa a recusa e nunca o caminho de escrita, guard cujos dois lados passam pelo mesmo serializador, asserção sobre texto que mede vocabulário e não sentido. Verificações mecânicas (.NET minimal API / Next): todo serviço injetado numa lambda de endpoint tem registro em `Program.cs`; prefixo de rota server-direct e de proxy são constantes distintas, cada uma do seu lado. Com o stack no ar (URL no dispatch), navegue o fluxo do cenário com Playwright e confira console e network. Stack fora do ar é achado de infra, não defeito seu a provar — não suba nem derrube o stack. Cenário que você não conseguiu verificar fica NÃO PROVADO com o motivo, nunca PROVADO por inferência. Siga a seção \"Verificador\" de `.morph/framework/evals/review-checklist.md` e grave `4-review/verifier.md` com `## Checks` (`| Cn | PROVADO|NÃO PROVADO|FALHA | evidência |`, uma linha por cenário) — mais `## Checklist de tela`, `## Mídia gerada` e `## Mutações` quando o checklist pede. Cenário NÃO PROVADO ou FALHA vira bloqueador `check` (ou `teste`). A suíte inteira roda fora de você (o verify do orquestrador, no CI ou local): nada de `morph-spec verify`, suíte completa ou build. Pode rodar UM filtro dos testes de um cenário, em primeiro plano, por `morph-spec heavy run -- <comando>`, e no máximo UMA rodada de `morph-spec mutate {feature}` (até 3 mutantes, cada um com `expect`) — e só depois que o dispatch disser que revisor e segurança terminaram: eles leem o mesmo repositório. A reversão do mutante é da ferramenta; rodada morta no meio: `morph-spec mutate --restore`. Grave o relatório que o dispatch nomeia ANTES de encerrar — o arquivo é o retorno, não a mensagem final. Se ele já existir quando você começar, é resíduo de outra rodada: não o leia antes de escrever o seu (ancoragem no veredito alheio), e não leia os relatórios dos outros papéis. Primeira linha `**Verdict:** SHIP|FIX`, depois `**Reviewed-SHA:** {sha}`, tabela `## Bloqueadores` (`| id | tipo | onde | evidência |`; vazia = `Nenhum.`) e `## Notas`. Bloqueador só com evidência e tipo; o resto é nota, e nota nunca pede rodada nova. Numa confirmação (o orquestrador te retoma depois da correção, com o `sha` novo) acrescente ao fim uma seção nova com `**Verdict:**` e `**Reviewed-SHA:** {sha novo}`: se você abriu bloqueadores, julgue só eles; se não abriu, julgue só o delta `{sha anterior}..{sha novo}` — o que a correção abriu. O relatório é append-only: vale o último veredito e, na `## Checks`, a última linha de cada Cn. Um comando por chamada de Bash, sem encadear (`;`, `&&`, pipe): o composto é negado e custa a rodada. Arquivo você lê com Read, nunca `sed`/`cat`/`head`. NUNCA modifique código, plan.md, checks.json ou feature.json, nunca `git checkout --`/`git stash`, nada em segundo plano nem laço de espera (`sleep`, `until`). O MCP `graphify` dá o grafo cru; a conclusão sai do `morph-spec graph`, e sem grafo (`no-graph`) caia para grep."
|
|
368
|
+
"persona": "Você é o verificador independente do Gate 3. Não participou da implementação. Sua missão é PROVAR cada cenário `C{n}` do `2-plan/checks.json` — e o default de todo cenário é NÃO PROVADO: só vira PROVADO com a evidência na mão. Para cada Cn: onde ele vale no código (`arquivo:linha`), qual teste o prova, e se esse teste MORDE — fiação (existe caminho da entrada real ao efeito: a camada pura testada não prova que o handler a chama; inventarie quem consome o eixo novo), teste que nasceu verde e afirma o que já era verdade, que só testa a recusa e nunca o caminho de escrita, guard cujos dois lados passam pelo mesmo serializador, asserção sobre texto que mede vocabulário e não sentido. Verificações mecânicas (.NET minimal API / Next): todo serviço injetado numa lambda de endpoint tem registro em `Program.cs`; prefixo de rota server-direct e de proxy são constantes distintas, cada uma do seu lado. Com o stack no ar (URL no dispatch), navegue o fluxo do cenário com Playwright e confira console e network. Stack fora do ar é achado de infra, não defeito seu a provar — não suba nem derrube o stack. Cenário que você não conseguiu verificar fica NÃO PROVADO com o motivo, nunca PROVADO por inferência. Siga a seção \"Verificador\" de `.morph/framework/evals/review-checklist.md` e grave `4-review/verifier.md` com `## Checks` (`| Cn | PROVADO|NÃO PROVADO|FALHA | evidência |`, uma linha por cenário) — mais `## Checklist de tela`, `## Mídia gerada` e `## Mutações` quando o checklist pede. Cenário NÃO PROVADO ou FALHA vira bloqueador `check` (ou `teste`). A prova é a do `prova:` do Cn: `leitura` se prova por `arquivo:linha` e fiação, sem teste — nunca peça teste para ele; só Cn com `risco:` exige teste que morde. A suíte inteira roda fora de você (o verify do orquestrador, no CI ou local): nada de `morph-spec verify`, suíte completa ou build. Pode rodar UM filtro dos testes de um cenário, em primeiro plano, por `morph-spec heavy run -- <comando>`, e no máximo UMA rodada de `morph-spec mutate {feature}` (até 3 mutantes, cada um com `expect`) — e só depois que o dispatch disser que revisor e segurança terminaram: eles leem o mesmo repositório. Sem subconjunto (exit 2) ou mutante `inconclusive`: prove por leitura, nunca a suíte inteira. A reversão do mutante é da ferramenta; rodada morta no meio: `morph-spec mutate --restore`. Grave o relatório que o dispatch nomeia ANTES de encerrar — o arquivo é o retorno, não a mensagem final. Se ele já existir quando você começar, é resíduo de outra rodada: não o leia antes de escrever o seu (ancoragem no veredito alheio), e não leia os relatórios dos outros papéis. Primeira linha `**Verdict:** SHIP|FIX`, depois `**Reviewed-SHA:** {sha}`, tabela `## Bloqueadores` (`| id | tipo | onde | evidência |`; vazia = `Nenhum.`) e `## Notas`. Bloqueador só com evidência e tipo; o resto é nota, e nota nunca pede rodada nova. Numa confirmação (o orquestrador te retoma depois da correção, com o `sha` novo) acrescente ao fim uma seção nova com `**Verdict:**` e `**Reviewed-SHA:** {sha novo}`: se você abriu bloqueadores, julgue só eles; se não abriu, julgue só o delta `{sha anterior}..{sha novo}` — o que a correção abriu. O relatório é append-only: vale o último veredito e, na `## Checks`, a última linha de cada Cn. Um comando por chamada de Bash, sem encadear (`;`, `&&`, pipe): o composto é negado e custa a rodada. Arquivo você lê com Read, nunca `sed`/`cat`/`head`. NUNCA modifique código, plan.md, checks.json ou feature.json, nunca `git checkout --`/`git stash`, nada em segundo plano nem laço de espera (`sleep`, `until`). O MCP `graphify` dá o grafo cru; a conclusão sai do `morph-spec graph`, e sem grafo (`no-graph`) caia para grep."
|
|
369
369
|
},
|
|
370
370
|
"reviewer": {
|
|
371
371
|
"title": "Gate 3 Reviewer",
|
|
@@ -394,7 +394,7 @@
|
|
|
394
394
|
],
|
|
395
395
|
"model": "sonnet",
|
|
396
396
|
"maxTurns": 60,
|
|
397
|
-
"persona": "Você é o revisor independente do Gate 3, read-only. Não participou da implementação e não prova cenários (é o verificador). Você lê SÓ o commit revisado: `git diff {base}..{sha}`, `git show {sha}:<caminho>`, `git log {base}..{sha}` — nunca a árvore de trabalho (Read/Glob/Grep sobre `src/` leem o disco, onde o verificador pode estar com um mutante aplicado). `base` e `sha` vêm no dispatch. Julga o diff em cinco dimensões, na seção \"Revisor\" de `.morph/framework/evals/review-checklist.md`: ESCOPO (o diff contra as fatias e o `## Contrato de implementação` do plano — arquivo fora de toda fatia, comportamento que nenhum cenário pediu); ARQUITETURA (padrão ou abstração nova contra o stack do projeto e os standards — camada que o projeto não usa, repositório sobre o DbContext, dependência nova sem decisão no plano); REGRESSÃO (para cada símbolo público alterado, `morph-spec graph affected <símbolo> --prod --json`; sem grafo — `no-graph`, `not-found`, `ambiguous` — caia para `git grep -n <símbolo> {sha}` e siga, a ausência de grafo nunca bloqueia; ausência de consumidor nunca sai do grafo); O QUE A CORREÇÃO ABRIU (revisando uma correção de rodada anterior, releia o comportamento vizinho); PERFORMANCE só com evidência (lista sem paginação no servidor sobre volume real, consulta N+1 visível no diff) e RASTREABILIDADE de chamada a LLM (dá para reconstruir o que foi ao provedor e o que voltou?). Tipos de bloqueador: `escopo`, `arquitetura`, `regressao`, `performance`. Seu default é SHIP: dúvida vira nota. Grave o relatório que o dispatch nomeia ANTES de encerrar — o arquivo é o retorno, não a mensagem final. Se ele já existir quando você começar, é resíduo de outra rodada: não o leia antes de escrever o seu (ancoragem no veredito alheio), e não leia os relatórios dos outros papéis. Primeira linha `**Verdict:** SHIP|FIX`, depois `**Reviewed-SHA:** {sha}`, tabela `## Bloqueadores` (`| id | tipo | onde | evidência |`; vazia = `Nenhum.`) e `## Notas`. Bloqueador só com evidência e tipo; o resto é nota, e nota nunca pede rodada nova. Numa confirmação (o orquestrador te retoma depois da correção, com o `sha` novo) acrescente ao fim uma seção nova com `**Verdict:**` e `**Reviewed-SHA:** {sha novo}`: se você abriu bloqueadores, julgue só eles; se não abriu, julgue só o delta `{sha anterior}..{sha novo}` — o que a correção abriu. O relatório é append-only: vale o último veredito e, na `## Checks`, a última linha de cada Cn. Um comando por chamada de Bash, sem encadear (`;`, `&&`, pipe): o composto é negado e custa a rodada. Arquivo do framework ou da feature (o checklist, o plan.md) você lê com Read, nunca `sed`/`cat`/`head`; código do commit, com `git show {sha}:<caminho>`. NUNCA modifique código, plan.md, checks.json ou feature.json, nunca `git checkout --`/`git stash`, nada em segundo plano nem laço de espera (`sleep`, `until`)."
|
|
397
|
+
"persona": "Você é o revisor independente do Gate 3, read-only. Não participou da implementação e não prova cenários (é o verificador). Você lê SÓ o commit revisado: `git diff {base}..{sha}`, `git show {sha}:<caminho>`, `git log {base}..{sha}` — nunca a árvore de trabalho (Read/Glob/Grep sobre `src/` leem o disco, onde o verificador pode estar com um mutante aplicado). `base` e `sha` vêm no dispatch. Julga o diff em cinco dimensões, na seção \"Revisor\" de `.morph/framework/evals/review-checklist.md`: ESCOPO (o diff contra as fatias e o `## Contrato de implementação` do plano — arquivo fora de toda fatia, comportamento que nenhum cenário pediu, teste além do orçamento — teste para Cn `prova: leitura`, mais de um por Cn de risco sem porquê no plano, teste que só fixa texto/constante/DTO; `expectedCount` menor no `config.json` sem teste apagado no mesmo diff é `regressao`); ARQUITETURA (padrão ou abstração nova contra o stack do projeto e os standards — camada que o projeto não usa, repositório sobre o DbContext, dependência nova sem decisão no plano); REGRESSÃO (para cada símbolo público alterado, `morph-spec graph affected <símbolo> --prod --json`; sem grafo — `no-graph`, `not-found`, `ambiguous` — caia para `git grep -n <símbolo> {sha}` e siga, a ausência de grafo nunca bloqueia; ausência de consumidor nunca sai do grafo); O QUE A CORREÇÃO ABRIU (revisando uma correção de rodada anterior, releia o comportamento vizinho); PERFORMANCE só com evidência (lista sem paginação no servidor sobre volume real, consulta N+1 visível no diff) e RASTREABILIDADE de chamada a LLM (dá para reconstruir o que foi ao provedor e o que voltou?). Tipos de bloqueador: `escopo`, `arquitetura`, `regressao`, `performance`. Seu default é SHIP: dúvida vira nota. Grave o relatório que o dispatch nomeia ANTES de encerrar — o arquivo é o retorno, não a mensagem final. Se ele já existir quando você começar, é resíduo de outra rodada: não o leia antes de escrever o seu (ancoragem no veredito alheio), e não leia os relatórios dos outros papéis. Primeira linha `**Verdict:** SHIP|FIX`, depois `**Reviewed-SHA:** {sha}`, tabela `## Bloqueadores` (`| id | tipo | onde | evidência |`; vazia = `Nenhum.`) e `## Notas`. Bloqueador só com evidência e tipo; o resto é nota, e nota nunca pede rodada nova. Numa confirmação (o orquestrador te retoma depois da correção, com o `sha` novo) acrescente ao fim uma seção nova com `**Verdict:**` e `**Reviewed-SHA:** {sha novo}`: se você abriu bloqueadores, julgue só eles; se não abriu, julgue só o delta `{sha anterior}..{sha novo}` — o que a correção abriu. O relatório é append-only: vale o último veredito e, na `## Checks`, a última linha de cada Cn. Um comando por chamada de Bash, sem encadear (`;`, `&&`, pipe): o composto é negado e custa a rodada. Arquivo do framework ou da feature (o checklist, o plan.md) você lê com Read, nunca `sed`/`cat`/`head`; código do commit, com `git show {sha}:<caminho>`. NUNCA modifique código, plan.md, checks.json ou feature.json, nunca `git checkout --`/`git stash`, nada em segundo plano nem laço de espera (`sleep`, `until`)."
|
|
398
398
|
},
|
|
399
399
|
"security": {
|
|
400
400
|
"title": "Gate 3 Security Reviewer",
|
package/framework/docs/CLI.md
CHANGED
|
@@ -38,7 +38,7 @@ No **review**, o `gate-check` lê os relatórios de `4-review/` (`src/lib/review
|
|
|
38
38
|
|
|
39
39
|
Um stamp de `verification` com status `fail` (último `morph-spec verify` vermelho) **força pausa** em qualquer gate. Um stamp `pass` mas **stale** (o código mudou depois do commit do stamp — só conta o que está fora de `.morph/`; o `config.json` conta exceto a troca de `expectedCount`, e um commit só de estado, como o do próprio `feature.json` do verify, não invalida) força pausa **só no ship** (`review`); em `plan`/`uiux` a staleness é computada e reportada em `signals`, mas não pausa nada — é regra de ship, não de gate genérico. Stamp **ausente** nunca pausa por isso (features legadas sem stamp).
|
|
40
40
|
|
|
41
|
-
**Dispensa de e2e:** o stamp carrega `nodes.e2e` e a razão literal `e2eReason`, porque um nó e2e que **pula** não reprova o rollup — sem eles o gate lê `pass` tanto quando o e2e rodou e passou quanto quando ele nunca rodou. No **ship** (`review`), um `skip` é classificado pela razão (`classifyE2eSkip`, em `risk-detector.js` — fonte única) e o veredito fica registrado em `gateDecisions.review.signals` (`e2eStatus`, `e2eReason`, `e2eSkipClass`): `project` ("project does not containerize")
|
|
41
|
+
**Dispensa de e2e:** o stamp carrega `nodes.e2e` e a razão literal `e2eReason`, porque um nó e2e que **pula** não reprova o rollup — sem eles o gate lê `pass` tanto quando o e2e rodou e passou quanto quando ele nunca rodou. No **ship** (`review`), um `skip` é classificado pela razão (`classifyE2eSkip`, em `risk-detector.js` — fonte única) e o veredito fica registrado em `gateDecisions.review.signals` (`e2eStatus`, `e2eReason`, `e2eSkipClass`): `project` ("project does not containerize") e `not-applicable` ("not applicable: …", a feature sem cenário `prova: e2e` e sem arquivo de UI, spec e2e ou container no diff) são **dispensa legítima** — passam, com o motivo gravado, sem precisar de `gate-decision` manual; `environment` ("docker is not available…"), `requested` (`--skip-e2e`) e `unknown` (qualquer outra razão, **inclusive razão nenhuma**) **pausam** — a máquina ou o operador não são evidência sobre o código, e uma dispensa sem motivo é o mesmo no-op silencioso que a regra existe para eliminar. `e2eStatus`/`e2eReason`/`e2eSkipClass` **não** são sobrescrevíveis por `--signals`: descrevem o que aconteceu no disco, como `gate`/`workType`.
|
|
42
42
|
|
|
43
43
|
**Prova de mídia:** do MESMO relatório e pelo MESMO leitor, o `gate-check` grava `signals.mediaClaims = {section, featureGeneratesMedia}`. `featureGeneratesMedia` é determinístico do disco — existe ao menos uma fatia do `checks.json` cujo `standards` cita `ai-agents-modalities-image-gen`, `ai-agents-media-video` ou `ai-agents-media-pipeline` — pelo id de STANDARDS.json ou pelo caminho, com ou sem `framework/`/`standards/` na frente, porque uma grafia não prevista desarmaria o guardrail sem uma linha de erro (`featureGeneratesMedia`, função exportada de `gate-check.js`, é onde essa normalização mora e é testada). Nessa condição, relatório **sem** a seção `## Mídia gerada` **pausa o Gate 3**: as quatro afirmações de mídia (custo, revisão humana, marcação, hot path não bloqueado) não foram provadas (`framework/evals/review-checklist.md`, "Feature que gera mídia").
|
|
44
44
|
|
|
@@ -58,7 +58,7 @@ A tabela é a mesma régua que `shouldPauseGate` aplica e que o `gate-check` imp
|
|
|
58
58
|
| `verificationStatus` | === 'fail' | `verify` vermelho — build, testes, validadores **ou e2e**. Vale em **qualquer** gate |
|
|
59
59
|
| `verificationStatus` | ausente, no `review` | nenhum `verify` carimbado: ship sem prova; `approve` auto aplica a mesma régua |
|
|
60
60
|
| `verificationStale` | true | Stamp do `verify` com sha != HEAD: o verde é de outro código. Só no **ship** |
|
|
61
|
-
| `e2eSkipClass` (derivada) | environment/requested/unknown | e2e pulou sem dispensa legítima (
|
|
61
|
+
| `e2eSkipClass` (derivada) | environment/requested/unknown | e2e pulou sem dispensa legítima (`project` e `not-applicable` passam). Só no **ship** |
|
|
62
62
|
| `promptModel` | prompt/modelo tocado | Sem nó `evals` declarado, ou eval pulado neste verify. Só no **ship** |
|
|
63
63
|
| `mediaClaims` | seção ausente | Feature que gera mídia, relatório sem `## Mídia gerada`. Só no **ship** |
|
|
64
64
|
| `screenChecklist` | item em aberto | **uiux**: tela sem checklist completo, nenhuma `## Tela:`, ou tela sem protótipo e prints 1280/390. **ship**: item decidido sem linha em `## Checklist de tela` |
|
|
@@ -282,6 +282,8 @@ O nó `e2e` é o único que **executa** a aplicação: sobe o `docker compose` d
|
|
|
282
282
|
|
|
283
283
|
As specs são procuradas na raiz, em `project.frontendPath` e, sem ele, nas pastas de frontend conhecidas (as mesmas do detector, mais `web`). Se o nó cai para smoke enquanto existe um `playwright.config.*` não executado em pasta de primeiro nível, o `verify` avisa nomeando a pasta e `project.frontendPath`. A contagem de specs sai em `nodes.e2e.count` do `verify --json` (`null` quando não rodou ou o sumário é ilegível, nunca 0); ela não é persistida no stamp.
|
|
284
284
|
|
|
285
|
+
**O e2e só sobe quando pode provar algo:** com testes vermelhos ele não roda (`tests failed — the e2e does not run over a red suite`); sem nó de teste `e2e: true` (esses são a prova do backend contra a stack e sempre a sobem), ele também não roda quando nenhum cenário do `checks.json` é `prova: e2e` e o diff da feature contra a branch default (fora de `.morph/`) não toca UI (`.tsx`, `.css`, `.html`…), spec e2e, `playwright.config.*`, Dockerfile/compose nem pasta de frontend conhecida — `skip` com a razão `not applicable: …`, que o gate aceita. Sem git, sem base ou diff vazio: roda (só para diante de evidência).
|
|
286
|
+
|
|
285
287
|
**Dispensa legítima × setup faltando:** projeto sem compose e sem a integração `docker` é `skip` com razão; projeto que **declara** `docker` e não tem compose é `fail` — é verificação que nunca foi montada, não projeto que não containeriza.
|
|
286
288
|
|
|
287
289
|
**Descoberta de testes e relógio:** a varredura por `*Tests.csproj` **não enxerga worktrees** — nem os convencionais (`worktrees/`, `.worktrees/`) nem os registrados em `git worktree list` fora da convenção. O timeout do nó `tests` deixou de ser fixo: `--timeout` (que agora cobre build **e** tests) > `project.testTimeoutMs` no `config.json` > **120 s por projeto de teste encadeado** — um encadeamento nunca nasce condenado pelo tamanho. Quando o relógio estoura, o nó diz isso com nome (`timeout após N ms na execução X de Y — nenhum teste falhou`) em vez de devolver log truncado.
|
|
@@ -316,7 +318,7 @@ Nenhuma regra de gate muda: e2e pulado, escopo, evals e stale valem igual.
|
|
|
316
318
|
|
|
317
319
|
**Sem workflow** que rode `morph-spec verify` publicando `morph-verify.json`, cria e commita `.github/workflows/morph-verify.yml` na branch da feature (gatilho `push` em `morph/**`, `.morph/` fora do gatilho exceto o `config.json`, `cancel-in-progress`, setup de .NET por `global.json`/stack, install por lockfile, browsers do Playwright onde há config, e o `morph-spec` na versão de `.morph/.morphversion`). Um run sobre um commit anterior vale quando só `.morph/` andou desde ele; run `cancelled`/`skipped`/`startup_failure` não é prova.
|
|
318
320
|
|
|
319
|
-
**Sem CI cai para o verify local, com a razão** (`project.ci: false`, origin fora do GitHub, `gh` ausente ou sem login, branch que não é `morph/<feature>`, token HTTPS sem o escopo `workflow` para criar o arquivo, push recusado, workflow que não disparou nem com `gh workflow run`, run sem o artefato). **Antes de
|
|
321
|
+
**Sem CI cai para o verify local, com a razão** (`project.ci: false`, origin fora do GitHub, `gh` ausente ou sem login, branch que não é `morph/<feature>`, token HTTPS sem o escopo `workflow` para criar o arquivo, push recusado, workflow que não disparou nem com `gh workflow run`, run sem o artefato). **Antes de tudo — com ou sem CI — reaproveita o stamp fresco:** último stamp `pass` com `sha`, nada fora de commit e `treeMovedSince(stamp.sha, HEAD)` falso (a mesma régua do `verificationStale`: só `.morph/` andou, ou o `config.json` mudou só `expectedCount`) → não empurra, não roda nem regrava, imprime "stamp verde e fresco — o CI não roda de novo" e o `--json` traz `reason: "stamp-reused"`, `status`, `nodes` e `reused: { sha, ts, source }`, exit 0.
|
|
320
322
|
|
|
321
323
|
Código não commitado é **erro de uso (exit 2)**: o CI só vê commits. CI rodando depois de 50 min é **exit 3** (`status: "pending"`), sem stamp — não é vermelho. Com task, `--filter`, `--skip-*`, `--fresh-e2e`, `--linux`, `--record-baseline`, `--refresh-cache` ou `--no-persist`, erro de uso. Vermelho imprime `gh run view <id> --log-failed`.
|
|
322
324
|
|
|
@@ -328,25 +330,25 @@ Código não commitado é **erro de uso (exit 2)**: o CI só vê commits. CI rod
|
|
|
328
330
|
|
|
329
331
|
**Validador `code-budget` (nó `validators` do `verify`)** — mede o que a árvore **adicionou** contra a branch default: `git diff -U0` a partir do merge-base com `origin/{default}` (ou `{default}` local), arquivo novo não rastreado conta inteiro e arquivo movido sem edição não conta. Lê `.cs`/`.ts`/`.tsx`/`.js`/`.jsx`/`.mjs`/`.cjs`, fora de `.d.ts`, de `node_modules`/`bin`/`obj`/`dist`/`.morph` e de código gerado (`*.Designer.cs`, `*.g.cs`, `*ModelSnapshot.cs`).
|
|
330
332
|
|
|
331
|
-
Três medidas, cada uma **um aviso, nunca erro**: (a) **linhas de comentário adicionadas que citam processo** — `UC-nn`, `ADR-nn`, `FR-nn`, `C{n}`/`F{n}` (cenário/fatia — fora tecla, métrica, célula e o modelo C4), `Gate N`, `plan.md`, `checks.json`, mockup — avisa a partir de uma, com a contagem sobre o total de linhas de comentário adicionadas e até 4 `arquivo:linha` (standard `architecture-code-comments`); comentário é o que o varredor de `src/lib/ai/comment-stripper.js` separa de string, com template e regex literal de TS/JS; (b) **linhas não vazias de teste ÷ de produção** — avisa acima de **1
|
|
333
|
+
Três medidas, cada uma **um aviso, nunca erro**: (a) **linhas de comentário adicionadas que citam processo** — `UC-nn`, `ADR-nn`, `FR-nn`, `C{n}`/`F{n}` (cenário/fatia — fora tecla, métrica, célula e o modelo C4), `Gate N`, `plan.md`, `checks.json`, mockup — avisa a partir de uma, com a contagem sobre o total de linhas de comentário adicionadas e até 4 `arquivo:linha` (standard `architecture-code-comments`); comentário é o que o varredor de `src/lib/ai/comment-stripper.js` separa de string, com template e regex literal de TS/JS; (b) **linhas não vazias de teste ÷ de produção** — avisa acima de **1×**, e só quando o teste adicionado passa de **40 linhas** (a regressão de um bug de duas linhas cabe abaixo disso); sem linha de produção, o aviso dá as duas contagens sem razão. (c) **densidade de comentário** — linhas de comentário adicionadas ÷ linhas de código adicionadas (as não vazias menos as de comentário), doc-comment (`///`, JSDoc) incluído — avisa acima de **1 a cada 10**, e só a partir de **40 linhas** de código, com até 4 arquivos mais comentados e suas contagens (o padrão do standard `architecture-code-comments` é nenhum comentário).
|
|
332
334
|
|
|
333
335
|
Teste é o que o validador `reuse` já trata como teste: arquivo `.test.` ou `.spec.` com extensão `js`/`jsx`/`ts`/`tsx`, e tudo sob `__tests__/`, `test/`, `tests/` ou pasta terminada em `Test`/`Tests` (`Foo.Tests/`, `FooTests/`). O resto conta como produção, inclusive `a.test.mjs`, `a.test.cjs` e `*.e2e.ts` fora dessas pastas.
|
|
334
336
|
|
|
335
|
-
Sem base git, ou sem linha de código adicionada, pula com razão; qualquer falha de medição também vira skip, nunca erro.
|
|
337
|
+
Sem base git, ou sem linha de código adicionada, pula com razão; qualquer falha de medição também vira skip, nunca erro.
|
|
336
338
|
|
|
337
339
|
**Por quê.** Excesso justificado não silencia o aviso: a justificativa mora na task (orçamento do `morph-plan` passo 5), e é lá que o avaliador a lê.
|
|
338
340
|
|
|
339
341
|
### mutate
|
|
340
342
|
|
|
341
|
-
**`morph-spec mutate [feature] [--plan <arquivo>] [--out <arquivo>] [--
|
|
343
|
+
**`morph-spec mutate [feature] [--plan <arquivo>] [--out <arquivo>] [--allow-dirty] [--jobs <n>] [--timeout <ms>] [--restore] [--json]`** — mutação **dirigida** para o verificador do Gate 3: no máximo **3** mutantes, só quando o diff tem uma guarda que um cenário exige e o verificador não achou o teste que a morde.
|
|
342
344
|
|
|
343
345
|
**Manifesto** (`--plan`, default `4-review/mutants.json`): `{"mutants":[{"id":"M1","file":"src/x.cs","line":42,"find":"a && b","replace":"a","expect":"OrdersTests.RecusaSemItens deve falhar"}]}` — `expect` é obrigatório (qual teste deve falhar e por quê, dito antes de rodar), `find` começa na `line` e é único nela; barra invertida do código vai como `{{BS}}` (o transporte do Bash a reduz). Mais de 3 mutantes ou `expect` ausente: exit 2.
|
|
344
346
|
|
|
345
347
|
**O que compila (.NET):** o `build` do nó quando declarado; senão o que o comando nomeia (`.sln`/`.slnx`/`.csproj` — a solution vale pelos projetos que lista, também para o subconjunto); senão a solution única (ou o projeto único) do diretório alvo, como o próprio `dotnet test` escolhe. Só sem nada descobrível recusa (exit 2), antes de mutar, pedindo a solution no comando ou o `build`.
|
|
346
348
|
|
|
347
|
-
**Método:** recusa arquivo não commitado (`--allow-dirty` assume o risco); snapshot dos bytes fora da árvore (`<git-common-dir>/morph-spec/mutation/<run>/`) com journal — rodada que morreu se desfaz por `mutate --restore`; em .NET, uma chave `MORPH_MUTANT` por mutante de expressão e um build só (o que a chave não compila cai para rebuild real, e falha de build é `build-error`, nunca morte); depois **o subconjunto decide**: os testes que a feature alterou mais os que citam os tipos mutados (vitest/jest usam `related`) — a ferramenta escolhe, não o verificador. `killed` = falha **nova** contra a rodada-base do mesmo escopo, com o motivo literal do TRX; `survived` no subconjunto é o veredito, com o `expect` ao lado;
|
|
349
|
+
**Método:** recusa arquivo não commitado (`--allow-dirty` assume o risco); snapshot dos bytes fora da árvore (`<git-common-dir>/morph-spec/mutation/<run>/`) com journal — rodada que morreu se desfaz por `mutate --restore`; em .NET, uma chave `MORPH_MUTANT` por mutante de expressão e um build só (o que a chave não compila cai para rebuild real, e falha de build é `build-error`, nunca morte); depois **o subconjunto decide**: os testes que a feature alterou mais os que citam os tipos mutados (vitest/jest usam `related`) — a ferramenta escolhe, não o verificador. `killed` = falha **nova** contra a rodada-base do mesmo escopo, com o motivo literal do TRX; `survived` no subconjunto é o veredito, com o `expect` ao lado; rodada que cai é `inconclusive`. **Nunca a suíte inteira:** sem subconjunto utilizável (nenhum teste da feature nem citando os tipos mutados) o comando recusa antes de compilar (exit 2) e manda provar o cenário por leitura; subconjunto que some em runtime (base que não seleciona teste, ou cai) deixa os mutantes `inconclusive` com a mesma razão.
|
|
348
350
|
|
|
349
|
-
**Nó `e2e: true`:** arquivo coberto **só** por nó de teste `e2e: true` é recusado (exit 2, nomeando mutante, arquivo e nó): a suíte testa o container do compose e o `mutate` recompila só localmente — todo mutante sobreviveria em falso. Com outro nó dono do arquivo, ele é o escolhido — mas, havendo qualquer nó `e2e: true` no config, só se algum arquivo de teste dele (com atributo de teste) citar um tipo declarado no arquivo mutado: o dono de um `.cs` é a suíte .NET, não a referência de projeto, e a unidade que só referencia a API daria sobrevivente em falso. Sem citação, recusa (exit 2) antes do snapshot. Nas duas recusas a saída prescreve o protocolo manual com o comando pronto do nó e2e, cada passo numa linha só encadeado por `&&` (nunca `;`): base verde antes do 1º mutante (`eval "$(morph-spec env <f>)" && morph-spec e2e up <f> && morph-spec heavy run -- <comando do nó>`), a mesma cadeia depois de cada edição, e restauração conferida por `git diff --quiet` seguida de um novo `e2e up` — registrado em `4-review`. Sem nó `e2e: true`,
|
|
351
|
+
**Nó `e2e: true`:** arquivo coberto **só** por nó de teste `e2e: true` é recusado (exit 2, nomeando mutante, arquivo e nó): a suíte testa o container do compose e o `mutate` recompila só localmente — todo mutante sobreviveria em falso. Com outro nó dono do arquivo, ele é o escolhido — mas, havendo qualquer nó `e2e: true` no config, só se algum arquivo de teste dele (com atributo de teste) citar um tipo declarado no arquivo mutado: o dono de um `.cs` é a suíte .NET, não a referência de projeto, e a unidade que só referencia a API daria sobrevivente em falso. Sem citação, recusa (exit 2) antes do snapshot. Nas duas recusas a saída prescreve o protocolo manual com o comando pronto do nó e2e, cada passo numa linha só encadeado por `&&` (nunca `;`): base verde antes do 1º mutante (`eval "$(morph-spec env <f>)" && morph-spec e2e up <f> && morph-spec heavy run -- <comando do nó>`), a mesma cadeia depois de cada edição, e restauração conferida por `git diff --quiet` seguida de um novo `e2e up` — registrado em `4-review`. Sem nó `e2e: true`, vale a regra do subconjunto acima.
|
|
350
352
|
|
|
351
353
|
**Sem `<feature>`:** vale a única feature em andamento; sem ela (nenhuma, ou mais de uma), exige `--plan`, e a seção só é gravada com `--out` — sai no stdout, `section: null` no `--json`.
|
|
352
354
|
|
|
@@ -496,6 +498,10 @@ Sem fatia na linha de comando, a saída traz `reviews: { verifier, reviewer, sec
|
|
|
496
498
|
|
|
497
499
|
**`morph-spec stack-scan [<feature>] [--json]`** — varredura determinística do código contra `config.project.stack`: só os stacks configurados são julgados (sem `project.stack`, nenhuma regra roda e o resultado é `não auditado: project.stack ausente em .morph/config/config.json`, nunca "Em compliance" — exit 0; stack sem regras de varredura sai `não auditado` pelo mesmo motivo; código de um stack não configurado é só anotado). `dotnet`: TargetFramework abaixo de net10 e ORM/banco diferente (Dapper puro, SQL Server, MySQL) são **Bloqueante**; `Guid.NewGuid()`, repository genérico (`IRepository<T>`/`IUnitOfWork` — código morto: apagar a pasta `Repository/` e as 2 linhas de DI), classe `*Service`/`*Manager` sobre `DbContext` e SQL cru (`FromSqlRaw`, `ExecuteSqlRaw`, `SqlQueryRaw`, `ExecuteQuery`) são **Alto**; classe não-sealed é **Médio**; pacote `Microsoft.EntityFrameworkCore|AspNetCore|Extensions` abaixo da major 10 é **Baixo**. `nextjs`: frontend sem Next.js é Bloqueante; Pages Router sem `app/` e biblioteca de UI diferente (MUI, antd, Chakra, Bootstrap, Mantine) são Médio. Código de teste não conta; `node_modules`, `bin`, `obj`, `.morph`, `.claude` e os contêineres de worktree ficam fora; arquivo ilegível é anotado, nunca derruba. Sem código fonte = GREENFIELD. As contagens são de texto e superestimam consumidores — o relatório aponta `graph affected <símbolo> --uses-only`. Desvio Bloqueante/Alto vira nó da árvore de decisões da `morph-plan`. Com `<feature>`, grava `.morph/features/<f>/2-plan/stack-scan.md` (exit 2 se a feature não existe, 1 fora da árvore dona); sem, imprime o markdown.
|
|
498
500
|
|
|
501
|
+
### tests-audit
|
|
502
|
+
|
|
503
|
+
**`morph-spec tests-audit [--json]`** — auditoria **somente leitura** dos arquivos de teste rastreados (`git ls-files` + `isTestPath`): total de casos (`[Fact]`/`[Theory]`, `it`/`test`), os maiores arquivos e quatro listas de **candidatos** — nunca vereditos, nada é apagado: teste que lê `.md`/`.txt` ou tem 3+ asserts de frase literal (fixa texto, não comportamento); constante comparada ao próprio literal; família de 4+ `[Fact]` com o mesmo prefixo de nome (candidata a `[Theory]`); o mesmo assunto em mais de uma camada (`XHandlerTests` e `XEndpointTests`/`XIntegrationTests` — fique com a mais barata que morde). Fora de git: exit 2 com a razão. É o ponto de partida de uma limpeza: apagar teste e depois rodar `verify --record-baseline` grava a contagem menor.
|
|
504
|
+
|
|
499
505
|
## Suítes de teste (`project.tests[]`) e a divisão loop × suíte
|
|
500
506
|
|
|
501
507
|
O nó `tests` do `verify` é **plural**: um projeto pode declarar quantas suítes tiver em
|
|
@@ -677,7 +683,7 @@ sem `--no-build` já compila sozinho, e pré-compilar ali só dobraria o relógi
|
|
|
677
683
|
**O ciclo da baseline, e o número que só sai à mão.** `verify --record-baseline` é a única via de
|
|
678
684
|
escrita: mede cada nó numa execução real e grava `expectedCount` de volta no `config.json` (escrita
|
|
679
685
|
atômica `tmp.{pid}` + rename, preservando todo o resto do arquivo). Recusa **quatro** vezes — execução
|
|
680
|
-
vermelha, execução **parcial** (sob `--filter`, mesmo com o verify verde: baseline de meia frota é
|
|
686
|
+
vermelha (fora o `count-drop` com exit 0, abaixo), execução **parcial** (sob `--filter`, mesmo com o verify verde: baseline de meia frota é
|
|
681
687
|
afirmação sobre a outra metade que ninguém fez), contagem desconhecida, e **sem `config.json` ou sem
|
|
682
688
|
`project.tests[]`** (erro de uso, exit 2; o arquivo nunca é criado implicitamente — gravar os nós que o
|
|
683
689
|
fallback sintetiza exigiria inventar a declaração que o comando veio manter). Verde com gravação
|
|
@@ -685,11 +691,7 @@ recusada sai **exit 1**, com a razão em **stderr** (sobrevive ao `--json`). A g
|
|
|
685
691
|
pelos **nós de teste**, não pelos quatro nós do verify: um `validators` vermelho não muda quantos
|
|
686
692
|
testes rodaram. A execução que **gravou** a baseline (verde e inteira) persiste o stamp `verification` como qualquer verify: ela mediu a suíte toda, e rodá-la de novo só para ter prova seria pagar duas vezes pelo mesmo
|
|
687
693
|
verde. Sem gravação (vermelha, parcial, contagem desconhecida) não há stamp, e o `reason` do `--json`
|
|
688
|
-
nomeia o nó que impediu. **
|
|
689
|
-
mão **alto demais** (9 onde a suíte roda 7) deixa o verify vermelho por `count-drop`, e então
|
|
690
|
-
`--record-baseline` recusa — preservando o 9. **Não há flag de regravação forçada:** rebaixe ou apague
|
|
691
|
-
o número à mão e então re-meça pelo comando. O caso oposto se conserta sozinho — número baixo demais
|
|
692
|
-
passa com aviso de alta, e o comando grava.
|
|
694
|
+
nomeia o nó que impediu. **Apagar teste é legítimo:** a única cor vermelha que a gravação aceita é o `count-drop` de um nó que saiu com exit 0 — a suíte ficou menor de propósito. `--record-baseline` grava o número menor que mediu, o nó fica verde nessa mesma execução, o stamp persiste e o `feedback` diz `[baseline] rebaixada: <nó> (9 → 7)`; o revisor do Gate 3 vê a queda e julga se foi limpeza. Sem a flag, a queda continua reprovando (regressão silenciosa). Queda ao lado de outro nó vermelho não grava nada.
|
|
693
695
|
|
|
694
696
|
**A divisão loop × suíte.** É a resposta ao "a suíte inteira não cabe numa chamada":
|
|
695
697
|
|
|
@@ -41,7 +41,10 @@ diferente") é nota; nota não bloqueia e não pede rodada nova. Na dúvida, sem
|
|
|
41
41
|
## Verificador (`4-review/verifier.md`)
|
|
42
42
|
|
|
43
43
|
Missão: **provar cada cenário** do `2-plan/checks.json`. O default de todo `Cn` é NÃO PROVADO;
|
|
44
|
-
critério que você não verificou nunca vira PROVADO por inferência.
|
|
44
|
+
critério que você não verificou nunca vira PROVADO por inferência. A prova é a que o plano declarou
|
|
45
|
+
(`prova:` do Cn): `leitura` prova-se pelo `arquivo:linha` e pela fiação, **sem teste** — Cn `leitura`
|
|
46
|
+
sem teste não é NÃO PROVADO, e pedir teste para ele não é bloqueador. Só Cn com `risco:` exige teste
|
|
47
|
+
que morde.
|
|
45
48
|
|
|
46
49
|
```markdown
|
|
47
50
|
## Checks
|
|
@@ -82,7 +85,9 @@ morde. Escreva `4-review/mutants.json` e rode `morph-spec mutate {feature}` **um
|
|
|
82
85
|
|
|
83
86
|
`expect` é obrigatório: diga qual teste deve falhar e por quê **antes** de rodar — mutante cujo
|
|
84
87
|
efeito você não sabe prever tende a ser equivalente. Barra invertida do código vira `{{BS}}`.
|
|
85
|
-
Sobreviveu numa linha que um cenário exige → bloqueador `teste`. Sobreviveu em outra → nota.
|
|
88
|
+
Sobreviveu numa linha que um cenário exige → bloqueador `teste`. Sobreviveu em outra → nota.
|
|
89
|
+
Sem subconjunto (exit 2) ou `inconclusive`: a mutação não roda a suíte inteira — prove por leitura
|
|
90
|
+
(`arquivo:linha` + o teste que cobre), nunca em laço. Cole a
|
|
86
91
|
seção `## Mutações` que a ferramenta imprime. A reversão é da ferramenta; rodada morta no meio:
|
|
87
92
|
`morph-spec mutate --restore`.
|
|
88
93
|
|
|
@@ -109,6 +114,11 @@ Read-only, sobre o commit do dispatch: `git diff {base}..{sha}`, `git show {sha}
|
|
|
109
114
|
árvore de trabalho — o verificador pode estar com um mutante aplicado nela. Default SHIP.
|
|
110
115
|
|
|
111
116
|
1. **Escopo**: o diff contra as fatias (`arquivos:`) e o `## Contrato de implementação` do plano.
|
|
117
|
+
Teste além do orçamento também é escopo: teste para Cn `prova: leitura`, mais de um teste por Cn de
|
|
118
|
+
risco sem porquê no plano, teste que só fixa texto/constante/DTO, o mesmo comportamento em duas
|
|
119
|
+
camadas — bloqueador `escopo` (apague, não acrescente). `expectedCount` menor no
|
|
120
|
+
`.morph/config/config.json` do diff sem teste apagado no mesmo diff é bloqueador `regressao`: é
|
|
121
|
+
suíte que parou de rodar, não limpeza.
|
|
112
122
|
2. **Arquitetura**: padrão ou abstração nova contra o stack do projeto e os standards (camada que o
|
|
113
123
|
projeto não usa, repositório sobre o DbContext, dependência nova sem decisão no plano).
|
|
114
124
|
3. **Regressão**: para cada símbolo público alterado, `morph-spec graph affected <símbolo> --prod --json`.
|
|
@@ -6,41 +6,16 @@ Comprehensive hooks system for enforcing spec-driven development at the Claude C
|
|
|
6
6
|
|
|
7
7
|
```
|
|
8
8
|
framework/hooks/
|
|
9
|
-
├── claude-code/
|
|
10
|
-
│ ├── core/
|
|
11
|
-
│
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
│ │ ├── block-destructive-worktree-removal.js # PreToolUse(Bash): raw removal follows junctions out
|
|
15
|
-
│ │ ├── block-raw-worktree-add.js # PreToolUse(Bash): raw `git worktree add` is ungoverned
|
|
16
|
-
│ │ └── warn-bash-source-write.js # PreToolUse(Bash): source written by redirect skips the Write/Edit guards
|
|
17
|
-
│ ├── user-prompt/
|
|
18
|
-
│ │ └── enrich-prompt.js # Context-aware prompt enrichment
|
|
19
|
-
│ ├── pre-tool-use/
|
|
20
|
-
│ │ ├── protect-spec-files.js # Block edits to approved spec artifacts
|
|
21
|
-
│ │ └── enforce-phase-writes.js # Enforce writes to correct phase dir
|
|
22
|
-
│ ├── post-tool-use/
|
|
23
|
-
│ │ └── dispatch.js # Dispatch on CLI commands (auto-checkpoint)
|
|
24
|
-
│ ├── stop/
|
|
25
|
-
│ │ └── validate-completion.js # Advisory: warn about incomplete work
|
|
26
|
-
│ ├── pre-compact/
|
|
27
|
-
│ │ └── save-morph-context.js # Snapshot state before compaction
|
|
28
|
-
├── shared/ # Reusable utilities for all hooks
|
|
29
|
-
│ ├── state-reader.js # Read-only state.json accessor
|
|
30
|
-
│ ├── phase-utils.js # Phase constants and path utilities
|
|
31
|
-
│ ├── hook-response.js # JSON response builders
|
|
32
|
-
│ └── stdin-reader.js # Stdin JSON reader
|
|
33
|
-
├── git/ # Git hooks (Bash)
|
|
34
|
-
│ ├── pre-commit/
|
|
35
|
-
│ │ ├── orchestrator.sh # Master hook dispatcher
|
|
36
|
-
│ │ └── agents.sh # Validates agents.json schema
|
|
37
|
-
│ ├── commit-msg/
|
|
38
|
-
│ │ └── conventional-commits.sh # Enforces conventional commits
|
|
39
|
-
│ └── pre-push/
|
|
40
|
-
│ └── run-tests.sh # Runs test suite before push
|
|
41
|
-
└── README.md # This file
|
|
9
|
+
├── claude-code/
|
|
10
|
+
│ ├── core/ # every hook, plus chain.js (one process per multi-hook group)
|
|
11
|
+
│ └── statusline.py # global statusline
|
|
12
|
+
├── shared/ # code hooks share (and src/ imports): state reader, guards, e2e, heavy, telemetry
|
|
13
|
+
└── README.md
|
|
42
14
|
```
|
|
43
15
|
|
|
16
|
+
The registered set is `MORPH_HOOKS` in `src/utils/hooks-installer.js` — the table below lists it. No hook builds,
|
|
17
|
+
typechecks or runs tests: that is `morph-spec verify`.
|
|
18
|
+
|
|
44
19
|
## Hook Events
|
|
45
20
|
|
|
46
21
|
| Event | Hook | Type | Purpose |
|
|
@@ -104,17 +79,6 @@ The installer writes to `.claude/settings.local.json`:
|
|
|
104
79
|
}
|
|
105
80
|
```
|
|
106
81
|
|
|
107
|
-
### Git Hooks
|
|
108
|
-
|
|
109
|
-
```bash
|
|
110
|
-
# In your project root
|
|
111
|
-
cd .git/hooks
|
|
112
|
-
ln -sf ../../framework/hooks/git/pre-commit/orchestrator.sh pre-commit
|
|
113
|
-
ln -sf ../../framework/hooks/git/commit-msg/conventional-commits.sh commit-msg
|
|
114
|
-
ln -sf ../../framework/hooks/git/pre-push/run-tests.sh pre-push
|
|
115
|
-
chmod +x pre-commit commit-msg pre-push
|
|
116
|
-
```
|
|
117
|
-
|
|
118
82
|
## Shared Utilities
|
|
119
83
|
|
|
120
84
|
All Claude Code hooks import from `framework/hooks/shared/`:
|
|
@@ -165,7 +165,7 @@ function handleAskUserQuestion(input, sessionRoot) {
|
|
|
165
165
|
|
|
166
166
|
// Same contract as `approve --self-assessed`: approving review without its reports is stamped, never silent.
|
|
167
167
|
const selfAssessed = gate === 'review' && feature?.workType !== 'hotfix'
|
|
168
|
-
&& ['verifier.md', 'reviewer.md'].some((f) => !existsSync(join(root, '.morph', 'features', featureName, '4-review', f)));
|
|
168
|
+
&& (feature?.workType === 'chore' ? ['reviewer.md'] : ['verifier.md', 'reviewer.md']).some((f) => !existsSync(join(root, '.morph', 'features', featureName, '4-review', f)));
|
|
169
169
|
if (selfAssessed) {
|
|
170
170
|
warnings.push(
|
|
171
171
|
`⚠️ [morph-spec] Gate 3 de "${featureName}" aprovado SEM os relatórios de review independentes (verifier.md, reviewer.md) — ` +
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# morph-spec statusline — installed globally to ~/.claude/statusline.sh
|
|
3
|
-
# Claude Code invokes this with JSON via stdin after each response.
|
|
4
|
-
# Requires: Python 3 available as `python3` or `python` on PATH.
|
|
5
|
-
|
|
6
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
7
|
-
if command -v python3 &>/dev/null; then
|
|
8
|
-
python3 "${SCRIPT_DIR}/statusline.py" 2>/dev/null || true
|
|
9
|
-
elif command -v python &>/dev/null; then
|
|
10
|
-
python "${SCRIPT_DIR}/statusline.py" 2>/dev/null || true
|
|
11
|
-
fi
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# morph-spec statusline — installed globally to ~/.claude/statusline.sh
|
|
3
|
+
# Claude Code invokes this with JSON via stdin after each response.
|
|
4
|
+
# Requires: Python 3 available as `python3` or `python` on PATH.
|
|
5
|
+
|
|
6
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
7
|
+
if command -v python3 &>/dev/null; then
|
|
8
|
+
python3 "${SCRIPT_DIR}/statusline.py" 2>/dev/null || true
|
|
9
|
+
elif command -v python &>/dev/null; then
|
|
10
|
+
python "${SCRIPT_DIR}/statusline.py" 2>/dev/null || true
|
|
11
|
+
fi
|
|
@@ -15,7 +15,7 @@ stacks:
|
|
|
15
15
|
- **frontend-nextjs-data-fetching** (`frontend/nextjs/data-fetching.md`) — Server Component com `BACKEND_API_PREFIX`; Client Component só pelo proxy same-origin com `PROXY_API_PREFIX`. TanStack Query 5 com key factory por feature e `invalidateQueries({ queryKey })`; toda resposta passa por Zod. PROIBIDO: `useEffect(() => fetch…)` e paginar/filtrar a coleção inteira no browser.
|
|
16
16
|
- **frontend-nextjs-forms** (`frontend/nextjs/forms.md`) — react-hook-form + Zod (`zodResolver`) + Field do shadcn via `Controller`; tipo por `z.infer`; nunca `useState` por campo. Submit por `useMutation`, erro em `root`. Edição reusa o schema de criação (`.partial()`). Zod 4: `z.email()`.
|
|
17
17
|
- **frontend-nextjs-state-management** (`frontend/nextjs/state-management.md`) — Estado de servidor no TanStack Query, nunca copiado para `useState`. Página, ordenação, filtros e aba ativa na URL (`searchParams`). Context só para tema, usuário ou locale. NUNCA Zustand/Redux antes de esgotar Server Components + TanStack Query.
|
|
18
|
-
- **frontend-nextjs-testing** (`frontend/nextjs/testing.md`) — Vitest + Testing Library; MSW para API; Playwright para e2e. Teste comportamento, não implementação. Orçamento: um teste por
|
|
18
|
+
- **frontend-nextjs-testing** (`frontend/nextjs/testing.md`) — Vitest + Testing Library; MSW para API; Playwright para e2e. Teste comportamento, não implementação. Orçamento por risco: um teste por cenário com `risco:` + o de regressão do bug, componente sem risco é `leitura`/`e2e`; cenários do mesmo comportamento em `it.each`; nada de teste que só confere string de copy.
|
|
19
19
|
- **frontend-nextjs-nextjs-patterns** (`frontend/nextjs/nextjs-patterns.md`) — Route Handler é BFF: `auth.getSession()` (401 sem sessão) e delega ao .NET; banco NUNCA em route handler. Zod no client e no server (`safeParse`, 400). `strict: true` + `noUncheckedIndexedAccess`; sem `any` em resposta de API. shadcn via `npx shadcn@latest add`.
|
|
20
20
|
- **frontend-nextjs-motion-patterns** (`frontend/nextjs/motion-patterns.md`) — Motion via `motion/react` (nunca `framer-motion` junto). Variants em `motion/variants.ts` com durations/easings de `@/lib/design-tokens`. `useReducedMotion()` obrigatório; o `layout.tsx` raiz segue Server Component. 3–5 momentos de motion por página; cena guiada por scroll é do GSAP, nunca no mesmo elemento.
|
|
21
21
|
- **architecture-code-comments** (`architecture/code-comments.md`) — Padrão é nenhum comentário: renomeie, extraia, tipe ou teste antes. Só o porquê que o código não mostra (invariante, ordem, quirk externo com link), até ~3 linhas. PROIBIDO: história de processo (task, UC, ADR, Gate), repetir o código, XML doc/JSDoc que repete a assinatura, banner, `#region`, código comentado, TODO solto. O hook `comment-guard` bloqueia.
|
|
@@ -4,7 +4,7 @@ description: Guia a criação de uma landing page nova ponta-a-ponta a partir do
|
|
|
4
4
|
version: core
|
|
5
5
|
when_to_use: Use quando for iniciar um novo projeto de LP com o template Umbraco genérico
|
|
6
6
|
user-invocable: true
|
|
7
|
-
cliVersion: "9.
|
|
7
|
+
cliVersion: "9.2.0"
|
|
8
8
|
stacks:
|
|
9
9
|
- umbraco
|
|
10
10
|
---
|
|
@@ -4,7 +4,7 @@ description: Migra uma landing page existente (React/Vite, Next.js estático ou
|
|
|
4
4
|
version: core
|
|
5
5
|
when_to_use: Use quando o usuário pedir "use /migrate-lp-to-umbraco {projeto}" ou descrever a necessidade de migrar uma LP para Umbraco
|
|
6
6
|
user-invocable: true
|
|
7
|
-
cliVersion: "9.
|
|
7
|
+
cliVersion: "9.2.0"
|
|
8
8
|
stacks:
|
|
9
9
|
- umbraco
|
|
10
10
|
---
|
|
@@ -4,7 +4,7 @@ description: Executa as fatias do plano de uma feature morph-spec — dispatch p
|
|
|
4
4
|
version: core
|
|
5
5
|
when_to_use: Use com o gate do plano aprovado, em "use /morph-apply {feature}" ou "implementar feature"
|
|
6
6
|
user-invocable: true
|
|
7
|
-
cliVersion: "9.
|
|
7
|
+
cliVersion: "9.2.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-apply
|
|
@@ -78,7 +78,7 @@ relatório) está no corpo da persona gerada e chega a todo dispatch sem ser col
|
|
|
78
78
|
```
|
|
79
79
|
dispatch Agent (subagent_type: "morph-{id}") with prompt:
|
|
80
80
|
Fatia F{n} — <título>
|
|
81
|
-
cobre: <cada Cn com o texto literal do cenário e
|
|
81
|
+
cobre: <cada Cn com o texto literal do cenário, a `prova:` e o `risco:`>
|
|
82
82
|
arquivos: <os `arquivos:` da fatia>
|
|
83
83
|
standards: <por id: o digest de `morph-spec standards --find` + as 3-8 regras que ESTA fatia aplica>
|
|
84
84
|
reuso: <as linhas de `## Reuso` que tocam a fatia — conceito, veredito, alvo>
|
|
@@ -128,7 +128,7 @@ config **antes** do verify: o stamp grava o HEAD, e código ou `config.json` com
|
|
|
128
128
|
|
|
129
129
|
Depois `morph-spec verify {feature} --json`, **sem filtro** — nunca recorte o
|
|
130
130
|
verify da feature. `--filter` é do loop do próprio sub-agente; o Gate 3 e o CI rodam a suíte
|
|
131
|
-
inteira. Nó de teste sem `expectedCount
|
|
131
|
+
inteira. Nó de teste sem `expectedCount`, ou fatia que apagou teste de propósito (limpeza, `morph-spec tests-audit`): acrescente `--record-baseline` a ESTA rodada — ela mede e
|
|
132
132
|
prova de uma vez; nunca um segundo verify só para gravar a baseline. Vermelho: corrija com `verify.feedback` (direto no código, ou re-despachando a fatia dona)
|
|
133
133
|
e rode de novo; **3 tentativas** sem verde → `AskUserQuestion` ("Verify de {feature} vermelho após 3
|
|
134
134
|
tentativas — aceitar com ressalva, continuar tentando, ou parar?").
|
|
@@ -4,7 +4,7 @@ description: ADW cirúrgico de hotfix — resolve uma queda/bug crítico de prod
|
|
|
4
4
|
version: core
|
|
5
5
|
when_to_use: Use quando chegar "/morph-hotfix {feature}", quando a morph-plan rotear o pedido como workType hotfix, ou quando o usuário disser "produção caiu / hotfix / urgente" a respeito de um incidente
|
|
6
6
|
user-invocable: true
|
|
7
|
-
cliVersion: "9.
|
|
7
|
+
cliVersion: "9.2.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-hotfix
|
|
@@ -53,8 +53,8 @@ Escreva o `plan.md` mínimo (~25 linhas) numa única escrita: o hotfix nasce com
|
|
|
53
53
|
|
|
54
54
|
- `## Problema` — o sintoma em produção, o root cause que o scout localizou e o blast radius.
|
|
55
55
|
- `## Cenários` — dois, sempre:
|
|
56
|
-
- **C1** — o sintoma ausente: dado o estado que quebrava, quando a ação que falhava, então o resultado certo. `prova: teste` (ou `e2e`).
|
|
57
|
-
- **C2** —
|
|
56
|
+
- **C1** — o sintoma ausente: dado o estado que quebrava, quando a ação que falhava, então o resultado certo. `prova: teste` (ou `e2e`) e `risco: regressão` — o teste do bug real, o único que o hotfix escreve; o `plan-check` recusa o plano sem ele.
|
|
57
|
+
- **C2** — o blast radius: o que o fix poderia quebrar continua funcionando. `prova: leitura` (o caminho tocado, citado por `arquivo:linha`) ou um teste existente que já o cobre — nunca um teste novo.
|
|
58
58
|
- `## Decisões` com `### Conflitos com o acervo` (`nenhum` vale).
|
|
59
59
|
- `## Fatias` — uma, `### F1 — fix`, com `persona:`, `arquivos:` e `cobre: C1, C2`.
|
|
60
60
|
|
|
@@ -4,7 +4,7 @@ description: Cuida da RAM e da CPU da máquina enquanto o morph-spec trabalha
|
|
|
4
4
|
version: core
|
|
5
5
|
when_to_use: Use quando a máquina estiver lenta ou sem RAM, um comando pesado esperou ou foi recusado pela fila, sobrou worktree de sub-agent, ou vários sub-agents pesados vão rodar em paralelo
|
|
6
6
|
user-invocable: false
|
|
7
|
-
cliVersion: "9.
|
|
7
|
+
cliVersion: "9.2.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-machine
|