Migration notes for akm v0.7.0

0.7.0 is the last pre-1.0 ship in the v1 cycle. It introduces the
proposal queue, agent reflection commands, the `lesson` asset type, the
`llm.features.*` per-call-site gates, and the first cut of `akm-bench`.
It also rolls in a batch of pre-prod hardening (security, UX, hygiene)
landed via PR #275.

The CLI surface, configuration schema, provider interfaces, and ref
grammar continue to match the v1 architecture spec
([`docs/technical/v1-architecture-spec.md`](../../technical/v1-architecture-spec.md)).
0.7.0 commits to maintaining those surfaces through the 0.8.x / 0.9.x
pre-releases — the formal freeze itself happens at 1.0 GA.

If you are coming from 0.6.x, the
[v1 migration guide](../v1.md) covers the per-surface delta and is the
canonical upgrade reference. This file is the executive summary of
what's new in 0.7.0.

For stash authors on the 0.7.x pre-release line: `.stash.json` remains supported
for compatibility in this release, but it is deprecated and will be removed in
v0.8.0. That timeline is intentional: during this aggressive pre-release
phase-out window, compatibility shims do not stay around until 1.0 unless they
still earn their cost. Prefer frontmatter for markdown assets and structured
code comments for scripts, and migrate any remaining `.stash.json` metadata
before taking the 0.8 upgrade.

## Major new surfaces in 0.7.0

### Proposal queue (`akm proposal *`) — new (#225, #226, #233)

All proposal-producing commands (`akm reflect`, `akm propose`,
`akm distill`, plus any plugin-emitted proposals) write through one
durable queue. The queue lives outside the asset tree so unaccepted
drafts never leak into search or commits. Promotion runs full validation
**before** routing through `writeAssetToSource()` — the same single
write path used by `akm remember` and `akm import`.

```sh
akm proposal list                       # list pending proposals
akm proposal show <id>                  # render one proposal
akm proposal diff <id>                  # diff vs. the live ref
akm proposal accept <id>                # validate, then promote
akm proposal reject <id> --reason "…"   # archive with reason
```

Multiple proposals for the same `ref` coexist without filesystem
collisions. Auto-accept is gated per-source via the source config
(`autoAcceptProposals: true`); the default is off and requires a
writable source. See v1 spec §11 and `docs/migration/v1.md`.

### `akm reflect`, `akm propose`, `akm distill` — new CLI surfaces (#225, #226, #227)

Three new commands produce proposals into the queue:

```sh
akm reflect [ref] [--task ...]           # reflection proposals
akm propose <type> <name> --task "..."   # generation proposals
akm distill <ref>                        # bounded LLM → `lesson` proposal
```

`reflect` and `propose` shell out via the agent CLI (`agent.*` config,
spec §12) and write **only** to the proposal queue — they never mutate
live stash content. `distill` is the canonical bounded in-tree LLM call
gated behind `llm.features.feedback_distillation`. All three emit usage
events (`reflect_invoked`, `propose_invoked`, `distill_invoked`). See
v1 spec §11.3 and §12.4.

### `lesson` asset type — new (#227)

`lesson` is a first-class well-known type with required frontmatter
`description` and `when_to_use`. Lessons are stored under
`lessons/<name>.md` in the working stash, parallel to `memories/`.
Normally produced by `akm distill <ref>` as a `proposed`-quality
proposal and promoted via `akm proposal accept`. Direct authoring via
`akm import` and `akm remember`-style flows is also supported. See v1
spec §13.

### `llm.features.*` map with default-false gates — new (#227)

Every bounded in-tree LLM call site is gated behind exactly one feature
flag. All defaults are `false` so adding the schema is a non-event
until the user opts in. Seven keys ship in 0.7.0:

| Key | Use site |
| --- | --- |
| `curate_rerank` | LLM rerank in `akm curate` |
| `tag_dedup` | LLM tag dedup during indexer enrichment |
| `memory_consolidation` | `akm remember --enrich` consolidation |
| `feedback_distillation` | `akm distill <ref>` |
| `embedding_fallback_score` | scorer fallback when embeddings unavailable |
| `memory_inference` | indexer split of pending memories into atomic facts |
| `graph_extraction` | indexer entity/relation extraction → SQLite graph tables |

Every gated call site uses `tryLlmFeature(feature, config, fn, fallback)`
from `src/llm/feature-gate.ts`. The wrapper guarantees:

- **Disabled** → `fallback` is returned without ever calling `fn`.
- **Throw** → the error is swallowed; `fallback` is returned.
- **Timeout** → a 30-second hard timeout (override via `timeoutMs`)
  raises `LlmFeatureTimeoutError`; `fallback` is returned.

Failure events surface through an optional `onFallback` sink so callers
can emit a structured `warnings` entry. See v1 spec §14.

### `quality: "proposed"` and `--include-proposed` — new

`SearchHit.quality` is an open string set with three well-known values:
`"generated"`, `"curated"`, and `"proposed"`. The first two are
included in default search; `"proposed"` is **excluded from default
search** and surfaces only via `akm search ... --include-proposed` or
via `akm proposal *`. Unknown values parse-warn-include — they remain
searchable so plugin authors can introduce new values without crashing
the indexer. `SearchHit` gains optional `quality?` and `warnings?`
fields. See v1 spec §4.2.

### `akm-bench` v1 — new (#234, PRs #266 / #268 / #269)

Bench grows beyond the 0.6.x smoke run into a paired-utility framework:

- **Track A — paired noakm/akm runs.** For each task, bench runs an
  agent CLI twice (without and with akm available), captures
  per-tool-call utility, and emits a comparable score pair.
- **Track B — registry attribution.** Utility deltas are mapped back
  to specific `[origin//]type:name` refs so operators can see which
  assets actually contributed.
- **`akm-bench compare`** aggregates paired runs into a delta report.
- **`akm-bench attribute`** surfaces the per-ref attribution report.
- **`akm-bench evolve`** is a stub for the closed-loop evolution
  workflow that lands in 0.8.

The bench technical reference lives in
[`docs/technical/benchmark.md`](../../technical/benchmark.md).

### Removed legacy fields

- The legacy registry boolean `curated` is removed. Legacy v2 index
  JSON parses and silently ignores it. Renderers no longer surface a
  `curated` column; the per-asset `quality` field replaces it.
  Publishers do not need to migrate existing JSON.
- Earlier 0.7.x pre-release work (#220–#223) finalised the registry
  curation surface removal, classification pipeline rewrites, and
  error envelope shape that 0.7.0 ships. Operators upgrading from a
  0.6.x baseline should read [`docs/migration/v1.md`](../v1.md) for
  the per-surface migration recipe.

### CLI surface as of 0.7.0

```
add | remove | list | update | search | show | clone | index | setup |
remember | import | feedback | info | curate | workflow * | vault * |
wiki * | enable | disable | completions | upgrade | save | help |
hints | config * | registry * |
agent | reflect | propose | proposal * | distill
```

This is the surface 0.7.0 commits to maintain through 0.8.x / 0.9.x.
Renaming or removing any of these commands at 1.0 GA would be a major
version bump.

## Post-0.7.0 additive surfaces

These landed after the 0.7.0 cut without changing the existing command grammar:

- `akm import <url>` now fetches one HTTP/HTTPS URL, converts it to markdown,
  and writes it into `knowledge/` using a URL-path-derived default name.
- `akm wiki stash <name> <url>` now fetches one HTTP/HTTPS URL, converts it to
  markdown, and writes it into `wikis/<name>/raw/`.
- Both flows are one-shot ingest only: they do not register a persistent
  website source and they do not crawl linked pages.
- Website source sync (`akm add <url> --provider website`) and one-shot URL
  ingest now share the same `src/sources/website-ingest.ts` module for URL
  validation, fetch/convert, and mirror generation behavior.

## Pre-prod hardening (PR #275)

PR #275 batched five issues plus the bench tmp follow-up that operators
should be aware of:

### Security

- **#270 — git message sanitization.** Commit messages and remote URLs
  written by akm are sanitized to prevent shell-substitution and
  control-character injection through user-supplied content.
- **#271 — bench env isolation.** `akm-bench` runs each agent invocation
  in a scrubbed environment so host secrets do not leak into bench
  transcripts or paired-run logs.
- **#272 — LLM body redact + npm tarball host validation.** Outbound
  LLM request/response bodies are redacted in error reporting before
  surfacing to stderr or warnings, and `akm add npm:…` validates the
  tarball download host against the configured npm registry rather
  than blindly following arbitrary `dist.tarball` URLs.

### UX

- **#273 — workflow noise gate, sources deprecation warn, setup
  `--help`.**
  - `akm workflow next/complete/status` no longer print spurious
    progress noise on quiet runs.
  - Configs still using the legacy `stashes[]` key emit a single
    deprecation warning per process (was: per call site).
  - `akm setup --help` now renders the same help block as `akm setup`
    with no args plus the documented agent-detection summary.

### Hygiene

- **#274 — tsconfig + HF pin + shapes throw.** `tsconfig.json` now
  includes `tests/` so `bunx tsc --noEmit` covers test files. The HF
  embeddings model is pinned to a specific revision to avoid silent
  upstream changes. The output-shape registry now throws on a missing
  shape rather than silently `JSON.stringify`-ing.

### Bench

- **#276 — bench tmp redirect.** `akm-bench` no longer writes scratch
  state under `/tmp`; everything lands under the AKM cache dir
  (`~/.cache/akm/bench/`) so cleanup is bounded and CI sandboxes that
  ban `/tmp` writes work out of the box.

## Surfaces 0.7.0 commits to maintain (toward 1.0 GA)

These are the contract surfaces 0.7.0 ships and intends to carry
forward through the 0.8.x / 0.9.x pre-releases into 1.0 GA. They are
not yet frozen — the freeze happens at 1.0 — but operators authoring
against 0.7.0 should expect them to remain stable through the final
pre-release cycle. The full list lives in v1 spec §9.

1. `writable` defaults to `true` on `filesystem`, `false` otherwise.
2. Registry results are off by default in `akm search`; pass
   `--include-registry` to merge them. Registry hits never land in
   `hits` — they live under `registryHits`.
3. Write target resolves as `--target` → `defaultWriteTarget` →
   working stash → `ConfigError`.
4. `writable: true` is rejected on `website` / `npm` at config load.
5. `SearchHit.score` is `[0, 1]`, higher = better. One scoring
   pipeline for all indexed content.
6. Asset refs are `[origin//]type:name`. No URI schemes.
7. `quality: "proposed"` is excluded from default search.
8. External agents are CLI shell-out only. The in-tree LLM stays
   bounded and stateless, gated per call site by `llm.features.*`.

## Manual actions

None for users on a 0.6.x or earlier 0.7.x pre-release with no `agent`
or `llm.features` blocks set. Everything new is opt-in.

If you want to use the new surfaces:

```sh
akm setup                                  # detects installed agent CLIs;
                                           # persists `agent.default`
akm config set llm.features.feedback_distillation true
akm distill memory:my-debugging-notes      # produces a lesson proposal
akm proposal list
akm proposal accept <id>
```

## Full migration guides

- [v1 migration guide](../v1.md) — per-surface delta from any 0.6.x
  baseline. The canonical reference for upgrading.
- [v0.5 → v0.6](../v0.5-to-v0.6.md) — the older terminology cut and
  registry schema v3.
- [v1 architecture spec](../../technical/v1-architecture-spec.md) —
  the architecture contract that 0.7.0 commits to maintain through
  1.0 GA.
