Repository navigation
FreeCiv v3: integrate freeciv-v3's pipeline into worlds/freeciv - #11
Conversation
Applies fleet/pod_bundle/freeciv_world_as_run.patch from freeciv-v3 (daca5a1), Jaeho's diff between the tracked package and the copy that ran the September 2026 replay fleet: observer-death and server-wait handling in fork_manager.py, savegame parsing, report fixes. The patch applies unchanged; worlds/freeciv on main has not changed since the freeciv-v3 base. Co-Authored-By: jaeholee-brown <jaeho_lee@brown.edu> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Byte-for-byte copies of 62 files from freeciv-v3 at daca5a1 (Jaeho Lee), with sources and hashes in worlds/freeciv/fbsim_v3/PROVENANCE.json: - draw/: corpus consolidation, candidate pools, the structural draw, resolution criteria, natural-conditional census and export, report regeneration, QC - run/: elicitation harnesses (one question per prompt, batched, natural-conditional, effort check), scorers v1/v2 and their self-test, row rebuild and reparse, selection fractions - fleet/: RunPod scripts, on-pod scripts and the pod bundle's scripts Paper material goes to forecastbench-sim-paper (production/freeciv and the analysis assets) and data to the private archive, per the README. Paths are fixed in the next commit. Co-Authored-By: jaeholee-brown <jaeho_lee@brown.edu> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Question sets, world reports and model panels come from FBSIM_FREECIV_V3_DATA (e.g. forecastbench-sim-paper/production/freeciv), a replay run's corpus from FBSIM_V3_CORPUS, keys from the environment. - Jaeho's local paths in draw/ and fleet/ become arguments or environment variables; finalize.sh takes the pod ids and drops the never-committed mine_v3.py step. - fleet/make_bundle.sh assembles the pod bundle from packages/fbsim-core and worlds/freeciv; bringup.sh builds it when absent. - uv.lock: zstandard, which the as-run patch added to worlds/freeciv. - Short README; PROVENANCE.json lists the adaptations. Checked: score_selftest.py passes; score_v2.py on the archived run-2b and run-2 natural-conditional rows reproduces run2_paper's score_items.csv, score_summary.csv and SCORES.md byte for byte; elicit_v2.py --dry-run builds 44 prompts per model. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
elsehow
left a comment
There was a problem hiding this comment.
This is great! Thanks for the PR. My biggest comment is inline on fork_manager.py.
Some minor notes:
- Pod IDs are hardcoded in finish_all.sh, rebalance.sh, fleet_ssh.sh, switch_anchor.sh and launch_pending.sh. Could we pull them into an env var or state file? That will help when we productize this more!
bringup.sh:7only builds the bundle if state/bundle is missing, so code changes don't reach the pods.- The "No temperature: provider-default sampling" comment in
parallel_evaluator.py(514/644/754) doesn't match main's fbsim-core, which still defaults to 0.0. Let's either port theNonedefault or drop the comment.
| # explicit rng_seed mod, clear the saved [random] table (and zero the | ||
| # recorded gameseed) so the engine draws a fresh seed on load. | ||
| if not any(mod.get("type") == "rng_seed" for mod in modifications): | ||
| modifier.clear_rng_state() |
There was a problem hiding this comment.
This makes every fork draw a fresh seed unless the caller pins one. That's right for the v3 replays, but conditional_runner.py (L4-15 on main) skips the control fork and compares the intervention fork against the recorded game. With this change, every fork rolls fresh dice.
I think we should either keep the saved dice for conditional_runner's forks, or run a no-intervention fork on the same new seed and compare against that instead of the recording
There was a problem hiding this comment.
Great catch! I fixed this in 3300403, by adding a reseed bool parameter that conditional_runner.py uses.
| missing = [i for i in sel if i not in idx] | ||
| if missing: sys.exit(f'{len(missing)} selected ids not in the pool, e.g. {missing[:3]}') | ||
| npool = collections.Counter(stratum(c) for c in idx.values()); nsel = collections.Counter(stratum(idx[i]) for i in sel) | ||
| r = {k: nsel[k] / npool[k] for k in nsel} |
There was a problem hiding this comment.
1/r per (band, T, family) is exact only if selection is uniform within each stratum. draw_v1 also caps 6 per world per cell and one item per subject, so inclusion probability still varies inside a stratum. And strata with n_selected = 0 are dropped, so the "whole pool" estimate covers 21,583 of 23,241 pool items (92.9%).
This script already reads the pool pickles. Could we get π_i by re-running draw_v1 over many seeds and weight by 1/π_i? At minimum, the paper should state the coverage.
There was a problem hiding this comment.
I agree with all of that but I think that is out of scope for this PR. I am going to be making a PR soon with the scripts that do the 1/r weighting and I will address this there.
bringup.sh built state/bundle only when it was missing, so code changes never reached pods brought up later. Rebuild it each time; set FBSIM_POD_BUNDLE to ship a fixed bundle as is. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fbsim-core's get_response_async defaults to temperature=0.0, so these calls never used provider-default sampling. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Thanks for the comments Nick, replies inline below.
It looks like the code pulls most pod ids from a file called
Good catch, fixed in a2db70b
Comments dropped in 66a00ac This made me notice a small inconsistency between how prompting was done for Freeciv/Micropolis and Starsim. |
Forks without an rng_seed mod now reseed by default, which breaks conditional_runner: it compares an intervention fork against the recorded game and relies on the fork reusing the recording's dice. Add reseed=True to create_fork (stored on Fork, applied in _apply_mods and _apply_modifications); reseed=False keeps the saved RNG state. conditional_runner creates its forks with reseed=False. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings Jaeho's FreeCiv v3 pipeline from the
freeciv-v3branch (atdaca5a15) into main, split by the "Paper material" rule from #10 instead of merged. A merge would have broughtfreeciv-v3's raw provider responses (about 100 MB ofresults/) into main's history.Companion PR in forecastbench-sim-paper: forecastingresearch/forecastbench-sim-paper#3. It adds the question sets, reports, model panels, launchers and run records to
production/freeciv, plus the run-2 analysis scripts.Commits
worlds/freeciv: the changes that ran on the replay pods. Appliesfleet/pod_bundle/freeciv_world_as_run.patchunchanged: observer-death and server-wait handling infork_manager.py, savegame parsing, report fixes, and azstandarddependency (15 files).worlds/freecivon main hasn't changed sincefreeciv-v3branched, so the patch applies cleanly.worlds/freeciv/fbsim_v3: 62 files copied byte for byte, with sources and hashes in itsPROVENANCE.json:draw/: corpus consolidation, candidate pools, the structural draw, criteria, natural conditionals, report regeneration, QCrun/: elicitation harnesses (one question per prompt, batched, natural-conditional, effort check), scorers v1 and v2 with the self-test, row rebuild, reparse, selection fractionsfleet/: RunPod scripts, on-pod scripts and the pod bundle's scriptsFBSIM_FREECIV_V3_DATA, which points at forecastbench-sim-paper'sproduction/freeciv. A replay run's corpus is read fromFBSIM_V3_CORPUS, and keys come from the environment.draw/andfleet/are now arguments or environment variables.finalize.shtakes the pod ids as arguments and drops themine_v3.pystep (that script was never committed).fleet/make_bundle.shbuilds the pod bundle frompackages/fbsim-coreandworlds/freeciv, instead of the vendored copies onfreeciv-v3.uv.lockgains only the twozstandardlines.PROVENANCE.jsonlists every adaptation.Not brought over
These stay on
freeciv-v3only:results/: already in the private data archive.paper/: the generators are already in forecastbench-sim-paper.draw/natcond_new_families.py.Checks
score_selftest.pypasses.score_v2.pyon the archived run-2b batched rows and run-2 natural-conditional rows reproducesrun2_paper'sscore_items.csv,score_summary.csvandSCORES.mdbyte for byte.elicit_v2.py --dry-runbuilds 44 prompts per model, which is run 2b's design.worlds/freeciv15 passed,worlds/micropolis227,worlds/pandemic25,packages/fbsim-core16. Inpackages/fbsim-benchmark, 59 pass and 2 fail (test_single_core_owner,test_noneditable_installed_packages); the same two fail on main.For review
freeciv_worldpackage that the older CivBench scripts also use.🤖 Generated with Claude Code