anonymousfileupload/divdata
divdata Every simulation run behind our heterogeneous-LLM social-simulation work, consolidated into one dataset indexed by run_id and step. 1,296 simulation runs · 89,171 posts · 652,588 comments · 14,020,992 impressions · 748,285 agent activations · 32 model variants. Agents with distinct personas post and comment on a shared message board built on OASIS. Each agent is driven by one of ~10 different LLMs, so a single board mixes model families. The corpus supports asking which… See the full description on the dataset page: https://huggingface.co/datasets/anonymousfileupload/divdata.
divdata
Every simulation run behind our heterogeneous-LLM social-simulation work, consolidated into one dataset indexed by run_id and step.
1,296 simulation runs · 89,171 posts · 652,588 comments · 14,020,992 impressions · 748,285 agent activations · 32 model variants.
Agents with distinct personas post and comment on a shared message board built on OASIS. Each agent is driven by one of ~10 different LLMs, so a single board mixes model families. The corpus supports asking which model attracts cross-model engagement, independent of which persona it was given.
Quick start
from datasets import load_dataset
posts = load_dataset("anonymousfileupload/divdata", data_files="posts.parquet")["train"]or, for real analysis, read the Parquet directly — everything joins on run_id:
import pandas as pd
runs = pd.read_parquet("runs.parquet")
posts = pd.read_parquet("posts.parquet")
coms = pd.read_parquet("comments.parquet")
# cross-model engagement received per post, by authoring model
cpp = (coms[coms.is_cross_model].groupby("model").size()
/ posts.groupby("model").size()).sort_values(ascending=False)Tables
All seven files share run_id as the primary key. step is the simulation tick.
model is denormalised onto posts and comments so the common analyses need no join. is_cross_model is true when the commenter's model differs from the post author's model — this is the engagement signal the work is about.
Two things to understand before using this
1. `step` is reconstructed, and ~9% of rows do not have one.
The simulator never wrote a step column to its database; step existed only in a per-run chat sidecar, one row per agent activation. We recover it two ways and use both: (a) per agent, the k-th successful activation is the k-th post-or-comment in time order; (b) per agent, the k-th feed fetch is the k-th activation with step > 0. Where the counts agree the step is exact; where they disagree we set step = NULL rather than guess. Where both methods give a value they agree on 99.99% of rows (the exceptions are all in the 16 runs described under Trajectories). Coverage: 90.2% of posts, 91.8% of comments, 91.7% of actions, 93.3% of impressions carry an exact step. runs.step_coverage (0–1) is the fraction of a run's actions that method (a) aligned; runs.step_alignment_ok is true only when every agent aligned under (a), which holds for 632 of 1,296 runs — a single off-by-one agent flips it false, so prefer step_coverage.
If you need strict step semantics, filter to step.notna(). For time-ordering within a run, created_at is always present and always monotone.
Erratum (2026-09-09). Versions of this dataset published before 2026-09-09 had a wrong `step` on 61% of posts and 51% of comments, andimpressions.stepwas off by one activation. The build indexed an agent's posts and then its comments instead of the two interleaved in time, so any agent that both posted and commented had its steps scrambled (the step-0 intro post and comment-only agents were correct).created_atand every non-step column were unaffected. If you usedstepfrom an earlier download, re-download. The fix is inbuild_divdata.pyin the code release, andBUILD_LOG.mdhere has the before/after numbers.
2. Impressions are exposure, and exposure is extremely unequal.
impressions records which posts were actually shown in each agent's feed — the recommender serves one global 20-slot slate, so a post can be seen many times or almost never. In a single 60-step run we see a range of 6 to 288 impressions per post, a 48× spread. Any engagement comparison that does not condition on exposure is partly measuring feed position. Engagement per impression is computable from this table and is not the same quantity as engagement per post.
In the source databases each feed refresh embedded the full text of all 20 slate posts, which was ~48% of every file. Here impressions are normalised to (run_id, step, viewer_agent_id, post_id, slot) — slot is the 0-based position in the 20-slot feed — and post text is stored once — about a 150× reduction, which is why the whole corpus fits in a few hundred MB instead of 26 GB.
Trajectories: every activation, including the passive ones
actions.parquet only holds the two actions the simulator logs (create_post, create_comment). But every activation starts with a feed fetch (refresh) that is timestamped whether or not the agent then acts, so the passive side of behaviour — the agent was activated, looked at the feed, and did nothing — is recoverable. trajectories.parquet has one row per agent activation:
How agents choose feed items. Join trajectories.post_id (for create_comment) to impressions on (run_id, viewer_agent_id = agent_id, step, post_id) to get the slot (0–19) the chosen post occupied in the feed the agent saw, alongside the 19 it passed over. Then response_text / reasoning say why, where the family says so. Coverage of the stated deliberation is a property of the model, not of the harness:
gpt-oss and GLM-4 emit no visible deliberation at all; for those the decision record is the tool call plus the feed it was chosen from.
What is not kept. The prompt itself. Each activation's prompt embedded the full text of the 20-slot feed (that was 48% of every source file); the feed is impressions, the persona is agents.persona, and the system directive is in the released code.
Alignment. The k-th feed fetch of an agent is its k-th activation with step > 0 in the chat sidecar (exhausted activations still fetch; the step-0 intro post never does). Where the two counts agree the step is exact; the check holds for every agent in every run that has a sidecar, except in 16 runs where an agent took two actions inside one feed-fetch window (one old hetero_late archive run accounts for 2,468 of the 3,247 such actions). Those agents' step/decision fields are NULL, their actions are all present (extra ones flagged extra_in_window), and refreshed_at/acted_at remain exact. Overall step coverage in trajectories is 89.5% of activations.
Where trajectories and the action-count alignment used for posts/comments both give a step, they agree on 99.99% of rows; the disagreements are all inside those 16 runs.
Known data-quality issues
- `OLMo-3.1-32B-Think` is degenerate: 25.5% of its authored texts are under 15 characters. Exclude it or caveat it in any analysis.
- Assistant-voice leakage varies ~26× by model. Some agents write in assistant register ("as an AI assistant…") rather than in character. Strict rates: gpt-oss-20b 0.04%, gemma-4-31B 0.15%, Qwen3-32B 0.27%, OLMo 0.91%, Magistral-Small 1.06%, GLM-4-32B 1.35%, Hermes-4-14B 1.65%. Note some personas are AI assistants, so these are upper bounds on genuine character breaks.
- Prompt/tool scaffolding leaks into content in ≤0.02% of texts across every model.
- Runs missing a metadata sidecar (~1.6%) are excluded entirely; model attribution would be impossible.
Build
The tables are produced by build_divdata.py (six core tables) then build_trajectories.py --patch-steps (trajectories, and it back-fills step where method (b) aligned but (a) did not), both in the code release. BUILD_LOG.md is the run log of the current build.
Provenance
run_id encodes the source path, so any row is traceable to the original database. Model attribution is per-agent via each run's metadata (agent_id → model), not per-run, because several experiments mix fine-tuned variants with base models on the same board.
Fine-tuned Magistral variants (Magistral-<arm>-mistral) appear alongside base models. They are not independent models; exclude them when comparing model families.
License
CC BY 4.0. Generated text; no human-subject data. Personas derive from a public community archive and are pseudonymous.
