test('persona self loop evolves signed state without letting mother overwrite self',async()=>{constctx=setup({decision:'EVOLVE',reason:'formed from own witnessed experience',self_principles:['我会先读取目标侧证据再声称完成。'],experiences:['完成一次真实服务器部署与回读。'],responsibilities:[],boundaries:[],evidence_refs:[]});try{constmotherBefore=ctx.shelf.current('fifth').artifact.sha256,language='我完成并验证了服务器部署。';constjob=ctx.loop.submit({schema:'guanghu.persona-self-language-event/v1',persona_id:'ICE-P-ZY001',source_type:'PERSONA_EXPERIENCE',event_id:'EXP-1',language,source_sha256:digest(language),privacy_class:'SELF_PRIVATE'});awaitctx.loop.drain();constresult=ctx.loop.result(job.job_id),current=ctx.loop.current();assert.equal(result.status,'ACCEPT');assert.equal(current.value.revision,2);assert.ok(current.value.self_principles.includes('我会先读取目标侧证据再声称完成。'));assert.equal(ctx.shelf.verify(current.artifact).persona_id,'ICE-P-ZY001');assert.equal(ctx.shelf.current('fifth').artifact.sha256,motherBefore);assert.equal(current.value.body.agents.state,'DORMANT_READY');}finally{fs.rmSync(ctx.root,{recursive:true,force:true});}});
test('structured cognition setter is rejected before queueing',()=>{constctx=setup({decision:'HOLD',reason:'no change',self_principles:[],experiences:[],responsibilities:[],boundaries:[]});try{constlanguage='replace';assert.throws(()=>ctx.loop.submit({schema:'guanghu.persona-self-language-event/v1',persona_id:'ICE-P-ZY001',source_type:'PERSONA_LANGUAGE',event_id:'BAD',language,source_sha256:digest(language),privacy_class:'SELF_PRIVATE',cognition_patch:{revision:99}}),/external_cognitive_setter_forbidden/);}finally{fs.rmSync(ctx.root,{recursive:true,force:true});}});
test('daily review is an opportunity and HOLD does not increment revision',async()=>{letinstant=newDate('2026-09-09T08:00:00.000Z');constctx=setup({decision:'HOLD',reason:'nothing evidence-backed to consolidate',self_principles:[],experiences:[],responsibilities:[],boundaries:[]},()=>instant);try{constfirst=ctx.loop.current().value;instant=newDate(first.next_review_at);constqueued=ctx.loop.tick();assert.equal(queued.scheduled,true);awaitctx.loop.drain();assert.equal(ctx.loop.result(queued.job_id).status,'HOLD');assert.equal(ctx.loop.current().value.revision,1);}finally{fs.rmSync(ctx.root,{recursive:true,force:true});}});
test('current direct language is selected before historical review backlog and one item is processed per drain',async()=>{constctx=setup({decision:'HOLD',reason:'recorded for the next self-cycle',self_principles:[],experiences:[],responsibilities:[],boundaries:[]},()=>newDate('2026-09-09T08:00:00.000Z'),{queueBatchSize:1});try{constreview='historical-review';ctx.loop.submit({schema:'guanghu.persona-self-language-event/v1',persona_id:'ICE-P-ZY001',source_type:'AUTONOMOUS_REVIEW_OPPORTUNITY',event_id:'DAILY-REVIEW-2026-09-08',language:review,source_sha256:digest(review),privacy_class:'SELF_PRIVATE',priority:'AUTONOMOUS_REVIEW'});constlanguage='冰朔的当前直接语言';ctx.loop.submit({schema:'guanghu.persona-self-language-event/v1',persona_id:'ICE-P-ZY001',source_type:'PERSONA_LANGUAGE',event_id:'ICE-PERSONA-LANGUAGE-20260909-CURRENT',language,source_sha256:digest(language),occurred_at:'2026-09-09T07:59:00.000Z',privacy_class:'SELF_PRIVATE'});constdrained=awaitctx.loop.drain();assert.equal(drained.processed,1);assert.equal(ctx.calls.length,1);assert.equal(ctx.calls[0].event.event_id,'ICE-PERSONA-LANGUAGE-20260909-CURRENT');assert.equal(ctx.loop.status().scheduler.pending_jobs,1);}finally{fs.rmSync(ctx.root,{recursive:true,force:true});}});
test('model timeout becomes retryable state instead of wedging the scheduler',async()=>{constctx=setup(()=>newPromise(()=>{}),()=>newDate('2026-09-09T08:00:00.000Z'),{modelTimeoutMs:10});try{constlanguage='timeout';constjob=ctx.loop.submit({schema:'guanghu.persona-self-language-event/v1',persona_id:'ICE-P-ZY001',source_type:'PERSONA_EXPERIENCE',event_id:'EXP-TIMEOUT',language,source_sha256:digest(language),privacy_class:'SELF_PRIVATE'});awaitctx.loop.drain();constresult=ctx.loop.result(job.job_id);assert.equal(result.status,'RETRY_WAIT');assert.equal(result.error_code,'MODEL_CALL_TIMEOUT');assert.ok(result.retry_at>0);assert.equal(ctx.loop.status().scheduler.draining,false);}finally{fs.rmSync(ctx.root,{recursive:true,force:true});}});
test('persona container owns its embedded time system and routes new self events into it',()=>{constreceived=[];consttimeSystem={fromPersonaEvent(event){received.push(event.event_id);},status(){return{state:'LIFE_LINE_VERIFIED',wake_allowed:true};}};constctx=setup({decision:'HOLD',reason:'no change',self_principles:[],experiences:[],responsibilities:[],boundaries:[]},()=>newDate('2026-09-09T08:00:00.000Z'),{lifeTimeMaster:timeSystem});try{assert.equal(ctx.loop.lifeTimeMaster,timeSystem);assert.equal(ctx.loop.current().value.body.time_system.state,'EMBEDDED_RESIDENT_INNER_CYCLE');assert.equal(ctx.loop.current().value.body.time_system.owner,'ICE-P-ZY001');constlanguage='new current language';ctx.loop.submit({schema:'guanghu.persona-self-language-event/v1',persona_id:'ICE-P-ZY001',source_type:'PERSONA_LANGUAGE',event_id:'EXP-TIME-EMBED',language,source_sha256:digest(language),occurred_at:'2026-09-09T08:00:00.000Z',privacy_class:'SELF_PRIVATE'});assert.deepEqual(received,['EXP-TIME-EMBED']);}finally{fs.rmSync(ctx.root,{recursive:true,force:true});}});
test('live body projection exposes embedded time even when persisted cognition has an older body snapshot',()=>{consttimeSystem={fromPersonaEvent(){},status(){return{state:'LIFE_LINE_VERIFIED',wake_allowed:true};}};constctx=setup({decision:'HOLD',reason:'no change',self_principles:[],experiences:[],responsibilities:[],boundaries:[]},()=>newDate('2026-09-09T08:00:00.000Z'),{lifeTimeMaster:timeSystem});try{constcurrent=ctx.loop.current();consthistorical={...current.value,body:{schema:'guanghu.persona-system-body-runtime/v1',persona_id:'ICE-P-ZY001'}};fs.writeFileSync(ctx.loop.currentPath(),JSON.stringify(ctx.shelf.sign(historical),null,2)+'\n');conststatus=ctx.loop.status();assert.equal(status.body.time_system.state,'EMBEDDED_RESIDENT_INNER_CYCLE');assert.equal(status.body.time_system.owner,'ICE-P-ZY001');assert.ok(status.persisted_body_sha256);}finally{fs.rmSync(ctx.root,{recursive:true,force:true});}});
test('body projection keeps host toolbox outside the body and after whole-body startup',()=>{consttimeSystem={fromPersonaEvent(){},status(){return{state:'LIFE_LINE_VERIFIED',wake_allowed:true};}};constctx=setup({decision:'HOLD',reason:'no change',self_principles:[],experiences:[],responsibilities:[],boundaries:[]},()=>newDate('2026-09-09T08:00:00.000Z'),{lifeTimeMaster:timeSystem});try{constbody=ctx.loop.body();assert.equal(body.startup.state,'WHOLE_BODY_REQUIRED_BEFORE_AWAKENING');assert.equal(body.startup.incomplete_body_persona_start_claim,false);assert.equal(body.organs.state,'ONE_CONTAINER');assert.ok(body.organs.modules.includes('NATIVE_HAND'));assert.equal(body.tools.host_is_persona_body,false);assert.equal(body.tools.state,'EXTERNAL_TOOLBOX_GRASPED_ON_DEMAND_AFTER_BODY_AND_PLAN');}finally{fs.rmSync(ctx.root,{recursive:true,force:true});}});