Packs go to schema 2, so the catalog stamp records the new roster field

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 <noreply@anthropic.com>
This commit is contained in:
slaguru666
2026-08-06 00:52:08 +01:00
co-authored by Claude Opus 5
parent c1e467c91b
commit d47a167fd0
35 changed files with 42 additions and 34 deletions
+2 -2
View File
@@ -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 |
+1 -1
View File
@@ -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": [
{
+1 -1
View File
@@ -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",
+1 -1
View File
@@ -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": {
+1 -1
View File
@@ -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": {
+1 -1
View File
@@ -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": {
+1 -1
View File
@@ -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",
+1 -1
View File
@@ -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": {
+1 -1
View File
@@ -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": {
+1 -1
View File
@@ -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": {
+1 -1
View File
@@ -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": {
+1 -1
View File
@@ -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": {
+1 -1
View File
@@ -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": {
+1 -1
View File
@@ -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": {
+1 -1
View File
@@ -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",
+1 -1
View File
@@ -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": {
+1 -1
View File
@@ -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": {
+4
View File
@@ -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';
@@ -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": [
{
@@ -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",
+1 -1
View File
@@ -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": {
@@ -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": {
+1 -1
View File
@@ -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": {
@@ -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",
+1 -1
View File
@@ -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": {
@@ -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": {
@@ -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": {
@@ -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": {
+1 -1
View File
@@ -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": {
@@ -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": {
@@ -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": {
+1 -1
View File
@@ -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",
@@ -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": {
@@ -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": {
+4
View File
@@ -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';