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 shows WAITING 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.json
twitter/actions.jsonl, reddit/actions.jsonl
twitter_simulation.db, reddit_simulation.db
simulation.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:1656 sits outside the if needs_finalization: block, so a completed or stopped run is wiped too. Reopening Step 3 to review a finished run destroys it.
_check_simulation_prepared() returns True for 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
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)
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
TOTAL EVENTS: 209).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-696starts a simulation on every mount, with no check for an existing run:The simulation id is a route path param (
frontend/src/router/index.js:28→/simulation/:simulationId/start, read atfrontend/src/views/SimulationRunView.vue:94), so it survives a reload and the mount call fires again with a valid id.doStartSimulation()(Step3Simulation.vue:383) hardcodesforce: trueon every call (:401).On the backend,
POST /simulation/starttreats 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), andcleanup_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.jsonThose files are the only copy.
get_all_actions()readsactions.jsonloff disk on every call (simulation_runner.py:1156-1198) and the/postsand/commentsendpoints 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:
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
onMountedauto-start,force: true, the/simulation/:simulationId/startroute, the backendforce→ cleanup wiring, andcleanup_simulation_logs()deleting the action logs all arrived in the same commit,f8a5881(2025-12-12) — the commit that addedStep3Simulation.vue.Checked
force:true+onMountedauto-start atf8a5881,0577ecd,d768fd1,c91dad3,2fd1227,3a8451c,867b54c,e4aa38d,b5b53ac— present at every one.d768fd1later added the two*_simulation.dbfiles 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 roundtime 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
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.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-statusbefore 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):force: trueshould only ever be sent for an explicit, user-initiated restart, never as the implicit default on component mount.Environment
b5b53acc57189a4a42e44a23e149dc655c98fe82(2026-08-03)