EPS
← All docs·Activity

Daily — 2026-06-01 — #448 on-policy re-run lands NULL; idle-pod burn recurred 3× (~$1k); 0 promoted

updated: 2026-06-02

What happened

  • #448 dominated the day (70 commits). The user halted the off-policy version mid-flight ("STOP — do not promote #448, its DV is off-policy") and forced a full re-run with the on-policy design. The 12-cell contrastive-LoRA sweep landed a clean NULL headline: none of four recipe knobs moves on-policy bystander marker leakage at this anchor's training budget, where the on-policy log-prob has saturated. Reached awaiting_promotion (MODERATE).
  • #458 checkpoint-deletion post-mortem + clean-result. Root-caused the data-loss incident (delete-after-eval rm -rf racing a best-effort WandB/HF upload under MooseFS + HF quota pressure → 20 of 36 trained cells finished with no recoverable artifact). Shipped the fix bundle: trainer.py fail-loud adapter-persist before the rm (merged to main 04265e50a), a CLAUDE.md Upload Policy rule, and the guard_repo_root_branch.sh PreToolUse hook. Clean-result reached awaiting_promotion (cosine similarity = coarse code-vs-prose detector, not a per-dataset EM predictor; MODERATE).
  • Three other experiments advanced. #459 (turner_em retrain) plan v2 approved → code-review r1 CONCERNS → r2 PASS → running. #462 (epoch-resolved on-policy marker transfer) ran train→crosseval→done. #463 (re-run EM predictors with full-response Rao-Blackwellized KL/JS) created + launched. #461 produced the predictor scatter grid + a mechanism correction.
  • Workflow + infra landings. CLAUDE.md gained canonical KL/JS-divergence + cosine-similarity definitions (full-response Rao-Blackwellized; persona-vectors cosine) after the user corrected a first-token-only JS implementation. Two workflow-fixes auto-applied (#448 experimenter pre-launch flag check; #408 eval-smoke-gate extension). Dashboard /updates/<N>/tasks/<N> redirect deployed, fixing the Dan/Christina mentor-link 404s from the May-29 refactor.
  • Day ended on a snag. #444 hit a preflight import-deadlock (last commit 22:12 "partial progress"); a 4×H100 pod had already idled ~21h on an unfired human gate. 0 clean-results promoted to completed during the June 1 PT day — #448 and #458 are parked at awaiting_promotion awaiting Thomas's manual task.py promote.

Proposed workflow improvements

Ordered by severity. PROPOSED ONLY — reply "do 1, 4, 6" (or "do all") and workflow-improver applies the greenlit ones. Script-side fixes (poll_pipeline.py, pod.py, preflight.py, bootstrap_pod.sh) are out of /daily proposal scope and live in ## Other problems & notes below.

  1. Target: .claude/skills/issue/SKILL.mdwhat: stop/terminate the pod when the pipeline blocks on a human gate OR crashes, before the session exits. Why: idle-pod burn recurred three times today, ~1k total. #444 idled a 4×H100 ~21h on an unfired `epm:fact-pick` gate (session dc2e0689: "roughly 170-250 of idle burn"); #404 idled ~2 days because Step 8 auto-terminate never fired after the pipeline skipped upload-verification (session dc93f209: "$600-800 already spent doing nothing"); #407 crashed in the aggregate phase and left a 4×H100 idle ~1 day (session 404cb6d9). The orchestrator leaves GPUs billing whenever a run dies or blocks outside the normal Step 8 path. Proposed edit:

    + ### Pod must not idle on a halt
    + When the pipeline (a) blocks on a human-input gate that cannot be satisfied
    + this turn (e.g. epm:fact-pick) or (b) is detected crashed/dead with GPUs idle,
    + run `pod.py stop --issue <N>` (volume preserved; resume re-provisions) or
    + `terminate` BEFORE exiting the turn. Never leave a pod RUNNING while awaiting
    + human input or after a crash. (Incident 2026-06-01: #444/#404/#407, ~$1k idle.)
    
  2. Target: .claude/agents/experiment-implementer.mdwhat: when porting a recipe from an unmerged parent branch, diff and port the WHOLE train+eval code path up front instead of cherry-picking function-by-function. Why: #451 cherry-picked factor_screen_397 but left train/sft.py at main's older TrainLoraConfig signature → all 72 cells crashed in ~10 min ("the cherry-pick brought the caller but not the callee change"). #456 hit the same class three times ("third partial-port — cherry-picking individual functions keeps missing siblings"), each crash burning a fix-relaunch on a live pod. Proposed edit:

    + ## Porting a recipe from an unmerged parent branch
    + If the parent's scripts/configs live on a branch never merged to main
    + (e.g. issue-432 @ <sha>), do NOT cherry-pick functions one at a time.
    + Run `git diff <parent-sha> -- <full train+eval path>` and port/verify the
    + ENTIRE divergence in one cycle before launch. Partial ports crash the pod one
    + phase at a time (#451: 72 cells; #456: 3 partial-port crashes, 2026-06-01).
    
  3. Target: .claude/skills/issue/SKILL.mdwhat: require a tiny-N end-to-end smoke run (every phase: gen → drift → train → eval → aggregate) before any multi-phase data-gen production launch; FAIL blocks production. Why: #408 hit 5+ distinct data-gen bugs discovered one-per-pod-cycle over 41h idle ($103 bleed) because the resume-skip design serialized bug discovery and no fast smoke run exercised every phase first (session e1e53b47: "the data-gen pipeline was never smoke-tested end-to-end before the expensive production run"). The #408 eval-smoke-gate extension landed today covers the eval cell, not the full gen→train→eval pipeline. Proposed edit:

    + ### Pre-launch end-to-end smoke gate (multi-phase data-gen pipelines)
    + Before the GPU production launch, run the FULL pipeline at tiny N (≈2-3 rows,
    + 1 cell, 1 seed) so EVERY phase executes once on CPU/1-GPU. A resume-skip design
    + hides downstream bugs; the smoke run forces them all up front, in minutes not
    + one-per-pod-cycle. FAIL blocks production. (Origin: #408, 5+ serialized crashes.)
    
  4. Target: .claude/skills/issue/SKILL.md (Step 10) — what: merge guard + status-flip ordering so a behind-main branch can't revert another task's state and a crash mid-merge can't strand a task at running. Why: the #458 merge branch (1,146 commits behind main) silently changed tasks/running/448/events.jsonlanother task's state (session dc93f209); the assistant caught it by hand and git checkout origin/main'd the foreign file. Separately #458's folder said running after the work was done, pod terminated, and branch merged — the session died between merge and status flip (session dc2e0689: "status drift — folder still says running"). Proposed edit:

    + ### Step 10 merge safety
    + 1. `git diff --name-only origin/main HEAD -- tasks/` MUST be empty except this
    +    task's folder. Any foreign tasks/ file in the merge → `git checkout
    +    origin/main -- <that file>` before push. Never let a behind-main branch
    +    revert another task's events.jsonl.
    + 2. Flip status OFF `running` BEFORE merge-to-main + pod terminate, so a crash
    +    mid-step can't strand a terminated-pod task at `running`. On `/issue <N>`
    +    resume: if pod terminated AND branch merged AND status still `running`,
    +    auto-advance instead of treating it as in-flight.
    
  5. Target: .claude/agents/interpretation-critic.md (Lens 1, measurement validity) — what: hard-FAIL a marker-leakage DV that reads log p(marker) teacher-forced at a fixed position after a canned/fixed response the model didn't generate. Why: #448 reached awaiting_promotion measuring the marker off-policy — the exact #432→#456 anti-pattern that CLAUDE.md forbids — and only the user's manual "STOP" caught it (session 49bae5c4). The measurement-validity lens should block it before promotion-readiness, not rely on Thomas. Proposed edit:

    + For marker-leakage DVs: hard FAIL (not a concern) if the eval reads
    + log p(marker) at a fixed position after a CANNED/teacher-forced response the
    + model did not itself generate. The marker MUST be measured on-policy, after
    + the model's own generation. This is the #432→#456→#448 anti-pattern and is a
    + hard block per CLAUDE.md.
    
  6. Target: ~/explore-persona-space/CLAUDE.md (Upload Policy) — what: replace the dead hf api list-repo-files command with the valid hf repo-files list. Why: the installed hf CLI has no api subcommand; it errors to stderr and | grep swallows it as an empty result that reads as a false "0 files uploaded." In the #458 post-mortem this nearly produced a wrong "checkpoints don't exist" conclusion (session 17478122: "that earlier '0' was a CLI error, not a real result"). Proposed edit:

    - Verify post-data-gen: `hf api list-repo-files superkaiba1/explore-persona-space-data --revision main | grep <bucket>`.
    + Verify post-data-gen: `hf repo-files list superkaiba1/explore-persona-space-data --revision main | grep <bucket>`
    +   (the `hf` CLI has NO `api` subcommand — it errors to stderr and `| grep` reads it as an empty/zero result; #458 post-mortem nearly drew a wrong conclusion from the silent "0").
    
  7. Target: .claude/skills/pm/SKILL.md + .claude/skills/daily/SKILL.mdwhat: prepend export PATH="$HOME/.local/bin:$PATH" and use uv run python in the opening scan commands. Why: non-login shells lack ~/.local/bin on PATH and there's no bare python. The /pm triage scan failed python: command not found (session dc2e0689); the /daily first parallel batch failed command not found: uv and even cancelled a sibling parallel call (session 0a149a32) — and this same failure hit me again at the start of this run. Three strikes today. Proposed edit:

    - python scripts/task.py list-by-status --limit 500
    + export PATH="$HOME/.local/bin:$PATH"   # uv lives in ~/.local/bin; non-login shells miss it
    + uv run python scripts/task.py list-by-status --limit 500
    
  8. Target: .claude/agents/analyzer.mdwhat: add a pre-emission register self-check so first-draft clean-result bodies pass Lens 2/7/13 without a critic bounce. Why: the analyzer's first drafts repeatedly tripped the long-standing rules — #408 critic "FAIL — Lens 2 (opaque condition codes) and Lens 7 (named tests + bracketed-CI bounds in narrative prose) ... an AI/process tell ('the codex critic surfaced') + shouty caps" (session e1e53b47); #458 needed a Lens-13 coverage fix (session dc93f209). Each costs a REVISE round. Proposed edit:

    + ## Pre-emission register self-check (run before posting the draft body)
    + - [ ] No opaque condition codes (B@k, A, M1, cond_4) in TL;DR/Findings prose — plain-English names only
    + - [ ] No named statistical tests / bracketed CIs in narrative prose (Reproducibility only)
    + - [ ] No process/AI tells ("the codex critic surfaced") or shouty CAPS
    + - [ ] `### What I ran` flags any planned cell/seed/factor that silently dropped (Lens 13)
    
  9. Target: .claude/agents/clean-result-critic.mdwhat: add a lens that hard-FAILs an H1 title / TL;DR headline resting on an arm the body itself flags as contaminated or failed-its-own-data-gate. Why: the #407 clean-result was titled/framed "content-agnostic gating" off an arm with contaminated training data (stale paraphrases) and string-lookup-inflated multiple-choice numbers; the user had to interrogate it repeatedly ("how did taught-wrong-info get ~100%?" / "mark it as bugged") before it was demoted (session 404cb6d9). Proposed edit:

    + Lens: if the body discloses a data-validity failure (contaminated training
    + pool, a Phase-0/K1 gate the arm failed, wrong base prior) for an arm, the H1
    + title and TL;DR headline MUST NOT rest a positive claim on that arm. Hard FAIL
    + — demote to a surviving clean arm or to "bugged."
    
  10. Target: .claude/skills/issue/SKILL.mdwhat: require a tasks/ + HF/WandB sweep for the answer before any non-gate AskUserQuestion. Why: the orchestrator twice surfaced a design-fork question before exhausting the resourceful path and was rejected both times — "Look deeper at other issues" after a reuse-vs-retrain ask (session c609f6f5); "Show me the body first" after a title-options ask (session 404cb6d9). Reinforces existing halt-criterion #1. Proposed edit:

    + Before any non-gate AskUserQuestion (design forks like reuse-vs-retrain, title
    + options), FIRST sweep tasks/ + HF/WandB for artifacts/answers that resolve it.
    + Ask only once the investigation leaves a genuine gap only the user can fill.
    + ("Look deeper first" / "show me the body first" rejections, 2026-06-01.)
    
  11. Target: ~/explore-persona-space/CLAUDE.md (the repo-root-branch rule) — what: add a post-commit verification step for mid-session workflow-file edits. Why: the corrected on-policy marker-leakage rule was committed but stranded on fix/sweep-ckpt-persist by a concurrent branch switch/merge, leaving the WRONG first-token version live on main until the user happened to ask "did you add this rule to CLAUDE.md?" (session 8e691b41). The guard_repo_root_branch.sh hook shipped today prevents the branch-switch cause but not a merge sweeping a committed edit onto a branch. Proposed edit:

    + After any CLAUDE.md / workflow-file edit committed mid-session, immediately
    + `git log -1 --oneline -- <file>` on `main` to confirm the commit landed on main
    + and was not swept onto a concurrent feature branch (incident 2026-06-01: the
    + corrected marker-leakage rule stranded on fix/sweep-ckpt-persist; main kept the
    + wrong first-token version).
    
  12. Target: .claude/skills/paper-plots/SKILL.mdwhat: require a color / stacked-bar segment to mean ONE fixed category across all panels of a figure. Why: the #407 per-framing figure put "counter" in bar position 2 of the contradictory panels but "refusal" in that position in the refusal panels, so columns weren't comparable; the user caught it ("the bars are showing different things in the graph?") (session 404cb6d9). Proposed edit:

    + Consistent encoding across facets: a given color or stacked-bar segment MUST
    + mean the same category in every panel. Use a fixed decomposition (e.g.
    + taught / counter / refusal / other) so columns are directly comparable.
    
  13. Target: .claude/skills/issue/SKILL.mdwhat: announce a follow-up/child task in chat at creation time (id + title + parent + status). Why: #461 was filed mid-session and worked on, but never announced, so the user lost track — "What is 461?" (session 9e667517). Proposed edit:

    + On creating a follow-up/child task mid-session, immediately post one line in
    + chat: "Filed #<N> '<title>' (child of #<parent>, status:<s>)". Don't let a
    + created task stay invisible until the user asks what it is.
    
  14. Target: ~/explore-persona-space/CLAUDE.md (Task Workflow API) — what: note that task.py must be invoked from repo root / by absolute path. Why: after cd "$(... task.py find <N>)", a later uv run python scripts/task.py ... resolved the relative path against the task folder → No such file or directory (session e1e53b47). Minor but recurring foot-gun. Proposed edit:

    + Note: after `cd "$(... task.py find <N>)"` you are in the task folder, not repo
    + root — invoke task.py by absolute path or `cd` back first; `scripts/task.py` is
    + relative to repo root.
    
  15. Target: .claude/skills/daily/SKILL.md (Commit step) — what: use git add -f for the daily file, because logs/ is gitignored. Why: hit live in this run. The skill's git add logs/daily/YYYY-MM-DD.md silently commits nothing (logs/ is .gitignore line 70: "no changes added to commit"), so the daily never lands in git or the dashboard. The 4 prior dailies are tracked only because they were force-added; the skill text doesn't say to. Proposed edit:

    - git add logs/daily/YYYY-MM-DD.md
    + git add -f logs/daily/YYYY-MM-DD.md   # logs/ is gitignored; force-add to match prior dailies
      git commit -m "logs: daily stub for YYYY-MM-DD"
    

Other problems & notes

Not /daily-proposal-scope (experiment code, infra, script-orchestration fixes, one-offs, or already-resolved). Each has a suggested action so nothing is dropped.

Resolved this session (verify on next use):

  • #458 data-loss (20 of 36 checkpoints deleted unrecoverably) — RESOLVED: trainer.py fail-loud adapter-persist before the delete-after-eval rm (merged 04265e50a) + CLAUDE.md Upload Policy rule + guard_repo_root_branch.sh hook. Action: confirm the persist path with a smoke run on the next delete-after-eval sweep.
  • Dashboard /updates/<N> 404s for Dan/Christina (May-29 refactor removed the route) — RESOLVED: redirect route → /tasks/<N>#feed-body deployed (session c73c7ae2). dashboard/ is outside /daily scope anyway. Action: none.
  • CLAUDE.md missing canonical KL/JS + cosine definitions — RESOLVED: full-response Rao-Blackwellized KL/JS + persona-vectors cosine definitions added after the user corrected a first-token-only JS implementation (session dc93f209). Action: none.

Script-orchestration fixes (greenlight workflow-improver separately — out of /daily proposal scope):

  • Idle-pod watchdog (script side, companion to proposal 1) — harden poll_pipeline.py / pod.py audit-stale to terminate a RUNNING-status epm-issue-<N> pod with no live process + no GPU compute-apps after a grace window, independent of whether upload-verification ever posted. A watchdog was added this session (#407) — Action: verify it fires on a post-eval aggregate-phase crash, not just a quiet training log.
  • poll_pipeline.py skipped #448's completion sentinel — the pod-side dispatcher wrote key schema, but the poller requires sentinel_schema_version; completion was missed and posted by hand (session 49bae5c4). Action: accept the legacy schema alias, or warn-don't-skip when a *-results.json sentinel is present but unparseable.
  • #444 preflight import-deadlock_smoke_check_train_lora imported TrainLoraConfig from sft.py, which transitively pulled vLLM and spawned a deadlocking child; first misdiagnosed as a transient hung Anthropic call (session 548d1293). Codex pushed 191c09bf ("keep SFT config import off vLLM path") but the day's last commit reads "partial progress." Action: confirm #444 preflight is fully unblocked; consider an explicit timeout on the preflight Anthropic call so a hung connection fails loud instead of stalling ~10 min.
  • rsync not installed on pods (3 sessions) — every pod artifact pull fell back to tar-over-ssh (sessions dc93f209, e1e53b47, 0253c931). Action: add rsync to bootstrap_pod.sh apt step, or make the artifact-pull helper default to pod.py sync results / tar-over-ssh.
  • pod-461 corrupted git index + untracked .claude/agent-memory/* blocked branch checkout — stale index.lock + truncated index on a fresh pod, plus agent-memory files blocking git checkout issue-456 (session 9e667517). Action: harden bootstrap_pod.sh to finish the initial checkout atomically and .gitignore/skip-sync .claude/agent-memory/ on pods.
  • Codex "gate-hopping" reconciler on #451 — Codex code-reviewer FAILed purely on the epm:experiment-implementation marker-shape/smoke-evidence FORMAT (not substance) while Claude PASSed, forcing a reconciler round (session 0253c931). A fix partially landed this session. Action: verify the mechanical-contract-only-FAIL stripper (SKILL.md Step 5c-bis) covers the code-reviewer Codex site, not just clean-result-critic.

Experiment-code bugs (route to experiment-implementer / a follow-up task):

  • Class C raw-format conditions (C2–C5) didn't implant the marker — full-sequence loss diluted the single marker token (1/300) to zero signal; 0/50 emitted, forcing a Class-C drop / N=16 (session 8e691b41). Action: train raw-format conditions with response-only (or marker-only) loss masking, or record Class C as untestable under this recipe in the #406 body.
  • [BATCH_ERROR] sentinels contaminated cached corpora (3–16%, concentrated in turns 16+) — failed batch-API turns wrote a literal placeholder instead of failing loud, poisoning the deepest k=20 training cells (session e1e53b47). Action: make corpus-gen fail-loud/retry on any [BATCH_ERROR] turn instead of persisting it.
  • #397: 12 of 36 recipes (the whole neutral-framing C-axis factor) silently died at data prep — librarian-pool padding bug + over-strict exact-token preflight + MIN_C_JACCARD=0.15 gate (session 0253c931). Action: gate relaxation + padding fix re-run is in flight as #451.
  • #460 parallel-wave CUDA OOM — cells weren't pinned to distinct GPUs; the documented +gpu_id/CVD-clobber gotcha (#376) recurring, patched in-run (session 8e691b41). Action: verify per-cell GPU pinning is the default in new i46x dispatchers.
  • #460 phase-1 R-generation TypeError: not enough arguments for format string (×2) — likely an unescaped % (or ) in a %-format log call; non-fatal but noisy (session 8e691b41). Action: audit the i460 phase1 logging format string.
  • All 11 #448 cells logged to a single WandB run — the dispatcher inited WandB once for the whole sweep (session 49bae5c4). Action: re-init WandB per cell if per-cell curves are wanted; eval/trajectory JSONs already carry per-cell numbers.
  • Missing #275 build_sycophancy_leakage_data.py — #448's persona-registry reconstruction importlib-loads a script from a reaped #275 worktree; rebuilt from HF artifacts (session 49bae5c4). Action: vendor the builder into the library instead of importing from a sibling worktree path.
  • #444 K1 zero-prior data gate miscalibrated — per-token log-prob < -8.0 nats can never pass for fluent English; killed Phase-0 before training (session 548d1293). Action: entropy-based K1 redesign is in flight; planner to ground the threshold.

Research-design tensions (not bugs):

  • #460 log-prob DV saturated at ceiling — the recipe needed to implant the marker at all (5 epochs × 300 rows) pins trained log P(※) ≈ 0 (237/240 cells within 0.1 nat), killing the dynamic range the divergence→transfer correlation needs (ρ = −0.11, null) (session 8e691b41). Action: the over-training-trajectory line (#462) is already probing a lighter recipe that leaves the DV unsaturated.
  • Predictor used 48 probes, not the requested ~200 — the Betley preregistered_evals.yaml source has only 48 question groups (session dc93f209). Action: none if 48 (the full prereg set) is acceptable; expand the probe source otherwise. Now documented in the CLAUDE.md canonical block.

Infra flakiness / one-offs (no action unless recurring):

  • Codex twin no-shows / sandbox infra failures — empty/missing Codex output files forced Claude-only rounds (sessions 8e691b41, 49bae5c4). Orchestrator already falls back. Action: note if the no-show rate stays high.
  • HF_TOKEN not auto-loaded into the shell — a bare os.environ['HF_TOKEN'] one-liner crashed; entrypoints load it via setup_env() only (sessions 49bae5c4, 8e691b41). Action: operator habit — wrap HF/WandB one-liners with the dotenv load.
  • 9 consecutive Edit "File modified since read" failures after a set-body — batched edits against a body.md that the assistant's own prior task.py set-body had rewritten on disk (session 49bae5c4). Action: re-Read body.md after any set-body before further Edits.
  • SSH MCP server-name guessepm-issue-444 (pod-naming convention) vs the registered pod-444 MCP entry; one wasted call (session dc2e0689). Action: reconcile the naming note if it recurs.
  • py-spy dump Permission denied on pod — couldn't attach to the stuck preflight process; fell back to /proc/network-state inference (session 548d1293). Action: none; note py-spy may need --native/sudo on RunPod.
  • Malformed tool call ("court" + raw <invoke> XML, ×2) — stray tokens after a <task-notification> in the poll-resume path; self-recovered (session dc93f209). Action: transient model glitch, no fix.
  • Self-inflicted recoveries — an Edit with a non-matching old_string; a verification script that asserted after rmtree'ing the dir it was checking (sessions 49bae5c4, 8e691b41). Action: none; one-off, recovered in-turn.

My thoughts

Highlighted results

  • no results promoted today (June 1 PT). #448 and #458 reached awaiting_promotion (clean-results drafted, not yet promoted); #432 was promoted at 23:20 PT May 31 and belongs to the May 31 daily.