---
name: errorlog-dream
description: "Lint the fleet error log (errorlog.md): top failure contexts, repeat ref= citations (rules that are not sticking), cross-day noise clusters, resolved entries, machine-name drift; --apply-archive rotates old entries to errorlog-archive/. Triggers: errorlog dream, lint/analyze the error log, errorlog patterns."
---

# Errorlog Dream

Sibling of `memory-dream` for `errorlog.md` — the corpus of skill failures,
user corrections, and self-inflicted friction that CLAUDE.md mandates logging.
The log exists so we "never pay tokens twice for the same avoidable mistake";
this skill is the payoff step: it reads the corpus and surfaces what to fix.

Read-only by default. The single mutating op (`--apply-archive`) only moves
old entries into `errorlog-archive/YYYY-MM.md`. Everything judgment-shaped
lands in a `## PROPOSED` section for the operator.

## What it reports

`scripts/errorlog_dream.py` parses the canonical entry format
(`YYYY-MM-DD | MACHINE | skill/context | [type] msg [ctx: ...] (xN)`;
`(xN)` is the log helper's same-day repeat counter) and produces:

1. SUMMARY — totals by type (exec/correction/friction), machine, date span,
   plus a count of unparsed legacy blocks (left untouched, never archived).
2. TOP CONTEXTS — failure volume by context group, weighted by `(xN)`.
3. REPEAT REFS — `ref=` citations appearing >=2x. **The highest-value signal:**
   a friction entry citing a documented gotcha means that rule/memory is NOT
   working; repeat citations mean it keeps failing. Checks whether the cited
   memory file actually exists.
4. NOISE CLUSTERS — same machine + skill + normalized message (ids/numbers
   collapsed) recurring across >=3 days or >=5 weighted hits. These need a
   skill-side fix (expected-condition filter, backoff, health-gate) — not
   more log lines.
5. RESOLVED — entries carrying a `[RESOLVED ...]` annotation; archive
   candidates regardless of age.
6. MACHINE-NAME DRIFT — the same machine logged under multiple spellings
   (case drift in identity.json).
7. ARCHIVE CANDIDATES — entries older than `--days` (default 60).
8. PROPOSED — `[STRENGTHEN?]` (repeat refs -> add a mechanical guard or
   rewrite the memory), `[SUPPRESS?]` (noise clusters -> fix the skill),
   `[ARCHIVE?]` (resolved entries).

## Modes

- Default — report only; prints to stdout and writes
  `errorlog-archive/_reports/YYYY-MM-DD-HHMM-dream.md`.
- `--no-file` — stdout only.
- `--report-file <path>` — explicit report path.
- `--days <n>` — archive-age threshold (default 60).
- `--apply-archive` — move entries older than `--days` into
  `errorlog-archive/YYYY-MM.md` (grouped by entry month, verbatim lines,
  unparsed legacy blocks never moved). Idempotent.

## Running it

Stdlib only, no pip deps.

```bash
# report only
bash "$CLAUDETOOLS_ROOT/.claude/scripts/py.sh" "$CLAUDETOOLS_ROOT/.claude/skills/errorlog-dream/scripts/errorlog_dream.py"

# rotate out entries older than 60 days
bash "$CLAUDETOOLS_ROOT/.claude/scripts/py.sh" "$CLAUDETOOLS_ROOT/.claude/skills/errorlog-dream/scripts/errorlog_dream.py" --apply-archive
```

## The operator MUST work the PROPOSED section — that is the run's purpose

Same posture as memory-dream: the report is not the deliverable, the fixes
are. After each run:

1. **`[STRENGTHEN?]` repeat refs** — the cited prose rule demonstrably fails
   under flow. Prefer a MECHANICAL guard over more prose: a PreToolUse hook,
   a wrapper that makes the safe path the only path (e.g. `-EncodedCommand`
   for quote-mangling layers), or a script-side preflight. If the cited
   memory file is missing, fix or remove the dangling ref convention.
2. **`[SUPPRESS?]` noise clusters** — patch the failing skill: filter
   expected/validation responses out of logging (the gz.py pattern +
   `GZ_SUPPRESS_ERRORLOG`-style env flag), add a stop-after-2-identical-
   failures guard, or health-gate a chronically-down backend.
3. **`[ARCHIVE?]` / archive candidates** — run `--apply-archive`; append
   `[RESOLVED <date>]` to entries you fixed so the next run proposes them.
4. Commit + `/sync` so the trimmed log and archive reach the fleet.

If a proposal needs a decision you can't make, leave it AND say so in your
summary — don't silently skip the section.

## Self-test

`scripts/selftest.py` builds a synthetic errorlog in a temp dir and asserts
every detector fires (counters, repeat refs, noise clusters, resolved,
machine drift, archive candidates) and that `--apply-archive` moves exactly
the old entries, splits by month, preserves the marker + unparsed blocks,
and is idempotent.

```bash
bash "$CLAUDETOOLS_ROOT/.claude/scripts/py.sh" "$CLAUDETOOLS_ROOT/.claude/skills/errorlog-dream/scripts/selftest.py"
```

## Files

```
.claude/skills/errorlog-dream/
  SKILL.md                      this file
  scripts/errorlog_dream.py     the analyzer (report / --apply-archive)
  scripts/selftest.py           fixture-based self-test
errorlog-archive/               rotated months + _reports/ (created on use)
```
