walkout-engine
v0.1.0
Published
A deterministic simulation of the coordination problem behind general strikes: participation thresholds, preference falsification, financial buffers, and cascading institutional defection.
Maintainers
Readme
walkout-engine
A deterministic simulation of the coordination problem behind general strikes.
Not whether people want change — whether enough of them move at the same time, in the right places, for long enough, and what that does to the institutions a regime depends on.
npm install walkout-engineimport { runSimulation, scenarioToConfig } from 'walkout-engine';
import scenario from 'walkout-engine/scenarios/petro-state.json' with { type: 'json' };
const run = runSimulation(scenarioToConfig(scenario, { seed: 1 }));
console.log(run.outcome.kind); // 'collapse' | 'stalemate' | 'negotiated' | …
console.log(run.outcome.reasons); // why, assembled from the run log itself
console.log(run.widestGap); // { value: 0.62, day: 0 }- Deterministic. Same config and seed produce a byte-identical run, always. One seeded
PRNG; no
Math.random, no clock reads, enforced by lint and test. - UI-free. No DOM, no Node builtins. Runs in Node, in a browser, and in a Web Worker.
- One dependency (
zod, for scenario validation). - Fully typed, with every parameter documented.
What it models
Three quantities, kept strictly separate: private support (who wants it), public participation (who is acting), and spent (whose savings are gone). The gap between the first two is the thing worth looking at — it can sit at sixty percentage points, and that is what makes cascades appear to come from nowhere.
Campaigns win by institutional defection, not headcount. Security forces, civil service, judiciary, media, business elites and international backers each independently decide whether to keep cooperating; breadth of participation erodes them faster than raw numbers.
The model can lose. Across a randomised sweep the most common outcome takes about a third of runs, and all five terminal states occur — including collapse and violent escalation.
Adapting it
Every parameter is described in the exported registry, including whether anyone has actually measured it:
import { ALL_PARAMETERS, judgementParameters } from 'walkout-engine';
judgementParameters().length; // 29 of 46 — the ones nobody has measured29 of the 46 are judgement, including every internal rate. The right way to use this is
to vary what you cannot source and check whether your conclusion survives.
Overrides cover every parameter and can add or remove sectors and institutions outright:
const config = scenarioToConfig(scenario, {
seed: 1,
movement: { strikeFundDays: 45 },
sectors: { transport: { bufferDays: 3 } },
addSectors: [myOwnSector],
});configToScenario() turns an edited model back into a validated scenario file you can cite
and share.
Documentation
- MODEL.md — every mechanic in plain language, with citations
- Limitations — what this model cannot tell you. Read this one.
- The simulator — the interface built on this engine
Grounded in Chenoweth & Stephan (2011), Sharp (1973), Helvey (2004), Granovetter (1978),
Kuran (1995) and Martin (2007). Every numeric constant carries either a citation or an
explicit UNSOURCED — tunable marker.
This is not a forecasting tool. It is not fitted to historical outcomes and has never been validated against them. It is for reasoning about mechanisms.
MIT licensed. Model critiques are the most welcome kind of issue.
