# Learning Dashboard

## Overview

The learning dashboard is the primary control plane for reviewing and acting on learning candidates generated by the observer daemon. It runs as a local HTTP server (`arcforge learn dashboard`) and presents a browser-based UI at `http://localhost:3334`.

Candidates arrive in the queue after the observer daemon's LLM curator analyzes batched tool-call observations and produces structured proposals. The dashboard is where a human reviewer approves, dismisses, promotes, or deactivates each candidate — no candidate ever changes active behavior without explicit human action through these gates.

## Starting the Dashboard

```bash
arcforge learn dashboard              # default port 3334
arcforge learn dashboard --port 3335  # custom port
```

Open `http://localhost:3334` in a browser. The dashboard serves until interrupted (`Ctrl+C`).

## Candidate Lifecycle

Each candidate moves through a defined set of statuses. The dashboard enforces the Action × Status legality matrix — only valid actions for each status are shown.

| Status | Meaning |
|---|---|
| `pending_review` | Queued by LLM curator, awaiting human review |
| `needs_more_evidence` | Flagged; more observations required before approval |
| `approved` | Human-approved, ready to materialize into draft artifacts |
| `materialized` | `.draft` artifact files written, ready to activate |
| `activated` | Draft artifacts promoted to active skill/instinct files |
| `deactivated` | Previously activated candidate, now turned off |
| `dismissed` | Rejected by reviewer; no artifacts written |
| `superseded` | Replaced by an evolved candidate |

## Actions

| Action | Available From | What It Does |
|---|---|---|
| **Dismiss** | `pending_review`, `needs_more_evidence` | Closes the candidate without writing artifacts |
| **Approve** | `pending_review` | Marks the analysis as correct; enables materialization |
| **Materialize** | `approved`, `deactivated` | Writes inactive draft to `~/.arcforge/learning/drafts/<cid>/<mid>/instincts/<name>.md` |
| **Activate** | `materialized`, `deactivated` | Copies the draft to the active path `~/.arcforge/instincts/<scope>/<cid>.md` |
| **Promote** | `pending_review`, `approved` | Creates a new global-scope candidate from this project candidate |
| **Evolve** | `pending_review`, `approved` | Creates a revised successor candidate |
| **Deactivate** | `activated` | Turns off a previously activated candidate |

**Promote and Evolve** create a new candidate record — they do not change the source candidate's status. Promotion to global scope always requires this explicit action; silent auto-promotion is not supported.

## Legacy CLI (pre-pivot data — not equivalent to dashboard)

The `arcforge learn ...` subcommands below remain in the CLI for backward compatibility with older instinct-clustering tests, but they read and write the **pre-pivot** legacy data model in `scripts/lib/learning.js`. They do not interact with the post-pivot `queue.jsonl` candidate queue or the Layer 7 / Layer 8 modules that back the dashboard. **Use the dashboard for v3.1 workflows.**

- `arcforge learn analyze --project` — retired (exits with deprecation notice)
- `arcforge learn review|inbox|inspect|drafts --project` — legacy read commands; show pre-pivot data only
- `arcforge learn approve|reject <id> --project` — legacy transitions; do not affect dashboard candidates
- `arcforge learn materialize <id> --project` — writes project-relative `.draft` siblings (legacy paths)
- `arcforge learn activate <id> --project` — legacy activation; does not call the post-pivot Layer 8 gate

## Storage

```
~/.arcforge/
├── learning/
│   ├── candidates/
│   │   └── queue.jsonl           # Append-only Layer 5 candidate queue
│   ├── drafts/
│   │   └── <cid>/<mid>/instincts/<name>.md   # Layer 7 inactive draft artifacts
│   ├── activations/
│   │   └── <activation-id>.json  # Layer 8 activation records
│   └── dashboard/
│       └── actions.jsonl         # Append-only audit log of dashboard actions
└── instincts/
    ├── <project>/
    │   ├── <cid>.md              # Active project-scoped instinct (Layer 8 output)
    │   └── .disabled/<cid>-<ts>.md  # Archive of deactivated instincts
    └── global/
        ├── <cid>.md              # Active global-scoped instinct
        └── .disabled/<cid>-<ts>.md
```

The dashboard never writes active instinct files directly. Materialization (Layer 7) writes drafts under `~/.arcforge/learning/drafts/` only; activation (Layer 8) is the sole layer that writes under `~/.arcforge/instincts/`, and only on explicit `[Activate]` action with a reviewer acknowledgement.

## Privacy Invariants

The dashboard wire model is allowlist-based. Raw evidence, full observation payloads, project identifiers, and internal body fields are **never served to the browser**. Only sanitized name, summary, rationale, and truncated preview windows appear in the UI. The same `sanitize-observation.js` redaction pass applied during candidate ingestion is applied again before any field is sliced into a preview.

## Security

Each dashboard session generates a per-session write token that must accompany every `POST /api/candidates/:id/action` request. The token is embedded in the page at serve time. Requests without a valid token are rejected with `403 Forbidden`.

Standard security headers (`X-Content-Type-Options`, `X-Frame-Options`, `Content-Security-Policy`) are set on all responses.

## Common Mistakes

### Running the dashboard before enabling learning
The dashboard can open, but the candidate queue will be empty. Enable project learning first:
```bash
arcforge learn enable --project
arcforge learn status
```

### Expecting `analyze` to populate the queue
`arcforge learn analyze` was retired in v3.1. The statistical analyzer has been replaced by the observer daemon's LLM curator (Layers 3+4). Candidates are queued automatically once learning is enabled — no manual trigger is needed.

### Activating without inspecting drafts
Activation copies the draft to the active path. Before clicking `[Activate]`, inspect the materialized draft on disk:
```bash
ls ~/.arcforge/learning/drafts/<candidate-id>/
cat ~/.arcforge/learning/drafts/<candidate-id>/<materialization-id>/instincts/<name>.md
```
Deactivation moves the active file to a `.disabled/` backup archive, so you can reactivate later if needed.

### Confusing Approve with Activate
**Approve** only authorizes materialization — no file is written yet.
**Materialize** writes the inactive draft under `~/.arcforge/learning/drafts/<cid>/<mid>/`.
**Activate** is the only action that produces an active artifact under `~/.arcforge/instincts/<scope>/`. Even after activation, instincts are **not** auto-loaded into Claude context at SessionStart — they surface through dashboard, `arc-recalling`, and explicit Read tool calls only.
