Task Specification¶
Every task in a Craft Easy project is driven by a spec file at tasks/<TASK-ID>/spec.md. The runner agent reads the spec before doing anything else. A high-quality spec produces a high-quality implementation.
Spec frontmatter¶
The spec begins with a metadata block:
**Domän:** API / Backend
**Berör:** craft-easy-api, craft-easy-admin
**Beror på:** PL-T289, PL-T293
**Risk:** HIGH | MEDIUM | LOW
**Modell:** `claude-opus-4-7`
**Spec-version:** 1
**Status:** Ready
| Field | Description |
|---|---|
Domän |
Primary domain (API / Backend, Frontend, Mobile, Infrastructure, …) |
Berör |
Which packages or repos are touched |
Beror på |
BACKLOG task IDs that must be complete before this task can run |
Risk |
HIGH = destructive migrations, auth changes, financial logic; MEDIUM = new features; LOW = docs, renames |
Modell |
Claude model to use. See Framework Hub: Model Routing |
Spec-version |
Increment when the spec is substantially revised after work has started |
Status |
Draft / Ready / In Progress / Done |
Spec sections¶
A complete spec has these sections, in order:
1. Mål (Goal)¶
One to two sentences: what does this task deliver and why? Written for someone who hasn't read the backlog.
2. Bakgrund (Background)¶
Context: what triggered this task, who is affected, how it fits the system, any tenant-specific behaviour.
3. Förundersökning (Pre-investigation)¶
Filled by the agent as Phase 0, before writing any code. Summary of findings, assumptions verified, discovered risks, and open questions for the owner. Uses the forundersokning.md template as a guide.
3.1 Spec-lucka-scan (mandatory first step)¶
A table — one row per sentence in §1–§2 plus any external spec source — where each row articulates:
| Column | Content |
|---|---|
| Specuttryck | Exact citation from the spec |
| Min tolkning | What the agent thinks it means |
| Vad jag gissar | How the agent plans to implement it |
| Behöver svar? | ja / nej — escalate ja rows to §3.4 |
Empty table = the task may not advance to §4. "Nothing unclear" is extremely rare — the agent should reconsider before claiming it.
The mechanism's purpose is to make tacit guesses visible. Without §3.1 the agent assumes silently and ships subtly wrong implementations.
3.2 Antaganden / 3.3 Risker / 3.4 Frågor till ägaren¶
Standard sections — assumptions verified by owner, identified risks, open questions with recommendations. See the template for full layout.
3.5 Berörda system¶
A scoping section listing the API paths, app surfaces, specs, and docs touched. Drives §13 (yt-täckningsmatris) and §14 (skapa-konsumera-par).
4. Acceptanskriterier (Acceptance Criteria)¶
Numbered, testable requirements. Each criterion will be signed off with a file:line reference at the end of the spec.
1. `POST /api/v1/agreements` returns 201 with the created document.
2. Existing agreements for the same tenant are not affected.
3. The admin UI shows a "New Agreement" button on the agreements list screen.
5. Datamodell (Data Model)¶
Exact field names, Python types, Beanie validators, defaults, indexes, TTL, soft-delete field. No vague descriptions — the agent must be able to implement without guessing.
6. Lager-trace (Layer Trace)¶
Field-by-field trace from database → query → model → DTO → API response → UI display. Ensures no field is lost or transformed unexpectedly.
6b. Data-flöde-trace (UI → backend)¶
Complement to §6 in the opposite direction, for every UI flow that sends data. Traces UI form / button → API wrapper → DTO → service → repository → DB. A single ✗ anywhere in the chain means the feature is "silently broken": the UI looks fine, the backend looks fine, but no data crosses the gap.
Classic catch this section was added to prevent: a UI that displayed "Discount code TEST −50%" applied locally, while discountCode was never serialised in the outgoing request body.
7. API-kontrakt (API Contract)¶
For each new or modified endpoint:
Method: POST
Path: /api/v1/agreements
Auth: Bearer + require_capability("agreements.create")
Request: { "tenant_id": str, "type": "FIPJP" | "CEP", "valid_from": date }
Response: 201 { "id": str, "created_at": datetime, ... }
Errors: 400 validation, 403 capability, 409 duplicate
8. UI-kontrakt (UI Contract)¶
Affected views, behaviour on success/error/loading/empty, i18n keys, responsiveness requirements.
9. Säkerhet — OWASP (Security)¶
Checklist for OWASP Top 10 items relevant to this task (A01 Broken Access Control, A02 Cryptographic Failures, A03 Injection, …). Mark N/A for items that genuinely do not apply.
10. Per-tenant testmatris (Per-Tenant Test Matrix)¶
Explicit test scenarios for each tenant configuration:
| Scenario | Sverige | France | Deutschland | Cross-tenant isolation |
|---|---|---|---|---|
| Happy path | ✓ | ✓ | ✓ | ✓ |
| Missing required field | ... | ... | ... | — |
11. Performance budget¶
- API: p95 response time ≤ 300ms (local dev, non-cold-start)
- Frontend bundle: delta ≤ +50KB gzipped vs. current build
- Database: new indexes declared; Cosmos Free Tier (1000 RU/s) considered
12. Accessibility (WCAG 2.1 AA)¶
Contrast ratio, keyboard navigation, ARIA labels, screen reader behaviour. Required for any UI change.
13. Ytäckningsmatris (Surface Coverage Matrix)¶
Which surfaces are affected and in which repositories:
| Surface | Repo | Affected? |
|---|---|---|
| API / Backend | craft-easy-api | ✓ |
| Web portal | petanque-life/apps/web | ✓ |
| Mobile | petanque-life/apps/app | — |
| Admin | craft-easy-admin | ✓ |
| Jobs | craft-easy-jobs | — |
14. Skapa-konsumera-par (Create-Consume Pairs)¶
Every "create" flow must have a matching "consume/display" flow and vice versa. List all pairs explicitly.
14b. Parallel-path-konsistens¶
A table for operations implemented in multiple places (Stripe / Swish / Invoice payment paths, per-tenant variations, alternative auth flows). Every row must either be identical or carry an explicit motivation for the divergence.
Catches: payment-path A applies a discount before tax, payment-path B applies it after, the spec says nothing about which is correct, and the test suite passes both because each path is tested in isolation.
15. Testscenario-matris (Test Scenario Matrix)¶
Filled BEFORE implementation (not post-hoc):
| Scenario | Type | Expected result |
|---|---|---|
| Valid agreement created | Happy path | 201, document in DB |
| Duplicate agreement same tenant | Edge | 409 |
Missing type field |
Validation | 400 |
Caller lacks agreements.create |
Authorization | 403 |
16. Tester som måste finnas (Required Tests)¶
Explicit list of test files and test cases that must exist when the task is marked complete. The agent cannot mark [x] in BACKLOG.md without these passing.
17. Dokumentation¶
- Which docs/ files need updating
- Which feature/ entries need adding
- Any public endpoint or settings change that requires reference updates
18. Definition of Done¶
Six-phase gate checklist. All gates must be green before marking [x] in BACKLOG.md:
| Phase | Gates |
|---|---|
| Fas 0 Förundersökning | Section 3 filled (incl. §3.1 spec-lucka-scan); all open questions resolved or escalated |
| Fas 1 Build | api_imports, api_lint, api_typecheck, frontend_build |
| Fas 2 Test | api_unit, api_integration, frontend_test |
| Fas 3 Verify | verify_changes (static analysis), verify_spec_coverage (all ACs mapped) |
| Fas 4 Smoke & E2E | *_smoke, web_e2e, app_maestro (where applicable) |
| Fas 5 Tenants & Security | sverige_fixture, france_fixture, deutschland_fixture, cross_tenant_isolation, pip_audit, npm_audit, secrets_scan, capability_check |
| Fas 6 Evidence | adversarial_review, vad_testade, surface_matrix, spec_bullet_signoff, create_consume_pairs, test_scenarios |
18b. Konfidens-bedömning (klar-gate)¶
Risk-adjusted confidence threshold the agent must clear before marking [x]:
| Risk | Threshold |
|---|---|
| LOW | ≥ 90 % |
| MEDIUM | ≥ 95 % |
| HIGH | ≥ 97 % (and two independent review passes) |
The agent must write a free-text statement of what the confidence is based on and what creates uncertainty. "Code looks correct" is explicitly insufficient. Checkbox-green doesn't satisfy this gate either — the gate exists exactly because checkbox-green has been wrong before.
19. Adversarial Self-Review¶
The agent's own adversarial pass: "If I were trying to break this, what would I try?" Must identify at least three potential attack vectors or failure modes and confirm they are handled.
19.1 Ready-to-use adversarial-review prompt¶
The template ships a complete Agent({...}) invocation to copy when running Fas 4. Output is saved to tasks/{TASK-ID}/review.md so it survives across runs and is part of the evidence trail.
19.2 Seven shallow-review traps¶
A concrete catalogue to actively scan against:
- Data-flow silence — UI/backend look correct in isolation; no data crosses the gap (driver for §6b)
- Null DI service — service registered but never wired into the consumer
- Missing DTO field — backend serialises a field the frontend silently ignores
- Parallel-path divergence — Stripe/Swish/Invoice differ in a way the spec doesn't sanction (driver for §14b)
- Spec-text vs code-state — spec says "must X", code does Y, tests pass because tests reflect Y
- Validation vs operation mismatch — input validated against schema A, operation reads schema B
- Too few review passes — single read-through claimed sufficient where HIGH-risk needed two independent passes
20. Vad jag faktiskt testade (What I Actually Tested)¶
Honest 30-second summary of what was actually run and verified. Marks: - ✓ = tested and passing - ✗ = known failure (must be documented in OWNER_TODO.md) - ⚠ = skipped with reason - 💬 = manual verification described
This section exists to prevent the agent from marking tasks complete without real verification.
21. Spec-bullet sign-off¶
Each acceptance criterion from section 4, mapped to the exact file and line number of the implementation:
1. POST /api/v1/agreements → 201: craft-easy-api/resources/agreements.py:47
2. Existing agreements unaffected: tests/integration/test_agreements.py:88
3. Admin "New Agreement" button: craft-easy-admin/screens/AgreementsScreen.tsx:112
Using the template¶
The tasks/templates/task-spec.md file in your project (synced from Framework Hub) contains the full empty template. When creating a new spec:
Or ask the Claude chat panel to create the spec — Opus will fill in sections based on your description of the feature.