Right now koditoki's village is three villagers hand-typed into a file. This is the read of what that world actually does when it runs, and the build-ordered brief for growing it into thirty-plus specialists without breaking the thing that makes it interesting: a digger who cannot feed himself.
Three agents, one dependency chain, no shortcuts. The forager eats what it picks and needs nobody. The smith casts one copper nugget into a tool and hands it to the digger, who alone can reach the roots under the bed. Cut any one relationship and someone starves — that fragility is the whole point of the demo, and it is the thing a cluster generator has to reproduce thirty times over, not paper over.
● digger ● forager (self-sufficient, sawtooth from eating alone) ● smith. The digger's last successful dig is t28; hunger rises unbroken after and pins at 1.0 by t62 — it does not die (no mortality system is wired in), it just sits there, "exhausted," for the rest of the run.
The world seeds exactly one copper nugget with hits: 4. The smith casts it once, hands it off at t07, and never holds copper again — its want clause (sharp ?x) <- (kind ?x copper)(holding self ?x) can't re-fire. The digger spends the four hits at t08/t12/t16/t28, and the tool's (sharp nugget) mark never returns.
| tick | event | hits left |
|---|---|---|
| t07 | smith gives nugget to digger | 4 |
| t08 | dig | 3 |
| t12 | dig | 2 |
| t16 | dig | 1 |
| t28 | dig — tool spent, sharp retracted | 0 |
| t62 | digger hunger reaches 1.0, never eats again | — |
The scripted 36-tick demo ends at t36 — before this ever shows. "The digger still eats" is a claim about a window, not a steady state, and any longer or larger run inherits it once per cluster, on the same clock, independently.
Trade is gated by trades-with (rigid, checked once at grounding) but priced by give's grounded literals, and the two behave nothing alike. Probed directly against compileFrame/give.ts:
| co-located, dealt-with partners | vocab bits | ops | frame |
|---|---|---|---|
| acquainted, not co-located (any count) | 0 | 0 | free |
| 1 | 7 / 64 | 1 | fits |
| 3 | 17 / 64 | 3 | fits |
| 6 | 32 / 64 | 6 | fits |
| 9 | 47 / 64 | 9 | tight |
| 12 | 62 / 64 | 12 | tight |
| 13+ | — | — | no-frame |
Same real village frame (give + cast + eatFromHand + walkTo + sleep). Each co-located partner adds ~5 bits: their location, a promise-retraction bit spent whether or not a promise exists, their holding, the give, the receipt. An acquaintance who isn't in the room costs nothing — that's the design lever.
A cluster is a grove (forager+bush), a bed (digger+roots), a forge (smith+mold+nugget) and a square, all local to that cluster's three specialists. Of everything in the three agent specs, almost all of it — clauses, reflexes, schemas, framing, disposition, body — parameterizes only over self and is copy-per-instance for free. Four things don't:
| what | today | indexed |
|---|---|---|
scenery(self)'s two module consts | AGENTS, WORKPLACES (whole village) | this cluster's 3 names only |
| smith's seeded promise | promised("smith","digger","pick") | promised(smith(i), digger(i), "pick") |
| smith's earshot belief | ["can-hear","forager","smith"] | [..., forager(i), smith(i)] |
smith's asksFor hearers | hearers: ["forager"] | hearers: [forager(i)] |
| world things | nugget, mold, bush, bed | nugget-i, mold-i, bush-i, bed-i |
AGENTS/WORKPLACES in place and leaving scenery() alone hands every mind every other cluster's agents and workplaces too — facts/mind grows with population, the exact OwnMap defect (koditoki-9bb1) already fixed once in households.ts. Worse: no AgentSpec in village.ts sets ownMap today, so build.ts's belief() silently hands every mind the world's whole topology regardless of what scenery() seeds — invisible now only because the world is 4 places.Each cluster is a 4-place diamond around its own square, diameter 2 — the shape the current 3-agent village already validates (and already fills to 64/64 bits). Clusters never share a place; they're joined only by empty road nodes, long enough that no agent's speech (hearing range 2) reaches a neighboring forge or grove.
| role | kHops | reach | why |
|---|---|---|---|
| forager, digger, smith | 2 | 2 | exactly the diamond's diameter through the square — unchanged by cluster count, held constant regardless of share |
share as scripted (how many clusters' squares coincide) is the honest reading of "the Dunbar knob" — but the frame has no headroom for it. The unmodified single cluster already peaks at 64/64 bits with nobody sharing anything.
trades-with stays scoped to each triple's own three members — forager, digger, smith of the same cluster, never a neighbor. Per §02, that's free at any population as long as the partner isn't standing in the same place. Three probed configurations, real compileFrame, 10 clusters, own-group scenery:
share | dealsWith scope | smith frame | result |
|---|---|---|---|
| 1 | own triple (3) | 29 / 64 | flat, 3→100 clusters |
| 2 | own triple, square shared | 38 / 64 | 88% full by share=4 |
| 2 | whole share-group | — | no-frame |
| 3, 6 | whole share-group (as scripted) | — | no-frame — both requested values fail |
Decision: default share = 1. It is not the density dial it's described as — it's an on/off switch, and it's off. share > 1 is a separate, deliberately-run experiment that needs its own frame-slimming pass (fewer ask words, tighter rigid set) before it means anything; ship it documented as expected-to-fail, not degraded-gracefully.
| metric | how | pass |
|---|---|---|
| specialist count | clusters × 3 | ≥ 30 (clusters ≥ 10) |
| facts/mind vs. population | compare clusters=3/10/30 with ownMap:true | flat, not the 174→1254 households curve |
| frame bits, per cluster | diff every cluster's per-tick trace against the unmodified 3-agent baseline | identical shape, no stray bit from a leaked cross-cluster fact |
| digger fed | each cluster's digger eats at least once inside the run window (< ~t60/cluster, per §01) | all clusters, not indefinitely — state the window explicitly |
| cross-cluster leakage | relations matrix: any give/ask/promise between agents of different clusters | zero, by construction |
| ms/agent | wall clock at clusters=3/10/30 | flat, matching the households anchor (~300–330ms/agent), not the fort's hub curve |
Already run at 10 clusters (30 agents), share=1, 120 ticks: 0 no-frame verdicts, 4 completed gives/cluster, all 10 diggers eat at least once, zero cross-cluster edges in the relations matrix, ~303–333ms/agent flat from clusters=3 to 30. This is the configuration to ship.
Smallest verifiable step first, so a regression is caught at the step that caused it — never at "run 30 clusters and see."
i=0, byte-identical to today. Write squareOf/groveOf/bedOf/forgeOf and the per-cluster scenery(); run clusters:1 and diff its full event log against unmodified village.ts.Gate: zero diff, including frame-bit counts per tick.ownMap: true to all three specs. Confirm KB size is unchanged at clusters:1 (topology was already only 4 places) — this step should be invisible here and only matter from step 3 on.Gate: facts/mind identical to step 1.share:1, roads long enough to clear hearing range 2. Run 40+ ticks; check cluster 1's forager KB never gains a fact naming cluster 2's agents, and vice versa.Gate: zero cross-cluster facts in either KB; both diggers eat once each.share:1. Run 120 ticks. Plot facts/mind and frame-bits vs. cluster index.Gate: both flat across clusters; 30 specialists; every digger eats at least once before ~t60.share:1. Repeat step 4's measurements at 3x scale; time the run.Gate: ms/agent flat vs. step 4, matching the households curve, not the fort's.share:2 as a named experiment. Don't fold into the main branch. Confirm it fails the way §05 predicts — no-frame near-immediately with the vocabulary as-is — before spending any effort slimming it.Gate: documented failure, matching the probe, not a surprise.Growing AGENTS/WORKPLACES in place while leaving scenery()'s body untouched compiles and runs fine at clusters:1–3 and silently reproduces the OwnMap facts/mind curve from clusters:10 up. It looks correct for exactly long enough to ship.
households.ts's pure star and dropping the forge–grove edge.households.ts has no spoke-to-spoke edge; village.ts's does, and the file's own comment says without it the smith forgets the grove is stocked before it can ask. A literal port drops this fourth edge per cluster, silently.
share as a dial instead of a switch.The brief names it the density knob; the measured frame has zero headroom above share=1. Anyone who runs share=3 expecting a smooth curve gets no-frame and will spend time debugging a working design.
It's single-shot per cluster, independent of clustering — one nugget, four hits, no resupply. Every cluster hunger-caps its digger on its own clock past ~t60. A report or demo run longer than that will show it, per cluster, at scale.
The hearing daemon delivers by ground-truth graph distance, not by who the speaker believes is listening (koditoki-9fc5). Road length has to be sized ≥ hearing range + 1 explicitly and verified with a two-cluster probe, or a neighboring forager quietly picks up a promise it can never collect on.
share as tunable and asks for measurements at 3 and 6; three independent probes (trade-cost, frame-bit, and the direct share∈{1,2,3,6} sweep) all agree it overflows at share=2 under the literal design and by share=3 under every scoping variant tried. This brief ships share defaulted to 1 and documents anything higher as a deliberately-broken experiment, because that is what three independent measurements say is actually true of this frame today — not because the knob is unwanted.