# MVP (v0.1.0) — Permanent Capabilities

Features and behaviors shipped in v0.1.0. Extracted from requirements.md, phase shift requirements, phase summaries, and decisions.md.

---

## Static Analysis Pipeline

- **Multi-language support:** Python (stdlib `ast`), TypeScript, JavaScript (tree-sitter)
- Well-documented adapter interface (`AdapterProtocol`) for community language contributions
- **Unsupported language fallback:** directory walking + file listing only (no AST); LLM receives raw file contents; user notified of limited depth
- Discovers git-tracked source files, parses imports, extracts functions/classes/entry points
- Builds import graph with in-degree centrality scoring
- Groups files into logical modules via label propagation clustering
- Detects test files by naming convention; parses `coverage.xml` when available (Tier 1 basic / Tier 2 enhanced)
- Scores files by importance signals for token-budget-based key file selection
- **Tree-sitter parser caching** at instance level (JS: 1 parser, TS: 2 parsers for .ts/.tsx)

## Analysis Filtering (Phase Shift — Phase 9)

- `FileFilter` class with 5-layer filter order:
  1. `ALWAYS_EXCLUDE` — VCS dirs, `__pycache__`, `node_modules`, `.venv`, `.pyc` (not overridable)
  2. `.gitignore` — via `pathspec` library
  3. `DEFAULT_EXCLUDE` — data/docs/config file patterns (overridable)
  4. User `include_patterns` — add back files from defaults
  5. User `exclude_patterns` — additional exclusions
- Per-repo config at `~/.unfamiliar/repos/<sha256(path)[:8]>/config.yaml`
- `ALWAYS_INCLUDE` list for dependency manifests (package.json, pyproject.toml, etc.)
- `excluded_count` tracked in `AnalysisResult`
- Filtering happens at discovery phase, before any processing

## Security Analysis

- **Secret detection** via `detect-secrets` library (Apache-licensed)
- **CVE scanning** via language-native tools: `pip-audit` (Python), `npm audit` (JS/TS)
- Security posture summary included in briefing
- Security-relevant missions tagged across all categories
- Analysis is purely local — no data leaves the machine

## LLM Integration

### Provider-Agnostic Factory (Phase Shift — Phase 14)

- All providers go through `init_chat_model` — single code path, no provider-specific branches
- **Built-in provider registry** with config overrides:
  - `anthropic`: native `init_chat_model` path, `ANTHROPIC_API_KEY`
  - `glm`: OpenAI-compatible endpoint via `base_url`, `ZHIPUAI_API_KEY`
- Config-driven: `[general]` section for provider, `[llm]` section for model/base_url/api_key_env/max_tokens (all optional)
- Backwards compatible — existing configs with only `[general]` still work
- `max_tokens` omitted from API call when not configured (let model decide)
- GLM uses OpenAI-compatible `Bearer` auth (not legacy JWT)

### Briefing Generation

- `build_briefing_context()` transforms AnalysisResult to structured LLM context with token budget enforcement
- `generate_briefing()` produces structured briefing + module naming
- Global budget enforcement on entire context (not just file contents)
- Max file size limit (10,000 chars) with truncation
- Dynamic budget allocation — file contents section gets remaining budget after other sections

### Mission Generation

- **Per-category generation** — 7 separate LLM calls (Architecture through Technical Debt), not monolithic
- **Multi-call generation** (Phase Shift — Phase 10) — up to 3 LLM calls per category, accumulating missions across calls
- **Truncation detection and recovery** — `detect_truncation()` identifies incomplete JSON; recovers complete missions and chains from truncated responses
- **Deduplication** by title across calls within a category
- **Title deduplication** (Phase 20) — `_deduplicate_titles()` disambiguates duplicate thematic titles with Roman numeral suffixes

### Mission Validation (Programmatic, No LLM)

- File path validation against actual filesystem
- Line range clamping to actual file bounds
- Prerequisite graph validation: cycle detection, max depth 3, reachability from root
- Root mission enforcement: each category has at least 1-2 zero-prerequisite missions
- Schema validation for required fields and enum values
- Auto-fix: clamp lines, break cycles, remove bad prerequisites
- **Validated data wired to persistence** (Phase Shift — Phase 15) — raw LLM output replaced with validated/cleaned data before storage

### Chain-Mission Linking (Phase Shift — Phase 15)

- Three-layer defense: prompt reinforcement (use `title_plain` in chains) + validation normalization (Film Noir titles mapped to `title_plain`) + persistence fallback lookup
- Truncated JSON recovery preserves complete chain objects (not drops all chains)

### Pipeline Orchestration

- LangGraph pipeline with SQLite checkpointing at category boundaries
- Categories processed in canonical order (`CATEGORY_ORDER`)
- Subset processing via optional `categories` parameter
- Resume from last checkpoint on restart (completed steps never repeated)
- `category_cooldown` between API calls (configurable)
- **Provider-aware retry** — exponential backoff with provider-specific base delays
- Error handling: `AuthenticationError` stops pipeline; `MissionGenerationError`/`TimeoutError` logged and skipped, continues to next category
- Partial results returned on failure — completed categories available while others are pending

### Theme-Aware Prompts (Phase 18)

- Templatized mission prompts with theme variables (theme_name, title_examples, intro_style, outro_style)
- `build_theme_prompt_vars()` produces template variables from ThemeConfig or fallback defaults
- Theme threaded through orchestrator → pipeline → generator → prompt

## Campaign Lifecycle (Phase 13 + Phase 20)

- `create_campaign(repo_path, force=False)` — full pipeline: analyze → briefing → missions → persist
- `CampaignExistsError` raised when overwriting ACTIVE campaign with progress (unless `force=True`)
- `resume_campaign()` — find most recent active/initializing campaign
- `discover_campaigns()` — scan `~/.unfamiliar/campaigns/` for all saved campaigns
- `reopen_campaign(db, campaign_id)` — reopen CLOSED campaigns
- Campaign status: INITIALIZING → ACTIVE on success; ACTIVE → CLOSED on end; CLOSED → ACTIVE on reopen

## Mission System (Phase 13 + Phase 20)

- `complete_mission()` returns `CompletionResult` dataclass; cascades unlock of eligible dependents
- `start_mission()` transitions AVAILABLE → IN_PROGRESS
- `unlock_mission()` — escape hatch to force AVAILABLE status
- `count_by_campaign()` and `count_completed()` query methods
- Multiple IN_PROGRESS missions allowed (free switching)
- Prerequisite enforcement is strict — locked missions cannot be started
- A completed mission counts across all chains it appears in

## CLI Entry Points

- `unfamiliar investigate <repo>` — start new campaign or resume existing, then launch TUI
- `unfamiliar campaigns` — list all saved campaigns with status
- `unfamiliar resume` — resume most recent active campaign, launch TUI
- `unfamiliar reopen` — reopen a closed campaign

## TUI (Phases 16–18, 20)

### Layout

- Persistent 4-region layout: header, command reference, main content area, command input
- Custom widgets: InvestigationHeader, CommandReference, ContentArea, CommandInput

### Commands

10 canonical commands with themed aliases (Film Noir):

| Canonical | Noir Alias | Function |
|-----------|-----------|----------|
| next | investigate | Show available missions, pick one |
| complete | file report | Complete current mission |
| status | case board | Campaign overview and stats |
| briefing | case file | Re-read codebase briefing |
| mission | lead | Show mission details |
| notebook | case notes | Print notebook path (v1.1 placeholder) |
| unlock | break in | Force locked → available |
| help | call in a marker | Show all commands |
| quit | bury the day | End session |
| end campaign | close the case | End campaign |

- Multi-word themed alias support (e.g., "break in 42")
- `next <N>` starts mission N from list; `mission <N>` views without starting
- Mission list cache for selection by number

### Interaction Flows

- Session resume detects in-progress missions with contextual welcome
- Confirmation modals for end-campaign and quit-with-active-mission
- Toast notifications for state changes
- `load_actionable_missions()` shows IN_PROGRESS (first) + AVAILABLE missions

### Film Noir Theme

- 10 command aliases, 17 vocabulary terms
- NarrativeConfig: tone, title_examples, intro_style, outro_style
- `vocab(key)`, `alias(key)`, `color(key)`, `decoration(key)`, `icon(key)` accessors with safe fallbacks
- TCSS stylesheet with focus styles for keyboard accessibility
- Theme registered via `register_theme()` / `get_theme()` / `list_themes()` registry

### Data Layer

- View data models (frozen dataclasses) with no DB/Textual dependencies
- Query layer (7 functions) bridging DB to view data
- Presentation fully separated from data/logic
