Skip to content

docs(logbook): T7 continuous-substrate cross-architecture ranking (029) - #255

Merged
chrisjz merged 6 commits into
mainfrom
openspec/t7-n8-ranking
Jun 24, 2026
Merged

docs(logbook): T7 continuous-substrate cross-architecture ranking (029)#255
chrisjz merged 6 commits into
mainfrom
openspec/t7-n8-ranking

Conversation

@chrisjz

@chrisjz chrisjz commented Jun 24, 2026

Copy link
Copy Markdown
Member

What

The T7 (high-fidelity continuous-2D) cross-architecture ranking — the analogue of Logbook 025 (T4 grid). Ranks the 6 MUST arms on the integrated C3 cell (food + predator + thermotaxis) at n=8 paired seeds, plateau-tail full-clear, uniform 6000ep + a 5-seed 8000ep convergence top-up, with paired Wilcoxon + 80% bootstrap + BH-FDR (the committed architecture-comparison-protocol stats layer).

Result

MLP 89.0 â‰Ŧ {CfC 75.8 ≈ Transformer 74.0} > LSTM 60.1 > connectome 52.2 â‰Ŧ GA 15.0 — three significant tiers (BH-FDR), robust across budget levels.

  • MLP is the unambiguous leader and best on all three behaviours.
  • CfC ≈ Transformer for Predator evasion #2 (statistical tie, q=0.53).
  • Connectome 5th — significantly below the trained nets (its T4 predator-evasion lag confirmed on the high-fidelity substrate) but significantly above gradient-free search; it learns the cell (52%, 8/8 converged) — not a STOP (Gate-3 G3.b).
  • GA is the significant floor (gradient-free weight search doesn't solve the integrated cell — reproduces T4).
  • The deliberately sub-saturation cell discriminates where T4's flat ~84% cluster tied.

Contents

  • docs/experiments/logbooks/029-continuous-architecture-ranking.md — main logbook (modeled on 025).
  • supporting/029/ — analysis outputs only (~28 KB, following 025's lighter practice): per-seed CSV, per-behaviour CSV, pairwise-stats JSON, GA results, details.md (budget-iteration story + the methodology dig-ins).
  • scripts/analysis/t7_continuous_ranking.py + t7_ga_champion_eval.py — the ranking harness (reuses the committed Wilcoxon/bootstrap/BH-FDR helpers).
  • Tracker: checked off the 6 c3_integrated cells + analysis.{ranking_upgraded, env_delta, connectome_final_ranking}.
  • MLP config: removed the dead entropy_coef_end/entropy_decay_episodes keys (mlpppo never implemented the schedule; it ran flat 0.08) + relabeled.
  • README active-experiments index entry.

Methodology (two dig-in fixes the result depended on)

  1. Level-agnostic ranked metric (feat(benchmark): level-agnostic plateau convergence detection #250) — the prior detector null'd sub-50% plateaus → a noisy last-10 fallback that mis-ranked arms; replaced with a plateau-tail metric + the real converged flag.
  2. Uniform budget — the arms learn at very different rates; at 3000–4000ep slow-climbers were under-ranked (CfC rose 65→76 at fair budget, moving it into the Predator evasion #2 tie).

Scope

T7.logbook is left unchecked — T7 is NOT closed. This publishes the MUST ranking; the SHOULD/MAY arms and a memory-bound control are deferred to a follow-up (the box ticks at T7 closure, not here).

Validation

openspec validate --strict ✓; pre-commit (ruff/pyright/mdformat/markdownlint/tests) ✓; all cross-doc links resolve; numbers cross-checked (logbook = CSV = pairwise JSON); no tmp/ links or home paths; no LFS-worthy files.

ðŸĪ– Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added new analysis workflows for continuous-2D cross-architecture ranking and FeedforwardGA “champion” evaluation, producing aggregated rankings, per-architecture behavior summaries, and exportable JSON results.
  • Documentation
    • Updated experiment tracking with an “Active Experiments” entry and added a detailed logbook plus supporting result tables for the continuous-substrate architecture ranking.
  • Bug Fixes
    • Updated a scenario configuration to reflect flat entropy handling (and removed/ignored prior entropy-annealing schedule keys), aligning documented settings with actual behavior.

chrisjz and others added 3 commits June 23, 2026 17:49
â€ĶWIP)

Plateau-tail (final-quarter) success + foods as the robust ranked metric (reads
the real convergence_run flag; avoids the last-10 fallback), reusing the
committed paired-Wilcoxon/bootstrap/BH-FDR stats layer. Results + logbook land
once the n>=8 @6000ep runs complete.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Publish logbook 029 — the T7 (high-fidelity continuous-2D) analogue of 025: the
6-MUST-arm integrated-C3 ranking (n=8 paired seeds, plateau-tail full-clear @
uniform 6000ep + a 5-seed 8000ep convergence top-up; paired Wilcoxon + 80%
bootstrap + BH-FDR via the committed stats layer).

Ranking: MLP 89.0 >> {CfC 75.8 ~ Transformer 74.0} > LSTM 60.1 > connectome 52.2
>> GA 15.0 — three significant tiers, robust across budgets. MLP best on all
three behaviours; connectome 5th (T4 evasion-lag confirmed, but learns the cell
8/8 — not a STOP, G3.b); GA gradient-free floor; the sub-saturation cell
discriminates where T4's flat cluster tied.

- Main logbook + supporting/029 (per-seed CSV, pairwise-stats JSON, GA results,
  budget-iteration + dig-in detail). Following 025's lighter artifact practice:
  analysis outputs only (~28K), no raw session dumps or weights.
- Tracker: check off the 6 c3_integrated cells + analysis.{ranking_upgraded,
  env_delta,connectome_final_ranking}. T7.logbook left UNCHECKED — T7 not closed
  (SHOULD/MAY arms + a memory-bound control deferred).
- MLP config: remove the dead entropy_coef_end/entropy_decay_episodes keys
  (mlpppo never implemented the schedule; it ran flat 0.08) + relabel the recipe.
- README active-experiments index updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

â„đïļ Recent review info
⚙ïļ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1ca41660-edc8-4013-96ff-cbfcdd02b3f3

ðŸ“Ĩ Commits

Reviewing files that changed from the base of the PR and between 843510c and 05f201a.

📒 Files selected for processing (4)
  • docs/experiments/logbooks/supporting/029-continuous-architecture-ranking/cross_arch_pairwise.json
  • docs/experiments/logbooks/supporting/029-continuous-architecture-ranking/ga_c3_results.json
  • scripts/analysis/t7_continuous_ranking.py
  • scripts/analysis/t7_ga_champion_eval.py
✅ Files skipped from review due to trivial changes (2)
  • docs/experiments/logbooks/supporting/029-continuous-architecture-ranking/ga_c3_results.json
  • docs/experiments/logbooks/supporting/029-continuous-architecture-ranking/cross_arch_pairwise.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • scripts/analysis/t7_ga_champion_eval.py
  • scripts/analysis/t7_continuous_ranking.py

📝 Walkthrough

Walkthrough

Adds T7 ranking and GA evaluation scripts, supporting result data, the Experiment 029 logbook and appendix, removes the MLPPPO entropy schedule keys, and updates the Phase 6 tracker plus experiments README.

Changes

T7 Cross-Architecture Ranking (Experiment 029)

Layer / File(s) Summary
Remove MLPPPO entropy schedule keys
configs/scenarios/foraging_predator_thermal/mlpppo_small_continuous2d_combined_klinotaxis.yml
Updates the MLPPPO scenario comment to describe a flat entropy coefficient and removes the brain-config entropy annealing keys.
Cross-architecture ranking analysis script
scripts/analysis/t7_continuous_ranking.py
Adds the continuous-C3 ranking CLI, plateau-tail metric parsing, PPO metric loading, GA merge handling, pairwise ranking statistics, and per-behaviour aggregation.
GA champion full-clear evaluator script
scripts/analysis/t7_ga_champion_eval.py
Adds the GA champion evaluation CLI, loads the simulation config and encoder, evaluates success and progress metrics for each seed, and writes aggregated results JSON.
Pairwise and GA result data files
docs/experiments/logbooks/supporting/029-continuous-architecture-ranking/cross_arch_pairwise.json, docs/experiments/logbooks/supporting/029-continuous-architecture-ranking/ga_c3_results.json
Adds the pairwise cross-architecture comparison JSON and the GA champion results JSON.
Experiment 029 logbook and supporting appendix
docs/experiments/logbooks/029-continuous-architecture-ranking.md, docs/experiments/logbooks/supporting/029-continuous-architecture-ranking/details.md
Adds the Experiment 029 logbook with objective, method, results, analysis, conclusions, limitations, next steps, and data references, plus the supporting appendix with per-seed tables, statistics, budget narrative, recipes, methodology findings, and GA evaluation notes.
Phase 6 tracker and experiments README
openspec/changes/phase6-tracking/tasks.md, docs/experiments/README.md
Marks T7 MUST and analysis checklist items complete, records the deferred SHOULD/MAY and memory-bound control items, and adds Experiment 029 to the active experiments README.

Estimated code review effort

ðŸŽŊ 3 (Moderate) | ⏱ïļ ~25 minutes

Possibly related PRs

  • SyntheticBrains/nematode#249: Directly introduced the MLPPPO continuous-2D integrated-cell config whose entropy annealing keys are removed in this PR.
  • SyntheticBrains/nematode#252: Updates the same T7 Phase 6 tracker sections around the plateau/convergence ranking work that this PR’s analysis scripts and logbook support.
  • SyntheticBrains/nematode#233: Aligns with the one-sided Wilcoxon plus bootstrap confidence-interval ranking method used in the new cross-architecture analysis.

🐇 I hopped through logs with a fluffy grin,
Flat entropy now, no schedule within.
Six ranks in a row, and the stats all sing,
GA champion scores with a tidy spring.
The tracker is checked, the logbook is set —
I nibble a carrot and dance a duet! ðŸĨ•

ðŸšĨ Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠ïļ Warning Docstring coverage is 77.78% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: publishing the T7 continuous-substrate cross-architecture ranking logbook 029.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏ïļ Tip: You can configure your own custom pre-merge checks in the settings.

âœĻ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧊 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch openspec/t7-n8-ranking

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

ðŸĪ– Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@docs/experiments/logbooks/supporting/029-continuous-architecture-ranking/ga_c3_results.json`:
- Around line 1-34: The GA results JSON is keyed by seed at the top level, but
the ranking ingestion in t7_continuous_ranking.py expects a "results" object, so
this payload is currently ignored. Fix the contract by either wrapping the seed
entries under a top-level "results" key in ga_c3_results.json or updating the
loader logic in the ranking script to accept both the existing top-level schema
and the "results"-wrapped schema. Make the change in the ranking loader path
that uses json.loads(...).get("results", {}) so GA data is preserved.

In `@scripts/analysis/t7_continuous_ranking.py`:
- Around line 61-82: The ranking path in t7_continuous_ranking.py currently
ignores episode budget, so mixed 3000/4000/6000-run manifests can still be
ranked together. Add a budget validation step before computing the plateau tail
in _plateau_tail and the downstream ranking flow (the related logic in the
referenced sections) so only a uniform 6000-episode dataset is accepted, and
fail fast or skip inputs that do not match the expected budget.
- Around line 128-145: The paired-seed ranking logic in the continuous-ranking
script is using partial overlaps, which changes the effective sample size per
comparison and can drop GA silently. Add a validation step in the
results-loading/ranking path (near the code that builds the `table` and before
any pairwise tests) to require a complete seed panel for every arm, including
`feedforwardga`, and fail fast if any seeds are missing. Then compute a single
shared seed intersection once and reuse it for all comparisons instead of
recomputing `common` per pair.

In `@scripts/analysis/t7_ga_champion_eval.py`:
- Around line 63-92: The GA seed scan in the loop over
args.runs_dir.glob("resultsdir_s*.txt") should fail fast when no files are found
instead of writing an empty results object and printing a nan mean. Add an
explicit empty-check before the evaluation loop in the script that builds
results/resultsdir entries, and raise an error or exit with a clear message if
no matching seeds are present so downstream ranking cannot silently proceed with
a missing GA arm.
🊄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

â„đïļ Review info
⚙ïļ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6d5dd27c-1e61-46dc-adce-033110268573

ðŸ“Ĩ Commits

Reviewing files that changed from the base of the PR and between 3a84261 and 843510c.

⛔ Files ignored due to path filters (2)
  • docs/experiments/logbooks/supporting/029-continuous-architecture-ranking/per-behaviour.csv is excluded by !**/*.csv
  • docs/experiments/logbooks/supporting/029-continuous-architecture-ranking/ranking-per-seed.csv is excluded by !**/*.csv
📒 Files selected for processing (9)
  • configs/scenarios/foraging_predator_thermal/mlpppo_small_continuous2d_combined_klinotaxis.yml
  • docs/experiments/README.md
  • docs/experiments/logbooks/029-continuous-architecture-ranking.md
  • docs/experiments/logbooks/supporting/029-continuous-architecture-ranking/cross_arch_pairwise.json
  • docs/experiments/logbooks/supporting/029-continuous-architecture-ranking/details.md
  • docs/experiments/logbooks/supporting/029-continuous-architecture-ranking/ga_c3_results.json
  • openspec/changes/phase6-tracking/tasks.md
  • scripts/analysis/t7_continuous_ranking.py
  • scripts/analysis/t7_ga_champion_eval.py

Comment on lines +61 to +82
def _plateau_tail(out_path: Path) -> tuple[float, float] | None:
"""(full-clear success %, mean foods) over the final-quarter plateau tail, from the .out.

The robust primary (success) + foraging sub-metric (foods), read from the per-run
``.out`` rather than the JSON's ``post_convergence_*`` / ``avg_*`` fields: the
post-convergence fields fall back to a noisy last-10-run mean for non-converged runs,
and the ``avg_*`` fields include the warm-up. The plateau-tail mean is the robust
plateau level (it equals ``post_convergence_success_rate`` within sampling noise for
converged seeds — the metric's final-window cross-check).
"""
if not out_path.exists():
return None
succ, foods = [], []
for ln in out_path.read_text().splitlines():
m = re.match(r"Run:\s+\d+\s+Status:\s+(\S+).*?Eaten:\s+(\d+)/", ln)
if m:
succ.append(1.0 if m.group(1) == "SUCCESS" else 0.0)
foods.append(int(m.group(2)))
if not succ:
return None
tail = max(1, int(len(succ) * _FINAL_WINDOW_FRAC))
return 100.0 * float(np.mean(succ[-tail:])), float(np.mean(foods[-tail:]))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ðŸŽŊ Functional Correctness | 🟠 Major | ⚡ Quick win

Validate the episode budget before ranking.

This script discards run length and even documents mixed budgets as acceptable, so a manifest that blends 3000/4000/6000-episode runs will still produce a ranking. That reintroduces the exact slow-learner under-ranking problem the T7 methodology says was fixed by moving to a uniform 6000-episode budget plus a separate 8000-episode sensitivity pass.

Suggested change
-def _plateau_tail(out_path: Path) -> tuple[float, float] | None:
+def _plateau_tail(out_path: Path) -> tuple[float, float, int] | None:
@@
-    return 100.0 * float(np.mean(succ[-tail:])), float(np.mean(foods[-tail:]))
+    return 100.0 * float(np.mean(succ[-tail:])), float(np.mean(foods[-tail:])), len(succ)
@@
-    success, foods_tail = tail
+    success, foods_tail, run_count = tail
     r = json.loads(jpath.read_text()).get("results", {})
@@
         "overall_success": (r.get("success_rate") or 0.0) * 100.0,
         "foods": foods_tail,
+        "run_count": run_count,
         "evasion_rate": (evas / enc * 100.0) if (enc and enc > 0) else None,
         "temp_comfort": r.get("post_convergence_temperature_comfort_score"),
     }
@@
     for arch in PPO_ARCHS:
         missing = [s for s in range(1, 9) if s not in table[arch]]
         if missing:
             print(f"  WARN {arch}: {len(missing)} seed(s) missing experiment JSON {missing}")
+
+    run_counts = {
+        m["run_count"]
+        for arch in PPO_ARCHS
+        for m in table[arch].values()
+        if "run_count" in m
+    }
+    if len(run_counts) != 1:
+        msg = f"Mixed PPO budgets in ranking input: {sorted(run_counts)}"
+        raise ValueError(msg)

Also applies to: 85-111, 114-145

ðŸĪ– Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/analysis/t7_continuous_ranking.py` around lines 61 - 82, The ranking
path in t7_continuous_ranking.py currently ignores episode budget, so mixed
3000/4000/6000-run manifests can still be ranked together. Add a budget
validation step before computing the plateau tail in _plateau_tail and the
downstream ranking flow (the related logic in the referenced sections) so only a
uniform 6000-episode dataset is accepted, and fail fast or skip inputs that do
not match the expected budget.

Comment on lines +128 to +145
for arch in PPO_ARCHS:
missing = [s for s in range(1, 9) if s not in table[arch]]
if missing:
print(f" WARN {arch}: {len(missing)} seed(s) missing experiment JSON {missing}")

if ga_results and ga_results.exists():
ga = json.loads(ga_results.read_text())
table["feedforwardga"] = {
int(s): {
"success": v["full_clear_rate"],
"converged": None, # n/a — the GA champion eval has no training-plateau notion
"foods": v.get("mean_foods"),
"evasion_rate": None,
"temp_comfort": None,
}
for s, v in ga.items()
}
return table

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄ïļ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Reject incomplete seed panels instead of recomputing common per pair.

The published method is a 6-arm, paired-seed n=8 ranking, but this only prints warnings for missing seeds and then runs each pairwise test on whatever overlap happens to exist. That silently changes n between comparisons and can even omit GA entirely while still emitting BH-FDR results.

Suggested guard
     for arch in PPO_ARCHS:
         missing = [s for s in range(1, 9) if s not in table[arch]]
         if missing:
-            print(f"  WARN {arch}: {len(missing)} seed(s) missing experiment JSON {missing}")
+            msg = f"{arch} is missing paired seeds {missing}"
+            raise ValueError(msg)
@@
     if ga_results and ga_results.exists():
         ga = json.loads(ga_results.read_text())
         table["feedforwardga"] = {
@@
             for s, v in ga.items()
         }
+        missing = [s for s in range(1, 9) if s not in table["feedforwardga"]]
+        if missing:
+            msg = f"feedforwardga is missing paired seeds {missing}"
+            raise ValueError(msg)
+    else:
+        raise ValueError("ga_results is required for the 6-arm T7 ranking")
@@
     for a, b in combinations(sorted(archs, key=lambda x: -means[x][0]), 2):
         common = sorted(
             set(_per_seed(primary[a], "success")) & set(_per_seed(primary[b], "success")),
         )
+        if common != list(range(1, 9)):
+            msg = f"Pair {a} vs {b} is not using the full paired seed panel: {common}"
+            raise ValueError(msg)
         deltas = [primary[a][s]["success"] - primary[b][s]["success"] for s in common]

Also applies to: 185-202

ðŸĪ– Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/analysis/t7_continuous_ranking.py` around lines 128 - 145, The
paired-seed ranking logic in the continuous-ranking script is using partial
overlaps, which changes the effective sample size per comparison and can drop GA
silently. Add a validation step in the results-loading/ranking path (near the
code that builds the `table` and before any pairwise tests) to require a
complete seed panel for every arm, including `feedforwardga`, and fail fast if
any seeds are missing. Then compute a single shared seed intersection once and
reuse it for all comparisons instead of recomputing `common` per pair.

Comment thread scripts/analysis/t7_ga_champion_eval.py Outdated
chrisjz and others added 3 commits June 24, 2026 22:31
Two silent-failure gaps from branch review:
- t7_ga_champion_eval.py: raise (instead of writing an empty results JSON +
  printing a nan mean) when the runs-dir has no resultsdir_s*.txt pointers.
- t7_continuous_ranking.py: warn (instead of silently excluding the GA arm) when
  --ga-results is provided but the file is missing/empty.

Skipped the other review findings as not-valid against current code: the GA
loader reads the top-level seed-keyed dict via ga.items() (NOT the PPO
.get("results") path — GA already ingests correctly, confirmed by the published
ranking); the plateau-tail metric is intentionally budget-agnostic and the
protocol allows non-uniform budgets (the final ranking itself mixes 6000/8000ep);
and per-pair common-seed intersection is the established (025) paired-test
behaviour that uses more data than a single global intersection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@chrisjz
chrisjz merged commit fc180f8 into main Jun 24, 2026
2 checks passed
@chrisjz
chrisjz deleted the openspec/t7-n8-ranking branch June 24, 2026 12:56
@codecov

codecov Bot commented Jun 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

ðŸ“Ē Thoughts on this report? Let us know!

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