# Analyze Task Generation & Execution Spec

> **Purpose**: Quality standards for task generation + execution specification for Phase 5 of `analyze-with-file`.
> **Consumer**: Phase 5 of `analyze-with-file` workflow.
> **Scope**: Task generation quality + direct inline execution.

---

## Task Generation Flow

> **Entry point**: Routed here from SKILL.md Phase 5 when complexity is `complex` (≥3 recommendations or high-priority with dependencies).

```
Step 1: Load context → Step 2: Generate .task/*.json → Step 3: Pre-execution analysis
    → Step 4: User confirmation → Step 5: Serial execution → Step 6: Finalize
```

**Input artifacts** (all from session folder):

| Artifact | Required | Provides |
|----------|----------|----------|
| `conclusions.json` | Yes | `recommendations[]` with action, rationale, priority, evidence_refs |
| `exploration-codebase.json` | No | `relevant_files[]`, `patterns[]`, `constraints[]`, `integration_points[]` — primary source for file resolution |
| `explorations.json` | No | `sources[]`, `key_findings[]` — fallback for file resolution |
| `perspectives.json` | No | Multi-perspective findings — alternative to explorations.json |

---

## File Resolution Algorithm

Target files are resolved with a 3-priority fallback chain. Recommendations carry only `evidence_refs` — file resolution is EXECUTE.md's responsibility:

```javascript
function resolveTargetFiles(rec, codebaseContext, explorations) {
  // Priority 1: Extract file paths from evidence_refs (e.g., "src/auth/token.ts:89")
  if (rec.evidence_refs?.length) {
    const filePaths = [...new Set(
      rec.evidence_refs
        .filter(ref => ref.includes('/') || ref.includes('.'))
        .map(ref => ref.split(':')[0])
    )]
    if (filePaths.length) {
      return filePaths.map(path => ({
        path,
        action: 'modify',
        target: null,
        changes: []
      }))
    }
  }

  // Priority 2: Match from exploration-codebase.json relevant_files
  if (codebaseContext?.relevant_files?.length) {
    const keywords = extractKeywords(rec.action + ' ' + rec.rationale)
    const matched = codebaseContext.relevant_files.filter(f =>
      keywords.some(kw =>
        f.path.toLowerCase().includes(kw) ||
        f.summary?.toLowerCase().includes(kw) ||
        f.relevance?.toLowerCase().includes(kw)
      )
    )
    if (matched.length) {
      return matched.map(f => ({
        path: f.path,
        action: 'modify',
        target: null,
        changes: rec.changes || []
      }))
    }
  }

  // Priority 3: Match from explorations.json sources
  if (explorations?.sources?.length) {
    const actionVerb = rec.action.split(' ')[0].toLowerCase()
    const matched = explorations.sources.filter(s =>
      s.summary?.toLowerCase().includes(actionVerb) ||
      s.file?.includes(actionVerb)
    )
    if (matched.length) {
      return matched.map(s => ({
        path: s.file,
        action: 'modify',
        target: null,
        changes: []
      }))
    }
  }

  // Fallback: empty array — task relies on description + implementation for guidance
  return []
}

function extractKeywords(text) {
  return text
    .toLowerCase()
    .replace(/[^a-z0-9\u4e00-\u9fa5\s]/g, ' ')
    .split(/\s+/)
    .filter(w => w.length > 2)
    .filter(w => !['the', 'and', 'for', 'with', 'from', 'that', 'this'].includes(w))
}
```

---

## Task Type Inference

| Recommendation Pattern | Inferred Type |
|------------------------|---------------|
| fix, resolve, repair, patch, correct | `fix` |
| refactor, restructure, extract, reorganize, decouple | `refactor` |
| add, implement, create, build, introduce | `feature` |
| improve, optimize, enhance, upgrade, streamline | `enhancement` |
| test, coverage, validate, verify, assert | `testing` |

```javascript
function inferTaskType(rec) {
  const text = (rec.action + ' ' + rec.rationale).toLowerCase()
  const patterns = [
    { type: 'fix',         keywords: ['fix', 'resolve', 'repair', 'patch', 'correct', 'bug'] },
    { type: 'refactor',    keywords: ['refactor', 'restructure', 'extract', 'reorganize', 'decouple'] },
    { type: 'feature',     keywords: ['add', 'implement', 'create', 'build', 'introduce'] },
    { type: 'enhancement', keywords: ['improve', 'optimize', 'enhance', 'upgrade', 'streamline'] },
    { type: 'testing',     keywords: ['test', 'coverage', 'validate', 'verify', 'assert'] }
  ]
  for (const p of patterns) {
    if (p.keywords.some(kw => text.includes(kw))) return p.type
  }
  return 'enhancement'  // safe default
}
```

## Effort Inference

| Signal | Effort |
|--------|--------|
| priority=high AND files >= 3 | `large` |
| priority=high OR files=2 | `medium` |
| priority=medium AND files <= 1 | `medium` |
| priority=low OR single file | `small` |

```javascript
function inferEffort(rec, targetFiles) {
  const fileCount = targetFiles?.length || 0
  if (rec.priority === 'high' && fileCount >= 3) return 'large'
  if (rec.priority === 'high' || fileCount >= 2) return 'medium'
  if (rec.priority === 'low' || fileCount <= 1) return 'small'
  return 'medium'
}
```

---

## Convergence Quality Validation

Every task's `convergence` MUST pass quality gates before writing to disk.

### Quality Rules

| Field | Requirement | Validation |
|-------|-------------|------------|
| `criteria[]` | **Testable** — assertions or concrete manual steps | Reject vague patterns; each criterion must reference observable behavior |
| `verification` | **Executable** — shell command or explicit step sequence | Must contain a runnable command or step-by-step verification procedure |
| `definition_of_done` | **Business language** — non-technical stakeholder can judge | Must NOT contain technical commands (jest, tsc, npm, build) |

### Vague Pattern Detection

```javascript
const VAGUE_PATTERNS = /正常|正确|好|可以|没问题|works|fine|good|correct|properly|as expected/i
const TECHNICAL_IN_DOD = /compile|build|lint|npm|npx|jest|tsc|eslint|cargo|pytest|go test/i

function validateConvergenceQuality(tasks) {
  const issues = []
  tasks.forEach(task => {
    // Rule 1: No vague criteria
    task.convergence.criteria.forEach((c, i) => {
      if (VAGUE_PATTERNS.test(c) && c.length < 20) {
        issues.push({
          task: task.id, field: `criteria[${i}]`,
          problem: 'Vague criterion', value: c,
          fix: 'Replace with specific observable condition from evidence'
        })
      }
    })

    // Rule 2: Verification should be executable
    if (task.convergence.verification && task.convergence.verification.length < 5) {
      issues.push({
        task: task.id, field: 'verification',
        problem: 'Too short to be executable', value: task.convergence.verification,
        fix: 'Provide shell command or numbered step sequence'
      })
    }

    // Rule 3: DoD should be business language
    if (TECHNICAL_IN_DOD.test(task.convergence.definition_of_done)) {
      issues.push({
        task: task.id, field: 'definition_of_done',
        problem: 'Contains technical commands', value: task.convergence.definition_of_done,
        fix: 'Rewrite in business language describing user/system outcome'
      })
    }

    // Rule 4: files[].changes should not be empty when files exist
    task.files?.forEach((f, i) => {
      if (f.action === 'modify' && (!f.changes || f.changes.length === 0) && !f.change) {
        issues.push({
          task: task.id, field: `files[${i}].changes`,
          problem: 'No change description for modify action', value: f.path,
          fix: 'Describe what specifically changes in this file'
        })
      }
    })

    // Rule 5: implementation steps should exist
    if (!task.implementation || task.implementation.length === 0) {
      issues.push({
        task: task.id, field: 'implementation',
        problem: 'No implementation steps',
        fix: 'Add at least one step describing how to realize this task'
      })
    }
  })

  // Auto-fix where possible, log remaining issues
  issues.forEach(issue => {
    // Attempt auto-fix based on available evidence
    // If unfixable, log warning — task still generated but flagged
  })
  return issues
}
```

### Good vs Bad Examples

**Criteria**:

| Bad | Good |
|-----|------|
| `"Code works correctly"` | `"refreshToken() returns a new JWT with >0 expiry when called with expired token"` |
| `"No errors"` | `"Error handler at auth.ts:45 returns 401 status with { error: 'token_expired' } body"` |
| `"Performance is good"` | `"API response time < 200ms at p95 for /api/users endpoint under 100 concurrent requests"` |

**Verification**:

| Bad | Good |
|-----|------|
| `"Check it"` | `"jest --testPathPattern=auth.test.ts && npx tsc --noEmit"` |
| `"Run tests"` | `"1. Run npm test -- --grep 'token refresh' 2. Verify no TypeScript errors with npx tsc --noEmit"` |

**Definition of Done**:

| Bad | Good |
|-----|------|
| `"jest passes"` | `"Users remain logged in across token expiration without manual re-login"` |
| `"No TypeScript errors"` | `"Authentication flow handles all user-facing error scenarios with clear error messages"` |

---

## Required Task Fields (analyze-with-file producer)

SKILL.md produces minimal recommendations `{action, rationale, priority, evidence_refs}`. EXECUTE.md enriches these into full task JSON. The final `.task/*.json` MUST populate:

| Block | Fields | Required |
|-------|--------|----------|
| IDENTITY | `id`, `title`, `description` | Yes |
| CLASSIFICATION | `type`, `priority`, `effort` | Yes |
| DEPENDENCIES | `depends_on` | Yes (empty array if none) |
| CONVERGENCE | `convergence.criteria[]`, `convergence.verification`, `convergence.definition_of_done` | Yes |
| FILES | `files[].path`, `files[].action`, `files[].changes`/`files[].change` | Yes (if files identified) |
| IMPLEMENTATION | `implementation[]` with step + description | Yes |
| CONTEXT | `evidence`, `source.tool`, `source.session_id`, `source.original_id` | Yes |

### Task JSON Example

```json
{
  "id": "TASK-001",
  "title": "Fix authentication token refresh",
  "description": "Token refresh fails silently when JWT expires, causing users to be logged out unexpectedly",
  "type": "fix",
  "priority": "high",
  "effort": "medium",
  "files": [
    {
      "path": "src/auth/token.ts",
      "action": "modify",
      "target": "refreshToken",
      "changes": [
        "Add await to refreshToken() call at line 89",
        "Add error propagation for refresh failure"
      ],
      "change": "Add await to refreshToken() call and propagate errors"
    },
    {
      "path": "src/middleware/auth.ts",
      "action": "modify",
      "target": "authMiddleware",
      "changes": [
        "Update error handler at line 45 to distinguish refresh failures from auth failures"
      ],
      "change": "Update error handler to propagate refresh failures"
    }
  ],
  "depends_on": [],
  "convergence": {
    "criteria": [
      "refreshToken() returns new valid JWT when called with expired token",
      "Expired token triggers automatic refresh without user action",
      "Failed refresh returns 401 with { error: 'token_expired' } body"
    ],
    "verification": "jest --testPathPattern=token.test.ts && npx tsc --noEmit",
    "definition_of_done": "Users remain logged in across token expiration without manual re-login"
  },
  "implementation": [
    {
      "step": "1",
      "description": "Add await to refreshToken() call in token.ts",
      "actions": ["Read token.ts", "Add await keyword at line 89", "Verify async chain"]
    },
    {
      "step": "2",
      "description": "Update error handler in auth middleware",
      "actions": ["Read auth.ts", "Modify error handler at line 45", "Add refresh-specific error type"]
    }
  ],
  "evidence": ["src/auth/token.ts:89", "src/middleware/auth.ts:45"],
  "source": {
    "tool": "analyze-with-file",
    "session_id": "ANL-auth-token-refresh-2025-01-21",
    "original_id": "TASK-001"
  }
}
```

---

## Step 1: Load All Context Sources

Phase 2-4 already loaded and processed these artifacts. If data is still in conversation memory, skip disk reads.

```javascript
// Skip loading if already in memory from Phase 2-4
// Only read from disk when entering EXECUTE.md from a fresh/resumed session

if (!conclusions) {
  conclusions = JSON.parse(Read(`${sessionFolder}/conclusions.json`))
}

if (!codebaseContext) {
  codebaseContext = file_exists(`${sessionFolder}/exploration-codebase.json`)
    ? JSON.parse(Read(`${sessionFolder}/exploration-codebase.json`))
    : null
}

if (!explorations) {
  explorations = file_exists(`${sessionFolder}/explorations.json`)
    ? JSON.parse(Read(`${sessionFolder}/explorations.json`))
    : file_exists(`${sessionFolder}/perspectives.json`)
      ? JSON.parse(Read(`${sessionFolder}/perspectives.json`))
      : null
}
```

## Step 2: Enrich Recommendations & Generate .task/*.json

SKILL.md Phase 4 produces minimal recommendations: `{action, rationale, priority, evidence_refs}`.
This step enriches each recommendation with execution-specific details using codebase context, then generates individual task JSON files.

**Enrichment pipeline**: `rec (minimal) + codebaseContext + explorations → task JSON (full)`

```javascript
const tasks = conclusions.recommendations.map((rec, index) => {
  const taskId = `TASK-${String(index + 1).padStart(3, '0')}`

  // 1. ENRICH: Resolve target files from codebase context (not from rec)
  const targetFiles = resolveTargetFiles(rec, codebaseContext, explorations)

  // 2. ENRICH: Generate implementation steps from action + context
  const implSteps = generateImplementationSteps(rec, targetFiles, codebaseContext)

  // 3. ENRICH: Derive change descriptions per file
  const enrichedFiles = targetFiles.map(f => ({
    path: f.path,
    action: f.action || 'modify',
    target: f.target || null,
    changes: deriveChanges(rec, f, codebaseContext) || [],
    change: rec.action
  }))

  return {
    id: taskId,
    title: rec.action,
    description: rec.rationale,
    type: inferTaskType(rec),
    priority: rec.priority,
    effort: inferEffort(rec, targetFiles),

    files: enrichedFiles,
    depends_on: [],

    // CONVERGENCE (must pass quality validation)
    convergence: {
      criteria: generateCriteria(rec),
      verification: generateVerification(rec),
      definition_of_done: generateDoD(rec)
    },

    // IMPLEMENTATION steps (generated here, not from SKILL.md)
    implementation: implSteps,

    // CONTEXT
    evidence: rec.evidence_refs || [],
    source: {
      tool: 'analyze-with-file',
      session_id: sessionId,
      original_id: taskId
    }
  }
})

// Quality validation
validateConvergenceQuality(tasks)

// Write each task as individual JSON file
Bash(`mkdir -p ${sessionFolder}/.task`)
tasks.forEach(task => {
  Write(`${sessionFolder}/.task/${task.id}.json`, JSON.stringify(task, null, 2))
})
```

**Enrichment Functions**:

```javascript
// Generate implementation steps from action + resolved files
function generateImplementationSteps(rec, targetFiles, codebaseContext) {
  // 1. Parse rec.action into atomic steps
  // 2. Map steps to target files
  // 3. Add context from codebaseContext.patterns if applicable
  // Return: [{step: '1', description: '...', actions: [...]}]
  return [{
    step: '1',
    description: rec.action,
    actions: targetFiles.map(f => `Modify ${f.path}`)
  }]
}

// Derive specific change descriptions for a file
function deriveChanges(rec, file, codebaseContext) {
  // 1. Match rec.action keywords to file content patterns
  // 2. Use codebaseContext.patterns for context-aware change descriptions
  // 3. Use rec.evidence_refs to locate specific modification points
  // Return: ['specific change 1', 'specific change 2']
  return [rec.action]
}
```

## Step 3-6: Execution Steps

After `.task/*.json` generation, validate and execute tasks directly inline.

### Step 3: Pre-Execution Analysis

```javascript
const taskFiles = Glob(`${sessionFolder}/.task/*.json`)
const tasks = taskFiles.map(f => JSON.parse(Read(f)))

// 1. Dependency validation
const taskIds = new Set(tasks.map(t => t.id))
const errors = []
tasks.forEach(task => {
  task.depends_on.forEach(dep => {
    if (!taskIds.has(dep)) errors.push(`${task.id}: depends on unknown task ${dep}`)
  })
})

// 2. Circular dependency detection (DFS)
function detectCycles(tasks) {
  const graph = new Map(tasks.map(t => [t.id, t.depends_on]))
  const visited = new Set(), inStack = new Set(), cycles = []
  function dfs(node, path) {
    if (inStack.has(node)) { cycles.push([...path, node].join(' → ')); return }
    if (visited.has(node)) return
    visited.add(node); inStack.add(node)
    ;(graph.get(node) || []).forEach(dep => dfs(dep, [...path, node]))
    inStack.delete(node)
  }
  tasks.forEach(t => { if (!visited.has(t.id)) dfs(t.id, []) })
  return cycles
}

// 3. Topological sort for execution order
function topoSort(tasks) {
  const inDegree = new Map(tasks.map(t => [t.id, 0]))
  tasks.forEach(t => t.depends_on.forEach(dep => {
    inDegree.set(t.id, inDegree.get(t.id) + 1)
  }))
  const queue = tasks.filter(t => inDegree.get(t.id) === 0).map(t => t.id)
  const order = []
  while (queue.length) {
    const id = queue.shift()
    order.push(id)
    tasks.forEach(t => {
      if (t.depends_on.includes(id)) {
        inDegree.set(t.id, inDegree.get(t.id) - 1)
        if (inDegree.get(t.id) === 0) queue.push(t.id)
      }
    })
  }
  return order
}

// 4. File conflict detection
const fileTaskMap = new Map()
tasks.forEach(task => {
  (task.files || []).forEach(f => {
    if (!fileTaskMap.has(f.path)) fileTaskMap.set(f.path, [])
    fileTaskMap.get(f.path).push(task.id)
  })
})
const conflicts = []
fileTaskMap.forEach((taskIds, file) => {
  if (taskIds.length > 1) conflicts.push({ file, tasks: taskIds })
})
```

### Step 4: Initialize Execution Artifacts

```javascript
// execution.md — overview with task table
const executionMd = `# Execution Overview

## Session Info
- **Session ID**: ${sessionId}
- **Plan Source**: .task/*.json (from analysis conclusions)
- **Started**: ${getUtc8ISOString()}
- **Total Tasks**: ${tasks.length}

## Task Overview

| # | ID | Title | Type | Priority | Status |
|---|-----|-------|------|----------|--------|
${tasks.map((t, i) => `| ${i+1} | ${t.id} | ${t.title} | ${t.type} | ${t.priority} | pending |`).join('\n')}

## Pre-Execution Analysis
${conflicts.length
  ? `### File Conflicts\n${conflicts.map(c => `- **${c.file}**: ${c.tasks.join(', ')}`).join('\n')}`
  : 'No file conflicts detected.'}

## Execution Timeline
> Updated as tasks complete
`
Write(`${sessionFolder}/execution.md`, executionMd)

// execution-events.md — chronological event log
Write(`${sessionFolder}/execution-events.md`,
  `# Execution Events\n\n**Session**: ${sessionId}\n**Started**: ${getUtc8ISOString()}\n\n---\n\n`)
```

### Step 5: Task Execution Loop

**User Confirmation** before execution:

```javascript
if (!autoYes) {
  const action = AskUserQuestion({
    questions: [{
      question: `Execute ${tasks.length} tasks?\n${tasks.map(t => `  ${t.id}: ${t.title} (${t.priority})`).join('\n')}`,
      header: "Confirm",
      multiSelect: false,
      options: [
        { label: "Start", description: "Execute all tasks serially" },
        { label: "Adjust", description: "Modify .task/*.json before execution" },
        { label: "Skip", description: "Keep .task/*.json, skip execution" }
      ]
    }]
  })
  // "Adjust": user edits task files, then resumes
  // "Skip": end — user can execute later separately
}
```

Execute tasks serially using `task.implementation` steps and `task.files[].changes` as guidance.

```
For each taskId in executionOrder:
  ├─ Load task from .task/{taskId}.json
  ├─ Check dependencies satisfied
  ├─ Record START event → execution-events.md
  ├─ Execute using task.implementation + task.files[].changes:
  │   ├─ Read target files listed in task.files[]
  │   ├─ Apply modifications described in files[].changes / files[].change
  │   ├─ Follow implementation[].actions sequence
  │   └─ Use Edit (preferred), Write (new files), Bash (build/test)
  ├─ Verify convergence:
  │   ├─ Check each convergence.criteria[] item
  │   ├─ Run convergence.verification (if executable command)
  │   └─ Record verification results
  ├─ Record COMPLETE/FAIL event → execution-events.md
  ├─ Update execution.md task status
  └─ Continue to next task
```

**Execution Guidance Priority** — what the AI follows when executing each task:

| Priority | Source | Example |
|----------|--------|---------|
| 1 | `files[].changes` / `files[].change` | "Add await to refreshToken() call at line 89" |
| 2 | `implementation[].actions` | ["Read token.ts", "Add await keyword at line 89"] |
| 3 | `implementation[].description` | "Add await to refreshToken() call in token.ts" |
| 4 | `task.description` | "Token refresh fails silently..." |

When `files[].changes` is populated, the AI has concrete instructions. When empty, it falls back to `implementation` steps, then to `description`.

### Step 5.1: Failure Handling

```javascript
// On task failure, ask user how to proceed
if (!autoYes) {
  AskUserQuestion({
    questions: [{
      question: `Task ${task.id} failed: ${errorMessage}\nHow to proceed?`,
      header: "Failure",
      multiSelect: false,
      options: [
        { label: "Skip & Continue", description: "Skip this task, continue with next" },
        { label: "Retry", description: "Retry this task" },
        { label: "Abort", description: "Stop execution, keep progress" }
      ]
    }]
  })
}
```

### Step 6: Finalize

After all tasks complete:

1. Append execution summary to `execution.md` (statistics, task results table)
2. Append session footer to `execution-events.md`
3. Write back `_execution` state to each `.task/*.json`:

```javascript
tasks.forEach(task => {
  const updated = {
    ...task,
    status: task._status,           // "completed" | "failed" | "skipped"
    executed_at: task._executed_at,
    result: {
      success: task._status === 'completed',
      files_modified: task._result?.files_modified || [],
      summary: task._result?.summary || '',
      error: task._result?.error || null,
      convergence_verified: task._result?.convergence_verified || []
    }
  }
  Write(`${sessionFolder}/.task/${task.id}.json`, JSON.stringify(updated, null, 2))
})
```

### Step 6.1: Post-Execution Options

```javascript
if (!autoYes) {
  AskUserQuestion({
    questions: [{
      question: `Execution complete: ${completedTasks.size}/${tasks.length} succeeded. Next:`,
      header: "Post-Execute",
      multiSelect: false,
      options: [
        { label: "Retry Failed", description: `Re-execute ${failedTasks.size} failed tasks` },
        { label: "View Events", description: "Display execution-events.md" },
        { label: "Create Issue", description: "Create issue from failed tasks" },
        { label: "Done", description: "End workflow" }
      ]
    }]
  })
}
```

---

## Output Structure

```
{sessionFolder}/
├── .task/                     # Individual task JSON files (with _execution state after completion)
│   ├── TASK-001.json
│   └── ...
├── execution.md               # Execution overview + task table + summary
└── execution-events.md        # Chronological event log
```

## execution-events.md Event Format

```markdown
## {timestamp} — {task.id}: {task.title}

**Type**: {task.type} | **Priority**: {task.priority}
**Status**: IN PROGRESS
**Files**: {task.files[].path}

### Execution Log
- Read {file} ({lines} lines)
- Applied: {change description}
- ...

**Status**: COMPLETED / FAILED
**Files Modified**: {list}

#### Convergence Verification
- [x/] {criterion 1}
- [x/] {criterion 2}
- **Verification**: {command} → PASS/FAIL

---
```
