From d47a167fd06072e8286be947519f3cdc72c79cc5 Mon Sep 17 00:00:00 2001 From: slaguru666 <111923774+slaguru666@users.noreply.github.com> Date: Thu, 6 Aug 2026 00:52:08 +0100 Subject: [PATCH] Packs go to schema 2, so the catalog stamp records the new roster field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit beat.mjs embeds a pack's roster verbatim into every area, so adding beforeInitiative changed the shape of the emitted delve file — and two files from the same seed could carry different structures under identical stamps. The change originates in the packs, not in the generator's composition, so it belongs to catalogVersion rather than GENERATOR_VERSION: the packs are at schema 2 and a file now stamps barrow@2. The note on GENERATOR_VERSION says which stamp owns which kind of change, since that was the ambiguity. README's test counts were still 39 and silent about the adapter suite. Co-Authored-By: Claude Opus 5 --- README.md | 4 ++-- core/content/barrow.json | 2 +- core/content/castle.json | 2 +- core/content/cave.json | 2 +- core/content/church.json | 2 +- core/content/city.json | 2 +- core/content/forest.json | 2 +- core/content/lake.json | 2 +- core/content/market.json | 2 +- core/content/mountain.json | 2 +- core/content/palace.json | 2 +- core/content/port.json | 2 +- core/content/river.json | 2 +- core/content/temple.json | 2 +- core/content/town.json | 2 +- core/content/valley.json | 2 +- core/content/village.json | 2 +- core/delve.mjs | 4 ++++ foundry-module/module/core/content/barrow.json | 2 +- foundry-module/module/core/content/castle.json | 2 +- foundry-module/module/core/content/cave.json | 2 +- foundry-module/module/core/content/church.json | 2 +- foundry-module/module/core/content/city.json | 2 +- foundry-module/module/core/content/forest.json | 2 +- foundry-module/module/core/content/lake.json | 2 +- foundry-module/module/core/content/market.json | 2 +- foundry-module/module/core/content/mountain.json | 2 +- foundry-module/module/core/content/palace.json | 2 +- foundry-module/module/core/content/port.json | 2 +- foundry-module/module/core/content/river.json | 2 +- foundry-module/module/core/content/temple.json | 2 +- foundry-module/module/core/content/town.json | 2 +- foundry-module/module/core/content/valley.json | 2 +- foundry-module/module/core/content/village.json | 2 +- foundry-module/module/core/delve.mjs | 4 ++++ 35 files changed, 42 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index d501568..aceb172 100644 --- a/README.md +++ b/README.md @@ -45,8 +45,8 @@ and two paper playtests that failed before anything worked. | | | |---|---| -| `core/` | the generator — pure JS, 39 tests | -| `foundry-module/` | the Foundry module, with `core/` vendored | +| `core/` | the generator — pure JS, 41 tests | +| `foundry-module/` | the Foundry module, with `core/` vendored — 60 tests | | `paper/` | a hand-written delve and both playtest logs | | `spike/` | the harness that measured VANITY's Forge outside Foundry | | `samples/` | generated output | diff --git a/core/content/barrow.json b/core/content/barrow.json index bdda586..00d088c 100644 --- a/core/content/barrow.json +++ b/core/content/barrow.json @@ -2,7 +2,7 @@ "id": "barrow", "label": "Barrow", "forgeStageType": "barrow", - "schema": 1, + "schema": 2, "_model": "Everything derives from one kernel: an APPETITE and the ACCOMMODATION made for it. The motif, danger, prize kind and faction all follow from the appetite. Cue fragments hang off the MOTIF and are tagged by FACET (institution/ritual/demand/wound/anchor) and level, so two delves sharing a motif draw different imagery. The foreshadow chain is a fixed facet progression mapped onto the arc — which is why area 2's bows and area 4's scratched eyes both point at the same wound.", "appetites": [ { diff --git a/core/content/castle.json b/core/content/castle.json index 98f1554..6d739e0 100644 --- a/core/content/castle.json +++ b/core/content/castle.json @@ -2,7 +2,7 @@ "id": "castle", "label": "Castle", "forgeStageType": "barrow", - "schema": 1, + "schema": 2, "_model": "Same kernel as barrow: an APPETITE and the ACCOMMODATION made for it. A castle's appetites are about holding — ground, fear, obedience, a name — and its accommodations are what a house does to keep them.", "facetProgression": { "approach": "institution", diff --git a/core/content/cave.json b/core/content/cave.json index 4d63ab9..9ed5e36 100644 --- a/core/content/cave.json +++ b/core/content/cave.json @@ -2,7 +2,7 @@ "id": "cave", "label": "Cave", "forgeStageType": "cave", - "schema": 1, + "schema": 2, "placeNameStyle": "claimant", "_model": "Wild kernel underground. The appetite belongs to the hole itself — it wants to be gone into, gone down, spoken to, and to keep whatever comes. Claimants are the cave's own names for itself, and the accommodation is what it did to whoever came in.", "facetProgression": { diff --git a/core/content/church.json b/core/content/church.json index b68d193..3955293 100644 --- a/core/content/church.json +++ b/core/content/church.json @@ -2,7 +2,7 @@ "id": "church", "label": "Church", "forgeStageType": "barrow", - "schema": 1, + "schema": 2, "placeNameStyle": "claimant", "_model": "Interior kernel. A parish church wants to be believed, attended, given to, or kept holy, and its accommodations are what a cure of souls does to keep a flock.", "facetProgression": { diff --git a/core/content/city.json b/core/content/city.json index eb9d6ef..a70b6ad 100644 --- a/core/content/city.json +++ b/core/content/city.json @@ -2,7 +2,7 @@ "id": "city", "label": "City", "forgeStageType": "village", - "schema": 1, + "schema": 2, "placeNameStyle": "own", "_model": "Settlement kernel at its largest. Nobody here knows anybody, so the city knows instead — by ward, by roll, by works, by freedom granted and withheld. Its cruelties are all administrative, which is why none of them can be argued with.", "facetProgression": { diff --git a/core/content/forest.json b/core/content/forest.json index 4bb1bcc..45eff94 100644 --- a/core/content/forest.json +++ b/core/content/forest.json @@ -2,7 +2,7 @@ "id": "forest", "label": "Forest", "forgeStageType": "forest", - "schema": 1, + "schema": 2, "_model": "The wild kernel: the APPETITE belongs to the place itself. A wood wants to be entered, fed, spread, or left uncounted, and the ACCOMMODATION is what it did to whoever was here — took them, grew through them, let them wander. Claimants are the wood's own names for itself.", "facetProgression": { "approach": "institution", diff --git a/core/content/lake.json b/core/content/lake.json index b15f3f3..86172b8 100644 --- a/core/content/lake.json +++ b/core/content/lake.json @@ -2,7 +2,7 @@ "id": "lake", "label": "Lake", "forgeStageType": "fen", - "schema": 1, + "schema": 2, "placeNameStyle": "claimant", "_model": "Wild kernel in still water. Where the river wants movement, the lake wants none: to be left flat, to be looked into, to keep what is under it exactly as it was, and to be a little bigger every year. Claimants are the water's own names for itself.", "facetProgression": { diff --git a/core/content/market.json b/core/content/market.json index 5f65513..ada0c8a 100644 --- a/core/content/market.json +++ b/core/content/market.json @@ -2,7 +2,7 @@ "id": "market", "label": "Market", "forgeStageType": "village", - "schema": 1, + "schema": 2, "placeNameStyle": "own", "_model": "Settlement kernel, but the place is a transaction rather than a community. The appetite belongs to the market itself; the claimants are its offices; and everything it did to people it did by contract, which is why none of it can be undone by force.", "facetProgression": { diff --git a/core/content/mountain.json b/core/content/mountain.json index 6174740..0a413ee 100644 --- a/core/content/mountain.json +++ b/core/content/mountain.json @@ -2,7 +2,7 @@ "id": "mountain", "label": "Mountain", "forgeStageType": "cave", - "schema": 1, + "schema": 2, "placeNameStyle": "claimant", "_model": "Wild kernel at altitude. The appetite belongs to the hill — it wants to be gone up, to be cold, to be the only way through, and to have everything come to rest at its foot. Claimants are the mountain's own names, and its cruelties are all things weather does anyway.", "facetProgression": { diff --git a/core/content/palace.json b/core/content/palace.json index fc396cb..fa22c56 100644 --- a/core/content/palace.json +++ b/core/content/palace.json @@ -2,7 +2,7 @@ "id": "palace", "label": "Palace", "forgeStageType": "barrow", - "schema": 1, + "schema": 2, "placeNameStyle": "claimant", "_model": "Interior kernel at its most VANITY-shaped. A palace wants to be attended, delighted, admired or centred on, and its accommodations are what a court does to people who are useful to that.", "facetProgression": { diff --git a/core/content/port.json b/core/content/port.json index 4cc79b2..8f03e78 100644 --- a/core/content/port.json +++ b/core/content/port.json @@ -2,7 +2,7 @@ "id": "port", "label": "Port", "forgeStageType": "village", - "schema": 1, + "schema": 2, "placeNameStyle": "own", "_model": "Settlement kernel on the water. The appetite belongs to the harbour, which is a place people are always about to leave — so every cruelty here is a way of stopping them, and every prize is something that makes leaving possible again.", "facetProgression": { diff --git a/core/content/river.json b/core/content/river.json index 7a08ed3..d4cdd84 100644 --- a/core/content/river.json +++ b/core/content/river.json @@ -2,7 +2,7 @@ "id": "river", "label": "River", "forgeStageType": "fen", - "schema": 1, + "schema": 2, "placeNameStyle": "claimant", "_model": "Wild kernel in moving water. The appetite belongs to the river — it wants to be asked before it is crossed, to carry things away, to run where it has always run, and to be given somebody rather than have to take them. Claimants are the river's own names.", "facetProgression": { diff --git a/core/content/temple.json b/core/content/temple.json index e515a4d..3fb4391 100644 --- a/core/content/temple.json +++ b/core/content/temple.json @@ -2,7 +2,7 @@ "id": "temple", "label": "Temple", "forgeStageType": "barrow", - "schema": 1, + "schema": 2, "placeNameStyle": "claimant", "_model": "Interior kernel, older and stranger than a church. A temple wants the rite performed exactly, to be fed, to keep its name unsaid, or to be the only one. Its accommodations are what a priesthood does when a god is literal.", "facetProgression": { diff --git a/core/content/town.json b/core/content/town.json index dd409fe..c70fcd8 100644 --- a/core/content/town.json +++ b/core/content/town.json @@ -2,7 +2,7 @@ "id": "town", "label": "Town", "forgeStageType": "village", - "schema": 1, + "schema": 2, "_model": "The settlement kernel: the APPETITE belongs to the place, not to a buried person. A town wants to be prosperous, respectable, safe or necessary, and its ACCOMMODATION is what a corporation does to keep it that way — price people out, charter them away, wall them off. Claimants are offices, not corpses.", "facetProgression": { "approach": "institution", diff --git a/core/content/valley.json b/core/content/valley.json index 275d11b..84a27e7 100644 --- a/core/content/valley.json +++ b/core/content/valley.json @@ -2,7 +2,7 @@ "id": "valley", "label": "Valley", "forgeStageType": "forest", - "schema": 1, + "schema": 2, "placeNameStyle": "claimant", "_model": "Wild kernel that keeps you by being kind. The appetite belongs to the valley — it wants nothing to go over the top, everything to come in out of the wind, everything to end up at the bottom, and its own sky. Every cruelty here looks like hospitality, which is what makes it hard to leave.", "facetProgression": { diff --git a/core/content/village.json b/core/content/village.json index 6e0696b..62542b3 100644 --- a/core/content/village.json +++ b/core/content/village.json @@ -2,7 +2,7 @@ "id": "village", "label": "Village", "forgeStageType": "village", - "schema": 1, + "schema": 2, "placeNameStyle": "own", "_model": "The settlement kernel at its smallest. The appetite belongs to the place; the claimant is an office, not a person; and what a village does to people who might leave is quieter and worse than what a town does.", "facetProgression": { diff --git a/core/delve.mjs b/core/delve.mjs index 2830bb2..0cd345a 100644 --- a/core/delve.mjs +++ b/core/delve.mjs @@ -14,6 +14,10 @@ import { baneBeatFor } from './director.mjs'; * it. Bump it when the shape of the emitted object changes or when content selection changes * enough that the same seed no longer yields the same delve — not when the module version moves. * 0.2.0: the `authored` layer, motif-scoped decisions/temptations/features, areas as situations. + * + * A change that originates in a pack rather than in this file belongs to `catalogVersion` instead + * — beat.mjs embeds the pack's roster verbatim, so a new roster field changes the emitted file + * without changing anything here. `beforeInitiative` is why the packs are at schema 2. */ export const GENERATOR_VERSION = '0.2.0'; diff --git a/foundry-module/module/core/content/barrow.json b/foundry-module/module/core/content/barrow.json index bdda586..00d088c 100644 --- a/foundry-module/module/core/content/barrow.json +++ b/foundry-module/module/core/content/barrow.json @@ -2,7 +2,7 @@ "id": "barrow", "label": "Barrow", "forgeStageType": "barrow", - "schema": 1, + "schema": 2, "_model": "Everything derives from one kernel: an APPETITE and the ACCOMMODATION made for it. The motif, danger, prize kind and faction all follow from the appetite. Cue fragments hang off the MOTIF and are tagged by FACET (institution/ritual/demand/wound/anchor) and level, so two delves sharing a motif draw different imagery. The foreshadow chain is a fixed facet progression mapped onto the arc — which is why area 2's bows and area 4's scratched eyes both point at the same wound.", "appetites": [ { diff --git a/foundry-module/module/core/content/castle.json b/foundry-module/module/core/content/castle.json index 98f1554..6d739e0 100644 --- a/foundry-module/module/core/content/castle.json +++ b/foundry-module/module/core/content/castle.json @@ -2,7 +2,7 @@ "id": "castle", "label": "Castle", "forgeStageType": "barrow", - "schema": 1, + "schema": 2, "_model": "Same kernel as barrow: an APPETITE and the ACCOMMODATION made for it. A castle's appetites are about holding — ground, fear, obedience, a name — and its accommodations are what a house does to keep them.", "facetProgression": { "approach": "institution", diff --git a/foundry-module/module/core/content/cave.json b/foundry-module/module/core/content/cave.json index 4d63ab9..9ed5e36 100644 --- a/foundry-module/module/core/content/cave.json +++ b/foundry-module/module/core/content/cave.json @@ -2,7 +2,7 @@ "id": "cave", "label": "Cave", "forgeStageType": "cave", - "schema": 1, + "schema": 2, "placeNameStyle": "claimant", "_model": "Wild kernel underground. The appetite belongs to the hole itself — it wants to be gone into, gone down, spoken to, and to keep whatever comes. Claimants are the cave's own names for itself, and the accommodation is what it did to whoever came in.", "facetProgression": { diff --git a/foundry-module/module/core/content/church.json b/foundry-module/module/core/content/church.json index b68d193..3955293 100644 --- a/foundry-module/module/core/content/church.json +++ b/foundry-module/module/core/content/church.json @@ -2,7 +2,7 @@ "id": "church", "label": "Church", "forgeStageType": "barrow", - "schema": 1, + "schema": 2, "placeNameStyle": "claimant", "_model": "Interior kernel. A parish church wants to be believed, attended, given to, or kept holy, and its accommodations are what a cure of souls does to keep a flock.", "facetProgression": { diff --git a/foundry-module/module/core/content/city.json b/foundry-module/module/core/content/city.json index eb9d6ef..a70b6ad 100644 --- a/foundry-module/module/core/content/city.json +++ b/foundry-module/module/core/content/city.json @@ -2,7 +2,7 @@ "id": "city", "label": "City", "forgeStageType": "village", - "schema": 1, + "schema": 2, "placeNameStyle": "own", "_model": "Settlement kernel at its largest. Nobody here knows anybody, so the city knows instead — by ward, by roll, by works, by freedom granted and withheld. Its cruelties are all administrative, which is why none of them can be argued with.", "facetProgression": { diff --git a/foundry-module/module/core/content/forest.json b/foundry-module/module/core/content/forest.json index 4bb1bcc..45eff94 100644 --- a/foundry-module/module/core/content/forest.json +++ b/foundry-module/module/core/content/forest.json @@ -2,7 +2,7 @@ "id": "forest", "label": "Forest", "forgeStageType": "forest", - "schema": 1, + "schema": 2, "_model": "The wild kernel: the APPETITE belongs to the place itself. A wood wants to be entered, fed, spread, or left uncounted, and the ACCOMMODATION is what it did to whoever was here — took them, grew through them, let them wander. Claimants are the wood's own names for itself.", "facetProgression": { "approach": "institution", diff --git a/foundry-module/module/core/content/lake.json b/foundry-module/module/core/content/lake.json index b15f3f3..86172b8 100644 --- a/foundry-module/module/core/content/lake.json +++ b/foundry-module/module/core/content/lake.json @@ -2,7 +2,7 @@ "id": "lake", "label": "Lake", "forgeStageType": "fen", - "schema": 1, + "schema": 2, "placeNameStyle": "claimant", "_model": "Wild kernel in still water. Where the river wants movement, the lake wants none: to be left flat, to be looked into, to keep what is under it exactly as it was, and to be a little bigger every year. Claimants are the water's own names for itself.", "facetProgression": { diff --git a/foundry-module/module/core/content/market.json b/foundry-module/module/core/content/market.json index 5f65513..ada0c8a 100644 --- a/foundry-module/module/core/content/market.json +++ b/foundry-module/module/core/content/market.json @@ -2,7 +2,7 @@ "id": "market", "label": "Market", "forgeStageType": "village", - "schema": 1, + "schema": 2, "placeNameStyle": "own", "_model": "Settlement kernel, but the place is a transaction rather than a community. The appetite belongs to the market itself; the claimants are its offices; and everything it did to people it did by contract, which is why none of it can be undone by force.", "facetProgression": { diff --git a/foundry-module/module/core/content/mountain.json b/foundry-module/module/core/content/mountain.json index 6174740..0a413ee 100644 --- a/foundry-module/module/core/content/mountain.json +++ b/foundry-module/module/core/content/mountain.json @@ -2,7 +2,7 @@ "id": "mountain", "label": "Mountain", "forgeStageType": "cave", - "schema": 1, + "schema": 2, "placeNameStyle": "claimant", "_model": "Wild kernel at altitude. The appetite belongs to the hill — it wants to be gone up, to be cold, to be the only way through, and to have everything come to rest at its foot. Claimants are the mountain's own names, and its cruelties are all things weather does anyway.", "facetProgression": { diff --git a/foundry-module/module/core/content/palace.json b/foundry-module/module/core/content/palace.json index fc396cb..fa22c56 100644 --- a/foundry-module/module/core/content/palace.json +++ b/foundry-module/module/core/content/palace.json @@ -2,7 +2,7 @@ "id": "palace", "label": "Palace", "forgeStageType": "barrow", - "schema": 1, + "schema": 2, "placeNameStyle": "claimant", "_model": "Interior kernel at its most VANITY-shaped. A palace wants to be attended, delighted, admired or centred on, and its accommodations are what a court does to people who are useful to that.", "facetProgression": { diff --git a/foundry-module/module/core/content/port.json b/foundry-module/module/core/content/port.json index 4cc79b2..8f03e78 100644 --- a/foundry-module/module/core/content/port.json +++ b/foundry-module/module/core/content/port.json @@ -2,7 +2,7 @@ "id": "port", "label": "Port", "forgeStageType": "village", - "schema": 1, + "schema": 2, "placeNameStyle": "own", "_model": "Settlement kernel on the water. The appetite belongs to the harbour, which is a place people are always about to leave — so every cruelty here is a way of stopping them, and every prize is something that makes leaving possible again.", "facetProgression": { diff --git a/foundry-module/module/core/content/river.json b/foundry-module/module/core/content/river.json index 7a08ed3..d4cdd84 100644 --- a/foundry-module/module/core/content/river.json +++ b/foundry-module/module/core/content/river.json @@ -2,7 +2,7 @@ "id": "river", "label": "River", "forgeStageType": "fen", - "schema": 1, + "schema": 2, "placeNameStyle": "claimant", "_model": "Wild kernel in moving water. The appetite belongs to the river — it wants to be asked before it is crossed, to carry things away, to run where it has always run, and to be given somebody rather than have to take them. Claimants are the river's own names.", "facetProgression": { diff --git a/foundry-module/module/core/content/temple.json b/foundry-module/module/core/content/temple.json index e515a4d..3fb4391 100644 --- a/foundry-module/module/core/content/temple.json +++ b/foundry-module/module/core/content/temple.json @@ -2,7 +2,7 @@ "id": "temple", "label": "Temple", "forgeStageType": "barrow", - "schema": 1, + "schema": 2, "placeNameStyle": "claimant", "_model": "Interior kernel, older and stranger than a church. A temple wants the rite performed exactly, to be fed, to keep its name unsaid, or to be the only one. Its accommodations are what a priesthood does when a god is literal.", "facetProgression": { diff --git a/foundry-module/module/core/content/town.json b/foundry-module/module/core/content/town.json index dd409fe..c70fcd8 100644 --- a/foundry-module/module/core/content/town.json +++ b/foundry-module/module/core/content/town.json @@ -2,7 +2,7 @@ "id": "town", "label": "Town", "forgeStageType": "village", - "schema": 1, + "schema": 2, "_model": "The settlement kernel: the APPETITE belongs to the place, not to a buried person. A town wants to be prosperous, respectable, safe or necessary, and its ACCOMMODATION is what a corporation does to keep it that way — price people out, charter them away, wall them off. Claimants are offices, not corpses.", "facetProgression": { "approach": "institution", diff --git a/foundry-module/module/core/content/valley.json b/foundry-module/module/core/content/valley.json index 275d11b..84a27e7 100644 --- a/foundry-module/module/core/content/valley.json +++ b/foundry-module/module/core/content/valley.json @@ -2,7 +2,7 @@ "id": "valley", "label": "Valley", "forgeStageType": "forest", - "schema": 1, + "schema": 2, "placeNameStyle": "claimant", "_model": "Wild kernel that keeps you by being kind. The appetite belongs to the valley — it wants nothing to go over the top, everything to come in out of the wind, everything to end up at the bottom, and its own sky. Every cruelty here looks like hospitality, which is what makes it hard to leave.", "facetProgression": { diff --git a/foundry-module/module/core/content/village.json b/foundry-module/module/core/content/village.json index 6e0696b..62542b3 100644 --- a/foundry-module/module/core/content/village.json +++ b/foundry-module/module/core/content/village.json @@ -2,7 +2,7 @@ "id": "village", "label": "Village", "forgeStageType": "village", - "schema": 1, + "schema": 2, "placeNameStyle": "own", "_model": "The settlement kernel at its smallest. The appetite belongs to the place; the claimant is an office, not a person; and what a village does to people who might leave is quieter and worse than what a town does.", "facetProgression": { diff --git a/foundry-module/module/core/delve.mjs b/foundry-module/module/core/delve.mjs index 2830bb2..0cd345a 100644 --- a/foundry-module/module/core/delve.mjs +++ b/foundry-module/module/core/delve.mjs @@ -14,6 +14,10 @@ import { baneBeatFor } from './director.mjs'; * it. Bump it when the shape of the emitted object changes or when content selection changes * enough that the same seed no longer yields the same delve — not when the module version moves. * 0.2.0: the `authored` layer, motif-scoped decisions/temptations/features, areas as situations. + * + * A change that originates in a pack rather than in this file belongs to `catalogVersion` instead + * — beat.mjs embeds the pack's roster verbatim, so a new roster field changes the emitted file + * without changing anything here. `beforeInitiative` is why the packs are at schema 2. */ export const GENERATOR_VERSION = '0.2.0';