@polymorphism-tech/morph-spec 4.22.0 → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +57 -71
- package/README.md +2 -2
- package/bin/morph-spec.js +224 -491
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +1 -1
- package/docs/QUICKSTART.md +1 -1
- package/framework/CLAUDE.md +55 -38
- package/framework/MORPH.md +244 -0
- package/framework/agents.json +127 -1198
- package/framework/commands/morph-apply.md +56 -240
- package/framework/commands/morph-archive.md +48 -85
- package/framework/commands/morph-preflight.md +7 -7
- package/framework/commands/morph-proposal.md +35 -191
- package/framework/commands/morph-status.md +19 -50
- package/framework/commands/morph-troubleshoot.md +2 -2
- package/framework/evals/rubrics/README.md +44 -0
- package/framework/evals/rubrics/architecture.md +46 -0
- package/framework/evals/rubrics/code-quality.md +50 -0
- package/framework/evals/rubrics/contracts.md +47 -0
- package/framework/evals/rubrics/test-coverage.md +50 -0
- package/framework/evals/scenarios/dotnet-crud.yaml +42 -0
- package/framework/evals/scenarios/nextjs-auth.yaml +38 -0
- package/framework/evals/suites/standard.yaml +5 -0
- package/framework/evals/trace-schema.md +67 -0
- package/framework/hooks/claude-code/core/README.md +3 -0
- package/framework/hooks/claude-code/core/denylist.json +14 -0
- package/framework/hooks/claude-code/{pre-tool-use → core}/enforce-phase-writes.js +5 -5
- package/framework/hooks/claude-code/core/post-edit-typecheck.js +69 -0
- package/framework/hooks/claude-code/core/pre-bash-denylist.js +29 -0
- package/framework/hooks/claude-code/{pre-tool-use → core}/protect-spec-files.js +4 -6
- package/framework/hooks/claude-code/{stop → core}/validate-completion.js +13 -82
- package/framework/hooks/shared/phase-utils.js +20 -31
- package/framework/hooks/shared/state-reader.js +4 -5
- package/framework/{skills/level-0-meta/mcp-registry.json → mcp/registry.json} +254 -243
- package/framework/phases.json +41 -115
- package/framework/rubrics/eval-rubric.json +66 -0
- package/framework/skills/README.md +39 -64
- package/framework/skills/core/README.md +3 -0
- package/framework/skills/core/morph-brainstorming/SKILL.md +102 -0
- package/framework/skills/core/morph-eval/SKILL.md +57 -0
- package/framework/skills/core/morph-implement/SKILL.md +83 -0
- package/framework/skills/core/morph-plan/SKILL.md +64 -0
- package/framework/skills/core/morph-review/SKILL.md +62 -0
- package/framework/skills/core/morph-stack-scan/SKILL.md +109 -0
- package/framework/skills/core/morph-standards/SKILL.md +49 -0
- package/framework/templates/CLAUDE.md.core.guide.md +29 -0
- package/framework/templates/CLAUDE.md.core.template +22 -0
- package/framework/templates/REGISTRY.json +4 -4
- package/framework/workflows/configs/fast-track.json +5 -10
- package/framework/workflows/configs/full.json +4 -8
- package/framework/workflows/configs/quick.json +32 -0
- package/framework/workflows/configs/standard.json +57 -64
- package/package.json +7 -6
- package/src/commands/mcp/mcp-setup.js +58 -31
- package/src/commands/project/doctor.js +69 -70
- package/src/commands/project/init.js +26 -5
- package/src/commands/project/status.js +18 -19
- package/src/commands/state/approve.js +1 -1
- package/src/commands/validation/validate-feature.js +18 -112
- package/src/core/paths/output-schema.js +133 -152
- package/src/core/state/phase-state-machine.js +10 -24
- package/src/core/state/state-manager.js +17 -17
- package/src/core/workflows/workflow-detector.js +214 -31
- package/src/core/workflows/workflow-router.js +204 -0
- package/src/dashboard/app/pages/AgentMap.jsx +32 -33
- package/src/dashboard/app/pages/LiveState.jsx +1 -1
- package/src/dashboard/app/pages/PhasePipeline.jsx +2 -4
- package/src/dashboard/app/pages/SkillsLibrary.jsx +2 -3
- package/src/dashboard/app/pages/Workflows.jsx +2 -2
- package/src/dashboard/scanner/agents-scanner.js +30 -35
- package/src/lib/agents/metrics-aggregator.js +1 -1
- package/src/lib/agents/output-collector.js +7 -9
- package/src/lib/context/context-builder.js +289 -0
- package/src/lib/detectors/claude-config-detector.js +19 -3
- package/src/lib/generators/context-generator.js +20 -42
- package/src/lib/generators/index.js +1 -0
- package/src/lib/generators/mandate-generator.js +512 -0
- package/src/lib/generators/metadata-extractor.js +1 -1
- package/src/lib/generators/recap-generator.js +3 -4
- package/src/lib/installers/mcp-installer.js +300 -92
- package/src/lib/phase-chain/phase-validator.js +36 -40
- package/src/lib/stack/stack-profile.js +74 -91
- package/src/lib/tasks/task-parser.js +1 -1
- package/src/lib/tasks/wave-resolver.js +353 -0
- package/src/lib/validators/checkpoint-persistence.js +2 -2
- package/src/lib/validators/content/cross-phase-validator.js +281 -0
- package/src/lib/validators/content/index.js +1 -0
- package/src/lib/validators/shared/emit-validator-dispatch.js +6 -56
- package/src/scripts/global-install.js +2 -27
- package/src/utils/agents-installer.js +224 -447
- package/src/utils/claude-settings-manager.js +57 -15
- package/src/utils/file-copier.js +1 -0
- package/src/utils/hooks-installer.js +15 -117
- package/src/utils/skills-installer.js +12 -18
- package/bin/detect-agents.js +0 -226
- package/bin/task-manager.js +0 -1036
- package/framework/agents/README.md +0 -13
- package/framework/agents/ai-agents/ai-system-architect.md +0 -194
- package/framework/agents/ai-agents/vector-search-expert.md +0 -247
- package/framework/agents/architecture/architecture-expert.md +0 -98
- package/framework/agents/architecture/morph-spec-architect.md +0 -66
- package/framework/agents/architecture/packages-validator.md +0 -89
- package/framework/agents/architecture/security-expert.md +0 -79
- package/framework/agents/architecture/seo-growth-hacker.md +0 -168
- package/framework/agents/architecture/standards-architect.md +0 -153
- package/framework/agents/backend/dotnet-senior.md +0 -163
- package/framework/agents/backend/ef-modeler.md +0 -119
- package/framework/agents/backend/hangfire-orchestrator.md +0 -133
- package/framework/agents/backend/ms-agent-expert.md +0 -55
- package/framework/agents/backend/neon-expert.md +0 -379
- package/framework/agents/frontend/css-specialist.md +0 -89
- package/framework/agents/frontend/design-system-validator.md +0 -100
- package/framework/agents/frontend/gsap-animator.md +0 -131
- package/framework/agents/frontend/nextjs-component-validator.md +0 -97
- package/framework/agents/frontend/nextjs-expert.md +0 -201
- package/framework/agents/frontend/ui-designer.md +0 -259
- package/framework/agents/infrastructure/infra-architect.md +0 -215
- package/framework/agents/integrations/asaas-financial.md +0 -138
- package/framework/agents/integrations/neon-auth.md +0 -151
- package/framework/agents/integrations/resend-email.md +0 -127
- package/framework/hooks/claude-code/post-tool-use/agent-complete.js +0 -122
- package/framework/hooks/claude-code/post-tool-use/dispatch.js +0 -363
- package/framework/hooks/claude-code/post-tool-use/handle-tool-failure.js +0 -78
- package/framework/hooks/claude-code/post-tool-use/validator-feedback.js +0 -194
- package/framework/hooks/claude-code/pre-compact/save-morph-context.js +0 -199
- package/framework/hooks/claude-code/pre-tool-use/task-tracking-guard.js +0 -55
- package/framework/hooks/claude-code/session-start/inject-morph-context.js +0 -323
- package/framework/hooks/claude-code/session-start/post-compact-restore.js +0 -41
- package/framework/hooks/claude-code/session-start/resume-context.js +0 -77
- package/framework/hooks/claude-code/teammate-idle/teammate-idle.js +0 -90
- package/framework/hooks/claude-code/user-prompt/enrich-prompt.js +0 -114
- package/framework/hooks/shared/compact-restore.js +0 -123
- package/framework/hooks/shared/dispatch-helpers.js +0 -147
- package/framework/hooks/shared/skill-reminder-helpers.js +0 -79
- package/framework/hooks/shared/stale-task-reset.js +0 -57
- package/framework/hooks/shared/worktree-helpers.js +0 -75
- package/framework/skills/level-0-meta/README.md +0 -7
- package/framework/skills/level-0-meta/morph-agent-teams/SKILL.md +0 -472
- package/framework/skills/level-0-meta/morph-brainstorming/SKILL.md +0 -174
- package/framework/skills/level-0-meta/morph-brainstorming/references/proposal-example.md +0 -138
- package/framework/skills/level-0-meta/morph-checklist/SKILL.md +0 -145
- package/framework/skills/level-0-meta/morph-code-review/SKILL.md +0 -250
- package/framework/skills/level-0-meta/morph-code-review/references/review-example.md +0 -164
- package/framework/skills/level-0-meta/morph-code-review/references/review-guidelines.md +0 -100
- package/framework/skills/level-0-meta/morph-code-review/scripts/scan-csharp.mjs +0 -151
- package/framework/skills/level-0-meta/morph-code-review-nextjs/SKILL.md +0 -165
- package/framework/skills/level-0-meta/morph-code-review-nextjs/references/review-example-nextjs.md +0 -254
- package/framework/skills/level-0-meta/morph-code-review-nextjs/scripts/scan-nextjs.mjs +0 -189
- package/framework/skills/level-0-meta/morph-frontend-review/SKILL.md +0 -344
- package/framework/skills/level-0-meta/morph-frontend-review/scripts/scan-accessibility.mjs +0 -376
- package/framework/skills/level-0-meta/morph-gemini-image/SKILL.md +0 -290
- package/framework/skills/level-0-meta/morph-init/SKILL.md +0 -537
- package/framework/skills/level-0-meta/morph-parallel-dispatch/SKILL.md +0 -225
- package/framework/skills/level-0-meta/morph-post-implementation/SKILL.md +0 -401
- package/framework/skills/level-0-meta/morph-post-implementation/scripts/detect-dev-server.mjs +0 -153
- package/framework/skills/level-0-meta/morph-post-implementation/scripts/detect-stack.mjs +0 -234
- package/framework/skills/level-0-meta/morph-simulation-checklist/SKILL.md +0 -106
- package/framework/skills/level-0-meta/morph-tool-usage-guide/SKILL.md +0 -243
- package/framework/skills/level-0-meta/morph-tool-usage-guide/references/tools-per-phase.md +0 -169
- package/framework/skills/level-0-meta/morph-verification-before-completion/SKILL.md +0 -148
- package/framework/skills/level-0-meta/morph-verification-before-completion/scripts/check-phase-outputs.mjs +0 -110
- package/framework/skills/level-1-workflows/README.md +0 -7
- package/framework/skills/level-1-workflows/morph-phase-codebase-analysis/SKILL.md +0 -269
- package/framework/skills/level-1-workflows/morph-phase-design/SKILL.md +0 -453
- package/framework/skills/level-1-workflows/morph-phase-design/references/architecture-analysis-guide.md +0 -44
- package/framework/skills/level-1-workflows/morph-phase-design/references/spec-authoring-guide.md +0 -55
- package/framework/skills/level-1-workflows/morph-phase-design/references/spec-example.md +0 -253
- package/framework/skills/level-1-workflows/morph-phase-implement/.morph/logs/activity.json +0 -38
- package/framework/skills/level-1-workflows/morph-phase-implement/SKILL.md +0 -634
- package/framework/skills/level-1-workflows/morph-phase-implement/prompts/code-quality-reviewer-prompt.md +0 -50
- package/framework/skills/level-1-workflows/morph-phase-implement/prompts/implementer-prompt.md +0 -54
- package/framework/skills/level-1-workflows/morph-phase-implement/prompts/spec-reviewer-prompt.md +0 -47
- package/framework/skills/level-1-workflows/morph-phase-implement/references/recap-example.md +0 -132
- package/framework/skills/level-1-workflows/morph-phase-implement/references/vsa-implementation-guide.md +0 -92
- package/framework/skills/level-1-workflows/morph-phase-plan/SKILL.md +0 -257
- package/framework/skills/level-1-workflows/morph-phase-tasks/.morph/logs/activity.json +0 -14
- package/framework/skills/level-1-workflows/morph-phase-tasks/SKILL.md +0 -291
- package/framework/skills/level-1-workflows/morph-phase-tasks/references/task-planning-patterns.md +0 -143
- package/framework/skills/level-1-workflows/morph-phase-tasks/references/tasks-example.md +0 -404
- package/framework/skills/level-1-workflows/morph-phase-tasks/scripts/validate-tasks.mjs +0 -112
- package/framework/skills/level-1-workflows/morph-phase-uiux/SKILL.md +0 -995
- package/framework/skills/level-1-workflows/morph-scope-escalation/SKILL.md +0 -147
- package/framework/squad-templates/backend-only.json +0 -47
- package/framework/squad-templates/frontend-only.json +0 -56
- package/framework/squad-templates/full-stack.json +0 -74
- package/src/commands/agents/agent-metrics.js +0 -174
- package/src/commands/agents/audit-dispatch.js +0 -82
- package/src/commands/agents/detect-agents.js +0 -275
- package/src/commands/agents/dispatch-agents.js +0 -461
- package/src/commands/agents/index.js +0 -13
- package/src/commands/agents/manage-agents.js +0 -352
- package/src/commands/agents/project-metrics.js +0 -74
- package/src/commands/phase/phase-reset.js +0 -74
- package/src/commands/scope/escalate.js +0 -217
- package/src/commands/state/advance-phase.js +0 -600
- package/src/commands/state/phase-runner.js +0 -215
- package/src/commands/state/state.js +0 -444
- package/src/commands/task/expand.js +0 -100
- package/src/commands/tasks/index.js +0 -4
- package/src/commands/tasks/task.js +0 -105
- package/src/commands/templates/index.js +0 -5
- package/src/commands/templates/template-render.js +0 -93
- package/src/commands/trust/trust.js +0 -118
- package/src/lib/agents/agents-manager.js +0 -349
- package/src/lib/build/build-runner.js +0 -99
- package/src/lib/checkpoints/checkpoint-hooks.js +0 -111
- package/src/lib/contracts/sprint-contract-generator.js +0 -137
- package/src/lib/scope/impact-analyzer.js +0 -106
- package/src/lib/trust/trust-manager.js +0 -157
- package/src/utils/tier-helpers.js +0 -24
- /package/framework/hooks/claude-code/{post-tool-use → core}/loop-detect.js +0 -0
|
@@ -1,404 +0,0 @@
|
|
|
1
|
-
# Tasks - Photo Processing Pipeline
|
|
2
|
-
|
|
3
|
-
> Example of a well-structured tasks.md. This is a filled-in reference — not a template.
|
|
4
|
-
> All tasks are atomic (15–60 min), independently commitable, and directly traceable to spec.md.
|
|
5
|
-
|
|
6
|
-
| Task ID | Type | Title | Status |
|
|
7
|
-
|---------|------|-------|--------|
|
|
8
|
-
| T001 | Contract | Define C# contracts and interfaces | Done |
|
|
9
|
-
| T002 | Domain | Create ProcessingJob entity and enum | Done |
|
|
10
|
-
| T003 | Infra | EF Core migration and DbContext setup | Done |
|
|
11
|
-
| T004 | Infra | Azure Blob Storage service | Done |
|
|
12
|
-
| T005 | Service | Implement PhotoProcessingService | In Progress |
|
|
13
|
-
| T006 | Job | Implement Hangfire background job | Pending |
|
|
14
|
-
| T007 | API | Upload and status endpoints (Minimal API) | Pending |
|
|
15
|
-
| T008 | UI | Blazor upload page component | Pending |
|
|
16
|
-
| T009 | UI | Blazor status polling page | Pending |
|
|
17
|
-
| T010 | Test | Unit tests for PhotoProcessingService | Pending |
|
|
18
|
-
| T011 | Test | Integration tests for upload + status API | Pending |
|
|
19
|
-
|
|
20
|
-
**Status Values:** `Pending | In Progress | Blocked | Done`
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
## Phase 1: Contracts & Data Model
|
|
25
|
-
|
|
26
|
-
### T001: Define C# contracts and interfaces
|
|
27
|
-
- **Type:** Contract
|
|
28
|
-
- **Priority:** 1
|
|
29
|
-
- **Estimate:** 30min
|
|
30
|
-
- **Assigned:** dotnet-senior
|
|
31
|
-
- **Dependencies:** None
|
|
32
|
-
|
|
33
|
-
**Description:**
|
|
34
|
-
Define all service interfaces, command/result records, and DTOs needed for the feature. These become the API contract other tasks depend on — implement data model and services against these interfaces.
|
|
35
|
-
|
|
36
|
-
**Deliverables:**
|
|
37
|
-
- [ ] Create: `src/Application/PhotoProcessing/Interfaces/IPhotoProcessingService.cs`
|
|
38
|
-
- [ ] Create: `src/Application/PhotoProcessing/Commands/UploadPhotoCommand.cs`
|
|
39
|
-
- [ ] Create: `src/Application/PhotoProcessing/Queries/GetJobStatusQuery.cs`
|
|
40
|
-
- [ ] Create: `src/Application/PhotoProcessing/DTOs/JobStatusDto.cs`
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
### T002: Create ProcessingJob entity and enum
|
|
45
|
-
- **Type:** Domain
|
|
46
|
-
- **Priority:** 1
|
|
47
|
-
- **Estimate:** 30min
|
|
48
|
-
- **Assigned:** dotnet-senior
|
|
49
|
-
- **Dependencies:** T001
|
|
50
|
-
|
|
51
|
-
**Description:**
|
|
52
|
-
Create the `ProcessingJob` domain entity and `ProcessingStatus` enum per the data model in spec.md. Entity must use private setters and expose domain methods for state transitions (`MarkProcessing()`, `MarkCompleted()`, `MarkFailed()`).
|
|
53
|
-
|
|
54
|
-
**Deliverables:**
|
|
55
|
-
- [ ] Create: `src/Domain/Entities/ProcessingJob.cs`
|
|
56
|
-
- [ ] Create: `src/Domain/Enums/ProcessingStatus.cs`
|
|
57
|
-
|
|
58
|
-
---
|
|
59
|
-
|
|
60
|
-
### T003: EF Core migration and DbContext setup
|
|
61
|
-
- **Type:** Infrastructure
|
|
62
|
-
- **Priority:** 1
|
|
63
|
-
- **Estimate:** 45min
|
|
64
|
-
- **Assigned:** dotnet-senior
|
|
65
|
-
- **Dependencies:** T002
|
|
66
|
-
|
|
67
|
-
**Description:**
|
|
68
|
-
Add `ProcessingJob` to `AppDbContext`, configure via Fluent API (column lengths, indexes, defaults), and create initial migration. Verify migration applies cleanly to a local SQL Server instance.
|
|
69
|
-
|
|
70
|
-
**Deliverables:**
|
|
71
|
-
- [ ] Update: `src/Infrastructure/Persistence/AppDbContext.cs`
|
|
72
|
-
- [ ] Create: `src/Infrastructure/Persistence/Configurations/ProcessingJobConfiguration.cs`
|
|
73
|
-
- [ ] Run: `dotnet ef migrations add AddProcessingJob`
|
|
74
|
-
- [ ] Verify: migration applies without errors
|
|
75
|
-
|
|
76
|
-
---
|
|
77
|
-
|
|
78
|
-
## Phase 2: Infrastructure Services
|
|
79
|
-
|
|
80
|
-
### T004: Azure Blob Storage service
|
|
81
|
-
- **Type:** Infrastructure
|
|
82
|
-
- **Priority:** 1
|
|
83
|
-
- **Estimate:** 45min
|
|
84
|
-
- **Assigned:** infra-architect
|
|
85
|
-
- **Dependencies:** None
|
|
86
|
-
|
|
87
|
-
**Description:**
|
|
88
|
-
Implement `IBlobStorageService` with upload and generate-URL operations using `Azure.Storage.Blobs` SDK. Register as scoped in DI. Add connection string to `appsettings.json` (placeholder) and Key Vault reference for production.
|
|
89
|
-
|
|
90
|
-
**Deliverables:**
|
|
91
|
-
- [ ] Create: `src/Infrastructure/Storage/IBlobStorageService.cs`
|
|
92
|
-
- [ ] Create: `src/Infrastructure/Storage/AzureBlobStorageService.cs`
|
|
93
|
-
- [ ] Create: `src/Infrastructure/Storage/FakeBlobStorageService.cs` (for simulation mode)
|
|
94
|
-
- [ ] Update: `src/Infrastructure/DependencyInjection.cs`
|
|
95
|
-
|
|
96
|
-
---
|
|
97
|
-
|
|
98
|
-
### T005: Implement PhotoProcessingService
|
|
99
|
-
- **Type:** Service
|
|
100
|
-
- **Priority:** 2
|
|
101
|
-
- **Estimate:** 1h
|
|
102
|
-
- **Assigned:** dotnet-senior
|
|
103
|
-
- **Dependencies:** T001, T002, T003, T004
|
|
104
|
-
|
|
105
|
-
**Description:**
|
|
106
|
-
Implement `IPhotoProcessingService` with `UploadAsync` (validate → blob upload → create job → enqueue Hangfire job) and `GetStatusAsync`. Use result pattern for validation errors; throw `NotFoundException` for missing jobs.
|
|
107
|
-
|
|
108
|
-
**Deliverables:**
|
|
109
|
-
- [ ] Create: `src/Application/PhotoProcessing/PhotoProcessingService.cs`
|
|
110
|
-
- [ ] Update: `src/Application/DependencyInjection.cs`
|
|
111
|
-
|
|
112
|
-
---
|
|
113
|
-
|
|
114
|
-
### T006: Implement Hangfire background job
|
|
115
|
-
- **Type:** Job
|
|
116
|
-
- **Priority:** 2
|
|
117
|
-
- **Estimate:** 1h
|
|
118
|
-
- **Assigned:** dotnet-senior
|
|
119
|
-
- **Dependencies:** T002, T004
|
|
120
|
-
|
|
121
|
-
**Description:**
|
|
122
|
-
Implement `IPhotoProcessingJob` that: sets status = Processing → downloads original from Blob → calls AI API → uploads processed photo → sets status = Completed. On exception: increment RetryCount, set Failed if >= 3. Add `[AutomaticRetry(Attempts = 3)]` attribute.
|
|
123
|
-
|
|
124
|
-
**Deliverables:**
|
|
125
|
-
- [ ] Create: `src/Application/PhotoProcessing/PhotoProcessingJob.cs`
|
|
126
|
-
- [ ] Create: `src/Application/PhotoProcessing/FakePhotoProcessingJob.cs` (simulation mode)
|
|
127
|
-
|
|
128
|
-
---
|
|
129
|
-
|
|
130
|
-
## Phase 3: API Endpoints
|
|
131
|
-
|
|
132
|
-
### T007: Upload and status endpoints (Minimal API)
|
|
133
|
-
- **Type:** API
|
|
134
|
-
- **Priority:** 2
|
|
135
|
-
- **Estimate:** 45min
|
|
136
|
-
- **Assigned:** dotnet-senior
|
|
137
|
-
- **Dependencies:** T005
|
|
138
|
-
|
|
139
|
-
**Description:**
|
|
140
|
-
Create two endpoints per spec.md:
|
|
141
|
-
- `POST /api/upload` — multipart/form-data, returns `{ jobId }`, maps to `UploadPhotoCommand`
|
|
142
|
-
- `GET /api/status/{jobId}` — returns `JobStatusDto`
|
|
143
|
-
- `GET /api/download/{jobId}` — redirects to Blob URL if Completed, else 404
|
|
144
|
-
|
|
145
|
-
**Deliverables:**
|
|
146
|
-
- [ ] Create: `src/Web/Endpoints/PhotoProcessingEndpoints.cs`
|
|
147
|
-
- [ ] Update: `src/Web/Program.cs` to register endpoint group
|
|
148
|
-
|
|
149
|
-
---
|
|
150
|
-
|
|
151
|
-
## Phase 4: UI Components
|
|
152
|
-
|
|
153
|
-
### T008: Blazor upload page component
|
|
154
|
-
- **Type:** UI
|
|
155
|
-
- **Priority:** 2
|
|
156
|
-
- **Estimate:** 1h
|
|
157
|
-
- **Assigned:** nextjs-expert
|
|
158
|
-
- **Dependencies:** T007
|
|
159
|
-
|
|
160
|
-
**Description:**
|
|
161
|
-
Frontend page at `/upload`. File input with client-side validation (type + size before submit). Loading state during upload. Redirect to `/processing/{jobId}` on success. Error message display per spec wireframe.
|
|
162
|
-
|
|
163
|
-
**Deliverables:**
|
|
164
|
-
- [ ] Create: `src/Web/Pages/Upload.razor`
|
|
165
|
-
- [ ] Create: `src/Web/Pages/Upload.razor.cs`
|
|
166
|
-
|
|
167
|
-
---
|
|
168
|
-
|
|
169
|
-
### T009: Blazor status polling page
|
|
170
|
-
- **Type:** UI
|
|
171
|
-
- **Priority:** 3
|
|
172
|
-
- **Estimate:** 1h
|
|
173
|
-
- **Assigned:** nextjs-expert
|
|
174
|
-
- **Dependencies:** T007
|
|
175
|
-
|
|
176
|
-
**Description:**
|
|
177
|
-
Frontend page at `/processing/{jobId}`. Polls `GET /api/status/{jobId}` every 5 seconds using `PeriodicTimer`. Shows status label + progress indicator. "Download" button when Completed. "Retry" suggestion when Failed. Stops polling on terminal state.
|
|
178
|
-
|
|
179
|
-
**Deliverables:**
|
|
180
|
-
- [ ] Create: `src/Web/Pages/ProcessingStatus.razor`
|
|
181
|
-
- [ ] Create: `src/Web/Pages/ProcessingStatus.razor.cs`
|
|
182
|
-
|
|
183
|
-
---
|
|
184
|
-
|
|
185
|
-
## Phase 5: Tests
|
|
186
|
-
|
|
187
|
-
### T010: Unit tests for PhotoProcessingService
|
|
188
|
-
- **Type:** Test
|
|
189
|
-
- **Priority:** 2
|
|
190
|
-
- **Estimate:** 1h
|
|
191
|
-
- **Assigned:** dotnet-senior
|
|
192
|
-
- **Dependencies:** T005
|
|
193
|
-
|
|
194
|
-
**Description:**
|
|
195
|
-
Unit tests covering: happy path upload, invalid file type rejection, file too large rejection, status retrieval for each status value, not-found case. Use Moq for `IBlobStorageService` and `IProcessingJobRepository`. FluentAssertions for assertions.
|
|
196
|
-
|
|
197
|
-
**Deliverables:**
|
|
198
|
-
- [ ] Create: `tests/Unit/Application/PhotoProcessing/PhotoProcessingServiceTests.cs`
|
|
199
|
-
|
|
200
|
-
---
|
|
201
|
-
|
|
202
|
-
### T011: Integration tests for upload + status API
|
|
203
|
-
- **Type:** Test
|
|
204
|
-
- **Priority:** 3
|
|
205
|
-
- **Estimate:** 1h
|
|
206
|
-
- **Assigned:** dotnet-senior
|
|
207
|
-
- **Dependencies:** T007, T010
|
|
208
|
-
|
|
209
|
-
**Description:**
|
|
210
|
-
Integration tests using `WebApplicationFactory` + in-memory SQLite (or TestContainers for SQL Server). Tests: POST /api/upload returns 200 with jobId, GET /api/status/{jobId} returns correct status, GET /api/download/{completedJobId} returns redirect.
|
|
211
|
-
|
|
212
|
-
**Deliverables:**
|
|
213
|
-
- [ ] Create: `tests/Integration/Api/PhotoProcessingEndpointTests.cs`
|
|
214
|
-
- [ ] Create: `tests/Integration/Fixtures/PhotoProcessingApiFixture.cs`
|
|
215
|
-
|
|
216
|
-
---
|
|
217
|
-
|
|
218
|
-
## Summary
|
|
219
|
-
|
|
220
|
-
| Phase | Tasks | Estimate |
|
|
221
|
-
|-------|-------|----------|
|
|
222
|
-
| Contracts & Data Model | T001–T003 | 1h45m |
|
|
223
|
-
| Infrastructure Services | T004–T006 | 2h45m |
|
|
224
|
-
| API Endpoints | T007 | 45m |
|
|
225
|
-
| UI Components | T008–T009 | 2h |
|
|
226
|
-
| Tests | T010–T011 | 2h |
|
|
227
|
-
| **Total** | **11 tasks** | **~9h15m** |
|
|
228
|
-
|
|
229
|
-
---
|
|
230
|
-
|
|
231
|
-
---
|
|
232
|
-
|
|
233
|
-
# Tasks - Book CRUD (VSA Example)
|
|
234
|
-
|
|
235
|
-
> Example of tasks.md for a Vertical Slice Architecture (VSA) feature.
|
|
236
|
-
> Key rule: 1 task = 1 complete slice (Handler + Validator + Endpoint together).
|
|
237
|
-
> GetAll slices have no Validator — stated explicitly in the task.
|
|
238
|
-
|
|
239
|
-
| Task ID | Category | Title | Status |
|
|
240
|
-
|---------|----------|-------|--------|
|
|
241
|
-
| T001 | entity | Criar Entity Book + registrar DbSet no ApplicationDbContext | Pending |
|
|
242
|
-
| T002 | errors | Criar BookErrors (NotFound + outros factory methods) | Pending |
|
|
243
|
-
| T003 | tags | Adicionar ApiTags.Books em Constants/ApiTags.cs | Pending |
|
|
244
|
-
| T004 | migration | Criar migration AddBook + aplicar ao banco | Pending |
|
|
245
|
-
| T005 | slice | Implementar slice CreateBook (Handler + Validator + Endpoint) | Pending |
|
|
246
|
-
| T006 | slice | Implementar slice GetAllBooks (Handler + Endpoint, sem Validator) | Pending |
|
|
247
|
-
| T007 | slice | Implementar slice GetBookById (Handler + Validator + Endpoint) | Pending |
|
|
248
|
-
| T008 | slice | Implementar slice UpdateBook (Handler + Validator + Endpoint) | Pending |
|
|
249
|
-
| T009 | slice | Implementar slice DeleteBook (Handler + Validator + Endpoint) | Pending |
|
|
250
|
-
|
|
251
|
-
**Status Values:** `Pending | In Progress | Blocked | Done`
|
|
252
|
-
|
|
253
|
-
---
|
|
254
|
-
|
|
255
|
-
## Phase 1: Foundation
|
|
256
|
-
|
|
257
|
-
### T001: Criar Entity Book + registrar DbSet no ApplicationDbContext
|
|
258
|
-
- **Category:** entity
|
|
259
|
-
- **Estimate:** 20min
|
|
260
|
-
- **Dependencies:** None
|
|
261
|
-
|
|
262
|
-
**Description:**
|
|
263
|
-
Criar a entity `Book` com todos os campos definidos no spec.md. Registrar `DbSet<Book>` no `ApplicationDbContext`. Usar `Guid.CreateVersion7()` para o campo Id — não `Guid.NewGuid()`. Propriedades obrigatórias como `sealed` ou com setters `private init`.
|
|
264
|
-
|
|
265
|
-
**Deliverables:**
|
|
266
|
-
- [ ] Create: `Entities/Book.cs`
|
|
267
|
-
- [ ] Update: `Database/ApplicationDbContext.cs` (add `public DbSet<Book> Books { get; set; } = null!;`)
|
|
268
|
-
|
|
269
|
-
---
|
|
270
|
-
|
|
271
|
-
### T002: Criar BookErrors (NotFound + outros factory methods)
|
|
272
|
-
- **Category:** errors
|
|
273
|
-
- **Estimate:** 10min
|
|
274
|
-
- **Dependencies:** T001
|
|
275
|
-
|
|
276
|
-
**Description:**
|
|
277
|
-
Criar a classe `BookErrors` static com factory methods para cada tipo de erro da feature. Cada method retorna um `Error` com code e description. Esses erros são compartilhados por todos os slices da BookFeature.
|
|
278
|
-
|
|
279
|
-
**Deliverables:**
|
|
280
|
-
- [ ] Create: `Features/BookFeature/BookErrors.cs`
|
|
281
|
-
|
|
282
|
-
---
|
|
283
|
-
|
|
284
|
-
### T003: Adicionar ApiTags.Books em Constants/ApiTags.cs
|
|
285
|
-
- **Category:** tags
|
|
286
|
-
- **Estimate:** 5min
|
|
287
|
-
- **Dependencies:** None
|
|
288
|
-
|
|
289
|
-
**Description:**
|
|
290
|
-
Adicionar a constante `Books` em `ApiTags` para uso em todos os endpoints da feature. Se a constante já existir, pular esta task.
|
|
291
|
-
|
|
292
|
-
**Deliverables:**
|
|
293
|
-
- [ ] Update: `Constants/ApiTags.cs` (add `public const string Books = "books";`)
|
|
294
|
-
|
|
295
|
-
---
|
|
296
|
-
|
|
297
|
-
### T004: Criar migration AddBook + aplicar ao banco
|
|
298
|
-
- **Category:** migration
|
|
299
|
-
- **Estimate:** 10min
|
|
300
|
-
- **Dependencies:** T001
|
|
301
|
-
|
|
302
|
-
**Description:**
|
|
303
|
-
Gerar a migration EF Core para a entity `Book` e aplicar ao banco local. Verificar que a migration foi gerada corretamente antes de aplicar.
|
|
304
|
-
|
|
305
|
-
**Deliverables:**
|
|
306
|
-
- [ ] Run: `dotnet ef migrations add AddBook`
|
|
307
|
-
- [ ] Run: `dotnet ef database update`
|
|
308
|
-
- [ ] Verify: migration applies without errors
|
|
309
|
-
|
|
310
|
-
---
|
|
311
|
-
|
|
312
|
-
## Phase 2: Slices
|
|
313
|
-
|
|
314
|
-
### T005: Implementar slice CreateBook (Handler + Validator + Endpoint)
|
|
315
|
-
- **Category:** slice
|
|
316
|
-
- **Estimate:** 45min
|
|
317
|
-
- **Dependencies:** T001, T002, T003, T004
|
|
318
|
-
|
|
319
|
-
**Description:**
|
|
320
|
-
Implementar o slice completo de criação. O arquivo Handler deve conter os records `CreateBookRequest` e `CreateBookResponse` no mesmo arquivo. O Validator deve herdar de `AbstractValidator<CreateBookRequest>`. O Endpoint deve ser `internal sealed` e usar `result.Match()` — nunca `result.Value` sem checar `IsSuccess`.
|
|
321
|
-
|
|
322
|
-
Handler injeta: `IRepository<Book>` + `IUnitOfWork`.
|
|
323
|
-
|
|
324
|
-
**Deliverables:**
|
|
325
|
-
- [ ] Create: `Features/BookFeature/CreateBook/CreateBookHandler.cs`
|
|
326
|
-
- [ ] Create: `Features/BookFeature/CreateBook/CreateBookValidator.cs`
|
|
327
|
-
- [ ] Create: `Features/BookFeature/CreateBook/CreateBookEndpoint.cs`
|
|
328
|
-
|
|
329
|
-
---
|
|
330
|
-
|
|
331
|
-
### T006: Implementar slice GetAllBooks (Handler + Endpoint, sem Validator)
|
|
332
|
-
- **Category:** slice
|
|
333
|
-
- **Estimate:** 25min
|
|
334
|
-
- **Dependencies:** T001, T004
|
|
335
|
-
|
|
336
|
-
**Description:**
|
|
337
|
-
Implementar o slice de listagem. GetAll NÃO tem Validator (sem parâmetros de entrada para validar). Handler injeta apenas `IRepository<Book>` — não precisa de `IUnitOfWork` (read-only).
|
|
338
|
-
|
|
339
|
-
**Deliverables:**
|
|
340
|
-
- [ ] Create: `Features/BookFeature/GetAllBooks/GetAllBooksHandler.cs`
|
|
341
|
-
- [ ] Create: `Features/BookFeature/GetAllBooks/GetAllBooksEndpoint.cs`
|
|
342
|
-
|
|
343
|
-
---
|
|
344
|
-
|
|
345
|
-
### T007: Implementar slice GetBookById (Handler + Validator + Endpoint)
|
|
346
|
-
- **Category:** slice
|
|
347
|
-
- **Estimate:** 30min
|
|
348
|
-
- **Dependencies:** T001, T002, T004
|
|
349
|
-
|
|
350
|
-
**Description:**
|
|
351
|
-
Implementar o slice de busca por ID. Validator verifica que o Guid não é empty. Handler retorna `BookErrors.NotFound()` se o livro não existir. Handler injeta apenas `IRepository<Book>`.
|
|
352
|
-
|
|
353
|
-
**Deliverables:**
|
|
354
|
-
- [ ] Create: `Features/BookFeature/GetBookById/GetBookByIdHandler.cs`
|
|
355
|
-
- [ ] Create: `Features/BookFeature/GetBookById/GetBookByIdValidator.cs`
|
|
356
|
-
- [ ] Create: `Features/BookFeature/GetBookById/GetBookByIdEndpoint.cs`
|
|
357
|
-
|
|
358
|
-
---
|
|
359
|
-
|
|
360
|
-
### T008: Implementar slice UpdateBook (Handler + Validator + Endpoint)
|
|
361
|
-
- **Category:** slice
|
|
362
|
-
- **Estimate:** 45min
|
|
363
|
-
- **Dependencies:** T001, T002, T003, T004
|
|
364
|
-
|
|
365
|
-
**Description:**
|
|
366
|
-
Implementar o slice de atualização. Handler retorna `BookErrors.NotFound()` se o livro não existir antes de atualizar. Handler injeta: `IRepository<Book>` + `IUnitOfWork`.
|
|
367
|
-
|
|
368
|
-
**Deliverables:**
|
|
369
|
-
- [ ] Create: `Features/BookFeature/UpdateBook/UpdateBookHandler.cs`
|
|
370
|
-
- [ ] Create: `Features/BookFeature/UpdateBook/UpdateBookValidator.cs`
|
|
371
|
-
- [ ] Create: `Features/BookFeature/UpdateBook/UpdateBookEndpoint.cs`
|
|
372
|
-
|
|
373
|
-
---
|
|
374
|
-
|
|
375
|
-
### T009: Implementar slice DeleteBook (Handler + Validator + Endpoint)
|
|
376
|
-
- **Category:** slice
|
|
377
|
-
- **Estimate:** 30min
|
|
378
|
-
- **Dependencies:** T001, T002, T003, T004
|
|
379
|
-
|
|
380
|
-
**Description:**
|
|
381
|
-
Implementar o slice de deleção. Handler verifica existência antes de deletar, retorna `BookErrors.NotFound()` se não existir. Handler injeta: `IRepository<Book>` + `IUnitOfWork`.
|
|
382
|
-
|
|
383
|
-
**Deliverables:**
|
|
384
|
-
- [ ] Create: `Features/BookFeature/DeleteBook/DeleteBookHandler.cs`
|
|
385
|
-
- [ ] Create: `Features/BookFeature/DeleteBook/DeleteBookValidator.cs`
|
|
386
|
-
- [ ] Create: `Features/BookFeature/DeleteBook/DeleteBookEndpoint.cs`
|
|
387
|
-
|
|
388
|
-
---
|
|
389
|
-
|
|
390
|
-
## Summary
|
|
391
|
-
|
|
392
|
-
| Phase | Tasks | Estimate |
|
|
393
|
-
|-------|-------|----------|
|
|
394
|
-
| Foundation (entity + errors + tags + migration) | T001–T004 | 45min |
|
|
395
|
-
| Slices (Create + GetAll + GetById + Update + Delete) | T005–T009 | 2h55m |
|
|
396
|
-
| **Total** | **9 tasks** | **~3h40m** |
|
|
397
|
-
|
|
398
|
-
> **VSA Note:** No manual DI registration needed — `AddHandlersFromAssembly()`,
|
|
399
|
-
> `RegisterApiEndpointsFromAssembly()`, and `AddValidatorsFromAssembly()` discover
|
|
400
|
-
> all handlers, endpoints and validators automatically via assembly scanning (Scrutor).
|
|
401
|
-
|
|
402
|
-
---
|
|
403
|
-
|
|
404
|
-
*MORPH-SPEC by Polymorphism Tech*
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* validate-tasks.mjs
|
|
4
|
-
*
|
|
5
|
-
* Validates a MORPH-SPEC tasks.md file for structure and completeness.
|
|
6
|
-
* Executed locally by Claude via Bash — output returned to Claude.
|
|
7
|
-
*
|
|
8
|
-
* Usage:
|
|
9
|
-
* node validate-tasks.mjs <tasks-file>
|
|
10
|
-
* node validate-tasks.mjs .morph/features/my-feature/4-tasks/tasks.md
|
|
11
|
-
*
|
|
12
|
-
* Checks:
|
|
13
|
-
* - Summary table exists with T### IDs and valid statuses
|
|
14
|
-
* - Each task header has T### format
|
|
15
|
-
* - Each task has Type, Priority, Estimate, Dependencies fields
|
|
16
|
-
* - Each task has at least one deliverable checkbox
|
|
17
|
-
* - Task IDs are sequential (no gaps)
|
|
18
|
-
* - Reports counts by status
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
import { readFileSync, existsSync } from 'fs';
|
|
22
|
-
|
|
23
|
-
const taskFile = process.argv[2];
|
|
24
|
-
|
|
25
|
-
if (!taskFile) {
|
|
26
|
-
console.error(JSON.stringify({ error: 'Usage: validate-tasks.mjs <tasks-file>' }));
|
|
27
|
-
process.exit(1);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (!existsSync(taskFile)) {
|
|
31
|
-
console.error(JSON.stringify({ error: `File not found: ${taskFile}` }));
|
|
32
|
-
process.exit(1);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const content = readFileSync(taskFile, 'utf-8');
|
|
36
|
-
const lines = content.split('\n');
|
|
37
|
-
|
|
38
|
-
const errors = [];
|
|
39
|
-
const warnings = [];
|
|
40
|
-
|
|
41
|
-
// 1. Parse summary table (| T001 | Type | Title | Status |)
|
|
42
|
-
const tableRows = lines.filter(l => /^\|\s*T\d{3}/.test(l));
|
|
43
|
-
const VALID_STATUSES = new Set(['Pending', 'In Progress', 'Blocked', 'Done']);
|
|
44
|
-
const summaryTasks = [];
|
|
45
|
-
|
|
46
|
-
for (const row of tableRows) {
|
|
47
|
-
const parts = row.split('|').map(s => s.trim()).filter(Boolean);
|
|
48
|
-
if (parts.length < 4) continue;
|
|
49
|
-
const [id, , , status] = parts;
|
|
50
|
-
summaryTasks.push({ id, status });
|
|
51
|
-
if (!VALID_STATUSES.has(status)) {
|
|
52
|
-
errors.push(`Task ${id}: invalid status '${status}' — must be one of: ${[...VALID_STATUSES].join(', ')}`);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (summaryTasks.length === 0) {
|
|
57
|
-
errors.push('No summary table found — expected rows matching | T### | Type | Title | Status |');
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// 2. Parse task headers (### T001: Title or ### T001 — Title or ### T001 - Title)
|
|
61
|
-
const taskHeaders = lines
|
|
62
|
-
.map((l, i) => ({ line: i + 1, match: l.match(/^###\s+(T\d{3})\s*[—–:\-]\s+(.+)/) }))
|
|
63
|
-
.filter(r => r.match);
|
|
64
|
-
|
|
65
|
-
// Check sequential IDs
|
|
66
|
-
const ids = taskHeaders.map(r => parseInt(r.match[1].slice(1)));
|
|
67
|
-
for (let i = 0; i < ids.length; i++) {
|
|
68
|
-
if (ids[i] !== i + 1) {
|
|
69
|
-
warnings.push(`Task ID gap or duplicate near T${String(ids[i]).padStart(3, '0')} (expected T${String(i + 1).padStart(3, '0')})`);
|
|
70
|
-
break;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// 3. Check each task section has required fields
|
|
75
|
-
for (const { line, match } of taskHeaders) {
|
|
76
|
-
const taskId = match[1];
|
|
77
|
-
// Collect lines in this task section (until next ### or end)
|
|
78
|
-
const start = line; // 1-indexed
|
|
79
|
-
let end = lines.length;
|
|
80
|
-
for (let i = start; i < lines.length; i++) {
|
|
81
|
-
if (i > start - 1 && /^#{1,3}\s/.test(lines[i])) { end = i; break; }
|
|
82
|
-
}
|
|
83
|
-
const section = lines.slice(start, end).join('\n');
|
|
84
|
-
|
|
85
|
-
if (!/\*\*Type:\*\*/.test(section)) errors.push(`${taskId}: missing **Type:** field`);
|
|
86
|
-
if (!/\*\*Priority:\*\*/.test(section)) errors.push(`${taskId}: missing **Priority:** field`);
|
|
87
|
-
if (!/\*\*Estimate:\*\*/.test(section)) errors.push(`${taskId}: missing **Estimate:** field`);
|
|
88
|
-
if (!/\*\*Dependencies:\*\*/.test(section)) warnings.push(`${taskId}: missing **Dependencies:** field`);
|
|
89
|
-
if (!/- \[ \]/.test(section)) warnings.push(`${taskId}: no deliverable checkboxes found`);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// 4. Status counts
|
|
93
|
-
const statusCounts = {};
|
|
94
|
-
for (const { status } of summaryTasks) {
|
|
95
|
-
statusCounts[status] = (statusCounts[status] ?? 0) + 1;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const result = {
|
|
99
|
-
file: taskFile,
|
|
100
|
-
valid: errors.length === 0,
|
|
101
|
-
tasks: {
|
|
102
|
-
total: summaryTasks.length,
|
|
103
|
-
byStatus: statusCounts,
|
|
104
|
-
completed: statusCounts['Done'] ?? 0,
|
|
105
|
-
remaining: (summaryTasks.length) - (statusCounts['Done'] ?? 0),
|
|
106
|
-
},
|
|
107
|
-
errors,
|
|
108
|
-
warnings,
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
console.log(JSON.stringify(result, null, 2));
|
|
112
|
-
process.exit(errors.length > 0 ? 1 : 0);
|