# Inkhaven 1.4.16 — Character arc tracking

_Inkhaven already tracks two things about a character: the **facts** the continuity bible records, and
the **speech** DIALOG-1 fingerprints. CHAR-1 adds the third axis — **change over time**. Per named
character: a chapter-ordered chain of their observable state, a deterministic *agency* score, and
completeness checks against the arc you declared. A character arc is a promise — *this person starts
here, and the book earns them to there* — and CHAR-1 measures whether the manuscript keeps it. It
reads only your manuscript and your declarations, never edits your prose, and the only LLM pass is the
state extraction. **No new runtime crates.**_

_Plan: [CHAR-1_PLAN.md](../PROPOSALS/CHAR-1_PLAN.md)_

## Declare the arc

In the **Characters** system book, give a character an arc by adding a `character_arc` block to their
paragraph (HJSON, alongside any other metadata):

```hjson
character_arc: {
  arc_type: positive_change      // flat | corruption | fall | disillusionment (+ aliases)
  desired_state_start: "Defers to her family in every decision."
  desired_midpoint_state: "Begins to act without asking permission."   // optional
  desired_state_end: "Chooses for herself, against her family's wishes."
}
```

The five `arc_type`s are the structural arcs (Scrooge / Atticus / Michael Corleone / Macbeth /
Javert); aliases like `redemption`, `growth`, `steadfast` map in, and any other string falls back to a
generic completeness probe. Only the start and end are required.

## The two passes

**Agency** is deterministic and zero-AI. For each chapter a character appears in, inkhaven scores
`active / (active + passive)` presence with a windowed name↔action-verb heuristic — a name *before* an
action verb (with no other character between) reads as active; a name *after* the verb, or the subject
of a passive construction, reads as passive — gated by NARR-1's passive detection. Five first-class
languages (EN/RU/DE/FR/ES), keyed off your project language.

**State extraction** is the only LLM pass. Chapter by chapter, with the previous chapter's summary fed
forward, it summarises what the character's behaviour, speech, and reactions *demonstrate* — observable
state only, never invented psychology — and flags whether something durably changed. Content-hash
lazy: editing one chapter re-extracts from there forward, nothing else. The chain is enriched with
DIALOG-1 utterance/hedge and NARR-1 interiority signals when those stores exist.

## Run it

```sh
inkhaven character refresh        # agency (instant) + state extraction (LLM)
inkhaven character check          # arc-completeness checks → exit 1 / 2 (CI gate)
inkhaven character plan           # Planning-Board coverage gaps (instant)
inkhaven character arc <name>     # the full report for one character
```

`check` runs four LLM checks per declared arc — start / midpoint / end alignment, and **arc earned**
(is the ending prepared, or merely asserted?) — plus a deterministic **stall** check (a long run of
unchanged chapters, with the chapter range and average agency). It exits **2** if the ending or the
earned-arc check fails, **1** on any other gap or stall. `plan` exits **1** if a declared arc has no
scene card, sits only in the first half, or never reaches the final act.

## In the TUI

- **`Ctrl+V Shift+N`** opens the **character arc view** for the nearest character (one named in the
  open paragraph, else the first tracked one): the declaration, the chapter state chain (✦ marks a
  change, with each chapter's agency), the arc checks, and any planning gaps. Read-only; `↑↓` scroll,
  `Esc` closes. Mnemonic: **N** for the arc, the bend (plain `n` is next-diagnostic).
- The **`Ctrl+B Shift+C`** review pass folds in the deterministic layers (agency + planning gaps +
  stalls) and surfaces the cached arc-check problems under the Output **`character`** category —
  zero-cost, no provider needed. The LLM checks stay explicit on the CLI.

## Notes

- **Scripting** — read-only `ink.char.{arc,stalls,checks,plan,refresh}` (the last two recompute only
  the deterministic cache).
- **Config** — the `char:` block tunes the stall threshold, agency windows, minimum chapters before
  LLM checks, the enrichment toggles, the language override, and `extra_action_verbs` for genre verbs
  the agency scorer should treat as deliberate action.
- **It never edits prose.** Findings are advisory; the cap informs, never blocks.
- **No new runtime crates; no new system books; no new `NodeKind`.** One new `.inkhaven/char.duckdb`,
  one `char:` config block, one new chord. New tutorial 99. Tests 2069 → 2103 (the deterministic
  surface — taxonomy, verbs, agency, store, planning gaps, prompt construction, JSON/check parsing —
  is unit-tested; the live LLM passes are integration-only, like Inner Editor's engage).
