Skip to content

Iterate, Versions & Reports

A study that has already run is a result — iteration must never silently destroy it. SocioVerse enforces that with one rule and one mechanism.

The rule: all changes go through /sv-iterate

Any change to an existing study — a new policy broadcast, more steps, a different population size, a tweaked threshold — goes through /sv-iterate.

Don't hand-edit and re-run

Editing artifacts in place and re-running overwrites the previous trajectory with no record. "add one more policy and run again" is an iteration, not an edit.

Before the gate: the reference guard

A study whose study.yaml carries reference: true — the bundled demo templates and adapted baselines — is fork-only. This guard runs before the version gate and bypasses it entirely: new-version, in-place and branch all mutate the same study_id, which is exactly what a shared baseline must never suffer.

So a "modify this" request against a reference study forks it:

  • the fork gets a new study_id (and reference: false); the template is untouched;
  • a fresh fork has no history to version, so the version gate is skipped — it starts its own version line at v1 and goes straight into the pipeline.

Editing the baseline template in place is a rare, deliberate choice that requires an explicit, spelled-out warning first: every future study built from that template inherits the change. A non-reference working study skips this guard and goes straight to the gate.

The version gate

/sv-iterate always asks (never assumes) how to version the change:

option what happens
new version (recommended default) the live directory is snapshotted to versions/v<N>/ — artifacts, code, results — then the study iterates as v<N+1>
in-place no snapshot; the current outputs are lost (the classic overwrite flow, opt-in only)
branch from v<X> the new version starts from an older version's artifacts; versions.json records the parent tree, so cross-version exploration stays navigable

Snapshots are immutable local history (versions/ is gitignored, like run outputs): old versions never auto-delete, and anything that ever ran stays inspectable.

Mode and provider switches are new-version-only

A switch of decision/run mode or provider — scripted ↔ LLM, local ↔ real-LLM, deterministic ↔ stochastic — is not offered the in-place option at all. The earlier run is the scientific comparison baseline: the whole point of a scripted dry-run or a local-model pass is to sit next to the real one. Only new version and branch are offered.

The review gate (待复核)

Creating a version requires saying where the pipeline resumes. create_version(..., resume_from_stage=...) takes:

change resume_from_stage
new version from current the earliest affected stage — a new broadcast → sv-build-environment; a population change → sv-build-population; a decision-logic change → sv-build-model
branch from an older version sv-init — branching is a large context shift, so everything is re-reviewed

From that stage forward, every carried stage shows as 待复核 / pending review in the dashboard until you handle it. There are exactly two ways to handle one:

  • Affected stage → re-author it through its sv-* skill, as usual.
  • Unaffected stage → validate the carried artifact against its schema, confirm it still fits the new question, and post its narrative. That narrative is what clears the 待复核 flag.

Verify and narrate — do not rewrite an unaffected artifact

Rewriting a carried artifact "just to be safe" churns its mtime and corrupts the dashboard's carried-vs-stale detection. Validate it, say why it still holds, and leave the bytes alone.

A carried stage that is neither re-authored nor verified stays 待复核 and holds the pointer — so the pipeline can never look finished while an unreviewed stage rides along from the parent version. /sv-run still confirms before spending.

Warm starts

When the change only affects the trajectory from step J onward — the horizon was extended, or a new intervention lands at step J — a full re-run would re-pay LLM cost for steps that cannot differ. A warm start avoids that:

warm_start = { source: <parent version>, resume_from: K }

/sv-run then replays the parent's steps 0..K from its stored actions — reproduced exactly, no LLM — and spends only on steps K+1..n_steps.

Eligibility

Warm starts apply to from-scratch (Path B) studies with interaction_rounds == 1, whose apply is a pure function of the actions. Wrapped-legacy and multi-round studies re-run from step 0; the engine raises an error rather than warm-starting them incorrectly.

The multi-round exclusion is not a limit of the replay code but of what was stored: only the final round's actions are persisted in the parent panel, so the intermediate rounds that produced them cannot be reconstructed. See Multi-round interaction.

Reports

/sv-report reads trajectory/study.duckdb (panel, metrics, events, optionally messages) and writes reports/report.md plus reports/figures/*.png. The report is analytical, not a data dump, and its structure is mandated — a 总–分–总 arc, in this order:

# section what it must do
总起 · 结论速览 (Overview) the 2–4 headline conclusions of the whole run, one line each, stated as claims — "X happened because Y", never "we simulated X". This is the thesis the body then proves.
trajectory tables & figures the descriptive backbone everything else reads off
分 · 发现与解读 (Findings) roughly one finding per key result. Each claim is immediately paired with the specific number or figure it reads off, and with the mechanism — the why, read off the panel and cohorts.
深层洞察 (Deeper insights) non-obvious cross-metric / cross-cohort conclusions the raw tables don't state — who is insulated vs exposed, a tipping threshold, a divergence between two metrics — each still tied to the data that reveals it
总结 · 回扣与深挖 (Conclusion) restate the headlines, now earned by the body, and go one level deeper: what they mean for the research question, the unifying mechanism, what remains uncertain. No new unsupported claims.
改进建议与下一步 actionable suggestions, and what the next /sv-iterate round should test — a policy to try, a parameter to sweep, a cohort to probe
数据基础与参考来源 last, rendered from the grounding sidecar

The binding rule of section ③

No claim without its number, no number without the claim it supports. A finding reads like "满意度从 0.74 跌到 0.61(step 2 政策后,见 figures/satisfaction.png)" followed by the mechanism — not a paragraph of interpretation next to a table the reader has to reconcile on their own.

The last section is generated from grounding/grounding.json as a pipe table:

事实 依据 来源
实证 / 代理 / 假设 title (url)

plus implementation_refs as 建模参考 and assumptions as 声明的假设. A study whose method_notes is "stylized" gets the single honest line "风格化模型,无真实世界锚点。"; a forked study opens the section by saying which anchors it inherited. See Grounding & Provenance.

Ask your own questions with SQL

The report is a rendering; the store is the result. study.duckdb stays queryable forever:

-- the longitudinal view of one agent
SELECT step, state, action_kind
FROM panel WHERE agent_id = '…' ORDER BY step;

-- the aggregate trajectory
SELECT * FROM metrics ORDER BY step;

-- what fired, and when
SELECT step, note FROM events ORDER BY step;

-- if the study used the message bus: who said what
SELECT step, author_id, content FROM messages ORDER BY step;

Parquet exports (panel.parquet, metrics.parquet) are written alongside at finalize time for pandas/R workflows. More query recipes live in the FAQ.