# Voice & Style at Book Scale (CHORUS)
*(2.1, RFC CHORUS-1 — see [`PROPOSALS/CHORUS-1_PLAN.md`](PROPOSALS/CHORUS-1_PLAN.md)
and [`PROPOSALS/CHORUS-1_IMPL.md`](PROPOSALS/CHORUS-1_IMPL.md))*
Inkhaven already measures the **narrator's** voice book-wide — sentence rhythm,
lexical diversity, hedging, interiority (NARR-1, `inkhaven prose`, see
[`PROSE_VOICE.md`](PROSE_VOICE.md)). CHORUS measures the rest of what makes a
book's voice hold together:
> **NARR-1 profiles the narrator. CHORUS profiles the cast, enforces the rules of
> the game, and coaches.**
Three measurement pillars, synthesised by a new inner-family reader — all
**advisory**: CHORUS measures and reports, it never edits your prose.
---
## Pillar A — Character voice
Every character's dialogue is profiled with the *same* metric engine that
profiles the narrator, so a character's voice is measured on the same axes.
- **Voice fingerprints** — each character's attributed dialogue (from DIALOG-1)
run through the NARR-1 metrics: rhythm, lexical diversity, hedging, interiority.
- **The distinctiveness matrix** — do any two characters read *identically*? Each
voice is z-scored across the cast (genre-relative — the baseline is your own
book's spread) and compared; pairs that read alike are flagged. The headline
finding: *"Mara and Joren read identically."*
- **Per-character drift** — does a character sound like themselves across their
arc? Measured against their *first* chapter.
Sparse speakers (a handful of lines) are profiled but never *flagged* — CHORUS
reports a confidence and refuses to judge a voice it can't measure.
```
inkhaven chorus voices [--book NAME] [--character NAME] [--json]
```
A signature card per character (rhythm / diversity / hedging / interiority, a
confidence badge, and a Δ-from-cast-mean), followed by the distinctiveness
summary and any voice-drift rows. Deliberate look-alikes (twins, a uniform
chorus) are silenced with `chorus.distinct_ignore_pairs`.
---
## Pillar B — POV & tense discipline
The two classic discipline errors that survive line edits because they're
structural.
- **Head-hopping** — a named character other than the scene's POV shown accessing
their own inner life (`Joren wondered…` in a Mara-POV scene). A scene's POV is
**declared** with a `pov:<name>` paragraph tag, or inferred as the
most-mentioned character. Heuristic by necessity (there is no parser in the
tree): it catches interiority attributed to a *named* subject, not pronoun
antecedents (`she thought` where "she" isn't the POV needs antecedent
resolution CHORUS deliberately doesn't attempt).
- **Tense slips** — a manuscript that lapses out of its established tense. Each
narration sentence is classified past/present from copula/auxiliary anchors;
the scene's dominant tense is the majority; sentences that break it are flagged.
### Declaring a scene's POV
Tag any paragraph in the scene:
| `pov:Mara` | single POV — Mara. Anyone else's interiority is a leak. |
| `pov:first` | first person — any *named* character's interiority is a leak. |
| `pov:omniscient` (`pov:multi`) | deliberately multi-POV — head-hop off. |
Undeclared scenes infer the POV from mention counts.
### The tense gate — EN/DE/FR/ES, Russian excluded
Tense-slip detection covers **English, German, French, and Spanish** — languages
that share the "keep one narrative tense" convention, each with its own
copula/auxiliary anchors and past-suffix markers. **Russian is excluded by
design**: its narrative tense is governed by *aspect* — the historical present
and perfective/imperfective interleaving are legitimate devices, not slips — and
nothing in the tree models aspect, so a past→present heuristic would be *wrong*
for Russian. `chorus scan` says so plainly rather than false-flagging. (Character
voice and head-hop **do** work in Russian.)
```
inkhaven chorus scan [--book NAME] [--json]
```
Per-scene POV / head-hop findings and per-scene tense slips (or the Russian
"not analysed" notice), plus the register drift below.
---
## Pillar C — Register & diction
The narrator's **register** — formal or plain, contracted or measured, plain or
archaic — tracked per chapter so *drift* becomes visible ("the prose gets casual
in Act III"). A word-list bundle: contraction rate, archaism density, a
formality balance, and an English latinate-diction proxy. Chapters that drift
from the opening beyond `chorus.register_drift_threshold` are flagged (part of
`chorus scan`). Solid for EN/RU; sparser languages degrade to what their lists
cover rather than guessing.
---
## The Inner Stylist — the coach
The seventh inner-family reader (alongside the Editor, Socrates, Theologian,
Poet, Rigor, Grounding). It doesn't measure — it **synthesises**: it reads all
three pillars and turns the numbers into a few grounded **Praise / Note /
Concern** observations, and — on the slow track — LLM coaching in the
inner-family voice (*"I notice…"*, never a rewrite).
- **In the editor** — the review pass **`Ctrl+B Shift+C`** includes the Inner
Stylist (its observations land in the Output pane), and the family hub
**`Ctrl+B J → Y`** opens its overview: **`F`** synthesises to Output, **`E`**
engages the AI coach into the Thoughts pane, **`R`** opens the report dashboard.
- **On the CLI**:
```
inkhaven chorus stylist [--book NAME] [--json] # Praise/Note/Concern
inkhaven chorus stylist --coach # grounded LLM coaching
inkhaven chorus stylist --suppress <key> # silence a finding
inkhaven chorus report # the full dashboard
```
Each finding carries a stable **key**; `--suppress <key>` silences it for good
(persisted in `inner_stylist.db`, this reader's own store). `chorus report` is
the one-screen dashboard: the narrator profile, the cast voices +
distinctiveness, and the Stylist's synthesis together.
---
## Multilingual
CHORUS keys off the project language and is honest about coverage. Character
voice + distinctiveness + drift work in every language (rhythm/diversity) with
the language-sensitive axes filling in for EN/RU/DE/FR/ES. Head-hop reuses the
per-language interiority markers (**including Russian**). Register is solid for
EN/RU. The **tense** check covers EN/DE/FR/ES (Russian excluded), and it says so. The Inner
Stylist coaches in the book's language.
---
## Configuration
```hjson
chorus: {
distinct_threshold: 0.5 // RMS z-distance below which two voices read alike
distinct_ignore_pairs: [] // ["Mara|Joren"] — deliberate look-alikes
register_drift_threshold: 0.08 // register change vs ch.1 that flags a drift
}
stylist: {
enabled: true
session_budget: 0.15 // informative LLM budget (never blocks)
language: null // coaching-language override (default: project)
}
```
All knobs inform and cap — per Inkhaven's permissive principle, they never block.
---
## From a script
The deterministic surfaces are Bund words (all `-- list`/`-- dict`, zero-AI):
```
ink.chorus.voices ( -- list ) per-character voice fingerprints
ink.chorus.distinct ( -- dict ) the distinctiveness matrix
ink.chorus.drift ( -- list ) per-character voice drift
ink.chorus.headhops ( -- list ) POV / head-hop findings
ink.chorus.tense ( -- dict ) the tense summary (or the honest reason)
ink.chorus.register ( -- dict ) per-chapter register + drifts
ink.stylist.findings ( -- list ) the synthesised Praise/Note/Concern, minus suppressions
ink.stylist.suppress ( key -- ) silence a finding by its key
ink.stylist.suppressions ( -- list ) the silenced keys
```
(The knowledge graph has the parallel `ink.graph.*` surface — see
[`GRAPH.md`](GRAPH.md).) The LLM coaching is not a sync word; use
`chorus stylist --coach`.
## What CHORUS is *not*
- Not a style *corrector* — it flags, it never rewrites.
- Not a grammar checker — there's no parser; the tense check is an honest,
EN/DE/FR/ES heuristic (Russian excluded).
- Not a "good writing" score — it measures *consistency and distinctiveness*, not
quality. Statistical voice ≠ literary voice: every surface states its limits.
---
## Not yet wired
Tense covers EN/DE/FR/ES; other languages beyond Russian are simply not built
yet. A *blocking* Bund word for the LLM coaching (`ink.stylist.coach_blocking`)
could follow if wanted; the deterministic surface is complete.