Skip to content

FreeCiv v3: integrate freeciv-v3's pipeline into worlds/freeciv - #11

Merged
elsehow merged 6 commits into
forecastingresearch:mainfrom
fdrocha:freeciv-v3-integrate
Oct 15, 2026
Merged

elsehow merged 6 commits into
forecastingresearch:mainfrom
fdrocha:freeciv-v3-integrate

Conversation

@fdrocha

@fdrocha fdrocha commented Oct 12, 2026 •

Copy link
Copy Markdown
Collaborator

Brings Jaeho's FreeCiv v3 pipeline from the freeciv-v3 branch (at daca5a15) into main, split by the "Paper material" rule from #10 instead of merged. A merge would have brought freeciv-v3's raw provider responses (about 100 MB of results/) 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

  1. worlds/freeciv: the changes that ran on the replay pods. Applies fleet/pod_bundle/freeciv_world_as_run.patch unchanged: observer-death and server-wait handling in fork_manager.py, savegame parsing, report fixes, and a zstandard dependency (15 files). worlds/freeciv on main hasn't changed since freeciv-v3 branched, so the patch applies cleanly.
  2. worlds/freeciv/fbsim_v3: 62 files copied byte for byte, with sources and hashes in its PROVENANCE.json:
    • draw/: corpus consolidation, candidate pools, the structural draw, criteria, natural conditionals, report regeneration, QC
    • run/: elicitation harnesses (one question per prompt, batched, natural-conditional, effort check), scorers v1 and v2 with the self-test, row rebuild, reparse, selection fractions
    • fleet/: RunPod scripts, on-pod scripts and the pod bundle's scripts
  3. Run from this repository:
    • Question sets, reports and model panels are read from FBSIM_FREECIV_V3_DATA, which points at forecastbench-sim-paper's production/freeciv. A replay run's corpus is read from FBSIM_V3_CORPUS, and keys come from the environment.
    • Jaeho's local paths in draw/ and fleet/ are now arguments or environment variables.
    • finalize.sh takes the pod ids as arguments and drops the mine_v3.py step (that script was never committed).
    • New fleet/make_bundle.sh builds the pod bundle from packages/fbsim-core and worlds/freeciv, instead of the vendored copies on freeciv-v3.
    • uv.lock gains only the two zstandard lines.
    • A short README. PROVENANCE.json lists every adaptation.

Not brought over

These stay on freeciv-v3 only:

  • results/: already in the private data archive.
  • paper/: the generators are already in forecastbench-sim-paper.
  • The dated manuscript-editing scripts and the October 2 logprob comparison.
  • The smoke, cost, cache and saturation tools.
  • draw/natcond_new_families.py.

Checks

  • score_selftest.py passes.
  • score_v2.py on the archived run-2b batched rows 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, which is run 2b's design.
  • Tests: worlds/freeciv 15 passed, worlds/micropolis 227, worlds/pandemic 25, packages/fbsim-core 16. In packages/fbsim-benchmark, 59 pass and 2 fail (test_single_core_owner, test_noneditable_installed_packages); the same two fail on main.

For review

  • Commit 1 changes the shared freeciv_world package that the older CivBench scripts also use.

🤖 Generated with Claude Code

fdrocha and others added 3 commits October 12, 2026 14:58
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 elsehow left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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:7 only 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 the None default 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()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

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}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

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.

fdrocha and others added 2 commits October 15, 2026 10:24
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>
@fdrocha

fdrocha commented Oct 15, 2026

Copy link
Copy Markdown
Collaborator Author

This is great! Thanks for the PR. My biggest comment is inline on fork_manager.py.

Thanks for the comments Nick, replies inline below.
My idea for this PR was to just bring in Jaeho's code that was missing with minimal modifications - bigger changes would wait for future PRs. That said, your notes are all reasonable and I will address all of those that don't require big changes.

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!

It looks like the code pulls most pod ids from a file called pods.tsv that Jaeho did not commit. Scripts do have some explicit pod ids in the code that are handled differently. I agree this needs to be cleaned up (also, Jaeho told me he used is personal Runpod account, so all the pod ids will change, even if we stick with Runpod).
But I would rather do all of that cleanup together at a later stage when I am trying to get this part of the code up and running, especially given that we might be switching to a different provider.

* `bringup.sh:7` only builds the bundle if state/bundle is missing, so code changes don't reach the pods.

Good catch, fixed in a2db70b

* 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 the `None` default or drop the comment.

Comments dropped in 66a00ac

This made me notice a small inconsistency between how prompting was done for Freeciv/Micropolis and Starsim.
Starsim uses fbsim-core defaults which sets T=0 for models that support it. Freeciv/Micropolis never specify temperature, just use provider defaults for every model. For paper updates we should stick with what was done until now, but for the benchmark we should be more consistent. I like the fbsim-core approach (I only switched to never setting temperature because I saw Jaeho did it and I didn't realize you hadn't), but let me know if you prefer the other one.

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>
@fdrocha
fdrocha requested a review from elsehow October 15, 2026 10:50
@fdrocha fdrocha mentioned this pull request Oct 15, 2026
@elsehow
elsehow merged commit ff80b48 into forecastingresearch:main Oct 15, 2026
2 checks passed
@fdrocha
fdrocha deleted the freeciv-v3-integrate branch October 28, 2026 13:08
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.

2 participants