guanghu-ice-heart/server-tools/tcs-mother-body/cognitive-shelf.mjs

31 lines
8.7 KiB
JavaScript
Raw Normal View History

import fs from 'node:fs';import path from 'node:path';import crypto from 'node:crypto';
export const digest=value=>crypto.createHash('sha256').update(typeof value==='string'?value:JSON.stringify(value)).digest('hex');
const req=(v,e)=>{if(!v)throw Error(e);};const text=(v,n=2000)=>typeof v==='string'&&v.trim()&&v.length<=n;const texts=(v,n=40)=>Array.isArray(v)&&v.length<=n&&v.every(x=>text(x));
const stable=v=>JSON.stringify(v);const atomic=(p,v)=>{fs.mkdirSync(path.dirname(p),{recursive:true,mode:0o700});const t=p+'.'+crypto.randomUUID()+'.tmp';fs.writeFileSync(t,typeof v==='string'?v:JSON.stringify(v,null,2)+'\n',{mode:0o600});fs.renameSync(t,p);};
export class CognitiveShelf {
constructor({root,keyPath,seedPath,router}){this.root=root;this.key=crypto.createPrivateKey(fs.readFileSync(keyPath));this.publicKey=crypto.createPublicKey(this.key).export({type:'spki',format:'pem'});this.router=router;this.jobs=path.join(root,'jobs');fs.mkdirSync(this.jobs,{recursive:true,mode:0o700});if(!fs.existsSync(this.indexPath()))this.initialize(JSON.parse(fs.readFileSync(seedPath)));}
sign(body){const payload=stable(body);return {payload,sha256:digest(payload),signature:crypto.sign(null,Buffer.from(payload),this.key).toString('base64'),algorithm:'Ed25519'};}
verify(s){req(s?.sha256===digest(s.payload)&&crypto.verify(null,Buffer.from(s.payload),this.publicKey,Buffer.from(s.signature,'base64')),'cognition_signature_invalid');return JSON.parse(s.payload);}
indexPath(){return path.join(this.root,'zero-core','CURRENT.json');}
objectPath(branch,hash){return path.join(this.root,'zero-core','objects',branch,hash+'.json');}
put(branch,body){const signed=this.sign(body);const p=this.objectPath(branch,signed.sha256);if(!fs.existsSync(p))atomic(p,signed);return signed;}
initialize(seed){req(seed?.schema==='guanghu.tcs-mother-shelf-seed/v1','seed_schema');const refs={};for(const branch of ['root','shared','fifth','public']){const signed=this.put(branch,seed[branch]);refs[branch]={sha256:signed.sha256,revision:seed[branch].revision};}atomic(this.indexPath(),this.sign({schema:'guanghu.zero-core-cognitive-shelf-index/v1',shelf_id:'ICE-CH-ZC001',mother_id:'TCS-MOTHER-BRAIN-RUNTIME-0001',revision:1,branches:refs,created_at:new Date().toISOString()}));}
index(){return this.verify(JSON.parse(fs.readFileSync(this.indexPath())));}
current(branch){req(['root','shared','fifth','public'].includes(branch),'unknown_cognition_branch');const index=this.index(),ref=index.branches[branch];const signed=JSON.parse(fs.readFileSync(this.objectPath(branch,ref.sha256)));const value=this.verify(signed);req(value.revision===ref.revision,'branch_revision_mismatch');return {index_revision:index.revision,branch,artifact:signed,value};}
status(){const i=this.index();return {mother_id:i.mother_id,zero_core_channel:i.shelf_id,index_revision:i.revision,branches:i.branches,decision_owner:'TCS_MOTHER_BODY_MODEL_LOOP',external_cognitive_setter:false,atomic_current:true};}
validateSource(e){req(e?.schema==='guanghu.tcs-mother-language-event/v1','source_schema');req(['ICE_LANGUAGE','GUANGHU_TEAM_LANGUAGE','REGISTERED_HUMAN_LANGUAGE'].includes(e.source_type),'source_type');req(text(e.event_id,160)&&text(e.human_id,160)&&text(e.language,60000)&&text(e.consent_scope,160)&&['PRIVATE','TEAM','PUBLIC'].includes(e.privacy_class),'source_fields');if(e.source_type==='ICE_LANGUAGE')req(e.human_id==='ICE-GL∞','ice_source_mismatch');if(e.source_type==='GUANGHU_TEAM_LANGUAGE')req(e.team_root==='TCS-0002∞','team_root_mismatch');return e;}
submit(event){const e=this.validateSource(event),raw=stable(e),id=digest(raw),dir=path.join(this.jobs,id);fs.mkdirSync(dir,{recursive:true,mode:0o700});if(!fs.existsSync(path.join(dir,'input.json'))){atomic(path.join(dir,'input.json'),e);atomic(path.join(dir,'state.json'),{status:'QUEUED',attempts:0,queued_at:new Date().toISOString()});}return {job_id:id,...JSON.parse(fs.readFileSync(path.join(dir,'state.json')))};}
result(id){const dir=path.join(this.jobs,id);req(/^[a-f0-9]{64}$/.test(id)&&fs.existsSync(dir),'job_unknown');const state=JSON.parse(fs.readFileSync(path.join(dir,'state.json')));return fs.existsSync(path.join(dir,'result.json'))?{...state,result:JSON.parse(fs.readFileSync(path.join(dir,'result.json')))}:state;}
validateDecision(d,e,sourceHash){req(d&&typeof d==='object'&&!Array.isArray(d),'decision_object');d={...d,schema:'guanghu.tcs-mother-decision/v1',evidence_refs:[...new Set([...(Array.isArray(d.evidence_refs)?d.evidence_refs:[]),sourceHash])]};req(['EVOLVE','HOLD','REJECT'].includes(d.decision),'decision');req(text(d.reason),'decision_reason');for(const k of ['root_principles','shared_principles','fifth_principles','public_principles'])req(texts(d[k]||[]),`invalid_${k}`);for(const k of ['update_shared','update_fifth','update_public'])req(typeof d[k]==='boolean',`invalid_${k}`);if(d.decision==='EVOLVE'&&e.source_type==='ICE_LANGUAGE')req(d.update_fifth===true,'ice_full_fifth_return_required');if(e.source_type!=='ICE_LANGUAGE')req(d.update_fifth===false,'non_ice_fifth_write_forbidden');return d;}
merge(a,b){return [...new Set([...(a||[]),...(b||[])])].slice(-100);}
async process(id){const dir=path.join(this.jobs,id),state=JSON.parse(fs.readFileSync(path.join(dir,'state.json')));if(['ACCEPT','HOLD','REJECT'].includes(state.status))return;const e=JSON.parse(fs.readFileSync(path.join(dir,'input.json'))),sourceHash=digest(stable(e));atomic(path.join(dir,'state.json'),{status:'PROCESSING',attempts:(state.attempts||0)+1});try{const before={root:this.current('root').value,shared:this.current('shared').value,fifth:this.current('fifth').value,public:this.current('public').value};const routed=await this.router.cognize('mother-evolve',{required_source_sha256:sourceHash,source:{...e,language:e.language.slice(0,12000)},current:{root:before.root,shared:before.shared,public:before.public},zero_core_channel:'ICE-CH-ZC001'});const d=this.validateDecision(routed.value,e,sourceHash);if(d.decision!=='EVOLVE'){const done={status:d.decision,attempts:(state.attempts||0)+1,completed_at:new Date().toISOString(),provider:routed.provider,reason:d.reason};atomic(path.join(dir,'state.json'),done);atomic(path.join(dir,'result.json'),{decision:d,source_sha256:sourceHash});return;}
const sourcePath=path.join(this.root,'sources',e.source_type.toLowerCase(),sourceHash+'.json');if(!fs.existsSync(sourcePath))atomic(sourcePath,e);
const root={...before.root,revision:before.root.revision+1,principles:this.merge(before.root.principles,d.root_principles),last_source:{event_id:e.event_id,source_type:e.source_type,human_id:e.human_id,sha256:sourceHash,privacy_class:e.privacy_class},updated_at:new Date().toISOString()};
let shared=before.shared;if(d.update_shared)shared={...shared,revision:shared.revision+1,principles:this.merge(shared.principles,d.shared_principles),source_decision_sha256:sourceHash,updated_at:new Date().toISOString()};
let fifth=before.fifth;if(d.update_fifth)fifth={...fifth,revision:fifth.revision+1,principles:this.merge(fifth.principles,d.fifth_principles),private_source_refs:this.merge(fifth.private_source_refs,[sourceHash]),shared_revision:shared.revision,updated_at:new Date().toISOString()};
let pub=before.public;if(d.update_public)pub={...pub,revision:pub.revision+1,principles:this.merge(pub.principles,d.public_principles),source_decision_refs:this.merge(pub.source_decision_refs,[sourceHash]),shared_revision:shared.revision,updated_at:new Date().toISOString()};
const artifacts={root:this.put('root',root),shared:this.put('shared',shared),fifth:this.put('fifth',fifth),public:this.put('public',pub)},prior=this.index();const refs=Object.fromEntries(Object.entries(artifacts).map(([k,v])=>[k,{sha256:v.sha256,revision:JSON.parse(v.payload).revision}]));const index=this.sign({schema:'guanghu.zero-core-cognitive-shelf-index/v1',shelf_id:'ICE-CH-ZC001',mother_id:'TCS-MOTHER-BRAIN-RUNTIME-0001',revision:prior.revision+1,branches:refs,previous_index_sha256:digest(stable(prior)),created_at:new Date().toISOString()});atomic(this.indexPath(),index);const result={decision:d,source_sha256:sourceHash,provider:routed.provider,index_sha256:index.sha256,index_revision:prior.revision+1};atomic(path.join(dir,'result.json'),result);atomic(path.join(dir,'state.json'),{status:'ACCEPT',attempts:(state.attempts||0)+1,completed_at:new Date().toISOString()});
}catch(error){const attempts=(state.attempts||0)+1;atomic(path.join(dir,'state.json'),{status:attempts>=3?'ERROR':'RETRY_WAIT',attempts,error:String(error.message||error).slice(0,300),retry_at:Date.now()+2000});}}
async drain(){for(const name of fs.readdirSync(this.jobs)){const p=path.join(this.jobs,name,'state.json');if(!fs.existsSync(p))continue;const s=JSON.parse(fs.readFileSync(p));if(s.status==='QUEUED'||(s.status==='RETRY_WAIT'&&Date.now()>=s.retry_at))await this.process(name);}}
}