# Phase 7: Issue Export

Map specification Epics to issues, create them via `ccw issue create`, and generate an export report with spec document links.

> **Execution Mode: Inline**
> This phase runs in the main orchestrator context (not delegated to agent) for direct access to `ccw issue create` CLI and interactive handoff options.

## Objective

- Read all EPIC-*.md files from Phase 5 output
- Assign waves: MVP epics → wave-1, non-MVP → wave-2
- Create one issue per Epic via `ccw issue create`
- Map Epic dependencies to issue dependencies
- Generate issue-export-report.md with mapping table and spec links
- Present handoff options for execution

## Input

- Dependency: `{workDir}/epics/_index.md` (and individual `EPIC-*.md` files)
- Reference: `{workDir}/readiness-report.md`, `{workDir}/spec-config.json`
- Reference: `{workDir}/product-brief.md`, `{workDir}/requirements/_index.md`, `{workDir}/architecture/_index.md`

## Execution Steps

### Step 1: Load Epic Files

```javascript
const specConfig = JSON.parse(Read(`${workDir}/spec-config.json`));
const epicFiles = Glob(`${workDir}/epics/EPIC-*.md`);
const epicsIndex = Read(`${workDir}/epics/_index.md`);

// Parse each Epic file
const epics = epicFiles.map(epicFile => {
  const content = Read(epicFile);
  const fm = parseFrontmatter(content);
  const title = extractTitle(content);
  const description = extractSection(content, "Description");
  const stories = extractSection(content, "Stories");
  const reqRefs = extractSection(content, "Requirements");
  const adrRefs = extractSection(content, "Architecture");
  const deps = fm.dependencies || [];

  return {
    file: epicFile,
    id: fm.id,           // e.g., EPIC-001
    title,
    description,
    stories,
    reqRefs,
    adrRefs,
    priority: fm.priority,
    mvp: fm.mvp || false,
    dependencies: deps,   // other EPIC IDs this depends on
    size: fm.size
  };
});
```

### Step 2: Wave Assignment

```javascript
const epicWaves = epics.map(epic => ({
  ...epic,
  wave: epic.mvp ? 1 : 2
}));

// Log wave assignment
const wave1 = epicWaves.filter(e => e.wave === 1);
const wave2 = epicWaves.filter(e => e.wave === 2);
// wave-1: MVP epics (must-have, core functionality)
// wave-2: Post-MVP epics (should-have, enhancements)
```

### Step 3: Issue Creation Loop

```javascript
const createdIssues = [];
const epicToIssue = {};  // EPIC-ID -> Issue ID mapping

for (const epic of epicWaves) {
  // Build issue JSON matching roadmap-with-file schema
  const issueData = {
    title: `[${specConfig.session_id}] ${epic.title}`,
    status: "pending",
    priority: epic.wave === 1 ? 2 : 3,  // wave-1 = higher priority
    context: `## ${epic.title}

${epic.description}

## Stories
${epic.stories}

## Spec References
- Epic: ${epic.file}
- Requirements: ${epic.reqRefs}
- Architecture: ${epic.adrRefs}
- Product Brief: ${workDir}/product-brief.md
- Full Spec: ${workDir}/`,
    source: "text",
    tags: [
      "spec-generated",
      `spec:${specConfig.session_id}`,
      `wave-${epic.wave}`,
      epic.mvp ? "mvp" : "post-mvp",
      `epic:${epic.id}`
    ],
    extended_context: {
      notes: {
        session: specConfig.session_id,
        spec_dir: workDir,
        source_epic: epic.id,
        wave: epic.wave,
        depends_on_issues: [],  // Filled in Step 4
        spec_documents: {
          product_brief: `${workDir}/product-brief.md`,
          requirements: `${workDir}/requirements/_index.md`,
          architecture: `${workDir}/architecture/_index.md`,
          epic: epic.file
        }
      }
    },
    lifecycle_requirements: {
      test_strategy: "acceptance",
      regression_scope: "affected",
      acceptance_type: "manual",
      commit_strategy: "per-epic"
    }
  };

  // Create issue via ccw issue create (pipe JSON to avoid shell escaping)
  const result = Bash(`echo '${JSON.stringify(issueData)}' | ccw issue create`);

  // Parse returned issue ID
  const issueId = JSON.parse(result).id;  // e.g., ISS-20260308-001
  epicToIssue[epic.id] = issueId;

  createdIssues.push({
    epic_id: epic.id,
    epic_title: epic.title,
    issue_id: issueId,
    wave: epic.wave,
    priority: issueData.priority,
    mvp: epic.mvp
  });
}
```

### Step 4: Epic Dependency → Issue Dependency Mapping

```javascript
// Map EPIC dependencies to Issue dependencies
for (const epic of epicWaves) {
  if (epic.dependencies.length === 0) continue;

  const issueId = epicToIssue[epic.id];
  const depIssueIds = epic.dependencies
    .map(depEpicId => epicToIssue[depEpicId])
    .filter(Boolean);

  if (depIssueIds.length > 0) {
    // Update issue's extended_context.notes.depends_on_issues
    // This is informational — actual dependency enforcement is in execution phase
    // Note: ccw issue create already created the issue; dependency info is in the context
  }
}
```

### Step 5: Generate issue-export-report.md

```javascript
const timestamp = new Date().toISOString();

const reportContent = `---
session_id: ${specConfig.session_id}
phase: 7
document_type: issue-export-report
status: complete
generated_at: ${timestamp}
stepsCompleted: ["load-epics", "wave-assignment", "issue-creation", "dependency-mapping", "report-generation"]
version: 1
dependencies:
  - epics/_index.md
  - readiness-report.md
---

# Issue Export Report

## Summary

- **Session**: ${specConfig.session_id}
- **Issues Created**: ${createdIssues.length}
- **Wave 1 (MVP)**: ${wave1.length} issues
- **Wave 2 (Post-MVP)**: ${wave2.length} issues
- **Export Date**: ${timestamp}

## Issue Mapping

| Epic ID | Epic Title | Issue ID | Wave | Priority | MVP |
|---------|-----------|----------|------|----------|-----|
${createdIssues.map(i =>
  `| ${i.epic_id} | ${i.epic_title} | ${i.issue_id} | ${i.wave} | ${i.priority} | ${i.mvp ? 'Yes' : 'No'} |`
).join('\n')}

## Spec Document Links

| Document | Path | Description |
|----------|------|-------------|
| Product Brief | ${workDir}/product-brief.md | Vision, goals, scope |
| Requirements | ${workDir}/requirements/_index.md | Functional + non-functional requirements |
| Architecture | ${workDir}/architecture/_index.md | Components, ADRs, tech stack |
| Epics | ${workDir}/epics/_index.md | Epic/Story breakdown |
| Readiness Report | ${workDir}/readiness-report.md | Quality validation |
| Spec Summary | ${workDir}/spec-summary.md | Executive summary |

## Dependency Map

| Issue ID | Depends On |
|----------|-----------|
${createdIssues.map(i => {
  const epic = epicWaves.find(e => e.id === i.epic_id);
  const deps = (epic.dependencies || []).map(d => epicToIssue[d]).filter(Boolean);
  return `| ${i.issue_id} | ${deps.length > 0 ? deps.join(', ') : 'None'} |`;
}).join('\n')}

## Next Steps

1. **team-planex**: Execute all issues via coordinated team workflow
2. **Wave 1 only**: Execute MVP issues first (${wave1.length} issues)
3. **View issues**: Browse created issues via \`ccw issue list --tag spec:${specConfig.session_id}\`
4. **Manual review**: Review individual issues before execution
`;

Write(`${workDir}/issue-export-report.md`, reportContent);
```

### Step 6: Update spec-config.json

```javascript
specConfig.issue_ids = createdIssues.map(i => i.issue_id);
specConfig.issues_created = createdIssues.length;
specConfig.phasesCompleted.push({
  phase: 7,
  name: "issue-export",
  output_file: "issue-export-report.md",
  issues_created: createdIssues.length,
  wave_1_count: wave1.length,
  wave_2_count: wave2.length,
  completed_at: timestamp
});
Write(`${workDir}/spec-config.json`, JSON.stringify(specConfig, null, 2));
```

### Step 7: Handoff Options

```javascript
AskUserQuestion({
  questions: [
    {
      question: `${createdIssues.length} issues created from ${epicWaves.length} Epics. What would you like to do next?`,
      header: "Next Step",
      multiSelect: false,
      options: [
        {
          label: "Execute via team-planex",
          description: `Execute all ${createdIssues.length} issues with coordinated team workflow`
        },
        {
          label: "Wave 1 only",
          description: `Execute ${wave1.length} MVP issues first`
        },
        {
          label: "View issues",
          description: "Browse created issues before deciding"
        },
        {
          label: "Done",
          description: "Export complete, handle manually"
        }
      ]
    }
  ]
});

// Based on user selection:
if (selection === "Execute via team-planex") {
  const issueIds = createdIssues.map(i => i.issue_id).join(',');
  Skill({ skill: "team-planex", args: `--issues ${issueIds}` });
}

if (selection === "Wave 1 only") {
  const wave1Ids = createdIssues.filter(i => i.wave === 1).map(i => i.issue_id).join(',');
  Skill({ skill: "team-planex", args: `--issues ${wave1Ids}` });
}

if (selection === "View issues") {
  Bash(`ccw issue list --tag spec:${specConfig.session_id}`);
}
```

## Output

- **File**: `issue-export-report.md` — Issue mapping table + spec links + next steps
- **Updated**: `.workflow/issues/issues.jsonl` — New issue entries appended
- **Updated**: `spec-config.json` — Phase 7 completion + issue IDs

## Quality Checklist

- [ ] All MVP Epics have corresponding issues created
- [ ] All non-MVP Epics have corresponding issues created
- [ ] Issue tags include `spec-generated` and `spec:{session_id}`
- [ ] Issue `extended_context.notes.spec_documents` paths are correct
- [ ] Wave assignment matches MVP status (MVP → wave-1, non-MVP → wave-2)
- [ ] Epic dependencies mapped to issue dependency references
- [ ] `issue-export-report.md` generated with mapping table
- [ ] `spec-config.json` updated with `issue_ids` and `issues_created`
- [ ] Handoff options presented

## Error Handling

| Error | Blocking? | Action |
|-------|-----------|--------|
| `ccw issue create` fails for one Epic | No | Log error, continue with remaining Epics, report partial creation |
| No EPIC files found | Yes | Error and return to Phase 5 |
| All issue creations fail | Yes | Error with CLI diagnostic, suggest manual creation |
| Dependency EPIC not found in mapping | No | Skip dependency link, log warning |

## Completion

Phase 7 is the final phase. The specification package has been fully converted to executable issues ready for team-planex or manual execution.
