# Inkhaven 1.3.35 — Keeping count

_Writing goals were always **~90% built** — the streak engine, per-book pacing,
daily targets, status-ladder, active-time, and the `Ctrl+V g` progress modal all
shipped long ago. This release finishes the job: it **surfaces** goals in the
terminal, **extends** the streak to a lifetime record, and makes goals **editable
in-app** without leaving the keyboard — each a pure addition over existing
infrastructure, zero new dependencies._

_Plan: [GOALS_PLAN.md](../PROPOSALS/GOALS_PLAN.md) · Roadmap:
[ROADMAP-1.4.0.md](../PROPOSALS/ROADMAP-1.4.0.md)_

## `inkhaven goals` — the terminal surface

Every other analytic — `cost`, `check`, `stats`, `concordance` — had a terminal
counterpart; the writing-progress view did not. **`inkhaven goals`** prints the
same picture the `Ctrl+V g` modal shows, reusing the *exact* `build_snapshot`
engine (no goal logic duplicated):

- project + per-book word totals,
- today vs `goals.daily_words` with a usage bar,
- current streak (with grace) **and lifetime best**,
- per-book required pace + days-to-deadline,
- this week's status-ladder promotions,
- active time today / week, and a 30-day sparkline.

Read-only; it records nothing and changes no config — handy for scripts, cron
digests, or a glance without opening the TUI.

## The streak you keep — lifetime best + milestones

The streak figure only ever knew the trailing run, and the heatmap's "longest" was
**window-bound** — it forgot. Now the snapshot computes a true **all-time best**
over the project's full writing history (same grace rule), shown as `· best Nd` in
both `inkhaven goals` and the progress modal whenever it beats the current run.

And crossings are worth marking: a new Bund hook **`hook.on_streak_milestone
( milestone_days -- )`** fires the first time the current streak crosses **7 / 30 /
100 / 365** days upward (the highest newly reached). Reopening a project already
past a milestone doesn't re-fire. In keeping with the house rule, it's an
**informative celebration — never blocking**. Documented in the Bund tutorial + the
cheat sheet.

## Editing goals in-app — and writing them back safely

Setting a goal used to mean hand-editing `inkhaven.hjson`. Now press **`e`** inside
the `Ctrl+V g` progress modal to open the **goals editor**: adjust
`goals.daily_words`, `active_minutes_daily`, and `streak_grace_per_week` inline
(`↑↓` field · digits · `Enter` save · `Esc` cancel). The change applies to the live
config immediately — no restart.

The write is the careful part. `Config::save` would full-rewrite the file and
**drop every comment** — unacceptable for a hand-tuned config. Instead the commit
routes through Inkhaven's existing **comment-preserving surgical-splice** pipeline:

- a **versioned backup** of the pre-patch file lands in `.config-backups/` first,
- only the **changed** keys are spliced (present) or appended (absent),
- the file is written **atomically** (`.tmp` + rename).

Every comment, every unrelated stanza, every unknown field survives byte-for-byte.
This is the **permissive principle** in practice: a writer's own config is never
clobbered, and there is always a backup.

## Housekeeping

Two never-used symbols (`ai::usage::uninstall`, `store::SYSTEM_TAG_INTENT`) were
removed to clear the build warnings. Clean build.

## Surfaces & docs

- **TUI** — `Ctrl+V g` now shows lifetime best; press `e` for the goals editor.
- **CLI** — `inkhaven goals`.
- **Hook** — `hook.on_streak_milestone`.
- **Docs** — KEYBINDING (the `Ctrl+V g` row + `e` editor), quick reference, Bund
  tutorial + cheat sheet.

## Dependencies & compatibility

**No external application or binary dependencies; no new runtime crates.** All three
increments are additions over the existing progress engine and the config-TUI's
splice pipeline. No on-disk shape moved; the new `goals.*` keys are the same ones
the config already understood. Tests 1804 → 1813.
