---
name: fp-erd-to-execplan
description: Break an ERD into a sprint-ready execution plan of waves → epics → stories with dependencies, hour estimates, critical path, and citations to the patterns/learnings that shaped each story. Saves to fastpace/exec-plans/<slug>.json for the local dashboard to render and assign. Triggers on /fp-erd-to-execplan <erd-slug>.
---

# fp-erd-to-execplan

Produce a plan the team can actually assign — waves that respect dependencies, epics that ship as coherent units, stories small enough for one engineer in 1-2 days, and a critical path the lead can watch.

## Preflight

1. **ERD must exist.** Read `fastpace/docs/erd/<slug>.md`. If missing, tell the user to run `/fp-prd-to-erd <slug>` first and stop.
2. **Context load (calibration):**
   - `fastpace/context/architecture.md` — which modules will each epic touch.
   - `fastpace/context/patterns.md` — reusable idioms shrink stories.
   - `fastpace/context/learnings.md` — past incidents may insert stories (e.g. "jitter" after a thundering-herd learning).
   - `fastpace/exec-plans/*.json` — prior plans of similar size calibrate your estimates.
3. **Check for prior plan.** If `fastpace/exec-plans/<slug>.json` exists, ask: "Plan exists — recompute from the current ERD, or diff against existing?" Default to diff, not overwrite.

## Structure

```
Plan
  ├─ Wave 1   (ships together; epics within run in parallel)
  │   ├─ Epic 1A
  │   │   ├─ Story 1A-1  (1-16h; one engineer)
  │   │   └─ Story 1A-2
  │   └─ Epic 1B
  ├─ Wave 2   (blocked_by wave 1)
  │   └─ …
  └─ Wave N
```

**Waves are time-ordered.** Epic in wave N cannot start until every epic in wave N-1 is done.
**Epics within a wave run in parallel** (can be assigned to different people).
**Stories are the unit of assignment.** One person, 1-2 days max.

## Process

1. **Extract epics** from the ERD. Good epic boundaries match ERD sections (Interface contract, Data model, Security, Observability, Rollout). Each epic ships a coherent piece.
2. **Order into waves.** A clean heuristic:
   - Wave 1: foundations — schema, auth changes, shared utilities.
   - Wave 2: core functionality — the thing the PRD asked for.
   - Wave 3: rollout — flags, metrics, alerts, canary.
   - Add more waves only when dependency chains are real.
3. **Break each epic into stories.** Each story gets: a name, an hour estimate, a list of files/areas it touches, optional dependencies on other stories.
4. **Hour estimates — honest, test-time included.**
   - Skeleton logic: 2-4h
   - Logic + unit tests: 4-8h
   - Logic + integration tests + migration: 8-12h
   - Cross-cutting or new subsystem: 12-16h (split further if possible)
   - **No story > 16h.** If you can't get below 16h, split it.
5. **Cite pattern/learning reuse.** For any story that reuses an existing pattern or sidesteps a past incident, record it in `sources`:
   ```json
   { "name": "withRetry wrapper", "hours": 3, "sources": ["fastpace/context/patterns.md#retry-with-backoff"] }
   ```
   These appear in the dashboard as chips on each story.
6. **Compute the critical path.** It's the longest chain of dependent stories across all waves. Store the ordered list of story IDs as `summary.critical_path`.
7. **Fill summary aggregates:** total hours, wave count, epic count, story count, critical-path hours + days.
8. **Write** to `fastpace/exec-plans/<slug>.json` using the schema below.
9. **Report**: summary line + "open `fastpace ui` to assign names and track progress".

## JSON schema (exact)

```json
{
  "id": "<slug>",
  "name": "<feature name>",
  "status": "active",
  "created_at": "<iso>",
  "updated_at": "<iso>",
  "erd_path": "fastpace/docs/erd/<slug>.md",
  "summary": {
    "waves": 3,
    "epics": 5,
    "stories": 12,
    "total_hours": 48,
    "critical_path": ["S1", "S2", "S5", "S9"],
    "critical_path_hours": 18,
    "critical_path_days": 2.25
  },
  "waves": [
    {
      "id": "W1",
      "name": "Wave 1 — Foundation",
      "epics": [
        {
          "id": "E1",
          "name": "Auth schema",
          "blocked_by": [],
          "stories": [
            {
              "id": "S1",
              "name": "User table migration",
              "hours": 4,
              "assignee": "",
              "status": "todo",
              "depends_on": [],
              "sources": ["fastpace/context/patterns.md#migrations"],
              "description": "",
              "acceptance_criteria": []
            }
          ]
        }
      ]
    }
  ]
}
```

All string IDs follow the scheme:
- Waves: `W1`, `W2`, `W3`, …
- Epics: `E1`, `E2`, `E3`, … (numbered across the whole plan, not per wave)
- Stories: `S1`, `S2`, `S3`, … (numbered across the whole plan)

## Rules

- **No story > 16h.** Split heroic stories. If something seems big, it hides unknowns — flag them as Open Questions on the ERD rather than burying them in the plan.
- **`assignee` always empty.** The team assigns via `fastpace ui` → Execution plans. Do not pre-assign.
- **`status: "todo"` on every new story.** The dashboard flips these.
- **`blocked_by` references epic IDs, not stories.** Use `depends_on` on the story level for intra-wave ordering.
- **Cite source only for non-obvious reuse.** "S1: write code" needs no source. "S5: jitter on retries" should cite `learnings.md` with the incident date.
- **Critical path is a property, not a guess.** It's the longest chain of strictly dependent stories. If two paths tie, pick the one with more unknowns (higher risk).
- **Don't invent dependencies.** If two epics could run in parallel, let them — don't gate unnecessarily.
- **Don't bloat stories with padding hours.** Honest numbers compound better than defensive ones.
- **If the ERD has acceptance criteria, map them.** Each criterion should be traceable to at least one story; copy the criterion text into that story's `acceptance_criteria`.

## Calibration — using prior plans

If `fastpace/exec-plans/` has other completed plans:

- Read their `summary.total_hours` and `summary.critical_path_hours`.
- If your new plan is dramatically larger or smaller than comparable prior features, say so in the report line: "Plan is ~1.8× the hours of `<prior-slug>`. Mention in case that's unexpected."
- Don't force-calibrate. Real changes in scope should show up as real changes in hours.

## Integration

- After writing, remind the user: `fastpace ui` to assign and track.
- If a story requires a new pattern you invented during design, suggest `/fp-remember` to add it to `patterns.md`.
- If the ERD had open questions, echo them back — execution plan is not the place to resolve ERD gaps.
- If a story's `sources` references `learnings.md`, surface that: "S5 insulates against `learnings.md § <date>` — make sure the assignee reads that entry before starting."

## Exit criteria

- File written at `fastpace/exec-plans/<slug>.json`.
- All stories have hours ≤ 16, status `todo`, assignee empty.
- `summary.critical_path` is non-empty and consistent with the stories.
- Report block includes: wave/epic/story counts, total hours, critical-path hours + days, and `fastpace ui` pointer.
