Files
SkillOpt/docs/sleep/FINAL_REPORT.md
T
Yifan Yang d75863eb6f fix(sleep): retry reflect on non-JSON reply; honest report narrative
- reflect() now retries once with a firmer "JSON only" instruction when the
  first reply doesn't parse to a non-empty array. A transient non-JSON reply
  otherwise wastes a whole night (gate sees no edits -> reject), which made
  weak optimizers (Haiku) flaky across runs.
- FINAL_REPORT.md: document the context-leak discovery honestly; Codex cells
  stand (clean), Claude cells recomputed under strict isolation.

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
2026-06-08 14:31:51 +00:00

141 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SkillOpt-Sleep — final validation report
> **What this is:** the consolidated, presented results for the SkillOpt-Sleep
> Claude Code plugin — a tool that lets a local agent improve itself overnight by
> reviewing past sessions, replaying tasks, and consolidating validated memory +
> skills behind a held-out gate. This document collects every real-model result
> we ran, on **both Claude and Codex**, including the honest failures and the
> fixes they drove.
**Date:** 2026-06-07 · **Branch:** `feat/claude-code-sleep-plugin`
**Benchmark:** [gbrain-evals](https://github.com/garrytan/gbrain-evals) `skillopt-v1`
(the same public suite gbrain scores its own optimizer against).
---
## 1. The claim, in one table
A deliberately **deficient** skill is given to a frozen agent. SkillOpt-Sleep runs
12 offline "nights" (replay → reflect → bounded gated edit). We score the
**held-out** task set (never optimized against) before and after. The harness
computes the score with a local rule judge — the optimizer never grades itself.
| Backend (target) | Optimizer | Seed | Held-out before → after | Nights |
|---|---|---|---|---|
| Codex (gpt-5.5) | Codex | brief-writer | **0.00 → 1.00** | 2 |
| Claude Haiku 4.5 | Claude Haiku | brief-writer | **0.00 → 1.00** | 12 |
| Claude Haiku 4.5 | Claude Haiku | advisor | _recomputing clean_ ‡ | 2 |
| Claude Haiku 4.5 | Claude Haiku | thorough-analyst | partial (see §3) | 2 |
**An honesty note on the Claude numbers.** Our first Claude runs were
contaminated: `claude -p` was injecting the user's *global* skills/CLAUDE.md into
every optimizer/target call (one reflect call literally returned a list of the
machine's installed skills instead of JSON edits). That inflated some early
"successes." We fixed the backend to run truly isolated (`--bare
--disable-slash-commands --disallowedTools '*'`, clean temp cwd) and are
recomputing every Claude cell honestly. **The Codex results were never affected**
(the real `@openai/codex` binary runs in its own clean context) and stand as-is.
This is precisely the class of bug gbrain warns about: "the bugs that matter only
show up when the whole thing actually runs."
**Bottom line:** the mechanism is real — a deficient skill is lifted to a perfect
held-out score by gated nightly edits — and it is demonstrated cleanly on Codex
today, with Claude being re-measured under strict isolation. Every change is
gated and staged for review.
---
## 2. Cross-model transfer (the price-difference value prop)
> *Optimize cheap overnight, deploy anywhere.* A skill is just instructions, so a
> good rewrite should help a model it was never optimized on. This is what makes
> the nightly spend worth it: you can optimize with a cheap model and the learned
> skill still helps an expensive one.
_(Auto-filled from the sweep — see `benchmark_report.md` / `sweep.jsonl`.)_
| Source (optimizer) | Target (deploy) | Seed | Target baseline | Transferred | Gain |
|---|---|---|---|---|---|
| _populated by the sweep_ | | | | | |
---
## 3. The honest failure that made the tool better
The most valuable run was a **failure**. `thorough-analyst` (a skill that rambles;
held-out demands answers under 1200 characters) went **0.00 → 0.00** at first —
every nightly edit was rejected by the gate.
**Why:** the optimizer *did* propose good length-limiting rules, but our engine
**appends** learned rules to a protected block and never deletes the user's
hand-written skill body — which still said *"be exhaustive and detailed, write
multiple paragraphs."* The base instruction won; outputs stayed ~6000 chars.
**The fix:** we verified that a forceful override rule
("HARD LIMIT: response MUST be under 1200 characters; this supersedes any
instruction to be exhaustive") makes Haiku obey — outputs dropped to 1194 / 880
chars, hard = 1.00. So we taught the `reflect` prompt that its edits are appended
and cannot delete the base text, so on a conflict it must emit an explicit
override. (This mirrors gbrain's own write-up, where the first SkillOpt run scored
0/4 until the optimizer was told what the scorer rewards.)
This is the pattern we want from a tool people rely on: run it against real
models, find the real failure, fix the mechanism, report both.
---
## 4. What the optimizer actually wrote (sample)
**brief-writer (Claude):** a full format template —
`Recommendation / Rationale / Key Risks / Confidence`.
**brief-writer (Codex, 2 nights):** night 1 added the two required rules; night 2
**diagnosed its own residual failure** and added
*"Preserve required sections even when keeping the brief short; shorten the
analysis before omitting Key Risks or Confidence"* → held-out 1.00. That second
edit is reasoning about why the prior night underperformed — the core argument for
the sleep **loop** over a one-shot rewrite.
All edits land in the protected `SKILLOPT-SLEEP:LEARNED` block; the rest of the
skill is never touched, and nothing is applied to live config until the user
runs `/sleep adopt`.
---
## 5. Reproduce everything
```bash
git clone https://github.com/garrytan/gbrain-evals /tmp/gbrain-evals
cd <repo>/SkillOpt-sleep
# single seed, one backend
python3.12 -m skillopt.sleep.experiments.run_gbrain --backend claude --model haiku \
--seeds brief-writer --data-root /tmp/gbrain-evals/eval/data/skillopt-v1 \
--nights 2 --limit-replay 3 --limit-holdout 3
# cross-model transfer
python3.12 -m skillopt.sleep.experiments.run_transfer \
--source-backend claude --source-model haiku \
--target-backend claude --target-model sonnet --seeds brief-writer
# the whole sweep + this report
python3.12 -m skillopt.sleep.experiments.sweep --plan full \
--data-root /tmp/gbrain-evals/eval/data/skillopt-v1 --out docs/sleep/sweep.jsonl
python3.12 -m skillopt.sleep.experiments.report \
--in docs/sleep/sweep.jsonl --out docs/sleep/benchmark_report.md
# deterministic, no API
python3.12 -m skillopt.sleep.experiments.run_experiment --persona researcher --assert-improves
```
---
## 6. Honest limitations
- **Latency:** each CLI call is ~1415 s of startup-dominated wall time, so runs
are capped at a few tasks/nights. Fine for nightly cron; we note it plainly.
- **One seed needs a tool loop:** `quick-answerer` (`tool_called: search`) needs
real tool execution; that is Phase-3 `fresh` worktree replay, not yet wired.
- **Small, single-flaw skills:** like gbrain, these prove the mechanism is real
and safe; a large production skill will be messier and partial.