@polymorphism-tech/morph-spec 8.43.0 → 8.45.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/CLAUDE.md +16 -13
- package/README.md +10 -10
- package/bin/morph-spec.js +10 -13
- package/bin/validate.js +379 -379
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +2 -4
- package/docs/QUICKSTART.md +6 -6
- package/framework/CLAUDE.md +6 -8
- package/framework/MORPH.md +39 -45
- package/framework/agents.json +8 -9
- package/framework/commands/morph-apply.md +1 -3
- package/framework/commands/morph-hotfix.md +1 -1
- package/framework/commands/morph-proposal.md +2 -2
- package/framework/docs/CLI.md +22 -17
- package/framework/evals/review-checklist.md +90 -0
- package/framework/evals/trace-schema.md +2 -12
- package/framework/hooks/README.md +2 -3
- package/framework/hooks/claude-code/core/heavy-gate.js +1 -1
- package/framework/hooks/claude-code/core/protect-spec-files.js +2 -2
- package/framework/hooks/claude-code/core/telemetry-log.js +2 -2
- package/framework/hooks/claude-code/core/trace-autogen.js +1 -22
- package/framework/hooks/claude-code/core/validate-completion.js +3 -56
- package/framework/hooks/claude-code/core/worktree-env-inject.js +1 -4
- package/framework/hooks/claude-code/statusline.sh +11 -11
- package/framework/hooks/git/commit-msg/conventional-commits.sh +33 -33
- package/framework/hooks/git/pre-commit/agents.sh +25 -25
- package/framework/hooks/git/pre-commit/orchestrator.sh +64 -64
- package/framework/hooks/git/pre-commit/specs.sh +50 -50
- package/framework/hooks/git/pre-push/run-tests.sh +44 -44
- package/framework/hooks/shared/build-check.js +1 -1
- package/framework/hooks/shared/comment-scanner.js +1 -1
- package/framework/hooks/shared/phase-utils.js +0 -5
- package/framework/hooks/shared/stdin-reader.js +26 -26
- package/framework/phases.json +4 -6
- package/framework/rubrics/backend.json +1 -1
- package/framework/rubrics/default.json +1 -1
- package/framework/rubrics/frontend.json +1 -1
- package/framework/rules/ai-agents-standards.md +1 -0
- package/framework/rules/morph-workflow.md +6 -6
- package/framework/schemas/feature.schema.json +2 -28
- package/framework/schemas/tasks.schema.json +6 -2
- package/framework/skills/README.md +1 -2
- 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 +145 -246
- package/framework/skills/core/morph-brainstorming/SKILL.md +1 -1
- package/framework/skills/core/morph-hotfix/SKILL.md +5 -3
- package/framework/skills/core/morph-implement/SKILL.md +101 -201
- package/framework/skills/core/morph-machine/SKILL.md +3 -3
- package/framework/skills/core/morph-media/SKILL.md +1 -1
- package/framework/skills/core/morph-plan/SKILL.md +171 -287
- package/framework/skills/core/morph-proposal/SKILL.md +4 -5
- package/framework/skills/core/morph-review/SKILL.md +109 -430
- package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
- package/framework/skills/core/morph-standards/SKILL.md +2 -2
- package/framework/skills/core/morph-uiux/SKILL.md +2 -3
- package/framework/standards/STANDARDS.json +54 -10
- package/framework/standards/ai-agents/agent-archetypes.md +1 -1
- package/framework/standards/ai-agents/agent-session.md +1 -1
- package/framework/standards/ai-agents/agent-spec.md +1 -1
- package/framework/standards/ai-agents/batching.md +1 -1
- package/framework/standards/ai-agents/context-providers.md +1 -1
- package/framework/standards/ai-agents/conversational-agent-with-phases.md +1 -1
- package/framework/standards/ai-agents/cost-and-budget.md +1 -1
- package/framework/standards/ai-agents/durable-workflows-hitl.md +1 -1
- package/framework/standards/ai-agents/guardrails.md +1 -1
- package/framework/standards/ai-agents/llm-runtime-defaults.md +1 -1
- package/framework/standards/ai-agents/mcp-server.md +1 -1
- package/framework/standards/ai-agents/mcp-tools.md +1 -1
- package/framework/standards/ai-agents/media-pipeline.md +1 -1
- package/framework/standards/ai-agents/media-video.md +1 -1
- package/framework/standards/ai-agents/middleware-patterns.md +1 -1
- package/framework/standards/ai-agents/modalities-image-gen.md +1 -1
- package/framework/standards/ai-agents/modalities-speech-to-text.md +1 -1
- package/framework/standards/ai-agents/modalities-text-to-speech.md +1 -1
- package/framework/standards/ai-agents/modalities-vision.md +1 -1
- package/framework/standards/ai-agents/multi-agent-patterns.md +1 -1
- package/framework/standards/ai-agents/observability-patterns.md +3 -3
- package/framework/standards/ai-agents/production.md +2 -2
- package/framework/standards/ai-agents/prompt-sources.md +1 -1
- package/framework/standards/ai-agents/providers/model-registry.md +1 -1
- package/framework/standards/ai-agents/rag-custom-pgvector.md +1 -1
- package/framework/standards/ai-agents/service-tier-flex.md +1 -1
- package/framework/standards/ai-agents/setup.md +1 -1
- package/framework/standards/ai-agents/structured-output.md +1 -1
- package/framework/standards/ai-agents/sweet-spot.md +1 -1
- package/framework/standards/ai-agents/testing-ai.md +1 -1
- package/framework/standards/ai-agents/tool-adapters.md +226 -0
- package/framework/standards/ai-agents/vector-data-extensions.md +1 -1
- package/framework/standards/ai-agents/workflows.md +1 -1
- package/framework/standards/infrastructure/docker/local-compose-isolation.md +11 -1
- package/framework/templates/CLAUDE.md.core.template +1 -1
- package/framework/templates/IDE-SNIPPETS.md +262 -262
- package/framework/templates/README.md +1 -1
- package/framework/templates/REGISTRY.json +0 -81
- package/framework/templates/code/dotnet/abstractions/api-endpoint.cs +7 -7
- package/framework/templates/code/dotnet/feature/endpoint.cs.hbs +21 -21
- 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/spec.md +19 -205
- package/framework/templates/docs/ui-components.md +52 -52
- package/framework/templates/docs/ui-design-system.md +76 -76
- package/framework/templates/docs/ui-flows.md +167 -167
- 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/README.md +56 -56
- 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/meta-prompts/validators/pre-commit-validator.md +95 -95
- package/framework/templates/state.template.json +17 -17
- package/framework/templates/ui/design-system.css +226 -226
- package/package.json +2 -2
- package/src/commands/e2e/e2e.js +1 -1
- package/src/commands/project/heavy.js +1 -1
- package/src/commands/project/status.js +3 -3
- package/src/commands/project/worktree.js +34 -16
- package/src/commands/state/approve.js +9 -50
- package/src/commands/state/finish.js +4 -0
- package/src/commands/state/gate-check.js +18 -107
- package/src/commands/state/gate-decision.js +1 -1
- package/src/commands/state/report-check.js +42 -17
- package/src/commands/validation/mutate.js +1 -1
- package/src/commands/validation/scout-check.js +28 -0
- package/src/commands/validation/validate-feature.js +5 -32
- package/src/commands/validation/verify.js +16 -25
- package/src/core/paths/output-schema.js +0 -2
- package/src/core/state/state-manager.js +1 -2
- package/src/core/templates/template-renderer.js +477 -477
- package/src/dashboard/app/lib/format.js +5 -0
- package/src/dashboard/app/main.jsx +13 -13
- package/src/dashboard/app/pages/FeatureDetail.jsx +16 -22
- package/src/dashboard/app/pages/Features.jsx +7 -7
- package/src/dashboard/app/pages/PhasePipeline.jsx +1 -1
- package/src/dashboard/app/pages/Rubrics.jsx +7 -11
- package/src/dashboard/scanner/docs-scanner.js +1 -2
- package/src/dashboard/scanner/features-scanner.js +3 -4
- package/src/dashboard/scanner/rubrics-scanner.js +12 -12
- package/src/dashboard/vite.config.js +24 -24
- package/src/lib/agents/output-collector.js +0 -1
- package/src/lib/detectors/design-system-detector.js +188 -188
- package/src/lib/e2e/compose-env.js +5 -2
- package/src/lib/evaluator-report.js +52 -334
- package/src/lib/generators/design-system-generator.js +508 -508
- package/src/lib/generators/handoff-generator.js +4 -5
- package/src/lib/git/evidence-staleness.js +39 -0
- package/src/lib/installers/memory-installer.js +2 -2
- package/src/lib/mutation/manifest.js +8 -2
- package/src/lib/mutation/report.js +5 -3
- package/src/lib/mutation/runner.js +9 -7
- package/src/lib/risk-detector.js +63 -125
- package/src/lib/scout/scout-check.js +293 -0
- package/src/lib/tasks/eval-node.js +4 -34
- package/src/lib/tasks/task-classifier.js +30 -30
- package/src/lib/tasks/task-parser.js +209 -209
- package/src/lib/tasks/tasks-json-parser.js +7 -5
- package/src/lib/tasks/test-nodes.js +1 -1
- package/src/lib/tasks/test-runner.js +1 -1
- package/src/lib/validators/contracts/contract-compliance-validator.js +4 -42
- package/src/lib/validators/css/css-validator.js +340 -340
- package/src/lib/validators/reuse/reuse-validator.js +6 -8
- package/src/lib/validators/verify-runner.js +1 -1
- package/src/lib/worktree/env-allocator.js +35 -5
- package/src/scripts/setup-infra.js +1 -1
- package/src/utils/agent-id-mapper.js +11 -11
- package/src/utils/agents-installer.js +5 -9
- package/src/utils/claude-settings-manager.js +300 -300
- package/src/utils/hooks-installer.js +3 -10
- package/src/utils/skills-installer.js +1 -1
- package/framework/evals/proof-rubrics/README.md +0 -76
- package/framework/evals/proof-rubrics/eval-de-modelo.md +0 -80
- package/framework/evals/proof-rubrics/fiacao.md +0 -54
- package/framework/evals/proof-rubrics/guard-cego.md +0 -52
- package/framework/evals/proof-rubrics/media-claims.md +0 -109
- package/framework/evals/proof-rubrics/mutation-proof.md +0 -107
- package/framework/evals/proof-rubrics/observabilidade-genai.md +0 -119
- package/framework/evals/proof-rubrics/verde-nao-e-coberto.md +0 -48
- package/framework/evals/rubrics/README.md +0 -45
- package/framework/evals/rubrics/architecture.md +0 -103
- package/framework/evals/rubrics/code-quality.md +0 -98
- package/framework/evals/rubrics/condensed.md +0 -57
- package/framework/evals/rubrics/contracts.md +0 -67
- package/framework/evals/rubrics/test-coverage.md +0 -99
- package/framework/evals/scenarios/dotnet-crud.yaml +0 -42
- package/framework/evals/scenarios/nextjs-auth.yaml +0 -38
- package/framework/evals/suites/standard.yaml +0 -5
- package/framework/hooks/claude-code/core/post-edit-typecheck.js +0 -127
- package/framework/skills/core/morph-eval/SKILL.md +0 -64
- package/framework/templates/.idea/morph-templates.xml +0 -92
- package/framework/templates/.vscode/morph-templates.code-snippets +0 -186
- package/framework/templates/docs/clarifications.md +0 -253
- package/framework/templates/docs/onboarding.md +0 -122
- package/framework/templates/docs/schema-analysis.md +0 -119
- package/framework/templates/docs/user-stories.md +0 -34
- package/src/commands/state/score.js +0 -147
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* PostToolUse Hook: TypeScript typecheck with debounce + build-dirty flag
|
|
5
|
-
*
|
|
6
|
-
* Event: PostToolUse | Matcher: Write|Edit
|
|
7
|
-
*
|
|
8
|
-
* Runs `npx tsc --noEmit` only for .ts/.tsx files, with a 3-second debounce
|
|
9
|
-
* so rapid sequential edits (e.g. multiple files in one task) don't each
|
|
10
|
-
* trigger a full typecheck. Silent on success — only injects on error.
|
|
11
|
-
*
|
|
12
|
-
* Also touches `.morph/memory/build-dirty.json` on EVERY Write/Edit of a
|
|
13
|
-
* source file (any extension build-check.js knows how to verify — dotnet .cs
|
|
14
|
-
* included, not just TS), even when the tsc check below is skipped/debounced.
|
|
15
|
-
* validate-completion.js (Stop hook) only runs its full build/typecheck when
|
|
16
|
-
* this flag is present — this is the write side of that dirty-flag gate
|
|
17
|
-
* (R1.2 of the performance plan).
|
|
18
|
-
*
|
|
19
|
-
* Debounce state: .morph/memory/typecheck-debounce.json
|
|
20
|
-
*
|
|
21
|
-
* Fail-open: exits 0 on any error.
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
import { execSync } from 'child_process';
|
|
25
|
-
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';
|
|
26
|
-
import { join } from 'path';
|
|
27
|
-
import { contextResult, runStandalone } from '../../shared/hook-response.js';
|
|
28
|
-
import { stateExists } from '../../shared/state-reader.js';
|
|
29
|
-
import { resolveRootForFile } from '../../shared/payload-utils.js';
|
|
30
|
-
|
|
31
|
-
const DEBOUNCE_MS = 3000;
|
|
32
|
-
const TSC_TIMEOUT_MS = 30000;
|
|
33
|
-
|
|
34
|
-
// Extensions build-check.js knows how to verify (dotnet .cs + the frontend
|
|
35
|
-
// TS/JS family) — broader than the `/\.tsx?$/` gate below on purpose: editing
|
|
36
|
-
// a .cs file never runs tsc here, but it DOES need the next Stop's
|
|
37
|
-
// `dotnet build` to run.
|
|
38
|
-
const SOURCE_FILE_RE = /\.(cs|ts|tsx|js|jsx|mjs|cjs|vue|razor|cshtml)$/i;
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Mark the build dirty for validate-completion.js's Stop-hook gate.
|
|
42
|
-
* Cheap, best-effort — never blocks, never throws.
|
|
43
|
-
*
|
|
44
|
-
* @param {string} morphRoot - the root whose `.morph/` the Stop hook itself
|
|
45
|
-
* reads (resolved by the `.morph` marker, NOT the tsc/package.json root —
|
|
46
|
-
* they can differ in a monorepo, e.g. editing `frontend/src/Foo.tsx` walks
|
|
47
|
-
* up to `frontend/` for tsc but `.morph/` still lives at the repo root).
|
|
48
|
-
*/
|
|
49
|
-
function markBuildDirty(morphRoot) {
|
|
50
|
-
try {
|
|
51
|
-
const memDir = join(morphRoot, '.morph', 'memory');
|
|
52
|
-
mkdirSync(memDir, { recursive: true });
|
|
53
|
-
writeFileSync(join(memDir, 'build-dirty.json'), JSON.stringify({ ts: new Date().toISOString() }), 'utf-8');
|
|
54
|
-
} catch { /* non-blocking */ }
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* @param {object} payload - parsed PostToolUse stdin payload (Write|Edit)
|
|
59
|
-
* @returns {Promise<object|null>} a hookSpecificOutput context object on a
|
|
60
|
-
* typecheck failure, or null (pass/silent). Never prints, never exits —
|
|
61
|
-
* see runStandalone()/chain.js at the bottom.
|
|
62
|
-
*/
|
|
63
|
-
export async function run(payload) {
|
|
64
|
-
try {
|
|
65
|
-
if (!stateExists()) return null;
|
|
66
|
-
|
|
67
|
-
const toolName = payload?.tool_name || '';
|
|
68
|
-
const filePath = payload?.tool_input?.file_path || payload?.tool_input?.path || '';
|
|
69
|
-
|
|
70
|
-
if (!['Write', 'Edit'].includes(toolName)) return null;
|
|
71
|
-
|
|
72
|
-
// Dirty-flag: resolved against the nearest ancestor that HAS a `.morph/`
|
|
73
|
-
// dir — the same root validate-completion.js reads from `process.cwd()`.
|
|
74
|
-
// This is deliberately independent of the tsc root below: a monorepo's
|
|
75
|
-
// `frontend/package.json` would otherwise make the flag land under
|
|
76
|
-
// `frontend/.morph/`, where the Stop hook (running from the repo root)
|
|
77
|
-
// never looks — a silently-dark guardrail.
|
|
78
|
-
const morphRoot = resolveRootForFile(filePath, process.cwd(), ['.morph']);
|
|
79
|
-
if (SOURCE_FILE_RE.test(filePath)) markBuildDirty(morphRoot);
|
|
80
|
-
|
|
81
|
-
if (!filePath.match(/\.tsx?$/)) return null;
|
|
82
|
-
|
|
83
|
-
// Resolve the root that OWNS the edited file — when a subagent edits inside
|
|
84
|
-
// its own git worktree (isolation: "worktree", §3b-w), tsc must run there,
|
|
85
|
-
// not in the main working tree. Falls back to cwd for the normal case.
|
|
86
|
-
const root = resolveRootForFile(filePath, process.cwd());
|
|
87
|
-
|
|
88
|
-
// No node_modules under the resolved root → tsc can't run; pass silently
|
|
89
|
-
// (a fresh worktree before `morph-spec worktree link` has no node_modules).
|
|
90
|
-
if (!existsSync(join(root, 'node_modules'))) return null;
|
|
91
|
-
|
|
92
|
-
// Debounce (keyed by root): skip if a typecheck ran within the last 3s.
|
|
93
|
-
const memDir = join(root, '.morph', 'memory');
|
|
94
|
-
const debouncePath = join(memDir, 'typecheck-debounce.json');
|
|
95
|
-
|
|
96
|
-
try {
|
|
97
|
-
if (existsSync(debouncePath)) {
|
|
98
|
-
const { lastRun } = JSON.parse(readFileSync(debouncePath, 'utf-8'));
|
|
99
|
-
if (Date.now() - new Date(lastRun).getTime() < DEBOUNCE_MS) return null;
|
|
100
|
-
}
|
|
101
|
-
} catch { /* corrupt file — proceed */ }
|
|
102
|
-
|
|
103
|
-
try {
|
|
104
|
-
mkdirSync(memDir, { recursive: true });
|
|
105
|
-
writeFileSync(debouncePath, JSON.stringify({ lastRun: new Date().toISOString() }), 'utf-8');
|
|
106
|
-
} catch { /* non-blocking */ }
|
|
107
|
-
|
|
108
|
-
try {
|
|
109
|
-
execSync('npx tsc --noEmit', { cwd: root, stdio: 'pipe', timeout: TSC_TIMEOUT_MS });
|
|
110
|
-
return null;
|
|
111
|
-
} catch (err) {
|
|
112
|
-
const stderr = err.stderr?.toString() || '';
|
|
113
|
-
const stdout = err.stdout?.toString() || '';
|
|
114
|
-
const output = (stderr + stdout).trim();
|
|
115
|
-
const fileName = filePath.split(/[\\/]/).pop();
|
|
116
|
-
const relevant = output.split('\n')
|
|
117
|
-
.filter(l => l.includes(fileName) || l.includes('error TS'))
|
|
118
|
-
.slice(0, 10)
|
|
119
|
-
.join('\n');
|
|
120
|
-
return contextResult(`TypeScript errors after editing ${fileName}:\n${relevant || output.split('\n').slice(0, 10).join('\n')}`, 'PostToolUse');
|
|
121
|
-
}
|
|
122
|
-
} catch {
|
|
123
|
-
return null;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
await runStandalone(run);
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: morph-eval
|
|
3
|
-
description: Avalia a qualidade de uma tarefa ou fase com rubricas graduadas 0-10
|
|
4
|
-
version: core
|
|
5
|
-
when-to-invoke: ao completar uma tarefa ou ao finalizar uma fase de implementação
|
|
6
|
-
user-invokable: false
|
|
7
|
-
cliVersion: "8.43.0"
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
# morph-eval
|
|
11
|
-
|
|
12
|
-
## Objetivo
|
|
13
|
-
Produzir um score 0-10 por dimensão e uma ação clara baseada no score.
|
|
14
|
-
O objetivo não é punir — é identificar o que melhorar antes de seguir adiante.
|
|
15
|
-
|
|
16
|
-
## Quando invocar
|
|
17
|
-
Após concluir uma tarefa ou ao finalizar a fase de implementação.
|
|
18
|
-
Também invocado ao receber o retorno de um sub-agent com auto-score < 7.
|
|
19
|
-
|
|
20
|
-
**Somente após `morph-spec verify {feature} {task}` verde** (a `morph-apply` garante isso no loop §3a). O verify é a barreira determinística (build+testes+validadores); esta skill julga o que o código não pega: arquitetura, contratos, qualidade, cobertura qualitativa.
|
|
21
|
-
|
|
22
|
-
> **Escopo de fase (Gate 3):** a avaliação da feature inteira NÃO é feita por quem implementou — a `morph-review` despacha a persona `evaluator` de `agents.json` (contexto fresco, sem autoria; recebe mandate + diff + saída real dos testes) usando esta skill como guia, **sempre com as 4 rubricas completas** — nunca a condensada, que é exclusiva do eval inline por task. O eval por task pode ser inline; o score composto do Gate 3 vem sempre do avaliador independente, com a régua completa.
|
|
23
|
-
|
|
24
|
-
## O que fazer
|
|
25
|
-
|
|
26
|
-
0. Confirme que o `morph-spec verify` da task está verde (a morph-apply passa o resultado; numa invocação manual, rode `morph-spec verify {feature} {task} --json`). Se estiver vermelho, NÃO avalie — devolva o `feedback[]` do verify ao loop de correção.
|
|
27
|
-
|
|
28
|
-
1. Identifique o escopo da avaliação: tarefa única (eval inline) ou fase completa (Gate 3).
|
|
29
|
-
|
|
30
|
-
2. Leia a rubrica correspondente ao escopo:
|
|
31
|
-
- **Tarefa única (eval inline, o caso comum):** leia SÓ `.morph/framework/evals/rubrics/condensed.md` — tabela única com as 4 dimensões e seus pesos, condensada das completas. Não abra as 4 rubricas completas para esse escopo; a condensada é fiel a elas (dimensões e pesos idênticos, enforced por `scripts/check-rubric-parity.js`).
|
|
32
|
-
- **Fase completa (Gate 3):** o avaliador independente despachado pela `morph-review` (persona `evaluator`, contexto fresco) usa **sempre** as 4 rubricas completas — a régua do juiz de Gate 3 não muda:
|
|
33
|
-
- `architecture.md` — peso 30% — vertical slice, separação de responsabilidades, infra
|
|
34
|
-
- `contracts.md` — peso 25% — tipos, validação, tratamento de erros, naming
|
|
35
|
-
- `code-quality.md` — peso 25% — naming, ausência de code smells, padrões do stack
|
|
36
|
-
- `test-coverage.md` — peso 20% — happy path, edge cases, isolamento, naming de testes
|
|
37
|
-
|
|
38
|
-
3. Atribua um score de 1 a 10 para cada dimensão seguindo as bandas da rubrica (condensada ou completa, conforme o passo 2).
|
|
39
|
-
|
|
40
|
-
4. Calcule o score composto: (arch × 0.30) + (contracts × 0.25) + (quality × 0.25) + (tests × 0.20).
|
|
41
|
-
|
|
42
|
-
5. Aja conforme o score composto:
|
|
43
|
-
- **9-10:** Aprovado — nenhuma saída necessária no contexto, a task avança.
|
|
44
|
-
- **< 9:** Produza **feedback priorizado** (bloqueantes primeiro) — este feedback é a entrada do loop de correção autônomo da `morph-apply`: ela re-invoca `morph-implement` passando esse feedback para a próxima tentativa. NÃO escale ao humano aqui; a escalada só acontece quando o loop esgota 3 tentativas sem atingir 9. O feedback deve ser acionável (o que corrigir, onde), não só descritivo.
|
|
45
|
-
|
|
46
|
-
6. Registre o score no recap.md da tarefa avaliada.
|
|
47
|
-
|
|
48
|
-
7. **NÃO escreva o trace manualmente.** O arquivo `.morph/traces/YYYY-MM-DD-{feature}-implement.json` é gerado automaticamente pelo hook `trace-autogen` a cada write de `tasks.json`, lendo `eval_score`/`eval_dimensions` do registro `taskScores` do feature.json. Garanta apenas que o score foi persistido via `morph-spec score {feature} {task} {score} --dims {a},{c},{q},{t}` (a `morph-apply` faz esse registro no loop) — é dali que o trace lê.
|
|
49
|
-
|
|
50
|
-
## Output esperado
|
|
51
|
-
- Score composto 0-10 com scores por dimensão
|
|
52
|
-
- Ação tomada com base no score (aprovado em >=9 / feedback acionável para o loop em <9)
|
|
53
|
-
- Entrada no recap.md com scores
|
|
54
|
-
- Score persistido em `taskScores` via `morph-spec score` (o trace é gerado automaticamente pelo hook `trace-autogen`)
|
|
55
|
-
|
|
56
|
-
## Referências
|
|
57
|
-
- `morph-spec verify {feature} [task] --json` — barreira determinística (build+testes+validadores) que precede esta skill
|
|
58
|
-
- `.morph/framework/evals/rubrics/condensed.md` — rubrica condensada (4 dimensões + pesos), usada no eval INLINE por task
|
|
59
|
-
- `.morph/framework/evals/rubrics/architecture.md` — rubrica completa de arquitetura (30%) — Gate 3, avaliador independente
|
|
60
|
-
- `.morph/framework/evals/rubrics/contracts.md` — rubrica completa de contratos (25%) — Gate 3, avaliador independente
|
|
61
|
-
- `.morph/framework/evals/rubrics/code-quality.md` — rubrica completa de qualidade (25%) — Gate 3, avaliador independente
|
|
62
|
-
- `.morph/framework/evals/rubrics/test-coverage.md` — rubrica completa de cobertura (20%) — Gate 3, avaliador independente
|
|
63
|
-
- `.morph/framework/evals/trace-schema.md` — formato canônico do trace
|
|
64
|
-
- `.morph/framework/MORPH.md` — seção 1 (papel Evaluator)
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
<templateSet group="MORPH Templates">
|
|
2
|
-
<template name="morph-pascal" value="{{pascalCase $FEATURE_NAME$}}" description="Convert to PascalCase (UserAuth)" toReformat="false" toShortenFQNames="true">
|
|
3
|
-
<variable name="FEATURE_NAME" expression="" defaultValue=""FEATURE_NAME"" alwaysStopAt="true" />
|
|
4
|
-
<context>
|
|
5
|
-
<option name="OTHER" value="true" />
|
|
6
|
-
</context>
|
|
7
|
-
</template>
|
|
8
|
-
|
|
9
|
-
<template name="morph-camel" value="{{camelCase $FEATURE_NAME$}}" description="Convert to camelCase (userAuth)" toReformat="false" toShortenFQNames="true">
|
|
10
|
-
<variable name="FEATURE_NAME" expression="" defaultValue=""FEATURE_NAME"" alwaysStopAt="true" />
|
|
11
|
-
<context>
|
|
12
|
-
<option name="OTHER" value="true" />
|
|
13
|
-
</context>
|
|
14
|
-
</template>
|
|
15
|
-
|
|
16
|
-
<template name="morph-snake" value="{{snakeCase $FEATURE_NAME$}}" description="Convert to snake_case (user_auth)" toReformat="false" toShortenFQNames="true">
|
|
17
|
-
<variable name="FEATURE_NAME" expression="" defaultValue=""FEATURE_NAME"" alwaysStopAt="true" />
|
|
18
|
-
<context>
|
|
19
|
-
<option name="OTHER" value="true" />
|
|
20
|
-
</context>
|
|
21
|
-
</template>
|
|
22
|
-
|
|
23
|
-
<template name="morph-title" value="{{titleCase $FEATURE_NAME$}}" description="Convert to Title Case (User Auth)" toReformat="false" toShortenFQNames="true">
|
|
24
|
-
<variable name="FEATURE_NAME" expression="" defaultValue=""FEATURE_NAME"" alwaysStopAt="true" />
|
|
25
|
-
<context>
|
|
26
|
-
<option name="OTHER" value="true" />
|
|
27
|
-
</context>
|
|
28
|
-
</template>
|
|
29
|
-
|
|
30
|
-
<template name="morph-kebab" value="{{kebabCase $FEATURE_NAME$}}" description="Convert to kebab-case (user-auth)" toReformat="false" toShortenFQNames="true">
|
|
31
|
-
<variable name="FEATURE_NAME" expression="" defaultValue=""FEATURE_NAME"" alwaysStopAt="true" />
|
|
32
|
-
<context>
|
|
33
|
-
<option name="OTHER" value="true" />
|
|
34
|
-
</context>
|
|
35
|
-
</template>
|
|
36
|
-
|
|
37
|
-
<template name="morph-if" value="{{#if $CONDITION$}} $END$ {{/if}}" description="Handlebars if block" toReformat="false" toShortenFQNames="true">
|
|
38
|
-
<variable name="CONDITION" expression="" defaultValue=""condition"" alwaysStopAt="true" />
|
|
39
|
-
<context>
|
|
40
|
-
<option name="OTHER" value="true" />
|
|
41
|
-
</context>
|
|
42
|
-
</template>
|
|
43
|
-
|
|
44
|
-
<template name="morph-if-else" value="{{#if $CONDITION$}} $TRUE_BRANCH$ {{else}} $FALSE_BRANCH$ {{/if}}" description="Handlebars if-else block" toReformat="false" toShortenFQNames="true">
|
|
45
|
-
<variable name="CONDITION" expression="" defaultValue=""condition"" alwaysStopAt="true" />
|
|
46
|
-
<variable name="TRUE_BRANCH" expression="" defaultValue="""" alwaysStopAt="true" />
|
|
47
|
-
<variable name="FALSE_BRANCH" expression="" defaultValue="""" alwaysStopAt="true" />
|
|
48
|
-
<context>
|
|
49
|
-
<option name="OTHER" value="true" />
|
|
50
|
-
</context>
|
|
51
|
-
</template>
|
|
52
|
-
|
|
53
|
-
<template name="morph-each" value="{{#each $ITEMS$}} {{this.$PROPERTY$}} {{/each}}" description="Handlebars each loop" toReformat="false" toShortenFQNames="true">
|
|
54
|
-
<variable name="ITEMS" expression="" defaultValue=""items"" alwaysStopAt="true" />
|
|
55
|
-
<variable name="PROPERTY" expression="" defaultValue=""name"" alwaysStopAt="true" />
|
|
56
|
-
<context>
|
|
57
|
-
<option name="OTHER" value="true" />
|
|
58
|
-
</context>
|
|
59
|
-
</template>
|
|
60
|
-
|
|
61
|
-
<template name="morph-service" value="namespace {{NAMESPACE}}.Application.Features.{{pascalCase FEATURE_NAME}}.Services; public class {{pascalCase FEATURE_NAME}}Service( I{{pascalCase FEATURE_NAME}}Repository repository, ILogger<{{pascalCase FEATURE_NAME}}Service> logger) : I{{pascalCase FEATURE_NAME}}Service { public async Task<{{pascalCase FEATURE_NAME}}Dto?> GetByIdAsync(int id, CancellationToken cancellationToken = default) { $END$ } }" description="MORPH .NET Service class template" toReformat="false" toShortenFQNames="true">
|
|
62
|
-
<context>
|
|
63
|
-
<option name="C_SHARP" value="true" />
|
|
64
|
-
</context>
|
|
65
|
-
</template>
|
|
66
|
-
|
|
67
|
-
<template name="morph-repository" value="public class {{pascalCase FEATURE_NAME}}Repository(AppDbContext context) : I{{pascalCase FEATURE_NAME}}Repository { private readonly DbSet<{{pascalCase FEATURE_NAME}}> _dbSet = context.Set<{{pascalCase FEATURE_NAME}}>(); public async Task<{{pascalCase FEATURE_NAME}}?> GetByIdAsync(int id, CancellationToken cancellationToken = default) { $END$ } }" description="MORPH .NET Repository class template" toReformat="false" toShortenFQNames="true">
|
|
68
|
-
<context>
|
|
69
|
-
<option name="C_SHARP" value="true" />
|
|
70
|
-
</context>
|
|
71
|
-
</template>
|
|
72
|
-
|
|
73
|
-
<template name="morph-component" value="@page "/{{kebabCase FEATURE_NAME}}" @inject I{{pascalCase FEATURE_NAME}}Service {{pascalCase FEATURE_NAME}}Service @inject ILogger<{{pascalCase FEATURE_NAME}}Page> Logger <PageTitle>{{pascalCase FEATURE_NAME}}</PageTitle> <div class="container-fluid"> $END$ </div> @code { }" description="MORPH Blazor component template" toReformat="false" toShortenFQNames="true">
|
|
74
|
-
<context>
|
|
75
|
-
<option name="HTML" value="true" />
|
|
76
|
-
</context>
|
|
77
|
-
</template>
|
|
78
|
-
|
|
79
|
-
<template name="morph-migration" value="public partial class Add{{pascalCase FEATURE_NAME}} : Migration { protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.CreateTable( name: "{{pascalCase FEATURE_NAME}}s", columns: table => new { Id = table.Column<int>(type: "int", nullable: false) .Annotation("SqlServer:Identity", "1, 1"), $END$ }, constraints: table => { table.PrimaryKey("PK_{{pascalCase FEATURE_NAME}}s", x => x.Id); }); } protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable(name: "{{pascalCase FEATURE_NAME}}s"); } }" description="MORPH EF Core migration template" toReformat="false" toShortenFQNames="true">
|
|
80
|
-
<context>
|
|
81
|
-
<option name="C_SHARP" value="true" />
|
|
82
|
-
</context>
|
|
83
|
-
</template>
|
|
84
|
-
|
|
85
|
-
<template name="morph-ts-contract" value="export interface {{pascalCase FEATURE_NAME}} { id: number; $FIELD1$ } export interface Create{{pascalCase FEATURE_NAME}}Request { $FIELD2$ } export interface Update{{pascalCase FEATURE_NAME}}Request { $END$ }" description="MORPH TypeScript contract template" toReformat="false" toShortenFQNames="true">
|
|
86
|
-
<variable name="FIELD1" expression="" defaultValue="""" alwaysStopAt="true" />
|
|
87
|
-
<variable name="FIELD2" expression="" defaultValue="""" alwaysStopAt="true" />
|
|
88
|
-
<context>
|
|
89
|
-
<option name="TypeScript" value="true" />
|
|
90
|
-
</context>
|
|
91
|
-
</template>
|
|
92
|
-
</templateSet>
|
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"MORPH Template - PascalCase": {
|
|
3
|
-
"prefix": "morph-pascal",
|
|
4
|
-
"body": ["{{pascalCase ${1:FEATURE_NAME}}}"],
|
|
5
|
-
"description": "Convert to PascalCase (UserAuth)"
|
|
6
|
-
},
|
|
7
|
-
"MORPH Template - camelCase": {
|
|
8
|
-
"prefix": "morph-camel",
|
|
9
|
-
"body": ["{{camelCase ${1:FEATURE_NAME}}}"],
|
|
10
|
-
"description": "Convert to camelCase (userAuth)"
|
|
11
|
-
},
|
|
12
|
-
"MORPH Template - snake_case": {
|
|
13
|
-
"prefix": "morph-snake",
|
|
14
|
-
"body": ["{{snakeCase ${1:FEATURE_NAME}}}"],
|
|
15
|
-
"description": "Convert to snake_case (user_auth)"
|
|
16
|
-
},
|
|
17
|
-
"MORPH Template - Title Case": {
|
|
18
|
-
"prefix": "morph-title",
|
|
19
|
-
"body": ["{{titleCase ${1:FEATURE_NAME}}}"],
|
|
20
|
-
"description": "Convert to Title Case (User Auth)"
|
|
21
|
-
},
|
|
22
|
-
"MORPH Template - kebab-case": {
|
|
23
|
-
"prefix": "morph-kebab",
|
|
24
|
-
"body": ["{{kebabCase ${1:FEATURE_NAME}}}"],
|
|
25
|
-
"description": "Convert to kebab-case (user-auth)"
|
|
26
|
-
},
|
|
27
|
-
"MORPH Template - UPPER_SNAKE_CASE": {
|
|
28
|
-
"prefix": "morph-upper-snake",
|
|
29
|
-
"body": ["{{upperSnakeCase ${1:FEATURE_NAME}}}"],
|
|
30
|
-
"description": "Convert to UPPER_SNAKE_CASE (USER_AUTH)"
|
|
31
|
-
},
|
|
32
|
-
"MORPH Template - Conditional If": {
|
|
33
|
-
"prefix": "morph-if",
|
|
34
|
-
"body": [
|
|
35
|
-
"{{#if ${1:condition}}}",
|
|
36
|
-
" $2",
|
|
37
|
-
"{{/if}}"
|
|
38
|
-
],
|
|
39
|
-
"description": "Handlebars if block"
|
|
40
|
-
},
|
|
41
|
-
"MORPH Template - Conditional If-Else": {
|
|
42
|
-
"prefix": "morph-if-else",
|
|
43
|
-
"body": [
|
|
44
|
-
"{{#if ${1:condition}}}",
|
|
45
|
-
" $2",
|
|
46
|
-
"{{else}}",
|
|
47
|
-
" $3",
|
|
48
|
-
"{{/if}}"
|
|
49
|
-
],
|
|
50
|
-
"description": "Handlebars if-else block"
|
|
51
|
-
},
|
|
52
|
-
"MORPH Template - Each Loop": {
|
|
53
|
-
"prefix": "morph-each",
|
|
54
|
-
"body": [
|
|
55
|
-
"{{#each ${1:items}}}",
|
|
56
|
-
" {{this.$2}}",
|
|
57
|
-
"{{/each}}"
|
|
58
|
-
],
|
|
59
|
-
"description": "Handlebars each loop"
|
|
60
|
-
},
|
|
61
|
-
"MORPH Template - Unless": {
|
|
62
|
-
"prefix": "morph-unless",
|
|
63
|
-
"body": [
|
|
64
|
-
"{{#unless ${1:condition}}}",
|
|
65
|
-
" $2",
|
|
66
|
-
"{{/unless}}"
|
|
67
|
-
],
|
|
68
|
-
"description": "Handlebars unless block"
|
|
69
|
-
},
|
|
70
|
-
"MORPH Template - .NET Service Class": {
|
|
71
|
-
"prefix": "morph-service",
|
|
72
|
-
"body": [
|
|
73
|
-
"namespace {{NAMESPACE}}.Application.Features.{{pascalCase FEATURE_NAME}}.Services;",
|
|
74
|
-
"",
|
|
75
|
-
"public class {{pascalCase FEATURE_NAME}}Service(",
|
|
76
|
-
" I{{pascalCase FEATURE_NAME}}Repository repository,",
|
|
77
|
-
" ILogger<{{pascalCase FEATURE_NAME}}Service> logger) : I{{pascalCase FEATURE_NAME}}Service",
|
|
78
|
-
"{",
|
|
79
|
-
" public async Task<{{pascalCase FEATURE_NAME}}Dto?> GetByIdAsync(int id, CancellationToken cancellationToken = default)",
|
|
80
|
-
" {",
|
|
81
|
-
" $1",
|
|
82
|
-
" }",
|
|
83
|
-
"}"
|
|
84
|
-
],
|
|
85
|
-
"description": "MORPH .NET Service class template"
|
|
86
|
-
},
|
|
87
|
-
"MORPH Template - .NET Repository Class": {
|
|
88
|
-
"prefix": "morph-repository",
|
|
89
|
-
"body": [
|
|
90
|
-
"public class {{pascalCase FEATURE_NAME}}Repository(AppDbContext context) : I{{pascalCase FEATURE_NAME}}Repository",
|
|
91
|
-
"{",
|
|
92
|
-
" private readonly DbSet<{{pascalCase FEATURE_NAME}}> _dbSet = context.Set<{{pascalCase FEATURE_NAME}}>();",
|
|
93
|
-
"",
|
|
94
|
-
" public async Task<{{pascalCase FEATURE_NAME}}?> GetByIdAsync(int id, CancellationToken cancellationToken = default)",
|
|
95
|
-
" {",
|
|
96
|
-
" $1",
|
|
97
|
-
" }",
|
|
98
|
-
"}"
|
|
99
|
-
],
|
|
100
|
-
"description": "MORPH .NET Repository class template"
|
|
101
|
-
},
|
|
102
|
-
"MORPH Template - Blazor Component": {
|
|
103
|
-
"prefix": "morph-component",
|
|
104
|
-
"body": [
|
|
105
|
-
"@page \"/{{kebabCase FEATURE_NAME}}\"",
|
|
106
|
-
"@inject I{{pascalCase FEATURE_NAME}}Service {{pascalCase FEATURE_NAME}}Service",
|
|
107
|
-
"@inject ILogger<{{pascalCase FEATURE_NAME}}Page> Logger",
|
|
108
|
-
"",
|
|
109
|
-
"<PageTitle>{{pascalCase FEATURE_NAME}}</PageTitle>",
|
|
110
|
-
"",
|
|
111
|
-
"<div class=\"container-fluid\">",
|
|
112
|
-
" $1",
|
|
113
|
-
"</div>",
|
|
114
|
-
"",
|
|
115
|
-
"@code {",
|
|
116
|
-
" $2",
|
|
117
|
-
"}"
|
|
118
|
-
],
|
|
119
|
-
"description": "MORPH Blazor component template"
|
|
120
|
-
},
|
|
121
|
-
"MORPH Template - EF Core Migration": {
|
|
122
|
-
"prefix": "morph-migration",
|
|
123
|
-
"body": [
|
|
124
|
-
"public partial class Add{{pascalCase FEATURE_NAME}} : Migration",
|
|
125
|
-
"{",
|
|
126
|
-
" protected override void Up(MigrationBuilder migrationBuilder)",
|
|
127
|
-
" {",
|
|
128
|
-
" migrationBuilder.CreateTable(",
|
|
129
|
-
" name: \"{{pascalCase FEATURE_NAME}}s\",",
|
|
130
|
-
" columns: table => new",
|
|
131
|
-
" {",
|
|
132
|
-
" Id = table.Column<int>(type: \"int\", nullable: false)",
|
|
133
|
-
" .Annotation(\"SqlServer:Identity\", \"1, 1\"),",
|
|
134
|
-
" $1",
|
|
135
|
-
" },",
|
|
136
|
-
" constraints: table =>",
|
|
137
|
-
" {",
|
|
138
|
-
" table.PrimaryKey(\"PK_{{pascalCase FEATURE_NAME}}s\", x => x.Id);",
|
|
139
|
-
" });",
|
|
140
|
-
" }",
|
|
141
|
-
"",
|
|
142
|
-
" protected override void Down(MigrationBuilder migrationBuilder)",
|
|
143
|
-
" {",
|
|
144
|
-
" migrationBuilder.DropTable(name: \"{{pascalCase FEATURE_NAME}}s\");",
|
|
145
|
-
" }",
|
|
146
|
-
"}"
|
|
147
|
-
],
|
|
148
|
-
"description": "MORPH EF Core migration template"
|
|
149
|
-
},
|
|
150
|
-
"MORPH Template - Hangfire Job": {
|
|
151
|
-
"prefix": "morph-job",
|
|
152
|
-
"body": [
|
|
153
|
-
"public class {{pascalCase FEATURE_NAME}}ProcessorJob(",
|
|
154
|
-
" I{{pascalCase FEATURE_NAME}}Service service,",
|
|
155
|
-
" ILogger<{{pascalCase FEATURE_NAME}}ProcessorJob> logger) : I{{pascalCase FEATURE_NAME}}ProcessorJob",
|
|
156
|
-
"{",
|
|
157
|
-
" [AutomaticRetry(Attempts = 3, DelaysInSeconds = new[] { 60, 300, 900 })]",
|
|
158
|
-
" [Queue(\"default\")]",
|
|
159
|
-
" [JobDisplayName(\"{{pascalCase FEATURE_NAME}} Processing - ID: {0}\")]",
|
|
160
|
-
" public async Task ExecuteAsync(int id, CancellationToken cancellationToken)",
|
|
161
|
-
" {",
|
|
162
|
-
" $1",
|
|
163
|
-
" }",
|
|
164
|
-
"}"
|
|
165
|
-
],
|
|
166
|
-
"description": "MORPH Hangfire job template"
|
|
167
|
-
},
|
|
168
|
-
"MORPH Template - TypeScript Contract": {
|
|
169
|
-
"prefix": "morph-ts-contract",
|
|
170
|
-
"body": [
|
|
171
|
-
"export interface {{pascalCase FEATURE_NAME}} {",
|
|
172
|
-
" id: number;",
|
|
173
|
-
" $1",
|
|
174
|
-
"}",
|
|
175
|
-
"",
|
|
176
|
-
"export interface Create{{pascalCase FEATURE_NAME}}Request {",
|
|
177
|
-
" $2",
|
|
178
|
-
"}",
|
|
179
|
-
"",
|
|
180
|
-
"export interface Update{{pascalCase FEATURE_NAME}}Request {",
|
|
181
|
-
" $3",
|
|
182
|
-
"}"
|
|
183
|
-
],
|
|
184
|
-
"description": "MORPH TypeScript contract template"
|
|
185
|
-
}
|
|
186
|
-
}
|