---
id: TASK-INT-002
title: Implement insight extraction service
task_type: feature
parent_review: TASK-REV-A880
feature_id: FEAT-INT-001
wave: 2
implementation_mode: task-work
complexity: 5
dependencies:
- TASK-INT-001
status: in_review
priority: high
tags:
- insight-extraction
- service
- chunking
- prompt-engineering
consumer_context:
- task: TASK-INT-001
  consumes: insight_models
  framework: Pydantic v2 (BaseModel, Field, Enum)
  driver: pydantic>=2.0
  format_note: All models must be importable from src.models.insight
autobuild_state:
  current_turn: 2
  max_turns: 25
  worktree_path: /Users/richardwoollcott/Projects/appmilla_github/youtube-transcript-mcp/.guardkit/worktrees/FEAT-87A6
  base_branch: main
  started_at: '2026-03-09T22:50:58.343312'
  last_updated: '2026-03-09T22:58:45.302448'
  turns:
  - turn: 1
    decision: feedback
    feedback: "- Not all acceptance criteria met:\n  \u2022 Code passes `ruff check`\
      \ and `mypy`"
    timestamp: '2026-03-09T22:50:58.343312'
    player_summary: Implementation via task-work delegation
    player_success: true
    coach_success: true
  - turn: 2
    decision: approve
    feedback: null
    timestamp: '2026-03-09T22:56:33.961196'
    player_summary: Implementation via task-work delegation
    player_success: true
    coach_success: true
---

# Task: Implement Insight Extraction Service

## Description

Create `src/services/insight_extractor.py` with the core extraction logic. This service structures transcripts for Claude-assisted analysis rather than embedding an LLM directly. It includes focus area resolution, prompt building, and transcript chunking for long content.

## Acceptance Criteria

- [ ] `src/services/__init__.py` exists (if not already)
- [ ] `src/services/insight_extractor.py` implements `get_focus_categories(focus_areas)` function
- [ ] `build_extraction_prompt(transcript, focus_areas, max_insights)` generates structured prompt
- [ ] `chunk_transcript(transcript, max_chars, overlap_chars)` splits long transcripts at paragraph boundaries
- [ ] `prepare_for_extraction(transcript, video_id, focus_areas, max_insights)` returns complete extraction metadata
- [ ] `get_focus_categories` handles 'all' keyword returning all categories
- [ ] `get_focus_categories` falls back to 'general' for unknown focus areas
- [ ] `get_focus_categories` deduplicates when same area specified twice
- [ ] `chunk_transcript` returns single chunk for short transcripts
- [ ] `chunk_transcript` maintains overlap between chunks for context continuity
- [ ] `prepare_for_extraction` returns: extraction_prompt, focus_areas, categories, category_definitions, transcript_length, chunk_count, needs_chunking, max_insights, chunks
- [ ] Prompt includes category descriptions, output format instructions, guidelines
- [ ] Code passes `ruff check` and `mypy`

## Seam Tests

The following seam test validates the integration contract with the producer task. Implement this test to verify the boundary before integration.

```python
"""Seam test: verify insight_models contract from TASK-INT-001."""
import pytest


@pytest.mark.seam
@pytest.mark.integration_contract("insight_models")
def test_insight_models_importable():
    """Verify insight models are importable from src.models.insight.

    Contract: All models must be importable from src.models.insight
    Producer: TASK-INT-001
    """
    from src.models.insight import (
        FocusArea,
        InsightCategory,
        Insight,
        KeyQuote,
        InsightExtractionResult,
        FOCUS_PRESETS,
        CATEGORY_DEFINITIONS,
    )

    assert len(FocusArea) == 6, f"Expected 6 FocusArea values, got {len(FocusArea)}"
    assert len(InsightCategory) == 24, f"Expected 24 InsightCategory values, got {len(InsightCategory)}"
    assert len(FOCUS_PRESETS) == 6, f"Expected 6 presets, got {len(FOCUS_PRESETS)}"
    assert len(CATEGORY_DEFINITIONS) == 24, f"Expected 24 definitions, got {len(CATEGORY_DEFINITIONS)}"
```

## Implementation Notes

Reference the complete service code in `docs/features/FEAT-INT-001-insight-extraction.md` lines 197-463.

Key design decisions:
- **Claude-assisted**: The service prepares prompts and metadata; actual LLM extraction happens at the host level
- **Chunking at paragraph boundaries**: Split on `\n\n` first, fall back to character split for very long paragraphs
- **Overlap**: 500 chars overlap between chunks to maintain context
- **Max chars per chunk**: 30,000 default (well within Claude's context window)
