@polymorphism-tech/morph-spec 4.5.0 → 4.6.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 (71) hide show
  1. package/.morph/.morphversion +3 -3
  2. package/.morph/analytics/threads-log.jsonl +6 -44
  3. package/.morph/config/config.json +1 -1
  4. package/.morph/framework/standards/frontend/nextjs/nextjs-patterns.md +17 -0
  5. package/.morph/framework/templates/docs/user-stories.md +34 -0
  6. package/.morph/logs/tool-failures.log +7 -51
  7. package/.morph/memory/{pre-compact-2026-02-22T17-01-01-658Z.json → pre-compact-2026-02-23T15-43-03-521Z.json} +1 -1
  8. package/CLAUDE.md +77 -56
  9. package/framework/{skills/level-2-domains → agents}/ai-agents/ai-system-architect.md +1 -4
  10. package/framework/{skills/level-2-domains → agents}/architecture/po-pm-advisor.md +1 -2
  11. package/framework/{skills/level-2-domains → agents}/architecture/prompt-engineer.md +1 -2
  12. package/framework/{skills/level-2-domains → agents}/architecture/seo-growth-hacker.md +1 -2
  13. package/framework/{skills/level-2-domains → agents}/architecture/standards-architect.md +1 -4
  14. package/framework/agents/backend/api-designer.md +103 -0
  15. package/framework/{skills/level-2-domains → agents}/backend/dotnet-senior.md +1 -2
  16. package/framework/agents/backend/ef-modeler.md +119 -0
  17. package/framework/{skills/level-2-domains → agents}/backend/hangfire-orchestrator.md +1 -4
  18. package/framework/{skills/level-2-domains → agents}/backend/ms-agent-expert.md +1 -4
  19. package/framework/{skills/level-2-domains → agents}/frontend/blazor-builder.md +1 -4
  20. package/framework/{skills/level-2-domains → agents}/frontend/nextjs-expert.md +1 -4
  21. package/framework/{skills/level-2-domains → agents}/frontend/ui-ux-designer.md +1 -2
  22. package/framework/{skills/level-2-domains → agents}/infrastructure/azure-architect.md +1 -2
  23. package/framework/{skills/level-2-domains → agents}/infrastructure/azure-deploy-specialist.md +1 -2
  24. package/framework/{skills/level-2-domains → agents}/infrastructure/bicep-architect.md +1 -4
  25. package/framework/{skills/level-2-domains → agents}/infrastructure/container-specialist.md +1 -4
  26. package/framework/{skills/level-2-domains → agents}/infrastructure/devops-engineer.md +1 -4
  27. package/framework/{skills/level-2-domains → agents}/integrations/asaas-financial.md +1 -4
  28. package/framework/{skills/level-2-domains → agents}/integrations/azure-identity.md +1 -4
  29. package/framework/{skills/level-2-domains → agents}/integrations/clerk-auth.md +1 -4
  30. package/framework/{skills/level-2-domains → agents}/integrations/hangfire-integration.md +1 -2
  31. package/framework/{skills/level-2-domains → agents}/integrations/resend-email.md +1 -4
  32. package/framework/{skills/level-2-domains → agents}/quality/code-analyzer.md +1 -4
  33. package/framework/{skills/level-2-domains → agents}/quality/testing-specialist.md +1 -4
  34. package/framework/hooks/claude-code/statusline.py +384 -85
  35. package/framework/hooks/shared/phase-utils.js +129 -129
  36. package/framework/skills/README.md +66 -0
  37. package/framework/skills/level-0-meta/{brainstorming.md → brainstorming/SKILL.md} +3 -1
  38. package/framework/skills/level-0-meta/brainstorming/references/proposal-example.md +138 -0
  39. package/framework/skills/level-0-meta/{code-review.md → code-review/SKILL.md} +3 -2
  40. package/framework/skills/level-0-meta/code-review/references/review-example.md +164 -0
  41. package/framework/skills/level-0-meta/code-review/scripts/scan-csharp.mjs +121 -0
  42. package/framework/skills/level-0-meta/{morph-checklist.md → morph-checklist/SKILL.md} +2 -5
  43. package/framework/skills/{level-1-workflows/morph-replicate.md → level-0-meta/morph-replicate/SKILL.md} +6 -7
  44. package/framework/skills/level-0-meta/{simulation-checklist.md → simulation-checklist/SKILL.md} +3 -6
  45. package/framework/skills/level-0-meta/{tool-usage-guide.md → tool-usage-guide/SKILL.md} +1 -2
  46. package/framework/skills/level-0-meta/{verification-before-completion.md → verification-before-completion/SKILL.md} +3 -1
  47. package/framework/skills/level-0-meta/verification-before-completion/scripts/check-phase-outputs.mjs +110 -0
  48. package/framework/skills/level-1-workflows/{phase-clarify.md → phase-clarify/SKILL.md} +3 -3
  49. package/framework/skills/level-1-workflows/phase-clarify/references/clarifications-example.md +117 -0
  50. package/framework/skills/level-1-workflows/{phase-codebase-analysis.md → phase-codebase-analysis/SKILL.md} +2 -3
  51. package/framework/skills/level-1-workflows/{phase-design.md → phase-design/SKILL.md} +13 -185
  52. package/framework/skills/level-1-workflows/phase-design/references/spec-example.md +253 -0
  53. package/framework/skills/level-1-workflows/{phase-implement.md → phase-implement/SKILL.md} +3 -3
  54. package/framework/skills/level-1-workflows/phase-implement/references/recap-example.md +132 -0
  55. package/framework/skills/level-1-workflows/{phase-setup.md → phase-setup/SKILL.md} +2 -3
  56. package/framework/skills/level-1-workflows/{phase-tasks.md → phase-tasks/SKILL.md} +4 -3
  57. package/framework/skills/level-1-workflows/phase-tasks/references/tasks-example.md +231 -0
  58. package/framework/skills/level-1-workflows/phase-tasks/scripts/validate-tasks.mjs +112 -0
  59. package/framework/skills/level-1-workflows/{phase-uiux.md → phase-uiux/SKILL.md} +2 -3
  60. package/package.json +1 -1
  61. package/src/commands/project/init.js +4 -64
  62. package/src/commands/project/update.js +1 -62
  63. package/src/lib/detectors/claude-config-detector.js +1 -3
  64. package/src/utils/agents-installer.js +2 -2
  65. package/src/utils/skills-installer.js +59 -15
  66. package/.morph/context/README.md +0 -17
  67. package/framework/skills/level-2-domains/backend/api-designer.md +0 -66
  68. package/framework/skills/level-2-domains/backend/ef-modeler.md +0 -65
  69. package/framework/skills/level-3-technologies/README.md +0 -7
  70. package/framework/skills/level-4-patterns/README.md +0 -7
  71. /package/framework/{skills/level-2-domains → agents}/README.md +0 -0
@@ -1,129 +1,129 @@
1
- // GENERATED by scripts/generate-refs.js — DO NOT EDIT manually
2
- // Source of truth: src/core/paths/output-schema.js
3
- // Regenerate with: node scripts/generate-refs.js
4
- /**
5
- * Shared phase utilities for Claude Code hooks.
6
- *
7
- * Maps phases to directories and output types.
8
- */
9
-
10
- /** Phase order */
11
- export const PHASE_ORDER = ["proposal","setup","uiux","design","clarify","tasks","implement","sync"];
12
-
13
- /** Map phase → allowed output subdirectory */
14
- export const PHASE_DIRS = {
15
- proposal: '0-proposal',
16
- setup: '0-proposal',
17
- uiux: '2-ui',
18
- design: '1-design',
19
- clarify: '1-design',
20
- tasks: '3-tasks',
21
- implement: '4-implement',
22
- sync: '4-implement',
23
- };
24
-
25
- /** Map output type (camelCase) → phase that produces it */
26
- export const OUTPUT_PHASE_MAP = {
27
- proposal: 'proposal',
28
- schemaAnalysis: 'design',
29
- spec: 'design',
30
- clarifications: 'clarify',
31
- contracts: 'design',
32
- tasks: 'tasks',
33
- uiDesignSystem: 'uiux',
34
- uiMockups: 'uiux',
35
- uiComponents: 'uiux',
36
- uiFlows: 'uiux',
37
- decisions: 'design',
38
- recap: 'implement',
39
- };
40
-
41
- /** Map filename → output type (camelCase) */
42
- export const FILENAME_TO_OUTPUT = {
43
- 'proposal.md': 'proposal',
44
- 'schema-analysis.md': 'schemaAnalysis',
45
- 'spec.md': 'spec',
46
- 'clarifications.md': 'clarifications',
47
- 'contracts.cs': 'contracts',
48
- 'tasks.md': 'tasks',
49
- 'design-system.md': 'uiDesignSystem',
50
- 'mockups.md': 'uiMockups',
51
- 'components.md': 'uiComponents',
52
- 'flows.md': 'uiFlows',
53
- 'decisions.md': 'decisions',
54
- 'recap.md': 'recap',
55
- };
56
-
57
- /** Protected spec files and the approval gate that locks them */
58
- export const PROTECTED_SPEC_FILES = {
59
- 'schema-analysis.md': 'design',
60
- 'spec.md': 'design',
61
- 'contracts.cs': 'design',
62
- 'tasks.md': 'tasks',
63
- 'design-system.md': 'uiux',
64
- 'mockups.md': 'uiux',
65
- 'components.md': 'uiux',
66
- 'flows.md': 'uiux',
67
- };
68
-
69
- /**
70
- * Extract feature name from a .morph/features/{feature}/... path
71
- * @param {string} filePath - File path to analyze
72
- * @returns {string|null} Feature name or null
73
- */
74
- export function extractFeatureName(filePath) {
75
- const normalized = filePath.replace(/\\/g, '/');
76
- const match = normalized.match(/\.morph\/features\/([^/]+)\//);
77
- return match ? match[1] : null;
78
- }
79
-
80
- /**
81
- * Extract phase subdirectory from a .morph/features/{feature}/{phaseDir}/... path
82
- * @param {string} filePath - File path to analyze
83
- * @returns {string|null} Phase directory (e.g., '0-proposal', '1-design') or null
84
- */
85
- export function extractPhaseDir(filePath) {
86
- const normalized = filePath.replace(/\\/g, '/');
87
- const match = normalized.match(/\.morph\/features\/[^/]+\/(\d+-[^/]+)\//);
88
- return match ? match[1] : null;
89
- }
90
-
91
- /**
92
- * Check if a file path is inside .morph/features/
93
- * @param {string} filePath
94
- * @returns {boolean}
95
- */
96
- export function isFeaturePath(filePath) {
97
- const normalized = filePath.replace(/\\/g, '/');
98
- return normalized.includes('.morph/features/');
99
- }
100
-
101
- /**
102
- * Check if a file path is inside .morph/framework/ (readonly)
103
- * @param {string} filePath
104
- * @returns {boolean}
105
- */
106
- export function isFrameworkPath(filePath) {
107
- const normalized = filePath.replace(/\\/g, '/');
108
- return normalized.includes('.morph/framework/');
109
- }
110
-
111
- /**
112
- * Check if a file path is state.json
113
- * @param {string} filePath
114
- * @returns {boolean}
115
- */
116
- export function isStatePath(filePath) {
117
- const normalized = filePath.replace(/\\/g, '/');
118
- return normalized.endsWith('.morph/state.json');
119
- }
120
-
121
- /**
122
- * Get the basename of a file path
123
- * @param {string} filePath
124
- * @returns {string}
125
- */
126
- export function getBasename(filePath) {
127
- const normalized = filePath.replace(/\\/g, '/');
128
- return normalized.split('/').pop();
129
- }
1
+ // GENERATED by scripts/generate-refs.js — DO NOT EDIT manually
2
+ // Source of truth: src/core/paths/output-schema.js
3
+ // Regenerate with: node scripts/generate-refs.js
4
+ /**
5
+ * Shared phase utilities for Claude Code hooks.
6
+ *
7
+ * Maps phases to directories and output types.
8
+ */
9
+
10
+ /** Phase order */
11
+ export const PHASE_ORDER = ["proposal","setup","uiux","design","clarify","tasks","implement","sync"];
12
+
13
+ /** Map phase → allowed output subdirectory */
14
+ export const PHASE_DIRS = {
15
+ proposal: '0-proposal',
16
+ setup: '0-proposal',
17
+ uiux: '2-ui',
18
+ design: '1-design',
19
+ clarify: '1-design',
20
+ tasks: '3-tasks',
21
+ implement: '4-implement',
22
+ sync: '4-implement',
23
+ };
24
+
25
+ /** Map output type (camelCase) → phase that produces it */
26
+ export const OUTPUT_PHASE_MAP = {
27
+ proposal: 'proposal',
28
+ schemaAnalysis: 'design',
29
+ spec: 'design',
30
+ clarifications: 'clarify',
31
+ contracts: 'design',
32
+ tasks: 'tasks',
33
+ uiDesignSystem: 'uiux',
34
+ uiMockups: 'uiux',
35
+ uiComponents: 'uiux',
36
+ uiFlows: 'uiux',
37
+ decisions: 'design',
38
+ recap: 'implement',
39
+ };
40
+
41
+ /** Map filename → output type (camelCase) */
42
+ export const FILENAME_TO_OUTPUT = {
43
+ 'proposal.md': 'proposal',
44
+ 'schema-analysis.md': 'schemaAnalysis',
45
+ 'spec.md': 'spec',
46
+ 'clarifications.md': 'clarifications',
47
+ 'contracts.cs': 'contracts',
48
+ 'tasks.md': 'tasks',
49
+ 'design-system.md': 'uiDesignSystem',
50
+ 'mockups.md': 'uiMockups',
51
+ 'components.md': 'uiComponents',
52
+ 'flows.md': 'uiFlows',
53
+ 'decisions.md': 'decisions',
54
+ 'recap.md': 'recap',
55
+ };
56
+
57
+ /** Protected spec files and the approval gate that locks them */
58
+ export const PROTECTED_SPEC_FILES = {
59
+ 'schema-analysis.md': 'design',
60
+ 'spec.md': 'design',
61
+ 'contracts.cs': 'design',
62
+ 'tasks.md': 'tasks',
63
+ 'design-system.md': 'uiux',
64
+ 'mockups.md': 'uiux',
65
+ 'components.md': 'uiux',
66
+ 'flows.md': 'uiux',
67
+ };
68
+
69
+ /**
70
+ * Extract feature name from a .morph/features/{feature}/... path
71
+ * @param {string} filePath - File path to analyze
72
+ * @returns {string|null} Feature name or null
73
+ */
74
+ export function extractFeatureName(filePath) {
75
+ const normalized = filePath.replace(/\\/g, '/');
76
+ const match = normalized.match(/\.morph\/features\/([^/]+)\//);
77
+ return match ? match[1] : null;
78
+ }
79
+
80
+ /**
81
+ * Extract phase subdirectory from a .morph/features/{feature}/{phaseDir}/... path
82
+ * @param {string} filePath - File path to analyze
83
+ * @returns {string|null} Phase directory (e.g., '0-proposal', '1-design') or null
84
+ */
85
+ export function extractPhaseDir(filePath) {
86
+ const normalized = filePath.replace(/\\/g, '/');
87
+ const match = normalized.match(/\.morph\/features\/[^/]+\/(\d+-[^/]+)\//);
88
+ return match ? match[1] : null;
89
+ }
90
+
91
+ /**
92
+ * Check if a file path is inside .morph/features/
93
+ * @param {string} filePath
94
+ * @returns {boolean}
95
+ */
96
+ export function isFeaturePath(filePath) {
97
+ const normalized = filePath.replace(/\\/g, '/');
98
+ return normalized.includes('.morph/features/');
99
+ }
100
+
101
+ /**
102
+ * Check if a file path is inside .morph/framework/ (readonly)
103
+ * @param {string} filePath
104
+ * @returns {boolean}
105
+ */
106
+ export function isFrameworkPath(filePath) {
107
+ const normalized = filePath.replace(/\\/g, '/');
108
+ return normalized.includes('.morph/framework/');
109
+ }
110
+
111
+ /**
112
+ * Check if a file path is state.json
113
+ * @param {string} filePath
114
+ * @returns {boolean}
115
+ */
116
+ export function isStatePath(filePath) {
117
+ const normalized = filePath.replace(/\\/g, '/');
118
+ return normalized.endsWith('.morph/state.json');
119
+ }
120
+
121
+ /**
122
+ * Get the basename of a file path
123
+ * @param {string} filePath
124
+ * @returns {string}
125
+ */
126
+ export function getBasename(filePath) {
127
+ const normalized = filePath.replace(/\\/g, '/');
128
+ return normalized.split('/').pop();
129
+ }
@@ -0,0 +1,66 @@
1
+ # MORPH-SPEC Skills
2
+
3
+ Skills installed to `.claude/skills/` during `morph-spec init` (or `morph-spec update`).
4
+
5
+ Each skill is a directory: `{name}/SKILL.md` + optional `scripts/`, `references/`, `assets/`.
6
+
7
+ ---
8
+
9
+ ## level-0-meta — Utilities & Meta-Skills
10
+
11
+ | Skill | Description |
12
+ |-------|-------------|
13
+ | `tool-usage-guide` | Tool selection flowchart — which tool for which action |
14
+ | `morph-checklist` | Pre-session checklist for MORPH-SPEC projects |
15
+ | `simulation-checklist` | Checklist for AI simulation / prompt testing |
16
+ | `brainstorming` | Collaborative ideation → spec via dialogue |
17
+ | `verification-before-completion` | Gate check before marking any work done |
18
+ | `code-review` | .NET/C# review checklist (naming, arch, async, DI, DTOs) |
19
+ | `morph-replicate` | Convert HTML prototypes to Blazor components |
20
+
21
+ ### level-0-meta extras
22
+
23
+ | Skill | File | Purpose |
24
+ |-------|------|---------|
25
+ | `brainstorming` | `references/proposal-example.md` | Filled-in proposal.md example |
26
+ | `verification-before-completion` | `scripts/check-phase-outputs.mjs` | Validate required phase outputs exist |
27
+ | `code-review` | `references/review-example.md` | Filled-in review with finding format |
28
+ | `code-review` | `scripts/scan-csharp.mjs` | Scan .cs files for CRITICAL/HIGH violations |
29
+
30
+ ---
31
+
32
+ ## level-1-workflows — Phase Workflow Skills
33
+
34
+ Invoked internally by `/morph-proposal` and `/morph-apply`. Not user-invocable.
35
+
36
+ | Skill | Phase | Description |
37
+ |-------|-------|-------------|
38
+ | `phase-codebase-analysis` | 0 | Analyse existing codebase before design |
39
+ | `phase-setup` | 1 | Project scaffolding and initial setup |
40
+ | `phase-design` | 2 | Technical spec + contracts + decisions |
41
+ | `phase-uiux` | 3 | UI/UX design system + mockups + components |
42
+ | `phase-clarify` | 4 | Clarification questions → edge cases → spec update |
43
+ | `phase-tasks` | 5 | Break spec into ordered task list (tasks.md) |
44
+ | `phase-implement` | 6 | Implement tasks with TDD + checkpoints + recap |
45
+
46
+ ### level-1-workflows extras
47
+
48
+ | Skill | File | Purpose |
49
+ |-------|------|---------|
50
+ | `phase-design` | `references/spec-example.md` | Filled-in spec.md example |
51
+ | `phase-clarify` | `references/clarifications-example.md` | Filled-in clarifications Q&A |
52
+ | `phase-tasks` | `references/tasks-example.md` | Filled-in tasks.md with T### format |
53
+ | `phase-tasks` | `scripts/validate-tasks.mjs` | Validate tasks.md structure and IDs |
54
+ | `phase-implement` | `references/recap-example.md` | Filled-in recap.md example |
55
+
56
+ ---
57
+
58
+ ## Domain Agents
59
+
60
+ Domain specialist agents (`framework/agents/`) are installed separately as `.claude/agents/morph-domain-{name}.md` — they are subagents, not skills.
61
+
62
+ See `framework/agents/README.md` for the full list.
63
+
64
+ ---
65
+
66
+ *MORPH-SPEC by Polymorphism Tech*
@@ -1,11 +1,13 @@
1
1
  ---
2
2
  name: brainstorming
3
- description: Morph-spec-aware brainstorming for exploring feature approaches, generating proposals, and designing architecture. Use before any creative or implementation work.
3
+ description: Morph-spec-aware brainstorming that loads project context, explores multiple design approaches, asks clarifying questions, and produces proposal.md or decisions.md. Use before designing a feature, when facing architectural decisions with multiple valid approaches, or when a feature needs requirements exploration before committing to a direction.
4
4
  ---
5
5
 
6
6
  # Brainstorming — MORPH-SPEC Integrated
7
7
 
8
8
  > Explore context, ask questions, generate multiple approaches, and produce a design document before committing to implementation.
9
+ >
10
+ > **Example:** `references/proposal-example.md` — filled-in proposal.md showing expected quality.
9
11
 
10
12
  ## When to Use
11
13
 
@@ -0,0 +1,138 @@
1
+ # Feature Proposal: Photo Processing Pipeline
2
+
3
+ > Example of a well-structured proposal.md. This is a filled-in reference — not a template.
4
+
5
+ ## Metadata
6
+
7
+ | Field | Value |
8
+ |-------|-------|
9
+ | **Proposed** | 2025-01-15 |
10
+ | **Author** | Product Team |
11
+ | **Status** | Approved |
12
+ | **Priority** | High |
13
+ | **Stack** | blazor-azure |
14
+
15
+ ---
16
+
17
+ ## Overview
18
+
19
+ Users currently cannot upload photos for AI-based transformations because no upload infrastructure exists. This feature adds an end-to-end photo upload, processing, and delivery pipeline using Azure Blob Storage and Hangfire background jobs.
20
+
21
+ ---
22
+
23
+ ## Problem Statement
24
+
25
+ ### What is the problem?
26
+
27
+ Users cannot submit photos for AI transformation, blocking the core product value proposition. The system has no file upload capability, no background processing queue, and no way to notify users when processing completes.
28
+
29
+ ### Who is affected?
30
+
31
+ All end users who want to use the photo transformation feature — the primary user journey is completely unavailable.
32
+
33
+ ### What is the impact?
34
+
35
+ - User productivity loss: 100% of core use case unavailable
36
+ - Revenue impact: Feature is the primary paid tier differentiator
37
+ - User satisfaction: Can't demo product to prospects
38
+
39
+ ---
40
+
41
+ ## Proposed Solution
42
+
43
+ ### Overview
44
+
45
+ A multi-step pipeline: user uploads a photo via a Blazor form → the file is stored in Azure Blob Storage → a Hangfire background job is queued for AI processing → the user polls for completion → the processed photo is returned via a download link.
46
+
47
+ ### Key Features
48
+
49
+ 1. **Upload endpoint** — Validates file type/size, stores in Azure Blob
50
+ 2. **Background processing** — Hangfire job calls AI API, stores result in Blob
51
+ 3. **Status polling** — User sees real-time progress (Pending → Processing → Completed)
52
+
53
+ ### User Journey
54
+
55
+ ```
56
+ 1. User selects a photo file on the upload page
57
+ 2. System validates (max 10MB, .jpg/.png only) and shows preview
58
+ 3. User clicks "Upload" → system enqueues job, redirects to /processing/{jobId}
59
+ 4. User sees progress bar polling every 5 seconds
60
+ 5. On completion: "Download" button appears, user gets processed photo
61
+ ```
62
+
63
+ ---
64
+
65
+ ## Success Metrics
66
+
67
+ | Metric | Current | Target |
68
+ |--------|---------|--------|
69
+ | Upload success rate | N/A | >99% |
70
+ | Processing time (p95) | N/A | <120s |
71
+ | Error recovery rate | N/A | >95% (auto-retry) |
72
+
73
+ ---
74
+
75
+ ## Scope
76
+
77
+ ### In Scope
78
+
79
+ - Photo upload (Blazor form, Azure Blob Storage)
80
+ - Background processing via Hangfire
81
+ - Status polling page with progress indicator
82
+ - Download link for processed photo
83
+ - Basic error handling and retry logic
84
+
85
+ ### Out of Scope
86
+
87
+ - Batch uploads (multiple photos at once)
88
+ - Email notifications when processing completes
89
+ - Photo editing before upload (crop, resize)
90
+
91
+ ### Future Considerations
92
+
93
+ - Webhooks for external integrations
94
+ - Processing history and gallery view
95
+
96
+ ---
97
+
98
+ ## Risks & Concerns
99
+
100
+ | Risk | Likelihood | Impact | Mitigation |
101
+ |------|------------|--------|------------|
102
+ | AI API unavailable | Medium | High | Retry with exponential backoff, fallback error state |
103
+ | Large file upload timeout | Low | Medium | Chunked upload or presigned URL direct to Blob |
104
+ | Blob storage costs unexpectedly high | Low | Low | Set blob lifecycle policy (auto-delete after 30 days) |
105
+
106
+ ---
107
+
108
+ ## Estimated Effort
109
+
110
+ | Phase | Estimate |
111
+ |-------|----------|
112
+ | Design & Spec | 2h |
113
+ | Implementation | 6h |
114
+ | Testing | 2h |
115
+ | **Total** | **10h** |
116
+
117
+ ---
118
+
119
+ ## Questions & Clarifications
120
+
121
+ 1. Maximum file size: 10MB or higher for pro users?
122
+ 2. Should processed photos be kept indefinitely or expire after 30 days?
123
+ 3. Does the AI API support async webhooks or only polling?
124
+
125
+ ---
126
+
127
+ ## Next Steps
128
+
129
+ Once approved:
130
+ 1. Create detailed `spec.md` with technical design
131
+ 2. Define contracts in `contracts.cs`
132
+ 3. Record decisions in `decisions.md`
133
+ 4. Break down into `tasks.md`
134
+ 5. Begin implementation
135
+
136
+ ---
137
+
138
+ *MORPH-SPEC by Polymorphism Tech*
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  name: code-review
3
- description: >
4
- Structured code review checklist for MORPH-SPEC projects covering architecture, standards compliance, contracts, and quality gates. Use after implementation to validate work.
3
+ description: .NET/C# code review checklist covering naming conventions, architecture layer integrity, async patterns, logging, error handling, DI lifetimes, and DTO contracts. Use after implementing .NET code, before creating PRs, or when reviewing C# code for compliance with MORPH-SPEC standards.
5
4
  user-invocable: true
6
5
  allowed-tools: Read, Write, Edit, Bash, Glob, Grep
7
6
  ---
@@ -12,6 +11,8 @@ allowed-tools: Read, Write, Edit, Bash, Glob, Grep
12
11
  > **Ref:** `framework/standards/core/coding.md` for naming conventions and style.
13
12
  > **Ref:** `framework/standards/core/architecture.md` for layer rules and SOLID.
14
13
  > **Ref:** `framework/standards/backend/database/ef-core.md` for DbContext patterns and background ops.
14
+ > **Example:** `references/review-example.md` — filled-in review showing expected finding format and severity levels.
15
+ > **Script:** `scripts/scan-csharp.mjs` — automated scan for CRITICAL/HIGH violations before manual review.
15
16
 
16
17
  ---
17
18
 
@@ -0,0 +1,164 @@
1
+ # Code Review Report — Photo Processing Pipeline
2
+
3
+ > Example of a well-structured code review output. Filled-in reference — not a template.
4
+
5
+ **Scope:** `src/Application/PhotoProcessing/` + `src/Web/Endpoints/PhotoProcessingEndpoints.cs`
6
+ **Date:** 2025-01-22
7
+ **Reviewer:** code-review skill
8
+
9
+ ---
10
+
11
+ ## Findings by Severity
12
+
13
+ | Severity | Count |
14
+ |----------|-------|
15
+ | CRITICAL | 1 |
16
+ | HIGH | 2 |
17
+ | MEDIUM | 2 |
18
+ | LOW | 1 |
19
+
20
+ ---
21
+
22
+ ### [CRITICAL] Naming: UPPER_SNAKE_CASE constant
23
+
24
+ **File:** `src/Application/PhotoProcessing/PhotoProcessingService.cs:14`
25
+
26
+ **Current code:**
27
+ ```csharp
28
+ private const int MAX_RETRY_COUNT = 3;
29
+ private const int DEFAULT_TIMEOUT_SECONDS = 30;
30
+ ```
31
+
32
+ **Suggested fix:**
33
+ ```csharp
34
+ private const int MaxRetryCount = 3;
35
+ private const int DefaultTimeoutSeconds = 30;
36
+ ```
37
+
38
+ **Why:** `ALL_CAPS` constants violate C# conventions (§ coding.md). Pascal case is the .NET standard.
39
+
40
+ ---
41
+
42
+ ### [HIGH] Async: Missing CancellationToken propagation
43
+
44
+ **File:** `src/Infrastructure/Storage/AzureBlobStorageService.cs:28`
45
+
46
+ **Current code:**
47
+ ```csharp
48
+ public async Task<string> UploadAsync(Stream content, string blobName)
49
+ {
50
+ var blobClient = _containerClient.GetBlobClient(blobName);
51
+ await blobClient.UploadAsync(content); // no CT
52
+ return blobClient.Uri.ToString();
53
+ }
54
+ ```
55
+
56
+ **Suggested fix:**
57
+ ```csharp
58
+ public async Task<string> UploadAsync(Stream content, string blobName, CancellationToken ct = default)
59
+ {
60
+ var blobClient = _containerClient.GetBlobClient(blobName);
61
+ await blobClient.UploadAsync(content, cancellationToken: ct);
62
+ return blobClient.Uri.ToString();
63
+ }
64
+ ```
65
+
66
+ **Why:** Cancellation cannot propagate into the Blob SDK call, meaning a cancelled HTTP request still holds the upload open.
67
+
68
+ ---
69
+
70
+ ### [HIGH] Logging: String interpolation in ILogger call
71
+
72
+ **File:** `src/Application/PhotoProcessing/PhotoProcessingJob.cs:52`
73
+
74
+ **Current code:**
75
+ ```csharp
76
+ _logger.LogError($"Job {jobId} failed after {retryCount} retries: {ex.Message}");
77
+ ```
78
+
79
+ **Suggested fix:**
80
+ ```csharp
81
+ _logger.LogError("Job {JobId} failed after {RetryCount} retries: {ErrorMessage}",
82
+ jobId, retryCount, ex.Message);
83
+ ```
84
+
85
+ **Why:** String interpolation allocates eagerly even if the log level is filtered. Message templates are structured and queryable in Application Insights / Seq.
86
+
87
+ ---
88
+
89
+ ### [MEDIUM] Architecture: Controller logic exceeds 50 lines
90
+
91
+ **File:** `src/Web/Endpoints/PhotoProcessingEndpoints.cs`
92
+
93
+ **Issue:** The upload endpoint inline lambda is 60+ lines — includes validation, service call, response mapping, and error handling all inline.
94
+
95
+ **Suggested fix:** Extract a `UploadPhotoRequestHandler` or move validation to a FluentValidation `IValidator<UploadPhotoCommand>`. The endpoint lambda should be < 10 lines.
96
+
97
+ **Why:** Fat endpoints are hard to test and violate the "thin API layer" rule (§ architecture.md).
98
+
99
+ ---
100
+
101
+ ### [MEDIUM] Error Handling: Generic catch without context
102
+
103
+ **File:** `src/Application/PhotoProcessing/PhotoProcessingService.cs:89`
104
+
105
+ **Current code:**
106
+ ```csharp
107
+ catch (Exception ex)
108
+ {
109
+ _logger.LogError(ex, "Upload failed");
110
+ throw;
111
+ }
112
+ ```
113
+
114
+ **Suggested fix:**
115
+ ```csharp
116
+ catch (Exception ex)
117
+ {
118
+ _logger.LogError(ex, "Upload failed for user {UserId}", userId);
119
+ throw;
120
+ }
121
+ ```
122
+
123
+ **Why:** Log entries without correlation IDs (UserId, JobId) are unqueryable in production. Always include the relevant entity ID.
124
+
125
+ ---
126
+
127
+ ### [LOW] Dead Code: Unused private method
128
+
129
+ **File:** `src/Application/PhotoProcessing/PhotoProcessingService.cs:110`
130
+
131
+ **Current code:**
132
+ ```csharp
133
+ private string BuildBlobPath(Guid jobId, string suffix)
134
+ => $"uploads/{jobId}/{suffix}";
135
+ // Called 0 times — path built inline everywhere
136
+ ```
137
+
138
+ **Suggested fix:** Either use `BuildBlobPath` consistently or delete it.
139
+
140
+ **Why:** Dead code misleads future readers and increases maintenance surface.
141
+
142
+ ---
143
+
144
+ ## Top Priorities
145
+
146
+ 1. `PhotoProcessingService.cs:14` — CRITICAL naming violation (5 min fix)
147
+ 2. `AzureBlobStorageService.cs:28` — HIGH missing CancellationToken (10 min fix)
148
+ 3. `PhotoProcessingJob.cs:52` — HIGH structured logging (5 min fix)
149
+ 4. `PhotoProcessingEndpoints.cs` — MEDIUM endpoint refactor (30 min)
150
+
151
+ ---
152
+
153
+ ## Passed Checks ✅
154
+
155
+ - Layer integrity: Domain has no Infrastructure references
156
+ - All async methods have `Async` suffix
157
+ - Private fields use `_camelCase`
158
+ - No hardcoded connection strings or secrets
159
+ - External services accessed through interfaces (`IBlobStorageService`, `IPhotoProcessingJob`)
160
+ - `ProcessingJob` entity uses private setters + domain methods
161
+
162
+ ---
163
+
164
+ *MORPH-SPEC by Polymorphism Tech*