# Decisions & history

> Decision records, the operation log, timeline, blame and symbol history, revert and undo, tags and attestations.
>
> Source: https://www.weave.directory/docs/decisions-and-history

Every change in Weave carries what it was for and why. History only moves forward: revert and undo add new entries, nothing is rewritten.

## Decision records

A **decision record** says why code is the way it is: a title (≤ 80 characters), the why (≤ 240), rejected alternatives and constraints, anchored to symbols. Records are files, `.weave/decisions/D-xxxx.toml`, that travel draft → stitch → weaved **with the code**, so they are owned, promoted, inherited and reverted like the code they explain. Agents need `.weave/decisions/**` in their `pathScope` to stitch them.

### Record decisions

```bash
# at stitch time: -w drafts a record anchored to the symbols you changed (confirm it, or -y)
weave stitch -i "Keep bcrypt" -w "login p99 budget is 250ms" -y

# directly
weave decision add -t "Keep bcrypt cost at 12" -w "login p99 budget is 250ms" \
  --on src/auth.rs::hash_password --alt "argon2id" --constraint "p99 login < 250ms" --comment
```

`--comment` puts a one-line `why: … [D-xxxx]` comment above each anchor. That tag is the strongest anchor: the record follows it through moves and renames. `WEAVE_DECISION_YES=1` records drafted decisions without asking.

### Read decisions (within a token budget)

```bash
weave decision for src/auth.rs::login                   # one short line per decision on it and its neighbours
weave decision for src/auth.rs::login --format constraints
weave decision search "password hashing" --near src/auth.rs::login
weave decision impact src/auth.rs::login --depth 2      # callers and callees with their decision counts
weave decision show D-7f3a
weave decision list --all                               # or --status active|needs_review|superseded|stale|retired
```

`--format constraints` prints rules for an agent's starter pack, best decision first:

```
KEEP: Keep bcrypt cost at 12 — login p99 budget is 250ms [D-7f3a]
KEEP: p99 login < 250ms [D-7f3a]
NEVER: argon2id [D-7f3a]
```

### Keep decisions current

When an anchored symbol changes, its decisions become `needs_review`; when every anchor is lost, `stale`.

```bash
weave decision review                 # follow moved / renamed anchors, mark drift, list the queue (--dry-run)
weave decision review D-7f3a --accept # it still holds
weave decision supersede D-7f3a -t "Use argon2id" -w "new hardware budget"
weave decision retire D-7f3a --reason "auth moved to the identity service"
```

`weave enrich` can find unconfirmed why-candidates with an LLM (your key, on your machine); `weave decision review --candidates` lists them and `weave decision confirm <n>` turns one into a decision.

MCP: `decisions_for`, `decision_search`, `decision_get`, `impact`, `decision_propose`, `decision_review`. Server API: `GET|POST /api/weave/{repoId}/decisions`, `GET …/decisions/{id}`, `POST …/decisions/{id}/supersede`, `POST …/decisions/{id}/retire`, `POST …/decisions/review` (see [API reference](https://www.weave.directory/docs/api#decisions)). Server writes are stitches too, so a write to a record someone else owns becomes a suggestion.

### Threads

**Threads** are the lighter companion: short behaviour notes per symbol, written directly to sidecars under `.weave/threads/` without drafts or stitches.

```bash
weave thread add src/auth.rs::login "token refresh is lazy"
weave thread show login --depth 1
weave thread search "refresh"
weave index && weave thread heal      # after renames
```

## Timeline and the operation log

```bash
weave timeline                         # weaved stitches of the active workstream, newest first
weave timeline main --limit 20         # author, agent, intent, why, promoted / inherited / revert
weave log                              # the operation log: every action, newest first (default 30)
weave log --actor alice --workstream main --limit 50
weave log --by-agent builder-1
weave log --symbol src/auth.rs::login  # everything that touched a symbol
weave log --verify                     # check the log's hash chain first
```

The **operation log** records every action — claims, releases, lease expiries, stitches, weaves, rejections, suggestions, change requests, promotions, reverts, undos, workstream removals, tags, attestations, purges — with the person and agent. It is append-only and hash-chained: each entry's id is the BLAKE3 hash of its content and the previous entry's id. In the web UI it is the repository's **Log** tab, with filters for person, agent, workstream and symbol.

## Blame and symbol history

Which weave last changed each symbol of a file (server API, read access):

```bash
curl -s "https://api.weave.directory/api/weave/$REPO_ID/workstreams/main/blame?path=src/auth.rs" \
  -H "Authorization: Bearer $WEAVE_TOKEN"
```

```json
{ "type": "blame", "workstream": "main", "path": "src/auth.rs", "head": "…", "total": 3, "next_offset": null,
  "items": [{ "symbol": "src/auth.rs::login", "kind": "function", "changeset": "…", "label": "stitch",
    "author": "alice", "agent": null, "at": "…", "intent": "MFA login", "why": "SOC2", "entry_id": "…" }] }
```

- Paged with `offset` and `limit` (default 200, max 1000). A symbol unchanged since its workstream was created is attributed in the parent.
- `GET …/workstreams/{ws}/symbol-history?symbol=src/auth.rs::login` lists every weave that changed one symbol.
- `GET …/workstreams/{ws}/history` pages weaved stitches newest first (`before`, `limit` ≤ 500) and filters by `kind`, `agent`, `author`, `source` and `symbol`. Items carry `reverted_by` / `reverts` links.
- `GET /api/weave/{repoId}/diff?from=<head|workstream>&to=<head|workstream>&level=file|symbol&path=` diffs two heads, by file or by symbol.

## Revert and undo

```bash
weave revert 9c1e --why "broke MFA on mobile"   # a new stitch with the inverse operations
weave undo                                      # reverse your own most recent action
weave undo <log entry id prefix>                # or a chosen entry of yours
```

- **Revert** takes back a weaved stitch with a new stitch. Symbols unchanged since are reverted; a symbol changed again since is not overwritten but becomes a change request. `--why` is required.
- **Undo** reverses **your own** action: a weaved stitch is reverted, a claim released, a suggestion withdrawn, a rejection reopened, a settings change restored, a removed workstream restored. Someone else's action is taken back with a revert or a suggestion instead. Undo is logged and never deletes entries.
- Several stitches as one revert, all or nothing (server API): `POST /api/weave/{repoId}/workstreams/{ws}/revert` with `{"changesets": ["<id>", "<id>"], "why": "…"}`. If a later weave changed one of the symbols, it answers `409 revert_conflict` with the `blocking` symbols and nothing is weaved.
- Restore paths or symbols to an older head as a new stitch: `POST /api/weave/{repoId}/restore` with `{"workstream", "head", "paths"?, "symbols"?, "intent"?, "why"?}`.
- Web UI: **Weaved** → **Revert** on a stitch; **Log** → undo on your own entries.

## Tags

Tags are immutable names for heads (server API):

```bash
curl -s https://api.weave.directory/api/weave/$REPO_ID/tags \
  -H "Authorization: Bearer $WEAVE_TOKEN" -H "Content-Type: application/json" \
  -d '{"name": "v1.2.0", "workstream": "main", "message": "spring release"}'
```

- `workstream` alone tags its current head; or pass `head` (a state of the repository). Write access.
- Names: letters, digits, `.`, `_`, `-`, `/`, ≤ 128 characters, no leading `-` `.` `/`, no trailing `/`, no `..` or `//`.
- The same name for the same head answers `200 created: false`; for another head, `409`.
- `GET …/tags[?head=]` lists them newest first; `GET …/tags/{name}` (encode `/` as `%2F`); `DELETE …/tags/{name}?why=` (repository admin).
- Tags aren't accepted as refs by `diff`, `archive` or `restore` yet: pass the tag's `head`.

## Attestations

An **attestation** is a signed statement about one exact head — `tests passed`, `security reviewed`, `approved` — that a [protected workstream](https://www.weave.directory/docs/workstreams#protected-workstreams) can require before a promotion.

1. **Register a key** (Ed25519). Repository keys: `POST /api/weave/{repoId}/attestation-keys` `{"publicKey": "<base64 of the raw 32-byte key>", "label"?, "types"?: ["approval"]}` (repository admin). Organization keys, trusted in every repository of the org: `POST https://weave.directory/api/v1/orgs/{slug}/attestation-keys` (scope `org:admin`). A key's id is `wak_` + the first 32 hex of sha256(raw public key).
2. **Sign** this text (UTF-8, `\n` between lines, no trailing newline):

   ```text
   weave-attestation/v1
   repo:<repo id>
   head:<head, 64 lowercase hex>
   type:<type>
   payload-sha256:<lowercase hex sha256 of the canonical payload bytes>
   ```

   A string payload is its UTF-8 text as is. Any other JSON is compact, with object keys sorted, recursively.

   ```js
   import crypto from "node:crypto";
   const canonical = (v) => typeof v === "string" ? v
     : Array.isArray(v) ? `[${v.map(canonical).join(",")}]`
     : v && typeof v === "object" ? `{${Object.keys(v).sort().map((k) => `${JSON.stringify(k)}:${canonical(v[k])}`).join(",")}}`
     : JSON.stringify(v);
   function attest(privateKey, repo, head, type, payload) {
     const text = typeof payload === "string" ? payload : canonical(payload);
     const digest = crypto.createHash("sha256").update(text, "utf8").digest("hex");
     const msg = `weave-attestation/v1\nrepo:${repo}\nhead:${head}\ntype:${type}\npayload-sha256:${digest}`;
     return crypto.sign(null, Buffer.from(msg, "utf8"), privateKey).toString("base64");
   }
   ```

3. **Post it**: `POST /api/weave/{repoId}/heads/{head}/attestations` `{"type", "payload", "signature", "keyId"}` (write access; any principal). `head` must be a 64-hex state id, so you attest exactly what was checked. The signature is verified on the way in.
4. **Read** them: `GET …/heads/{head}/attestations` (a workstream name works here). Anyone can fetch a public key without a token: `GET /api/weave/attestation-keys/{keyId}`.

A revoked key verifies no attestation recorded after its revocation; ones it signed before stay valid.

## Verified audit trail

The server verifies every repository's hash-chained log every hour and writes checkpoints to write-once storage, chained to each other. Read the latest with `GET /api/weave/{repoId}/audit/verification` (read access; `?deep=true` for admins re-checks the stored checkpoint) and export the log with `GET …/audit/export?from=&to=&format=json|ndjson` (admin). `GET …/log/verify` checks the chain on demand. See [Security & access](https://www.weave.directory/docs/security#audit-trail).
