Refreshing the Step 3 page force-restarts the simulation and permanently deletes the run's data
Summary
Reloading the browser tab on Step 3 makes the frontend re-send a force-restart to the backend. The backend kills the running subprocess and deletes the run's data files, then starts again from round 0. Everything the timeline / posts / comments views render is gone, permanently. There is no confirmation prompt and nothing indicates that reloading is destructive.
Reproduction
- Start a simulation and let it run a few rounds until the timeline populates (e.g.
TOTAL EVENTS: 209). - Refresh the tab, or close and reopen it.
- The round counter resets to
0/35,ACTS 0, the timeline showsWAITING FOR AGENT ACTIONS..., and the previous run's posts and comments are gone.
Root cause
frontend/src/components/Step3Simulation.vue:691-696 starts a simulation on every mount, with no check for an existing run:
onMounted(() => {
addLog(t('log.step3Init'))
if (props.simulationId) {
doStartSimulation()
}
})
The simulation id is a route path param (frontend/src/router/index.js:28 → /simulation/:simulationId/start, read at frontend/src/views/SimulationRunView.vue:94), so it survives a reload and the mount call fires again with a valid id.
doStartSimulation() (Step3Simulation.vue:383) hardcodes force: true on every call (:401).
On the backend, POST /simulation/start treats that as permission to tear the run down (backend/app/api/simulation.py:1626-1667). stop_simulation() SIGTERMs then SIGKILLs the process group (backend/app/services/simulation_runner.py:1004), and cleanup_simulation_logs() (simulation_runner.py:1398-1431) deletes:
run_state.jsontwitter/actions.jsonl,reddit/actions.jsonltwitter_simulation.db,reddit_simulation.dbsimulation.log,stdout.log,stderr.log,env_status.json
Those files are the only copy. get_all_actions() reads actions.jsonl off disk on every call (simulation_runner.py:1156-1198) and the /posts and /comments endpoints open the SQLite files directly (simulation.py:2169, :2247). This is not a display or caching problem — the underlying data is gone. Zep graph data survives only because it lives outside the deleted directory, not because anything preserves it.
Two details worth flagging:
- The cleanup call at
simulation.py:1656sits outside theif needs_finalization:block, so acompletedorstoppedrun is wiped too. Reopening Step 3 to review a finished run destroys it. _check_simulation_prepared()returnsTruefor a run in progress (profiles and config are still on disk), so the destructive branch is reachable rather than gated off.
Affected versions
All of them. The onMounted auto-start, force: true, the /simulation/:simulationId/start route, the backend force → cleanup wiring, and cleanup_simulation_logs() deleting the action logs all arrived in the same commit, f8a5881 (2025-12-12) — the commit that added Step3Simulation.vue.
Checked force:true + onMounted auto-start at f8a5881, 0577ecd, d768fd1, c91dad3, 2fd1227, 3a8451c, 867b54c, e4aa38d, b5b53ac — present at every one. d768fd1 later added the two *_simulation.db files to the delete list, widening the blast radius from the timeline to posts and comments. There is no tag or release to fall back to.
Impact
Simulations run for hours — the UI logs its own 60 minutes per round time config. Any accidental refresh, tab restore, browser crash recovery, or close-and-reopen discards the entire run and the LLM spend behind it, with no warning and no recovery path.
Related issues and PRs
- #21 asked exactly this ("if a simulation has already started, what happens if I refresh the page or close and reopen it") and was closed on 2026-07-21 stating that the UI "can normally rediscover simulation-stage history after reopening".
onMountedandforce: truewere byte-identical atmain@4ebb2ed, the commit that answer was checked against, so it does not match the code. That is still the public answer users find when they search. - #718 fixes this as one bullet inside an 18-file runtime-hardening PR. Its parent issue #717 does not mention the behaviour.
- #693 gives the same diagnosis and fixes it alongside a new read-only conversation view.
Neither PR is merged, and the bug has no issue of its own — which is why I am filing this one, so the data loss can be tracked and referenced independently of either PR's review.
Suggested fix
Probe GET /simulation/<id>/run-status before deciding what to do on mount. The endpoint already exists (simulation.py:1865) and the frontend wrapper is already there (frontend/src/api/simulation.js:102):
- run already exists (live or terminal) → adopt it, resume polling if live, load the existing timeline if not
- genuinely nothing there → start as today
force: true should only ever be sent for an explicit, user-initiated restart, never as the implicit default on component mount.
Environment
- Commit reviewed:
b5b53acc57189a4a42e44a23e149dc655c98fe82(2026-08-03)
Source: 666ghj/MiroFish