@polymorphism-tech/morph-spec 9.7.0 → 10.0.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 +11 -11
- package/README.md +4 -4
- package/bin/morph-spec.js +41 -44
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +1 -1
- package/docs/QUICKSTART.md +1 -1
- package/framework/CLAUDE.md +24 -30
- package/framework/MORPH.md +47 -123
- package/framework/agents.json +6 -374
- package/framework/commands/morph-apply.md +1 -1
- package/framework/commands/morph-archive.md +4 -3
- package/framework/commands/morph-hotfix.md +8 -30
- package/framework/commands/morph-infra.md +2 -2
- package/framework/commands/morph-media.md +10 -9
- package/framework/commands/morph-review.md +15 -0
- package/framework/commands/morph-status.md +1 -1
- package/framework/docs/CLI.md +100 -102
- package/framework/evals/review-checklist.md +46 -54
- package/framework/hooks/README.md +4 -4
- package/framework/hooks/claude-code/__pycache__/statusline.cpython-313.pyc +0 -0
- package/framework/hooks/claude-code/core/README.md +1 -1
- package/framework/hooks/claude-code/core/denylist.json +4 -4
- package/framework/hooks/claude-code/core/gate-guard.js +9 -0
- package/framework/hooks/claude-code/core/masked-exit.js +49 -0
- package/framework/hooks/claude-code/core/state-sync.js +4 -1
- package/framework/hooks/claude-code/core/telemetry-log.js +1 -2
- package/framework/hooks/claude-code/core/test-budget.js +10 -70
- package/framework/hooks/claude-code/core/validate-completion.js +11 -24
- package/framework/hooks/claude-code/core/worktree-context.js +5 -22
- package/framework/hooks/claude-code/core/worktree-create.js +6 -45
- package/framework/hooks/claude-code/core/worktree-env-inject.js +2 -10
- package/framework/hooks/shared/e2e-check.js +0 -0
- package/framework/hooks/shared/gate-event.js +2 -2
- package/framework/hooks/shared/graph-refresh.js +20 -3
- package/framework/hooks/shared/heavy-command.js +32 -1
- package/framework/hooks/shared/heavy-config.js +1 -1
- package/framework/hooks/shared/heavy-slots.js +41 -4
- package/framework/hooks/shared/next-step.js +63 -24
- package/framework/hooks/shared/phase-utils.js +6 -9
- package/framework/hooks/shared/report-progress.js +86 -0
- package/framework/hooks/shared/state-reader.js +3 -2
- package/framework/hooks/statusline.js +332 -0
- package/framework/phases.json +32 -10
- package/framework/rules/ai-agents-standards.md +9 -1
- package/framework/rules/csharp-standards.md +4 -0
- package/framework/rules/ef-standards.md +20 -0
- package/framework/rules/frontend-standards.md +1 -1
- package/framework/rules/implement-report.md +25 -0
- package/framework/rules/infrastructure-standards.md +2 -0
- package/framework/rules/nextjs-standards.md +7 -0
- package/framework/rules/plan-grammar.md +53 -0
- package/framework/rules/ui-design.md +27 -0
- package/framework/schemas/config.schema.json +12 -19
- package/framework/schemas/feature.schema.json +7 -1
- package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
- package/framework/skills/core/create-umbraco-lp/references/umbraco-lp-patterns.md +1 -1
- package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +2 -2
- package/framework/skills/core/morph-apply/SKILL.md +38 -166
- package/framework/skills/core/morph-apply/references/debugging.md +8 -0
- package/framework/skills/core/morph-apply/references/hotfix.md +42 -0
- package/framework/skills/core/morph-apply/references/machine.md +29 -0
- package/framework/skills/core/{morph-media/SKILL.md → morph-apply/references/media.md} +11 -74
- package/framework/skills/core/morph-apply/references/review.md +65 -0
- package/framework/skills/core/morph-plan/SKILL.md +42 -108
- package/framework/skills/core/morph-plan/references/critique.md +40 -0
- package/framework/skills/core/morph-plan/references/interview.md +25 -0
- package/framework/skills/core/morph-uiux/SKILL.md +47 -64
- package/framework/skills/core/morph-uiux/surfaces.json +32 -0
- package/framework/standards/STANDARDS.json +32 -5
- package/framework/standards/STANDARDS.meta.json +5 -1
- package/framework/standards/ai-agents/agent-session.md +2 -3
- package/framework/standards/ai-agents/context-providers.md +2 -2
- package/framework/standards/ai-agents/durable-workflows-hitl.md +2 -2
- package/framework/standards/ai-agents/providers/model-registry.md +2 -2
- package/framework/standards/ai-agents/rag-custom-pgvector.md +6 -6
- package/framework/standards/ai-agents/setup.md +1 -1
- package/framework/standards/ai-agents/tool-adapters.md +2 -2
- package/framework/standards/architecture/stack-baseline.md +47 -0
- package/framework/standards/backend/integrations/neon-auth/neon-auth.md +2 -4
- package/framework/standards/frontend/design-system/ai-image-generation.md +51 -12
- package/framework/standards/frontend/design-system/ai-video-generation.md +50 -4
- package/framework/standards/frontend/design-system/art-direction.md +2 -2
- package/framework/standards/frontend/scroll-driven/frame-scrub.md +12 -2
- package/framework/standards/frontend/scroll-driven/scroll-components.md +76 -4
- 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/REGISTRY.json +1 -2
- 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/context/ARCHITECTURE.md +1 -1
- package/framework/templates/docs/plan.md +12 -12
- package/framework/templates/docs/ui-mockups.md +17 -105
- package/framework/templates/frontend/nextjs/client-component.tsx.hbs +26 -26
- package/framework/templates/frontend/nextjs/tsconfig.json.hbs +26 -26
- package/framework/templates/infrastructure/docker/Dockerfile.template +58 -58
- package/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -38
- package/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -48
- package/framework/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +45 -45
- package/framework/templates/infrastructure/github/actions/health-check/action.yml.hbs +27 -27
- package/framework/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +59 -59
- package/framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +39 -39
- package/framework/templates/state.template.json +17 -17
- package/framework/templates/ui/design-system.css +226 -226
- package/package.json +1 -1
- package/src/commands/e2e/e2e.js +88 -23
- package/src/commands/graph/diff.js +74 -0
- package/src/commands/graph/status.js +1 -1
- package/src/commands/observability/cost.js +2 -4
- package/src/commands/observability/telemetry.js +1 -1
- package/src/commands/project/doctor.js +23 -39
- package/src/commands/project/fleet.js +5 -6
- package/src/commands/project/init.js +63 -36
- package/src/commands/project/stack-scan.js +3 -42
- package/src/commands/project/stack-set.js +26 -0
- package/src/commands/project/status.js +12 -13
- package/src/commands/project/update.js +39 -3
- package/src/commands/project/worktree.js +27 -16
- package/src/commands/state/advance.js +17 -17
- package/src/commands/state/approve.js +0 -6
- package/src/commands/state/archive.js +27 -1
- package/src/commands/state/auto-approval.js +1 -1
- package/src/commands/state/create.js +0 -5
- package/src/commands/state/finish.js +43 -1
- package/src/commands/state/gate-check.js +37 -30
- package/src/commands/state/gate-decision.js +3 -2
- package/src/commands/state/next.js +1 -0
- package/src/commands/state/recap.js +67 -0
- package/src/commands/state/report-check.js +39 -146
- package/src/commands/validation/plan-check.js +16 -11
- package/src/commands/validation/validate-feature.js +3 -3
- package/src/commands/validation/verify.js +6 -6
- package/src/core/paths/output-schema.js +3 -3
- package/src/core/state/state-manager.js +2 -4
- package/src/dashboard/app/components/CommandPalette.jsx +2 -5
- package/src/dashboard/app/components/GatePauses.jsx +116 -0
- package/src/dashboard/app/components/SessionMap.jsx +77 -0
- package/src/dashboard/app/main.jsx +13 -13
- package/src/dashboard/app/pages/Activity.jsx +4 -0
- package/src/dashboard/app/pages/AgentMap.jsx +1 -2
- package/src/dashboard/app/pages/FeatureDetail.jsx +129 -186
- package/src/dashboard/app/pages/Features.jsx +7 -7
- package/src/dashboard/app/pages/PhasePipeline.jsx +1 -1
- package/src/dashboard/app/pages/Portfolio.jsx +40 -5
- package/src/dashboard/scanner/activity-scanner.js +29 -0
- package/src/dashboard/scanner/agents-scanner.js +11 -14
- package/src/dashboard/scanner/features-scanner.js +45 -24
- package/src/dashboard/scanner/project-api.js +11 -2
- package/src/dashboard/scanner/skills-scanner.js +11 -1
- package/src/dashboard/vite.config.js +24 -24
- package/src/lib/e2e/applicability.js +3 -1
- package/src/lib/git/tree-state.js +1 -16
- package/src/lib/graph/diff-tree.js +127 -0
- package/src/lib/graph/graphify-runtime.js +12 -5
- package/src/lib/heavy/gate.js +22 -1
- package/src/lib/installers/memory-installer.js +2 -2
- package/src/lib/installers/rules-installer.js +57 -0
- package/src/lib/installers/stack-assets.js +17 -0
- package/src/lib/installers/stack-sync.js +219 -0
- package/src/lib/plan/checks.js +55 -110
- package/src/lib/plan/critique.js +28 -0
- package/src/lib/plan/media.js +42 -0
- package/src/lib/plan/plan-html.js +125 -0
- package/src/lib/plan/plan-parser.js +34 -45
- package/src/lib/recap/piper.js +36 -0
- package/src/lib/recap/recap.js +232 -0
- package/src/lib/review-reports.js +33 -7
- package/src/lib/risk-detector.js +90 -11
- package/src/lib/specs/screen-checklist.js +33 -48
- package/src/lib/stack/dotnet-build-ignores.js +8 -9
- package/src/lib/tasks/test-nodes.js +24 -6
- package/src/lib/tasks/test-runner.js +40 -1
- package/src/lib/telemetry/metrics.js +27 -29
- package/src/lib/validators/reuse/reuse-validator.js +1 -9
- package/src/lib/validators/verify-runner.js +50 -19
- package/src/lib/worktree/fleet-scanner.js +7 -20
- package/src/lib/worktree/worktree-audit.js +0 -37
- package/src/scripts/setup-infra.js +15 -50
- package/src/utils/agents-installer.js +27 -201
- package/src/utils/hooks-installer.js +11 -95
- package/framework/hooks/claude-code/core/warn-bash-source-write.js +0 -23
- package/framework/hooks/claude-code/statusline.py +0 -699
- package/framework/hooks/claude-code/statusline.sh +0 -11
- package/framework/hooks/shared/agent-reap.js +0 -74
- package/framework/hooks/shared/slice-progress.js +0 -110
- package/framework/skills/core/morph-hotfix/SKILL.md +0 -133
- package/framework/skills/core/morph-machine/SKILL.md +0 -46
- package/framework/skills/core/morph-review/SKILL.md +0 -129
- package/framework/skills/core/morph-standards/SKILL.md +0 -52
- package/framework/standards/PROVENANCE.json +0 -119
- package/src/commands/project/worktree-reap.js +0 -34
- package/src/commands/state/handoff.js +0 -65
- package/src/commands/validation/mutate.js +0 -263
- package/src/commands/validation/scout-check.js +0 -28
- package/src/lib/generators/handoff-generator.js +0 -172
- package/src/lib/mutation/adapters.js +0 -79
- package/src/lib/mutation/commands.js +0 -61
- package/src/lib/mutation/dotnet-introspection.js +0 -281
- package/src/lib/mutation/manifest.js +0 -144
- package/src/lib/mutation/plan.js +0 -44
- package/src/lib/mutation/report.js +0 -68
- package/src/lib/mutation/runner.js +0 -301
- package/src/lib/mutation/schemata.js +0 -60
- package/src/lib/mutation/snapshot.js +0 -65
- package/src/lib/mutation/subset.js +0 -109
- package/src/lib/mutation/trx.js +0 -50
- package/src/lib/scout/scout-check.js +0 -293
- package/src/lib/validators/traceability-check.js +0 -103
- package/src/lib/worktree/agent-reaper.js +0 -247
|
@@ -1,11 +0,0 @@
|
|
|
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,74 +0,0 @@
|
|
|
1
|
-
// O SessionStart tem 5 s: o disparo só olha o disco e solta um worker DESTACADO
|
|
2
|
-
// com `cwd` no git common dir, que nunca segura o diretório de uma worktree.
|
|
3
|
-
|
|
4
|
-
import { spawn } from 'child_process';
|
|
5
|
-
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'fs';
|
|
6
|
-
import { join, resolve } from 'path';
|
|
7
|
-
import { fileURLToPath } from 'url';
|
|
8
|
-
import { isSecondaryWorktree, resolveGitCommonDir } from './git-paths.js';
|
|
9
|
-
import { primaryTree } from './graph-freshness.js';
|
|
10
|
-
import { runMorphSpec } from './morph-cli.js';
|
|
11
|
-
|
|
12
|
-
const WORKER = fileURLToPath(import.meta.url);
|
|
13
|
-
const THROTTLE_MS = 10 * 60_000;
|
|
14
|
-
const WORKER_TIMEOUT_MS = 15 * 60_000;
|
|
15
|
-
const ADMIN_DIR = /^agent-[0-9a-f]+\d*$/;
|
|
16
|
-
const AGENT_BRANCH_FILE = /^agent-[0-9a-f]+$/;
|
|
17
|
-
|
|
18
|
-
function anyEntry(dir, pattern) {
|
|
19
|
-
try { return readdirSync(dir).some((name) => pattern.test(name)); } catch { return false; }
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function hasAgentLeftovers(common) {
|
|
23
|
-
if (anyEntry(join(common, 'worktrees'), ADMIN_DIR)) return true;
|
|
24
|
-
if (anyEntry(join(common, 'refs', 'heads', 'morph-task'), AGENT_BRANCH_FILE)) return true;
|
|
25
|
-
try {
|
|
26
|
-
return /refs\/heads\/morph-task\/agent-[0-9a-f]+/.test(readFileSync(join(common, 'packed-refs'), 'utf8'));
|
|
27
|
-
} catch {
|
|
28
|
-
return false;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function recentlyKicked(marker, now) {
|
|
33
|
-
try {
|
|
34
|
-
const age = now - Number(readFileSync(marker, 'utf8'));
|
|
35
|
-
return age >= 0 && age < THROTTLE_MS;
|
|
36
|
-
} catch {
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function kickAgentReap(dir, { spawnFn = spawn, env = process.env, now = Date.now } = {}) {
|
|
42
|
-
if (env.MORPH_WORKTREE_REAP === '0') return { kicked: false, reason: 'disabled' };
|
|
43
|
-
const common = resolveGitCommonDir(dir);
|
|
44
|
-
const root = common && primaryTree(dir);
|
|
45
|
-
if (!root) return { kicked: false, reason: 'not-a-repo' };
|
|
46
|
-
if (isSecondaryWorktree(dir)) return { kicked: false, reason: 'secondary-worktree' };
|
|
47
|
-
if (!hasAgentLeftovers(common)) return { kicked: false, reason: 'nothing-to-reap' };
|
|
48
|
-
|
|
49
|
-
const marker = join(common, 'morph-spec', 'agent-reap.kick');
|
|
50
|
-
if (recentlyKicked(marker, now())) return { kicked: false, reason: 'throttled' };
|
|
51
|
-
try {
|
|
52
|
-
mkdirSync(join(common, 'morph-spec'), { recursive: true });
|
|
53
|
-
writeFileSync(marker, String(now()));
|
|
54
|
-
const child = spawnFn(process.execPath, [WORKER, '--run', root], {
|
|
55
|
-
cwd: common, env, detached: true, stdio: 'ignore', windowsHide: true,
|
|
56
|
-
});
|
|
57
|
-
child.on?.('error', () => {});
|
|
58
|
-
child.unref?.();
|
|
59
|
-
return { kicked: true, pid: child.pid };
|
|
60
|
-
} catch {
|
|
61
|
-
return { kicked: false, reason: 'spawn-failed' };
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const isMain = (() => {
|
|
66
|
-
const argv1 = process.argv[1];
|
|
67
|
-
if (!argv1) return false;
|
|
68
|
-
const norm = (p) => (process.platform === 'win32' ? resolve(p).toLowerCase() : resolve(p));
|
|
69
|
-
return norm(argv1) === norm(WORKER);
|
|
70
|
-
})();
|
|
71
|
-
|
|
72
|
-
if (isMain && process.argv[2] === '--run' && process.argv[3] && existsSync(process.argv[3])) {
|
|
73
|
-
try { runMorphSpec(['worktree', 'reap', '--json'], { cwd: process.argv[3], timeoutMs: WORKER_TIMEOUT_MS }); } catch { /* fail-open */ }
|
|
74
|
-
}
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'fs';
|
|
2
|
-
import { join } from 'path';
|
|
3
|
-
|
|
4
|
-
/** `PARCIAL` on the report's first non-blank line, tolerating heading/bold/quote typography. */
|
|
5
|
-
export const PARTIAL_MARKER = /^[\s#>*_]*PARCIAL\b/;
|
|
6
|
-
|
|
7
|
-
/** `BLOQUEADO`: the slice waits on a decision only the human can make; re-dispatching it repeats the question. */
|
|
8
|
-
export const BLOCKED_MARKER = /^[\s#>*_]*BLOQUEADO\b/;
|
|
9
|
-
|
|
10
|
-
export function checksPath(featureDir) {
|
|
11
|
-
return join(featureDir, '2-plan', 'checks.json');
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function sliceReportPath(featureDir, sliceId) {
|
|
15
|
-
return join(featureDir, '3-implement', 'reports', `${sliceId}.md`);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function sliceStatusFromReport(text) {
|
|
19
|
-
if (text == null) return 'pendente';
|
|
20
|
-
const first = String(text).split(/\r?\n/).find((l) => l.trim() !== '') ?? '';
|
|
21
|
-
if (BLOCKED_MARKER.test(first)) return 'bloqueado';
|
|
22
|
-
return PARTIAL_MARKER.test(first) ? 'parcial' : 'feito';
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/** @returns {{ total, done, partial, blocked, pending, slices } | null} null when the checks text is unreadable */
|
|
26
|
-
export function sliceProgressFrom(checksText, readReport) {
|
|
27
|
-
let slices;
|
|
28
|
-
try {
|
|
29
|
-
slices = JSON.parse(checksText ?? '').slices;
|
|
30
|
-
} catch {
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
|
-
if (!Array.isArray(slices)) return null;
|
|
34
|
-
const out = slices
|
|
35
|
-
.filter((s) => s && typeof s.id === 'string')
|
|
36
|
-
.map((s) => ({
|
|
37
|
-
id: s.id,
|
|
38
|
-
title: s.title ?? '',
|
|
39
|
-
depends: Array.isArray(s.depends) ? s.depends : [],
|
|
40
|
-
covers: Array.isArray(s.covers) ? s.covers : [],
|
|
41
|
-
status: sliceStatusFromReport(readReport(s.id)),
|
|
42
|
-
}));
|
|
43
|
-
const count = (status) => out.filter((s) => s.status === status).length;
|
|
44
|
-
return {
|
|
45
|
-
total: out.length,
|
|
46
|
-
done: count('feito'),
|
|
47
|
-
partial: count('parcial'),
|
|
48
|
-
blocked: count('bloqueado'),
|
|
49
|
-
pending: count('pendente'),
|
|
50
|
-
slices: out,
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function readOrNull(path) {
|
|
55
|
-
try {
|
|
56
|
-
return existsSync(path) ? readFileSync(path, 'utf8') : null;
|
|
57
|
-
} catch {
|
|
58
|
-
return null;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export function sliceProgress(featureDir) {
|
|
63
|
-
return sliceProgressFrom(readOrNull(checksPath(featureDir)), (id) => readOrNull(sliceReportPath(featureDir, id)));
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export function readySlices(progress) {
|
|
67
|
-
if (!progress) return [];
|
|
68
|
-
const done = new Set(progress.slices.filter((s) => s.status === 'feito').map((s) => s.id));
|
|
69
|
-
return progress.slices.filter((s) => s.status !== 'feito' && s.status !== 'bloqueado' && s.depends.every((d) => done.has(d)));
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Loose on purpose: a false "complete" costs a read, a false "incomplete"
|
|
73
|
-
// re-dispatches finished work.
|
|
74
|
-
export const REPORT_MARKERS = [
|
|
75
|
-
{ id: 'files', re: /^\s*(?:[-*]\s*)?(?:\*\*|#+\s*)?arquivos\s*:?\**\s*:?/mi },
|
|
76
|
-
];
|
|
77
|
-
|
|
78
|
-
const MIN_PROSE_CHARS = 80;
|
|
79
|
-
|
|
80
|
-
const scenarioRe = (id) => new RegExp(`(?<![\\w-])${id}(?![\\w-])`);
|
|
81
|
-
|
|
82
|
-
/** Every scenario in `covers` must be named in the report. */
|
|
83
|
-
export function inspectReport(path, { covers = [] } = {}) {
|
|
84
|
-
const missingAll = ['what', 'files', ...covers];
|
|
85
|
-
if (!existsSync(path)) return { exists: false, complete: false, missing: missingAll };
|
|
86
|
-
let body = '';
|
|
87
|
-
try {
|
|
88
|
-
body = readFileSync(path, 'utf8');
|
|
89
|
-
} catch {
|
|
90
|
-
return { exists: true, complete: false, missing: missingAll, unreadable: true };
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const missing = REPORT_MARKERS.filter((m) => !m.re.test(body)).map((m) => m.id);
|
|
94
|
-
missing.push(...covers.filter((id) => !scenarioRe(id).test(body)));
|
|
95
|
-
const prose = body
|
|
96
|
-
.split('\n')
|
|
97
|
-
.filter((l) => !/^\s*(#|[-*]\s|\*\*)/.test(l))
|
|
98
|
-
.join(' ')
|
|
99
|
-
.replace(/\s+/g, ' ')
|
|
100
|
-
.trim();
|
|
101
|
-
if (prose.length < MIN_PROSE_CHARS) missing.unshift('what');
|
|
102
|
-
|
|
103
|
-
const firstLine = body.split('\n').find((l) => l.trim() !== '') ?? '';
|
|
104
|
-
const partial = PARTIAL_MARKER.test(firstLine);
|
|
105
|
-
if (partial) missing.push('partial');
|
|
106
|
-
const blocked = BLOCKED_MARKER.test(firstLine);
|
|
107
|
-
if (blocked) missing.push('blocked');
|
|
108
|
-
|
|
109
|
-
return { exists: true, complete: missing.length === 0, missing, partial, blocked };
|
|
110
|
-
}
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: morph-hotfix
|
|
3
|
-
description: ADW cirúrgico de hotfix — resolve uma queda/bug crítico de produção com prioridade máxima em velocidade, com aprovação humana obrigatória antes do ship.
|
|
4
|
-
version: core
|
|
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
|
-
user-invocable: true
|
|
7
|
-
cliVersion: "9.7.0"
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
# morph-hotfix
|
|
11
|
-
|
|
12
|
-
## Objetivo
|
|
13
|
-
|
|
14
|
-
Resolver uma queda ou bug crítico de produção o mais rápido possível — prioridade é velocidade, não elegância — mantendo aprovação humana obrigatória antes do ship. É o pipeline dimensionado por `workType: hotfix` (MORPH.md §2.1): scout → fix cirúrgico → aprovação humana → test loop → ship.
|
|
15
|
-
|
|
16
|
-
## Quando invocar
|
|
17
|
-
|
|
18
|
-
- Usuário roda `/morph-hotfix {feature}` diretamente.
|
|
19
|
-
- `Skill(morph-plan)` roteia o pedido como `hotfix` e invoca esta skill.
|
|
20
|
-
- Usuário diz "produção caiu", "hotfix", "urgente", "incident", "P0" — sinais que o detector determinístico de `morph-spec create --request` já reconhece.
|
|
21
|
-
|
|
22
|
-
## Argumentos
|
|
23
|
-
|
|
24
|
-
- `{feature-name}` — nome em kebab-case da feature. Se ausente, perguntar via `AskUserQuestion`.
|
|
25
|
-
|
|
26
|
-
## Fluxo
|
|
27
|
-
|
|
28
|
-
### 1. Nascimento da feature
|
|
29
|
-
|
|
30
|
-
```
|
|
31
|
-
morph-spec create {feature} --type hotfix --description "<o incidente: o que quebrou / sintoma>"
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Carimba `name` (o slug) + `description` (obrigatória no nascimento — descreva o incidente) e o gate `plan` como `approvedBy: "policy:hotfix"`, e cria as pastas `2-plan/` e `3-implement/` num passo só — a feature já nasce em `implement` (fase derivada é gate-aware). Se a feature já existe, siga adiante sem recriar.
|
|
35
|
-
|
|
36
|
-
### 2. Scout — mapa do território (obrigatório)
|
|
37
|
-
|
|
38
|
-
Despache o scout com o sintoma reportado, antes de qualquer fix:
|
|
39
|
-
|
|
40
|
-
```
|
|
41
|
-
subagent_type: "morph-scout"
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
**Fallback** (se `morph-scout` não estiver registrado nos subagent types deste projeto): `general-purpose` com o campo `persona` do agente `scout` colado no prompt, **registrando o fallback no `reports/F1.md`**.
|
|
45
|
-
|
|
46
|
-
Peça ao scout: localizar o root cause provável, os arquivos afetados e o blast radius (o que mais pode quebrar). Ele é read-only (Read/Glob/Grep/Bash somente-leitura) e o corpo da persona dele já carrega o contrato read-only: o contrato de dispatch dos implementadores — commit `wip`, orçamento de teste, escopo da fatia — não se aplica a quem não escreve. O prompt dele diz só o sintoma: ele não escreve nem reverte nada, e o mapa é a mensagem final (Observado/Inferido, no contrato de citação que a persona já carrega). Você grava o mapa.
|
|
47
|
-
|
|
48
|
-
**Audite o mapa antes do brief.** Grave a resposta do scout em `.morph/features/{feature}/2-plan/scout-map.md` e rode `morph-spec scout-check .morph/features/{feature}/2-plan/scout-map.md --json`. Exit ≠ 0 → descarte o mapa e re-despache o scout **uma** vez com as `failures` no prompt (o mapa novo abre com o motivo); na segunda reprovação, faça você o grep do root cause e siga. Root cause e blast radius que entram no brief se conferem com grep próprio mesmo com o mapa aprovado: sob pressão de hotfix, citação inventada vira um segundo incidente.
|
|
49
|
-
|
|
50
|
-
### 3. Plano curto (`2-plan/plan.md` → `checks.json`)
|
|
51
|
-
|
|
52
|
-
Escreva o `plan.md` mínimo (~25 linhas) numa única escrita: o hotfix nasce com o gate `plan` carimbado, o `create` não escreve esqueleto e o arquivo congela assim que existe. Gramática completa: `morph-spec plan-check --help`.
|
|
53
|
-
|
|
54
|
-
- `## Problema` — o sintoma em produção, o root cause que o scout localizou e o blast radius.
|
|
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`) 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
|
-
- `## Decisões` com `### Conflitos com o acervo` (`nenhum` vale).
|
|
59
|
-
- `## Fatias` — uma, `### F1 — fix`, com `persona:`, `arquivos:` e `cobre: C1, C2`.
|
|
60
|
-
|
|
61
|
-
Rode `morph-spec plan-check {feature}` até zero erro: ele grava `2-plan/checks.json`, que o
|
|
62
|
-
`report-check` e o Gate 3 leem. Não pule esta escrita mesmo sob pressão de tempo.
|
|
63
|
-
|
|
64
|
-
### 4. Fix cirúrgico
|
|
65
|
-
|
|
66
|
-
Implemente a mudança mínima — inline se estiver no domínio já carregado, ou despachando a persona de domínio via `subagent_type: "morph-{id}"` (a `morph-apply` §3 mostra o prompt: só os campos da fatia). Inline ou despachada, a fatia termina em `3-implement/reports/F1.md` com `**Arquivos:**` e `**Checks:**` (C1 e C2 com a evidência). Prioridade: tirar a falha do ar, não refatorar — melhorias de forma (não de correção) vão para o roadmap-fora-hotfix, não para este diff.
|
|
67
|
-
|
|
68
|
-
### 5. Prova
|
|
69
|
-
|
|
70
|
-
```
|
|
71
|
-
morph-spec verify {feature} --json
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
Sem filtro: é a prova que o Gate 3 lê. Para iterar rápido antes, `--skip-tests`/`--skip-build` servem, mas não gravam o stamp `verification` (`reason: 'skip-tests'`/`'skip-build'`): o Gate 3 só lê uma execução completa. C1 se prova com o sintoma reproduzido antes e ausente depois; capture a saída real no `3-implement/reports/F1.md` — não descreva "testes passaram" sem colar a evidência.
|
|
75
|
-
|
|
76
|
-
### 6. Gate 3 — SEMPRE humano
|
|
77
|
-
|
|
78
|
-
O hotfix nasce com o Gate 3 em `forcedPauseGates` — o Gate 3 pausa **sempre**, mesmo em `trust: auto`. `gate-check` já sabe disso: lê `workType` do disco e `shouldPauseGate` força a pausa antes de checar qualquer outro sinal — rode direto, sem `--signals`:
|
|
79
|
-
|
|
80
|
-
```
|
|
81
|
-
morph-spec gate-check {feature} review [--json]
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
Escreva você mesmo `4-review/verifier.md` — o hotfix não despacha verificador nem revisor: `**Verdict:** SHIP|FIX`, `**Reviewed-SHA:** {git rev-parse HEAD}`, `## Checks` com C1 e C2 (`| Cn | PROVADO|NÃO PROVADO|FALHA | evidência |`, a evidência é a saída real do `verify` do passo 5), o diff do fix e `## Bloqueadores` (`Nenhum.` quando não há). Depois, **`AskUserQuestion` SEMPRE**:
|
|
85
|
-
|
|
86
|
-
```
|
|
87
|
-
question: "Gate 3 — Hotfix de {feature} pronto para ship?"
|
|
88
|
-
header: "Gate 3"
|
|
89
|
-
options:
|
|
90
|
-
- { label: "aprovado, ship", description: "Aceitar o fix e liberar para produção" }
|
|
91
|
-
- { label: "preciso ajustar", description: "Apontar correções antes de fechar" }
|
|
92
|
-
- { label: "rollback", description: "Desfazer o fix — voltar ao estado anterior" }
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
**NUNCA `morph-spec approve {feature} review --mode auto`** — o CLI recusa explicitamente essa combinação (gate `review` + `workType: hotfix` + aprovador `auto`) porque `forcedPauseGates` sobrepõe qualquer trust mode. Em contexto headless (sem `AskUserQuestion` disponível), **o `state-sync` NÃO cobre este caso**: ele é um hook `PostToolUse` com matcher `Write|Edit|AskUserQuestion`, e uma resposta em texto puro do usuário não é tool call — não gera evento e não grava gate nenhum. Esperar por ele deixa o Gate 3 por aprovar em silêncio. O caminho é registrar a aprovação humana explicitamente:
|
|
96
|
-
|
|
97
|
-
```
|
|
98
|
-
morph-spec approve {feature} review --approver "<nome de quem aprovou>"
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
`--approver` é a única assinatura que passa pelo backstop em headless — as outras rotas de `resolveApprovedBy` (`--mode auto`, e "sem TTY") resolvem para `"auto"` e são recusadas. Ela é **auto-declarada**: o CLI não consegue verificar que houve um humano, só recusa as assinaturas definitivamente não-humanas. Por isso: **nunca invente o nome** — use `--approver` só quando o humano de fato aprovou, senão o backstop do hotfix vira teatro.
|
|
102
|
-
|
|
103
|
-
### 7. Pós-gate (o "test loop → ship" de `MORPH.md` §2.1)
|
|
104
|
-
|
|
105
|
-
- Se o código mudou depois do verify do passo 5 (ajuste pedido no Gate 3), rode `morph-spec verify {feature}` de novo.
|
|
106
|
-
- Feche com `morph-spec finish {feature} --pr|--merge` — o mesmo encerramento único das demais features (arquiva commitando dentro de `morph/{f}`, desmonta). Num hotfix urgente o `--merge` (local, direto na default, integra na hora) costuma ser o caminho; use `--pr` quando o fix precisa passar por CI/review antes do merge — mas `--pr` **não integra**: sai com `finished: true` e `integrated: false`, `awaiting: "merge"`. Um hotfix "fechado" por `--pr` ainda não chegou na produção — não relate o incidente como resolvido até o merge. Ver `MORPH.md` §2.2.
|
|
107
|
-
- Não integre automaticamente — o usuário decide quando e por qual modo (`finish` toca a default ou o remoto). Feature legada sem `morph/{f}`: `finish` roteia para `morph-spec archive {feature}`.
|
|
108
|
-
|
|
109
|
-
## Anti-padrões
|
|
110
|
-
|
|
111
|
-
- Não pular o scout — mesmo sob pressão, o mapa de blast radius evita um segundo incidente causado pelo próprio fix.
|
|
112
|
-
- Não auto-aprovar o Gate 3 — nunca tente `morph-spec approve {feature} review --mode auto` num hotfix; o backstop server-side existe exatamente para isso.
|
|
113
|
-
- Não "fazer do jeito certo" às custas da velocidade — refatoração, cobertura extra, ou hardening que não bloqueia o sintoma atual vira item no roadmap-fora-hotfix, não neste diff.
|
|
114
|
-
- Não rodar suíte ad-hoc fora do `morph-spec verify` — a cadeia determinística é a única fonte de evidência aceita no `verifier.md`.
|
|
115
|
-
|
|
116
|
-
## Output esperado
|
|
117
|
-
|
|
118
|
-
- `.morph/features/{feature}/2-plan/plan.md` + `checks.json` — C1 sintoma ausente, C2 regressão, F1 fix
|
|
119
|
-
- `.morph/features/{feature}/3-implement/reports/F1.md` — o relatório da fatia, com a evidência real de teste
|
|
120
|
-
- `.morph/features/{feature}/4-review/verifier.md` — escrito pelo orquestrador: C1/C2 com evidência + diff, Gate 3 sempre humano
|
|
121
|
-
- Gate `plan` carimbado `approvedBy: "policy:hotfix"`; Gate 3 registrado em `feature.json` (autoritativo) com uma **assinatura humana** — `"manual"` pelo `state-sync` (resposta ao `AskUserQuestion`), o nome passado em `--approver`, ou `$USER` num terminal interativo. **Nunca `"auto"`** — é o que o backstop recusa.
|
|
122
|
-
|
|
123
|
-
## Referências
|
|
124
|
-
|
|
125
|
-
- `.morph/framework/MORPH.md` §2.1 — roteamento por tipo de trabalho
|
|
126
|
-
- `.morph/framework/MORPH.md` §5 — Gates de aprovação, gate humano forçado no hotfix
|
|
127
|
-
- `.morph/framework/MORPH.md` §6 — Sub-agents, persona de estágio scout, protocolo obrigatório
|
|
128
|
-
- `.claude/skills/morph-plan/SKILL.md` — roteamento que invoca esta skill
|
|
129
|
-
- `.claude/skills/morph-apply/SKILL.md` §3/§5 — prompt de dispatch e retomada por `report-check`
|
|
130
|
-
- `morph-spec create {feature} --type hotfix --json` — mostra a política do tipo (`scaffold`, `skippedGates`, `forcedPauseGates`) como o CLI a aplicou
|
|
131
|
-
- `morph-spec create {feature} --type hotfix` — nascimento com política de gates
|
|
132
|
-
- `morph-spec verify {feature} --json` — cadeia determinística build+testes+validadores
|
|
133
|
-
- `morph-spec gate-check {feature} review [--json]` — persiste a decisão de pausa (forçada por `workType: hotfix`) antes do Gate 3
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: morph-machine
|
|
3
|
-
description: Cuida da RAM e da CPU da máquina enquanto o morph-spec trabalha — fila de builds e testes pesados (heavy), processos órfãos, worktrees de sub-agent que sobram. Invoque quando a máquina ou o editor estiver lento ou sem RAM, quando um comando voltar "⏳ não rodou" ou sair com exit 3 (fila cheia), quando sobrar agent-* em worktrees/, ou antes de despachar vários sub-agents que compilam ou testam em paralelo.
|
|
4
|
-
version: core
|
|
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
|
-
user-invocable: false
|
|
7
|
-
cliVersion: "9.7.0"
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
# morph-machine
|
|
11
|
-
|
|
12
|
-
## Objetivo
|
|
13
|
-
|
|
14
|
-
Manter a máquina do dev utilizável enquanto o trabalho paralelo do morph-spec roda. Você aplica isto sozinho quando o sintoma aparece; o usuário não precisa pedir.
|
|
15
|
-
|
|
16
|
-
## Regras que não se negociam
|
|
17
|
-
|
|
18
|
-
- **Nunca** `taskkill /IM`, `pkill`, `killall` nem `Stop-Process -Name`: derrubam os MCPs de todas as sessões abertas. O único que encerra processo é `doctor --procs --prune`, e por PID.
|
|
19
|
-
- **Fila cheia não é erro de código.** `⏳ … não rodou`, `slots pesados ocupados` e exit 3 querem dizer que a fila já esperou o prazo dela (`heavy.waitTimeoutSec`). Não entra no loop de correção, não conta como tentativa e não é vermelho no `verify`. No máximo uma chamada nova; persistiu, siga sem aquela rodada e avise o usuário — nunca `sleep`/`until` nem retentativa agendada.
|
|
20
|
-
- **Nunca remova worktree** por `git worktree remove`, `rm -rf` ou `Remove-Item -Recurse`: atravessa a junction e apaga o conteúdo real da raiz. Só `finish`, `worktree remove` ou `worktree reap`.
|
|
21
|
-
- **Destrutivo pergunta antes.** `doctor --procs --prune` e `worktree reap` (sem `--dry-run`): mostre a lista e use `AskUserQuestion`.
|
|
22
|
-
|
|
23
|
-
## Sintoma → comando
|
|
24
|
-
|
|
25
|
-
| Sintoma | Comando | Como ler e o que fazer |
|
|
26
|
-
|---|---|---|
|
|
27
|
-
| Máquina ou editor lento, pouca RAM | `morph-spec doctor --procs` (só lê) | Cada linha diz órfão ou protegido, com a razão. Sem órfão, a pressão vem de fora (vmmem do WSL, IDE): diga isso e passe a sugestão de `.wslconfig` que o relatório traz. Com órfão, mostre a lista e ofereça `--prune`. |
|
|
28
|
-
| Comando voltou `⏳ … não rodou` ou exit 3 | `morph-spec heavy status` | Mostra quem segura cada vaga, há quanto tempo, e a RAM livre. A vaga solta sozinha (processo morto ou timeout). Vaga presa por sessão viva: diga ao usuário quem a segura. Se a causa for RAM e nenhuma vaga estiver presa, rode `doctor --procs`. |
|
|
29
|
-
| Vão rodar vários sub-agents pesados em paralelo | `morph-spec heavy status` antes | São 2 vagas por padrão. O que não couber espera na fila sem falhar, mas cada espera custa turnos: despache só o que cabe. |
|
|
30
|
-
| Build ou teste pesado avulso, fora do `verify` | `morph-spec heavy run -- <comando>` | Ou ligue o `heavy.gateBash` (abaixo) e o hook cuida disso. |
|
|
31
|
-
| Sobrou `agent-*` em `worktrees/` ou branch `morph-task/agent-*` | `morph-spec worktree reap --dry-run`, depois `worktree reap` | Só remove o que parou, está limpo e não tem commit exclusivo; o resto volta com a razão (`dirty`, `locked`…). `doctor --worktrees` lista tudo, inclusive árvore fora do contêiner. |
|
|
32
|
-
| A worktree precisa de arquivo fora do git (`.env`, segredos) | `.worktreeinclude` na raiz do repo | Um padrão por linha, sintaxe do gitignore. Copia só o que casa **e** é ignorado; nunca `node_modules`, build ou `.git`. O `setup` e o `provision` aplicam. |
|
|
33
|
-
| Editor pesado por causa das worktrees | `worktree.root` em `.morph/config/config.json` | Põe as worktrees fora da árvore aberta (caminho absoluto fora do projeto). `init` e `update` já gravam as exclusões no `.vscode/settings.json`. |
|
|
34
|
-
|
|
35
|
-
## Ligar o `heavy.gateBash`
|
|
36
|
-
|
|
37
|
-
Por padrão só o `verify`, o `e2e up` e o `heavy run` passam pela fila. O `dotnet build`, `dotnet test` ou `npm test` cru de um sub-agent não passa. Com `"heavy": { "gateBash": true }` em `.morph/config/config.json` (depois `morph-spec update`), um hook toma a vaga antes desses comandos e a devolve depois; sem vaga no prazo, a chamada é recusada com a causa.
|
|
38
|
-
|
|
39
|
-
Recomende (`AskUserQuestion`, com a opção recomendada primeiro) quando sub-agents rodam build ou teste cru em paralelo, quando há mais de uma sessão na máquina, ou quando já houve queda por RAM. **Nunca ligue sem perguntar:** o efeito é uma chamada recusada quando a fila enche.
|
|
40
|
-
|
|
41
|
-
Limites: não cobre `run_in_background`, PowerShell nem comando fora da lista; uma chamada negada por regra ou interrompida segura a vaga até o timeout dela.
|
|
42
|
-
|
|
43
|
-
## Referências
|
|
44
|
-
|
|
45
|
-
- `.morph/framework/CLI.md` — `### heavy`, `### worktree reap`, `### doctor --procs` e `### worktree.root`.
|
|
46
|
-
- `MORPH.md` §2.2 (worktrees) e a cláusula PROCESSOS do contrato de dispatch.
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: morph-review
|
|
3
|
-
description: Conduz o Gate 3 — despacha verificador ∥ revisor (∥ segurança, quando exigida) em contexto fresco sobre um SHA fixo e decide pelo gate-check
|
|
4
|
-
version: core
|
|
5
|
-
when_to_use: Use quando a fase review começar, com todas as fatias com relatório final e o verify da feature verde
|
|
6
|
-
user-invocable: true
|
|
7
|
-
cliVersion: "9.7.0"
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
# morph-review
|
|
11
|
-
|
|
12
|
-
## Objetivo
|
|
13
|
-
Responder, com evidência: **cada cenário do plano está provado, sem quebrar o que já funcionava?**
|
|
14
|
-
Três agentes independentes, cada um com o seu relatório em `4-review/`: `verifier.md` (prova cada
|
|
15
|
-
`Cn`), `reviewer.md` (escopo, arquitetura, regressão) e `security.md` (só com caminho sensível). O
|
|
16
|
-
Gate 3 decide por `**Verdict:** SHIP|FIX`, bloqueadores tipados e a cobertura dos `Cn` — não por
|
|
17
|
-
nota. Você não escreve relatório de review: os três arquivos são o retorno.
|
|
18
|
-
|
|
19
|
-
## Ritmo
|
|
20
|
-
- Comando em **primeiro plano**, com timeout. Só o `verify {feature}` de projeto grande passa do teto
|
|
21
|
-
de 10 min do Bash: aí `run_in_background` e espere a notificação. Nunca `sleep`/`until`.
|
|
22
|
-
- **Bloqueio de ambiente não é laço.** Slot pesado ocupado (exit 3 / `busy`), Docker fora: tente
|
|
23
|
-
**uma** vez mais; persistiu, siga — o `gate-check` pausa com a razão. Nunca agende retentativas.
|
|
24
|
-
|
|
25
|
-
## 1. Relatórios já íntegros?
|
|
26
|
-
`morph-spec report-check {feature} --json` (sem fatia) — também em sessão retomada: retomar não
|
|
27
|
-
reseta este passo. Leia `reviews.verifier|reviewer|security`: `complete` → **não re-despache** esse
|
|
28
|
-
papel; `partial: true` → passo 4 (PARCIAL); ausente → despache no passo 3.
|
|
29
|
-
|
|
30
|
-
## 2. Prova da suíte — uma rodada
|
|
31
|
-
Commite o trabalho da feature (`git add <paths>` + `git commit`) e rode
|
|
32
|
-
`morph-spec verify {feature} --ci --json` com `run_in_background`. Ele empurra a branch, espera o run
|
|
33
|
-
e grava o stamp do artefato que o run publicou; sem CI, roda local e diz por quê.
|
|
34
|
-
**Sem `--filter`, sempre**: o Gate 3 roda a suíte inteira. Esta é a única execução de testes do Gate 3 — nenhum agente
|
|
35
|
-
roda a suíte de novo. `repeatOf` no JSON = nada mudou, use aquela rodada; `reason: "stamp-reused"` = nada
|
|
36
|
-
fora de `.morph/` andou desde o último verify verde (local ou CI): ele vale e o CI não roda de novo.
|
|
37
|
-
- **Quando a saída mostrar `CI rodando`, despache (passo 3) sem esperar o fim**: o push e o
|
|
38
|
-
workflow já estão commitados e a foto da árvore não os acusa. Saiu `verify local`: espere o fim
|
|
39
|
-
antes do passo 3 — suíte local e `mutate` disputam a máquina. Exit 2 = trabalho fora de commit.
|
|
40
|
-
- Nó `e2e`: `pass` local → `morph-spec e2e status {feature} --json` → `baseUrl` vai ao verificador.
|
|
41
|
-
`fail` → correção (CI: `gh run view <id> --log-failed`). `skip` → quem classifica é o `gate-check`
|
|
42
|
-
(`classifyE2eSkip`): dispensa de projeto e `not applicable` (feature sem UI/spec/container no diff e sem
|
|
43
|
-
`prova: e2e`) passam; ambiente, `--skip-e2e` ou razão desconhecida pausam.
|
|
44
|
-
- `traceability.warnings` do verify vão ao revisor como sinal.
|
|
45
|
-
|
|
46
|
-
## 3. Dispatch — verificador ∥ revisor (∥ segurança)
|
|
47
|
-
`morph-spec report-check {feature} --before-eval --json` tira a foto da árvore e diz quem despachar:
|
|
48
|
-
`reviewModels.verifier.model` (opus com prompt/modelo ou mídia), `reviewModels.security.required`.
|
|
49
|
-
Anote `base` (merge-base com a default) e `sha` (`git rev-parse HEAD`). Blast radius: para cada
|
|
50
|
-
símbolo público do diff, `morph-spec graph affected <símbolo> --prod --json`; sem grafo
|
|
51
|
-
(`no-graph`/`not-found`/`ambiguous`), siga sem o blast radius — o revisor cai para `git grep` — e
|
|
52
|
-
registre a ausência no recado a ele. Cada agente nasce com contexto fresco e **nunca recebe relatório anterior** (ancoragem).
|
|
53
|
-
`chore` tem review leve: só o revisor (∥ segurança, quando exigida) — sem verificador, sem cobertura de
|
|
54
|
-
`Cn`, sem mutação. Despache todos na mesma resposta, **sem nome no dispatch**: com nome, o `agent_type` que o hook
|
|
55
|
-
`test-budget` lê vira o nome, e o guard de review não reconhece o papel.
|
|
56
|
-
```
|
|
57
|
-
dispatch Agent (subagent_type: "morph-verifier", model: {reviewModels.verifier.model}) with prompt:
|
|
58
|
-
feature, base, sha, JSON do verify (nós, e2e, URL) se já terminou, 1-design/mockups.md e
|
|
59
|
-
3-implement/evidencias/*.md se existirem. Grave .morph/features/{feature}/4-review/verifier.md.
|
|
60
|
-
Não rode `morph-spec mutate` até eu avisar que revisor e segurança terminaram.
|
|
61
|
-
NUNCA `git checkout --`: descarta trabalho não commitado.
|
|
62
|
-
dispatch Agent (subagent_type: "morph-reviewer") with prompt:
|
|
63
|
-
feature, base, sha, blast radius (ou a ausência dele), traceability.warnings.
|
|
64
|
-
Grave .morph/features/{feature}/4-review/reviewer.md.
|
|
65
|
-
dispatch Agent (subagent_type: "morph-security") with prompt: ← só com security.required
|
|
66
|
-
feature, base, sha, reviewModels.security.reasons. Grave .morph/features/{feature}/4-review/security.md.
|
|
67
|
-
```
|
|
68
|
-
O prompt leva só os campos acima. O que você notou no loop chega ao revisor como
|
|
69
|
-
`traceability.warnings` ou como item da `## Errata` do plano, nunca como lista solta de "fatos do
|
|
70
|
-
loop": é histórico da conversa (MORPH §6) e ancora quem nasceu para olhar sem ele.
|
|
71
|
-
O contrato fixo (o que provar, `**Reviewed-SHA:**` obrigatório, formato, PARCIAL, read-only) mora no
|
|
72
|
-
corpo de cada persona e em `.morph/framework/evals/review-checklist.md`. Tipo não registrado:
|
|
73
|
-
`general-purpose` com o campo `persona` de `.morph/framework/agents.json` no topo do prompt.
|
|
74
|
-
|
|
75
|
-
Revisor e segurança voltaram: diga ao verificador, por `SendMessage`, que a mutação está liberada —
|
|
76
|
-
opcional, no máximo 3 mutantes com `expect`, só para guarda sem teste que a morda (review-checklist).
|
|
77
|
-
Achou o teste por leitura: não rode.
|
|
78
|
-
|
|
79
|
-
## 4. Ao retomar — higiene antes de ler o veredito
|
|
80
|
-
Não rode build nem teste enquanto um agente está `running`. Com todos de volta,
|
|
81
|
-
`morph-spec report-check {feature} --json`:
|
|
82
|
-
- `tree.sinceBeforeEval.changed` vazio e `tree.markers` vazio = árvore como antes do dispatch.
|
|
83
|
-
Arquivo listado = mutação que ficou no disco: `morph-spec mutate --restore` devolve os bytes do
|
|
84
|
-
snapshot; fora de uma rodada de mutação, desfaça linha a linha pelo diff.
|
|
85
|
-
**NUNCA `git checkout -- src/` aqui**: o checkout apaga junto tudo o que não foi commitado depois
|
|
86
|
-
da prova (correção de bloqueador, trabalho de outra sessão).
|
|
87
|
-
- `tree.sinceBeforeEval` `null` = sem foto; `tree` `null` = git não respondeu.
|
|
88
|
-
|
|
89
|
-
Depois leia os relatórios e rode `morph-spec worktree reap --json`.
|
|
90
|
-
|
|
91
|
-
**PARCIAL** (`reviews.<papel>.partial: true`): não leia veredito dele e não re-despache frio —
|
|
92
|
-
retome o MESMO agente por `SendMessage`, colando `tree.dirty` e `tree.commits`. Só se o id não
|
|
93
|
-
retomar, despache um novo.
|
|
94
|
-
|
|
95
|
-
## 5. Bloqueadores
|
|
96
|
-
O avaliador também erra: **antes de editar, reverifique cada bloqueador no código** — evidência que
|
|
97
|
-
não se reproduz vira pergunta ao mesmo agente, não correção. Confirmado: corrija (loop da
|
|
98
|
-
`morph-apply`), commite, rode `verify {feature}` local (o stamp verde dele é a prova: um `--ci` depois
|
|
99
|
-
reusa, não roda de novo) e uma foto `--before-eval` nova.
|
|
100
|
-
Retome por `SendMessage` TODO agente exigido, com o `sha` novo e `tree.dirty`/`tree.commits`: quem
|
|
101
|
-
abriu bloqueadores **confirme só os bloqueadores** (retomando o MESMO agente que os abriu); os outros
|
|
102
|
-
julgam só o delta `{sha anterior}..{sha novo}` — o que a correção abriu. `reviewModels.security.required`
|
|
103
|
-
virou `true` agora: despache a segurança. Ninguém reavalia a feature inteira, e **nota nunca motiva
|
|
104
|
-
nova rodada**. Agente encerrado: despache um novo dizendo que é uma confirmação — o relatório é
|
|
105
|
-
append-only e vale o último `**Verdict:**`. Cada relatório carrega o `**Reviewed-SHA:**` —
|
|
106
|
-
obrigatório: o `approve` recusa quando o código andou depois de QUALQUER um deles.
|
|
107
|
-
|
|
108
|
-
## 6. Gate 3
|
|
109
|
-
`morph-spec gate-check {feature} review [--json]` lê os relatórios exigidos, a cobertura dos `Cn` e
|
|
110
|
-
os demais sinais do disco. Violação das verificações mecânicas entra por
|
|
111
|
-
`--signals '{"standardsViolations":[...]}'`. Forçar a passagem apesar de uma pausa:
|
|
112
|
-
`morph-spec gate-decision {feature} review --pause false --reason "..."`. Nunca edite `feature.json`.
|
|
113
|
-
|
|
114
|
-
**`pause === true`** → `AskUserQuestion`:
|
|
115
|
-
```
|
|
116
|
-
question: "Gate 3 — Review de {feature} aprovado?{ reason ? ' Sinal: ' + reason : '' }"
|
|
117
|
-
header: "Gate 3"
|
|
118
|
-
options:
|
|
119
|
-
- { label: "aprovado, fechar feature", description: "Próximo passo: morph-spec finish --pr|--merge (morph-apply §8)" }
|
|
120
|
-
- { label: "preciso ajustar", description: "Apontar correções antes de fechar" }
|
|
121
|
-
- { label: "rollback", description: "Voltar para implement" }
|
|
122
|
-
```
|
|
123
|
-
**`pause === false`** → resumo de 3 linhas (vereditos, cenários provados, bloqueadores: 0) e
|
|
124
|
-
`morph-spec approve {feature} review --mode auto`. A pergunta nomeia a feature: é por ela que o hook
|
|
125
|
-
`state-sync` grava a aprovação. Fechar é da `morph-apply` §8.
|
|
126
|
-
|
|
127
|
-
## Referências
|
|
128
|
-
- `.morph/framework/evals/review-checklist.md` — o que cada papel procura e o formato dos relatórios
|
|
129
|
-
- `morph-spec verify|mutate|report-check|gate-check` — `.morph/framework/CLI.md`
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: morph-standards
|
|
3
|
-
description: Localiza um standard específico via busca server-side (morph-spec standards --find) e carrega só a seção necessária (--show id#âncora)
|
|
4
|
-
version: core
|
|
5
|
-
when_to_use: Use quando precisar consultar um standard específico durante a implementação
|
|
6
|
-
user-invocable: true
|
|
7
|
-
cliVersion: "9.7.0"
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
# morph-standards
|
|
11
|
-
|
|
12
|
-
## Objetivo
|
|
13
|
-
Achar o standard certo para a fatia e pôr no contexto só o trecho que ela precisa. Nunca abra o
|
|
14
|
-
`STANDARDS.json` inteiro.
|
|
15
|
-
|
|
16
|
-
## Quando invocar
|
|
17
|
-
Durante a implementação, quando surgir dúvida de padrão (arquitetura, contrato, qualidade, teste)
|
|
18
|
-
que o `plan.md` e os standards da fatia não resolvem.
|
|
19
|
-
|
|
20
|
-
## O que fazer
|
|
21
|
-
|
|
22
|
-
1. **Digest.** Busque no servidor:
|
|
23
|
-
```
|
|
24
|
-
morph-spec standards --find "<domínio/tecnologia da fatia>" [--category <cat>] [--tags <a,b>] [--json]
|
|
25
|
-
```
|
|
26
|
-
Devolve o top 3 com `id`, `path`, `digest` e as chaves de âncora. O digest é um resumo, não o
|
|
27
|
-
texto do standard: serve para decidir se o standard se aplica e muitas vezes basta para aplicá-lo.
|
|
28
|
-
|
|
29
|
-
2. **Seção.** O digest não bastou → leia só a seção que importa:
|
|
30
|
-
```
|
|
31
|
-
morph-spec standards --show <id>#<âncora>
|
|
32
|
-
```
|
|
33
|
-
A âncora é uma das chaves que o `--find` listou, ou o slug de qualquer heading do `.md`.
|
|
34
|
-
`morph-spec standards --show <id>` mostra o digest e a tabela de âncoras.
|
|
35
|
-
|
|
36
|
-
3. **Arquivo inteiro** (campo `path`, sob `.morph/framework/standards/`) só quando a fatia toca o
|
|
37
|
-
standard todo ou precisa de um exemplo que nenhuma seção isolada traz.
|
|
38
|
-
|
|
39
|
-
4. Dois standards em conflito → adote o mais específico ao stack do projeto.
|
|
40
|
-
|
|
41
|
-
5. Registre no `**Standards:**` do relatório da fatia (`3-implement/reports/F{n}.md`) qual standard (e qual âncora) aplicou e, havendo, o conflito.
|
|
42
|
-
|
|
43
|
-
## Sem query clara
|
|
44
|
-
`morph-spec standards` sem flag lista categorias e contagens; use para escolher o `--category` de
|
|
45
|
-
um `--find` em seguida.
|
|
46
|
-
|
|
47
|
-
## Quando nenhum standard cobre o caso
|
|
48
|
-
Registre no relatório da fatia o critério adotado. Não invente standard: padrão não documentado é dívida.
|
|
49
|
-
|
|
50
|
-
## Referências
|
|
51
|
-
- `.morph/framework/CLI.md` — seção `standards` (flags, `--json`, falhas)
|
|
52
|
-
- `.morph/framework/MORPH.md` — §4 (Como consultar Standards)
|