commons-test.js
54 lines · in natura-src-1.0.0.zip as natura/commons-test.js · a test
// commons-test.js -- assertions for THE COMMONS (tragedy of the commons + Ostrom governance). Run: node commons-test.js
const N = require('./natura.js');
const { makeCommons } = require('./commons.js');
const { World, UNITS } = N;
const DAY = UNITS.DAY;
let pass = 0, fail = 0;
const ok = (c, m) => { if (c) pass++; else { fail++; console.log(' FAIL: ' + m); } };
const build = (cfg) => World({ seed: 7, systems: [makeCommons(cfg || {})] });
const run = (w, days) => { for (let i = 0; i < days / 4; i++) w.step(4 * DAY); };
console.log('commons assertions:');
// 1. DETERMINISM
{
const a = build({ mode: 'open' }), b = build({ mode: 'open' }); run(a, 400); run(b, 400);
ok(a.fields().commons.stock === b.fields().commons.stock, 'same config -> identical trajectory (reproducible)');
}
// 2. THE TRAGEDY -- open access draws the stock past its floor and it COLLAPSES
{
const w = build({ mode: 'open' }); const s0 = w.fields().commons.stock; run(w, 500); const f = w.fields().commons;
ok(s0 > 0.7 && f.collapsed && f.stock < 0.1, 'open access COLLAPSES the commons (stock ' + s0 + ' -> ' + f.stock + ')');
}
// 3. GOVERNANCE SAVES IT -- quota + monitoring + strong sanctions hold the stock high with a real yield
{
const w = build({ mode: 'managed', monitor: 0.7, sanction: 0.9 }); run(w, 500); const f = w.fields().commons;
ok(!f.collapsed && f.stock > 0.4 && f.yield > 0.02, 'strong governance SUSTAINS the commons (stock ' + f.stock + ', yield ' + f.yield + ', compliance ' + f.compliance + ')');
}
// 4. THE BIFURCATION -- weak sanctions are not enough; the managed commons still collapses (governance has a threshold)
{
const weak = build({ mode: 'managed', monitor: 0.3, sanction: 0.15 }); run(weak, 500);
const strong = build({ mode: 'managed', monitor: 0.7, sanction: 0.9 }); run(strong, 500);
ok(weak.fields().commons.stock < 0.15 && strong.fields().commons.stock > 0.4,
'governance has a THRESHOLD: weak sanctions collapse (' + weak.fields().commons.stock + '), strong ones sustain (' + strong.fields().commons.stock + ')');
}
// 5. YIELD -- the well-governed commons out-yields the collapsed one in the long run (conservation pays)
{
const open = build({ mode: 'open' }); run(open, 600);
const managed = build({ mode: 'managed', monitor: 0.7, sanction: 0.9 }); run(managed, 600);
ok(managed.fields().commons.yield > open.fields().commons.yield + 0.02,
'the sustained commons out-yields the collapsed one long-run (managed ' + managed.fields().commons.yield + ' vs open ' + open.fields().commons.yield + ')');
}
// 6. COMPLIANCE builds under monitoring + sanctions (the mechanism that does the saving)
{
const w = build({ mode: 'managed', monitor: 0.7, sanction: 0.9 }); const c0 = w.fields().commons.compliance; run(w, 200);
ok(c0 < 0.2 && w.fields().commons.compliance > 0.7, 'compliance builds under monitoring + sanctions (' + c0 + ' -> ' + w.fields().commons.compliance + ')');
}
console.log(`\n${pass} passed, ${fail} failed`);
process.exit(fail ? 1 : 0);