# Brain-retro aggregation template

## Period

YYYY-MM-DD .. YYYY-MM-DD ({N} sessions)

## Path-type distribution

| path_type | count | % |
|---|---|---|
| regulated | A | x% |
| improvised | B | y% |
| alternative | C | z% |
| mixed | D | w% |

## Outcome distribution

| outcome | count |
|---|---|
| success | M |
| partial | N |
| failure | O |
| aborted | P |

## Top nodes used (from `skill_invoked` events)

| node | times used | first / last |
|---|---|---|

## Hook script breakdown (from `hook_fired.scripts`, schema v3+)

Per-script counts across the period. Surfaces which discipline-enforcing hooks fired (and which silently failed to fire). Aggregate from `events[].hook_fired.scripts` of v3 episodes — v2 episodes have only matcher-level `counts` and contribute nothing here.

| script | times fired | notes |
|---|---|---|
| `tools/observer-stop-hook.mjs` | N | should fire once per turn — gaps = observer drop |
| `tools/subagent-prompt-prefix.mjs` | N | once per Task-tool call |
| `inline:<sha-16>` | N | inline `node -e "..."` — see settings.json for body |

**Discipline highlights:**

- `tools/observer-stop-hook.mjs` count < turn count → observer skipped turns; cross-check `observerErrorCount` and STATUS.md C5.
- `tools/subagent-prompt-prefix.mjs` count vs `Agent` tool_use count — mismatch = missing pre-flight injection.
- Inline `claude-md`/`schema.sql` guards — fired iff someone touched those files.

## Recommended-node candidates (from `primary_rationale.recommended_node`, schema v3+)

Distinct from `missedActivations` (which aggregates): this is the per-episode signal embedded in each direct episode.

| recommended_node | times direct | top classifications |
|---|---|---|
| #19 | N | feature, planning |
| none (v2 or no recommendation) | N | — |

Cross-reference with `factorMatrix.recommended_node_for_direct` and `missedActivations.byNode`. A persistent (#NN, count > threshold) — strong missed-activation pattern, candidate for retro discussion.

## Factor analysis matrix (v2 — from `tools/brain-retro-analyzer.mjs`)

Outcome distribution per factor value. Source: the analyzer’s `factorMatrix`.
Outcome is the *inferred* outcome (next-prompt sentiment), not the stored
`unknown`. The factor `decision_provenance` directly answers the owner’s
question — "is the rework mine or the router’s?"

For each factor below, render a table: factor value × outcome counts
(`success` / `partial` / `rework` / `unknown`).

### decision_provenance (autonomous vs user_directed_method)

| provenance | success | partial | rework | unknown |
|---|---|---|---|---|

### economy_level

| economy_level | success | partial | rework | unknown |
|---|---|---|---|---|

### model · post_compaction · task_size bucket

(one table each — same columns)

### node_chosen · task_classification

(one table each — same columns)

## Missed Activations (Pravila §16.4 v1.36)

Surface candidates where a profile-classified task ran with `node_chosen === 'direct'` and at least one non-dormant recommended node was available. The analyzer returns `missedActivations: { totalMissed, byNode, byClassification }` — render the two breakdowns below.

**Source:** `analyze(episodes, { classificationMap, dormancy }).missedActivations`.

### By node

| Node | Episodes missed | Classifications hit |
|---|---|---|
| #NN | N | refactor (a), bugfix (b) |

### By classification

| Classification | Missed episodes | Top recommended nodes (non-dormant) |
|---|---|---|
| refactor | N | #11, #12, #43 |

**Interpretation guide:**

- High count on one node → router-miss pattern. Suggest updating `tools/observer-classification-map.json` or a workflow nudge.
- Spread across many nodes with classification leaning to `other` → the classification dictionary may need refinement (separate concern, not a missed activation).
- All zero → either no profile work this period, or the router is operating cleanly.

**NOT to be auto-applied:** these are candidates for human review in retro, not commits or hook blocks.

**Schema v3 NB:** since 2026-05-23, each direct episode carries `primary_rationale.recommended_node` directly. The analyzer's `missedActivations` aggregates these into `byNode`/`byClassification`. For per-episode forensics (which prompt, which session), grep episodes-*.jsonl on `"recommended_node":"#NN"`.

## Episodes → tasks (from analyzer `tasks`)

| task_ref | episodes | turns that are rework |
|---|---|---|

## Causal-chain candidates (from analyzer `causalChains`)

| from (errored episode) | to (later episode) | shared files |
|---|---|---|

## Observer health

- `observerErrorCount` from the analyzer — observer_error markers in the period.
  Non-zero = the observer failed silently somewhere; investigate.

## Canonical chains L1–L13+ hit rate (from analyzer `factorMatrix.chain_ref`)

| chain | times | outcome split | notes |
|---|---|---|---|

Each node may belong to several L (a multi-chain episode is counted in each).
`null` = episodes outside any chain (`direct` + nodes not in L1–L13+) — **not a
problem** per `memory/feedback_brain_unused_tools_not_problem`.

## Improvised chains (path_type=improvised, repeated ≥2)

| node-set | times | candidate L13+? |
|---|---|---|

## chain_divergence cases

| canonical | chosen | reason | recurring? |
|---|---|---|---|

## Top error classes

| error class | count | recovery pattern |
|---|---|---|

## confusion_marker hot-spots

| context | count |
|---|---|

## Candidates for owner review

### Candidate 1: `<title>`

- **Type**: new canonical chain L13+ / new ADR / boundary clarification / etc.
- **Evidence**: refs to JSONL lines (file:line).
- **Suggested action**: `<concrete edit>`.
- **Cost / risk**: `<brief>`.

(repeat for each candidate; could be 0)

## Informational metrics (NOT alerts)

- Nodes used at least once this period: K / 60+
- Nodes never used since beginning of observer logs: L / 67 — **not a problem if there was no profile task** per Pravila §16.4 v1.36 and [feedback_brain_unused_tools_not_problem](../../../memory/feedback_brain_unused_tools_not_problem.md). See `## Missed Activations` above for profile-task-present cases.
