Skip to content

research(worldmodel): overnight forward-eval — no knob lifts control (nodes 7-13)#22

Open
aurascoper wants to merge 8 commits into
mainfrom
worldmodel/overnight-transform-ab
Open

research(worldmodel): overnight forward-eval — no knob lifts control (nodes 7-13)#22
aurascoper wants to merge 8 commits into
mainfrom
worldmodel/overnight-transform-ab

Conversation

@aurascoper

Copy link
Copy Markdown
Owner

What

Overnight autonomous WorldModel forward-eval research (nodes 7–13), run under the /loop harness. Systematically tests whether any tunable knob improves control (goal-conditioned latent MPC) on the synthetic-1/f JEPA. Two small eval-harness features + a fully-ledgered chain of A/Bs. WorldModel/ only — no Sources/, no app coupling.

The result (converged)

No knob lifts control above chance, and every representation-improving change is neutral-to-harmful for it. The ceiling is the JEPA objective (it optimizes representation, not control) and the goal-latent planning geometry.

node category finding
7 Document standardize is the baseline, not a treatment (the dataset already z-scores at the seam)
8 Integrate symlog (`sign(x)·log1p(
9 Benchmark symlog = neutral; confirmed the epsilon-floor (not log-compression) was log_features' node-33 harm
10 Integrate exposed the CEM knobs (mpc_cem_iters/mpc_n_samples/mpc_elite_frac) through evaluate() + CLI
11 Benchmark more CEM budget does not help MPC — the planner isn't the bottleneck
12 Benchmark more predictor capacity (epochs+latent) HURTS control (MPC→chance) while improving the static chi probe
13 Benchmark triple dissociation (corrects node 12): epochs drive 4× rollout error (control-neutral); latent_dim crashes MPC below chance (rollout-neutral); rollout and mpc are driven by different knobs and are not interchangeable proxies

Full narrative in WorldModel/EXPERIMENT_LEDGER.md (nodes 7–13).

Code changes (2 files)

  • WorldModel/eeg_jepa.pysymlog transform on JEPATransitionDataset (mutually exclusive with log_features; log1p(0)=0 avoids the epsilon-floor outlier).
  • WorldModel/forward_eval.py — thread symlog + expose CEM knobs through evaluate(), the 3 dataset constructions, the config panel, and the CLI; smoke-test extended to exercise the symlog path.

Tests

venv/bin/python WorldModel/forward_eval.py --smoke-test passes (baseline + log_features + symlog arms all finite). A/Bs were run at n=384, 22 epochs, 3 seeds × 2 modes each; numbers in the ledger.

Scope / caveats

  • Synthetic task only — no real EEG, no app wiring (per WorldModel/README.md's decoupling).
  • The negative result is the deliverable: it redirects the next lever from knob-tuning to a new objective (a model-based-control training signal / control-aware goal metric) — a design decision, not built here.

🤖 Generated with Claude Code

aurascoper and others added 8 commits July 21, 2026 03:16
…t a treatment

Audited JEPATransitionDataset (WorldModel/eeg_jepa.py): the default normalize=True
already z-scores per feature (mean/std from the train split, clamp at sigma 8), so
the log_features=OFF baseline that node 33 calls raw z-scored IS standardization.
Drop standardize as an A/B arm; it is the control. Next distinct buildable arm is
symlog. Documentation only, no code change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MprrYMDxCHVsP8UiHkwBBx
Add symlog = sign(x)*log1p(|x|) as a mutually-exclusive-with-log_features
transform at the JEPATransitionDataset seam (WorldModel/eeg_jepa.py), applied
pre-normalization so stats are computed in symlog-space. Unlike log_features,
log1p(0)=0 preserves zero/near-dead channels exactly instead of mapping them to
log(1e-6) ~ -13.8, a large negative outlier the z-score amplifies.

Thread symlog through evaluate() and all three dataset constructions (train,
rollout, MPC-encode) so they share one input space; add --symlog CLI, config
panel field, and a smoke assertion that the symlog path stays finite. Smoke test
passes. A/B benchmark pending (node 9). WorldModel/ only, two files.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MprrYMDxCHVsP8UiHkwBBx
12-cell A/B {symlog off/on} x {signal,nuisance} x seeds{0,1,2}, n=384, 22 epochs.
Pooled OFF->ON: rollout 0.0120->0.0122 (delta +0.0002, well below the +/-0.0022
seed noise), mpc 0.342->0.358 (within noise), chi 0.9501->0.9545 (small consistent
gain). Confirms node 8: the epsilon floor was log_features' rollout harm (which was
+37%); symlog with log1p(0)=0 removes it, dropping the harm to ~0. But symlog does
not IMPROVE the forward metrics, so it stays default OFF. Three arms in (standardize
= baseline, log_features = reject, symlog = neutral), no transform beats raw z-score.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MprrYMDxCHVsP8UiHkwBBx
Per the overnight user redirect: the transform-A/B line converged (no input-space
transform beats raw z-score; nodes 7/33/9), so pivot to the weakest forward metric
-- MPC success barely beats random. Expose the CEM planner knobs (mpc_cem_iters,
mpc_n_samples, mpc_elite_frac) through evaluate() and the CLI; they were hardcoded
at 3/64/0.2 in _mpc_success. Add them to the config panel.

Single-seed sanity: base (3/64) MPC 0.300 -> tuned (8/192) MPC 0.400 vs the same
0.200 random baseline, same predictor -- more planning budget lifts success. Proper
multi-seed sweep launched to background for node 11. Smoke test passes (defaults
unchanged). WorldModel/forward_eval.py only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MprrYMDxCHVsP8UiHkwBBx
12-cell A/B {default(3,64) vs tuned(8,192)} x {signal,nuisance} x seeds{0,1,2},
n=384, 22 epochs. mpc_success default=0.342+/-0.151 vs tuned=0.325+/-0.144 (delta
-0.017, within the +/-0.15 seed noise). Per (mode,seed) the tuned plans match
default almost exactly — more planning budget finds the same plans. The single-seed
0.30->0.40 sanity was noise. Reject the CEM-budget hypothesis; keep default 3/64.
The MPC ceiling (~0.34 vs 0.29 random) is the predictor's latent-dynamics accuracy,
not the planner. Next lever: predictor quality (epochs / latent_dim).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MprrYMDxCHVsP8UiHkwBBx
12-cell A/B {default(22ep,32d) vs pushed(44ep,64d)} x {signal,nuisance} x seeds.
mpc_success 0.342 -> 0.292 (lands exactly on the 0.2917 random baseline: control
collapses to chance). rollout_mean 0.0120 -> 0.0478 (4x worse). chi 0.9501 -> 0.9744
(better static factor recovery). So a bigger/longer predictor polishes the
representation while destroying forward dynamics + control -- same dissociation as
node 33's log_features. The 4x rollout jump fingers latent_dim=64 over the epochs.

Reject the capacity lever; keep default. Accumulated: no knob (transform / planner /
predictor capacity) lifts control above ~0.34 vs 0.29 chance. The ceiling is the
JEPA objective (representation, not control) -- a design decision for the user, not
an overnight build. One clean confound-decoupling A/B (epochs-only vs latent-only)
remains before declaring the knob line converged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MprrYMDxCHVsP8UiHkwBBx
…line converged

Decoupling A/B {epochs_only(44,32) vs latent_only(22,64)} vs node-12 default(22,32).
Corrects node 12's attribution: the 4x rollout blow-up was EPOCHS (rollout
0.0120->0.0494, mpc unchanged 0.333), not latent_dim. The MPC collapse was
LATENT_DIM (mpc 0.342->0.217, below the 0.292 random baseline, while rollout stayed
0.0105 and chi rose to 0.970). So rollout_error and mpc_success are driven by
different knobs and are not interchangeable proxies; and a bigger latent is a better
representation (chi up) yet a worse planning substrate (MPC below chance).

Keep default (22ep,32d). Across nodes 7-13 no knob lifts control above ~0.34 vs 0.29
chance; representation-improving changes are neutral-to-harmful for control. The knob
line is CONVERGED — the ceiling is the JEPA objective and the goal-latent planning
geometry, both design decisions for the user, not overnight builds. Parking here.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MprrYMDxCHVsP8UiHkwBBx
…symlog

Two review findings (neither corrupts the delivered synthetic A/Bs, which both
reviewers verified sound):
- Finding A (provenance): add mpc_elite_frac to the forward_eval.py config panel;
  node 10 claimed all three CEM knobs were logged but elite_frac was omitted. The
  node-11 sweep held it at 0.2, so its numbers are unaffected.
- Finding B (latent trap): add --symlog to the real-data trainer eeg_jepa.py and
  thread it into the train + val JEPATransitionDataset constructions; it had
  --log-features but not --symlog, so a future real-EEG symlog A/B would have
  silently trained the baseline. Mutual-exclusion guard confirmed on this path too.
- Also refresh the evaluate() docstring to describe symlog (node-7) alongside
  log_features (node-33), and ledger the three findings incl. Finding C (symlog ==
  log1p on nonnegative powers; the epsilon-floor distinction is the real one).

Both smoke tests pass. WorldModel/ only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MprrYMDxCHVsP8UiHkwBBx
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant