---

# Stage identity per spec Section 6.1
stage: 1
stage_id: "01"
title: "Documentation Scan"
workflow: sync-docs
estimated_tokens: 5000

# Context specification
context:
  static:
    persona: "technical writer verifying documentation accuracy against implementation"
    purpose: "Identify outdated .md documentation that no longer matches current implementation"
  dynamic:
    - key: exclude_patterns
      source: cli_arg
      default: "specs/**,**/node_modules/**,**/.git/**"
    - key: iterations
      source: cli_arg
      default: 1

# Pre-validation checks
pre_validation: []

# Execution flow with step types
# YAML step -> Markdown section mapping:
#   1 check_repoix          -> Step 1: Check civyk-repoix Availability
#   2 branch_diff_discovery  -> Step 2: Branch-Diff Discovery
#   3 discover_docs          -> Step 3: Discover Documentation Files
#   4 discover_code          -> Step 4: Discover Code Structure
#   5 analyze_docs           -> Step 5: Analyze Each Documentation File
#   6 identify_missing       -> Step 6: Identify Missing Documentation
#   7 classify_docs          -> Step 7: Classify Documentation
#   8 generate_report        -> Step 8: Generate Sync Report
#   9 store_findings         -> Step 9: Store Sync Findings
execution_flow:
  - step: 1
    type: action
    name: check_repoix
    instruction: "Check civyk-repoix availability and index status"
    output_variable: repoix_mode
  - step: 2
    type: action
    name: branch_diff_discovery
    instruction: "Use git(action=\"diff\") to discover code changes and target docs accordingly"
    output_variable: branch_changes
  - step: 3
    type: action
    name: discover_docs
    instruction: "Find all .md documentation files in repo (excluding specs/)"
    output_variable: doc_files
  - step: 4
    type: action
    name: discover_code
    instruction: "Use civyk-repoix to understand codebase structure, components, and APIs"
    output_variable: code_structure
  - step: 5
    type: action
    name: analyze_docs
    instruction: "For each doc file, verify code references still exist and are accurate"
  - step: 6
    type: action
    name: identify_missing
    instruction: "Find undocumented public APIs, services, and CLI commands"
  - step: 7
    type: action
    name: classify_docs
    instruction: "Classify docs as CURRENT, OUTDATED, ORPHANED, or MISSING"
  - step: 8
    type: action
    name: generate_report
    instruction: "Generate sync report with findings"
    output_variable: sync_report
  - step: 9
    type: action
    name: store_findings
    instruction: "Store sync findings in AI cache for Stage 2"

# Guardrails
guardrails:
  enforcement: active
  allowed_tools:
    - civyk-repoix
    - Read
    - Grep
    - Glob
    - Bash  # Only for: git commands, civyk-hatch CLI
  forbidden_actions:
    - "Delete any files"
    - "Modify any files during scan stage"
  read_only: true

# Post-validation checks
post_validation:
  - check: docs_scanned
    description: "All documentation files were scanned"
    severity: error
  - check: report_generated
    description: "Sync report was generated with findings"
    severity: error

# Output specification
output:
  state_update:
    sync-docs.status: "in_progress"
    sync-docs.current_stage: "01-scan"
  completion_command: "civyk-hatch update-stage sync-docs 01 --status completed"

# Next stage
next:
  stage: 2
  stage_id: "02"
  command: "civyk-hatch sync-docs --stage=2 --iterations={iterations}"
  auto_continue: true
  is_terminal: false
version: 1.0.0
---

{{include:strict-execution-mode-lite.md}}

{{include:ai-cache-enforcement.md}}

# Stage 1: Documentation Scan

Verify all .md documentation in the repository matches current implementation. Identify outdated, orphaned, and missing documentation.

## Prerequisites

- Mode: `{REPOIX_MODE}` (if "cli", convert MCP calls per table below)
- Exclude: specs/, node_modules/, .git/

## Critical Rules

| Rule | Action |
|------|--------|
| Exclude specs/ | **NEVER** scan or modify files in specs/ folder |
| Read before classify | **MUST** verify code before marking doc as outdated |
| Pagination | **MUST** fetch all pages when `has_more=true` |
| **Use understand cache** | **MUST** check for existing understand workflow cache before discovery |
| **Use branch diff** | **MUST** use `git(action="diff")` to discover changes (don't guess) |
| **Iteration limit** | **MUST** stop after {max_iterations:10} iterations to prevent infinite loops |
| **Deep content check** | **MUST** verify documented **functionality, architecture, and behavior** match actual implementation - not just symbol existence or counts. Use `understand(action="recall")` to compare documented descriptions against cached code insights |
| **Use understand recall** | **MUST** call `understand(action="recall", target=<code_path>)` for every code reference to get actual implementation details for comparison. Do NOT rely only on symbol-exists checks |

---

## Iteration Safeguard

```text
# [!] MANDATORY: Check iteration count at stage start
IF iterations >= {max_iterations:10}:
    OUTPUT: "=== ITERATION LIMIT REACHED ({max_iterations:10}) ==="
    OUTPUT: "Some documentation may still be out of sync."
    OUTPUT: "Review remaining issues manually or run again."
    STOP workflow
```

---

## Checkpointing & Resume

sync-docs supports checkpointing for large documentation sets.

### Save Checkpoint After Scan

```text
# After completing scan (before auto-continue to Stage 2):
# [!] PREREQUISITE: Requires repoix (skip when REPOIX_MODE == "none")
IF REPOIX_MODE == "none":
    OUTPUT: "[INFO] Checkpointing skipped - no repoix available"
    SKIP checkpoint

understand(action="store",
    scope="project",
    target="sync-docs-checkpoint",  # Unique to sync-docs workflow
    purpose="sync-docs workflow checkpoint for Stage 1",
    importance="high",
    key_points=[
        "stage: 1",
        "iteration: {iterations}",
        "outdated_arch_count: {outdated_arch_count}",
        "outdated_counts_count: {outdated_counts_count}",
        "orphaned_count: {orphaned_count}",
        "missing_count: {missing_count}"
    ],
    gotchas=["Resume with: civyk-hatch sync-docs --resume"],
    analysis="Stage 1 scan complete. {total_issues} issues found ({outdated_arch_count} arch + {outdated_counts_count} counts)."
)
```

### Resume from Checkpoint

```text
# [!] PREREQUISITE: Requires repoix (skip when REPOIX_MODE == "none")
IF REPOIX_MODE == "none":
    SKIP checkpoint resume

understand(action="recall", target="sync-docs-checkpoint")

IF found AND fresh:
    OUTPUT: "Found checkpoint from iteration {iteration}."
    # Use cached scan results instead of re-scanning
```

---

## Understand Workflow Cache Integration

**CRITICAL: Before performing code discovery, check if the understand workflow has already cached project/module/file understanding. This can save 5-10x processing time.**

**NOTE: This section runs AFTER Step 1 (repoix availability). The `understand(action="recall")` and `understand(action="stats")` calls below require REPOIX_MODE != "none". If REPOIX_MODE == "none", set CACHE_STATUS = "none" and skip to Step 3.**

### Check Understand Cache First

```text
# [!] PREREQUISITE: Requires repoix (set by Step 1)
IF REPOIX_MODE == "none":
    CACHE_STATUS = "none"
    OUTPUT: "=== NO REPOIX - Skipping understand cache check ==="
    SKIP to Step 2

# [!] MANDATORY: Check for existing understand workflow cache
understand(action="stats", limit=100)

# Check for project-level understanding
understand(action="recall", target="project")
# IF found AND fresh: Extract architecture, components, APIs

# Check for module-level understanding
understand(action="recall", target="src/")
understand(action="recall", target="scripts/")
# IF found AND fresh: Extract module summaries

# Determine cache status
IF project understanding fresh AND >80% modules fresh:
    CACHE_STATUS = "full"     # Skip all discovery, use cache
    OUTPUT: "=== USING UNDERSTAND CACHE (full) ==="
ELSE IF any understanding found:
    CACHE_STATUS = "partial"  # Use cache where available, discover rest
    OUTPUT: "=== USING UNDERSTAND CACHE (partial) ==="
ELSE:
    CACHE_STATUS = "none"     # Full discovery required
    OUTPUT: "=== NO UNDERSTAND CACHE - Full discovery ==="
```

### Fast Path (CACHE_STATUS = "full")

When understand cache is fully available:

```text
# Extract from project understanding:
# - Architecture patterns
# - Key components and their purposes
# - API endpoints
# - Entry points

# Extract from module understandings:
# - Directory summaries
# - File purposes
# - Internal relationships

# Skip Steps 4.1-4.4 (code discovery)
# Proceed directly to Step 5 (document analysis)
```

### Partial Path (CACHE_STATUS = "partial")

When understand cache is partially available:

```text
# Use cached understanding where available
# Only discover code for modules without cache
# Merge cached and discovered information
```

### Standard Path (CACHE_STATUS = "none")

Fall back to full discovery (Steps 4.1-4.5)

## Step 1: Check civyk-repoix Availability

**Strategy:** Try MCP first, fall back to CLI if MCP fails.

### Step 1a: Try MCP First

```text
status(action="check")
```

**IF MCP succeeds:** Set `REPOIX_MODE = "mcp"` and proceed.

### Step 1b: CLI Fallback (if MCP fails)

```bash
civyk-repoix query status --action check
```

**IF CLI succeeds:** Set `REPOIX_MODE = "cli"` and proceed.

### Step 1c: Neither Available

Set `REPOIX_MODE = "none"` and use manual file reads.

**NOTE: When REPOIX_MODE = "none", ALL repoix tools are unavailable including AI cache tools (`understand(action="recall")`, `understand(action="store")`, `understand(action="invalidate")`, `understand(action="stats")`). Skip these calls throughout and fall through to manual fallbacks (Read, Grep, Glob).**

**MCP/CLI conversion table:**

| MCP Call | CLI Equivalent |
|----------|----------------|
| `status(action="check")` | `civyk-repoix query status --action check` |
| `architecture(action="components")` | `civyk-repoix query architecture --action components` |
| `architecture(action="dependencies")` | `civyk-repoix query architecture --action dependencies` |
| `architecture(action="endpoints", limit=N)` | `civyk-repoix query architecture --action endpoints --limit N` |
| `symbol(action="detail", fqn="...")` | `civyk-repoix query symbol --action detail --fqn "..."` |
| `search(action="symbols", query="...", kind="...")` | `civyk-repoix query search --action symbols --query "..." --kind "..."` |
| `search(action="code", query="...", is_regex=true, limit=N)` | `civyk-repoix query search --action code --query "..." --is-regex true --limit N` |
| `search(action="code", query="...", glob="*.md", limit=N)` | `civyk-repoix query search --action code --query "..." --glob "*.md" --limit N` |
| `file(action="symbols", path="...", kinds=["..."])` | `civyk-repoix query file --action symbols --path "..." --kinds "..."` |
| `file(action="imports", path="...")` | `civyk-repoix query file --action imports --path "..."` |
| `symbol(action="hierarchy", fqn="...", direction="both")` | `civyk-repoix query symbol --action hierarchy --fqn "..." --direction both` |
| `symbol(action="references", fqn="...")` | `civyk-repoix query symbol --action references --fqn "..."` |
| `symbol(action="callers", fqn="...", depth=N)` | `civyk-repoix query symbol --action callers --fqn "..." --depth N` |
| `files(pattern="...", limit=N)` | `civyk-repoix query files --pattern "..." --limit N` |
| `context(action="task", task="...", token_budget=N)` | `civyk-repoix query context --action task --task "..." --token-budget N` |
| `git(action="hotspots", since="...", limit=N)` | `civyk-repoix query git --action hotspots --since "..." --limit N` |
| `git(action="changes", since="...", include_symbols=true)` | `civyk-repoix query git --action changes --since "..." --include-symbols true` |
| `quality(action="dead_code", limit=N)` | `civyk-repoix query quality --action dead_code --limit N` |
| `symbol(action="similar", fqn="...", similarity_threshold=N)` | `civyk-repoix query symbol --action similar --fqn "..." --similarity-threshold N` |
| `git(action="diff", base_branch="...", include_symbols=true)` | `civyk-repoix query git --action diff --base-branch "..." --include-symbols true` |

---

## Step 2: Branch-Diff Discovery (Smart Mode)

**CRITICAL: Use branch diff as source of truth for what changed. Don't rely on user input or guessing.**

When running sync-docs on a feature branch, use `git(action="diff")` to automatically discover what code changed, then target docs accordingly.

### 2.0 Check Branch Context

```text
# [!] PREREQUISITE: Verify repoix is available for branch diff
IF REPOIX_MODE == "none":
    OUTPUT: "=== NO REPOIX - Full scan mode ==="
    OUTPUT: "Branch diff requires civyk-repoix. Will scan all docs equally."
    SKIP to Step 3 (branch diff not available)

# Determine if branch diff is applicable
current_branch = git rev-parse --abbrev-ref HEAD
base_branch = "main"  # Or configured base branch

IF current_branch == base_branch OR current_branch == "main" OR current_branch == "master":
    OUTPUT: "=== ON MAIN BRANCH - Full scan mode ==="
    OUTPUT: "No branch diff available. Will scan all docs equally."
    SKIP to Step 3 (branch diff not applicable)

# Check for common ancestor with base branch
merge_base = git merge-base {current_branch} {base_branch}
IF command exits with non-zero status:
    OUTPUT: "=== NO COMMON ANCESTOR - Full scan mode ==="
    SKIP to Step 3
```

### 2.1 Get Branch Diff

```text
# [!] RECOMMENDED: Discover changes from git diff
git(action="diff", base_branch="main", include_symbols=true, source_only=false)

# Extract from diff:
# - files_changed: Total number of files modified
# - files[].path: Each changed file path
# - files[].additions/deletions: Change size
# - files[].symbols: New/modified classes, functions, etc.
```

### 2.2 Identify New Features from Diff

```text
# [!] GUARD 1: Detect "new project" scenario (most files are additions, 90%+)
# When most files are additions, there are very few outdated references to find.
# Skip per-file doc searching (Step 2.3) to prevent tool call explosion.
#
# IMPORTANT: Use git diff --name-status to check for "A" (Added) status.
# Do NOT rely on deletions==0 alone - a file with additions>0, deletions=0
# could be an append-only edit to an existing file, not a new file.
NEW_PROJECT = false  # Default; set to true below if most files are additions
file_statuses = git diff --name-status {base_branch}..HEAD
new_file_count = count(files where file_statuses shows "A")
mostly_new_files = (new_file_count >= files_changed * 0.9)  # 90%+ new files

IF mostly_new_files AND files_changed > 20:
    OUTPUT: "=== NEW PROJECT ({files_changed} new files) - Summary mode ==="
    GROUP files BY top_directory
    new_modules = [dir for dir in groups IF dir.total_additions > 100]
    new_classes = [s for f in files for s in f.symbols IF s.kind == "class"][:20]
    new_functions = [s for f in files for s in f.symbols IF s.kind == "function"][:30]
    OUTPUT: "Modules: {len(new_modules)} | Classes: {len(new_classes)} | Functions: {len(new_functions)}"
    NEW_PROJECT = true
    SKIP Step 2.3  # No outdated refs to find in a new project
    PROCEED to Step 2.4

# [!] GUARD 2: Large diffs - cap per-file processing to prevent explosion
IF files_changed > 30:
    OUTPUT: "=== LARGE DIFF ({files_changed} files) - Processing top 30 by size ==="
    files = sorted(files, key=file.additions, reverse=true)[:30]

# Analyze diff to discover new implementations:
FOR each file in files:
    IF file.deletions == 0 OR file.additions > file.deletions * 2:
        add to new_files
    IF file in new_files AND file.additions > 100:
        add to new_modules
    FOR each symbol in file.symbols:
        is_new_symbol = (file.deletions == 0) OR (symbol.is_new IF exists)
        IF symbol.kind == "class" AND is_new_symbol:
            add to new_classes
        IF symbol.kind == "function" AND is_new_symbol:
            add to new_functions

OUTPUT: "=== BRANCH DIFF DISCOVERY ==="
OUTPUT: "Changed files: {files_changed}"
OUTPUT: "New modules: {new_module_count}"
OUTPUT: "New classes: {new_class_count}"
OUTPUT: "New functions: {new_function_count}"
```

### 2.3 Search Docs for Outdated References

```text
# [!] SKIP if NEW_PROJECT detected in Step 2.2 (no outdated refs possible)
IF NEW_PROJECT == true:
    OUTPUT: "=== SKIPPING Step 2.3 - New project has no outdated references ==="
    PROCEED to Step 2.4

# Accumulate docs found referencing changed code (consumed by Step 2.4)
docs_referencing_changed_code = []

# Get current counts from code
api_results = architecture(action="endpoints", limit=1)  # Only need total_count
api_count = api_results.total_count
class_results = search(action="symbols", query="%", kind="class", limit=1)  # Only need total_count
class_count = class_results.total_count

# Search docs for hardcoded counts that may be stale
stale_count_results = search(action="code", query="(has|have|provides?|supports?) [0-9]+ (endpoints|APIs|tools|features|commands)", is_regex=true, glob="*.md", limit=50)
IF stale_count_results.files:
    docs_referencing_changed_code.extend(stale_count_results.files)

# Search for missing feature mentions
# [!] CAP: Max 15 classes to prevent tool call explosion
class_search_list = new_classes[:15]
FOR each new_class in class_search_list:
    results = search(action="code", query=new_class.name, glob="*.md", limit=10)
    IF results.files:
        docs_referencing_changed_code.extend(results.files)
    IF not found in docs AND class is public/exported:
        mark as MISSING documentation

# Search for references to changed code
# [!] CAP: Max 20 files to prevent tool call explosion
changed_file_search = files[:20]  # "files" from branch_diff Step 2.1
FOR each changed_file in changed_file_search:
    results = search(action="code", query=changed_file.path, glob="*.md", limit=10)
    IF results.files:
        docs_referencing_changed_code.extend(results.files)
    # Docs referencing changed files may be OUTDATED

# Search for references to renamed/deleted symbols (only if deletions detected)
deleted_symbols = [s for f in files IF f.deletions > 0 for s in f.symbols][:10]
FOR each deleted_symbol in deleted_symbols:
    results = search(action="code", query=deleted_symbol.name, glob="*.md", limit=10)
    IF results.files:
        docs_referencing_changed_code.extend(results.files)
    # Docs referencing deleted code = ORPHANED

# [!] Set explicit flag for Step 6 conditional skip
BRANCH_DIFF_MISSING_DOCS = true  # Step 2.3 completed class/file/symbol searches
```

### 2.4 Build Targeted Scan List

```text
# Priority scan based on branch diff:
PRIORITY_SCAN = {"HIGH": [], "MEDIUM": [], "LOW": []}

# Populate HIGH from Step 2.3 search(action="code") results (already found which docs
# reference changed code, new classes, and deleted symbols):
PRIORITY_SCAN["HIGH"] = deduplicate([
    # Docs found by search(action="code") in Step 2.3 referencing changed files/classes/symbols
    *docs_referencing_changed_code,
    # README.md is always HIGH priority
    "README.md"
])

# MEDIUM and LOW cannot be determined yet (doc_files not available until Step 3).
# These will be populated after Step 3, before Step 5:
#   MEDIUM = docs in same directory as changed code (but not directly referencing it)
#   LOW = all remaining docs
# See Step 5 header for deferred population logic.

OUTPUT: "=== TARGETED SCAN LIST (partial) ==="
OUTPUT: "High priority: {len(PRIORITY_SCAN['HIGH'])} docs (reference changed code)"
OUTPUT: "Medium/Low: deferred until Step 3 discovers all doc files"
```

### 2.5 Store Branch Diff Findings

```text
# Store discoveries for Stage 2
understand(action="store",
    scope="project",
    target="sync-docs-branch-diff",
    purpose="Branch diff analysis for targeted doc sync",
    importance="high",
    key_points=[
        "branch: {current_branch}",
        "base: {base_branch}",
        "files_changed: {count}",
        "new_modules: {list}",
        "new_classes: {list}",
        "new_functions: {list}",
        "outdated_refs_found: {list}"
    ],
    gotchas=["Docs with stale architecture/functionality descriptions", "Docs with stale counts/references", "Missing docs for new public APIs"],
    analysis="Branch adds {new_module_count} modules, {new_class_count} classes, {new_function_count} functions. Found {outdated_ref_count} outdated references in docs."
)
```

### Why Branch-Diff Discovery Matters

**Problem:** Without branch diff, sync-docs relies on:

- User remembering what changed
- Scanning all docs equally (inefficient)
- Missing new features that need documentation

**Solution:** Branch diff provides source of truth:

- Code changes -> automatically detected
- New modules/classes -> flagged for documentation
- Docs referencing changed code -> prioritized for review
- No user input required for discovery

---

## Step 3: Discover Documentation Files

```text
# Find all markdown files (excluding specs/)
IF REPOIX_MODE != "none":
    offset = 0
    doc_results = files(pattern="**/*.md", limit=200)
    doc_files = doc_results.files

    # Handle pagination for large doc sets
    WHILE doc_results.has_more:
        offset = offset + 200
        doc_results = files(pattern="**/*.md", limit=200, offset=offset)
        doc_files.extend(doc_results.files)

    # Filter excluded paths (repoix may include specs/ in results)
    doc_files = [f for f in doc_files IF NOT f.startswith("specs/")]
ELSE:
    # Fallback: use Glob when repoix unavailable
    doc_files = Glob(pattern="**/*.md")
    # Exclude specs/, node_modules/, .git/ from results
    doc_files = [f for f in doc_files IF NOT f.startswith("specs/")
                 AND NOT "node_modules/" in f AND NOT ".git/" in f]

OUTPUT: "Found {len(doc_files)} documentation files"
IF len(doc_files) > 100:
    OUTPUT: "[INFO] Large doc set - consider running understand workflow first for faster processing"
```

**Filter results to exclude:**
- `specs/**` - Feature specifications
- `**/node_modules/**` - Dependencies
- `**/.git/**` - Git internals

**Expected documentation locations:**

| Location | Purpose |
|----------|---------|
| `README.md` | Project overview, installation |
| `docs/**/*.md` | Detailed documentation |
| `CLAUDE.md`, `AGENTS.md` | AI context files |
| `CONTRIBUTING.md` | Contribution guidelines |
| `CHANGELOG.md` | Version history |
| `.github/**/*.md` | GitHub templates |

---

## Step 4: Discover Code Structure

**CONDITIONAL: Skip this step if CACHE_STATUS = "full" (use cached understanding instead)**

**NOTE: CACHE_STATUS is set by the "Understand Workflow Cache Integration" section above (runs after Step 1). If that section was skipped (REPOIX_MODE = "none"), CACHE_STATUS defaults to "none" and all sub-steps below execute.**

### 4.0 Use Cached Understanding (if available)

```text
IF CACHE_STATUS == "full" OR CACHE_STATUS == "partial":
    # Load from understand workflow cache
    understand(action="recall", target="project")
    # Extract: architecture, components, APIs, patterns

    FOR each module in project.key_points[:20]:  # Cap at 20 modules
        understand(action="recall", target="<module_path>")
        # Extract: module purpose, exports, dependencies

    # Build code_structure from cache
    code_structure = {
        "components": <from project understanding>,
        "apis": <from project understanding>,
        "patterns": <from project understanding>,
        "modules": <from module understandings>
    }

    IF CACHE_STATUS == "full":
        SKIP to Step 5  # No discovery needed, proceed to doc analysis
```

### 4.1 Get Project Architecture

**CONDITIONAL: Only run if CACHE_STATUS = "none" OR "partial" (for uncached modules)**

```text
IF REPOIX_MODE != "none":
    # Index metrics
    status(action="check")
    # Extract: files_indexed, symbols_indexed

    # High-level architecture
    architecture(action="components")
    architecture(action="dependencies")

    # Public APIs and entry points
    architecture(action="endpoints", limit=200)

    # CLI commands (if any)
    search(action="code", query="@click.command|argparse|def main", is_regex=true, limit=50)
ELSE:
    # Manual fallback: use Glob + Read for code structure discovery
    code_files = Glob(pattern="**/*.py") + Glob(pattern="**/*.ts") + Glob(pattern="**/*.js")
    # Read key entry points (setup.py, pyproject.toml, package.json) for architecture
    # Use Grep for CLI command discovery:
    Grep(pattern="@click.command|argparse|def main", glob="*.py")
```

### 4.2 Find Key Patterns (Like DeepWiki)

**CONDITIONAL: Skip if CACHE_STATUS = "full" OR REPOIX_MODE = "none"**

```text
IF CACHE_STATUS == "full":
    OUTPUT: "=== SKIPPING Step 4.2 - Full class info available from understand cache ==="
    PROCEED to Step 4.3

IF REPOIX_MODE == "none":
    OUTPUT: "=== SKIPPING Step 4.2 - No repoix for symbol search ==="
    PROCEED to Step 4.3

# Service classes
search(action="symbols", query="%Service", kind="class", limit=50)
search(action="symbols", query="%Handler", kind="class", limit=50)
search(action="symbols", query="%Controller", kind="class", limit=50)

# Configuration classes
search(action="symbols", query="%Config", kind="class", limit=30)
search(action="symbols", query="%Settings", kind="class", limit=30)

# Base classes and interfaces
search(action="symbols", query="Base%", kind="class", limit=30)
search(action="symbols", query="I%", kind="interface", limit=30)

# Error classes
search(action="symbols", query="%Error", kind="class", limit=50)
search(action="symbols", query="%Exception", kind="class", limit=50)
```

### 4.3 Build Context Pack

**CONDITIONAL: Only run if CACHE_STATUS = "none" OR "partial", AND REPOIX_MODE != "none"**

```text
IF REPOIX_MODE == "none":
    OUTPUT: "=== SKIPPING Step 4.3 - No repoix for context pack ==="
    PROCEED to Step 4.4

# Comprehensive context for documentation verification
context(action="task", task="verify documentation accuracy against implementation", token_budget=3000, prefer_kinds=["class", "function"])
```

### 4.4 Check Recent Changes (May Indicate Outdated Docs)

**ALWAYS RUN: Recent changes indicate potentially outdated docs regardless of cache**

```text
# Files changed recently - likely to have outdated docs
IF REPOIX_MODE != "none":
    git(action="changes", since="30d", include_symbols=true, limit=100)
    git(action="hotspots", since="90d", limit=50)
ELSE:
    # Fallback: use git log for recent changes
    recent_changes = Bash: git log --since="30 days ago" --name-only --pretty=format: | sort -u
    # No hotspots available without repoix

# Cross-reference with cached understanding
IF CACHE_STATUS != "none":
    # Compare recent changes against cached understanding timestamps
    # Files changed after understanding was stored = potentially stale
    FOR each changed_file in recent_changes[:20]:  # Cap at 20
        understand(action="recall", target="<changed_file>")
        IF NOT fresh:
            mark file for deeper analysis in Step 5
```

### 4.5 Store Architecture Understanding

**CONDITIONAL: Only store if CACHE_STATUS = "none" (don't overwrite understand workflow cache)**

```text
IF REPOIX_MODE == "none":
    OUTPUT: "=== SKIPPING Step 4.5 - No repoix for understand(action=store) ==="
    PROCEED to Step 5

IF CACHE_STATUS == "none":
    # [!] MANDATORY: Store codebase understanding
    understand(action="store",
      scope="project",
      target="project",
      purpose="Codebase architecture for documentation sync",
      importance="critical",
      key_points=["<component_count> components", "<api_count> APIs", "<key_patterns>"],
      gotchas=["<recent_changes>", "<hotspot_files>"],
      analysis="<architecture>: <summary>. <key_apis>: <list>. <patterns>: <discovered>."
    )
ELSE:
    # Understand workflow cache exists - don't overwrite
    # Just store documentation-sync specific findings
    understand(action="store",
      scope="project",
      target="documentation-sync-discovery",
      purpose="Documentation sync discovery findings (incremental)",
      importance="high",
      key_points=["<recent_changes>", "<hotspot_files>"],
      gotchas=["<files_changed_since_last_understand>"],
      analysis="<recent_changes_count> files changed since understand. <hotspot_count> hotspots."
    )
```

---

## Step 5: Analyze Each Documentation File

**Process docs in PRIORITY_SCAN order (from Step 2.4): HIGH first, then MEDIUM, then LOW.**
**If PRIORITY_SCAN not available (branch diff was skipped): process all docs equally, starting with README.md.**

```text
# Initialize cross-doc cache (persists across per-doc iterations)
api_endpoints_cache = None  # Lazy-loaded in Step 5.2B on first use

# Complete PRIORITY_SCAN population (MEDIUM/LOW deferred from Step 2.4):
IF PRIORITY_SCAN available AND len(PRIORITY_SCAN["MEDIUM"]) == 0:
    changed_dirs = set(dirname(f.path) for f in branch_diff.files)
    FOR each doc in doc_files:
        IF doc NOT in PRIORITY_SCAN["HIGH"]:
            doc_dir = dirname(doc.path)
            IF doc_dir in changed_dirs:
                PRIORITY_SCAN["MEDIUM"].append(doc)
            ELSE:
                PRIORITY_SCAN["LOW"].append(doc)
```

For each .md file (in priority order, or all docs if no priority):

### 5.1 Extract Code References AND Content Claims from Document

**Patterns to identify:**

| Reference Type | Pattern | Example |
|----------------|---------|---------|
| File paths | `src/`, `.py`, `.ts` | `src/auth/login.py` |
| Function names | `func()`, backticks | `authenticate()` |
| Class names | PascalCase | `UserService` |
| CLI commands | `$`, command-line | `civyk-hatch init` |
| API endpoints | HTTP methods | `GET /api/users` |
| Config options | `--flag`, env vars | `--timeout=30` |
| **Architecture claims** | descriptions of how components interact | "The bridge connects MCP to MT5 via named pipes" |
| **Functionality claims** | descriptions of what code does | "supports real-time event streaming" |
| **Workflow/flow claims** | descriptions of data flow or sequences | "requests flow from MCP server through BridgeClient to PipeServer" |
| **Feature lists** | bullet lists of capabilities | "Account management, Market data, Trading" |

**[!] CRITICAL: Do NOT only check symbol names. Also verify that every prose description of functionality, architecture, and behavior in the doc accurately reflects the actual implementation.**

### 5.2 Deep Content Verification (understand recall first)

**[!] CRITICAL: This is a DEEP check, not a shallow symbol-exists check. For every doc, verify that the documented functionality, architecture, and behavior accurately describe what the code actually does.**

**[!] CAP: Process at most 30 code references per document.**

**Step A: Use understand(action="recall") for deep comparison (ALWAYS try this first)**

```text
# [!] MANDATORY: Call understand(action="recall") for EVERY code file referenced in the doc.
# The cached understanding contains purpose, key_points, gotchas, and analysis
# which describe WHAT the code actually does - compare this against the doc's claims.

# Collect unique code files/modules referenced in this doc
referenced_paths = unique paths from code_references and content_claims
uncached_paths = []  # Paths not in cache - will be verified in Step B

FOR each referenced_path in referenced_paths[:20]:  # Cap at 20 paths
    result = understand(action="recall", target=referenced_path)

    IF result.found AND result.fresh:
        # DEEP COMPARISON: Compare doc claims against cached understanding
        # 1. Does the doc's description of PURPOSE match result.purpose?
        # 2. Do the doc's feature/capability claims match result.key_points?
        # 3. Does the doc's architecture description match result.analysis?
        # 4. Are there gotchas in result.gotchas that the doc misses or contradicts?
        #
        # Examples of what to catch:
        #   - Doc says "uses REST API" but code actually uses gRPC
        #   - Doc says "3 tool categories" but code has 7
        #   - Doc describes old architecture that was refactored
        #   - Doc lists features that were removed or renamed
        #   - Doc misses major functionality added since doc was written

        IF doc claims CONTRADICT cached understanding:
            mark as OUTDATED
            note: "Doc describes: <doc_claim>. Actual: <cached_insight>"
        IF doc OMITS major functionality from cached understanding:
            mark as OUTDATED (incomplete)
            note: "Doc missing: <key_point_from_cache>"
    ELSE:
        # No cache - fall back to repoix verification (Step B below)
        add to uncached_paths
```

**Step B: Repoix verification (for uncached paths or when cache unavailable)**

```text
# Group references by source file - batch verify
# Use uncached_paths from Step A, or all referenced_paths if cache was unavailable
files_to_check = uncached_paths[:15] IF len(uncached_paths) > 0 ELSE referenced_paths[:15]

IF REPOIX_MODE != "none":
    FOR each source_file in files_to_check:
        file(action="symbols", path=source_file, kinds=["class", "function", "method"])
        # Compare documented symbols, signatures, and descriptions against actual

    # For API endpoints - use cached result from first doc, don't re-call per doc:
    IF api_endpoints_cache is NOT set:
        api_endpoints_cache = architecture(action="endpoints", limit=200)
    # Cross-reference all documented endpoints against api_endpoints_cache

    # For file paths:
    files(pattern="referenced/path/*", limit=1)
ELSE:
    # Manual fallback: read source files directly
    FOR each source_file in files_to_check:
        Read(file_path=source_file)
        # Extract symbols, signatures from source code manually
        # Compare against documented claims
```

**Step C: Verify architecture and workflow claims**

```text
# [!] CRITICAL: Don't skip this. Architecture claims go stale fastest.

# Collect architecture/workflow/functionality claims from doc (from Step 5.1)
arch_claims = [c for c in content_claims IF c.type in ("architecture", "workflow", "functionality")]

# Deduplicate: skip modules already checked in Step A
already_checked = set(referenced_paths[:20])  # Paths verified in Step A

FOR each claim in arch_claims[:10]:  # Cap at 10 claims per doc
    # Identify the modules/components referenced in the claim
    referenced_modules = extract_module_paths(claim)

    FOR each module_path in referenced_modules[:5]:
        IF module_path in already_checked:
            # Already verified in Step A - reuse that result
            CONTINUE
        result = understand(action="recall", target=module_path)
        IF result.found AND result.fresh:
            # Compare claim against cached understanding:
            # - Does the described interaction match result.analysis?
            # - Does the described technology match result.key_points?
            # - Are there components in result that the claim doesn't mention?
            IF claim CONTRADICTS result:
                mark doc as OUTDATED
                note: "Architecture claim: '{claim}'. Actual: '{result.analysis}'"
        ELSE:
            # No cache - read the actual code to verify
            IF REPOIX_MODE != "none":
                file(action="symbols", path=module_path, kinds=["class", "function"])
            ELSE:
                Read(file_path=module_path)
            # Compare claim against actual code structure

# Common architecture claims that go stale:
#   - "System has N components" (new ones added)
#   - "Data flows from A to B" (intermediate step C added)
#   - "Uses technology X" (migrated to Y)
#   - "Supports protocols A, B" (C added)
```

### 5.3 Check for Code Similarity (Detect Renamed Code)

```text
# If symbol not found, check if similar code exists elsewhere
IF REPOIX_MODE != "none":
    symbol(action="similar", fqn="<old_documented_symbol>", similarity_threshold=0.6, limit=5)
    # May indicate renamed/refactored code
ELSE:
    # Fallback: search for similar names in codebase
    Grep(pattern="<old_documented_symbol>", glob="*.py,*.ts,*.js")
# [!] CAP: Max 5 symbol(action="similar")/Grep calls per doc to prevent tool call explosion
```

---

## Step 6: Identify Missing Documentation

**CONDITIONAL: Skip redundant class searches if branch diff already identified missing docs in Step 2.3**

```text
IF NEW_PROJECT == true:
    OUTPUT: "=== NEW PROJECT - using Step 2.2 class/function discoveries ==="
    # Step 2.2 already collected new_classes and new_functions
    # Only check API endpoints and CLI commands (not collected in Step 2.2)
    architecture(action="endpoints", limit=200)
    search(action="code", query="@click.command|@app.command", is_regex=true, limit=30)
    PROCEED to Step 7

IF branch_diff available AND BRANCH_DIFF_MISSING_DOCS == true:
    OUTPUT: "=== SKIPPING redundant class searches - using Step 2.3 findings ==="
    # Only run API endpoint and CLI checks (not redundant with Step 2.3)
    architecture(action="endpoints", limit=200)
    # Cross-reference with docs - any API not documented = MISSING
    search(action="code", query="@click.command|@app.command", is_regex=true, limit=30)
    # Check key functions from branch diff (new_functions from Step 2.2)
    FOR each func in new_functions[:10]:
        search(action="code", query=func.name, glob="*.md", limit=5)
        IF not found in docs AND func is public/exported:
            mark as MISSING documentation
    PROCEED to Step 7

# Full discovery path (only when no branch diff available)
IF REPOIX_MODE != "none":
    architecture(action="endpoints", limit=200)
    # Cross-reference with docs - any API not documented = MISSING

    # Find important classes without docs
    search(action="symbols", query="%Service", kind="class", limit=50)
    search(action="symbols", query="%Handler", kind="class", limit=50)
    search(action="symbols", query="%Controller", kind="class", limit=50)
    # Check if each has corresponding documentation

    # Find CLI commands without docs
    search(action="code", query="@click.command|@app.command", is_regex=true, limit=30)

    # Find dead code (may have orphaned docs)
    quality(action="dead_code", limit=50)
ELSE:
    # Manual fallback: use Grep for discovery
    Grep(pattern="class .*(Service|Handler|Controller)", glob="*.py")
    Grep(pattern="@click.command|@app.command", glob="*.py")
    # Cross-reference with docs to find MISSING documentation
```

---

## Step 7: Classify Documentation

| Status | Meaning | Criteria |
|--------|---------|----------|
| CURRENT | Doc matches implementation | All references valid, signatures match, **architecture/functionality descriptions accurate** |
| OUTDATED | Doc has stale content | References exist but details changed, **OR documented architecture/functionality/behavior doesn't match actual implementation** |
| ORPHANED | Doc references deleted code | References to non-existent code |
| MISSING | Important code lacks docs | Public APIs without documentation |

---

## Step 8: Generate Sync Report

```text
=== DOCUMENTATION SYNC REPORT ===

Scan: Iteration {iterations}
Project: <project_name>
Discovery Mode: {REPOIX_MODE}
Files Scanned: {doc_count}
Index: {files_indexed} files, {symbols_indexed} symbols

=== BRANCH DIFF DISCOVERY ===
{IF branch_diff available:}
  Branch: {current_branch} vs {base_branch}
  Changed files: {files_changed}
  New modules: {new_module_count}
  New classes: {new_class_count}
  Outdated refs found: {outdated_ref_count}
{ELSE:}
  [~] Branch diff not available (on main branch or no common ancestor)
  [INFO] Running full scan mode
{END IF}

=== UNDERSTAND CACHE STATUS ===
Cache Mode: {CACHE_STATUS}  # full | partial | none
{IF CACHE_STATUS == "full":}
  [ok] Project understanding: fresh
  [ok] Module understandings: {fresh_modules}/{total_modules} fresh
  [ok] File understandings: {fresh_files}/{total_files} fresh
  [SPEEDUP] Discovery skipped - using cached understanding
{ELSE IF CACHE_STATUS == "partial":}
  [~] Project understanding: {fresh|stale|missing}
  [~] Module understandings: {fresh_modules}/{total_modules} fresh
  [~] File understandings: {fresh_files}/{total_files} fresh
  [PARTIAL] Using cache where available, discovered {discovered_count} items
{ELSE:}
  [!] No understand cache - full discovery performed
  [TIP] Run 'civyk-hatch understand --mode=deep' to build cache for 5-10x speedup
{END IF}

OUTDATED DOCUMENTATION (requires update):
| File | Issue | Type | Lines | Priority |
|------|-------|------|-------|----------|
| README.md | Architecture section describes REST but code uses gRPC | ARCH | 20-45 | HIGH |
| docs/api.md | Function `auth()` renamed to `authenticate()` | COUNT | 45-52 | HIGH |
| README.md | Feature list missing 4 new tool categories | ARCH | 50-65 | HIGH |
| docs/architecture.md | Data flow diagram missing new EventPipe component | ARCH | 10-30 | HIGH |
| README.md | Installation command uses deprecated flag | COUNT | 12-15 | MEDIUM |
| docs/models.md | UserService has new methods not documented | ARCH | 80-95 | MEDIUM |

ORPHANED DOCUMENTATION (references deleted code):
| File | Issue | Priority |
|------|-------|----------|
| docs/legacy-auth.md | References removed `LegacyAuth` class | HIGH |
| docs/old-api.md | Entire file documents deleted endpoints | HIGH |

MISSING DOCUMENTATION (undocumented code):
| Code | Location | What Needs Docs | Priority |
|------|----------|-----------------|----------|
| `NewService` | src/services/new.py | New service class | HIGH |
| `--batch` flag | src/cli.py:45 | New CLI option | MEDIUM |
| `POST /api/v2/users` | src/api/users.py | New API endpoint | HIGH |

CURRENT DOCUMENTATION (no changes needed):
- CHANGELOG.md
- CONTRIBUTING.md
- LICENSE

Summary:
- Current: {N}
- Outdated (architecture/functionality): {N}  # PRIORITY for Stage 2
- Outdated (counts/references): {N}
- Orphaned: {N}
- Missing: {N}
```

**[!] TRUNCATION:** If any report table exceeds 20 rows, show top 20 by priority and add: `... and {remaining} more items (full list stored in documentation-sync cache)`.

---

## Step 9: Store Sync Findings

```text
# Store findings for Stage 2 (including REPOIX_MODE for continuity)
IF REPOIX_MODE != "none":
    understand(action="store",
      scope="project",
      target="documentation-sync",
      purpose="Documentation sync analysis results",
      importance="high",
      key_points=[
          "repoix_mode: {REPOIX_MODE}",  # Pass mode to Stage 2
          "outdated_architecture: <files with stale architecture/functionality descriptions>",
          "outdated_counts: <files with stale counts/references only>",
          "orphaned: <file_list>",
          "missing: <code_list>"
      ],
      gotchas=["<high_priority_items>", "<blocking_issues>"],
      analysis="<arch_outdated_count> need architecture updates (PRIORITY). <count_outdated_count> need count updates. <orphaned_count> reference deleted code. <missing_count> APIs need docs."
    )
ELSE:
    # No repoix - findings transfer via session context (auto_continue keeps same agent)
    OUTPUT: "=== FINDINGS FOR STAGE 2 (session context) ==="
    OUTPUT: "repoix_mode: {REPOIX_MODE}"
    OUTPUT: "outdated_architecture: <files with stale architecture/functionality descriptions>"
    OUTPUT: "outdated_counts: <files with stale counts/references only>"
    OUTPUT: "orphaned: <file_list>"
    OUTPUT: "missing: <code_list>"
```

---

## Exit Condition

If all docs are CURRENT and no MISSING docs:

```text
=== ALL DOCUMENTATION IN SYNC ===

All {doc_count} documentation files match current implementation.
No outdated, orphaned, or missing documentation found.

[ok] DOCUMENTATION SYNC COMPLETE
```

**-> STOP (workflow complete)**

---

## [AUTO-CONTINUE]

If outdated, orphaned, or missing documentation found, automatically proceed to Stage 2 to update them.

## NEXT

```bash
civyk-hatch sync-docs --stage=2 --iterations={iterations}
```
