# Plan 32-01: Deep-Reading Mode Detection

**Phase:** 32 — Deep-Reading Mode Detection
**Goal:** Plugin detects `deep-reading.md` files by filename + parent directory pattern and routes to a dedicated `deep-reading` dashboard mode.
**Depends on:** Phase 31 (Bug Fixes)
**Requirements:** DEEP-01
**CONTEXT:** `.planning/phases/32-deep-reading-mode-detection/32-CONTEXT.md`

## Tasks

### Task 1: Extract `_resolveModeForFile()` pure function

**File:** `paperforge/plugin/main.js` (around line 714)

Extract a pure function that determines the mode for a given file without side effects:

```javascript
_resolveModeForFile(file) {
    if (!file) return { mode: 'global', filePath: null, key: null };

    const ext = file.extension;
    const filePath = file.path;

    if (ext === 'base') {
        return { mode: 'collection', filePath, key: null, domain: file.basename };
    }

    if (ext === 'md') {
        // D-01: Check deep-reading.md FIRST (before zotero_key)
        if (file.name === 'deep-reading.md') {
            const parentDir = file.parent?.name || '';
            // D-02: Parent directory must match {8-char-key} - {Title} pattern
            if (/^[A-Z0-9]{8} - .+$/.test(parentDir)) {
                const cache = this.app.metadataCache.getFileCache(file);
                const key = cache?.frontmatter?.zotero_key;
                if (key) {
                    return { mode: 'deep-reading', filePath, key };
                }
            }
        }

        // Standard .md handling — check for zotero_key (D-03 fallback)
        const cache = this.app.metadataCache.getFileCache(file);
        const key = cache?.frontmatter?.zotero_key;
        if (key) {
            return { mode: 'paper', filePath, key };
        }
        return { mode: 'global', filePath, key: null };
    }

    return { mode: 'global', filePath, key: null };
}
```

**Verification:**
- `_resolveModeForFile(null)` → `{ mode: 'global', ... }`
- `_resolveModeForFile(.base file)` → `{ mode: 'collection', ... }`
- `_resolveModeForFile(deep-reading.md in workspace)` → `{ mode: 'deep-reading', key: 'ABCDEFG' }`
- `_resolveModeForFile(deep-reading.md outside workspace)` → `{ mode: 'paper', key: 'ABCDEFG' }` (falls through to zotero_key check)
- `_resolveModeForFile(.md with zotero_key)` → `{ mode: 'paper', key: 'ABCDEFG' }`
- `_resolveModeForFile(.md without zotero_key)` → `{ mode: 'global', ... }`

### Task 2: Refactor `_detectAndSwitch()` to use pure function

**File:** `paperforge/plugin/main.js` (around line 714)

Replace the current `_detectAndSwitch()` method:

```javascript
_detectAndSwitch() {
    const activeFile = this.app.workspace.getActiveFile();
    const resolved = this._resolveModeForFile(activeFile);

    // D-06: Set state vars from resolved mode
    this._currentDomain = resolved.domain || null;
    this._currentPaperKey = resolved.key || null;
    this._currentPaperEntry = resolved.key ? this._findEntry(resolved.key) : null;

    // D-06, D-10: Switch mode with identity guard
    this._switchMode(resolved.mode, resolved.filePath);
}
```

### Task 3: Update `_switchMode()` with file-path identity guard

**File:** `paperforge/plugin/main.js` (around line 763)

```javascript
_switchMode(mode, filePath) {
    // D-06: Identity guard — check BOTH mode AND file path
    if (this._currentMode === mode && this._currentFilePath === filePath) {
        this._refreshCurrentMode();
        return;
    }

    this._currentMode = mode;
    this._currentFilePath = filePath;
    // ... existing content clear and render dispatch ...
}
```

Also add `_currentFilePath` initialization:
```javascript
constructor() {
    // ... existing init code ...
    this._currentMode = null;       // 'global' | 'paper' | 'collection' | 'deep-reading'
    this._currentFilePath = null;   // D-06: for identity guard
    // ... rest of existing init ...
}
```

### Task 4: Add `deep-reading` case to mode dispatch

**File:** `paperforge/plugin/main.js` (around line 775, `_switchMode`'s render dispatch)

```javascript
// Inside _switchMode's mode dispatch section:
case 'deep-reading':
    this._renderDeepReadingMode();
    break;
```

This creates the dispatch entry point. The actual `_renderDeepReadingMode()` implementation is Phase 33 — for now, it can render a placeholder or empty state.

```javascript
/* ── Deep-Reading Mode Render (placeholders — Phase 33 populates) ── */
_renderDeepReadingMode() {
    this._contentEl.createEl('div', {
        cls: 'paperforge-content-placeholder',
        text: 'Deep-reading dashboard — Phase 33 will populate this view.',
    });
}
```

### Task 5: Update mode type reference

**File:** `paperforge/plugin/main.js`

Add `'deep-reading'` to any mode type checks or render-mode-header logic:

```javascript
// In _renderModeHeader (around line 1051):
case 'deep-reading':
    modeName = 'Deep Reading';
    break;
```

## Success Criteria

1. Opening `deep-reading.md` inside a paper workspace (`Literature/骨科/ABCDEFG - Title/deep-reading.md`) switches dashboard to `deep-reading` mode with placeholder content.
2. `deep-reading.md` with `zotero_key` in frontmatter routes to `deep-reading` mode, NOT per-paper mode (filename check precedes frontmatter check).
3. Switching away from `deep-reading.md` to another file transitions to the correct mode.
4. Identity guard prevents re-render when same file is re-detected (active-leaf-change double-fire).
5. `deep-reading.md` outside a valid workspace parent directory falls through to per-paper mode (if has zotero_key).
6. All existing mode routing still works: .base → collection, .md + zotero_key → paper, no file → global.

## Rollback

```bash
git checkout -- paperforge/plugin/main.js
```
