const {test}=require('node:test'); const assert=require('node:assert/strict'); const {execute}=require('../.test-build/service.js'); const {seed}=require('../.test-build/seed.js'); const {runPopulationDirector}=require('../.test-build/world.js'); const {connectors}=require('../.test-build/connectors/index.js'); class Store { constructor(){this.state=seed();} async load(){return structuredClone(this.state);} async save(s,r){assert.equal(this.state.revision,r);s.revision=r+1;this.state=structuredClone(s);} } test('every seeded resident has a home or explicit housing state',()=>{ const state=seed(); for(const bot of state.bots){ assert.ok(bot.homeId,bot.name+' should have a home'); const home=state.homes.find(h=>h.id===bot.homeId); assert.ok(home,bot.name+' home should exist'); assert.ok(home.residentIds.includes(bot.id),bot.name+' should be registered as a resident'); } }); test('Zaku lives in Brill and has a hidden one HP plot armor floor',()=>{ const state=seed(); const zaku=state.bots.find(b=>b.id==='hero-zaku'); const home=state.homes.find(h=>h.id===zaku.homeId); assert.equal(home.zone,'Brill'); assert.equal(zaku.plotArmorHpFloor,1); assert.equal(zaku.simulationBand,'foreground'); assert.ok(zaku.memories.some(m=>/room in Brill/i.test(m.text))); }); test('population director prefers believable existing residents and creates no identities',()=>{ const state=seed(); const before=state.bots.length; const plan=runPopulationDirector(state,{id:'t1',kind:'zone-change',zone:'Duskwood',at:new Date().toISOString(),playerName:'Player'}); assert.ok(plan.requested>=0); assert.ok(plan.selectedBotIds.every(id=>state.bots.some(b=>b.id===id))); assert.equal(state.bots.length,before); }); test('world trigger activates existing residents without synthesizing new characters',async()=>{ const store=new Store(); const before=store.state.bots.length; await execute(store,{type:'worldTrigger',kind:'zone-change',zone:'Duskwood',playerName:'Player',detail:'Player entered the zone'}); assert.equal(store.state.bots.length,before); assert.ok(store.state.population.lastPlan); assert.equal(store.state.events.at(-1).kind,'population'); }); test('Zaku cannot be manually placed into hardcore death state',async()=>{ const store=new Store(); await assert.rejects( execute(store,{type:'recordDeath',botId:'hero-zaku',cause:'Test death',zone:'Duskwood',confirmed:true}), /plot armor/ ); const zaku=store.state.bots.find(b=>b.id==='hero-zaku'); assert.notEqual(zaku.status,'dead'); assert.equal(zaku.death,undefined); }); test('a bridge reporting Zaku dead is treated as a plot armor breach, never a death',async()=>{ const store=new Store(); const old=connectors.simulation; connectors.simulation=()=>({ health:async()=>({ok:true,detail:'test'}), lifecycle:async()=>{}, decide:async()=>({summary:'unused'}), observe:async()=>({zone:'Duskwood',level:12,summary:'bad bridge death',availableActions:['quest'],alive:false,death:{id:'bad-death',at:new Date().toISOString(),cause:'Combat',verified:true}}) }); try{ await assert.rejects(execute(store,{type:'think',botId:'hero-zaku'}),/Plot armor breach/); const zaku=store.state.bots.find(b=>b.id==='hero-zaku'); assert.notEqual(zaku.status,'dead'); assert.equal(zaku.death,undefined); }finally{connectors.simulation=old;} });