# Discovery schema — the OLD spelling of the Product level

> **Since E75 this is the older spelling.** New products get a Foundation in `{project-root}/foundation/`
> — see `foundation-schema.md`, seeded by `yad foundation new`. This page stays because a product that
> already has an `EP-discovery` keeps working exactly as described here: the engine still reads it, gates
> it, and ends its review at `discovery-done`.
>
> **Converting it.** On a **local** ledger, `yad migrate --apply` moves `epics/EP-discovery/` into
> `foundation/`: the six files keep their names (so their fingerprint, and every approval bound to it,
> is unchanged), the ledger is re-labelled to the Foundation's ids, and the step keeps `artifact:
> "discovery/"` so the gate still hashes those six files. On a **verified** ledger CI owns the files and
> the move cannot be made by a human commit, so the gate bot makes it: `yad gate ci` moves the folder at
> the next merged review it handles, once the product level's own review has passed and the checks
> committed in the repo know `foundation/`. A product has ONE product level: never seed a Foundation beside an `EP-discovery`.

The project discovery phase ("epic zero") lives under `{project-root}/epics/EP-discovery/`. It reuses
the per-epic ledger files (`.sdlc/state.json`, `approvals.json`, `comments.json`, `reviews/`,
`product-prs.json` + `hub-prs.json`) unchanged — `EP-discovery` is a valid epic id, so the existing gate, PR/MR bridge, CI
sync, and `yad next` all operate on it. What is special is the `kind: "discovery"` marker on the state
object and the 2-step chain.

## State (`.sdlc/state.json`)

```json
{
  "epicId": "EP-discovery",
  "kind": "discovery",
  "createdAt": "<YYYY-MM-DD>",
  "currentStep": "discovery-review",
  "steps": [
    { "id": "discovery",        "type": "author",         "artifact": "discovery/", "assistance": "review", "driver": "pair", "automation": "human_approve", "advance": "human", "locked": true, "status": "done",      "risk_tags": [] },
    { "id": "discovery-review", "type": "review+approve", "artifact": "discovery/", "assistance": "review", "driver": "pair", "automation": "human_approve", "advance": "human", "locked": true, "status": "in_review", "risk_tags": [] }
  ]
}
```

- `artifact: "discovery/"` is a **virtual** base: `artifactHash` fingerprints the whole discovery file
  set (`discoveryHash` in `cli/epic-state.mjs`), so an edit to any discovery file revokes prior
  approvals — exactly like `stories/` fingerprints the stories directory. The frontmatter `status:` line
  is left out of each file's fingerprint, so the gate flipping it to `approved` is not an edit.
- The **full set is required to review**: if any of the six files is missing, `discoveryHash` returns
  `null` — the discovery is **incomplete and non-reviewable** (no hash to bind an approval to), and
  `yad gate open` / `yad gate sync` warn with the missing filenames. Write all six (in greenfield,
  `current-state.md` is a short clean-slate note) before handing off to the gate.
- On approval the gate sets `currentStep: "discovery-done"` (a terminal sentinel — discovery has **no**
  Build, so it never becomes `ready-for-build`).
- The discovery files (relative to the epic dir) the gate commits on the review branch and re-hashes at
  merge are: `market-research.md`, `competitor-analysis.md`, `current-state.md`, `feasibility.md`,
  `requirements.md`, `roadmap.md` (the `DISCOVERY_FILES` list).

## Artifact templates

### `requirements.md`

```markdown
---
id: EP-discovery
artifact: requirements
status: draft
owner:
---

## Functional requirements
<!-- candidate features — each becomes (or seeds) a feature epic later -->

| Ref | Requirement | Description | Priority | MVP? |
|-----|-------------|-------------|----------|------|
| F-01 | Registration | A new user can create an account | must | yes |
| F-02 | Login | A returning user can authenticate | must | yes |

## Non-functional requirements
<!-- cross-cutting qualities the whole product must hold -->

| Ref | Category | Requirement | Target / acceptance |
|-----|----------|-------------|---------------------|
| N-01 | Performance | p95 page load | < 2s on 4G |
| N-02 | Security | auth + data-at-rest | OWASP ASVS L1; encrypted at rest |
| N-03 | Accessibility | WCAG conformance | AA |
```

### `roadmap.md` (the spine of the review)

```markdown
---
id: EP-discovery
artifact: roadmap
status: draft
owner:
---

## Summary
<!-- the product thesis in 2–3 lines; links to market-research, competitor-analysis,
     current-state, feasibility, requirements -->

## Phase 1 — MVP
<!-- the smallest valuable slice; the features here are built first -->

| Feature | Proposed epic id | Requirements | Status |
|---------|------------------|--------------|--------|
| Registration | EP-registration | F-01 | planned |
| Login | EP-login | F-02 | planned |

## Phase 2 — <name>
| Feature | Proposed epic id | Requirements | Status |
|---------|------------------|--------------|--------|
| … | EP-… | F-… | planned |

## Later / parked
<!-- explicitly deferred, with why -->
```

**Do not update the `Status` column by hand.** Editing the roadmap after its review has passed makes the
approvals read as stale; `yad foundation status` reads each feature's status from the epic ledgers, for
this spelling too. (The column's old hand-set ladder was `planned` → `epic-started` → `shipped`; rows that
already say so can stay.) The proposed `EP-<slug>` ids are suggestions for the eventual
`yad-epic` runs — `yad-epic` still assigns the id (and skips the reserved `EP-discovery`).

The other four artifacts (`market-research.md`, `competitor-analysis.md`, `current-state.md`,
`feasibility.md`) are free-form Markdown with a `--- id / artifact / status / owner ---` frontmatter
block matching the two above. `competitor-analysis.md` is required in BOTH greenfield and brownfield;
`current-state.md` is the substantive code-aware study in brownfield and a short clean-slate note in
greenfield.
