# Plans History Durability Design

audience: AI coding agents first.

## Goal

Keep v2 run observability durable after supervision cleanup, quarantine, reboot, or GC. Never admit historical records to reconcile/watchdog control.

## Architecture

- Persist observer metadata in `~/.harness/history/v2/runs/<runId>.json`.
- Keep live-control records exclusively in `~/.harness/state/v2/runs/<token>.json`.
- Make control API `/runs` read durable history only.
- Seed durable history idempotently from legacy `~/.harness/v2/runs`, preserved quarantine history records, and `runstate/v2` journals under known project roots.
- Register every new run in durable history before execution.
- Keep reconcile/watchdog readers unchanged at canonical active-control directory and require `validRecord`.

## Durable History Contract

History record shape:

```text
{ runId, slug, repoRoot, planPath, preset?, account?, startedAt? }
```

- Validate absolute `repoRoot` and `planPath`; validate non-empty `runId` and `slug`.
- Write atomically and idempotently by `runId`.
- Never delete history during coordinator finalization or supervision GC.
- Ignore malformed history records individually; retain valid sibling records.
- Never import a control record directly as a displayed run. Journal discovery may create history only when a valid plan is resolved.

## Journal Import

- Discover `runstate/v2/*/*/events.ndjson` below project roots learned from legacy history, control records, quarantine records, and default `~/Projects`.
- Read journal identity from events; require one stable `runId` and `slug`.
- Resolve exactly one `docs/plans/<slug>.jsonl` or `docs/plans/*-<slug>.jsonl`.
- Preserve journal events verbatim.
- Upsert observer metadata only; replay remains status ground truth.
- Fail closed per malformed journal or ambiguous plan without blanking other runs.

## Projection

- Latest `plan-error` after latest `plan-start` produces `failed`.
- `plan-end` produces `succeeded` only when all task outcomes succeeded/skipped-done and landing status is successful.
- Completed task count derives from final per-task replay.
- `plan-error.message` supplies degraded reason when tasks completed but finalization failed.
- Phase3 therefore displays completed task work with failed landing/finalization, never success.

## Collector/UI Data Flow

- Web remains unchanged: `/plans` fetches `/api/collector/state`.
- Collector harness poll reads `/runs` and `/queue`.
- Deploy current harness release so `/queue` exists; root red/stale state disappears.
- Empty state remains valid only when durable `/runs` and queue are both empty.

## Tests

- Quarantined/terminal history survives migration and API restart.
- History record cannot satisfy active-control validation or trigger reconcile/watchdog.
- Journal importer restores phase3 and older v2 runs idempotently.
- Final phase3 `plan-error` stays failed with completed tasks and finalization reason.
- Malformed history/journal fails closed per record while valid runs remain.
- Collector harness poll accepts non-empty imported history and queue.

## Architecture Decisions

- Dedicated history directory passes deletion test: removing it recouples UI retention to mutable supervision.
- Importer stays inside history registry module; separate service would expose only one implementation and add a shallow seam.
- No UI changes: current schema already represents failed finalization plus completed tasks.
