# Remaind Contract v1

This file is the binding contract for everything that reads or writes
`.context/`. Changes to file shapes, semantics, or guarantees here must ship
with a migration step under `schemas/migrations/`.

## Authority order (load-bearing)

When sources disagree, all readers and agents must resolve truth in this
order. Lower wins.

1. Latest explicit user instruction
2. Raw event log (`logs/events.jsonl`)
3. `active/state.json`
4. `active/handover.md`
5. Derived memories

A stale summary or memory MUST NOT override a newer user instruction.

## Storage model

| File | Role | Mutability |
|------|------|------------|
| `logs/events.jsonl` | Immutable raw timeline | Append-only |
| `active/state.json` | Derived working state | Atomic replace |
| `active/handover.md` | Compact human/agent handover | Atomic replace |
| `active/resume_packet.md` | Assembled fresh-context packet | Runtime, git-ignored |
| `db/context.sqlite` | Derived memory + FTS5 index | Runtime, git-ignored |
| `artifacts/` | Large/binary outputs | Runtime, git-ignored |

`state.json` and `handover.md` are derived. They MUST NOT be treated as more
authoritative than the raw log.

## Schemas

Canonical schemas live in `schemas/`. JSON Schemas are Draft 2020-12. They
are canonical; runtime models (e.g. Pydantic) must validate against the JSON
Schema rather than silently becoming the source of truth.

- `event.schema.json` — every line in `logs/events.jsonl`
- `state.schema.json` — `active/state.json`
- `memory.schema.json` — rows in `db/context.sqlite::memories`
- `validation.schema.json` — compaction validation result

## Importance and compaction

Event importance values:

- `0` trace / debug
- `1` normal useful event
- `2` decision, correction, constraint, file change, blocker, meaningful result
- `3` explicit remember instruction, active next step, active blocker,
      critical user instruction

Compaction MUST preserve all `importance >= 2` items in the summary chain
unless superseded. `importance = 3` MUST be explicitly represented in active
state, active handover, or active memory.

## Atomic writes

Derived files MUST be written atomically:

1. Copy current target to `active/history/<kind>/<timestamp>.{ext}` if it exists
2. fsync the history copy
3. Write `<file>.tmp` next to target
4. fsync the temp file
5. Rename temp over target
6. fsync the parent directory where supported

Raw JSONL is append-only through the single writer.

## Resume gate

Resume is internal and seamless by default. The agent interrupts the user
only when:

- raw log, state, and handover conflict
- `next_step` is missing
- latest user instruction is not represented
- resume confidence is low AND the next planned tool has `mutates`,
  `spends_money`, or `external_side_effect`

Tool risk is mechanical and comes from `schemas/tools.yaml`. Do not infer
risk from prose.

## Migrations

- State migrations (`schemas/migrations/state/`) are write-time, pure
  functions, applied eagerly on bootstrap. A full dry-run chain runs first.
- Event adapters (`schemas/migrations/events/`) are read-time only and
  MUST NOT rewrite `events.jsonl`. Applied lazily per event read.

On failure: abort, leave original file untouched, raise a structured
exception, and (once logging exists) append an `error` event.

## Hard rules

- Do not rewrite `events.jsonl`.
- Do not let summaries become source of truth.
- Do not store secrets in raw logs (see `schemas/redaction.yaml`).
- Do not store huge outputs inline (threshold: 4096 bytes).
- Do not allow stale memory to override latest user instruction.
- Do not accept compaction without structured validation
  (`validation.schema.json`).
- Do not mutate files on resume if the resume packet is contradictory or
  unsafe.

## V1 non-goals

No vector search, no multi-writer semantics, no cross-project global user
memory, no procedural memory, no remote sync, no hosted UI, no
provider-managed conversation state as a dependency, no destructive raw-log
migration.
