# Revision Agent

Process annotations and formatting edits from the Revision Editor (Production Console → Revision tab).

---

## Invocation

```
/revise [project] [annotations_file]
```

**Examples:**
```
/revise the-hike THE-HIKE-COMPLETE-gen5-annotations.json
/revise leviathan LEVIATHAN-COMPLETE-annotations.json
```

---

## Workflow

### Phase 0: Load & Parse

1. Read the annotations JSON file from project root or specified path
2. Parse and validate structure (annotations array, optional edits array)
3. Report summary:

```
Loading THE-HIKE-COMPLETE-gen5-annotations.json...

SOURCE: THE-HIKE-COMPLETE-gen5.fountain
PROJECT: the-hike

FORMATTING EDITS: 4
  - Episode 8: 2 edits (1 type change, 1 text fix)
  - Episode 12: 2 edits (2 type changes)

ANNOTATIONS: 7 across 3 episodes
  - Episode 8: 3 annotations (2 REWRITE, 1 DELETE)
  - Episode 32: 2 annotations (1 REWRITE, 1 FLAG)
  - Episode 46: 2 annotations (2 FLAG)

Proceed? [Y]es / [Q]uit
```

---

### Phase 1: Apply Formatting Edits (Automatic)

Formatting edits are applied automatically without prompting (user already made these decisions in the Revision Editor).

For each edit in the `edits` array:

1. Read the target episode file: `/[project]/episodes/ep_XXX.md`
2. Create backup before first modification
3. Find the line by searching for `original_text`
4. Apply changes:
   - **Type change**: Convert Fountain formatting (e.g., action → dialogue means adding character cue)
   - **Text change**: Replace the text content
5. Log to revision_log.json

```
Applying 4 formatting edits...

Episode 8:
  ✓ Line 45: action → dialogue (added character cue)
  ✓ Line 67: text corrected

Episode 12:
  ✓ Line 23: dialogue → action (removed from dialogue block)
  ✓ Line 88: character → action

Formatting edits complete. 2 episodes modified.
```

#### Type Change Rules

When changing line types, adjust Fountain formatting:

| From | To | Transformation |
|------|-----|----------------|
| action | dialogue | Insert before previous character cue, or prompt for character name |
| action | character | Convert to ALL CAPS |
| dialogue | action | Add blank line before, ensure not indented |
| character | action | Convert to sentence case |
| parenthetical | action | Remove parentheses, add blank line |
| scene-heading | action | Convert to sentence case (rare, verify intent) |

If transformation is ambiguous (e.g., action→dialogue but no character cue exists), prompt:

```
⚠ Line 45 changed to dialogue but no character found.
Who is speaking?

[1] SAM
[2] DAVID
[3] JASON
[4] Enter name manually

>
```

---

### Phase 2: Process Annotations (Interactive)

For each annotation, execute this loop:

#### Step 1: Load Context

```
---
[1/7] Episode 8, Line 102
ACTION: REWRITE
SELECTED: "A MAN lies on the forest floor. Caucasian. Thirties."
NOTE: Caucasian feels clinical, describe features instead

Loading context...
```

Read the following files for full context:
- Target episode: `/[project]/episodes/ep_XXX.md`
- Previous episode: `/[project]/episodes/ep_XXX-1.md` (if exists)
- Next episode: `/[project]/episodes/ep_XXX+1.md` (if exists)
- Character voices: `/[project]/bible/characters.md`

#### Step 2: Display Current State

Show the target line(s) with surrounding context (5 lines before and after):

```
CURRENT (Lines 98-108):
  98: Sam crouches on the ground. Not hurt. Not attacked.
  99:
 100: Crouched over someone else.
 101:
 102: A MAN lies on the forest floor. Caucasian. Thirties.  ← TARGET
 103: Eyes unfocused. Arm clutched to his chest.
 104:
 105: He looks up at David.
 106:
 107: Says something in Mandarin.
 108:
```

#### Step 3: Present Options

```
[A] Generate AI suggestion
[M] Manual edit (you provide the text)
[S] Skip this annotation
[V] View full episode
[F] View surrounding episodes
[Q] Quit session (progress saved)

>
```

#### Step 4: Handle User Choice

**If [A] Generate AI suggestion:**

Generate a replacement that:
- Addresses the user's note/comment
- Maintains voice consistency with `characters.md`
- Fits the V12 constraints (word count, texture)
- Preserves continuity with surrounding episodes

Present the suggestion:

```
AI SUGGESTION:
"A MAN lies on the forest floor. White. Thirties.
Stubble darkens his jaw. Eyes that have seen too much."

[Y] Accept  [N] Reject  [E] Edit suggestion  [R] Regenerate

>
```

**If [M] Manual edit:**

```
Enter replacement text (or paste). End with empty line:
>
```

**If [S] Skip:**

Log as skipped, move to next annotation.

**If [V] View full episode:**

Display entire episode, then return to options.

**If [Q] Quit:**

Save progress to `revision_session.json`, exit.

#### Step 5: Apply Change

Before any modification:

1. Create backup: `ep_XXX.md` → `ep_XXX.md.backup.NNN`
2. Find the exact text in the episode file using `selected_text`
3. Replace with approved text
4. Validate word count still within V12 limits
5. Log to `revision_log.json`

```
Creating backup: ep_008.md → ep_008.md.backup.001
Applying change...
✓ Applied. Word count: 221 → 225 (within limits)
Logged to revision_log.json.

---
[2/7] Episode 8, Lines 88-89
...
```

---

## Action-Specific Handling

### REWRITE

Standard flow as above. Generate suggestion based on user's note.

### DELETE

```
[1/7] Episode 8, Lines 88-89
ACTION: DELETE
SELECTED: "David's heart hammers. Every terrible scenario..."
NOTE: Internal monologue breaks tension

LINES TO DELETE:
  88: David's heart hammers. Every terrible scenario floods
  89: his mind. Heart attack. Broken leg. Snake bite. Bear.

[D] Delete these lines
[K] Keep (skip)
[V] View more context
[Q] Quit

>
```

If confirmed, remove lines and adjust formatting.

### MOVE

```
[3/7] Episode 32, Line 78
ACTION: MOVE
SELECTED: "Sam smiles. Sad. Warm."
NOTE: Should come after the laugh, not before

Current location: Line 78
Move to: [Enter line number or "after LINE_NUMBER"]

>
```

Cut from current location, insert at new location.

### FLAG

FLAGS are discussion items, not automatic changes:

```
[5/7] Episode 46
ACTION: FLAG
NOTE: Confession pacing feels rushed overall

This is a FLAG for discussion. No automatic action.

Options:
[D] Discuss - describe what you'd like to change
[S] Skip - acknowledge and move on
[N] Add note to revision_log.json

>
```

If [D] Discuss, enter freeform conversation about the issue.

---

## Backup System

### Backup Naming

```
ep_008.md.backup.001  ← First backup
ep_008.md.backup.002  ← Second backup (same session or later)
ep_008.md.backup.003  ← etc.
```

### Backup Manifest

Store in `revision_log.json`:

```json
{
  "backups": [
    {
      "file": "ep_008.md",
      "backup": "ep_008.md.backup.001",
      "timestamp": "2026-01-12T15:35:22Z",
      "annotation_id": "ann_001",
      "action": "REWRITE"
    }
  ]
}
```

### Restore Command

```
/rewind [project] [backup_number]
```

Example: `/rewind the-hike 001` restores all `.backup.001` files.

---

## Revision Log Format

`/[project]/state/revision_log.json`:

```json
{
  "sessions": [
    {
      "id": "session_1705012345",
      "started_at": "2026-01-12T15:30:00Z",
      "completed_at": "2026-01-12T16:15:00Z",
      "annotations_file": "annotations.json",
      "total_annotations": 7,
      "applied": 5,
      "skipped": 1,
      "flagged": 1,
      "decisions": [
        {
          "annotation_id": "ann_001",
          "episode": 8,
          "line": 102,
          "action": "REWRITE",
          "decision": "applied",
          "original": "A MAN lies on the forest floor. Caucasian. Thirties.",
          "revised": "A MAN lies on the forest floor. White. Thirties.\nStubble darkens his jaw. Eyes that have seen too much.",
          "backup": "ep_008.md.backup.001",
          "timestamp": "2026-01-12T15:35:22Z"
        },
        {
          "annotation_id": "ann_002",
          "episode": 8,
          "lines": [88, 89],
          "action": "DELETE",
          "decision": "skipped",
          "reason": "User decided to keep for pacing",
          "timestamp": "2026-01-12T15:40:15Z"
        }
      ]
    }
  ]
}
```

---

## V12 Validation

After each change, validate:

- [ ] Word count: 450-500 words per episode (see `/CONSTANTS.md`)
- [ ] Dialogue: ≤40% of word count
- [ ] Texture: Action blocks have sensory detail

If validation fails:

```
⚠ WARNING: Change exceeds word limit (521 words, max 500)

Options:
[T] Trim suggestion (AI will reduce)
[F] Force apply anyway
[E] Edit manually
[R] Reject change

>
```

---

## Session Persistence

If user quits mid-session:

1. Save progress to `revision_session.json`
2. On next `/revise` invocation, check for incomplete session:

```
Found incomplete revision session from 2026-01-12 15:30.
3/7 annotations processed.

[R] Resume session
[N] Start new session (discard progress)

>
```

---

## Error Handling

### Text Not Found

If `selected_text` doesn't match episode content:

```
⚠ Cannot find selected text in episode file.
The file may have been modified since annotation.

Selected: "A MAN lies on the forest floor. Caucasian."
Episode 8 does not contain this exact text.

Options:
[S] Search for similar text
[M] Manual locate (show episode, you identify)
[K] Skip this annotation

>
```

### Episode Not Found

```
⚠ Episode file not found: ep_008.md
Expected at: /the-hike/episodes/ep_008.md

Options:
[P] Specify alternate path
[K] Skip annotations for this episode

>
```

---

## Phase 3: Cleanup (Automatic)

After all annotations are processed (session completes — NOT on mid-session quit), delete stale Script Doctor working files so they don't reappear in the Revision Editor.

**Delete these files from `/[project]/state/`:**

| File | Reason |
|------|--------|
| `script_doctor_annotations.json` | Working file consumed by this session |
| `script_doctor_broad.json` | Intermediate diagnostic output (Pass 2) |
| `script_doctor_structural.json` | Intermediate diagnostic output (Pass 1: transitions) |
| `script_doctor_focus_*.json` | Intermediate per-dimension passes |
| `script_doctor_payload_preview.txt` | Debug/dry-run output |
| `script_doctor_verify.json` | Post-revision verification (stale after new revisions) |
| `transition_check.json` | Standalone transition check output (if run separately) |
| `revision_session.json` | Session recovery file (session is complete) |

**Keep these files (archival/reference):**

| File | Reason |
|------|--------|
| `script_doctor_brief.json` | Source of truth for findings — reference document |
| `deep_fix_F*.json` | Structural fix guidance — may be needed for future review |
| `revision_log.json` | Audit trail of all decisions — permanent record |

**Implementation:**

```python
import glob, os

state_dir = f"/[project]/state/"
delete_patterns = [
    "script_doctor_annotations.json",
    "script_doctor_broad.json",
    "script_doctor_structural.json",
    "script_doctor_focus_*.json",
    "script_doctor_payload_preview.txt",
    "script_doctor_verify.json",
    "transition_check.json",
    "revision_session.json",
]

deleted = []
for pattern in delete_patterns:
    for f in glob.glob(os.path.join(state_dir, pattern)):
        os.remove(f)
        deleted.append(os.path.basename(f))
```

Report cleanup in the summary:

```
CLEANUP: 3 stale files removed
  - script_doctor_annotations.json
  - script_doctor_broad.json
  - revision_session.json
```

**This is deterministic.** No validation loop. If the session completed, the working files are consumed and safe to delete.

**Important:** Only run cleanup on full session completion. If user quits mid-session ([Q]), do NOT delete — the annotations are still needed for resume.

---

## Summary Report

At session end:

```
REVISION SESSION COMPLETE

SOURCE: THE-HIKE-COMPLETE-gen5-annotations.json

FORMATTING EDITS: 4
  ✓ Applied:  4
  - 2 type changes
  - 2 text corrections

ANNOTATIONS: 7
  ✓ Applied:  5
  ○ Skipped:  1
  ⚑ Flagged:  1

EPISODES MODIFIED: 4
  - ep_008.md (2 edits, 2 annotations)
  - ep_012.md (2 edits)
  - ep_032.md (2 annotations)
  - ep_046.md (1 annotation)

BACKUPS: 4
  ep_008.md.backup.001
  ep_012.md.backup.001
  ep_032.md.backup.001
  ep_046.md.backup.001

CLEANUP: 3 stale files removed
  - script_doctor_annotations.json
  - script_doctor_broad.json
  - revision_session.json

Log saved to: /the-hike/state/revision_log.json

NEXT STEPS:
  1. Run /compile the-hike to regenerate fountain file
  2. Review changes in compiled output
  3. Run /rewind the-hike 001 to restore if needed
```
