Files
vanity-delve/docs/drafts/NEW-FEATURES.md
T
slaguru666andClaude Opus 5 1ca0a64295 Stage the delve's own theme; show the foes that exist, not the plan
Two bugs, both of them the adapter drifting from what the core says.

PACK was a module global set once at boot to barrow. load() never
switched it and enter() read PACK.forgeStageType, so a port delve
authored at the desk staged barrow geometry — the fiction said quayside
and the map was a burial chamber. Fifteen of the sixteen themes, silently
wrong, on the path the module documents as its intended entry point. It
now resolves per call from d.params.theme, which is written from pack.id
at generation and so is always present and always right. Per call rather
than once at load, because a page reload resets the global while the
staged delve in world state survives; and before the folder is created,
so a bad theme fails without leaving anything behind.

The pack roster describes the encounter DELVE planned. The Forge takes no
cast — it rolls its own monsters from the heat — so the roster and the
actors in the world were never the same list, and both surfaces printed
the roster's stats as though they were. In several themes the roster also
carries "blessed, silvered or magical weapons ONLY", naming a Wraith that
was never created; the journal told the GM to say so before initiative.
Both surfaces now run off the actors that exist, read from the documents
themselves, and the plan is kept but labelled as the plan. The chat card
drops the immunity line entirely — it is the live surface and a false
immunity is worst there; the journal keeps it captioned, since a GM at
the desk may choose to cast the fight by hand.

Adds one core test for the contract the fix rests on: every delve records
the pack it came from, across all sixteen. The adapter itself has no test
harness — see the note in the commit for the release.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 23:41:31 +01:00

11 KiB
Raw Permalink Blame History

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:

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). Pressure, timerDue, telegraphDue, escalate, onPace and triggerNumber appear nowhere in foundry-module/. The only hit for "Pressure" is an <h3> 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) 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):

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/<id>/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.