<purpose>
Research how to implement a phase. Spawns gmd-phase-researcher with phase context.

Standalone research command. For most workflows, use `/gmd:plan-phase` which integrates research automatically.

**Two research tiers:**
- **Normal** (default): Standard web search, Context7, codebase analysis. Produces RESEARCH.md.
- **High** (`--high-research` flag): Adds NotebookLM notebook creation for deep synthesis. Produces RESEARCH.md + vault notes in Knowledge/Research-Notes/.

**Usage:**
- `/gmd:research-phase 3` — Normal research
- `/gmd:research-phase 3 --high-research` — Deep research with NotebookLM
</purpose>

<process>

## Step 0: Mode-Aware Path Resolution (v1.5.9 Parallel Milestone Organization)

Resolve organizational mode + active milestone slug ONCE; all subsequent path lookups route through `resolveMilestonePaths(mode, slug, artifact)`. Workflow consumes `active_milestone_slug` from init JSON — it does NOT parse `--milestone` itself (P3 thin-wrapper; flag parsed once at gmd-tools.cjs init dispatch entry per Plan 66-01).

```bash
INIT=$(node "$HOME/.claude/get-magic-done/bin/gmd-tools.cjs" init phase-op "${PHASE}" --raw)
MODE=$(echo "$INIT" | jq -r '.organizational_mode')
SLUG=$(echo "$INIT" | jq -r '.active_milestone_slug // empty')
NEEDS_PROMPT=$(echo "$INIT" | jq -r '.active_milestone_needs_prompt')
```

**Tier 4 prompt (parallel mode, no flag, no pointer, multiple/zero In Progress milestones):**

If `$NEEDS_PROMPT == "true"`:
- Read `.active_milestone_candidates` array from init JSON
- Invoke AskUserQuestion with the candidate list
- Persist selection: `node "$HOME/.claude/get-magic-done/bin/gmd-tools.cjs" state set-current-milestone "<chosen-slug>"`
- Re-run init to pick up the now-set slug (re-execute the INIT=$(...) block above)

**Path lookups (used throughout this workflow):**

```bash
REQS_PATH=$(node -e "const {resolveMilestonePaths}=require('$HOME/.claude/get-magic-done/bin/lib/path-resolve.js'); console.log(resolveMilestonePaths('$MODE', '$SLUG' || null, 'REQUIREMENTS'))")
ROADMAP_PATH=$(node -e "const {resolveMilestonePaths}=require('$HOME/.claude/get-magic-done/bin/lib/path-resolve.js'); console.log(resolveMilestonePaths('$MODE', '$SLUG' || null, 'ROADMAP'))")
STATE_PATH=$(node -e "const {resolveMilestonePaths}=require('$HOME/.claude/get-magic-done/bin/lib/path-resolve.js'); console.log(resolveMilestonePaths('$MODE', '$SLUG' || null, 'STATE'))")
PHASES_DIR=$(node -e "const {resolveMilestonePaths}=require('$HOME/.claude/get-magic-done/bin/lib/path-resolve.js'); console.log(resolveMilestonePaths('$MODE', '$SLUG' || null, 'phases-dir'))")
```

**Sequential mode:** `MODE=sequential, SLUG=null` → paths resolve to root `.planning/` (byte-identical to pre-v1.5.9 behavior per P1). No Tier 4 prompt fires.

**Parallel mode:** `MODE=parallel, SLUG=<active>` → paths route to `.planning/milestones/<slug>/`. If `--milestone <slug>` flag was passed at `/gmd:research-phase` invocation, it overrides the pointer (Tier 1; init.cjs handled this at flag-parse entry).

**Project-level paths stay literal** (root in BOTH modes per Phase 65 Decision O6-lean PROJECT_LEVEL_PATHS table): `.planning/PROJECT.md`, `.planning/MILESTONES.md`, `.planning/config.json`.

## Step 0.5: Resolve Model Profile

@C:/Users/Christopher/.claude/get-magic-done/references/model-profile-resolution.md

Resolve model for:
- `gmd-phase-researcher`

## Step 1: Normalize and Validate Phase

@C:/Users/Christopher/.claude/get-magic-done/references/phase-argument-parsing.md

```bash
PHASE_INFO=$(node "$HOME/.claude/get-magic-done/bin/gmd-tools.cjs" roadmap get-phase "${PHASE}")
```

If `found` is false: Error and exit.

## Step 2: Check Existing Research

```bash
# Mode-aware: ${PHASES_DIR} resolved at Step 0 to .planning/phases (sequential)
# or .planning/milestones/<slug>/phases (parallel).
ls "${PHASES_DIR}"/${PHASE}-*/RESEARCH.md 2>/dev/null
```

If exists: Offer update/view/skip options.

## Step 3: Gather Phase Context

```bash
INIT=$(node "$HOME/.claude/get-magic-done/bin/gmd-tools.cjs" init phase-op "${PHASE}")
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
# Extract: phase_dir, padded_phase, phase_number, state_path, requirements_path, context_path
```

## Step 3.5: Parse Flags

Extract `--high-research` flag from $ARGUMENTS.

**Profile check:** If model profile is 'budget' (from config.json), high research falls back to normal research even if the flag is set.

<step name="vault_preflight" priority="early">
Run `vault-orient` to pre-warm the 5-min query cache and build a compressed `<vault_context>` block for injection into every downstream Task() prompt. This is the D9b orchestrator-side default: vault-use as the default code path, not an opt-in. Component-gate-aware: skips silently when `components.obsidian.enabled: false`.

```bash
VAULT_ORIENT_RAW=$(node "$HOME/.claude/get-magic-done/bin/gmd-tools.cjs" vault-orient \
  --agent orchestrator-research-phase 2>/dev/null || echo '{"skipped":"vault unavailable"}')
```

**Compress orient JSON to a ~300-tok `<vault_context>` block:**

1. Parse the orient JSON. If `.skipped` is set OR the JSON contains an error field, set `VAULT_CONTEXT_BLOCK=""` (empty) and skip to step 3.
2. Otherwise, extract:
   - `index_summary` — cap at 1200 chars (append `…[truncated]` if longer)
   - `in_scope_notes[0..4]` — top 5 notes, emit `path + summary` only (no bodies)
   - `directives[*].summary` (or first-line fallback) — directive summaries only, no bodies
3. Build the block in this exact shape (omit entirely if compression produced nothing):

   ```
   <vault_context>
   ## Index Summary
   {index_summary}

   ## In-Scope Notes (top 5)
   - {path}: {summary}
   - ...

   ## Directives (summary only; re-read via vault-read if needed)
   - {path}: {summary}
   - ...

   vault_status: {ok | empty | error}
   </vault_context>
   ```

**Injection contract:** The `VAULT_CONTEXT_BLOCK` must be injected into every downstream Task() prompt immediately before the existing `<files_to_read>` block. When empty (skipped/error/empty orient), omit the block entirely — never inject an empty `<vault_context></vault_context>`. Cached orient means subsequent subagent `vault-query` calls hit the warm 5-min cache (~116ms cached vs ~1700ms uncached on Windows).
</step>

## Step 3.7: Budget Check (D14)

<step name="budget_check">
Before spawning the researcher subagent, estimate the vault token budget using the scope-sized heuristic wired in Plan 19-01.

**Inputs:**
- `TOPIC_COUNT` — distinct research topics derived from CONTEXT.md sections + REQUIREMENTS.md categories for this phase. Count unique category/topic identifiers from both files. Default to 1 if neither file is available (single implicit topic).
- `REQ_COUNT` — number of phase requirements (from `phase_req_ids` in INIT JSON or from REQUIREMENTS.md traceability). Default to 0 when no requirements mapped.

**Run budget estimation:**

```bash
BUDGET_ESTIMATE=$(node "$HOME/.claude/get-magic-done/bin/gmd-tools.cjs" vault-budget estimate \
  --orchestrator researcher \
  --topic-count "${TOPIC_COUNT}" \
  --req-count "${REQ_COUNT}" 2>/dev/null || echo '{"error":"budget estimation failed"}')
```

Budget formula (from D14): `5000 + 3000 × research_topic_count + 1000 × req_count`. Ceiling for researcher: 40K.

**Branching:**

1. **If estimate exceeds 40K ceiling** (`partition: true` in output):
   - Auto-partition into subagents — one per distinct research topic.
   - Each subagent receives the `<vault_context>` block + its topic scope.
   - Main session composes the final RESEARCH.md from subagent synthesis only (AGENT-03 context discipline).
   - Log structured event:
     ```
     {"event":"budget_exceeded","orchestrator":"gmd-phase-researcher","estimated":<N>,"budget":40000,"partitioned_into":<K>}
     ```
   - Stamp final artifact frontmatter:
     ```yaml
     partitioned: true
     subagent_count: <K>
     ```

2. **If estimate is under ceiling** (`partition: false`):
   - Single researcher agent runs normally (current behavior; continue to Step 4).

3. **If budget estimation fails** (vault-budget returned error, or `.error` field set):
   - Proceed with single-agent mode. Do NOT block the workflow.
   - Log: `{"event":"budget_estimation_failed","orchestrator":"gmd-phase-researcher","fallback":"single-agent"}`
</step>

## Step 4: Spawn Researcher

```
Task(
  prompt="<objective>
Research implementation approach for Phase {phase}: {name}
</objective>

{VAULT_CONTEXT_BLOCK}

<files_to_read>
- {context_path} (USER DECISIONS from /gmd:discuss-phase)
- {requirements_path} (Project requirements)
- {state_path} (Project decisions and history)
</files_to_read>

<additional_context>
Phase description: {description}

**Research tier:** {normal | high-research}
If high-research: Use NotebookLM integration for deep synthesis (see high-research tier in agent definition)
</additional_context>

<output>
Write to: ${PHASES_DIR}/${PHASE}-{slug}/${PHASE}-RESEARCH.md
</output>",
  subagent_type="gmd-phase-researcher",
  model="{researcher_model}"
)
```

## Step 5: Handle Return

- `## RESEARCH COMPLETE` — Display summary, offer: Plan/Dig deeper/Review/Done
- `## CHECKPOINT REACHED` — Present to user, spawn continuation
- `## RESEARCH INCONCLUSIVE` — Show attempts, offer: Add context/Try different mode/Manual

## Step 6: Vault Sync

After RESEARCH.md is written, sync to Obsidian vault:

```bash
node bin/gmd-tools.cjs vault-sync "${PHASES_DIR}/${PHASE}-{slug}/${PHASE}-RESEARCH.md" 2>/dev/null
```

Graceful if vault not configured (skip with note).

</process>
