Files
mmcghen 10e772d087 Run 15: known-nodes exploration (addendum stage 1), per-town debug, O(n^2) fix
Exploration addendum stage 1: per-NPC known-nodes. NPCs gather only from
resources they've personally sensed (radius 22) or been told about;
founders seed with home ground, children inherit parents' maps, node
knowledge diffuses between neighbors like skills. Starving NPCs venture
outward and sense as they go - non-random needs-driven exploration, the
seed of first contact. Repopulation preserved (seeding + survival food
fallback): all towns fed, population stable 86-109 over 240 days.

Debug screen rebuilt: the ~68-row per-villager roster (overflowing at
four-town scale) replaced with a per-town summary - pop, fed%, knowledge,
debris, state breakdown, buildings, culture-colored, plus world
births/deaths. Scales to any population.

Performance: added phase timers and measured instead of guessing - npc.Tick
was 94% of cost, O(n^2) via TickResting calling RestingOccupancy (full
population scan) per building per resting NPC. Fixed with a once-per-tick
occupancy cache on Building. npc phase ~4x faster and now linear; full
240-day four-town run in 180s, faster than the pre-exploration baseline.
Profiling scaffolding removed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 21:17:24 -04:00

380 lines
19 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# WorldSim — Soak Experiment Findings (July 2026)
Four long-run experiments against the South (Nature) town MVP. Each run:
15 NPCs, 256×256 world, seed 12345, ~240 simulated days (2 years) at
accelerated speed. Data: `soak_stats.csv` (daily), `soak_npc_days.csv`
(per-villager dominant states), `soak_gifts.csv` (every gift, with names).
---
## Run 1 — Baseline (no seasons): the dead paradise
**Setup:** constant regeneration, upkeep + food demand only.
**Result:** perfectly stable, perfectly inert. 200 days: wood held a ±1%
band, shelter condition pinned at 100%, **zero trades**, no roles — every
villager Socializing-dominant ~114 of 119 days, 78% of waking life idle.
The village completed all construction and expansion by day 34 and then
had nothing left to want.
**Lesson:** a village is a metabolism, not a project. Equilibrium without
pressure produces no society: no differentiation, no exchange, no
structure. Abundance makes generosity unobservable.
---
## Run 2 — Seasons (regen throttle only): the buffers win
**Setup:** 30-day seasons; winter cuts food regen to 5%, wood to 40%.
Granary added (clay walls — first clay use), need-based gift trigger.
**Result:** winter became a *worked* season — gathering 4,889 ticks/day vs
1,857 in summer, wild stocks visibly drained and refilled. But nourishment
ran the identical sawtooth year-round, the granary sat untouched at
150/150 through two winters, and trades stayed at **zero** across 240 days.
**Lesson:** three compounding buffers (the sustainability floor acting as a
~360-unit hidden savings account, personal pack reserves, wild food budget
exceeding winter need) meant scarcity never reached an individual. Pressure
that only raises labor doesn't create interdependence.
---
## Run 3 — Frost: the hungry gap
**Setup:** winter now *decays* standing food ~7%/day toward 15% (frost
kills the larder); granary draws deepened; anti-redeposit rule.
**Result:** the simulation came alive.
- **First trades in sim history: 21** (17 deep winter, 4 early spring) —
exactly when granary-empty met neighbor-with-food.
- **Granary sawtooth textbook**: full through autumn, empty by winter day
~25, refilled within 4 days of spring. Both years.
- **The sim reproduced the "hungry gap"** — a real agricultural phenomenon
neither designed nor named in the code: worst hunger (village nourishment
0.21) fell in *early spring*, after stores ran out but before the land
regrew past harvestable thresholds.
- Crisis cascaded: the food emergency pulled labor from heating (firewood
reserves dipped to 10, condition below 100% for the first time).
- Balanced: severe hunger, zero lasting health damage, both years.
**Lesson:** storage limits + decay + regrowth lag ⇒ emergent seasonality of
need. Sharing is a *response*, not a behavior: 480 days of abundance
produced zero exchanges; ten days of genuine need produced twenty-one.
Still missing: individual roles — identical souls in a global work queue
respond identically (winter gather ticks all within 490553).
---
## Run 4 — The contrast test: 3 selfish souls among 12
**Setup:** villagers M/N/O run the East (Selfish) soul profile. Same
engine, same possibility space; only behavior weights differ: low
sustainability (strip nodes to ~15% vs the 50% commons floor), low
generosity (refuse gifts; excluded from asking), low community bias (no
communal work at all), high accumulation (double carry, standing hoard).
**Result — the four-town thesis validated:**
- Selfish villager-days: **0 build ticks** (vs 104/day for nature souls),
gather 69 vs 269, **rest 0** (never tired), socializing 1,369 vs 921.
A visible leisure class living off a working village.
- Gift network: 11 gifts, all nature→nature. The selfish never gave and
never needed to receive. First individual differentiation appeared:
**Villager_A gave 4 of 11 gifts** — the village's generous one.
- The 12 communal souls absorbed 15 souls' worth of burden without a
single ruin.
**The central finding: selfishness strictly won.** Most leisure, least
fatigue, fullest bellies, zero costs, no pushback. This is not a balance
bug — it is the empirical case for the game's soul layer. Economics alone
cannot make selfishness cost anything; that is the job of imprints,
debris, echoes, and social memory (the Unity POC's warmth-echo system).
The soul-consequence layer is not flavor on top of the economy — it is
the only thing standing between the South town and being farmed by the
East.
---
## Run 5 — The soul layer, uncalibrated: everyone a sinner
**Setup:** warmth echoes (memory replaces omniscience), refusal debris,
commons-line harvest debris, soul-to-soul atmospheric pressure, debris
metabolic tax (faster drain, weaker meals).
**Result:** justice arrived — all 108 refusals belonged to the selfish
three, whose health collapsed to 3164 while nature souls held 100 (the
selfish never rest, so they have no healing loop — laziness blocking
recovery is fully emergent). But two pathologies: (1) the whole village
ratcheted to maxed others-regard debris, because the 50% commons penalty
line sat above the nature souls' own 45% harvest floor and debris had no
clearing path — harm without healing; (2) warmth-weighted asking plus
near-total gift transfers produced a 2,501-gift winter food-swapping
loop, and the universal debris tax turned the hungry gap into famine
(village nourishment 0.00).
**Lesson:** a moral system needs calibrated innocence and a redemption
path, or it converges to universal guilt and reads as noise.
## Run 6 — The soul layer, calibrated: the ledger works
**Setup:** commons line lowered to 40% (below any respectful floor);
gifts capped (keep 5, give ≤3, ask only when genuinely hungry); giving
heals the giver (0.003 others-regard vs +0.02 per refusal — harm ~7×
easier than healing).
**Result — the design document, in numbers:**
- **Nature souls: debris 0.000 after two years.** The innocent are
innocent.
- **Selfish souls: 0.225 and climbing.** The debris gap is total and
driven entirely by how each soul lives.
- Gift ping-pong dead (2 gifts); the contact log is 18 refusals — in the
hungry gap the only villagers with surplus are the hoarders, so the
starving ask them, are refused, and learn. The village's warmth map is
a map of learned coldness pointing at three names.
- Material consequences within one lifetime are mild — the selfish stay
comfortable. **The sim's justice is written in the souls, not the
outcomes.** That is correct: in the full game, the ledger cashes out
at death (heavy debris carries forward; the rebirth verdict; the grave
nobody tends). The sim now produces exactly the input reincarnation
consumes.
---
## Next
## Run 7 — Organic construction v1: the stone-lock collapse
**Setup:** two towns (South nature+selfish, North generational); all
construction quotas removed. Shelters founded after three unsheltered
nights (beds are real: 3 + modules); granaries founded from surplus.
**Result:** a construction boom (8 shelters, multiple granaries by day
10), then **total civilizational collapse by day 40** — every building
ruined, and both towns spent the remaining 200 days homeless among the
monuments. Cause: a priority inversion. The homeless-gather-stone rule
preempted every other communal priority, so once ruins made everyone
homeless, all communal souls locked onto stone forever — foundations got
laid, walls (wood) never did, firewood hauling and granary stocking
ceased entirely, and the emergency rule prevented the emergency from
ever ending.
**Lesson:** in a needs-driven economy, priority ordering *is* the
constitution. An urgent rule that outranks the work needed to resolve it
deadlocks the society. (Also: surplus-founding without scarcity memory
produced granary sprawl by day 5 — buildings must be founded by lived
need, not by momentary abundance.)
**Fixes → run 8:** construction sites outrank homeless stone-gathering
(finish the walls before founding another foundation); homeless founding
defers while any shelter is under construction; granary founding
requires hunger memory + surplus, not surplus alone.
## Runs 89 — Organic construction v2: fixed forward, broken backward
Headless debugging (runs driven from the CLI) found and fixed three real
bugs: **wilderness homes** (founders built wherever their pack filled —
usually at a stone mine 100+ cells out; homes now rise at the founder's
habitual sleeping spot, within reach of the community), **sleepless
nights** (low-fatigue villagers socialized all night, so beds went unused
and rough nights — the founding trigger — never occurred; night now sends
everyone to bed), and **floor-sleeping** (arrivals at a full shelter
counted as sheltered; a bed must exist when you lie down in it).
**Verified working:** bootstrap founding near town, ~2,200 construction
deliveries, first roofs by day 3, three seasons of stability.
**Open problem (later resolved in run 10):** the loop cannot recover from
loss. The winter crisis ruins shelters and rebuilding stalls.
## Run 10 — The mineral question: recovery achieved
Demand diagnostics found the recovery blocker was *material*, not
motivational: homeless villagers correctly demanded stone (462/525
villager-days) but could not get it, twice over:
1. **The commons ethic stranded the stone.** Respectful souls won't take
the last half of any deposit — but stone doesn't regrow, so once all
deposits sat at the floor, the world's remaining stone was morally
untouchable and the homeless stayed homeless forever. *Fix: the
harvest floor is an ethic of regrowth — floors and commons debris now
apply only to living, regenerating resources. Minerals quarry to
depletion, for every soul equally.*
2. **Lossy packs milled the mountains to dust.** Idle variety-gathering
mined stone as busywork, and the make-room rule vaporized cargo on
every demand flap — 900+ stone destroyed in packs. *Fix: idle
gathering touches only what regrows, and packs may only shed what the
land replaces. Minerals are mined on purpose and conserved.*
**Correction:** run 10's original "zero year-2 ruins" claim was
contaminated — the headless console wrapper orphaned child sim processes
that kept writing to later runs' CSVs. (Instrumentation lesson: kill
process trees; distrust out-of-order data.) Clean reruns showed the
recovery loop worked but the town *cycled* — collapse each winter,
rebuild each spring — with chronic post-famine hunger.
## Run 11 — Enough, and the stone-mules: clean stability
Two fixes closed it: **granary satiation** (hunger scars motivate
storage only until the town's capacity could carry a winter — enough is
a real quantity; sprawl of ~10 granaries fell to the sated level), and
**quarry return** (villagers whose packs filled with undroppable stone
after rebuilds became starving porters, unable to gather food while
carrying a house on their backs; unneeded stone now goes back to the
quarry).
**Clean verified result:** year-1 catastrophe and rebuild as before;
then year-2 nourishment steady at 0.77, **year-2 winter with zero new
ruins and 100% condition**, textbook granary sawtooth (1,200 → 0 →
refilled). Organic civilization: naive youth, catastrophe, learning,
stable maturity — now on trustworthy data.
Open (Phase 3 economy, not a bug): accessible stone ran dry during the
rebuild (construction + quarry-return overflow at full nodes + selfish
hoards), so housing plateaus below population — a stable, fed town with
a permanently under-roofed minority. Wants deeper quarrying/metal and
real stockpiles.
---
## Run 12 — Knowledge, mortality, and the North's soul (SPEC §5)
**Built:** three skill domains (forage/woodcraft/masonry) that pay off
(skilled hands harvest more, masons waste less) and grow by practice;
proximity diffusion soul-calibrated by absorption × teaching-drive;
**mortality** — the piece that makes knowledge *generational*: elders die
at ~150230 days, everything unshared dies with them, and a youth comes
of age knowing almost nothing. The North's whole identity is two numbers
(absorption 1.6, teaching 0.9) vs the South's (1.0, 0.3); the East
teaches no one, ever.
**First finding (instrumentation):** headless soaks were being
contaminated by orphaned Godot child processes writing to later runs'
CSVs — two files disagreeing on the final day was the tell. Fixed with a
`StopAfterDays` clean self-terminate (no external kill, no race).
**Second finding (design):** passive-only diffusion barely helped the
North — youths spawned at the empty town centroid and worked solo, so a
death reset a villager to roughly what they'd have self-taught anyway.
The missing mechanic was the North's actual culture: **the young must
seek out elders on purpose.** Added deliberate teacher-seeking for
high-absorption souls, and youths now cradle beside the town's wisest
elder instead of in a void.
**Result:** the North leads at every checkpoint (day 150: 0.586 vs 0.477;
final 0.972 vs 0.951) and both towns reach far higher knowledge than
before. But the gap is modest **because a stable town approaches the
knowledge ceiling regardless of teaching speed** — everyone eventually
maxes out; the North just arrives sooner. Teaching culture is a
*recovery* advantage, not an equilibrium one.
**Next experiment (the real test):** a shock that kills the experts, then
measure which town rebuilds its knowledge — the North's thesis stated as
a falsifiable claim.
---
## Run 13 — The full world: four towns, one engine
**Built:** world scaled 3× (768×768), all four towns at compass points
each running its own soul culture (North generational, South nature,
West materialist — new profile — East selfish); two new resources (Ore,
Herb — herbs are medicine, mended health; a reason to forage and a trade
good); a **spatial hash grid** so proximity queries stop being O(n²)
(3.6× headless speedup at ~80 NPCs, live view viable); and the first
social verb beyond work: **pair-bonds** (settled adults who keep warm
company pair up; warmth now accrues from proximity, not only gifts;
bonds break at death). Reproduction deferred (bonds-first, per plan).
**Result — the four-town thesis, fully realized on one engine:**
| Town | Nourish | Knowledge | Debris | Character |
|-------|---------|-----------|--------|-----------|
| North | 0.84 | **1.27** | 0.000 | wise, whole — teaching wins |
| South | **0.85** | 1.18 | 0.000 | content, clean, lives with the land |
| West | 0.80 | 1.24 | **0.227** | prosperous but soul-marked |
| East | 0.60 | 1.08 | 0.223 | scheming and hungriest — selfishness starves itself |
The two positive cultures stay soul-clean; the two negative carry real
debris. The North leads knowledge (its purpose); the East trails it and
is hungriest (teaches no one, shares nothing). 99 bonds, 80 deaths — a
living, pairing, generational population in four distinct societies, all
from behavior weights. Nothing is scripted; the cultures are emergent.
## Run 14 — Reproduction, and towns anchored to the compass
**Built:** children from bonds (Phase B). Death no longer auto-spawns a
replacement — people die and are gone; bonded, fed, adult pairs conceive
(logistic-damped toward a per-town carrying capacity, so population is a
band, not an explosion or a collapse). Population is now genuinely
dynamic: births vs deaths. Also anchored towns to their cardinal seeds —
the build-centroid is now 70% weighted to the fixed compass point, so
settlements stay planted (North founds at ~(388,139) by its (384,130)
seed) instead of drifting to map-center where foraging paths overlap
(West had wandered 100+ cells before).
**Tuning story (three failed calibrations, logged as the lesson):**
first pass exploded (80→211 by day 80 — young founders, nobody dying,
every couple breeding); over-damped to fix it and the world died out
(80→6, East extinct); the real bug was a *generational gap* — founders
aged out of fertility before their children matured and bonded, so
births stopped even as room opened. Fix: wide fertility window (to 85%
of life) + generous rate (0.12/couple/day × room). Population dynamics
are a control loop; the birth rate must track the death rate or the
system runs away in whichever direction it's biased.
**Result — reproduction sharpens the four-town thesis:** births (108) ≈
deaths (104), population settled in a healthy band (~68109). And the
cultures now diverge in *demographics*, not just soul-state: North (26)
and South (22) thrive and stay soul-clean; West shrinks (16) with debris
creeping in; **East collapses to 4, starving (nourishment 0.00), highest
debris — selfishness now literally fails to sustain a population.** A
town that won't share or cooperate can't feed its people or raise a next
generation. The most damning verdict the sim has produced.
## Run 15 — Known-nodes exploration (addendum §4) + the O(n²) hunt
**Built (stage 1 of the exploration addendum):** per-NPC known-nodes — an
NPC gathers only from resource nodes it has personally sensed (radius 22)
or been told about. Founders seed with their home ground; children
inherit their parents' map; node knowledge diffuses between neighbors by
the same proximity rule as skills. When nothing known qualifies, a
starving NPC ventures outward (biased away from town anchor) and senses
as it goes — the non-random, needs-driven venture-out the addendum wants,
and the seed of first contact. Repopulation explicitly preserved: seeding
+ a survival food fallback keep towns fed (verified: all four 0.560.78
fed, population stable 86109 over 240 days).
**Debug screen rebuilt:** the per-villager roster (one line per soul,
~68 rows overflowing the panel at four-town scale) replaced with a
per-town summary — population, fed%, knowledge, debris, state breakdown,
buildings, colored by culture, plus world births/deaths. Scales to any
population.
**The performance lesson, earned properly this time:** the sim slowed to
a crawl and I burned four rounds guessing (node index — no; periodic
sensing — barely; node cell-index — barely; gated diffusion — barely).
Then I added phase timers and *measured*: `npc.Tick` was 94% of cost and
grew O(n²) with population. The culprit was `TickResting` calling
`RestingOccupancy` (a full-population scan) once per building per resting
NPC — O(buildings × NPCs²) per tick. Fixed with a once-per-tick occupancy
cache on Building. Result: npc phase ~4× faster and now linear; full
240-day four-town run in **180s, faster than the pre-exploration
baseline** despite all the new systems. Lesson restated: profile first;
the bottleneck is never where you guess.
**Next:** stage 2 (soul-weighted venture-out + first contact); crisis-
recovery experiment; save/load; then the player pivot.
---
Soul layer: done and validated (runs 56). The expansion phase begins:
1. **Towns as spatial structure**: multiple settlements with their own
centroids, buildings, and granaries; NPCs affiliated with a home town
but free to roam — the blend space between towns becomes real.
2. **The North (Generational) town**: second settlement; its signature
knowledge/teaching system (SPEC §5) is the largest unbuilt spec piece.
3. Inter-town contact and trade routes (Phase 3); object-level soul
residue traveling with traded goods.
4. Save/load round-trip (SPEC §9 amendment) — still outstanding.