@polymorphism-tech/morph-spec 9.0.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.
Files changed (345) hide show
  1. package/CLAUDE.md +8 -9
  2. package/README.md +38 -36
  3. package/bin/morph-spec.js +11 -63
  4. package/bin/validate.js +1 -39
  5. package/claude-plugin.json +1 -1
  6. package/docs/CHEATSHEET.md +1 -1
  7. package/docs/QUICKSTART.md +1 -1
  8. package/framework/CLAUDE.md +2 -1
  9. package/framework/MORPH.md +3 -3
  10. package/framework/agents.json +19 -11
  11. package/framework/commands/morph-apply.md +1 -1
  12. package/framework/commands/morph-status.md +1 -1
  13. package/framework/docs/CLI.md +22 -31
  14. package/framework/evals/review-checklist.md +12 -2
  15. package/framework/hooks/README.md +8 -44
  16. package/framework/hooks/claude-code/core/block-destructive-worktree-removal.js +6 -49
  17. package/framework/hooks/claude-code/core/block-raw-worktree-add.js +2 -35
  18. package/framework/hooks/claude-code/core/chain.js +4 -65
  19. package/framework/hooks/claude-code/core/comment-guard.js +2 -16
  20. package/framework/hooks/claude-code/core/enforce-phase-writes.js +6 -50
  21. package/framework/hooks/claude-code/core/gate-guard.js +7 -67
  22. package/framework/hooks/claude-code/core/graph-refresh-kick.js +3 -24
  23. package/framework/hooks/claude-code/core/heavy-gate.js +3 -21
  24. package/framework/hooks/claude-code/core/heavy-release.js +2 -13
  25. package/framework/hooks/claude-code/core/loop-detect.js +2 -31
  26. package/framework/hooks/claude-code/core/pre-bash-denylist.js +0 -4
  27. package/framework/hooks/claude-code/core/protect-spec-files.js +7 -67
  28. package/framework/hooks/claude-code/core/state-sync.js +12 -68
  29. package/framework/hooks/claude-code/core/telemetry-log.js +12 -93
  30. package/framework/hooks/claude-code/core/validate-completion.js +11 -57
  31. package/framework/hooks/claude-code/core/warn-bash-source-write.js +1 -9
  32. package/framework/hooks/claude-code/core/worktree-context.js +10 -110
  33. package/framework/hooks/claude-code/core/worktree-create.js +6 -70
  34. package/framework/hooks/claude-code/core/worktree-env-inject.js +5 -56
  35. package/framework/hooks/claude-code/core/worktree-remove.js +5 -31
  36. package/framework/hooks/claude-code/statusline.sh +11 -11
  37. package/framework/hooks/shared/activity-logger.js +9 -89
  38. package/framework/hooks/shared/agent-reap.js +2 -17
  39. package/framework/hooks/shared/build-check.js +6 -75
  40. package/framework/hooks/shared/claim-registry.js +9 -119
  41. package/framework/hooks/shared/command-tokens.js +6 -51
  42. package/framework/hooks/shared/comment-rules.js +5 -20
  43. package/framework/hooks/shared/comment-scanner.js +6 -25
  44. package/framework/hooks/shared/comment-stripper.js +11 -85
  45. package/framework/hooks/shared/e2e-check.js +0 -0
  46. package/framework/hooks/shared/errata.js +2 -15
  47. package/framework/hooks/shared/feature-locator.js +11 -95
  48. package/framework/hooks/shared/frontend-locations.js +1 -3
  49. package/framework/hooks/shared/gate-question.js +1 -7
  50. package/framework/hooks/shared/git-exclude.js +3 -20
  51. package/framework/hooks/shared/git-paths.js +8 -104
  52. package/framework/hooks/shared/graph-freshness.js +22 -166
  53. package/framework/hooks/shared/graph-refresh.js +21 -149
  54. package/framework/hooks/shared/heavy-command.js +4 -12
  55. package/framework/hooks/shared/hook-response.js +8 -83
  56. package/framework/hooks/shared/morph-cli.js +8 -52
  57. package/framework/hooks/shared/payload-utils.js +10 -132
  58. package/framework/hooks/shared/phase-utils.js +1 -42
  59. package/framework/hooks/shared/redact-secrets.js +4 -15
  60. package/framework/hooks/shared/reparse-scan.js +6 -66
  61. package/framework/hooks/shared/slice-progress.js +4 -23
  62. package/framework/hooks/shared/source-files.js +4 -17
  63. package/framework/hooks/shared/state-reader.js +13 -183
  64. package/framework/hooks/shared/state-writer.js +8 -52
  65. package/framework/hooks/shared/stdin-reader.js +1 -11
  66. package/framework/hooks/shared/telemetry-logger.js +7 -67
  67. package/framework/hooks/shared/transcript-usage.js +7 -29
  68. package/framework/hooks/shared/worktree-root.js +7 -29
  69. package/framework/rules/csharp-standards.md +1 -1
  70. package/framework/rules/frontend-standards.md +1 -0
  71. package/framework/rules/hangfire-standards.md +1 -1
  72. package/framework/rules/neon-standards.md +1 -1
  73. package/framework/rules/nextjs-standards.md +1 -1
  74. package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
  75. package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
  76. package/framework/skills/core/morph-apply/SKILL.md +4 -4
  77. package/framework/skills/core/morph-hotfix/SKILL.md +3 -3
  78. package/framework/skills/core/morph-machine/SKILL.md +1 -1
  79. package/framework/skills/core/morph-media/SKILL.md +1 -1
  80. package/framework/skills/core/morph-plan/SKILL.md +9 -7
  81. package/framework/skills/core/morph-review/SKILL.md +9 -6
  82. package/framework/skills/core/morph-standards/SKILL.md +1 -1
  83. package/framework/skills/core/morph-uiux/SKILL.md +29 -12
  84. package/framework/standards/STANDARDS.json +36 -14
  85. package/framework/standards/STANDARDS.meta.json +16 -2
  86. package/framework/standards/ai-agents/agent-archetypes.md +2 -2
  87. package/framework/standards/ai-agents/agent-session.md +1 -1
  88. package/framework/standards/ai-agents/conversational-agent-with-phases.md +4 -4
  89. package/framework/standards/ai-agents/durable-workflows-hitl.md +3 -3
  90. package/framework/standards/ai-agents/guardrails.md +1 -1
  91. package/framework/standards/ai-agents/multi-agent-patterns.md +2 -2
  92. package/framework/standards/ai-agents/observability-patterns.md +1 -1
  93. package/framework/standards/ai-agents/production.md +1 -1
  94. package/framework/standards/ai-agents/prompt-sources.md +2 -2
  95. package/framework/standards/ai-agents/providers/model-registry.md +1 -1
  96. package/framework/standards/ai-agents/rag-custom-pgvector.md +2 -2
  97. package/framework/standards/ai-agents/setup.md +2 -2
  98. package/framework/standards/ai-agents/sweet-spot.md +2 -2
  99. package/framework/standards/ai-agents/tool-adapters.md +0 -2
  100. package/framework/standards/ai-agents/vector-data-extensions.md +4 -4
  101. package/framework/standards/ai-agents/workflows.md +1 -1
  102. package/framework/standards/architecture/code-comments.md +1 -1
  103. package/framework/standards/architecture/vertical-slice/vertical-slice.md +1 -1
  104. package/framework/standards/backend/api/validation.md +1 -1
  105. package/framework/standards/backend/dotnet/testing.md +10 -4
  106. package/framework/standards/backend/dotnet/vsa-handler-patterns.md +5 -5
  107. package/framework/standards/backend/integrations/hangfire/hangfire-jobs.md +1 -1
  108. package/framework/standards/backend/integrations/neon-auth/neon-auth.md +2 -2
  109. package/framework/standards/data/nosql/cache/redis.md +1 -1
  110. package/framework/standards/data/nosql/cosmos-db.md +3 -3
  111. package/framework/standards/frontend/admin-app/forms.md +1 -1
  112. package/framework/standards/frontend/design-system/art-direction.md +88 -0
  113. package/framework/standards/frontend/design-system/premium-finish.md +77 -2
  114. package/framework/standards/frontend/nextjs/testing.md +10 -6
  115. package/framework/standards/infrastructure/neon/neon-pgvector.md +5 -5
  116. package/framework/templates/.idea/morph-templates.xml +92 -0
  117. package/framework/templates/.vscode/morph-templates.code-snippets +186 -0
  118. package/framework/templates/CLAUDE.md.core.template +3 -3
  119. package/framework/templates/IDE-SNIPPETS.md +262 -262
  120. package/framework/templates/REGISTRY.json +9 -9
  121. package/framework/templates/code/dotnet/abstractions/api-endpoint.cs +7 -7
  122. package/framework/templates/code/dotnet/feature/request.cs.hbs +4 -4
  123. package/framework/templates/code/dotnet/feature/response.cs.hbs +4 -4
  124. package/framework/templates/code/sql/ai-agents/pgvector-embeddings-migration.sql.template +91 -91
  125. package/framework/templates/docs/plan.md +3 -1
  126. package/framework/templates/docs/ui-mockups.md +4 -0
  127. package/framework/templates/frontend/nextjs/client-component.tsx.hbs +26 -26
  128. package/framework/templates/frontend/nextjs/feature-form.tsx.hbs +56 -56
  129. package/framework/templates/frontend/nextjs/tsconfig.json.hbs +26 -26
  130. package/framework/templates/infrastructure/docker/Dockerfile.template +58 -58
  131. package/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -38
  132. package/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -48
  133. package/framework/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +45 -45
  134. package/framework/templates/infrastructure/github/actions/health-check/action.yml.hbs +27 -27
  135. package/framework/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +59 -59
  136. package/framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +39 -39
  137. package/framework/templates/meta-prompts/fusion/fusion-agent.md +76 -76
  138. package/framework/templates/meta-prompts/fusion/fusion-aggregator.md +100 -100
  139. package/framework/templates/state.template.json +17 -17
  140. package/framework/templates/ui/design-system.css +226 -226
  141. package/package.json +1 -1
  142. package/src/commands/context/context-refresh.js +0 -16
  143. package/src/commands/dashboard/dashboard.js +2 -8
  144. package/src/commands/e2e/e2e.js +17 -104
  145. package/src/commands/graph/affected.js +0 -14
  146. package/src/commands/graph/build.js +11 -50
  147. package/src/commands/graph/explain.js +0 -16
  148. package/src/commands/graph/status.js +1 -12
  149. package/src/commands/mcp/mcp-setup.js +4 -62
  150. package/src/commands/observability/cost.js +5 -57
  151. package/src/commands/observability/telemetry.js +1 -14
  152. package/src/commands/project/branch.js +4 -45
  153. package/src/commands/project/claim.js +4 -48
  154. package/src/commands/project/doctor.js +48 -302
  155. package/src/commands/project/env.js +1 -27
  156. package/src/commands/project/fleet.js +3 -32
  157. package/src/commands/project/init.js +4 -68
  158. package/src/commands/project/install-plugin-cmd.js +0 -1
  159. package/src/commands/project/standards.js +1 -62
  160. package/src/commands/project/status.js +0 -53
  161. package/src/commands/project/update.js +31 -239
  162. package/src/commands/project/worktree.js +108 -882
  163. package/src/commands/scaffold/scaffold.js +0 -25
  164. package/src/commands/state/advance.js +14 -85
  165. package/src/commands/state/approve.js +15 -97
  166. package/src/commands/state/archive.js +12 -64
  167. package/src/commands/state/auto-approval.js +2 -5
  168. package/src/commands/state/create.js +22 -109
  169. package/src/commands/state/delete.js +11 -63
  170. package/src/commands/state/finish.js +98 -475
  171. package/src/commands/state/gate-check.js +22 -132
  172. package/src/commands/state/gate-decision.js +3 -39
  173. package/src/commands/state/handoff.js +3 -30
  174. package/src/commands/state/list.js +14 -84
  175. package/src/commands/state/report-check.js +8 -58
  176. package/src/commands/state/retype.js +4 -26
  177. package/src/commands/validation/index.js +0 -3
  178. package/src/commands/validation/mutate.js +11 -11
  179. package/src/commands/validation/plan-check.js +4 -2
  180. package/src/commands/validation/tests-audit.js +7 -0
  181. package/src/commands/validation/validate-feature.js +10 -97
  182. package/src/commands/validation/verify.js +30 -113
  183. package/src/core/paths/output-schema.js +2 -101
  184. package/src/core/state/feature-identity.js +1 -25
  185. package/src/core/state/gate-order.js +0 -27
  186. package/src/core/state/lifecycle-audit.js +8 -100
  187. package/src/core/state/state-manager.js +22 -304
  188. package/src/core/templates/template-registry.js +2 -97
  189. package/src/core/templates/template-renderer.js +13 -93
  190. package/src/core/templates/template-seed.js +0 -1
  191. package/src/core/work-types.js +1 -36
  192. package/src/dashboard/app/App.jsx +1 -8
  193. package/src/dashboard/app/components/ActivityFeed.jsx +0 -5
  194. package/src/dashboard/app/components/CommandPalette.jsx +0 -7
  195. package/src/dashboard/app/components/DetailPanel.jsx +1 -5
  196. package/src/dashboard/app/components/EntityLink.jsx +0 -12
  197. package/src/dashboard/app/components/ErrorBoundary.jsx +1 -8
  198. package/src/dashboard/app/components/KnowledgeMarkdown.jsx +0 -11
  199. package/src/dashboard/app/components/Markdown.jsx +0 -9
  200. package/src/dashboard/app/components/PhaseRail.jsx +0 -11
  201. package/src/dashboard/app/components/SearchFilter.jsx +0 -4
  202. package/src/dashboard/app/components/Sidebar.jsx +0 -5
  203. package/src/dashboard/app/hooks/useMorphQuery.js +1 -11
  204. package/src/dashboard/app/hooks/usePref.js +1 -5
  205. package/src/dashboard/app/lib/format.js +0 -2
  206. package/src/dashboard/app/lib/phases.js +1 -5
  207. package/src/dashboard/app/lib/project.js +0 -12
  208. package/src/dashboard/app/main.jsx +13 -13
  209. package/src/dashboard/app/pages/AgentMap.jsx +1 -8
  210. package/src/dashboard/app/pages/FeatureDetail.jsx +1 -5
  211. package/src/dashboard/app/pages/Features.jsx +1 -8
  212. package/src/dashboard/app/pages/Guide.jsx +0 -1
  213. package/src/dashboard/app/pages/HookInspector.jsx +2 -23
  214. package/src/dashboard/app/pages/PhasePipeline.jsx +0 -3
  215. package/src/dashboard/app/pages/Portfolio.jsx +0 -1
  216. package/src/dashboard/app/pages/RulesMap.jsx +1 -16
  217. package/src/dashboard/app/pages/SkillsLibrary.jsx +1 -16
  218. package/src/dashboard/app/pages/Standards.jsx +2 -17
  219. package/src/dashboard/scanner/activity-scanner.js +10 -69
  220. package/src/dashboard/scanner/agents-scanner.js +1 -23
  221. package/src/dashboard/scanner/docs-scanner.js +0 -6
  222. package/src/dashboard/scanner/feature-status.js +2 -5
  223. package/src/dashboard/scanner/features-scanner.js +10 -66
  224. package/src/dashboard/scanner/hooks-scanner.js +5 -28
  225. package/src/dashboard/scanner/index.js +0 -4
  226. package/src/dashboard/scanner/portfolio.js +5 -29
  227. package/src/dashboard/scanner/project-api.js +8 -54
  228. package/src/dashboard/scanner/rules-scanner.js +1 -2
  229. package/src/dashboard/scanner/skills-scanner.js +2 -12
  230. package/src/dashboard/scanner/standards-scanner.js +2 -6
  231. package/src/dashboard/vite-plugin-morph-data.js +5 -19
  232. package/src/dashboard/vite.config.js +24 -24
  233. package/src/lib/ai/ai-checks.js +7 -52
  234. package/src/lib/ai/ai-project-scan.js +14 -108
  235. package/src/lib/ai/code-audit.js +7 -63
  236. package/src/lib/ai/pin-drift.js +8 -51
  237. package/src/lib/ai/registry-audit.js +11 -90
  238. package/src/lib/ci/ci-verify.js +4 -19
  239. package/src/lib/ci/github-ci.js +9 -37
  240. package/src/lib/ci/workflow-scaffold.js +14 -10
  241. package/src/lib/detectors/claude-config-detector.js +13 -74
  242. package/src/lib/detectors/index.js +4 -50
  243. package/src/lib/e2e/applicability.js +37 -0
  244. package/src/lib/e2e/compose-env.js +5 -66
  245. package/src/lib/e2e/stack-teardown.js +6 -40
  246. package/src/lib/generators/architecture-scanner.js +18 -156
  247. package/src/lib/generators/handoff-generator.js +9 -53
  248. package/src/lib/generators/scaffold-generator.js +5 -101
  249. package/src/lib/generators/settings-generator.js +4 -37
  250. package/src/lib/git/branch-classifier.js +11 -84
  251. package/src/lib/git/default-branch.js +14 -169
  252. package/src/lib/git/evidence-staleness.js +1 -0
  253. package/src/lib/git/gh.js +2 -17
  254. package/src/lib/git/pending-prs.js +6 -37
  255. package/src/lib/git/pr-files.js +3 -28
  256. package/src/lib/git/pr-index.js +3 -34
  257. package/src/lib/git/tree-fingerprint.js +3 -15
  258. package/src/lib/git/tree-state.js +6 -33
  259. package/src/lib/graph/god-nodes.js +2 -22
  260. package/src/lib/graph/graph-health.js +3 -24
  261. package/src/lib/graph/graph-loader.js +5 -56
  262. package/src/lib/graph/graphify-runtime.js +7 -37
  263. package/src/lib/graph/graphifyignore.js +8 -74
  264. package/src/lib/graph/sanitize.js +16 -136
  265. package/src/lib/heavy/cleanup.js +1 -1
  266. package/src/lib/installers/effects.js +8 -93
  267. package/src/lib/installers/mcp-installer.js +9 -169
  268. package/src/lib/installers/memory-installer.js +4 -27
  269. package/src/lib/installers/templates-reconcile.js +5 -60
  270. package/src/lib/mutation/adapters.js +6 -17
  271. package/src/lib/mutation/dotnet-introspection.js +20 -106
  272. package/src/lib/mutation/runner.js +23 -75
  273. package/src/lib/mutation/subset.js +1 -4
  274. package/src/lib/mutation/trx.js +0 -1
  275. package/src/lib/plan/artifact-vocabulary.js +5 -25
  276. package/src/lib/plan/checks.js +34 -33
  277. package/src/lib/plan/plan-parser.js +7 -8
  278. package/src/lib/projects/registry.js +7 -44
  279. package/src/lib/review-reports.js +11 -26
  280. package/src/lib/risk-detector.js +41 -173
  281. package/src/lib/specs/adr-index.js +6 -34
  282. package/src/lib/specs/frontmatter.js +2 -15
  283. package/src/lib/specs/gfm-table.js +1 -7
  284. package/src/lib/specs/revocations.js +1 -14
  285. package/src/lib/specs/screen-checklist.js +47 -124
  286. package/src/lib/stack/dotnet-build-ignores.js +2 -6
  287. package/src/lib/stack/stack-profile.js +1 -28
  288. package/src/lib/stack/stack-scan.js +1 -8
  289. package/src/lib/stack-filter.js +4 -27
  290. package/src/lib/standards/registry.js +1 -7
  291. package/src/lib/standards/sections.js +2 -13
  292. package/src/lib/standards/verified-against.js +19 -191
  293. package/src/lib/tasks/eval-node.js +21 -169
  294. package/src/lib/tasks/linux-runner.js +18 -142
  295. package/src/lib/tasks/test-nodes.js +43 -240
  296. package/src/lib/tasks/test-runner.js +43 -341
  297. package/src/lib/telemetry/metrics.js +7 -36
  298. package/src/lib/telemetry/telemetry-reader.js +13 -125
  299. package/src/lib/telemetry/verify-event.js +2 -30
  300. package/src/lib/tests-audit/audit.js +96 -0
  301. package/src/lib/validators/code-budget/code-budget-validator.js +4 -44
  302. package/src/lib/validators/code-budget/index.js +0 -7
  303. package/src/lib/validators/contracts/contract-compliance-validator.js +2 -24
  304. package/src/lib/validators/contracts/index.js +0 -6
  305. package/src/lib/validators/nextjs/index.js +0 -5
  306. package/src/lib/validators/nextjs/next-component-validator.js +4 -81
  307. package/src/lib/validators/packages/index.js +0 -6
  308. package/src/lib/validators/packages/package-validator.js +6 -56
  309. package/src/lib/validators/reuse/index.js +0 -8
  310. package/src/lib/validators/reuse/reuse-validator.js +11 -101
  311. package/src/lib/validators/reuse/symbol-scanner.js +6 -62
  312. package/src/lib/validators/traceability-check.js +5 -63
  313. package/src/lib/validators/validation-runner.js +21 -158
  314. package/src/lib/validators/verify-runner.js +85 -376
  315. package/src/lib/work-type-detector.js +5 -67
  316. package/src/lib/worktree/docker-audit.js +17 -136
  317. package/src/lib/worktree/env-allocator.js +10 -98
  318. package/src/lib/worktree/feature-truth.js +12 -115
  319. package/src/lib/worktree/finish-backup.js +32 -242
  320. package/src/lib/worktree/fleet-scanner.js +13 -95
  321. package/src/lib/worktree/ignored-triage.js +15 -91
  322. package/src/lib/worktree/vscode-settings.js +2 -3
  323. package/src/lib/worktree/worktree-audit.js +21 -213
  324. package/src/lib/worktree/worktree-include.js +3 -5
  325. package/src/scripts/global-install.js +3 -9
  326. package/src/scripts/install-plugin.js +1 -13
  327. package/src/scripts/setup-infra.js +17 -147
  328. package/src/utils/agents-installer.js +29 -276
  329. package/src/utils/banner.js +4 -25
  330. package/src/utils/claude-md-injector.js +1 -37
  331. package/src/utils/claude-settings-manager.js +1 -52
  332. package/src/utils/file-copier.js +11 -95
  333. package/src/utils/hooks-installer.js +21 -298
  334. package/src/utils/skills-installer.js +4 -101
  335. package/src/utils/version-checker.js +4 -83
  336. package/framework/commands/morph-proposal.md +0 -9
  337. package/framework/hooks/git/commit-msg/conventional-commits.sh +0 -33
  338. package/framework/hooks/git/pre-commit/agents.sh +0 -25
  339. package/framework/hooks/git/pre-commit/orchestrator.sh +0 -64
  340. package/framework/hooks/git/pre-push/run-tests.sh +0 -44
  341. package/src/commands/utils/index.js +0 -3
  342. package/src/lib/detectors/design-system-detector.js +0 -188
  343. package/src/lib/generators/design-system-generator.js +0 -508
  344. package/src/lib/specs/old-format.js +0 -68
  345. package/src/utils/agent-id-mapper.js +0 -11
package/CLAUDE.md CHANGED
@@ -34,7 +34,7 @@ npm run docs
34
34
  npm run generate
35
35
  ```
36
36
 
37
- No build step — pure ESM JavaScript, runs directly via Node.js 18+.
37
+ No build step — pure ESM JavaScript, runs directly via Node.js 22+.
38
38
 
39
39
  ## Architecture
40
40
 
@@ -49,7 +49,7 @@ No build step — pure ESM JavaScript, runs directly via Node.js 18+.
49
49
  - `workflows/` — Workflow type detector
50
50
  - **`src/lib/`** — Libraries and subsystems:
51
51
  - `validators/` — Validators run by the `verify` validators node (code-budget, contracts, nextjs, packages, reuse)
52
- - `generators/` — Code generation (recap, context, handoff)
52
+ - `generators/` — Code generation (architecture context, handoff, scaffold, settings)
53
53
  - `stack-filter.js` — Stack-aware asset filtering via YAML frontmatter `stacks:` tags
54
54
  - `installers/` — Agents, skills, hooks installers
55
55
  - **`src/utils/`** — Shared utilities (logger, banner, file-copier, claude-settings-manager, agents-installer, skills-installer, hooks-installer)
@@ -79,7 +79,7 @@ No build step — pure ESM JavaScript, runs directly via Node.js 18+.
79
79
 
80
80
  **Stack-aware filtering:** Assets declare `stacks: ['dotnet']` in YAML frontmatter or `stack: ['dotnet']` in `agents.json`. `setup-infra.js` reads `config.json → project.stack`, splits into tags, and installs only matching assets.
81
81
 
82
- **Personas, not tiers:** `agents.json` has 10 flat personas — 6 domain implementers (dotnet-senior, ef-modeler, maf-expert, nextjs-expert, ui-designer, infra-engineer), the 3 read-only Gate 3 roles (verifier, reviewer, security) and 1 stage persona (`scout`, read-only). `model` is sized per stage: `sonnet` for implementers, `scout`, `verifier` and `reviewer`; `security` is `opus`; the dispatch routes the verifier to `opus` when `verifierModelFor` (risk-detector.js, read by `report-check --before-eval`) sees prompt/model or media (measured against haiku in `docs/specs/scout-evidence/decisions.md`). No tier system — Claude assumes the 3 NLH roles (Orchestrator/Specialist/Evaluator) per MORPH.md.
82
+ **Personas, not tiers:** `agents.json` has 10 flat personas — 6 domain implementers (dotnet-senior, ef-modeler, maf-expert, nextjs-expert, ui-designer, infra-engineer), the 3 read-only Gate 3 roles (verifier, reviewer, security) and 1 stage persona (`scout`, read-only). `model` is sized per stage: `sonnet` for implementers, `scout`, `verifier` and `reviewer`; `security` and `ui-designer` (design quality is the deliverable, high effort) are `opus`; the dispatch routes the verifier to `opus` when `verifierModelFor` (risk-detector.js, read by `report-check --before-eval`) sees prompt/model or media (measured against haiku in `docs/specs/scout-evidence/decisions.md`). No tier system — Claude assumes the 3 NLH roles (Orchestrator/Specialist/Evaluator) per MORPH.md.
83
83
 
84
84
  ### Phase Sequence
85
85
 
@@ -96,7 +96,7 @@ Authoritative, committed state: `.morph/features/{f}/feature.json` (status, appr
96
96
  ## Testing Conventions
97
97
 
98
98
  - **Framework:** Node.js native `node:test` — no Jest or Mocha
99
- - **Concurrency:** files run in parallel (`scripts/run-tests.mjs`) — `node --test` gives each file its own process, so `process.chdir()` stays inside the file. A test that WRITES a tracked file of this repo (and restores it) must be listed in `SERIAL` in `scripts/run-tests.mjs`; the runner fails if the parallel phase changes the tracked tree
99
+ - **Concurrency:** files run in parallel (`scripts/run-tests.mjs`) — `node --test` gives each file its own process, so `process.chdir()` stays inside the file. A test never writes a tracked file of this repo: a script under test reads its root from `MORPH_REPO_ROOT`, and the test points it at `copyTrackedRepo()` (`test/helpers/repo-copy.js`, a temp git repo with the tracked files). The runner fails if a run changes the tracked tree
100
100
  - **Subprocesses:** drive the CLI through `test/helpers/cli.js` (`runCli`, no shell) and git through `test/helpers/git.js` (`git(cwd, ...args)`) — `execSync('git …')` pays a cmd.exe per call on Windows. Hooks that export `run(payload)` can be called in-process (see `test/hooks/loop-detect.test.js`); keep one spawn per hook for the standalone wiring
101
101
  - **Temp dirs:** `createTempDir()` / `cleanupTempDir()` from `test/helpers/test-utils.js`
102
102
  - **Home:** a suite that runs `setupInfra`/`updateCommand`/`initCommand` calls `isolateHome()` (test-utils) at the top — the installers write `~/.claude/settings.json` through `os.homedir()`. Canary: `test/meta/home-isolation.test.js`
@@ -118,7 +118,7 @@ When modifying framework components, verify the full scope of related files.
118
118
 
119
119
  | When you modify... | Also verify... |
120
120
  |----------------------------------|-------------------------------------------------------------------------------------------|
121
- | `framework/agents.json` | agents-installer.js (test/utils/agents-installer.test.js), doctor.js (REQUIRED_AGENTS). **`maxTurns` (ADR-004):** UMA régua de validade, `maxTurnsError` em `agents-installer.js`, com QUATRO leitores — `installAgents` (recusa antes de escrever), `checkAgentsDrift` (`invalid`), `validateAgentsJson` do `doctor` (error) e o Check 6 do `validate-framework.js` (`test/framework/validate-framework-agents.test.js`); uma segunda noção de "valor válido" faz o mesmo arquivo passar num e ser recusado no outro. Sem o campo, o frontmatter sai byte a byte igual ao de antes (canário COMPAT). O corpo gerado anuncia o teto ao sub-agent, e a cláusula 5 dos templates de dispatch depende disso. O drift lê o registry MCP do PACOTE (`mcpRegistryDir`): a cópia instalada não tem `mcp/`, e ler dela dava toda persona com `mcp` como stale numa instalação limpa. O marcador `PARCIAL` (1ª linha) que o corpo da persona manda gravar é lido por `PARTIAL_MARKER` de `framework/hooks/shared/slice-progress.js` (no `report-check`: `report-incomplete`, ação `resume`; no progresso: fatia `parcial`): mudar a grafia num lado só devolve o parcial lido como `ok`. **`effort`:** mesma régua única em quatro leitores (`effortError`); ausente, o frontmatter não ganha linha e o sub-agent herda o effort da sessão (COMPAT intacto). Implementadores e `scout` `medium`; `verifier`, `reviewer` e `security` sem o campo — o Gate 3 não é barateado. `reviewer`/`security` são read-only sobre o SHA (`git diff {base}..{sha}`, nunca a árvore): o corpo da persona diz isso, e é o que torna seguro o paralelo com a mutação do verificador (F46). **`surfaces` (ADR-005):** mesma régua única em quatro leitores (`surfacesError`), e `personaStandardIds` é a leitura única de "todo standard da persona" para o Check 1, o drift e os scanners do dashboard (`agents-scanner.js`, `standards-scanner.js`) — iterar só `standards` deixa id de superfície sem validar e a aresta do grafo sumida. Sem o campo, o `.md` sai byte a byte o de antes: `test/fixtures/agents/ui-designer-5.3.0.{json,md}` é a persona do 5.3.0 e o render do installer de main, comparados com `strictEqual` — nunca regere a fixture para fazer o teste passar. A chave da superfície é a que o checklist de tela do `morph-uiux` escreve em `Superfície` e que o `morph-plan` usa para somar a lista em `standards:` da fatia. **Forma do corpo (`buildBody`):** só a persona no formato do 5.3.0 — implementadora (Write/Edit), sem `effort` e sem `surfaces` (`legacyShape`) — mantém `## Domains` e a lista de standards sem a linha de busca; no `agents.json` atual NENHUMA cai nesse caso (todo implementador tem `effort`; `verifier`/`reviewer`/`security` são read-only), e o formato vive pela fixture COMPAT acima. Toda outra persona perde `## Domains`, ganha `STANDARDS_HINT` (`--find <id>` e `--show <id>#<âncora>`) no topo de `## Standards to consult on demand` e, com `neon` no `mcp` (hoje `ef-modeler` e `infra-engineer`), o aviso `NEON_CAUTION` (ensaio de migração em branch descartável; tool destrutiva só com confirmação humana). Canários: `test/utils/agents-installer.test.js` e `test/framework/maf-expert-persona.test.js` |
121
+ | `framework/agents.json` | agents-installer.js (test/utils/agents-installer.test.js), doctor.js (REQUIRED_AGENTS). **`maxTurns` (ADR-004):** UMA régua de validade, `maxTurnsError` em `agents-installer.js`, com QUATRO leitores — `installAgents` (recusa antes de escrever), `checkAgentsDrift` (`invalid`), `validateAgentsJson` do `doctor` (error) e o Check 6 do `validate-framework.js` (`test/framework/validate-framework-agents.test.js`); uma segunda noção de "valor válido" faz o mesmo arquivo passar num e ser recusado no outro. Sem o campo, o frontmatter sai byte a byte igual ao de antes (canário COMPAT). O corpo gerado anuncia o teto ao sub-agent, e a cláusula 5 dos templates de dispatch depende disso. O drift lê o registry MCP do PACOTE (`mcpRegistryDir`): a cópia instalada não tem `mcp/`, e ler dela dava toda persona com `mcp` como stale numa instalação limpa. O marcador `PARCIAL` (1ª linha) que o corpo da persona manda gravar é lido por `PARTIAL_MARKER` de `framework/hooks/shared/slice-progress.js` (no `report-check`: `report-incomplete`, ação `resume`; no progresso: fatia `parcial`): mudar a grafia num lado só devolve o parcial lido como `ok`. **`effort`:** mesma régua única em quatro leitores (`effortError`); ausente, o frontmatter não ganha linha e o sub-agent herda o effort da sessão (COMPAT intacto). Implementadores e `scout` `medium`, menos a `ui-designer` (`high`, com `opus`: a qualidade visual é a entrega); `verifier`, `reviewer` e `security` sem o campo — o Gate 3 não é barateado. `reviewer`/`security` são read-only sobre o SHA (`git diff {base}..{sha}`, nunca a árvore): o corpo da persona diz isso, e é o que torna seguro o paralelo com a mutação do verificador (F46). **`surfaces` (ADR-005):** mesma régua única em quatro leitores (`surfacesError`), e `personaStandardIds` é a leitura única de "todo standard da persona" para o Check 1, o drift e os scanners do dashboard (`agents-scanner.js`, `standards-scanner.js`) — iterar só `standards` deixa id de superfície sem validar e a aresta do grafo sumida. Sem o campo, o `.md` sai byte a byte o de antes: `test/fixtures/agents/ui-designer-5.3.0.{json,md}` é a persona do 5.3.0 e o render do installer de main, comparados com `strictEqual` — nunca regere a fixture para fazer o teste passar. A chave da superfície é a que o checklist de tela do `morph-uiux` escreve em `Superfície` e que o `morph-plan` usa para somar a lista em `standards:` da fatia. **Forma do corpo (`buildBody`):** só a persona no formato do 5.3.0 — implementadora (Write/Edit), sem `effort` e sem `surfaces` (`legacyShape`) — mantém `## Domains` e a lista de standards sem a linha de busca; no `agents.json` atual NENHUMA cai nesse caso (todo implementador tem `effort`; `verifier`/`reviewer`/`security` são read-only), e o formato vive pela fixture COMPAT acima. Toda outra persona perde `## Domains`, ganha `STANDARDS_HINT` (`--find <id>` e `--show <id>#<âncora>`) no topo de `## Standards to consult on demand` e, com `neon` no `mcp` (hoje `ef-modeler` e `infra-engineer`), o aviso `NEON_CAUTION` (ensaio de migração em branch descartável; tool destrutiva só com confirmação humana). Canários: `test/utils/agents-installer.test.js` e `test/framework/maf-expert-persona.test.js` |
122
122
  | `framework/standards/**` | STANDARDS.json entry exists (o **digest** e o que `standards --find` devolve — corrigir a prosa e esquecer o digest e o caso mais comum), e o bullet do standard na rule `framework/rules/*-standards.md` que o roteia (resumo inline; `@`-import em rule resolve relativo ao arquivo da rule e, quando resolve, carrega em TODA sessão ignorando `paths:` — medido; canário `test/framework/rules-no-imports.test.js`), agents reference standard, .md file exists. **Bloco de codigo `csharp` num standard e afirmacao verificavel:** extraia com `node scripts/extract-doc-csharp.mjs <std.md> "## Secao" out.cs` e compile numa sonda com o pin + `TreatWarningsAsErrors` (sem ele `MEAI001` vira aviso e o build fica verde sobre codigo que o consumidor nao compila). Medido: um exemplo carimbado sem compilar tinha 3 erros independentes |
123
123
  | `isImplementer` (Check 6 de `scripts/validate-framework.js`) | toda persona com Write/Edit no escopo efetivo de tools tem de alcançar, pelos `standards`, as âncoras `comment-policy` e `test-budget` do STANDARDS.json (`IMPLEMENTER_ANCHORS`). Renomear a chave da âncora no registry derruba o `validate`, e persona implementadora nova sem os dois standards também. Installer e `doctor` não cobram isso de propósito: um `agents.json` instalado antigo continua valendo |
124
124
  | `scripts/generate-standards-registry.js` | Escreve DOIS arquivos: `framework/standards/STANDARDS.json` (o que o runtime lê: `id`, `name`, `path`, `category`, `stacks`, `tags`, `anchors`, `digest`) e o sidecar `STANDARDS.meta.json` (`aliases`, `verifiedAgainst`, `provedBy` por **id**, e `sharedAliases` no topo). REGENERE os dois, nunca patch textual. Os `aliases` do sidecar se preservam pelo id da entrada: renomear um id sem levar a chave do sidecar perde os aliases dele. `--check` compara os DOIS arquivos com o que geraria (drift em qualquer um reprova o `npm run generate:check`). As âncoras são validadas contra os headings pelo `headingSlugs` de `src/lib/standards/sections.js`, a mesma resolução do `--show`. `src/lib/standards/verified-against.js` (`parseVerifiedAgainst`/`deriveProvedBy`: `verifiedAgainst` e `provedBy` sao DERIVADOS a cada run e NAO entram em `PRESERVE_FIELDS`), `test/framework/standards-registry.test.js`. **Renomear um standard e uma PARADA, nao um exit 0**: path sumido + path novo faz o gerador recusar nomeando os dois conjuntos e prescrevendo a edicao do campo `path` da entrada antiga — ele nao adivinha o par. `MORPH_STANDARDS_BASE` e o unico seam de teste do script e nada em producao o define |
@@ -149,13 +149,13 @@ When modifying framework components, verify the full scope of related files.
149
149
  | `src/lib/git/branch-classifier.js` | `src/commands/project/branch.js`, `worktree-audit.js` (`unintegratedWork` reusa `classifyBranch` — o `doctor` e o `branch prune` não podem discordar sobre a mesma branch), `test/commands/branch-prune.test.js`, e `lifecycle-audit.js` (`abandoned-scaffold` conta commit próprio pelo mesmo `resolveBaseRef` + `commitsAhead`) |
150
150
  | `src/lib/git/pending-prs.js` | os TRÊS consumidores da mesma síntese "aguardando merge": `list.js` (linha sintetizada), `fleet-scanner.js` (entrada `pr-pending`) e `doctor.js` (`auditPullRequests`). Uma feature visível numa superfície e invisível na outra é o bug que este módulo existe para impedir |
151
151
  | `src/lib/git/gh.js` | `pr-index.js`, `pr-files.js` e `finish.js` — as DUAS formas de invocar o `gh` viraram uma; uma segunda cópia de `resolveGh` volta a tornar o caminho de sucesso do índice intestável |
152
- | `src/lib/git/evidence-staleness.js` (`treeMovedSince`, "a árvore andou desde o commit da prova") | os DOIS leitores do mesmo fato: `gate-check.js` (`verificationStale`, o carimbo do `verify`) e `approve.js` (`reviewStaleness`, o `Reviewed-SHA` do review-report). Uma régua só: comparar SHA com HEAD fazia todo commit de estado (o `feature.json` do próprio verify, um relatório de fatia, `recap.md`) invalidar a prova sem nenhum byte de código diferente. Conta tudo fora de `.morph/` e, dentro dele, só o `config.json` — sem `expectedCount`, que a rodada de baseline escreve e não é evidência; um comando de teste trocado conta. `--no-renames` é load-bearing: um arquivo movido para dentro de `.morph/` aparece como criação lá e a deleção fora some. SHA que o git não resolve = andou (a resposta de antes); sem SHA ou sem HEAD = não andou (fail-open). `treeFingerprint` (`tree-fingerprint.js`) segue a MESMA régua (árvore commitada sem `.morph/`, `config.json` sem `expectedCount`) para `repeatOf` e para o `--ci` sem CI reaproveitar o stamp verde fresco; mudar uma sem a outra faz o reaproveitamento e o gate discordarem. Canários: `test/lib/git/evidence-staleness.test.js` (mutação: sem a normalização e sem `--no-renames` cada um derruba um teste) e os de `gate-check.test.js`/`approve.test.js` |
152
+ | `src/lib/git/evidence-staleness.js` (`treeMovedSince`, "a árvore andou desde o commit da prova") | os DOIS leitores do mesmo fato: `gate-check.js` (`verificationStale`, o carimbo do `verify`) e `approve.js` (`reviewStaleness`, o `Reviewed-SHA` do review-report). Uma régua só: comparar SHA com HEAD fazia todo commit de estado (o `feature.json` do próprio verify, um relatório de fatia) invalidar a prova sem nenhum byte de código diferente. Conta tudo fora de `.morph/` e, dentro dele, só o `config.json` — sem `expectedCount`, que a rodada de baseline escreve e não é evidência; um comando de teste trocado conta. `--no-renames` é load-bearing: um arquivo movido para dentro de `.morph/` aparece como criação lá e a deleção fora some. SHA que o git não resolve = andou (a resposta de antes); sem SHA ou sem HEAD = não andou (fail-open). `treeFingerprint` (`tree-fingerprint.js`) segue a MESMA régua (árvore commitada sem `.morph/`, `config.json` sem `expectedCount`) para `repeatOf` e para o `--ci` sem CI reaproveitar o stamp verde fresco; mudar uma sem a outra faz o reaproveitamento e o gate discordarem. Canários: `test/lib/git/evidence-staleness.test.js` (mutação: sem a normalização e sem `--no-renames` cada um derruba um teste) e os de `gate-check.test.js`/`approve.test.js` |
153
153
  | `src/lib/git/tree-fingerprint.js` (a impressão da árvore) | `verify.js` (grava `fingerprint` no evento `Verify`; `findRepeatedVerify`, de `verify-event.js`, compara com o último verify de feature COMPLETO — rodada com `persisted: false` nunca é a prova que uma completa substitui) e `metrics.js` (`verify.unchangedRepeats`, pela mesma regra). `.morph/` fica fora, exceto `config/config.json`: o próprio verify escreve feature.json e logs a cada rodada, e contá-los faria duas rodadas sobre o mesmo código parecerem diferentes. `repeatOf` é informação e nenhum gate o lê: ligá-lo ao Gate 3 é aceitar a prova de uma rodada anterior no lugar da atual |
154
154
  | `framework/hooks/shared/slice-progress.js` (progresso e relatório de fatia) | A régua ÚNICA de "em que pé está a fatia" (`sliceProgress`: relatório ausente = pendente, `PARTIAL_MARKER` na 1ª linha = parcial, senão feito) e de "o relatório está completo" (`inspectReport`/`REPORT_MARKERS`: prosa, `**Arquivos:**`, cada `C{n}` de `cobre:`). Leitores: `report-check.js` (reexporta), o Stop hook `validate-completion.js` (`auditSliceReports`), `worktree-context.js`, `handoff-generator.js`/`handoff.js`, `fleet-scanner.js` (pelo `git show` da branch da feature), `status.js` e o `features-scanner.js` do dashboard — nenhum reinterpreta relatório nem tem status próprio de fatia. O `statusline.py` é Python e carrega cópia do marcador: o canário de paridade em `test/hooks/statusline.test.js` a compara com a de JS. O exemplo de relatório da `morph-apply` passa pelos `REPORT_MARKERS` (`test/framework/slice-report-format-rule.test.js`), o Stop hook diz o que falta em cada marca (`MISSING_HINT`), e o do corpo da persona pelo `inspectReport` (`test/framework/morph-apply-skill.test.js`) |
155
155
  | `src/lib/git/tree-state.js` (o bloco `tree` do `report-check`) | `report-check.js` (toda saída, inclusive o batch `report-check <f> F1 F2`, e a foto `--before-eval` em `4-review/tree-before-eval.json`) e as skills que leem os campos: `morph-apply` (pós-dispatch e retomada do PARCIAL) e `morph-review` (higiene contra `tree.sinceBeforeEval`). Campo renomeado aqui sem as skills é instrução que lê `undefined`: `test/framework/report-check-wiring.test.js` confere que todo `tree.*` citado existe na saída real. A foto compara CONTEÚDO (blob por arquivo), não o `git status`: a mutação que o verificador commitou também aparece. Fora de git o bloco é `null`, nunca árvore vazia. `MUTATION_MARKER` tem a mesma grafia que as skills mandam gravar |
156
156
  | `src/lib/worktree/feature-truth.js` | The six readers of the same "which tree owns this feature" predicate: `fleet-scanner.js`, `list.js`, `handoff.js`, the mutator guard (`approve.js`/`advance.js`/`gate-decision.js`/`gate-check.js`), `verify.js` (`decidePersistence`, asked from the PRIMARY ROOT — asked from cwd, step 4 would make any scratch tree carrying a `feature.json` persist) and the dashboard's `features-scanner.js` (only for ACTIVE features — it spawns git — and a worktree owner without the feature files is shown as `rootStale`, never silently replaced by the root skeleton) |
157
157
  | `src/lib/tasks/test-runner.js` | `verify-runner.js` (o nó `tests` repassa o `--timeout` e lê `timedOut`), `src/commands/project/worktree.js` (as constantes `WORKTREES_DIR`/`LEGACY_WORKTREES_DIR` que a descoberta ignora — duplicar as strings aqui é como o bug volta), `test/lib/test-runner.test.js` (o canário do ignore de worktrees e o do timeout escalado). Um worktree é o checkout de OUTRA feature: varrê-lo dobra o relógio e reporta sobre código fora da árvore avaliada. `stripAnsi` roda antes de TODO extrator de contagem (ponto único em `parseTestCount`) — uma cor SGR no meio do sumário derrotava os regexes ancorados (#110). O extrator `dotnet` lê os DOIS sumários (#115): a linha VSTest e o bloco MTP (cabeçalho `Test run summary:`/`Resumo da execução de teste:` na coluna 0, `total:` indentado), em pt-BR e en-US — UM bloco por invocação de `dotnet test` (uma solução de dois projetos dá um bloco agregado, medido), então somar blocos é somar links `&&`; um terceiro locale é `null` (capturas medidas em `test/fixtures/test-output/`). `isInside` e `canonicalPath` também são lidos por `mutation/dotnet-introspection.js`, pelo registro de projetos e pelo dashboard — um segundo canonicalizador é como dois leitores passam a discordar sobre o mesmo path |
158
- | `src/lib/specs/screen-checklist.js` (checklist de tela, #129) | o sinal mora aqui (`collectScreenChecklist`) e tem QUATRO leitores: `gate-check.js` na `uiux` (`problems` → pausa) e no `review` (`uncovered`: item decidido sem linha na seção `## Checklist de tela` do `verifier.md`, lida por `verifierScreenChecklist` (`review-reports.js`) — última ocorrência; tela toda "não se aplica" não deve nada), e `approve.js`/`advance.js` com assinatura `auto` (`uiuxAutoApprovalBlock`). Política só em `risk-detector.js`: `uiuxChecklistPause` é o predicado ÚNICO do gate-check pausar e do auto recusar — uma segunda regra no advance fez approve e advance discordarem da mesma feature — e `gateDecisions.uiux.pause === false` destrava os dois só para o mockup que a decisão viu: `persistGateDecision` (`gate-decision.js`, o escritor único de `gateDecisions`) grava `mockupsHash` e `uiuxAutoApprovalBlock` o compara com o arquivo atual — os dois leem `mockupsHash` daqui, e um segundo cálculo do hash (outra normalização de BOM/CRLF) faz toda decisão parecer de outro mockup. `--force` não destrava em nenhum dos dois. Mockup legado (`## S\d+:` e nenhuma `## Tela:`, o template anterior) é isento nas duas fases com `exempt` = `LEGACY_MOCKUP_EXEMPTION` à vista no `getRiskSignals`; qualquer outro heading é "nenhuma tela declarada", senão trocar o heading pularia o checklist (fixture: `test/fixtures/mockups/legacy-ui-mockups.md`, o template de main). Os rótulos dos itens casam com DOIS textos que o parser não vê, os dois com canário em `test/lib/specs/screen-checklist.test.js`: o template do prompt da `morph-uiux` §3 e `framework/templates/docs/ui-mockups.md`; mais o formato de linha que `framework/evals/review-checklist.md` (seção "Verificador", "Contrato de tela") prescreve. A `Superfície` é validada contra as chaves de `surfaces` da `ui-designer` (`knownSurfaces`) — é a chave que o `morph-plan` §5 (`superfície:` da fatia) usa para somar standards |
158
+ | `src/lib/specs/screen-checklist.js` (checklist de tela, #129) | o sinal mora aqui (`collectScreenChecklist`) e tem QUATRO leitores: `gate-check.js` na `uiux` (`problems` → pausa) e no `review` (`uncovered`: item decidido sem linha na seção `## Checklist de tela` do `verifier.md`, lida por `verifierScreenChecklist` (`review-reports.js`) — última ocorrência; tela toda "não se aplica" não deve nada), e `approve.js`/`advance.js` com assinatura `auto` (`uiuxAutoApprovalBlock`). Política só em `risk-detector.js`: `uiuxChecklistPause` é o predicado ÚNICO do gate-check pausar e do auto recusar — uma segunda regra no advance fez approve e advance discordarem da mesma feature — e `gateDecisions.uiux.pause === false` destrava os dois só para o mockup que a decisão viu: `persistGateDecision` (`gate-decision.js`, o escritor único de `gateDecisions`) grava `mockupsHash` e `uiuxAutoApprovalBlock` o compara com o arquivo atual — os dois leem `mockupsHash` daqui, e um segundo cálculo do hash (outra normalização de BOM/CRLF) faz toda decisão parecer de outro mockup. `--force` não destrava em nenhum dos dois. Na uiux o sinal também leva `prototypes` (`auditPrototypes`: a linha `**Protótipo:**` da tela, o HTML e os prints `-1280`/`-390` ao lado), lido pelo MESMO `uiuxChecklistPause` depois do checklist — o template `ui-mockups.md` e a `morph-uiux` §3 ensinam essa linha. Mockup legado (`## S\d+:` e nenhuma `## Tela:`, o template anterior) é isento nas duas fases com `exempt` = `LEGACY_MOCKUP_EXEMPTION` à vista no `getRiskSignals`; qualquer outro heading é "nenhuma tela declarada", senão trocar o heading pularia o checklist (fixture: `test/fixtures/mockups/legacy-ui-mockups.md`, o template de main). Os rótulos dos itens casam com DOIS textos que o parser não vê, os dois com canário em `test/lib/specs/screen-checklist.test.js`: o template do prompt da `morph-uiux` §3 e `framework/templates/docs/ui-mockups.md`; mais o formato de linha que `framework/evals/review-checklist.md` (seção "Verificador", "Contrato de tela") prescreve. A `Superfície` é validada contra as chaves de `surfaces` da `ui-designer` (`knownSurfaces`) — é a chave que o `morph-plan` §5 (`superfície:` da fatia) usa para somar standards |
159
159
  | `src/lib/scout/scout-check.js` (o mapa do scout) | os DOIS escritores do mesmo formato e os que mandam rodá-lo: a persona `scout` do `framework/agents.json` (o CONTRATO DE EVIDÊNCIA e seus exemplos `Formato:`), MORPH.md §6 ("Scout"), `morph-plan` §4, `morph-hotfix` §2 (+ `framework/commands/morph-hotfix.md`) e a entrada do `framework/docs/CLI.md`. Persona que ensina uma forma que o checker reprova faz TODO mapa voltar: `test/framework/scout-persona-format.test.js` passa os exemplos da persona pelo checker. Os relaxamentos (linha já citada, bloco cercado logo depois, listagem sob comando de busca, subseção de Inferido, menção entre aspas) têm cada um o caso parecido que continua reprovando em `test/lib/scout/scout-check.test.js`; crase descritiva depois de citação reprova de propósito, é a forma do erro de campo. Raiz = `--root` ou topo da worktree, nunca a raiz primária. Medição de modelo/effort: `docs/specs/scout-evidence/decisions.md` |
160
160
  | `src/lib/stack/stack-scan.js` (`morph-spec stack-scan`) | Varredura determinística contra `config.project.stack` (`getProjectTags` de `stack-filter.js`; só stacks configurados são julgados), com `SEVERITIES` e regras por stack. O que fica fora vem de leitores únicos — `isTestPath` (`src/lib/graph/sanitize.js`), `WORKTREE_DIR_NAMES` (`src/lib/worktree/dirs.js`) e `PACKAGE_LOCATIONS` (`src/lib/detectors/index.js`) —, nunca listas próprias. `src/commands/project/stack-scan.js` é fino: com `<feature>` grava `2-plan/stack-scan.md` e recusa fora da árvore dona. Leitores do relatório: `morph-plan` (Bloqueante/Alto vira nó da árvore de decisões) e `morph-uiux`; regras e severidades descritas no bullet `stack-scan` de `framework/docs/CLI.md`, que muda junto. Canários: `test/lib/stack/stack-scan.test.js`, `test/commands/stack-scan.test.js` |
161
161
  | `framework/hooks/shared/spawn-command.js` (`resolveSpawn`) | a regra ÚNICA de "como executar `npx`/`npm`/`pnpm`/`yarn` neste SO", com dois leitores: `defaultExec` de `e2e-check.js` (o spec do e2e, detectado ou `e2e.command`, e o seed do auth) e `heavy run` (`heavy.js`). No win32 o shim `.cmd` sem shell é ENOENT e o Node recusa `.cmd` com `shell: false`: `npx playwright` vira `node node_modules/@playwright/test/cli.js` quando o arquivo existe, o resto vai ao `.cmd` pelo shell. Canário: `test/hooks/spawn-command.test.js` (inclui um `npx --version` real) |
@@ -188,8 +188,7 @@ When modifying framework components, verify the full scope of related files.
188
188
  | `src/lib/worktree/docker-audit.js` | `worktree-audit.js` (`auditWorktrees` concatena os achados e é quem PASSA as features conhecidas — um segundo scan aqui discordaria sobre o que é órfão), `doctor.js` (a classificação `info`/`warn` = não-falha em `doctorWorktreesCommand`; e `samePathCase`, a regra de caixa de path que o WARN de frontend do `doctor --full` reusa — uma segunda cópia dela foi removida), `env-allocator.js` (`allocatedFeatures` é read-only de propósito: `allocateEnvBlock` ESCREVE, e uma auditoria que aloca inventa o estado que reporta), `test/lib/worktree/docker-audit.test.js`. Nunca no `doctor --full` (D10): `test/commands/doctor.test.js:46` exige zero `✗` neste repo |
189
189
  | `src/lib/risk-detector.js` | os DOIS lados da mesma decisão de gate: `gate-check.js` (`collectSignals` COLETA do disco; nenhum sinal que descreva um FATO pode entrar em `OVERRIDABLE_SIGNAL_KEYS` — `gate`/`workType`/`e2e*` são o precedente), `src/commands/validation/verify.js` (o stamp `verification` é a ÚNICA coisa que o gate lê: campo novo aqui só vira sinal se o stamp o gravar), `framework/schemas/feature.schema.json` (`verification` é `additionalProperties: false`), a tabela `#### Sinais` sob `### gate-check` do `framework/docs/CLI.md` (a régua escrita do comando; o MORPH.md §5 só lista os sinais que a sessão passa por `--signals` — canário em `test/framework/verify-stack-docs-prose.test.js`). Política escrita no coletor cria duas fontes para o mesmo fato — foi assim que `gate-check` e `approve` divergiram uma vez sobre o Gate 3. Os relatórios do Gate 3 são lidos por UM leitor (`src/lib/review-reports.js`) e decididos por UMA regra (`reviewPause`): `approve` exige cada relatório exigido com `status: ok`, `gate-check` pausa em `FIX`, bloqueador aberto ou sem tipo, ou `Cn` sem linha PROVADO. **O plano entra pelo `checks.json`:** `planChecksPause` é o predicado ÚNICO de "o plano não foi extraído até zero erro" — o `gate-check` pausa o gate do plano por ele e `approve`/`advance` automáticos recusam por ele (`planAutoApprovalBlock`); `sliceCount > MAX_SLICES` pausa. `featureGeneratesMedia` lê os `standards` das fatias por id ou caminho (`standardIdOf`), e o `report-check --before-eval` usa o mesmo predicado para rotear o verificador a opus — canário ponta a ponta em `test/framework/media-claims.test.js`. A prova de verify é sempre da feature inteira: `--filter` de escopo de feature não persiste o stamp (`reason: 'filtered'`), nem `--skip-tests`/`--skip-build` (`'skip-tests'`/`'skip-build'`, #113 — nó pulado não reprova o rollup e nenhuma regra do gate lê `tests`/`build` pulados; a lista é `PARTIAL_RUN_FLAGS`) |
190
190
  | `src/lib/review-reports.js` (os relatórios do Gate 3) | O leitor ÚNICO de `4-review/{verifier,reviewer,security}.md`: veredito (o último, append-only), bloqueadores tipados (`BLOCKER_TYPES`), `PARCIAL` (o `PARTIAL_MARKER` de `slice-progress.js`, nunca uma cópia), `**Reviewed-SHA:**` e a `## Checks` do verificador. Leitores: `gate-check.js` (`collectReviewSignal` → `reviewSignal`), `approve.js` (status por papel, `--self-assessed` e o `Reviewed-SHA`, o pior vence), `report-check.js` (`reviews` por papel; `reviewModels` no `--before-eval`), `risk-detector.js` (`reviewPause` lê o sinal e `BLOCKER_TYPES`), `screen-checklist.js` (`verifierScreenChecklist`), o dashboard (`features-scanner.js`, por `reviewReportsFromDir` — sem git, `security` conta só presente) e o hook `state-sync` (que, por não importar `src/`, só testa a existência de `verifier.md`/`reviewer.md`). Quais papéis são exigidos é UMA regra: `requiredReviewRoles` + `securityReviewFor` via `collectReviewRequirement` (`gate-check.js`), lida pelos três comandos — uma segunda noção faz o approve aprovar o que o gate pausa. Cobertura: `checksCoverage` — status por igualdade EXATA (`NÃO PROVADO` contém `PROVADO`), Cn sem linha falta; `checks.json` ilegível pausa. Canários: `test/lib/review-reports.test.js` (medido por mutação: aceitar `NAO PROVADO` como prova e tratar Cn sem linha como coberto derrubam 3 testes cada) e o bloco "relatórios de review no Gate 3" de `test/commands/gate-check.test.js`; o fixture é `test/helpers/review-fixtures.js` |
191
- | `src/lib/installers/effects.js` | os NOVE pontos de emissão que atravessam o caminho de `update`: `update.js` (clean, payloads, spawn de `generate-refs.js`, `gitIndex`), `skills-installer.js`, `agents-installer.js`, `setup-infra.js` (`installRulesForStack`, `installCommandsForStack`, `updateClaudeMdAgentsBlock`), `hooks-installer.js` (`installClaudeHooks`, `installGlobalStatusline`), `file-copier.js` (`updateGitignore`, `ensureGitattributes`), `claude-md-injector.js`, `version-checker.js` (`saveProjectMorphVersion`) e `templates-reconcile.js`. **O caminho real também emite** — o resumo de uma execução real sai de `list()`, e é por isso que um ponto de emissão esquecido some das DUAS saídas ao mesmo tempo. Canários: `test/lib/installers/effects.test.js` (igualdade dry × real do MESMO roteiro) e `test/commands/update-dry-run.test.js` — que tem DOIS canários e precisa dos dois: **igualdade** prova que os dois lados percorrem o mesmo caminho, **diferencial** (mudar `--templates` muda a previsão) prova que o caminho lê a flag. Só igualdade aprova uma previsão e uma execução que ignoram a MESMA flag — foi medido nesta feature, por mutação. Um laço de limpeza de órfão novo tem de nascer calado em `fx.dryRun` (D6): o clean o subsome. E a lista de `frameworkDirsToClean` é pinada **à mão** no teste (`DIRETORIOS_APAGADOS_POR_INTEIRO`, dez caminhos, `deepEqual` ordenado): derivar a expectativa chamando a própria função deixou a suíte inteira cega — medido, dava para remover 2 das 10 entradas sem matar nenhum dos 207 arquivos de teste |
192
- | `src/lib/specs/old-format.js` (feature em voo no formato anterior) | A regra ÚNICA (`isOldFormatFeature`: `2-plan/tasks.json` ou `0-proposal/` sem `2-plan/plan.md`, status fora de `completed`/`abandoned`, raiz + toda worktree do `git worktree list`) e a mensagem ÚNICA (`oldFormatGuardLines`, que prescreve a 8.47 ou `archive <feature> --force`). As portas de escrita a aplicam ANTES de qualquer mutação, nenhuma dispensa por flag: `update.js` (`--force` não dispensa; `--dry-run` relata no topo) e `setupInfra` (`src/scripts/setup-infra.js`, também sob `force` e `reinstall`), por onde passam `init --force` e `setup-infra [--reinstall]`, que saem 1. Uma porta nova que sobrescreva `.morph/`/`.claude/` sem chamar a regra reabre o contorno. Texto da recusa em `framework/docs/CLI.md` (`### update`). Canários: `test/lib/specs/old-format.test.js` e `test/commands/update-old-format.test.js` (update, `setupInfra` com `force`/`reinstall`, `initCommand --force`, a CLI `setup-infra --reinstall`, e o `archive --force` que a mensagem prescreve rodando de verdade) |
191
+ | `src/lib/installers/effects.js` | os NOVE pontos de emissão que atravessam o caminho de `update`: `update.js` (clean, payloads, spawn de `generate-refs.js`, `gitIndex`), `skills-installer.js`, `agents-installer.js`, `setup-infra.js` (`installRulesForStack`, `installCommandsForStack`, `updateClaudeMdAgentsBlock`), `hooks-installer.js` (`installClaudeHooks`, `installGlobalStatusline`), `file-copier.js` (`updateGitignore`, `ensureGitattributes`), `claude-md-injector.js`, `version-checker.js` (`saveProjectMorphVersion`) e `templates-reconcile.js`. **O caminho real também emite** — o resumo de uma execução real sai de `list()`, e é por isso que um ponto de emissão esquecido some das DUAS saídas ao mesmo tempo. Canários: `test/lib/installers/effects.test.js` (igualdade dry × real do MESMO roteiro) e `test/commands/update-dry-run.test.js` — que tem DOIS canários e precisa dos dois: **igualdade** prova que os dois lados percorrem o mesmo caminho, **diferencial** (mudar `--templates` muda a previsão) prova que o caminho lê a flag. Só igualdade aprova uma previsão e uma execução que ignoram a MESMA flag — foi medido nesta feature, por mutação. Um laço de limpeza de órfão novo tem de nascer calado em `fx.dryRun` (D6): o clean o subsome. E a lista de `frameworkDirsToClean` é pinada **à mão** no teste (`DIRETORIOS_APAGADOS_POR_INTEIRO`, nove caminhos, `deepEqual` ordenado): derivar a expectativa chamando a própria função deixou a suíte inteira cega — medido, dava para remover 2 das 10 entradas de então sem matar nenhum dos 207 arquivos de teste |
193
192
  | `src/lib/ai/**` (`doctor --ai`) | `src/commands/project/doctor.js` (`doctorAiCommand` + a guarda de uso indevido), `bin/morph-spec.js` (`--ai`), `framework/docs/CLI.md`. **`--ai` NUNCA entra no `doctor --full` nem no default** — o renderer do `--full` manda tudo que não é `ok`/`warn` para `✗` e `test/commands/doctor.test.js` exige zero `✗` neste repositório. **Nada alcançável por `--ai` pode escrever**: `test/commands/doctor-ai.test.js` varre o grafo de imports E o corpo de `doctorAiCommand` (com os imports dinâmicos fixados nos dois permitidos), reprovando `writeFileSync`/`spawn`/`fs-extra` em CÓDIGO — comentários apagados antes, porque os módulos EXPLICAM por escrito que não fazem isso e medir a menção seria medir uma cópia do objeto. `null` é DESCONHECIDO e vira `skip` **com razão obrigatória**; `[]` é "perguntei e não achei" e vira `ok` |
194
193
  | `src/lib/ai/registry-audit.js` | o leitor de PRODUÇÃO do mesmo documento: `framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelRegistry.cs` (`CommentHandling = Skip`, `AllowTrailingCommas`, `AllowedAliasProperties` com `pricing`/`pricingWaiver`) e o exemplar `model-registry.v2.json` que o framework manda COPIAR. A auditoria tem de enxergar a **mesma forma** que o leitor de produção enxerga: com `JSON.parse` estrito, duas das cinco checagens saíam `skip` sobre o exemplar canônico — e `skip` não muda exit code, então o silêncio era total. A tolerância a JSONC vive em `framework/hooks/shared/comment-stripper.js`, ÚNICA (o `code-audit.js` usa o mesmo varredor, e o `code-budget` também, o único com a opção `js` — template e regex literal de TS/JS; sem ela o varredor é o de antes) — e a paridade é nos DOIS sentidos: `jsoncToJson` **lança** no comentário de bloco não fechado, porque o `JsonCommentHandling.Skip` do .NET lança, e ser mais frouxo que o kit é aprovar documento que a app recusa carregar. Ao mascarar strings, **as aspas delimitadoras ficam**: apagá-las junto faz um elemento-string virar espaço puro e o detector de vírgula sobrando comer um SEPARADOR real (`{"tags":["a","b"]}` saía inválido). Canário obrigatório: array terminado em **string**, com e sem vírgula sobrando — uma suíte só com arrays de número passa dos dois lados dessa inversão. A **REGRA DURA** do exemplar — *todo alias declara `pricing` OU `pricingWaiver`, nunca os dois, nunca nenhum* — é do alias, não de um mapa no topo: ler só o mapa dava 6 falsos positivos sobre um documento correto. O canário **copia o exemplar do disco**, nunca uma paráfrase dele |
195
194
  | `src/lib/worktree/dirs.js` | ÚNICA fonte do nome do container (`worktrees/`, sem ponto — Jest esconde diretório com ponto e reporta 0 testes sem erro). `worktree.js` re-exporta; `graphifyignore.js`, `file-copier.js`, `architecture-scanner.js`, `test-runner.js`, `worktree-audit.js`, os scanners do dashboard (`features-scanner.js`, `project-api.js`), `tasks/linux-runner.js` (exclusões do `tar` do `--linux`) importam. `test/lib/worktree/dirs.test.js` cobra cada leitor |
package/README.md CHANGED
@@ -3,14 +3,14 @@
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.0.0
6
+ **Version:** 9.2.0
7
7
  **Requires:** Node.js 22+, Claude Code
8
8
 
9
9
  ---
10
10
 
11
11
  ## What it does
12
12
 
13
- morph-spec enforces a spec-first development workflow. When you ask for a feature, it does not write code immediately. It runs through structured phases (proposal, plan, implement) with approval gates before a single line of implementation is generated. Each phase produces traceable output files. Every decision is documented.
13
+ morph-spec enforces a spec-first development workflow. When you ask for a feature, it does not write code immediately. It runs through structured phases (plan, implement, review) with approval gates before a single line of implementation is generated. Each phase produces traceable output files. Every decision is documented.
14
14
 
15
15
  It integrates natively with Claude Code: skills become slash commands, agents become native subagents, hooks inject state context automatically, and rules enforce standards based on file paths.
16
16
 
@@ -61,17 +61,17 @@ your-project/
61
61
  │ ├── config/
62
62
  │ │ └── config.json # Project configuration
63
63
  │ ├── framework/
64
- │ │ ├── agents.json # 8 domain personas (READ-ONLY)
64
+ │ │ ├── agents.json # 10 personas (READ-ONLY)
65
65
  │ │ ├── standards/ # Coding and architecture standards (READ-ONLY)
66
66
  │ │ └── templates/ # Code and IaC templates (READ-ONLY)
67
67
  │ ├── context/ # Project context (README.md, standards.md)
68
68
  │ ├── features/ # Active features
69
69
  │ │ └── {feature}/
70
- │ │ ├── 0-proposal/ # Problem statement + acceptance criteria
71
- │ │ ├── 1-design/ # UI/UX design (optional, UI-heavy features)
72
- │ │ ├── 2-plan/ # usecases/ + spec.md + tasks.json
73
- │ │ ├── 3-implement/ # Recap and implementation notes
74
- │ │ └── 4-review/ # Review report + Gate 3
70
+ │ │ ├── feature.json # Authoritative state (committed)
71
+ │ │ ├── 2-plan/ # plan.md + checks.json (from plan-check)
72
+ │ │ ├── 1-design/ # UI/UX design (optional, after the plan gate)
73
+ │ │ ├── 3-implement/ # reports/F{n}.md — one per plan slice
74
+ │ │ └── 4-review/ # verifier.md + reviewer.md [+ security.md]
75
75
  │ └── state.json # READ-ONLY — managed by CLI only
76
76
  └── .claude/
77
77
  ├── commands/ # Slash commands
@@ -88,28 +88,27 @@ your-project/
88
88
  Features move through structured phases. Some are optional depending on feature type.
89
89
 
90
90
  ```
91
- proposal → [uiux] → plan → implement → review
91
+ plan → [uiux] → implement → review
92
92
  ```
93
93
 
94
- `uiux` is optional — applies only to UI-heavy features.
94
+ `uiux` is optional — it applies only to UI-heavy features and comes after the plan gate.
95
95
 
96
96
  ### Phase outputs
97
97
 
98
98
 
99
99
  | Phase | Directory | Key files |
100
100
  | --------- | --------------- | ------------------------------------------------------------------ |
101
- | Proposal | `0-proposal/` | `proposal.md`, `stack-scan.md`, `migration-plan.md` (optional) |
101
+ | Plan | `2-plan/` | `plan.md` (scenarios `C{n}`, decisions, slices `F{n}`), `checks.json`, `stack-scan.md`, `scout-map.md` |
102
102
  | Design | `1-design/` | `design-system.md`, `mockups.md`, `components.md`, `flows.md` |
103
- | Plan | `2-plan/` | `usecases/`, `spec.md`, `tasks.json`, `decisions.md` |
104
- | Implement | `3-implement/` | `recap.md` + source code |
105
- | Review | `4-review/` | `review-report.md` |
103
+ | Implement | `3-implement/` | `reports/F{n}.md` + source code |
104
+ | Review | `4-review/` | `verifier.md`, `reviewer.md`, `security.md` (when required) |
106
105
 
107
106
 
108
107
  ### Approval gates
109
108
 
110
- - **Gate 1 (Proposal)** — Problem statement must be approved before plan.
111
- - **Gate 2 (Plan)** — Use cases + spec + tasks must be approved before implement.
112
- - **Gate 3 (Review)** — Review report must be approved before archive.
109
+ - **Plan gate** — `plan.md` must pass `morph-spec plan-check` with zero errors (it writes `checks.json`) before implement.
110
+ - **UI/UX gate** (optional) — the `1-design/` outputs, after the plan gate.
111
+ - **Gate 3 (Review)** — independent sub-agents write `verifier.md` (every `C{n}` proved), `reviewer.md` and, when required, `security.md`, each answering SHIP or FIX.
113
112
 
114
113
  In `trust: "auto"` mode (default), gates auto-pass without risk signals. See `framework/MORPH.md` for risk-signal details.
115
114
 
@@ -123,9 +122,9 @@ morph-spec approval-status {feature}
123
122
 
124
123
  ## Work-type routing & worktrees
125
124
 
126
- Not every change deserves the full pipeline. Every feature is born with a **work type** — `feature`, `bug`, `chore`, or `hotfix` — set via `morph-spec create {feature} --type <type>` or classified from free text with `--request "<text>"`. The type dimensions the pipeline: `feature` runs the full proposal → [uiux] → plan → implement → review sequence; `bug` runs a lean proposal/plan; `chore` skips straight to implement (Gates 1/2 stamped by policy at birth); `hotfix` runs scout (read-only root-cause) → surgical fix → test loop, and its Gate 3 always pauses for a human even under `trust: auto`. Change the type mid-flight with `morph-spec retype {feature} {newType}` (undoes only policy-stamped gates, preserves human approvals, blocked after Gate 3).
125
+ Not every change deserves the full pipeline. Every feature is born with a **work type** — `feature`, `bug`, `chore`, or `hotfix` — set via `morph-spec create {feature} --type <type>` or classified from free text with `--request "<text>"`. The type dimensions the pipeline: `feature` and `bug` run the full plan → [uiux] → implement → review sequence; `chore` skips straight to implement (plan gate stamped by policy at birth); `hotfix` runs scout (read-only root-cause) → surgical fix → test loop, and its Gate 3 always pauses for a human even under `trust: auto`. Change the type mid-flight with `morph-spec retype {feature} {newType}` (undoes only policy-stamped gates, preserves human approvals, blocked after Gate 3).
127
126
 
128
- Independent features can also be developed **in parallel, each isolated in its own git worktree** — one feature, one worktree, one Claude Code instance. `morph-spec create {feature} --worktree` (or `morph-spec worktree setup {feature}`) creates `worktrees/{feature}/` on branch `morph/{feature}`. The authoritative `feature.json` travels committed on the branch; shared infra (`node_modules`, `.claude`, `.morph/framework`) is linked via junctions (`morph-spec worktree link --all` repairs it if missing). Close out with `morph-spec worktree finish {feature}` (merges `--no-ff` back into the clean primary root) followed by `morph-spec archive {feature}` at the root; `morph-spec worktree list` shows every active worktree with its phase and gate status.
127
+ Independent features can also be developed **in parallel, each isolated in its own git worktree** — one feature, one worktree, one Claude Code instance. `morph-spec create {feature} --worktree` (or `morph-spec worktree setup {feature}`) creates `worktrees/{feature}/` on branch `morph/{feature}`. The authoritative `feature.json` travels committed on the branch; shared infra (`node_modules`, `.claude`, `.morph/framework`) is linked via junctions (`morph-spec worktree link --all` repairs it if missing). Close out with `morph-spec finish {feature} --pr|--merge` (archive + integrate + teardown); `morph-spec worktree list` shows every active worktree with its phase and gate status.
129
128
 
130
129
  ---
131
130
 
@@ -136,7 +135,7 @@ These commands are available inside Claude Code after init.
136
135
 
137
136
  | Command | Description |
138
137
  | ------------------------------ | ---------------------------------------------------------- |
139
- | `/morph-proposal {feature}` | Business understanding + plan (Gates 1 and 2) |
138
+ | `/morph-plan {feature}` | Interview, `plan.md`, `plan-check` and the plan gate |
140
139
  | `/morph-apply {feature}` | Autonomous execution + review (Gate 3) |
141
140
  | `/morph-hotfix {feature}` | Surgical hotfix ADW — scout → fix → human Gate 3 → ship |
142
141
  | `/morph-status [feature]` | Status of the active (or specified) feature |
@@ -164,7 +163,7 @@ morph-spec doctor --full # Full health check (all file verificatio
164
163
  ```bash
165
164
  morph-spec fleet # Every active feature (root + worktrees): phase, gates, activity
166
165
  morph-spec status {feature} # Feature status dashboard
167
- morph-spec approve {feature} {gate} # Approve a phase gate (proposal, plan, review)
166
+ morph-spec approve {feature} {gate} # Approve a phase gate (plan, uiux, review)
168
167
  morph-spec advance {feature} # Approve the current gate and scaffold the next phase folder
169
168
  morph-spec approval-status {feature} # Show approval status for all gates
170
169
  morph-spec finish {feature} --pr|--merge # Close a feature: archive + integrate (PR or local merge) + teardown
@@ -173,7 +172,7 @@ morph-spec archive {feature} # Archive WITHOUT integrating (le
173
172
 
174
173
  `finish` is the normal close for both flows: it archives (committing the move inside `morph/{feature}`), then integrates — `--merge` merges `--no-ff` into the default branch locally; `--pr` pushes the branch and runs `gh pr create` (needs `origin` + authenticated `gh`) — and tears down the worktree if there is one. Plain `archive` is reserved for legacy features (born before every feature had a `morph/{feature}` branch) and cleanup.
175
174
 
176
- Task progress within a feature is recorded in `tasks.json` — Claude writes the mutable `status`/`outputs`/`notes` fields as it goes, and there is no separate CLI command for starting or finishing a task.
175
+ Progress within a feature is the slice reports `3-implement/reports/F{n}.md`: absent means pending, `PARCIAL` on the first line means partial. There is no CLI command for starting or finishing a slice.
177
176
 
178
177
  ### Validation
179
178
 
@@ -181,7 +180,7 @@ Task progress within a feature is recorded in `tasks.json` — Claude writes the
181
180
  morph-spec validate # Run all validators
182
181
  morph-spec validate {validator} # Run specific validator
183
182
  morph-spec validate-feature {feature} # Content-aware feature validation
184
- morph-spec verify {feature} [task] # Deterministic build+tests+validators chain, before the LLM judge
183
+ morph-spec verify {feature} # Deterministic build+tests+validators chain, before the LLM judge
185
184
  ```
186
185
 
187
186
  ### Work-type routing
@@ -190,7 +189,6 @@ morph-spec verify {feature} [task] # Deterministic build+tests+validators ch
190
189
  morph-spec create {feature} --type feature|bug|chore|hotfix --description "<what/why>" # Explicit birth: type dimensions the pipeline, description is required
191
190
  morph-spec create {feature} --request "<free text>" # Detector classifies the type AND seeds the description
192
191
  morph-spec retype {feature} {newType} # Change work type mid-flight (blocked after Gate 3)
193
- morph-spec dag {feature} [--mermaid] # DAG dispatch decision; --mermaid emits a flowchart
194
192
  ```
195
193
 
196
194
  ### Worktrees (parallel development)
@@ -200,7 +198,7 @@ morph-spec create {feature} --description "<what/why>" --worktree # Birth the
200
198
  morph-spec worktree setup {feature} # Create worktrees/{feature}/ on branch morph/{feature}
201
199
  morph-spec worktree link [--all] # Relink shared infra (node_modules, .claude, .morph/framework)
202
200
  morph-spec worktree list [--json] # List active feature worktrees with phase/gate status
203
- # Close a worktree feature with `morph-spec finish {feature} --pr|--merge` (see Feature workflow) — it absorbed `worktree finish`.
201
+ # Close a worktree feature with `morph-spec finish {feature} --pr|--merge` (see Feature workflow).
204
202
  ```
205
203
 
206
204
  **Codebase graph** — optional, fail-open. `init` installs [graphify](https://pypi.org/project/graphifyy/) (pinned 0.9.50) when a Python toolchain is available and writes a stack-aware `.graphifyignore`; without one, it records the fact and moves on. Everything degrades to grep.
@@ -218,7 +216,7 @@ The gain is **precision, not recall**: the graph finds nothing grep would miss,
218
216
 
219
217
  ## Agent model
220
218
 
221
- morph-spec dispatches 8 flat domain personas — no tiers, no hierarchy — defined in `.morph/framework/agents.json` (single source of truth) and installed identically to `.claude/agents/morph-{id}.md`. Claude picks the right persona per task from the domains/keywords in `agents.json`, then dispatches it via the `Agent` tool.
219
+ morph-spec dispatches 10 flat personas — no tiers, no hierarchy — defined in `.morph/framework/agents.json` (single source of truth) and installed identically to `.claude/agents/morph-{id}.md`. Claude picks the right persona per plan slice from the domains/keywords in `agents.json`, then dispatches it via the `Agent` tool.
222
220
 
223
221
  | Persona | Domain | Model |
224
222
  | ---------------- | -------------------------------------- | ------ |
@@ -228,7 +226,9 @@ morph-spec dispatches 8 flat domain personas — no tiers, no hierarchy — defi
228
226
  | `nextjs-expert` | Frontend (Next.js/React) | sonnet |
229
227
  | `ui-designer` | UI/UX, design systems | sonnet |
230
228
  | `infra-engineer` | Jobs, deployment, observability | sonnet |
231
- | `evaluator` | Independent code/architecture review (Gate 3) | opus |
229
+ | `verifier` | Gate 3: proves every scenario `C{n}` (read-only) | sonnet (opus for prompt/model or media) |
230
+ | `reviewer` | Gate 3: judges the diff (read-only) | sonnet |
231
+ | `security` | Gate 3: security review (read-only) | opus |
232
232
  | `scout` | Read-only codebase diagnosis | sonnet |
233
233
 
234
234
  `morph-spec doctor` detects drift between `agents.json` and the generated `.claude/agents/morph-*.md` files — never hand-edit the generated files.
@@ -237,16 +237,18 @@ morph-spec dispatches 8 flat domain personas — no tiers, no hierarchy — defi
237
237
 
238
238
  ## Hooks
239
239
 
240
- Guardrail hooks are installed into `.claude/settings.local.json` across 7 event bindings. All are **fail-open** — they check that state exists first and silently no-op on missing/corrupt state; they never throw, write state, or orchestrate.
240
+ Guardrail hooks are installed into `.claude/settings.local.json` across 13 event bindings. All are **fail-open** — they check that state exists first and silently no-op on missing/corrupt state; they never throw, write state, or orchestrate.
241
241
 
242
242
 
243
243
  | Event | Hook(s) | Purpose |
244
244
  | --------------------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
245
245
  | `SessionStart` | `worktree-context.js` | Injects feature identity (worktree) or active-feature summary (root) |
246
- | `PreToolUse` (Write\|Edit) | `protect-spec-files.js`, `enforce-phase-writes.js` | Blocks edits to the frozen plan contract post-Gate-2; enforces phase folders |
247
- | `PreToolUse` (Bash) | `pre-bash-denylist.js` | Detects destructive shell patterns |
248
- | `PostToolUse` | `tasks-json-guard.js`, `trace-autogen.js`, `comment-guard.js` | Guards `tasks.json` plan-contract edits; auto-generates execution traces; blocks added comments the comment standard forbids |
249
- | `PostToolUse` | `state-sync.js`, `gate-guard.js`, `loop-detect.js` | Syncs feature state; enforces gate ordering; detects repeated-action loops |
246
+ | `PreToolUse` (Write\|Edit) | `protect-spec-files.js`, `enforce-phase-writes.js` | Freezes `plan.md` after the plan gate (only `plan-check` writes `checks.json`); enforces phase folders |
247
+ | `PreToolUse` (Bash) | `pre-bash-denylist.js`, `block-destructive-worktree-removal.js`, `block-raw-worktree-add.js`, `warn-bash-source-write.js`, `heavy-gate.js`, `worktree-env-inject.js` | Destructive-command guards, worktree governance, heavy-node semaphore, per-worktree env |
248
+ | `WorktreeCreate` / `WorktreeRemove` | `worktree-create.js`, `worktree-remove.js` | Native worktrees delegate to the CLI |
249
+ | `PostToolUse` (Write\|Edit) | `comment-guard.js` | Blocks added comments the comment standard forbids |
250
+ | `PostToolUse` | `state-sync.js`, `gate-guard.js` | Syncs feature state; enforces gate ordering |
251
+ | `PostToolUse`, `PostToolUseFailure`, `PostToolBatch`, `SubagentStop`, `UserPromptSubmit` | `telemetry-log.js`, `loop-detect.js`, `graph-refresh-kick.js`, `heavy-release.js` | Telemetry, repeated-action loops, graph refresh, heavy-slot release |
250
252
  | `Stop` | `validate-completion.js` | Warns about incomplete tasks, missing outputs, or pending approval gates |
251
253
 
252
254
 
@@ -303,16 +305,16 @@ After updating, run `morph-spec doctor` to confirm the installation is healthy.
303
305
 
304
306
  ## Key rules
305
307
 
306
- **Never skip phases.** Every feature starts with a proposal. No code is written until the design is approved and a task list exists.
308
+ **Never skip phases.** Every feature starts with a plan. No code is written until `plan.md` passes `plan-check` and the plan gate is approved.
307
309
 
308
310
  **Never edit protected files directly:**
309
311
 
310
312
  - `.morph/state.json` — derived automatically from `feature.json`; use `morph-spec approve`/`advance`/`gate-decision` to change feature state
311
313
  - `.morph/framework/` — read-only, updated by `morph-spec update`
312
314
 
313
- **Always document decisions.** Each feature can have a `2-plan/decisions.md`. Architectural choices go there, not in commit messages.
315
+ **Always document decisions.** Architectural choices go in the `## Decisões` section of `2-plan/plan.md` (ADRs are indexed when the feature closes), not in commit messages.
314
316
 
315
- **Verify runs after every task.** `morph-spec verify` runs the build + test + validator chain relevant to your stack; a task closes when it is green and each `doneCriteria` has the evidence that proves it — red triggers an autonomous correction loop rather than a pause. Gate 3 is an independent evaluator that answers SHIP or FIX with evidence-typed blockers.
317
+ **Verify runs once per feature.** `morph-spec verify {feature}` runs the build + test + validator chain relevant to your stack; red triggers an autonomous correction loop rather than a pause. Gate 3 is three independent sub-agents (verifier, reviewer, security when required) that answer SHIP or FIX with evidence-typed blockers.
316
318
 
317
319
  ---
318
320
 
@@ -378,4 +380,4 @@ Code generated by morph-spec (contracts, templates, implementation output) belon
378
380
 
379
381
  ---
380
382
 
381
- *morph-spec v9.0.0 by [Polymorphism Tech](https://polymorphism.tech)*
383
+ *morph-spec v9.2.0 by [Polymorphism Tech](https://polymorphism.tech)*