Conversation
GeoGuesser already measures frac_reward_zero_std; TRL still trains on those groups. This adds the 2,309-word list as a training env, an estimator that splits dead groups into cliffs and collapse, a CPU ablation, and a reanalysis of GeoGuesser's published medians. Co-authored-by: Grok 4.6 <grok@x.ai>
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved moderate issues remain in the training recipes and GeoGuesser analysis/configuration.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Adds a Wordle GRPO project that classifies dead groups as reward cliffs or policy collapse, with a 2,309-word environment, CPU experiments, GeoGuesser analysis, training recipes, tests, and reproducibility artifacts.
Changes:
- Adds Wordle gameplay, rewards, information-gain scoring, and dataset splits.
- Adds alive-group classification, GRPO experiments, and GeoGuesser simulations.
- Adds documentation, test coverage, result artifacts, and project metadata.
File summaries
| File | Reviewed change / final review note |
|---|---|
README.md |
Registers the Wordle project. |
04-wordle/train/tiny_grpo.py |
Implements CPU GRPO training. Moderate (2 votes): non-skipping arms drop zero-advantage rollouts, so they do not match the claimed vanilla GRPO baseline. |
04-wordle/train/test_tiny.py |
Tests the tiny policy trainer. |
04-wordle/train/test_geoguesser_run4.py |
Tests GeoGuesser helpers. |
04-wordle/train/test_alive.py |
Tests classification and estimators. |
04-wordle/train/README.md |
Documents training scripts. Nit (1 vote): the dead-group metric should correspond to frac_dead, not frac_cliff. |
04-wordle/train/grpo_wordle.py |
Provides the TRL recipe. Moderate (3 votes): recorded cliff tasks are never replayed. Moderate (3 votes): the recipe does not apply the documented centered-rank estimator. |
04-wordle/train/geoguesser_run4.py |
Provides GeoGuesser classification helpers. Moderate (1 vote): advertised skip/stop settings are not wired through. Moderate (1 vote): collapsed groups can still receive a train recommendation. |
04-wordle/train/analyse_geoguesser.py |
Simulates GeoGuesser dead groups. Moderate (2 votes): the no-submission model is not calibrated to the cited zero-scoring data. Moderate (2 votes): resampling changes the task median instead of preserving the same task. |
04-wordle/train/alive.py |
Implements group classification, advantages, and replay weighting. |
04-wordle/results/tiny-ablation.json |
Stores CPU ablation results. |
04-wordle/results/tiny-ablation.csv |
Stores ablation curves. |
04-wordle/results/README.md |
Documents generated result artifacts. |
04-wordle/results/geoguesser-dead-groups.json |
Stores GeoGuesser simulation results. |
04-wordle/REPRODUCE.md |
Provides reproduction commands. |
04-wordle/README.md |
Documents the environment and findings. Nit (1 vote): the dead-group metric should correspond to frac_dead, not frac_cliff. |
04-wordle/project.yaml |
Defines project metadata. |
04-wordle/LEARNINGS.md |
Records experiment conclusions. |
04-wordle/envs/wordle/rollout.py |
Provides a readable rollout. Nit (1 vote): the docstring describes candidate scoring that the implementation does not perform. |
04-wordle/envs/wordle/core/words.py |
Loads the answer vocabulary. |
04-wordle/envs/wordle/core/test_core.py |
Tests Wordle domain behavior. |
04-wordle/envs/wordle/core/tasks.py |
Defines training and evaluation splits. |
04-wordle/envs/wordle/core/rewards.py |
Defines reward shapes. |
04-wordle/envs/wordle/core/information.py |
Computes remaining candidates and information gain. |
04-wordle/envs/wordle/core/game.py |
Implements Wordle gameplay and feedback. |
04-wordle/envs/wordle/core/answers.txt |
Adds the 2,309-word answer list. |
04-wordle/envs/wordle/core/__init__.py |
Exports core APIs. |
Review details
Suppressed comments (5)
04-wordle/README.md:102
frac_reward_zero_stdcounts every dead group, so it corresponds toalive/frac_dead(frac_cliff + frac_collapse), notalive/frac_cliff. These metrics will diverge as soon as collapse is nonzero, causing the suggested check to report a false mismatch.
Watch `alive/frac_cliff` against TRL's `frac_reward_zero_std`. They should agree. Watch `alive/frac_collapse`, which TRL does not report. If collapse is high and solve rate has been flat for 50 steps, stop. That is the $70.
04-wordle/envs/wordle/rollout.py:5
- The docstring says the rollout chooses the remaining answer that keeps the most greens, but the implementation simply uses
left[0]and never scores candidate guesses. The description should match the deterministic first-candidate behavior, or the selection algorithm should be implemented.
Uses the frequency opener CRANE, then picks the remaining answer that keeps
the most greens. Not a policy — a trajectory, so you can see what the
environment actually returns before anyone trains against it.
04-wordle/train/README.md:20
frac_reward_zero_stdcounts every dead group, so it corresponds toalive/frac_dead(frac_cliff + frac_collapse), notalive/frac_cliff. These metrics will diverge as soon as collapse is nonzero, causing the suggested check to report a false mismatch.
Step 3 has not been run in this contribution. The numbers in the project README are from steps 1 and 2. If you run step 3, the metric to watch is `alive/frac_cliff` against TRL's `frac_reward_zero_std` — they should agree — and `alive/frac_collapse`, which TRL does not report.
04-wordle/train/geoguesser_run4.py:102
- The recommended launch settings above advertise
ALIVE_SKIP_CLIFF=1andALIVE_STOP_COLLAPSE=0.8, but this helper omits both and the existing GeoGuesser trainer does not consume them. Callingrun4_env()therefore cannot enable the promised skip/stop behavior; add the settings and wire them into the caller, or remove them from the launch recommendation.
"NUM_GENERATIONS": "8",
"SAVE_STEPS": "25",
"MAX_TURNS": "12",
}
04-wordle/train/geoguesser_run4.py:80
- For a collapsed group whose mean turn count is above the 1.5 threshold,
skipremains true by default butrecommendationis stilltrain. A consumer following the recommendation can run the backward pass that this report says to skip; handle all collapse groups explicitly and reservetrainfor live groups.
else:
recommendation = "train"
- Files reviewed: 27/27 changed files
- Comments generated: 5
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+73
to
+77
| task_median = rng.lognormal(mean=math.log(MEDIAN_KM), sigma=0.85, size=n_tasks) | ||
| jitter = rng.normal(0.0, 0.35, size=(n_tasks, group)) | ||
| distances = task_median[:, None] * np.exp(jitter) | ||
| missing = rng.random((n_tasks, group)) < NO_GUESS | ||
| distances = distances.astype(np.float64) |
| def main() -> None: | ||
| rng = np.random.default_rng(0) | ||
| distances = sample_task_distances(rng, N_TASKS, GROUP) | ||
| extra = sample_task_distances(rng, N_TASKS, GROUP) |
Comment on lines
+137
to
+141
| _REPLAY.observe(task_id, kind) | ||
| if kind == "cliff": | ||
| # Point a random other index at this task for the rest of the run. | ||
| donor = random.randrange(len(_ANSWERS)) | ||
| _REMAP[donor] = task_id |
Comment on lines
+256
to
+259
| # Rank advantages are the tiny-policy default. TRL will still | ||
| # subtract the group mean; centered ranks are invariant to that. | ||
| # `group` is run 1's amplifier — leave it available as an env. | ||
| scale_rewards=os.getenv("SCALE_REWARDS", "none"), |
Comment on lines
+284
to
+286
| if float(np.max(np.abs(adv))) < 1e-12: | ||
| stats.skipped += 1 | ||
| continue |
Vanilla GRPO arms were dropping tied groups from the batch mean. The TRL recipe recorded cliffs but never sampled them, and claimed rank advantages while passing raw scalars. The GeoGuesser Monte Carlo treated never-submit as the subtract floor and resampled a different location. Same-task resample of a dead GeoGuesser group now goes 6.43% -> 4.56% dead, not 0.39%. CPU ablation rerun with the baseline fix. Co-authored-by: Grok 4.6 <grok@x.ai>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
GeoGuesser already tells you to watch
frac_reward_zero_std. If it is near 1, the step taught nothing. TRL still has no dynamic sampling, so those groups still get a backward pass. This folder treats that as a training failure rather than a chart.What it is
04-wordle/— the 2,309-word answer list as a training env (project 00 is 50 words), an estimator that splits a dead GRPO group into a cliff (different trajectories, same reward) and collapse (the same trajectory, G times), and two CPU measurements.The two kinds need opposite responses. Resampling a cliff can recover a gradient. Resampling a collapse draws the same action; that is the 750 steps after GeoGuesser run 1 plateaued.
What it is not
A Qwen run.
train/grpo_wordle.pyis the TRL recipe (in-process, no Space). It has not been spent on a GPU. The numbers below are from a 32-d pointer over the answer list and from a Monte Carlo of GeoGuesser's published medians.Numbers
Wordle, groups of 8, 200 steps, one seed, greedy eval on a 200-word holdout:
Sparse GRPO peaked at step 75 and gave the points back as dead groups went 0.02 → 0.19. That is run 1's plateau, on CPU. Process reward is the +0.10; skipping dead groups is the dead-group column, not a substitute for a ranking the reward refused to give.
GeoGuesser, 20,000 within-task groups of 8, from the medians in
03-geoguesser/LEARNINGS.md:Population zeros are not group zeros.
ACCUM=2is the setting where this number is the within-task std.How to check
The observation never names the answer.
rollout.py zonalis the trajectory a person can read.train/geoguesser_run4.pyis the classifier plus the env I would actually launch on GeoGuesser (SCALE_REWARDS=none,COST_SCALE=0.2,MAX_STEPS=250). It is not a fourth GeoGuesser run until someone launches it.If 04 is taken by an in-flight PR, renumber. The next free folder on main was 04.