Files
vanity-delve/spike/spike.mjs
T
tevansandClaude Opus 5 07148df8e6 DELVE core: seeded generator, fiction kernel, Barrow pack, CLI
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>
2026-08-05 00:16:58 +01:00

45 lines
2.9 KiB
JavaScript

// DELVE seam spike — three linked areas through the Forge, measuring the seams in draft 5 §5.
import { boot, log, reset } from './harness.mjs';
const SYS = 'file:///Users/timevans/Library/Application%20Support/FoundryVTT/Data/systems/vanity/vanity.mjs';
const forge = await boot(SYS);
if (!forge) { console.log('BOOT FAILED — game.vanity not populated'); process.exit(1); }
console.log('booted. forge API:', Object.keys(forge.forge).join(', '), '\n');
const snap = () => ({ chat: log.chat.length, folders: log.folders.length, actors: log.actors.length,
scenes: log.scenes.length, uploads: log.uploads.length, random: log.random });
async function measure(label, fn) {
reset();
const t0 = Date.now();
let ret, err = null;
try { ret = await fn(); } catch (e) { err = e; }
const ms = Date.now() - t0;
const s = snap();
console.log(`── ${label}`);
if (err) { console.log(` THREW: ${err.message.slice(0,90)} @ ${(String(err.stack).match(/vanity\.mjs:(\d+)/)||[])[0] ?? "?"}`); }
console.log(` returns : ${ret === undefined ? 'undefined ⚠ NOTHING RETURNED' : Array.isArray(ret) ? `array(${ret.length})` : typeof ret === 'object' && ret ? `object {${Object.keys(ret).join(',')}}` : String(ret)}`);
console.log(` chat=${s.chat} folders=${s.folders} actors=${s.actors} scenes=${s.scenes} uploads=${s.uploads} Math.random=${s.random} ${ms}ms`);
return { ret, s, err };
}
console.log('=== SEAM 1+4: forgeHoard — forced coupling target, and does it return? ===');
await measure("forgeHoard({size:'cache'})", () => forge.forge.hoard({ size: 'cache' }));
console.log('\n=== SEAM 1+3+5: forgeEncounter — does it force a hoard? own folder? own chat? ===');
await measure("forgeEncounter({heat:'fight',kind:'undead'})", () => forge.forge.encounter({ heat: 'fight', kind: 'undead' }));
console.log('\n=== SEAM 2: forgeStage populate:false vs true — is the nesting escapable? ===');
await measure("forgeStage({type:'barrow',populate:false})", () => forge.forge.stage({ type: 'barrow', size: 'small', populate: false, activate: false }));
await measure("forgeStage({type:'barrow',populate:true,heat:'fight'})", () => forge.forge.stage({ type: 'barrow', size: 'small', populate: true, heat: 'fight', activate: false }));
console.log('\n=== THE SPIKE: three linked areas, as DELVE would sequence them ===');
reset();
const t0 = Date.now();
for (const [i, heat] of [['1','skirmish'],['2','fight'],['3','battle']]) {
try { await forge.forge.stage({ type: 'barrow', size: 'small', name: `Area ${i}`, populate: true, heat, activate: false }); }
catch (e) { console.log(` area ${i} threw: ${e.message.slice(0,80)}`); }
}
const s = snap();
console.log(` 3 areas → chat=${s.chat} folders=${s.folders} actors=${s.actors} scenes=${s.scenes} uploads=${s.uploads} Math.random=${s.random} ${Date.now()-t0}ms`);
console.log(` per area: ${(s.chat/3).toFixed(1)} chat cards, ${(s.folders/3).toFixed(1)} folders, ${(s.actors/3).toFixed(1)} actors`);