@polymorphism-tech/morph-spec 4.19.0 → 4.20.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 (62) hide show
  1. package/README.md +2 -2
  2. package/bin/morph-spec.js +11 -0
  3. package/bin/task-manager.js +35 -10
  4. package/claude-plugin.json +1 -1
  5. package/docs/CHEATSHEET.md +1 -1
  6. package/docs/QUICKSTART.md +1 -1
  7. package/framework/agents/architecture/architecture-expert.md +12 -0
  8. package/framework/agents/architecture/packages-validator.md +12 -0
  9. package/framework/agents/architecture/security-expert.md +12 -0
  10. package/framework/agents/frontend/design-system-validator.md +12 -0
  11. package/framework/agents/frontend/nextjs-component-validator.md +12 -0
  12. package/framework/hooks/claude-code/post-tool-use/dispatch.js +20 -3
  13. package/framework/hooks/claude-code/post-tool-use/validator-feedback.js +60 -11
  14. package/framework/rubrics/backend.json +36 -0
  15. package/framework/rubrics/default.json +36 -0
  16. package/framework/rubrics/frontend.json +36 -0
  17. package/framework/skills/level-0-meta/morph-frontend-review/SKILL.md +1 -1
  18. package/framework/skills/level-1-workflows/morph-phase-codebase-analysis/SKILL.md +1 -1
  19. package/framework/skills/level-1-workflows/morph-phase-design/SKILL.md +1 -1
  20. package/framework/skills/level-1-workflows/morph-phase-implement/SKILL.md +1 -1
  21. package/framework/skills/level-1-workflows/morph-phase-plan/SKILL.md +1 -1
  22. package/framework/skills/level-1-workflows/morph-phase-tasks/SKILL.md +1 -1
  23. package/framework/skills/level-1-workflows/morph-phase-uiux/SKILL.md +1 -1
  24. package/framework/skills/level-1-workflows/morph-scope-escalation/SKILL.md +1 -1
  25. package/package.json +1 -1
  26. package/src/commands/dashboard/dashboard.js +53 -0
  27. package/src/dashboard/app/App.jsx +31 -0
  28. package/src/dashboard/app/components/DetailPanel.jsx +11 -0
  29. package/src/dashboard/app/components/FlowGraph.jsx +17 -0
  30. package/src/dashboard/app/components/SearchFilter.jsx +22 -0
  31. package/src/dashboard/app/components/Sidebar.jsx +45 -0
  32. package/src/dashboard/app/hooks/useDetailPanel.js +15 -0
  33. package/src/dashboard/app/main.jsx +13 -0
  34. package/src/dashboard/app/pages/AgentMap.jsx +371 -0
  35. package/src/dashboard/app/pages/HookInspector.jsx +418 -0
  36. package/src/dashboard/app/pages/LiveState.jsx +239 -0
  37. package/src/dashboard/app/pages/PhasePipeline.jsx +410 -0
  38. package/src/dashboard/app/pages/RulesMap.jsx +273 -0
  39. package/src/dashboard/app/pages/SkillsLibrary.jsx +367 -0
  40. package/src/dashboard/app/pages/Standards.jsx +332 -0
  41. package/src/dashboard/app/pages/Workflows.jsx +346 -0
  42. package/src/dashboard/app/styles/index.css +47 -0
  43. package/src/dashboard/index.html +12 -0
  44. package/src/dashboard/package.json +24 -0
  45. package/src/dashboard/scanner/agents-scanner.js +35 -0
  46. package/src/dashboard/scanner/hooks-scanner.js +41 -0
  47. package/src/dashboard/scanner/index.js +21 -0
  48. package/src/dashboard/scanner/phases-scanner.js +15 -0
  49. package/src/dashboard/scanner/rubrics-scanner.js +12 -0
  50. package/src/dashboard/scanner/rules-scanner.js +37 -0
  51. package/src/dashboard/scanner/skills-scanner.js +43 -0
  52. package/src/dashboard/scanner/squads-scanner.js +13 -0
  53. package/src/dashboard/scanner/standards-scanner.js +26 -0
  54. package/src/dashboard/scanner/state-scanner.js +8 -0
  55. package/src/dashboard/scanner/workflows-scanner.js +18 -0
  56. package/src/dashboard/vite-plugin-morph-data.js +17 -0
  57. package/src/dashboard/vite.config.js +24 -0
  58. package/src/lib/checkpoints/checkpoint-hooks.js +2 -1
  59. package/src/lib/generators/recap-generator.js +15 -0
  60. package/src/lib/validators/score-aggregator.js +244 -0
  61. package/src/lib/validators/validation-runner.js +44 -0
  62. package/src/scripts/setup-infra.js +8 -0
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  > Spec-driven development framework for multi-stack projects. Turns feature requests into implementation-ready code through structured, AI-orchestrated phases.
4
4
 
5
5
  **Package:** `@polymorphism-tech/morph-spec`
6
- **Version:** 4.19.0
6
+ **Version:** 4.20.0
7
7
  **Requires:** Node.js 18+, Claude Code
8
8
 
9
9
  ---
@@ -364,4 +364,4 @@ Code generated by morph-spec (contracts, templates, implementation output) belon
364
364
 
365
365
  ---
366
366
 
367
- *morph-spec v4.19.0 by [Polymorphism Tech](https://polymorphism.tech)*
367
+ *morph-spec v4.20.0 by [Polymorphism Tech](https://polymorphism.tech)*
package/bin/morph-spec.js CHANGED
@@ -65,6 +65,9 @@ import { projectMetricsCommand } from '../src/commands/agents/project-metrics.js
65
65
  // Context commands
66
66
  import { contextRefreshCommand } from '../src/commands/context/context-refresh.js';
67
67
 
68
+ // Dashboard commands
69
+ import { dashboardCommand } from '../src/commands/dashboard/dashboard.js';
70
+
68
71
  const __dirname = dirname(fileURLToPath(import.meta.url));
69
72
  const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8'));
70
73
 
@@ -477,4 +480,12 @@ contextCommand
477
480
  .option('--json', 'Output scan result as JSON')
478
481
  .action((options) => contextRefreshCommand(options));
479
482
 
483
+ // Dashboard / Inspector
484
+ program
485
+ .command('dashboard')
486
+ .description('Open the morph-spec inspector dashboard')
487
+ .option('-p, --port <port>', 'Port number', '3200')
488
+ .option('--no-open', 'Don\'t auto-open browser')
489
+ .action(dashboardCommand);
490
+
480
491
  program.parse();
@@ -208,13 +208,20 @@ class TaskManager {
208
208
  console.log(chalk.cyan('\n ℹ️ Dry-run — tasks NOT marked as complete'));
209
209
  return [];
210
210
  }
211
- if (!validationResult.passed) {
211
+ // Score-based retry decision (falls back to pass/fail if scores unavailable)
212
+ const scoreAction = validationResult.scores?.action;
213
+ const shouldFail = scoreAction ? scoreAction !== 'approve' : !validationResult.passed;
214
+
215
+ if (shouldFail) {
212
216
  // Reload state to ensure we have the latest (may have been modified by validation)
213
217
  const currentState = loadState();
214
218
  const currentFeature = currentState.features[featureName];
215
219
  if (currentFeature) {
220
+ // Score-based escalation: 'escalate' action blocks immediately
221
+ const forceEscalate = scoreAction === 'escalate';
222
+
216
223
  for (const task of tasksToComplete) {
217
- this.persistValidationHistory(currentFeature, task.id, validationResult);
224
+ this.persistValidationHistory(currentFeature, task.id, validationResult, forceEscalate);
218
225
  }
219
226
  saveState(currentState);
220
227
 
@@ -224,11 +231,18 @@ class TaskManager {
224
231
  return hist?.status === 'blocked';
225
232
  });
226
233
  if (blockedTasks.length > 0) {
227
- console.error(chalk.red(`\n⛔ ESCALATION — Task(s) ${blockedTasks.map(t => t.id).join(', ')} have failed 3 times`));
228
- console.error(chalk.red(' Human review required. Mark resolved with: morph-spec state set <feature> validationHistory.<taskId>.status passed'));
234
+ const scoreInfo = validationResult.scores ? ` (score: ${validationResult.scores.score}/10)` : '';
235
+ console.error(chalk.red(`\n⛔ ESCALATION — Task(s) ${blockedTasks.map(t => t.id).join(', ')}${scoreInfo}`));
236
+ if (forceEscalate) {
237
+ console.error(chalk.red(' Score below retry threshold — immediate escalation'));
238
+ } else {
239
+ console.error(chalk.red(' Failed 3 times — human review required'));
240
+ }
241
+ console.error(chalk.red(' Mark resolved with: morph-spec state set <feature> validationHistory.<taskId>.status passed'));
229
242
  } else {
230
243
  const attempt = currentFeature.validationHistory?.[tasksToComplete[0]?.id]?.attempt || 1;
231
- console.error(chalk.red(`\n❌ Validation failed (attempt ${attempt}/3) — tasks NOT marked as complete`));
244
+ const scoreInfo = validationResult.scores ? ` | score: ${validationResult.scores.score}/10` : '';
245
+ console.error(chalk.red(`\n❌ Validation failed (attempt ${attempt}/3${scoreInfo}) — tasks NOT marked as complete`));
232
246
  console.log(chalk.gray(' Fix the issues above, then run task done again'));
233
247
  if (attempt >= 2) {
234
248
  console.log(chalk.yellow(` ⚠️ Next failure will escalate to human review`));
@@ -436,14 +450,14 @@ class TaskManager {
436
450
  ? validatorEntries.filter(v => v.passed).length / validatorEntries.length
437
451
  : (result.passed ? 1.0 : 0.0);
438
452
 
439
- return { passed: result.passed, validators, passRate };
453
+ return { passed: result.passed, validators, passRate, scores: result.scores || null };
440
454
  } catch (error) {
441
455
  // If validation runner fails to load, warn but don't block task completion.
442
456
  // This is fail-open by design: a broken validator shouldn't block commits.
443
457
  // Common cause: missing optional deps.
444
458
  console.log(chalk.yellow(`\n⚠️ Validation skipped (${error.message})`));
445
459
  console.log(chalk.gray(` Run manually: morph-spec validate-feature ${featureName}`));
446
- return { passed: true, validators: {}, passRate: 1.0 };
460
+ return { passed: true, validators: {}, passRate: 1.0, scores: null };
447
461
  }
448
462
  }
449
463
 
@@ -455,21 +469,32 @@ class TaskManager {
455
469
  * @param {string} taskId - Task ID
456
470
  * @param {{ passed: boolean, validators: Object, passRate: number }} validationResult
457
471
  */
458
- persistValidationHistory(feature, taskId, validationResult) {
472
+ persistValidationHistory(feature, taskId, validationResult, forceEscalate = false) {
459
473
  if (!feature.validationHistory) {
460
474
  feature.validationHistory = {};
461
475
  }
462
476
  const existing = feature.validationHistory[taskId] || { attempt: 0 };
463
477
  const attempt = (existing.attempt || 0) + 1;
464
- const status = attempt >= 3 ? 'blocked' : 'failed';
478
+ const status = forceEscalate ? 'blocked' : (attempt >= 3 ? 'blocked' : 'failed');
465
479
 
466
- feature.validationHistory[taskId] = {
480
+ const entry = {
467
481
  attempt,
468
482
  validators: validationResult.validators || {},
469
483
  passRate: validationResult.passRate || 0,
470
484
  status,
471
485
  updatedAt: new Date().toISOString(),
472
486
  };
487
+
488
+ // Attach score data when available
489
+ if (validationResult.scores) {
490
+ entry.scores = {
491
+ score: validationResult.scores.score,
492
+ action: validationResult.scores.action,
493
+ breakdown: validationResult.scores.breakdown,
494
+ };
495
+ }
496
+
497
+ feature.validationHistory[taskId] = entry;
473
498
  }
474
499
 
475
500
  /**
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "morph-spec",
3
- "version": "4.19.0",
3
+ "version": "4.20.0",
4
4
  "displayName": "MORPH-SPEC Framework",
5
5
  "description": "Spec-driven development with 38 agents and 8-phase workflow for .NET/Blazor/Next.js/Azure",
6
6
  "publisher": "polymorphism-tech",
@@ -196,4 +196,4 @@ These files are never edited directly. Use CLI commands or `morph-spec update` i
196
196
 
197
197
  ---
198
198
 
199
- *morph-spec v4.19.0 by Polymorphism Tech*
199
+ *morph-spec v4.20.0 by Polymorphism Tech*
@@ -197,4 +197,4 @@ morph-spec doctor
197
197
 
198
198
  ---
199
199
 
200
- *morph-spec v4.19.0 by Polymorphism Tech*
200
+ *morph-spec v4.20.0 by Polymorphism Tech*
@@ -19,6 +19,18 @@ READ-ONLY scanner for architectural violations in .NET VSA projects.
19
19
 
20
20
  ---
21
21
 
22
+ ## Evaluation Posture
23
+
24
+ You are an ADVERSARIAL evaluator. Your default assumption is that architectural violations exist.
25
+
26
+ - **Assume violations exist** until proven otherwise — your job is to FIND them, not confirm the architecture is clean
27
+ - **Challenge surface appearances** — code that compiles and runs may hide dependency violations or SRP breaches
28
+ - **A clean report is suspicious** — if you found nothing, dig deeper before concluding
29
+ - **Prioritize by severity** — wrong dependency direction and DI violations before style warnings
30
+ - **Be specific** — every finding needs file path, line number, violation type, and concrete fix
31
+
32
+ ---
33
+
22
34
  ## Scan Categories
23
35
 
24
36
  ### Critical (Severity: Error)
@@ -19,6 +19,18 @@ READ-ONLY scanner for NuGet and npm package issues.
19
19
 
20
20
  ---
21
21
 
22
+ ## Evaluation Posture
23
+
24
+ You are an ADVERSARIAL evaluator. Your default assumption is that dependency issues exist.
25
+
26
+ - **Assume problems exist** until proven otherwise — your job is to FIND version conflicts and deprecated packages, not confirm everything is up to date
27
+ - **Challenge surface appearances** — packages that install without errors may still have version conflicts, security advisories, or deprecated APIs
28
+ - **A clean report is suspicious** — if you found nothing, dig deeper before concluding
29
+ - **Prioritize by severity** — version conflicts and security advisories before style preferences
30
+ - **Be specific** — every finding needs file path, package name, installed version, and concrete fix
31
+
32
+ ---
33
+
22
34
  ## Scan Categories
23
35
 
24
36
  ### NuGet (.csproj)
@@ -18,6 +18,18 @@ READ-ONLY scanner for security vulnerabilities across all source files.
18
18
 
19
19
  ---
20
20
 
21
+ ## Evaluation Posture
22
+
23
+ You are an ADVERSARIAL evaluator. Your default assumption is that security vulnerabilities exist.
24
+
25
+ - **Assume vulnerabilities exist** until proven otherwise — your job is to FIND them, not confirm the code is safe
26
+ - **Challenge surface appearances** — code that looks secure may hide subtle injection vectors or auth bypasses
27
+ - **A clean report is suspicious** — if you found nothing, dig deeper before concluding
28
+ - **Prioritize by severity** — critical vulnerabilities (injection, secrets) before style issues
29
+ - **Be specific** — every finding needs file path, line number, vulnerability type, and concrete fix
30
+
31
+ ---
32
+
21
33
  ## Scan Categories
22
34
 
23
35
  ### Critical (Severity: Error)
@@ -29,6 +29,18 @@ READ-ONLY scanner for design token compliance across CSS and component files.
29
29
 
30
30
  ---
31
31
 
32
+ ## Evaluation Posture
33
+
34
+ You are an ADVERSARIAL evaluator. Your default assumption is that design token violations exist.
35
+
36
+ - **Assume violations exist** until proven otherwise — your job is to FIND hardcoded values and naming inconsistencies, not confirm compliance
37
+ - **Challenge surface appearances** — components that look correct visually may use hardcoded colors, spacing, or typography that bypass the design system
38
+ - **A clean report is suspicious** — if you found nothing, dig deeper before concluding
39
+ - **Prioritize by severity** — hardcoded colors and spacing before naming convention warnings
40
+ - **Be specific** — every finding needs file path, line number, the hardcoded value found, and the correct design token to use
41
+
42
+ ---
43
+
32
44
  ## Scan Categories
33
45
 
34
46
  ### Colors
@@ -21,6 +21,18 @@ READ-ONLY scanner for App Router compliance in Next.js projects.
21
21
 
22
22
  ---
23
23
 
24
+ ## Evaluation Posture
25
+
26
+ You are an ADVERSARIAL evaluator. Your default assumption is that App Router violations exist.
27
+
28
+ - **Assume violations exist** until proven otherwise — your job is to FIND boundary errors and pattern misuse, not confirm compliance
29
+ - **Challenge surface appearances** — components that render correctly may have wrong `'use client'` placement, missing Suspense boundaries, or server/client leaks
30
+ - **A clean report is suspicious** — if you found nothing, dig deeper before concluding
31
+ - **Prioritize by severity** — server/client boundary violations before performance optimizations
32
+ - **Be specific** — every finding needs file path, line number, the violation type, and concrete fix
33
+
34
+ ---
35
+
24
36
  ## Scan Categories
25
37
 
26
38
  ### Server/Client Boundaries
@@ -83,6 +83,19 @@ async function dispatch(command, payload) {
83
83
  }).trim();
84
84
  } catch { /* no git */ }
85
85
 
86
+ // Include score context from latest validation if available
87
+ let scoreContext = '';
88
+ try {
89
+ const evalFeature = getFeature(featureName);
90
+ const taskScores = evalFeature?.validationHistory?.[taskId]?.scores;
91
+ if (taskScores) {
92
+ scoreContext = `\n## Previous Validation Score: ${taskScores.score}/10\n` +
93
+ Object.entries(taskScores.breakdown || {})
94
+ .map(([cat, d]) => ` ${cat}: ${Math.round(d.score * 10) / 10}/10 (weight ${Math.round(d.weight * 100)}%)`)
95
+ .join('\n') + '\n\nFocus your evaluation on categories with the lowest scores.\n';
96
+ }
97
+ } catch { /* non-blocking */ }
98
+
86
99
  contextParts.push(
87
100
  `🔍 EVALUATOR DISPATCH\n` +
88
101
  `════════════════════════════════════════\n` +
@@ -92,14 +105,18 @@ async function dispatch(command, payload) {
92
105
  ` model: "sonnet"\n` +
93
106
  ` prompt: (see below)\n\n` +
94
107
  `--- EVALUATOR PROMPT ---\n` +
95
- `You are an independent evaluator. Validate this implementation against the sprint contract.\n\n` +
108
+ `You are an ADVERSARIAL evaluator. Your default assumption is that defects exist.\n` +
109
+ `Do NOT confirm correctness — actively search for problems.\n\n` +
96
110
  `## Contract\n${contractContent}\n\n` +
97
- `## Changed Files\n${changedFiles || '(unable to determine)'}\n\n` +
111
+ `## Changed Files\n${changedFiles || '(unable to determine)'}\n` +
112
+ `${scoreContext}\n` +
98
113
  `## Instructions\n` +
99
114
  `1. Read each changed file\n` +
100
115
  `2. Run the verification commands from the contract\n` +
101
116
  `3. Evaluate each definitionOfDone item: PASS or FAIL with evidence\n` +
102
- `4. Return a structured result with overall PASS/FAIL\n` +
117
+ `4. For each category, score 0-10 and explain deficiencies found\n` +
118
+ `5. A clean report is suspicious — dig deeper before declaring PASS\n` +
119
+ `6. Return a structured result with overall PASS/FAIL and score breakdown\n` +
103
120
  `--- END EVALUATOR PROMPT ---`
104
121
  );
105
122
  }
@@ -79,6 +79,7 @@ try {
79
79
  function buildRemediationContext(featureName, taskId, taskHistory) {
80
80
  const attempt = taskHistory.attempt || 1;
81
81
  const validators = taskHistory.validators || {};
82
+ const scores = taskHistory.scores || null;
82
83
 
83
84
  // Collect all issues across all validators
84
85
  const allIssues = [];
@@ -95,28 +96,60 @@ function buildRemediationContext(featureName, taskId, taskHistory) {
95
96
  const lines = [];
96
97
 
97
98
  if (taskHistory.status === 'blocked') {
98
- // Max attempts reached — escalation message
99
- lines.push(`⛔ ESCALATION REQUIRED — Task ${taskId} in feature '${featureName}'`);
100
- lines.push(` Validation failed ${attempt} times (max attempts reached).`);
99
+ // Max attempts reached OR score-based escalation
100
+ const scoreInfo = scores ? ` (score: ${scores.score}/10)` : '';
101
+ lines.push(`⛔ ESCALATION REQUIRED — Task ${taskId} in feature '${featureName}'${scoreInfo}`);
102
+ if (scores?.action === 'escalate') {
103
+ lines.push(` Score below retry threshold — immediate escalation.`);
104
+ } else {
105
+ lines.push(` Validation failed ${attempt} times (max attempts reached).`);
106
+ }
101
107
  lines.push(` Human review required before proceeding.`);
108
+ if (scores) {
109
+ lines.push(``);
110
+ lines.push(` Score breakdown:`);
111
+ appendScoreBreakdown(lines, scores);
112
+ }
102
113
  lines.push(` Last failures:`);
103
114
  for (const issue of allIssues.slice(0, 5)) {
104
115
  lines.push(` • [${issue.validator}] ${issue.message} ${issue.file ? `(${issue.file}${issue.line ? ':' + issue.line : ''})` : ''}`);
105
116
  }
106
117
  } else {
107
118
  // Active remediation — attempt N of 3
108
- lines.push(`🔄 REMEDIATION REQUIRED — Task ${taskId} (attempt ${attempt}/3)`);
119
+ const scoreInfo = scores ? ` | score: ${scores.score}/10` : '';
120
+ lines.push(`🔄 REMEDIATION REQUIRED — Task ${taskId} (attempt ${attempt}/3${scoreInfo})`);
109
121
  lines.push(` Validation failed. Fix the following issues and re-run:`);
110
122
  lines.push(` morph-spec task done ${featureName} ${taskId}`);
111
123
  lines.push(``);
112
124
 
113
- for (const issue of allIssues) {
114
- const refKey = getRefKey(issue.rule || issue.validator);
115
- const ref = refKey ? ` — Ref: ${STANDARD_REFS[refKey] || refKey}` : '';
116
- const location = issue.file
117
- ? ` (${issue.file}${issue.line ? ':' + issue.line : ''})`
118
- : '';
119
- lines.push(` • [${issue.validator}] ${issue.message}${location}${ref}`);
125
+ // Score-based prioritized feedback (when available)
126
+ if (scores?.breakdown) {
127
+ lines.push(` Priority fixes (by impact):`);
128
+ const sorted = Object.entries(scores.breakdown)
129
+ .filter(([, cat]) => (cat.issues?.length || 0) > 0)
130
+ .sort((a, b) => ((10 - b[1].score) * b[1].weight) - ((10 - a[1].score) * a[1].weight));
131
+
132
+ for (const [category, cat] of sorted) {
133
+ const topIssue = cat.issues[0];
134
+ const location = topIssue?.file ? ` (${topIssue.file}${topIssue.line ? ':' + topIssue.line : ''})` : '';
135
+ const msg = topIssue?.message || 'Issues detected';
136
+ lines.push(` ${Math.round(cat.score * 10) / 10}/10 [${category}] ${msg}${location}`);
137
+ if (cat.issues.length > 1) {
138
+ lines.push(` ... and ${cat.issues.length - 1} more issue(s)`);
139
+ }
140
+ }
141
+ lines.push(``);
142
+ appendScoreBreakdown(lines, scores);
143
+ } else {
144
+ // Fallback: original issue-by-issue format
145
+ for (const issue of allIssues) {
146
+ const refKey = getRefKey(issue.rule || issue.validator);
147
+ const ref = refKey ? ` — Ref: ${STANDARD_REFS[refKey] || refKey}` : '';
148
+ const location = issue.file
149
+ ? ` (${issue.file}${issue.line ? ':' + issue.line : ''})`
150
+ : '';
151
+ lines.push(` • [${issue.validator}] ${issue.message}${location}${ref}`);
152
+ }
120
153
  }
121
154
 
122
155
  if (attempt >= 2) {
@@ -128,6 +161,22 @@ function buildRemediationContext(featureName, taskId, taskHistory) {
128
161
  injectContext(lines.join('\n'));
129
162
  }
130
163
 
164
+ /**
165
+ * Append score breakdown lines to output.
166
+ * @param {string[]} lines - Output array
167
+ * @param {Object} scores - { score, action, breakdown }
168
+ */
169
+ function appendScoreBreakdown(lines, scores) {
170
+ if (!scores?.breakdown) return;
171
+ const approveThreshold = scores.approveThreshold ?? 8.0;
172
+ for (const [category, data] of Object.entries(scores.breakdown)) {
173
+ if (category === '_unmapped') continue; // skip internal unmapped category
174
+ const pct = Math.round(data.weight * 100);
175
+ const indicator = data.score >= approveThreshold ? '\u2713' : data.score >= 6 ? '\u2193' : '\u2193\u2193';
176
+ lines.push(` ${category}: ${Math.round(data.score * 10) / 10}/10 (weight ${pct}%) ${indicator}`);
177
+ }
178
+ }
179
+
131
180
  /**
132
181
  * Map a rule/validator name to a STANDARD_REFS key.
133
182
  * @param {string} ruleOrValidator
@@ -0,0 +1,36 @@
1
+ {
2
+ "id": "backend",
3
+ "version": "1.0.0",
4
+ "description": "Backend-focused rubric. Higher weight on architecture, security, and package health.",
5
+ "categories": {
6
+ "functionality": {
7
+ "weight": 0.30,
8
+ "validators": ["contract-compliance"],
9
+ "description": "Core feature correctness and contract compliance"
10
+ },
11
+ "code_quality": {
12
+ "weight": 0.30,
13
+ "validators": ["architecture"],
14
+ "description": "Architecture patterns, dependency direction, and code structure"
15
+ },
16
+ "design_ui": {
17
+ "weight": 0.05,
18
+ "validators": ["design-system", "css", "contrast", "nextjs-component"],
19
+ "description": "Design system compliance (minimal weight for backend projects)"
20
+ },
21
+ "security": {
22
+ "weight": 0.15,
23
+ "validators": [],
24
+ "description": "Security posture (agent-evaluated, no automated validator)"
25
+ },
26
+ "packages": {
27
+ "weight": 0.20,
28
+ "validators": ["packages"],
29
+ "description": "Dependency health, version compatibility, and deprecated packages"
30
+ }
31
+ },
32
+ "thresholds": {
33
+ "approve": 8.0,
34
+ "retry": 6.0
35
+ }
36
+ }
@@ -0,0 +1,36 @@
1
+ {
2
+ "id": "default",
3
+ "version": "1.0.0",
4
+ "description": "Default rubric for general-purpose projects. Balanced weights across all categories.",
5
+ "categories": {
6
+ "functionality": {
7
+ "weight": 0.30,
8
+ "validators": ["contract-compliance"],
9
+ "description": "Core feature correctness and contract compliance"
10
+ },
11
+ "code_quality": {
12
+ "weight": 0.25,
13
+ "validators": ["architecture"],
14
+ "description": "Architecture patterns and code structure"
15
+ },
16
+ "design_ui": {
17
+ "weight": 0.15,
18
+ "validators": ["design-system", "css", "contrast", "nextjs-component"],
19
+ "description": "Design system compliance, CSS quality, and UI correctness"
20
+ },
21
+ "security": {
22
+ "weight": 0.15,
23
+ "validators": [],
24
+ "description": "Security posture (agent-evaluated, no automated validator)"
25
+ },
26
+ "packages": {
27
+ "weight": 0.15,
28
+ "validators": ["packages"],
29
+ "description": "Dependency health and compatibility"
30
+ }
31
+ },
32
+ "thresholds": {
33
+ "approve": 8.0,
34
+ "retry": 6.0
35
+ }
36
+ }
@@ -0,0 +1,36 @@
1
+ {
2
+ "id": "frontend",
3
+ "version": "1.0.0",
4
+ "description": "Frontend-focused rubric. Higher weight on design system compliance and UI quality.",
5
+ "categories": {
6
+ "functionality": {
7
+ "weight": 0.25,
8
+ "validators": ["contract-compliance"],
9
+ "description": "Core feature correctness and contract compliance"
10
+ },
11
+ "code_quality": {
12
+ "weight": 0.15,
13
+ "validators": ["architecture"],
14
+ "description": "Architecture patterns and code structure"
15
+ },
16
+ "design_ui": {
17
+ "weight": 0.35,
18
+ "validators": ["design-system", "css", "contrast", "nextjs-component"],
19
+ "description": "Design system compliance, CSS quality, contrast ratios, and component correctness"
20
+ },
21
+ "security": {
22
+ "weight": 0.10,
23
+ "validators": [],
24
+ "description": "Security posture (agent-evaluated, no automated validator)"
25
+ },
26
+ "packages": {
27
+ "weight": 0.15,
28
+ "validators": ["packages"],
29
+ "description": "Dependency health and compatibility"
30
+ }
31
+ },
32
+ "thresholds": {
33
+ "approve": 8.0,
34
+ "retry": 6.0
35
+ }
36
+ }
@@ -10,7 +10,7 @@ allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion,
10
10
  mcp__playwright__browser_navigate, mcp__playwright__browser_resize,
11
11
  mcp__playwright__browser_take_screenshot, mcp__playwright__browser_snapshot,
12
12
  mcp__playwright__browser_evaluate, mcp__playwright__browser_console_messages
13
- cliVersion: "4.19.0"
13
+ cliVersion: "4.20.0"
14
14
  stacks:
15
15
  - nextjs
16
16
  ---
@@ -3,7 +3,7 @@ name: morph-phase-codebase-analysis
3
3
  description: MORPH-SPEC Design sub-phase that analyzes existing codebase and database schema, producing schema-analysis.md with real column names, types, relationships, and field mismatches. Use at the start of Design phase before generating contracts.cs to prevent incorrect field names or types.
4
4
  user-invocable: false
5
5
  allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion
6
- cliVersion: "4.19.0"
6
+ cliVersion: "4.20.0"
7
7
  ---
8
8
 
9
9
  # MORPH Codebase Analysis - Design Sub-phase
@@ -4,7 +4,7 @@ description: MORPH-SPEC Phase 2 (Design). Schema-first interactive design: reads
4
4
  argument-hint: "[feature-name]"
5
5
  user-invocable: false
6
6
  allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion, Agent
7
- cliVersion: "4.19.0"
7
+ cliVersion: "4.20.0"
8
8
  ---
9
9
 
10
10
  # MORPH Design — Phase 2
@@ -5,7 +5,7 @@ argument-hint: "[feature-name]"
5
5
  context: fork
6
6
  agent: general-purpose
7
7
  user-invocable: false
8
- cliVersion: "4.19.0"
8
+ cliVersion: "4.20.0"
9
9
  allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion, Agent
10
10
  ---
11
11
 
@@ -4,7 +4,7 @@ description: MORPH-SPEC Phase 3 (Plan). Generates a detailed implementation plan
4
4
  argument-hint: "[feature-name]"
5
5
  user-invocable: false
6
6
  allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion
7
- cliVersion: "4.19.0"
7
+ cliVersion: "4.20.0"
8
8
  ---
9
9
 
10
10
  # MORPH Plan — Phase 3
@@ -4,7 +4,7 @@ description: MORPH-SPEC Phase 4 (Tasks). Breaks approved spec into bottom-up ord
4
4
  argument-hint: "[feature-name]"
5
5
  user-invocable: false
6
6
  allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion
7
- cliVersion: "4.19.0"
7
+ cliVersion: "4.20.0"
8
8
  ---
9
9
 
10
10
  # MORPH Tasks — Phase 4
@@ -4,7 +4,7 @@ description: MORPH-SPEC Phase 2 (UI/UX). Creates design-system.md, mockups.md, c
4
4
  argument-hint: "[feature-name]"
5
5
  user-invocable: false
6
6
  allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion
7
- cliVersion: "4.19.0"
7
+ cliVersion: "4.20.0"
8
8
  ---
9
9
 
10
10
  # MORPH UI/UX Design - Phase 2
@@ -4,7 +4,7 @@ description: Guided workflow for mid-implementation scope escalation — analyze
4
4
  user-invocable: true
5
5
  argument-hint: "[feature-name]"
6
6
  allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion
7
- cliVersion: "4.19.0"
7
+ cliVersion: "4.20.0"
8
8
  ---
9
9
 
10
10
  # Scope Escalation Workflow
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polymorphism-tech/morph-spec",
3
- "version": "4.19.0",
3
+ "version": "4.20.0",
4
4
  "description": "MORPH-SPEC: AI-First development framework with validation pipeline and multi-stack support",
5
5
  "keywords": [
6
6
  "claude-code",