Two bugs the first real button-press exposed.
The ⛏ never appeared. getSceneControlButtons was written for the old array
shape, but v13+ passes a record keyed by name and the token group is `tokens`,
plural — so the hook silently added nothing. Every earlier test had gone through
the API, which masked it completely. It now handles both shapes.
Area names were picked per-area from a small per-role list, so two areas sharing
a role could collide: a generated dungeon shipped with two scenes both called
"The Lesser Vault". Names are now dealt globally without replacement, falling
back to other roles' lists before ever repeating. This is the same bug already
fixed for features, decisions, temptations and situations — missed for names
because names were assigned in beat.mjs rather than dealt in delve.mjs.
A test now generates 180 delves at 6, 9 and 12 areas and asserts no two areas
in one delve share a name. Tests 38 -> 39.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Four readings of generated output reached the same verdict, and the last one
answered 'would you run this tomorrow' with No. Three renderer passes each
fixed what the previous review named and each introduced a new fault: adding
resolution blocks made it menu-like, and subtracting blocks buried the clue and
the skip guidance. The density is not a rendering bug. Everything on the page
is a vice at the table and a virtue at the desk.
So one working file, two surfaces. The worksheet carries everything, labelled,
with reroll commands beside each component and explicit prompts where only a
human can write. The play sheet carries the GM's own prose, the leverage point,
the decision on one line and the numbers — 61 lines against the worksheet's 137.
The JSON is the document. An authored layer holds what the GM writes and the
generator never touches it, so a reroll cannot destroy prose. Lock what is
good, reroll what is not, write the read-aloud, export.
Two bugs found while building it, both in reroll: the exclusion set omitted the
area's own current value so a reroll could hand back what was already there,
and when every option was in use — six areas against a six-item pool — the
fallback did the same. A reroll that changes nothing looks broken.
DELVE does not write the read-aloud and does not write the climax. It gets a GM
to a strong first draft in a minute instead of an evening, then gets out of the
way. Tests 28 -> 38.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A cold read caught the subtraction pass emitting broken English:
'Nobody — but the bells are moving is a summons is being rung...'. The opener
template assumed occupant was a noun phrase and doing was a participle; ten
situations broke that, and one occupant carried its own clause.
Root cause fixed in the data, not the template. The template also drops its
hardcoded copula for an em-dash appositive, which removes subject-verb
agreement as a failure mode entirely — 'The bells is ringing' cannot recur.
Three invariants now guard it: occupants carry no verb, actions are participle
phrases, and no rendered opener contains a stray copula. The first version of
that last test was wrong rather than the output — it counted em-dashes and
flagged 191 false positives on cue fragments that legitimately contain one.
The audit regex also had a false negative, since 'something' ends in -ing.
Tests 25 -> 28.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Third reading said the core criticism was gone — areas now arrive as playable
rooms — but that the result was over-stuffed: 'a room plus its operating
manual'. Asked for the single remaining gap, it said one word: integration.
The hand-written delve makes image, situation, pressure and choice read as one
thing; this presented them as stacked components.
So this removes blocks, not content. The image, the situation and the automatic
clue become one opening paragraph to read from. The decision collapses to
attempt/miss/or. Trigger, bane beat, fallback and skip-guidance become a single
GM footer line. The per-area truth drops the delve-level transgression, which
was already in the header and was being reprinted in every area.
Areas go from roughly thirty lines to eleven to eighteen.
A new invariant asserts the pass removed blocks and not information: for twenty
delves, every situation, onArrival, because, offer, decision, alternative,
trigger, fallback, temptation and roster must still appear in the rendered page.
Tests 24 -> 25.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The review's verdict after resolution blocks: 'still choices attached to
prompts, not spaces that naturally produce play'. The hand-written delve gives
a place — four people back-to-back around a dead lantern — and the decisions
fall out of it. DELVE gave a decision and asked the GM to imagine the room.
Every area now carries a situation: an occupant, what they are doing, what
changes when the party walks in, why (GM), and what it offers. 48 across 8
motifs, motif-scoped and dealt without replacement.
It produces chains nothing planned: in seed live-table-01 a grave-robber in
area 2 is trying to get a password's intonation right, and area 4 is a door
that needs one. Three routes to it now exist where there was a Wits roll.
Also closes the last two open complaints: the five roll-less decisions now have
real attempts (a voice you could not speak to was the weakest), and {priorCue}
resolves against a cue the party has actually seen instead of granting the
answer by fiat.
Tests 19 -> 24.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Playtest 3 put four players (Codex) through a generated delve with only the
player-facing text. Verdict: "a list of room-prompts, not a place", which
"expects the GM to invent too much of the actual game". It localised that to
one thing — decisions had a cue and a cost but no resolution.
Every decision now carries: an attempt roll, an explicit success outcome, an
explicit failure outcome, and an always-available alternative. 48 blocks across
8 motifs. The alternative is not optional: playtest 1 died on a gate the table
could fail without knowing, and the sharpest complaint this time was a door
whose only options were "guess blind and bleed Banes" or "pay time".
Features are now motif-scoped too, so all three furniture pools belong to the
fiction rather than a global list. 136 authored entries per theme.
Three new invariants make the failure modes unauthorable: every decision has a
resolution, no decision gates progress without an alternative, and every rolled
decision states both success and failure. Tests 16 -> 19.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The review's sharpest finding was that the fiction cohered but the things in
the rooms did not belong to it: only the motif cue fragment was projected, while
decisions and temptations came from global pools. The output was a consistent
wrapper around generic room furniture.
Both now live under motifs.<id> — 6 decisions and 5 temptations each, 88
authored entries across 8 motifs. A `keeping` delve offers a flower that has not
wilted and a room you may search or leave exactly as you found it; a
`precedence` delve offers a corridor that will not let two walk abreast.
Two bugs surfaced while wiring it, both the same shape as one fixed earlier for
cue fragments: decisions and temptations were picked independently per area
rather than dealt, so a pool of 3 repeated a temptation in 75 of 80 test delves.
Both are now dealt without replacement.
Where a long delve outruns its motif pool, decisions top up from the generic
pool but temptations do not. A generic relic breaks the fiction; a repeated one
only looks thin.
Tests 11 -> 15: motif provenance for both pools, and no repeats at 6 and 9 areas.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Build steps 1, 2 and 4 of the plan in DESIGN.md.
core/ is pure JS with zero Foundry globals and 11 passing invariants. The
fiction model has one root draw — an APPETITE plus the ACCOMMODATION someone
made for it — and projects the motif, danger, prize, faction, cue fragments and
the appeasement move from it, so the fiction coheres instead of being four
unrelated draws. 336 kernels from 21 authored lines; 60 generated delves gave
51 distinct kernels.
Cue fragments are tagged by facet (institution/ritual/demand/wound/anchor) and
dealt without replacement. The facet progression across the arc reproduces the
hand-authored paper delve's structure, which had arrived at it by instinct.
Generation and table dice stay apart: pressure.mjs decides when a clock roll is
due and what it means, and never rolls. That is what makes the skeleton seed an
honest promise rather than a half-truth.
paper/ holds the hand-written delve and both playtest logs. spike/ holds the
instrumented harness that measured the Forge outside Foundry.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>