# Phase 01 — Scope & Intent

**Mode:** INLINE (interactive — orchestrator + user co-produce the migration intent).
**Workflow CLI param:** `--workflow=migration`.
**Inputs (must exist on entry):** The 6 context markers from Phase 00 (`MIGRATION_ID`, `FROM_PATTERN`, `TO_PATTERN`, `SCOPE`, `EXCLUSIONS`, `DRY_RUN`); `tmp/${MIGRATION_ID}/` exists.
**Outputs (must exist on exit):** `tmp/${MIGRATION_ID}/intent.json` — the 5-field migration contract that the rest of the workflow reads from disk.

---

## Entry Gate [MANDATORY]

```bash
devforgeai-validate phase-check ${SESSION_ID} --workflow=migration --from=00 --to=01
```
IF exit != 0: HALT — Phase 00 incomplete or skipped.

---

## Reference Loading [MANDATORY]

```
Read(file_path=".claude/skills/spec-driven-migration/assets/templates/intent-template.json")
```

IF Read fails: HALT -- "Phase 01 reference files not loaded."

---

## Step 1.1: Confirm the Migration Intent with the User

Phase 01 is the **only** phase in the workflow where the user's judgment shapes the migration scope. The /migrate-refs command supplies defaults, but those defaults are starting points — the user must explicitly approve the final scope before any classification, transformation, or commit happens.

The most consequential decision is the **scope tightness**. A loose scope produces many false-positive matches the classifier has to bucket out; a tight scope risks missing legitimate occurrences. Per [[feedback_dual_path_mechanical_migration]] (project-side memory): "scope by the verification grep, not the raw grep" — choose `scope_dirs` and `exclusions` such that the final residual `Grep(pattern=FROM_PATTERN)` returns ONLY intentional / historical / EXCLUDED hits. If a directory is full of historical references that will never need to change, EXCLUDE it now; do not rely on the classifier to bucket each one as DOC-historical.

**EXECUTE:**

Issue AskUserQuestion to confirm the 5 fields of `intent.json`. The question MUST surface the context-marker defaults verbatim AND the implications.

```
AskUserQuestion:
  Question: "Confirm migration intent for ${MIGRATION_ID}. From-pattern: '${FROM_PATTERN}'. To-pattern: '${TO_PATTERN}'. Default scope: ${SCOPE}. Default exclusions: ${EXCLUSIONS}. Proceed with these, narrow scope, or amend exclusions?"
  Header: "Migration Intent Confirmation"
  Options:
    - label: "Confirm as defaulted (Recommended)"
      description: "Use ${SCOPE} as scope_dirs and ${EXCLUSIONS} as exclusions; classify to_type from ${TO_PATTERN} signal."
    - label: "Narrow scope_dirs"
      description: "Restrict scope_dirs to a subset of the default (orchestrator will prompt for the subset)."
    - label: "Expand exclusions"
      description: "Add exclusion patterns (orchestrator will prompt for the additional patterns)."
    - label: "Override to_type"
      description: "Explicitly declare to_type as file | folder | cli (overrides the auto-detect from ${TO_PATTERN})."
  multiSelect: true
```

For each non-"Confirm as defaulted" option the user selects, issue a follow-up AskUserQuestion to collect the specific override. Resolve all four fields:

- **from_pattern** — literal string (locked at the value of `$FROM_PATTERN`; cannot be amended in Phase 01).
- **to_pattern** — literal string (locked at the value of `$TO_PATTERN`).
- **to_type** — one of `file`, `folder`, `cli`. Auto-detect: if `$TO_PATTERN` ends with `/` → `folder`; if it matches `<noun>-<verb>` (e.g., `query-source-tree`) → `cli`; else `file`. The user override always wins.
- **scope_dirs** — list of directory paths (defaulted from `$SCOPE`).
- **exclusions** — list of glob patterns (defaulted from `$EXCLUSIONS`, possibly extended).

**VERIFY:**
- The user explicitly selected at least one option (defaults are NOT silently inherited).
- For every override option selected, a concrete value was collected.
- `to_type` is one of `{file, folder, cli}`.
- `scope_dirs` is a non-empty list. Each entry resolves to a directory that exists in the working tree (`Glob(pattern="<dir>/")` returns ≥ 1 path).
- `exclusions` is a list (may be empty).

IF the user picked "Confirm as defaulted" alongside any override option: HALT — these are mutually exclusive. AskUserQuestion to clarify.

**RECORD:**
```bash
devforgeai-validate phase-record ${SESSION_ID} --workflow=migration --phase=01 --step=intent-confirmed
```

---

## Step 1.2: Write `intent.json`

The 5 confirmed fields become the durable migration contract. Every downstream phase reads from this file — the orchestrator's in-memory state is NOT a substitute.

**EXECUTE:**

Read the template:
```
Read(file_path="assets/templates/intent-template.json")
```
(Forward-declared; the template is authored separately. If the file does not exist yet, fall back to the inline schema below.)

Inline fallback schema:
```json
{
  "migration_id": "<MIGRATION_ID>",
  "from_pattern": "<from_pattern>",
  "to_pattern":   "<to_pattern>",
  "to_type":      "<file|folder|cli>",
  "scope_dirs":   ["<dir1>", "<dir2>", "..."],
  "exclusions":   ["<glob1>", "<glob2>", "..."],
  "dry_run":      <true|false>,
  "captured_at":  "<ISO 8601 timestamp>"
}
```

Populate every field from Step 1.1's confirmed values + the Phase 00 markers. Then:
```
Write(file_path="tmp/${MIGRATION_ID}/intent.json", content=<populated JSON>)
```

**VERIFY:**
- The file exists on disk:
  ```
  Glob(pattern="tmp/${MIGRATION_ID}/intent.json")  # MUST return exactly 1 path
  ```
- The file content is valid JSON (re-Read and parse).

**RECORD:**
```bash
devforgeai-validate phase-record ${SESSION_ID} --workflow=migration --phase=01 --step=intent-written
```

---

## Step 1.3: Structural Re-Verification of `intent.json`

The Write succeeded by exit code, but the orchestrator MUST independently structurally verify the file before Phase 02 reads it. A malformed `intent.json` would propagate silently into the classifier's fresh context, and the classifier would produce a useless `classification.md`.

**EXECUTE:**
```
Read(file_path="tmp/${MIGRATION_ID}/intent.json")
```
Confirm each of the 5 required keys is present by Grep:
```
Grep(pattern="\"from_pattern\"",  path="tmp/${MIGRATION_ID}/intent.json")
Grep(pattern="\"to_pattern\"",    path="tmp/${MIGRATION_ID}/intent.json")
Grep(pattern="\"to_type\"",       path="tmp/${MIGRATION_ID}/intent.json")
Grep(pattern="\"scope_dirs\"",    path="tmp/${MIGRATION_ID}/intent.json")
Grep(pattern="\"exclusions\"",    path="tmp/${MIGRATION_ID}/intent.json")
```
Each Grep MUST return exactly 1 match.

**VERIFY:**
- All 5 Greps returned 1 match each.
- The JSON's `to_type` value is one of `{file, folder, cli}` (re-parse and check).
- The JSON's `scope_dirs` is a non-empty array.
- No required field has the literal string `"<...>"` (an un-substituted template placeholder).

IF any verification fails: HALT and AskUserQuestion — "intent.json failed structural verification. Re-run Step 1.2 (rewrite the file) or escalate the malformed field."

**RECORD:**
```bash
devforgeai-validate phase-record ${SESSION_ID} --workflow=migration --phase=01 --step=intent-verified
```

---

## Exit Gate [MANDATORY]

```bash
devforgeai-validate phase-complete ${SESSION_ID} --workflow=migration --phase=01 --checkpoint-passed
```
IF exit != 0: HALT.

---

## Phase 01 Success Criteria

- [ ] The user explicitly confirmed (or overrode) every field of the migration intent via AskUserQuestion. Defaults were NOT silently inherited.
- [ ] `tmp/${MIGRATION_ID}/intent.json` exists on disk with all 5 required fields (`from_pattern`, `to_pattern`, `to_type`, `scope_dirs`, `exclusions`) populated.
- [ ] `to_type` is one of `{file, folder, cli}`.
- [ ] `scope_dirs` is a non-empty list and every entry resolves to a real directory in the working tree.
- [ ] The orchestrator independently structurally verified the file (5 key-presence Greps + re-parse), not just trusted the Write exit code.
- [ ] `phase-record` was called for each of the 3 steps (`intent-confirmed`, `intent-written`, `intent-verified`).
- [ ] The Exit Gate `phase-complete` returned exit 0.
