# DELVE — proposed features
*Draft 1, 2026-08-05. Against `316716e`, module v0.6.1, generator 0.2.0.*
*Ranked. Every "Evidence" line was verified in the source or by running the code, not recalled.*
---
## The gate
**DELVE has never been run at a live table.** Sixteen themes, 39 tests, six releases and two paper
playtests of a *hand-written* delve — but no session has ever used the generated article.
That fact sets the order below. Items 1–4 are things I can justify without a session, because they
are defects or they are measurement. Items 5–9 are things I would not start until a table has run
one delve, because a session will change what they should be. **The most valuable thing that could
happen to this project is four hours and four players, not another feature.**
---
# TIER 1 — defects wearing feature costumes
*These should land before anything new is built. Both are the same root cause.*
## 1. Wire the live Pressure engine to the table
**What.** The Foundry module should instantiate `Pressure` from the loaded delve and drive the
clock through it, instead of reimplementing a degenerate version inline.
**Why.** `pressure.mjs` is 130 lines that exist *because two playtests falsified the originals* —
escalation, telegraphing, and pace-checking were each added to fix a specific observed failure.
None of that reaches a table. The module's clock is:
```js
const fired = roll.total <= 1; // vanity-delve.mjs:147
```
A hardcoded 1. So:
- **Escalation never happens.** `Pressure.escalate()` widens the trigger from 1 to 2 if the clock
has not fired by the halfway area. Playtest 1's central failure was a clock that rolled 1-in-6
four times and never fired — the exact scenario escalation was written to prevent — and at the
table it still cannot fire.
- **The telegraph never fires.** `telegraphDue()` is never called, so the "voice a cue one Turn
ahead" rule is documentation only.
- **The timer never comes round.** `timerDue()` is never called. `st.turn` increments per area and
is otherwise unused.
- **Pace-checking is generation-only.** `onPace()` shapes which Bane beats get *planned*, but the
live tab (`st.tab`) never feeds back, so a table that banks Banes fast or slow changes nothing.
**Evidence.** The module imports exactly three core modules — `rng`, `authoring`, `forge-app`
([`vanity-delve.mjs:17-19`](../../foundry-module/module/vanity-delve.mjs)). `Pressure`,
`timerDue`, `telegraphDue`, `escalate`, `onPace` and `triggerNumber` appear **nowhere** in
`foundry-module/`. The only hit for "Pressure" is an `
` in the panel.
**Cost.** Small. `Pressure` is already pure and serialisable; the module already persists
`st.clock` and `st.tab` as world state. This is roughly: construct on load, replay the recorded
rolls, call `recordClock()` instead of comparing to a literal, and surface `triggerNumber` in the
card.
**Risk.** Low, but it changes live behaviour mid-campaign for anyone with a delve loaded. Needs a
state migration or a version check on the stored state blob.
**Done when.** A delve that reaches its halfway area without a clock firing shows "something comes
on 1–2" on the next card, and the escalation is visible to the GM.
## 2. Make the pressure setting mean something
**What.** Record the clock period in the delve file and derive the panel text from it.
**Why.** `slow` / `standard` / `hunted` is offered in the UI, stored in `lastParams`, and passed
into generation — and then discarded. `Pressure.summary()`
([`pressure.mjs:119`](../../core/pressure.mjs)) emits `turn`, `clockRolls`, `clockFired`,
`triggerNumber`, `escalated`, `tab` and `target` — **but not `period`**. So the one number the
setting controls never leaves the constructor.
**Evidence.** Generating the same seed at all three settings produces byte-identical pressure
blocks:
```
slow → {"turn":0,...,"triggerNumber":1,"escalated":false,"tab":6,"target":5}
standard → {"turn":0,...,"triggerNumber":1,"escalated":false,"tab":6,"target":5}
hunted → {"turn":0,...,"triggerNumber":1,"escalated":false,"tab":6,"target":5}
```
And the panel hardcodes the standard value regardless
([`forge-app.mjs:188`](../../foundry-module/module/forge-app.mjs)):
> `Roll 1d6 on any attention trigger, or every 3 Turns.`
A GM who picks `hunted` is told 3 Turns and gets 3 Turns.
**Cost.** Trivial — add `period` to `summary()`, read it in the panel. It is item 1's prerequisite
and probably the same commit.
**Risk.** None beyond item 1. Old delve files lack `period`; default to 3.
---
# TIER 2 — build steps designed but never started
## 3. The overlay catalog *(build step 5)*
**What.** A curated encounter catalog layered over the Forge's output, with per-entry theme,
faction, role, uniqueness — plus two fields that must be **tests, not tags**:
- **playability** — *can a hero with a mundane weapon damage this at all?*
- **survivability** — *can the party's weakest member survive one clean hit and two rounds of being
focused?*
**Why.** Both tests come from a corpse. The Wraith's immunity made a finale literally unwinnable; a
5d6 armour-ignoring attack that drains max Grit, against 3 Grit, is not a fight. DELVE currently
plans *heat* and hands composition to the Forge, so it cannot promise either property.
**Cost.** Large — it is authored content per theme plus a selection layer, and it interacts with
the roster data already in the packs.
**Risk.** This is the item most likely to be wrong before a live session. Heat may turn out to be
sufficient at a real table, in which case a curated catalog is a lot of authoring for a problem
that only appeared in simulation. **I would hold this until after the session.**
## 4. A Bane calibration harness
**What.** A pure-core simulator: run N delves against a modelled table, count Banes at the ending,
report the distribution. Then set `baneTarget` from data instead of intuition.
**Why.** The target has been marked **UNCALIBRATED** since draft 5. It is ~5; playtest 2 reached 3.
Every Bane-beat decision in `baneBeatFor()` keys off `onPace()`, which keys off that number — so an
uncalibrated target silently miscalibrates the whole tab engine.
**Cost.** Small, and it needs no Foundry and no table. This is the cheapest real answer available
right now.
**Risk.** A simulated table is not a table. The output is a *prior*, not a calibration, and should
be labelled as one — the same mistake as "6 areas: validated" would be easy to repeat here.
**Done when.** DESIGN.md can state a target with a measured distribution behind it, and open
question 4 either closes or gets sharper.
---
# TIER 3 — worth doing, but after a session
## 5. The play sheet as a Foundry surface
**What.** Render the play sheet in-world — a GM window carrying the current area's prose, the
decision, the numbers, and the live tab, instead of scrollback.
**Why.** The play sheet is currently CLI markdown only. At the table the GM card is *chat*, and
chat scrolls away. The whole two-surface design exists because table-facing material must be
scannable; a surface you have to scroll back through is not.
**Cost.** Medium. Renderer exists (`render-authoring.mjs`); this is a Foundry Application over it.
## 6. In-world authoring
**What.** Write the read-aloud, notes and title inside Foundry — the `authored` layer is already
the right shape for it.
**Why.** Today the only authoring path is the CLI, which means a GM who wants to fix one area's
prose leaves the VTT, edits JSON, and reloads. The module can already *detect* unfinished work
(`outstanding()` is exposed on `game.delve`) but offers no way to resolve it.
**Cost.** Medium. Needs a save-back path to `worlds//delves/`, which the module currently only
reads.
**Risk.** Two writers on one file. Needs a clear rule about which side owns the file.
## 7. A theme quality audit beyond Barrow
**What.** Read one generated delve per theme against the barrow benchmark, and add whatever
invariant each failure implies.
**Why.** Sixteen packs pass `validate-pack.mjs`, but validation is structural — it proves a pack
*can* fill six areas without repeating, not that the result is any good. Only barrow has ever been
read closely against a playtest. **A pack can pass every invariant and still be dull.**
**Cost.** Medium, and mostly reading rather than coding.
**Risk.** None. This is the item most likely to find something surprising per hour spent.
## 8. The growing delve map *(build step 7)*
**What.** A map that accumulates as areas are staged — the pointcrawl made visible.
**Why.** v1 is explicitly a pointcrawl and players will ask where they are.
**Cost.** Large. Browser-only by necessity (`forgeStage` needs `Image`/canvas/`XMLSerializer`), so
it cannot be tested in the CLI, which is where all 39 tests live.
**Risk.** High. This is the feature most likely to consume a week and produce something a GM
sketches better on paper. **I would want a session to ask for it before building it.**
## 9. Injectable RNG in the Forge → full replay
**What.** Thread a seeded RNG through VANITY's Forge so a seed replays the population too.
**Why.** It closes the honesty gap in the seed promise (§5 of the app draft).
**Cost.** Large and it is in the *other* repo — 36 `Math.random` sites across four helpers. It was
explicitly deferred as not gating a first release, and that judgment still looks right.
---
# TIER 4 — proposed and rejected
**More themes.** Sixteen is already more than has been validated at a table. Another family adds
authored content behind an unmeasured quality bar. **Stop until item 7 runs.**
**Multi-motif or two-faction delves.** The fiction model coheres *because* it has one root draw.
Two motifs is the most plausible way to break the thing that currently works best.
**Generated read-aloud prose.** Named in DESIGN.md as the one dishonest thing this tool could do.
Still true. The cue-fragment ceiling is the honest one.
**A balance guarantee.** Out of scope by design, and the overlay tests (item 3) are the correct
scoped version of this instinct.
---
## Suggested sequence
1. **Items 1 + 2** — one commit, small, fixes a rule that is documented but not running.
2. **Item 4** — cheap, no table needed, turns an admitted unknown into a number.
3. **Run a session.** Four hours, four players, one barrow delve, generated not hand-written.
4. **Item 7** while the session is fresh.
5. Re-rank 3, 5, 6, 8 against what the session actually showed. **I expect at least one of them to
look wrong afterwards, and I would rather find out which one before building it than after.**
## Where I am least confident
- **Item 3's priority.** I have ranked a designed-and-documented build step below a simulation
harness and a reading exercise. That is arguable, and the argument turns entirely on whether
heat-without-curation survives a real fight.
- **Whether items 5 and 6 are one feature.** A play-sheet window that cannot be edited may be half
a thing; shipping both at once may be the smaller total change.
- **The whole ranking assumes the session happens.** If it realistically will not happen soon, tier
3 should be reordered to whatever makes the tool most useful at the desk — probably 6, then 5.