# Inkhaven 1.2.16 — Author intelligence + polish

Status: **proposal**, written 2026-06-01.
Cycle target: 6-8 weeks.
Tests target: `695 → ~770` (+75 new regression
tests across the 11 sub-phases).

## 0. Why this cycle

1.2.15 was the stability + security release.  The
infrastructure underneath inkhaven is now durable
(atomic writes everywhere, panic-survivable
crashes, background health monitor, path-traversal
sandboxed), but the author-visible surface hasn't
moved since 1.2.14.  1.2.16 turns that
infrastructure into author value.

Three currents flow through this cycle:

1. **Author intelligence.**  A unified
   *manuscript intelligence dashboard*
   (`Ctrl+V Shift+J`) synthesises every metric
   inkhaven has been collecting since 1.2.5
   (word count, streak, structure, pacing,
   rhythm, POV, thread health, comments digest,
   AI-critique summary) into one pane.  This is
   the cycle's headline.

2. **Deepening, not broadening.**  Polish
   carryovers from 1.2.13 (language CLI
   exports), 1.2.14 (snippet pickers), 1.2.15
   (deferred DB-side health checks, backup +
   disk-space safety rails).  Make what's there
   work better; don't add new system books.

3. **Scriptability + worldbuilding.**  New
   `ink.*` stdlib categories (`ink.review.*`,
   `ink.thread.*`, `ink.workflow.*`) give power
   users a real automation surface on top of the
   1.2.15 trust gate.  Plot-mining checks +
   worldbuilding-consistency scans extend the
   1.2.14 threads doctor into broader narrative
   audit.

## 1. Themes

### Theme T — Tantivy correction

Small documentation fix landing first.  The 1.2.15
release-cycle docs (release notes, tutorial 52,
the SECURITY_WARNING audit findings) referenced
Tantivy as the full-text-search backend.  In
practice, inkhaven's `Store::search_text` is
**semantic vector search via HNSW + fastembed** —
there is no Tantivy in the dep tree.  Single
commit; corrects every reference, adds a one-line
note in MAINTENANCE.md clarifying the search
model.

### Theme P — Polish carryovers

Four sub-phases (P1 + P4-pre + P4 + P5 + P6),
all small-to-medium.

### Theme I.4 — Bund stdlib expansion

Three new `ink.*` categories: review tools,
thread manipulation, workflow chaining.  Pairs
with the 1.2.15 trust gate (H.1) — only trusted
projects gain the new surface.

### Theme A.2 — Manuscript intelligence dashboard

Headline.  One pane unifying everything inkhaven
already knows about the project.

### Theme A.6 — Plot mining

Extends 1.2.14 threads doctor with deterministic
"dropped character" / "unresolved tension" /
"pacing collapse" detectors.

### Theme A.5 — Worldbuilding consistency pack

One genre-adjacent specialisation: cross-system
consistency scan (Characters / Places / Artefacts
/ Language) for contradictions.  Mystery +
historical packs deferred to 1.2.17.

### Theme I.1 — Performance pass

Last phase of 1.2.16.  `cargo flamegraph` first,
targeted fixes second.  Focused on large-project
handling (10K+ paragraphs).

## 2. Theme T — Tantivy correction

### 2.1 Sites to fix

* `Documentation/RELEASE_NOTES/1.2.15.md` —
  Theme H implementation log mentions
  "Tantivy index integrity" as a deferred
  check.  Change to "Tantivy was never in the
  dep tree; the equivalent FTS layer would be
  a new index — out of scope".
* `Documentation/Tutorials/52-health-and-doctor.md`
  — mentions Tantivy index parity as a
  deferred check.  Same fix.
* `Documentation/PROPOSALS/1.2.15_PLAN.md` —
  §3.2 health-check table includes a "Tantivy
  index integrity" row.  Change to "(no FTS
  layer; semantic search via HNSW)".
* `Documentation/SECURITY_WARNING.md` — §4.3
  "Design Properties" — clarify the search
  model in plain English.
* `Documentation/MAINTENANCE.md` — add a
  one-paragraph "Search model" section
  explaining DuckDB (metadata + blobs) + HNSW
  (semantic search via fastembed).

### 2.2 Test budget

0 — pure documentation.

## 3. Theme P — Polish carryovers

### 3.1 P5 — Language-book CLI exports (D.2 carryover from 1.2.13)

Three new `inkhaven language export` formats +
three new headless CLIs.

* `--format grammar` — printable grammar
  reference.  TOC + chapter per rule category +
  examples table + cross-references.  Output
  via the typst in-process compiler.
* `--format phrasebook` — Sample-texts chapter
  rendered as a two-column phrasebook (gloss
  left, working language right).
* `--format csv` — round-trip-compatible CSV
  that the existing `--import` path can
  re-ingest.  Closes the import/export loop.
* `inkhaven language test <name>` — headless
  roundtrip-translation drift CLI for CI.
  Walks a corpus of sample texts through
  `Ctrl+B Q` → `Ctrl+B Shift+Q` and reports
  drift > configurable threshold.
* `inkhaven language translate <language>
  <text>` — headless flavour of the in-TUI
  chord.  Shell-pipe friendly.
* `inkhaven language define-rule <language>
  <rule_id> --category <cat>` — open the rule
  template in `$EDITOR` for hand-editing.

Test budget: ~8 (one per export format roundtrip
+ a `language test` drift detector test + CLI
smoke tests).

### 3.2 P6 — Snippet picker placeholders + `bund:` prefix (Q.2 carryover from 1.2.14)

Three picker-based placeholders and one Bund-VM
prefix.  All four need the **async snippet state
machine** that wasn't built in 1.2.14.

* `{char_lookup}` / `{place_lookup}` /
  `{artefact_lookup}` — open the corresponding
  system-book picker; substitute the chosen
  entry's display name on commit.
* `bund:` prefix — when the snippet body starts
  with `bund:`, the rest is interpreted as a
  Bund-VM program; its top-of-stack string
  becomes the expansion.

Implementation lift: new `Modal::SnippetPicker`
variant that wraps an existing
`{char,place,artefact}` picker, returns the
chosen entry to a continuation callback that
completes the expansion.  Bund-VM evaluator
called synchronously (Bund is fast); error
falls back to literal expansion of the source
text.

Test budget: ~8 (one per placeholder + one for
the `bund:` prefix + Bund-error fallback + the
async-state-machine state transitions).

### 3.3 P4-pre — Cross-thread `Store` sharing

Prerequisite for P4 (DB-side health checks) and
for I.4's future hook flow.  Today `Store` is
held by App; the health monitor runs in a
separate tokio task and can't borrow `&Store`.

Options surveyed in §7 of the 1.2.15 proposal:

* `Arc<RwLock<Store>>` — simple, the standard
  pattern.  Reads share, writes exclude.
* IoC channel — TUI asks for check, monitor
  task accumulates pending requests.  More
  ceremony, no real benefit for the
  single-user case.

Going with `Arc<RwLock<Store>>`.  Adds one
field to `App`; monitor task takes an
`Arc<RwLock<Store>>` clone at spawn time.
Tests pin the parity of reads under contention.

Test budget: ~3 (clone semantics, concurrent
read parity, no deadlock under nested-lock
scenarios).

### 3.4 P4 — DB-side health checks

Five real checks landing on top of the H.1-H.3
scaffold.  Each runs at its own cadence, emits
the same `HealthEvent` enum, logs to
`.inkhaven/health.log` like the existing checks.

| Check | Cadence | Auto-repair? |
|-|-|-|
| DuckDB `PRAGMA integrity_check` | 15 min | No — Critical, surface to user |
| HNSW vector parity vs. DB row count | 15 min | Yes — re-embed missing rows |
| Open paragraph textarea vs. on-disk file | 30 sec | Yes via `editor.autosave_resolution_policy` |
| Tree parent-pointer integrity | 30 sec | Yes — re-link by slug |
| Disk free % (< 10 % → Critical) | 5 min | No |

Note: HNSW + textarea + tree checks need access
to the project Store via the P4-pre sharing
work.  Disk free uses a no-deps approach
(walking the filesystem statvfs equivalent via
`std::fs` — available on stable Rust without
sysinfo).

Test budget: ~12 (each check's clean / dirty
case + the auto-repair where applicable).

### 3.5 P1 — Backup + disk safety rails

Two pieces:

* **Disk-space pre-flight** before save /
  assemble / backup operations.  Refuse to
  start under critical-low conditions (< 50 MB
  free + the operation needs > free); fall
  through gracefully with a status message
  instead of trapping a write error half-way.
* **Amber backup-freshness chip** — pair with
  the 1.2.15 health monitor's hard-warn check.
  Show a status-bar chip when the newest
  backup crosses 50 % of `backup.max_age`
  (configurable as `backup.amber_threshold:
  0.5` default).  Gives the user visibility
  BEFORE the hard warning fires.

(Git portion explicitly dropped: out of scope
for 1.2.16 per the user's direction.)

Test budget: ~4 (pre-flight refusal, pre-flight
allow, amber-threshold detection, chip render).

## 4. Theme I.4 — Bund stdlib expansion

Three new categories, gated by the existing
default-deny policy + 1.2.15 trust gate.

### 4.1 `ink.review.*` (REVIEW_WRITE)

* `ink.review.add_comment` — programmatic
  comment creation; takes paragraph UUID +
  start_char + end_char + body + category.
* `ink.review.resolve` — close a comment by ID.
* `ink.review.list` — return every comment in
  the project as a Bund map.

Category default-deny.  Enables: prepare a
"reviewer summary" script that walks the
manuscript and inserts structural-feedback
comments en masse.

### 4.2 `ink.thread.*` (STORE_WRITE — existing category)

* `ink.thread.add_waypoint` — append a
  waypoint to a thread chapter.
* `ink.thread.link_paragraph` — link a waypoint
  to a manuscript paragraph.
* `ink.thread.list` — return every thread as a
  Bund map.

Existing STORE_WRITE category — already
default-deny — so no new policy needed.

### 4.3 `ink.workflow.*` (no new category)

* `ink.workflow.chain` — sequence of
  `(prompt, scope_chord, apply_action)` tuples
  applied in order.  Each step waits for the
  previous AI inference to complete (`ink.ai.
  poll`) before firing the next.  Lets a power
  user encode "for every paragraph in chapter
  3, run grammar-check + apply" as a script.

Pure orchestration over existing `ink.ai.*` —
no new permissions.

Test budget: ~8 (one per word + one workflow-
chain integration test).

## 5. Theme A.2 — Manuscript intelligence dashboard

The headline.  `Ctrl+V Shift+J` ("Journal") opens
a synthesis pane showing every metric inkhaven
has collected since 1.2.5, in one place.

### 5.1 Layout

```text
 ┌ Journal — manuscript intelligence ─────────────────────────────┐
 │                                                                │
 │  Word count                                                    │
 │    today:   1247   week:  8430   total:  78912                 │
 │    target:  80000  remaining: 1088   ETA: 2026-06-15           │
 │    streak:  ✓ 7 days   longest: 23                             │
 │                                                                │
 │  Structure                                                     │
 │    books: 1  chapters: 12  scenes (paragraphs): 142            │
 │    avg chapter:  6580 words   stdev: 1240 (CV 19%)             │
 │    pacing:  steady  (chapters: 6/12/12/8/15...)                │
 │                                                                │
 │  Prose                                                         │
 │    POV:  Aerin (47% mentions in last chapter)                  │
 │    rhythm:  varied  (cv 64%)                                   │
 │    filter words today:  3  show-don't-tell flags:  2           │
 │                                                                │
 │  Threads                                                       │
 │    active: 6   completed: 2   dormant: 1 (Trial arc)           │
 │                                                                │
 │  Comments                                                      │
 │    open: 4 (3 structural · 1 prose)   resolved this week: 7    │
 │                                                                │
 │  Recent AI critique (last paragraph)                           │
 │    "The dialogue between Aerin and her father is               │
 │    over-explanatory; the audience already knows..."            │
 │                                                                │
 │  ↑↓ scroll · e export to markdown · Esc close                  │
 └────────────────────────────────────────────────────────────────┘
```

Sections collapse-able (Space toggles); state
persisted in `.session.json`.

### 5.2 Data sources

Everything in §5.1 is data inkhaven already
collects.  This phase is composition + render,
not measurement.

| Section | Source |
|-|-|
| Word count | `progress::aggregates` |
| Structure | `Hierarchy::flatten` + word counts per branch |
| Pacing | chapter-word-count vector + CV |
| POV | `pov_tracker::compute_pov_chip` |
| Rhythm | `sentence_rhythm` |
| Filter words | `style_warnings::filter_word_count_today` (new helper) |
| Threads | walk Threads system book |
| Comments | walk `.comments.json` sidecars |
| Recent AI critique | `ai_history` last entry's first ~100 chars |

### 5.3 Export

`e` from the modal serialises the snapshot to
`<project>/journal-<UTC>.md` — markdown the user
can paste into a weekly check-in or share with
an editor.

### 5.4 Daily auto-summary

Optional HJSON knob `journal.daily_summary: true`
(default false).  When set, the same snapshot
appends to `.inkhaven/journal.log` once per day
on first project open.  Gives the user a
chronological project record.

Test budget: ~10 (per-section formatter, full-
dashboard composition, export roundtrip, daily-
summary append + dedup, scroll/collapse state).

## 6. Theme A.6 — Plot mining

Extends the 1.2.14 threads doctor with broader
deterministic narrative-audit checks.

### 6.1 Detectors

* **Dropped character** — a character mentioned
  in the first 30 % of the manuscript who
  doesn't appear again.  Walks the Characters
  lexicon + paragraph mentions; flags
  characters whose last-mention chapter index
  is below `total_chapters * 0.7`.
* **Unresolved tension** — paragraphs ending in
  question marks / opener clauses ("she
  realised...") that don't have a follow-up
  resolution-style paragraph within N chapters.
  Heuristic — false positives expected; the
  finding's confidence is exposed in the doctor
  output.
* **Pacing collapse** — chapter-word-count CV
  spike (one chapter 3+ stdev from the trailing
  mean).  Could be intentional (an epilogue);
  flagged as Info, not Warning.
* **Stalled thread** — already in the 1.2.14
  thread doctor; surfaced here too for unified
  reading.

### 6.2 Integration

These slot into `inkhaven doctor --scan` as new
classes (kebab-case slugs `dropped-character`,
`unresolved-tension`, etc.).  Severity defaults
to Info (this is structural feedback, not data
loss).  No autofix — these are author-judgment
findings.

### 6.3 The TUI surface

The `Ctrl+B Shift+0` doctor panel inherits the
new classes automatically (they're just more
findings).  An additional "narrative" filter
button (`n` inside the panel) shows only
narrative-audit findings.

Test budget: ~10 (each detector's positive +
negative case + the doctor-panel filter).

## 7. Theme A.5 — Worldbuilding consistency pack

One genre-adjacent specialisation.  Mystery
(A5.1) and historical-fiction (A5.3) packs
deferred to 1.2.17.

### 7.1 Cross-system consistency scan

Walks Characters, Places, Artefacts, Language
entries looking for contradictions in their
metadata + their mentions in prose.

* **Numeric contradictions** — a Character with
  `age: 23` mentioned as "twenty-six" in a
  paragraph; a Place with `population: 5000`
  described as "the largest city, half a
  million souls".  Detected via simple
  number-extraction + comparison.
* **Spatial contradictions** — a Place with
  `north_of: "the river"` described as "south
  of the river" elsewhere.  Walks adjective
  declarations in metadata vs. prose-extracted
  prepositional phrases.
* **Naming inconsistency** — a Character named
  "Aerin Stormbringer" referenced as "Aerin
  Stormbreaker" once.  Edit distance > 0,
  surface-form clustering.

### 7.2 Anachronism overlay (deferred from A5.3 historical pack)

* HJSON knob `project.era` (optional).
* Wordlist of "post-epoch" vocabulary
  configurable via a Bund script that returns
  the list (so users can supply their own).
* Style-warning-style inline overlay when prose
  uses post-epoch vocabulary, toggled by the
  existing `Ctrl+B Shift+F` style-warnings
  chord.

### 7.3 Glossary chip

Status-bar chip with cumulative count of
distinct Characters / Places / Artefacts /
Language entries — a sanity check on
worldbuilding density (if you're 30 chapters in
with only 4 named characters, you might want
to know).

Test budget: ~12 (each contradiction class +
anachronism overlay + glossary chip).

## 8. Theme I.1 — Performance pass

Last phase of 1.2.16.  Two passes:

### 8.1 Profiling

`cargo flamegraph` runs against a synthetic
large project (10K paragraphs, generated by a
new `inkhaven dev generate-fixture <path>
--paragraphs 10000` helper) for these
benchmark scenarios:

* Project open from cold cache
* Full search (semantic)
* Doctor scan
* Save current paragraph
* Tree-pane scroll through 1000 rows

### 8.2 Targeted fixes

Driven by the flamegraph results.  Likely
candidates:

* **Lazy tree row materialisation** — currently
  `Hierarchy::flatten` builds every row; only
  materialise visible rows + a buffer.
* **Background embedding refresh** — re-embed
  on a separate tokio task so save returns
  immediately.
* **DuckDB write batching** — coalesce
  short-burst writes into single transactions.

Test budget: ~8 (regression tests pinning the
fixture-based latencies — fast enough that
flakes are unlikely; CI hard-failures on >
2× regression).

## 9. Phased rollout

| Phase | Scope | Tests |
|-|-|-|
| **T** | Tantivy correction (docs only) | 0 |
| **P5** | Language CLI exports | 8 |
| **P6** | Snippet pickers + `bund:` prefix | 8 |
| **P4-pre** | `Arc<RwLock<Store>>` sharing | 3 |
| **P4** | DB-side health checks (5 checks) | 12 |
| **P1** | Disk-space pre-flight + amber backup chip | 4 |
| **I.4** | Bund stdlib expansion (review/thread/workflow) | 8 |
| **A.2** | Manuscript intelligence dashboard | 10 |
| **A.6** | Plot mining detectors | 10 |
| **A.5** | Worldbuilding consistency pack | 12 |
| **I.1** | Performance pass + targeted fixes | 8 |

Total target: **83 new tests** on top of 695 →
~778.

## 10. Risks + open questions

* **A.2's "AI critique summary" section is just
  the last AI history entry's first ~100
  chars.**  If history is empty or stale, this
  cell shows "(no recent critique)".  Not
  worth doing anything cleverer for the first
  cut.

* **P6's async snippet state machine adds a
  modal-state transition we haven't had
  before.**  The existing snippet pipeline is
  fully synchronous.  Need to be careful that
  expanding a snippet, popping a picker,
  cancelling the picker, and re-typing don't
  leave the editor in a half-substituted
  state.  Regression test: pop picker → Esc →
  the trigger text remains in the buffer
  (no half-expansion).

* **A.6's "unresolved tension" detector is a
  heuristic.**  Will surface false positives.
  Severity = Info, not Warning, so it doesn't
  trip CI gates; confidence value exposed in
  the doctor output so users can filter.

* **A.5's numeric-contradiction detector
  requires reasonable number extraction from
  prose** ("twenty-six", "5,000", "half a
  million").  We have a number-words crate in
  the transitive tree?  If not, add `numerics`
  or implement a small extractor (English-only
  for now; document the limitation).

* **I.4's `ink.workflow.chain` is the first
  Bund word that does async orchestration.**
  Today the VM is fully sync.  Either we wrap
  the inference call in a `block_on` (risk:
  pause the UI for the duration; acceptable for
  scripted workflows since the user explicitly
  invoked them) or we add a yield mechanism
  (bigger change).  Start with `block_on`;
  document the foreground-blocking behaviour.

* **I.1's lazy tree row materialisation
  interacts with the visited-history +
  bookmark + paragraph-cursor caches.**  Each
  is keyed by UUID, so as long as we never
  return a row whose UUID isn't in the
  hierarchy, those should be safe.  Add a
  property test.

## 11. Out of scope

* **TTS work.**  Per the user's direction:
  Piper replacement is the eventual path
  (current `tts-rs` quality is poor) but
  deferred to 1.2.17+.  `Ctrl+B S` and
  `Ctrl+B Shift+R` continue to work as today.

* **M1 (action-ring detail hygiene) + M3
  (script-modal phishing prefix).**  Per the
  user's direction — both small enough to ride
  the next docs commit but deferred from the
  proposal scope here.

* **A.4 — local-model maturity** (provider
  routing, inference cache, Ollama fine-tune).
  Deferred to a future cycle.

* **A.1 — editor mode / collaboration.**
  Single-user constraint.

* **I.2 — web/HTML export.**  Out of scope per
  typst-first roadmap.

* **I.3 — multi-process safety.**  Single-user
  constraint.

* **Mystery + historical-fiction genre packs
  (A.5.1, A.5.3).**  Deferred to 1.2.17 to keep
  1.2.16 worldbuilding-pack-only.

* **Git integration.**  Out of scope per the
  user's direction.

## 12. Recommendation

Ship in this order:

1. **T** first — small docs commit; corrects
   the released 1.2.15 documentation.
2. **P5 + P6** next — clean carryovers, ship
   fast.
3. **P4-pre then P4** — `Arc<RwLock<Store>>`
   unlocks the deferred health checks.
4. **P1** — small safety rails, no
   dependencies.
5. **I.4** — opens the scriptable surface for
   power users.
6. **A.2** — the headline; benefits from I.4
   for the `ink.workflow.*` orchestration that
   the dashboard's "export to markdown" can use.
7. **A.6** — narrative audit detectors on top
   of the doctor scan.
8. **A.5** — one worldbuilding-consistency
   pack.
9. **I.1** — performance pass at the end.

Mid-cycle cut points: if scope runs long, defer
**A.5** (one pack to 1.2.17 is reasonable) or
**A.6's "unresolved tension" detector** (the
heuristic is the part most likely to need
iteration after real-world testing).

The cycle's exit criteria:

* Manuscript intelligence dashboard renders in
  < 200 ms for a 1000-paragraph project.
* Every doctor scan class (including the new
  A.6 + A.5 detectors) ships with an `--autofix`
  path or an explicit "no autofix —
  author-judgment finding" note.
* All five DB-side health checks land + pass
  their regression tests under concurrent
  Store access.
* P4-pre's `Arc<RwLock<Store>>` introduces zero
  deadlocks under the property-test fuzz.
* Performance pass produces a measurable
  improvement on at least three of the five
  benchmark scenarios.

When all five hold, we cut 1.2.16.
