Skip to content

Persist sim options before StartSimul so the seed is honored (AB#2742) - #2

Merged
vosesoftware merged 2 commits into
mainfrom
fix/seed-persist-manual-seed
Jun 18, 2026
Merged

Persist sim options before StartSimul so the seed is honored (AB#2742)#2
vosesoftware merged 2 commits into
mainfrom
fix/seed-persist-manual-seed

Conversation

@vosesoftware

Copy link
Copy Markdown
Owner

Problem

run_simulation(seed=N) ran non-reproducibly even with a fixed seed — two runs at the same seed produced different streams.

The seed packing was never the issue: the bridge packs [SeedFixed]:1 / [seed0]:N correctly (matching ModelRisk's PackToStringList), and the options array marshals fine — both verified by reading back ModelRisk's own parsed SimOpt_SeedFixed=1 / SimOpt_Seed0=N after feeding the exact payload to VoseSetSimulOptions12.

Root cause

ModelRisk's per-cell-twister Manual-Seed mode sources its base seed from the workbook-persisted SimOpt_SeedFixed / SimOpt_Seed0 defined-names (written by SaveOptionsToWorkbook), not from the per-call options passed to VoseStartSimulCustom12.

The bridge set the per-call [seed0] (parsed into m_Seeds but ignored by the twister) and never persisted it to the workbook, so Manual Seed stayed OFF → Random mode → a different stream every run.

Proof: persist SimOpt_Seed0=999 via VoseSetSimulOptions12, then run the sim passing per-call seed=12345 → the stream tracks 999, not 12345.

Fix

Call VoseSetSimulOptions12 with the same options payload before VoseStartSimulCustom12. That runs SaveOptionsToWorkbook, persisting SimOpt_SeedFixed=1 / SimOpt_Seed0=N, which the twister then honors.

Side effect (acceptable, matches ModelRisk's own ribbon Simulate): the MCP's sim settings are now written into the workbook.

Verification (end-to-end against the engine oracle, single-cell =VoseOutput("U")+VoseUniform(0,1))

  • two runs at seed=12345byte-identical streams (was: differing)
  • seed=12345 vs seed=555 → different reproducible streams (the seed now drives it)
  • the seed=12345 stream matches mrengine's per-cell twister-0 reference [0.929616, 0.890155, 0.316376, 0.130707, 0.183919, 0.039759, ...] exactly, validating the byte-identical parity path

Note

The running MCP server must be reloaded (Claude Desktop restart) before the live run_simulation tool picks up this change.

🤖 Generated with Claude Code

vosesoft and others added 2 commits June 18, 2026 12:46
run_simulation(seed=N) packed the seed correctly ([SeedFixed]:1 /
[seed0]:N, matching ModelRisk's PackToStringList), and the array
marshalled fine — verified by reading back ModelRisk's own parsed
SimOpt_SeedFixed=1 / SimOpt_Seed0=N after feeding the exact payload to
VoseSetSimulOptions12. But the simulation still ran non-reproducibly.

Root cause: ModelRisk's per-cell-twister Manual-Seed mode sources its
base seed from the WORKBOOK-persisted SimOpt_SeedFixed / SimOpt_Seed0
defined-names (written by SaveOptionsToWorkbook), NOT from the per-call
options passed to VoseStartSimulCustom12. The bridge set the per-call
[seed0] (ignored by the twister) but never persisted it to the workbook,
so Manual Seed stayed OFF -> Random mode -> different stream every run.

Fix: call VoseSetSimulOptions12 with the same options payload before
VoseStartSimulCustom12. That runs SaveOptionsToWorkbook, persisting
SimOpt_SeedFixed=1 / SimOpt_Seed0=N, which the twister then honors.

Verified end-to-end against the engine oracle (single-cell VoseUniform):
- two runs at seed=12345 -> byte-identical streams (was: differing)
- seed=12345 vs seed=555 -> different reproducible streams (seed now drives it)
- the seed=12345 stream matches mrengine's per-cell twister-0 reference
  (0.929616, 0.890155, 0.316376, 0.130707, 0.183919, 0.039759, ...) exactly,
  validating the byte-identical parity path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…B#2742)

The seed-persist fix inserts VoseSetSimulOptions12 before
VoseStartSimulCustom12, so run_simulation now issues 3 Run() calls
(persist, start, save) instead of 2. Update the order/index assertions
accordingly and add an invariant that the persist call receives the same
options payload as the start call.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vosesoftware
vosesoftware merged commit bf5848d into main Jun 18, 2026
3 checks passed
@vosesoftware
vosesoftware deleted the fix/seed-persist-manual-seed branch June 18, 2026 11:04
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