@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
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * scan-csharp.mjs
4
+ *
5
+ * Scans .cs files for MORPH-SPEC coding standard violations.
6
+ * Executed locally by Claude via Bash — output returned to Claude.
7
+ *
8
+ * Usage:
9
+ * node scan-csharp.mjs [path] # scan directory or file
10
+ * node scan-csharp.mjs src/ # scan src/ recursively
11
+ * node scan-csharp.mjs --summary # counts only, no details
12
+ *
13
+ * Checks (ref: framework/standards/core/coding.md):
14
+ * - UPPER_SNAKE_CASE constants → should be PascalCase
15
+ * - Hungarian notation → strName, iCount, btnSubmit
16
+ * - Missing CancellationToken → async methods without CT param
17
+ * - String interpolation in logging → $"" in ILogger calls
18
+ * - Empty catch blocks → catch { } or catch (E) { }
19
+ */
20
+
21
+ import { readdirSync, readFileSync, statSync, existsSync } from 'fs';
22
+ import { join, extname, relative } from 'path';
23
+
24
+ const targetPath = process.argv[2] ?? '.';
25
+ const summaryOnly = process.argv.includes('--summary');
26
+
27
+ const CHECKS = [
28
+ {
29
+ id: 'UPPER_SNAKE_CASE',
30
+ severity: 'CRITICAL',
31
+ pattern: /\bconst\s+\w+\s+([A-Z][A-Z_]{2,})\s*=/g,
32
+ message: (m) => `Constant '${m[1]}' uses UPPER_SNAKE_CASE (anti-pattern in C#) → use PascalCase`,
33
+ },
34
+ {
35
+ id: 'HUNGARIAN_NOTATION',
36
+ severity: 'CRITICAL',
37
+ pattern: /\b(str|int|bool|btn|lbl|txt|dbl|flt|obj|arr|lst)([A-Z]\w*)\b/g,
38
+ message: (m) => `'${m[0]}' looks like Hungarian notation → rename to '${m[2].charAt(0).toLowerCase() + m[2].slice(1)}'`,
39
+ },
40
+ {
41
+ id: 'MISSING_CANCELLATION_TOKEN',
42
+ severity: 'HIGH',
43
+ pattern: /public\s+async\s+Task(?:<[^>]+>)?\s+(\w+Async)\s*\(([^)]*)\)/g,
44
+ message: (m) => {
45
+ const params = m[2];
46
+ if (params.includes('CancellationToken') || params.includes('ct ') || params.includes('ct,') || params.includes('ct)')) return null;
47
+ return `Async method '${m[1]}' missing CancellationToken parameter`;
48
+ },
49
+ },
50
+ {
51
+ id: 'LOG_STRING_INTERPOLATION',
52
+ severity: 'HIGH',
53
+ pattern: /\.(LogInformation|LogWarning|LogError|LogDebug|LogCritical)\s*\(\s*\$"/g,
54
+ message: () => 'String interpolation ($"") in log call → use message template with structured parameters',
55
+ },
56
+ {
57
+ id: 'EMPTY_CATCH',
58
+ severity: 'CRITICAL',
59
+ pattern: /catch\s*(\([^)]*\))?\s*\{\s*\}/g,
60
+ message: () => 'Empty catch block — exceptions are silently swallowed',
61
+ },
62
+ ];
63
+
64
+ function collectCsFiles(dir) {
65
+ if (!existsSync(dir)) return [];
66
+ const stat = statSync(dir);
67
+ if (stat.isFile()) return dir.endsWith('.cs') ? [dir] : [];
68
+ const results = [];
69
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
70
+ if (entry.isDirectory() && entry.name !== 'bin' && entry.name !== 'obj' && entry.name !== '.git') {
71
+ results.push(...collectCsFiles(join(dir, entry.name)));
72
+ } else if (entry.isFile() && extname(entry.name) === '.cs') {
73
+ results.push(join(dir, entry.name));
74
+ }
75
+ }
76
+ return results;
77
+ }
78
+
79
+ const files = collectCsFiles(targetPath);
80
+ const findings = [];
81
+
82
+ for (const file of files) {
83
+ const content = readFileSync(file, 'utf-8');
84
+ const lines = content.split('\n');
85
+
86
+ for (const check of CHECKS) {
87
+ const regex = new RegExp(check.pattern.source, check.pattern.flags);
88
+ let match;
89
+ while ((match = regex.exec(content)) !== null) {
90
+ const msg = check.message(match);
91
+ if (!msg) continue;
92
+ const lineNum = content.slice(0, match.index).split('\n').length;
93
+ findings.push({
94
+ severity: check.severity,
95
+ id: check.id,
96
+ file: relative(process.cwd(), file).replace(/\\/g, '/'),
97
+ line: lineNum,
98
+ message: msg,
99
+ snippet: lines[lineNum - 1]?.trim().slice(0, 100),
100
+ });
101
+ }
102
+ }
103
+ }
104
+
105
+ const bySeverity = { CRITICAL: 0, HIGH: 0, MEDIUM: 0, LOW: 0 };
106
+ for (const f of findings) bySeverity[f.severity] = (bySeverity[f.severity] ?? 0) + 1;
107
+
108
+ const summary = {
109
+ scanned: files.length,
110
+ findings: findings.length,
111
+ bySeverity,
112
+ clean: findings.length === 0,
113
+ };
114
+
115
+ if (summaryOnly) {
116
+ console.log(JSON.stringify(summary, null, 2));
117
+ } else {
118
+ console.log(JSON.stringify({ summary, findings }, null, 2));
119
+ }
120
+
121
+ process.exit(findings.some(f => f.severity === 'CRITICAL') ? 1 : 0);
@@ -1,14 +1,11 @@
1
1
  ---
2
2
  name: morph-checklist
3
- description: >
4
- Pre-implementation checklist verifying that all MORPH-SPEC phases are complete and outputs exist before starting code. Use before any implementation work begins.
3
+ description: Pre-deploy, security, SEO, performance, accessibility, and LGPD compliance checklists for MORPH-SPEC projects. Use before deploying to production, during security audits, when optimizing for SEO or performance, or when validating Brazilian LGPD data protection compliance.
5
4
  user-invocable: true
6
5
  allowed-tools: Read, Write, Edit, Bash, Glob, Grep
7
6
  ---
8
7
 
9
- # Skill: /morph-checklist
10
-
11
- > **Layer:** 2 | **Load:** on-keyword | **Keywords:** checklist, deploy, security, seo, performance, accessibility, lgpd, legal
8
+ # MORPH Checklists
12
9
 
13
10
  Types: `deploy`, `security`, `seo`, `performance`, `accessibility`, `legal-brazil`, `simulation` (see [simulation-checklist.md](simulation-checklist.md))
14
11
 
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  name: morph-replicate
3
- description: >
4
- Replicates a completed MORPH-SPEC feature into a new feature, copying and adapting phase outputs. Called when a user wants to clone an existing feature as a starting point.
3
+ description: Simplified workflow for converting HTML prototypes into functional Blazor components, extracting design patterns and mapping HTML elements to Fluent UI/MudBlazor equivalents. Use when an approved HTML prototype exists and needs conversion to Blazor without a full MORPH-SPEC spec pipeline.
5
4
  user-invocable: false
6
5
  allowed-tools: Read, Write, Edit, Bash, Glob, Grep
7
6
  ---
@@ -209,12 +208,12 @@ Mapeamento HTML → Blazor:
209
208
 
210
209
  ---
211
210
 
212
- ## Referencias
211
+ ## Referências
213
212
 
214
- - [HTML to Blazor Guide](../../../../framework/standards/html-to-blazor.md)
215
- - [CSS Naming Convention](../../../../framework/standards/css-naming.md)
216
- - [CSS Animations](../../../../framework/standards/css-animations.md)
217
- - [Fluent UI Blazor](../../../../framework/standards/fluent-ui-blazor.md)
213
+ - **Ref:** `framework/standards/frontend/blazor/html-conversion.md`
214
+ - **Ref:** `framework/standards/frontend/design-system/naming.md`
215
+ - **Ref:** `framework/standards/frontend/design-system/animations.md`
216
+ - **Ref:** `framework/standards/frontend/blazor/fluent-ui.md`
218
217
 
219
218
  ---
220
219
 
@@ -1,16 +1,13 @@
1
1
  ---
2
2
  name: simulation-checklist
3
- description: >
4
- Checklist for simulating a full MORPH-SPEC workflow run to validate phase outputs and state consistency. Use to verify the framework is working correctly.
3
+ description: Checklist for implementing mock/simulation clients for external .NET services (AI APIs, payments, email). Use when setting up simulation mode without real API access, when creating fake service implementations for development/testing, or when debugging external service integrations.
5
4
  user-invocable: true
6
5
  allowed-tools: Read, Write, Edit, Bash, Glob, Grep
7
6
  ---
8
7
 
9
- # Skill: /morph-checklist simulation
8
+ # Simulation Checklist
10
9
 
11
- > **Layer:** 2 | **Load:** on-keyword | **Keywords:** simulation, mock, fake, external service, sandbox
12
-
13
- Checklist for simulating external services (AI, payment, email APIs).
10
+ Checklist for simulating external services (AI, payment, email APIs) in .NET projects.
14
11
 
15
12
  ## Pre-Implementation
16
13
 
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  name: tool-usage-guide
3
- description: >
4
- Decision guide for selecting the right Claude Code tool (Read, Grep, Glob, Bash, Task) for each situation in MORPH-SPEC workflows. Reference when unsure which tool to use.
3
+ description: Decision flowchart and per-phase reference for selecting the right Claude Code tool (Read, Grep, Glob, Bash, Task) or MCP tool in MORPH-SPEC workflows. Use when unsure which tool to use for a given action, when choosing between native tools and MCPs, or when deciding whether to use a subagent vs direct tools.
5
4
  user-invocable: true
6
5
  allowed-tools: Read, Write, Edit, Bash, Glob, Grep
7
6
  ---
@@ -1,11 +1,13 @@
1
1
  ---
2
2
  name: verification-before-completion
3
- description: Morph-spec-aware verification checklist before claiming any work is complete. Runs validation, checks outputs, and confirms with evidence.
3
+ description: Phase-specific verification checklists and morph-spec validation commands for confirming MORPH-SPEC outputs are complete and correct. Use before marking any task done, before advancing to the next phase, before committing, or before creating PRs.
4
4
  ---
5
5
 
6
6
  # Verification Before Completion — MORPH-SPEC Integrated
7
7
 
8
8
  > Never claim work is complete without running verification. Evidence before assertions.
9
+ >
10
+ > **Script:** Run `node scripts/check-phase-outputs.mjs <feature> [phase]` to check required output files exist.
9
11
 
10
12
  ## When to Use
11
13
 
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * check-phase-outputs.mjs
4
+ *
5
+ * Verifies that required MORPH-SPEC output files exist for a feature/phase.
6
+ * Executed locally by Claude via Bash — output is returned to Claude.
7
+ *
8
+ * Usage:
9
+ * node check-phase-outputs.mjs <feature> [phase]
10
+ *
11
+ * Examples:
12
+ * node check-phase-outputs.mjs photo-processing design
13
+ * node check-phase-outputs.mjs photo-processing # checks all phases
14
+ *
15
+ * Output: JSON array of { phase, file, exists, required }
16
+ */
17
+
18
+ import { existsSync } from 'fs';
19
+ import { join } from 'path';
20
+
21
+ const PHASE_OUTPUTS = {
22
+ proposal: [
23
+ { file: '0-proposal/proposal.md', required: true },
24
+ ],
25
+ design: [
26
+ { file: '1-design/spec.md', required: true },
27
+ { file: '1-design/contracts.cs', required: true },
28
+ { file: '1-design/decisions.md', required: true },
29
+ { file: '1-design/schema-analysis.md', required: false },
30
+ ],
31
+ uiux: [
32
+ { file: '2-ui/design-system.md', required: true },
33
+ { file: '2-ui/mockups.md', required: true },
34
+ { file: '2-ui/components.md', required: true },
35
+ { file: '2-ui/flows.md', required: false },
36
+ ],
37
+ tasks: [
38
+ { file: '3-tasks/tasks.md', required: true },
39
+ ],
40
+ implement: [
41
+ { file: '4-implement/recap.md', required: true },
42
+ ],
43
+ };
44
+
45
+ const feature = process.argv[2];
46
+ const targetPhase = process.argv[3];
47
+
48
+ if (!feature) {
49
+ console.error(JSON.stringify({ error: 'Usage: check-phase-outputs.mjs <feature> [phase]' }));
50
+ process.exit(1);
51
+ }
52
+
53
+ // Walk up to find .morph/ directory
54
+ let cwd = process.cwd();
55
+ let morphDir = null;
56
+ for (let i = 0; i < 5; i++) {
57
+ const candidate = join(cwd, '.morph');
58
+ if (existsSync(candidate)) {
59
+ morphDir = candidate;
60
+ break;
61
+ }
62
+ const parent = join(cwd, '..');
63
+ if (parent === cwd) break;
64
+ cwd = parent;
65
+ }
66
+
67
+ if (!morphDir) {
68
+ console.error(JSON.stringify({ error: '.morph/ directory not found. Run from inside a MORPH-SPEC project.' }));
69
+ process.exit(1);
70
+ }
71
+
72
+ const featureDir = join(morphDir, 'features', feature);
73
+ if (!existsSync(featureDir)) {
74
+ console.error(JSON.stringify({ error: `Feature directory not found: .morph/features/${feature}` }));
75
+ process.exit(1);
76
+ }
77
+
78
+ const phases = targetPhase
79
+ ? { [targetPhase]: PHASE_OUTPUTS[targetPhase] }
80
+ : PHASE_OUTPUTS;
81
+
82
+ if (targetPhase && !PHASE_OUTPUTS[targetPhase]) {
83
+ console.error(JSON.stringify({ error: `Unknown phase: ${targetPhase}. Valid: ${Object.keys(PHASE_OUTPUTS).join(', ')}` }));
84
+ process.exit(1);
85
+ }
86
+
87
+ const results = [];
88
+ let missingRequired = 0;
89
+
90
+ for (const [phase, outputs] of Object.entries(phases)) {
91
+ for (const { file, required } of outputs) {
92
+ const fullPath = join(featureDir, file);
93
+ const exists = existsSync(fullPath);
94
+ if (required && !exists) missingRequired++;
95
+ results.push({ phase, file, exists, required });
96
+ }
97
+ }
98
+
99
+ const summary = {
100
+ feature,
101
+ featureDir: featureDir.replace(/\\/g, '/'),
102
+ checks: results.length,
103
+ passed: results.filter(r => r.exists).length,
104
+ missingRequired,
105
+ ready: missingRequired === 0,
106
+ results,
107
+ };
108
+
109
+ console.log(JSON.stringify(summary, null, 2));
110
+ process.exit(missingRequired > 0 ? 1 : 0);
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  name: phase-clarify
3
- description: >
4
- MORPH-SPEC Phase 3 (Clarify). Resolves ambiguities from the design phase, producing clarifications.md and updating the spec. Called after design approval.
3
+ description: MORPH-SPEC Phase 3 (Clarify). Reviews spec.md for ambiguities, generates 3-7 targeted clarification questions, waits for user answers, then updates spec with edge cases and clarification sections. Use after design approval to eliminate spec ambiguities before task breakdown begins.
5
4
  argument-hint: "[feature-name]"
6
5
  user-invocable: false
7
6
  allowed-tools: Read, Write, Edit, Bash, Glob, Grep
@@ -21,8 +20,9 @@ Identifique ambiguidades na especificação e faça perguntas de clarificação
21
20
 
22
21
  ## Ferramentas Recomendadas
23
22
 
24
- > **Ref:** `framework/skills/level-0-meta/tool-usage-guide.md` para guia completo.
23
+ > **Ref:** `framework/skills/level-0-meta/tool-usage-guide/SKILL.md` para guia completo.
25
24
  > **Ref:** `framework/standards/integration/mcp/mcp-tools.md` para referência MCP.
25
+ > **Example:** `references/clarifications-example.md` — filled-in clarifications.md showing expected Q&A format.
26
26
 
27
27
  | Ação | Ferramenta | Alternativa |
28
28
  |------|------------|-------------|
@@ -0,0 +1,117 @@
1
+ # Clarifications - Photo Processing Pipeline
2
+
3
+ > Example of a well-structured clarifications.md. Filled-in reference — not a template.
4
+ > Each Q&A is concise: question raised during design review → answer → spec update.
5
+
6
+ **Feature**: photo-processing
7
+ **Phase**: CLARIFY (Phase 3)
8
+ **Status**: Resolved — all items incorporated into spec.md
9
+
10
+ ---
11
+
12
+ ## Questions & Answers
13
+
14
+ ### Q1: File size limit — 10MB for all users or tiered?
15
+
16
+ **Question:** The spec says max 10MB but the proposal mentioned "higher for pro users." Should we implement tiered limits now?
17
+
18
+ **Answer:** Free tier: 10MB. Pro tier: 50MB. Enforce via `[Authorize]` + claims check in the upload endpoint. YAGNI — don't build a generic tier system, just check the plan claim directly.
19
+
20
+ **Spec Updates:**
21
+ - Updated `spec.md` FR1 to specify tiered limits
22
+ - Added `CanUploadLargeFile` policy to Security section
23
+ - Updated `UploadPhotoCommand` to accept `userPlan` claim
24
+
25
+ **Priority:** High — affects contracts
26
+ **Resolved:** ✅ Yes
27
+
28
+ ---
29
+
30
+ ### Q2: Processed photo retention — indefinite or expiring?
31
+
32
+ **Question:** Should processed photos in Blob Storage be kept forever, or do they expire?
33
+
34
+ **Answer:** Auto-delete after 30 days via Blob lifecycle policy (no code needed, configured in Azure). Free tier: 7 days. Pro tier: 30 days. This is infrastructure-only — `ProcessingJob.ProcessedPhotoUrl` stays in DB but becomes a dead link after expiry.
35
+
36
+ **Spec Updates:**
37
+ - Added ADR-003 (Blob lifecycle policy over code-based cleanup)
38
+ - Added note to `AzureBlobStorageService` about lifecycle dependency
39
+
40
+ **Priority:** Low — no code change
41
+ **Resolved:** ✅ Yes
42
+
43
+ ---
44
+
45
+ ### Q3: AI API — async webhook or polling?
46
+
47
+ **Question:** spec.md assumed Hangfire polls job completion, but the AI vendor docs mention a webhook callback option.
48
+
49
+ **Answer:** Use fire-and-forget HTTP call + Hangfire continuation (not webhook). The AI API's webhook requires a public URL we don't have in dev. Fire-and-forget is simpler and testable. If the vendor SLA changes, we can swap to webhook via `IPhotoProcessingJob` interface — no consumer changes needed.
50
+
51
+ **Spec Updates:**
52
+ - Clarified Processing Flow in spec.md to show fire-and-forget + await pattern
53
+ - Added to Risks: "AI API webhook migration path if needed"
54
+
55
+ **Priority:** High — affects job implementation
56
+ **Resolved:** ✅ Yes
57
+
58
+ ---
59
+
60
+ ## Edge Cases
61
+
62
+ ### EC1: Upload during Hangfire downtime
63
+
64
+ **Scenario:** User uploads successfully but Hangfire server is stopped — job never executes.
65
+
66
+ **Expected Behavior:** Job stays in `Pending` indefinitely. On next Hangfire server start, job auto-resumes (Hangfire persistent storage).
67
+
68
+ **Solution:** No code change. Add monitoring alert if job stays Pending > 10 minutes.
69
+
70
+ **Acceptance Criteria:**
71
+ - [ ] `ProcessingJob` with status `Pending` survives Hangfire restart
72
+ - [ ] Hangfire picks up orphaned jobs on startup (built-in behavior, covered by docs)
73
+
74
+ ---
75
+
76
+ ### EC2: Concurrent uploads of same file
77
+
78
+ **Scenario:** User double-clicks Upload button, sending two identical requests simultaneously.
79
+
80
+ **Expected Behavior:** Two separate `ProcessingJob` records created. Both process independently. No deduplication (not required at MVP scale).
81
+
82
+ **Solution:** No code change. Each request gets a fresh GUID. If deduplication becomes needed, add idempotency key header in v2.
83
+
84
+ ---
85
+
86
+ ## Business Rules Clarified
87
+
88
+ ### BR1: Only the uploading user can download their processed photo
89
+
90
+ **Rule:** `GET /api/download/{jobId}` must check `job.UserId == currentUserId`. Return 403 if mismatch.
91
+
92
+ **Rationale:** Users might guess sequential GUIDs (they can't since we use random GUIDs, but defense in depth).
93
+
94
+ **Implementation:** Add `[Authorize]` + ownership check to download endpoint. Already in Security section of spec.md.
95
+
96
+ ---
97
+
98
+ ## Summary
99
+
100
+ | | Count |
101
+ |---|---|
102
+ | Questions Answered | 3 / 3 |
103
+ | Edge Cases Documented | 2 |
104
+ | Business Rules Clarified | 1 |
105
+ | Spec Updates Made | 6 |
106
+
107
+ ## Next Steps
108
+
109
+ 1. [x] All questions resolved
110
+ 2. [x] `spec.md` updated with all clarifications
111
+ 3. [x] `contracts.cs` updated (`UploadPhotoCommand` + plan claim)
112
+ 4. [x] Stakeholder approval received
113
+ 5. [ ] Advance to Phase 4 (Tasks)
114
+
115
+ ---
116
+
117
+ *MORPH-SPEC by Polymorphism Tech*
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  name: phase-codebase-analysis
3
- description: >
4
- MORPH-SPEC sub-phase of Design. Analyzes existing codebase patterns, architecture, and conventions before writing the spec. Called automatically at the start of Design phase.
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.
5
4
  user-invocable: false
6
5
  allowed-tools: Read, Write, Edit, Bash, Glob, Grep
7
6
  ---
@@ -21,7 +20,7 @@ Automatiza a análise de código existente para gerar `schema-analysis.md` com d
21
20
 
22
21
  ## Ferramentas Recomendadas
23
22
 
24
- > **Ref:** `framework/skills/level-0-meta/tool-usage-guide.md` para guia completo.
23
+ > **Ref:** `framework/skills/level-0-meta/tool-usage-guide/SKILL.md` para guia completo.
25
24
  > **Ref:** `framework/standards/integration/mcp/mcp-tools.md` para referência MCP.
26
25
 
27
26
  | Ação | Ferramenta | Alternativa |