Compare commits
2 Commits
34bc8fa70b
...
914cf01763
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
914cf01763 | ||
|
|
fe17bc8fae |
@@ -21,7 +21,7 @@
|
|||||||
* 6. Predator and prey — two coupled Stocks whose interlocking loops oscillate.
|
* 6. Predator and prey — two coupled Stocks whose interlocking loops oscillate.
|
||||||
* 7. Epidemic — a chain of Stocks joined by Stock→Stock Flows: no clouds.
|
* 7. Epidemic — a chain of Stocks joined by Stock→Stock Flows: no clouds.
|
||||||
*
|
*
|
||||||
* Last, four of Donella Meadows' system *traps* — structures that reliably misbehave
|
* Last, five of Donella Meadows' system *traps* — structures that reliably misbehave
|
||||||
* (Thinking in Systems, ch. 5), to contrast the healthy dynamics above — and, paired
|
* (Thinking in Systems, ch. 5), to contrast the healthy dynamics above — and, paired
|
||||||
* with the first, the cure that escapes it:
|
* with the first, the cure that escapes it:
|
||||||
*
|
*
|
||||||
@@ -32,16 +32,20 @@
|
|||||||
* *larger* than the trap's boom leaves alive.
|
* *larger* than the trap's boom leaves alive.
|
||||||
* 10. Escalation — a single Reinforcing loop spanning two Stocks, with
|
* 10. Escalation — a single Reinforcing loop spanning two Stocks, with
|
||||||
* no brake in the structure: an arms race.
|
* no brake in the structure: an arms race.
|
||||||
* 11. Fixes that fail — a fix drains the symptom Stock (B) while its side
|
* 11. Success to the successful — two equal rivals split one conserved prize (the field's
|
||||||
|
* attention); a gap-driven Flow tilts it to whoever leads,
|
||||||
|
* so a 51–49 near-tie locks in to ~100–0. Escalation's
|
||||||
|
* zero-sum twin — it concentrates instead of exploding.
|
||||||
|
* 12. Fixes that fail — a fix drains the symptom Stock (B) while its side
|
||||||
* effect refills it (R): the cure feeds the disease.
|
* effect refills it (R): the cure feeds the disease.
|
||||||
* 12. Drift to low performance — a goal that erodes toward actual performance, so the
|
* 13. Drift to low performance — a goal that erodes toward actual performance, so the
|
||||||
* effort it drives never overcomes a steady decay: a
|
* effort it drives never overcomes a steady decay: a
|
||||||
* Reinforcing loop ratchets both downward.
|
* Reinforcing loop ratchets both downward.
|
||||||
*
|
*
|
||||||
* Next, the dynamic the book is named for, and the one the gallery has saved until a
|
* Next, the dynamic the book is named for, and the one the gallery has saved until a
|
||||||
* reader knows every piece it needs:
|
* reader knows every piece it needs:
|
||||||
*
|
*
|
||||||
* 13. Overshoot and collapse — a Reinforcing harvester on a *renewable* Resource with
|
* 14. Overshoot and collapse — a Reinforcing harvester on a *renewable* Resource with
|
||||||
* an extinction threshold (an Allee floor): a fleet
|
* an extinction threshold (an Allee floor): a fleet
|
||||||
* overshoots the renewal rate and pushes the fishery past
|
* overshoots the renewal rate and pushes the fishery past
|
||||||
* the point of no return. The dark twin of "Limits to
|
* the point of no return. The dark twin of "Limits to
|
||||||
@@ -50,14 +54,14 @@
|
|||||||
* Last, the language pointed at a live debate — a classic trap (Shifting the burden to
|
* Last, the language pointed at a live debate — a classic trap (Shifting the burden to
|
||||||
* the intervenor, ch. 5) wearing today's clothes:
|
* the intervenor, ch. 5) wearing today's clothes:
|
||||||
*
|
*
|
||||||
* 14. AI deskilling spiral — handing the burden of code quality to AI atrophies the
|
* 15. AI deskilling spiral — handing the burden of code quality to AI atrophies the
|
||||||
* Expertise that holds quality up, so the team leans on AI
|
* Expertise that holds quality up, so the team leans on AI
|
||||||
* harder and Technical debt spirals: addiction, not a fix.
|
* harder and Technical debt spirals: addiction, not a fix.
|
||||||
*
|
*
|
||||||
* And a mechanical coda — the gallery's one *hard* ceiling, to contrast the emergent
|
* And a mechanical coda — the gallery's one *hard* ceiling, to contrast the emergent
|
||||||
* ones (above all "Limits to growth"):
|
* ones (above all "Limits to growth"):
|
||||||
*
|
*
|
||||||
* 15. Bathtub with an overflow — the tap runs flat out (a Constant inflow that never
|
* 16. Bathtub with an overflow — the tap runs flat out (a Constant inflow that never
|
||||||
* reads the level) and a spillway carries whatever rises
|
* reads the level) and a spillway carries whatever rises
|
||||||
* past the brim into a second Stock, the floor. The only
|
* past the brim into a second Stock, the floor. The only
|
||||||
* model on the `overflow` rule — a one-sided Gap, the
|
* model on the `overflow` rule — a one-sided Gap, the
|
||||||
@@ -67,7 +71,7 @@
|
|||||||
* Then one last trap, held back until the overflow rule existed to carry it — the
|
* Then one last trap, held back until the overflow rule existed to carry it — the
|
||||||
* language pointed at the most-told cautionary tale in systems thinking:
|
* language pointed at the most-told cautionary tale in systems thinking:
|
||||||
*
|
*
|
||||||
* 16. The cobra effect — a bounty on dead cobras (a Balancing fix) quietly funds a
|
* 17. The cobra effect — a bounty on dead cobras (a Balancing fix) quietly funds a
|
||||||
* cobra *farm* (a Reinforcing engine); breeding outruns what
|
* cobra *farm* (a Reinforcing engine); breeding outruns what
|
||||||
* the bounty can absorb, the farm gluts, and its now-worthless
|
* the bounty can absorb, the farm gluts, and its now-worthless
|
||||||
* surplus spills through an `overflow` gate into the wild —
|
* surplus spills through an `overflow` gate into the wild —
|
||||||
@@ -77,7 +81,7 @@
|
|||||||
*
|
*
|
||||||
* And the capstone — every piece at once, at the scale the whole gallery points toward:
|
* And the capstone — every piece at once, at the scale the whole gallery points toward:
|
||||||
*
|
*
|
||||||
* 17. World on a warming planet — the Club of Rome's World3 (Meadows et al., *The Limits
|
* 18. World on a warming planet — the Club of Rome's World3 (Meadows et al., *The Limits
|
||||||
* to Growth*) in miniature, its pollution sector reframed
|
* to Growth*) in miniature, its pollution sector reframed
|
||||||
* as a climate channel: four coupled Stocks where two
|
* as a climate channel: four coupled Stocks where two
|
||||||
* Reinforcing engines (capital, population) overshoot a
|
* Reinforcing engines (capital, population) overshoot a
|
||||||
@@ -943,6 +947,82 @@ function escalation(): Model {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Success to the successful — Donella Meadows' competitive-exclusion trap (Thinking
|
||||||
|
* in Systems, ch. 5), known in the sociology of science as the *Matthew effect*
|
||||||
|
* (Robert Merton, after Matthew 25:29: "unto every one that hath shall be given").
|
||||||
|
* Two researchers of equal ability compete for one finite thing — the field's
|
||||||
|
* attention — and the only difference between them is that A begins a single point
|
||||||
|
* ahead (Renown 51 vs 49 of a fixed 100).
|
||||||
|
*
|
||||||
|
* The community's attention is a *conserved* budget: a citation, an invitation, a
|
||||||
|
* grant that goes to one does not go to the other, so Renown A + Renown B never
|
||||||
|
* leaves 100. The marginal piece of it drifts to whoever is already better known —
|
||||||
|
* `attention = factor × (Renown A − Renown B)`, a single Stock→Stock Flow draining
|
||||||
|
* the lesser name into the greater. There are no clouds: nothing enters or leaves
|
||||||
|
* the system, it only *redistributes*. That one valve carries *two* Reinforcing
|
||||||
|
* loops — Renown A → [+] → attention → (fills A) → Renown A (more renown wins more
|
||||||
|
* attention), and Renown B → [−] → attention → (drains B) → Renown B (the falling
|
||||||
|
* name is forgotten ever faster). Neither loop has a surviving `−`, so both are
|
||||||
|
* Reinforcing: nothing brakes the gap, and it can only widen.
|
||||||
|
*
|
||||||
|
* A tie is therefore an *unstable* equilibrium — the knife-edge this trap balances
|
||||||
|
* on. A's one-point lead is enough: attention tilts to A, the gap grows, attention
|
||||||
|
* tilts harder, and the field locks in. Renown A climbs 51 → 100 and Renown B fades
|
||||||
|
* 49 → 0 by t≈42 — a near-total monopoly of acclaim, though the two were equally
|
||||||
|
* able. The cruel lesson Meadows draws: where the prize for winning is more power to
|
||||||
|
* win, it is *initial conditions*, not merit, that decide the outcome.
|
||||||
|
*
|
||||||
|
* Contrast "Escalation", the gallery's other two-Stock all-Reinforcing trap: there
|
||||||
|
* the cross-loop has no minus and *both* arsenals blow up together (positive-sum,
|
||||||
|
* unbounded); here the single loop is zero-sum — A rises only as fast as B is drained
|
||||||
|
* — so the same Reinforcing structure *concentrates* instead of exploding. (The cure
|
||||||
|
* Meadows prescribes is to break the coupling — level the field, diversify the prize,
|
||||||
|
* or handicap the leader — none of which the structure here contains: that is the trap.)
|
||||||
|
*/
|
||||||
|
function successToTheSuccessful(): Model {
|
||||||
|
// Two Stocks on one line, the lone attention valve nudged above their midpoint so
|
||||||
|
// the pipe (Renown B → attention → Renown A) and the two info links (each Stock
|
||||||
|
// into the valve) read apart instead of overlapping. Hand-placed, not at midpoint.
|
||||||
|
const renownB = makeStock({ x: -260, y: 80 }, "Renown B")
|
||||||
|
renownB.initialValue = 49
|
||||||
|
renownB.description =
|
||||||
|
"Researcher B's standing — equal in ability to A, and a single point behind at the start. The lesser name the attention drains away from, fading to nothing though B never did anything wrong."
|
||||||
|
const renownA = makeStock({ x: 260, y: 80 }, "Renown A")
|
||||||
|
renownA.initialValue = 51
|
||||||
|
renownA.description =
|
||||||
|
"Researcher A's standing — one point ahead at the start, and that hair's lead is all it takes. Attention concentrates here until A holds nearly the whole field's acclaim."
|
||||||
|
// attention = factor × (Renown A − Renown B): a Gap whose `+` level is A and `−`
|
||||||
|
// target is B. Source B, target A, so a positive rate drains the lesser name into
|
||||||
|
// the greater — and since draining B only widens the gap, the rate never reverses.
|
||||||
|
const attention = makeFlow({ x: 0, y: -120 }, "attention", renownB.id, renownA.id)
|
||||||
|
attention.rule = { kind: "gap", factor: 0.05 }
|
||||||
|
attention.description =
|
||||||
|
"The field's finite attention drifting to the better-known name, ∝ the lead (Renown A − Renown B). A conserved transfer: what A gains, B loses — the one valve through which both Reinforcing loops run."
|
||||||
|
return model(
|
||||||
|
"Success to the successful",
|
||||||
|
[renownB, renownA, attention],
|
||||||
|
[
|
||||||
|
link(
|
||||||
|
renownA,
|
||||||
|
attention,
|
||||||
|
"+",
|
||||||
|
"Renown A is the level in the gap: the further ahead A is, the faster attention flows its way. With the inflow it fills, this closes A's Reinforcing loop — the rich getting richer.",
|
||||||
|
),
|
||||||
|
link(
|
||||||
|
renownB,
|
||||||
|
attention,
|
||||||
|
"-",
|
||||||
|
"Renown B is the target the gap is measured against (the − input). As B fades the gap only widens, so it is drained faster still — a second Reinforcing loop, the same minus on both the link and the outflow.",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
// From a 51–49 near-tie the gap runs away: Renown A climbs 51 → ~100 and Renown B
|
||||||
|
// fades 49 → ~0 by t≈42, then both hold — a near-total monopoly of acclaim won on a
|
||||||
|
// one-point head start. The unstable 50–50 knife-edge a hair's difference tips.
|
||||||
|
{ start: 0, stop: 50, dt: 1 },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fixes that fail — the archetype where a quick fix relieves a symptom but feeds it
|
* Fixes that fail — the archetype where a quick fix relieves a symptom but feeds it
|
||||||
* through a side effect, so the symptom returns and the fix is reapplied for ever.
|
* through a side effect, so the symptom returns and the fix is reapplied for ever.
|
||||||
@@ -1485,23 +1565,23 @@ function bathtubOverflow(): Model {
|
|||||||
* is a Stock the reward built, the brake is the overflow gate, and the damage is permanent.
|
* is a Stock the reward built, the brake is the overflow gate, and the damage is permanent.
|
||||||
*/
|
*/
|
||||||
function cobraEffect(): Model {
|
function cobraEffect(): Model {
|
||||||
// The policy lever (bounty) sits up top, centre, wired into three flows at once: the
|
// Laid out left→right: the farm engine on the left (a Source breeds Farmed cobras,
|
||||||
// intended cull of Wild cobras on the left, and on the right the farm's breeding and
|
// harvest draining up to a Sink), the release bridge in the centre spilling the glut
|
||||||
// cash-out. The release bridge dips below, carrying the farm's glut back across to the
|
// rightward into Wild cobras, and the bounty-driven cull running off to the right. The
|
||||||
// wild, with glut hanging beneath it. Valves are hand-placed, not at midpoints, so
|
// policy lever (bounty) sits up top, wired down into all three flows — cull, breeding,
|
||||||
// every Information Link lands in open space.
|
// cash-out — with glut beneath the bridge it gates. Hand-placed valves keep links clear.
|
||||||
const bounty = makeConverter({ x: 0, y: -300 }, "bounty")
|
const bounty = makeConverter({ x: -80, y: -340 }, "bounty")
|
||||||
bounty.rule = { kind: "constant", value: 1 }
|
bounty.rule = { kind: "constant", value: 1 }
|
||||||
bounty.description =
|
bounty.description =
|
||||||
"The reward paid per dead cobra — held at 1, a normalised policy lever, so every rate here scales with it (a bigger bounty would only run the whole story faster). One lever wired into three flows: the cull, the breeding, and the cash-out."
|
"The reward paid per dead cobra — held at 1, a normalised policy lever, so every rate here scales with it (a bigger bounty would only run the whole story faster). One lever wired into three flows: the cull, the breeding, and the cash-out."
|
||||||
|
|
||||||
// The intended fix: a bounty-driven cull empties the streets of wild cobras.
|
// The intended fix: a bounty-driven cull empties the streets of wild cobras.
|
||||||
const wild = makeStock({ x: -360, y: -40 }, "Wild cobras")
|
const wild = makeStock({ x: 380, y: -40 }, "Wild cobras")
|
||||||
wild.initialValue = 100
|
wild.initialValue = 100
|
||||||
wild.description =
|
wild.description =
|
||||||
"The actual problem the bounty targets — hunted down at first, then overrun once the farm's surplus is loosed on it. It has no inflow of its own, so any rebound can only be the farm's doing."
|
"The actual problem the bounty targets — hunted down at first, then overrun once the farm's surplus is loosed on it. It has no inflow of its own, so any rebound can only be the farm's doing."
|
||||||
const cullSink = makeCloud({ x: -680, y: -40 })
|
const cullSink = makeCloud({ x: 920, y: -40 })
|
||||||
const culling = makeFlow({ x: -520, y: -40 }, "culling", wild.id, cullSink.id)
|
const culling = makeFlow({ x: 660, y: -40 }, "culling", wild.id, cullSink.id)
|
||||||
// culling = 0.16 × Wild × bounty: the Balancing drain, ∝ the stock. Fast enough to
|
// culling = 0.16 × Wild × bounty: the Balancing drain, ∝ the stock. Fast enough to
|
||||||
// crash the wild population by t≈20 — the policy's whole visible success.
|
// crash the wild population by t≈20 — the policy's whole visible success.
|
||||||
culling.rule = { kind: "proportional", factor: 0.16 }
|
culling.rule = { kind: "proportional", factor: 0.16 }
|
||||||
@@ -1509,19 +1589,19 @@ function cobraEffect(): Model {
|
|||||||
"Wild cobras killed for the bounty, ∝ Wild cobras × bounty — the intended Balancing fix that empties the streets at first."
|
"Wild cobras killed for the bounty, ∝ Wild cobras × bounty — the intended Balancing fix that empties the streets at first."
|
||||||
|
|
||||||
// The perverse stock: a farm bred to cash in on the bounty.
|
// The perverse stock: a farm bred to cash in on the bounty.
|
||||||
const farm = makeStock({ x: 360, y: -40 }, "Farmed cobras")
|
const farm = makeStock({ x: -520, y: -40 }, "Farmed cobras")
|
||||||
farm.initialValue = 5
|
farm.initialValue = 5
|
||||||
farm.description =
|
farm.description =
|
||||||
"Cobras bred to cash in on the bounty — the Stock the reward calls into being. It compounds unseen while the streets look clear, then spills its surplus into the wild."
|
"Cobras bred to cash in on the bounty — the Stock the reward calls into being. It compounds unseen while the streets look clear, then spills its surplus into the wild."
|
||||||
const breedSrc = makeCloud({ x: 680, y: -40 })
|
const breedSrc = makeCloud({ x: -980, y: -200 })
|
||||||
const breeding = makeFlow({ x: 520, y: -40 }, "breeding", breedSrc.id, farm.id)
|
const breeding = makeFlow({ x: -760, y: -200 }, "breeding", breedSrc.id, farm.id)
|
||||||
// breeding = 0.31 × Farm × bounty: Farm → breeding → Farm, no `−` → the Reinforcing
|
// breeding = 0.31 × Farm × bounty: Farm → breeding → Farm, no `−` → the Reinforcing
|
||||||
// engine the bounty funds without meaning to.
|
// engine the bounty funds without meaning to.
|
||||||
breeding.rule = { kind: "proportional", factor: 0.31 }
|
breeding.rule = { kind: "proportional", factor: 0.31 }
|
||||||
breeding.description =
|
breeding.description =
|
||||||
"The farm breeding more cobras, ∝ Farmed cobras × bounty — the Reinforcing engine the bounty funds without intending to: more breeding stock, more bred."
|
"The farm breeding more cobras, ∝ Farmed cobras × bounty — the Reinforcing engine the bounty funds without intending to: more breeding stock, more bred."
|
||||||
const harvestSink = makeCloud({ x: 360, y: -260 })
|
const harvestSink = makeCloud({ x: 600, y: -220 })
|
||||||
const harvest = makeFlow({ x: 360, y: -140 }, "harvest", farm.id, harvestSink.id)
|
const harvest = makeFlow({ x: 400, y: -220 }, "harvest", farm.id, harvestSink.id)
|
||||||
// harvest = 0.10 × Farm × bounty: farmed cobras killed and turned in — the rule beating,
|
// harvest = 0.10 × Farm × bounty: farmed cobras killed and turned in — the rule beating,
|
||||||
// and a Balancing drain on the farm.
|
// and a Balancing drain on the farm.
|
||||||
harvest.rule = { kind: "proportional", factor: 0.1 }
|
harvest.rule = { kind: "proportional", factor: 0.1 }
|
||||||
@@ -1531,11 +1611,11 @@ function cobraEffect(): Model {
|
|||||||
// The backfire bridge: once the farm gluts, its worthless surplus is dumped into the
|
// The backfire bridge: once the farm gluts, its worthless surplus is dumped into the
|
||||||
// wild. A one-sided overflow gate (shut below the glut) — no scripted policy reversal
|
// wild. A one-sided overflow gate (shut below the glut) — no scripted policy reversal
|
||||||
// needed; the release falls out of the farm outgrowing its own worth.
|
// needed; the release falls out of the farm outgrowing its own worth.
|
||||||
const glut = makeConverter({ x: 0, y: 300 }, "glut")
|
const glut = makeConverter({ x: -260, y: 260 }, "glut")
|
||||||
glut.rule = { kind: "constant", value: 200 }
|
glut.rule = { kind: "constant", value: 200 }
|
||||||
glut.description =
|
glut.description =
|
||||||
"The farm size past which cobras lose their worth (a fixed 200) — the threshold the spill opens above. A structural stand-in for the day the bounty was scrapped and the snakes became worthless."
|
"The farm size past which cobras lose their worth (a fixed 200) — the threshold the spill opens above. A structural stand-in for the day the bounty was scrapped and the snakes became worthless."
|
||||||
const releases = makeFlow({ x: 0, y: 120 }, "releases", farm.id, wild.id)
|
const releases = makeFlow({ x: -40, y: 60 }, "releases", farm.id, wild.id)
|
||||||
// releases = max(0, 0.6 × (Farm − glut)): shut while the farm is worth keeping, then it
|
// releases = max(0, 0.6 × (Farm − glut)): shut while the farm is worth keeping, then it
|
||||||
// carries off the surplus. The overflow that overruns the wild — and, draining the farm
|
// carries off the surplus. The overflow that overruns the wild — and, draining the farm
|
||||||
// above the glut, the Balancing brake that caps it.
|
// above the glut, the Balancing brake that caps it.
|
||||||
@@ -1908,6 +1988,12 @@ export const SAMPLES: Sample[] = [
|
|||||||
blurb: "An arms race: one Reinforcing loop spanning two Stocks.",
|
blurb: "An arms race: one Reinforcing loop spanning two Stocks.",
|
||||||
build: escalation,
|
build: escalation,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "Success to the successful",
|
||||||
|
blurb:
|
||||||
|
"Two equal researchers, one a hair ahead: the field's attention locks onto the leader and the rival fades — a winner-take-all trap.",
|
||||||
|
build: successToTheSuccessful,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: "Fixes that fail",
|
title: "Fixes that fail",
|
||||||
blurb: "Road building eases congestion (B) but induces the traffic that refills it (R).",
|
blurb: "Road building eases congestion (B) but induces the traffic that refills it (R).",
|
||||||
|
|||||||
Reference in New Issue
Block a user