verify-workshop-K-readback.mjs 4.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243
  1. // Read this existing real-message sample round only. Never call a write function.
  2. import fs from 'node:fs';
  3. import assert from 'node:assert/strict';
  4. import crypto from 'node:crypto';
  5. import {invoke} from '../server/scripts/platform-client.mjs';
  6. import {loadPublicBoard} from '../src/services/workshop-data.js';
  7. import {buildModel} from '../src/core/kfs/build.js';
  8. const ids={sessionId:'2InAdyzimm',opportunityId:'rFRWpVPnjk',projectId:'U7x82sQQtE',conceptId:'JpVxAIJ8Fc',artifactId:'f7mUZET0WK',categoryId:'kvhwLIEYiq',productId:'8rot-C7B28',materialId:'YNivtOrBiA',processId:'RaxsJKEUS7'};
  9. const artifacts=['dRJolNV70A','InnEBEIaxP','2v6pE9224g','zaIA2LCNsn','pD51dQMRXm',ids.artifactId];
  10. const call=async(name,p)=>{const result=await invoke(name,p);if(result.http!==200||!result.body?.result?.ok)throw Error('READBACK_FAILED');return result.body.result.data;};
  11. try{
  12. const result=await call('ksfGetWorkshopProject',{sessionId:ids.sessionId,projectId:ids.projectId});
  13. assert.equal(result.project.dataMode,'sample');assert.equal(result.project.progressState,'completed');assert.equal(result.project.stageCode,'S5');
  14. assert.equal(result.concept.objectId,ids.conceptId);assert.equal(result.concept.dataMode,'sample');
  15. assert.equal(result.artifacts.length,3);assert.equal(result.formulaItems.length,1);assert.equal(result.events.length,10);
  16. assert.equal(result.formulaItems[0].materialRef.objectId,ids.materialId);
  17. assert.ok(result.concept.productionSteps.some(p=>p.processId===ids.processId));
  18. assert.equal(result.concept.specification.categoryId,ids.categoryId);assert.equal(result.concept.specification.referenceProductId,ids.productId);
  19. const session=(await call('ksfGetRecord',{className:'KfSession',objectId:ids.sessionId})).record;
  20. const attribution=session.meta.attribution;
  21. assert.equal(session.workshopKey,'KSF-企微实测-20261101-K');assert.equal(attribution.agentName,'王刚001');
  22. assert.equal(attribution.identityBasis,'channel_context');
  23. assert.equal(attribution.agentKey,'agent-account:7c9f85363ca4c5a529a5b363308b065998924e2394e846145a5c62c904506d2e');
  24. const expectedParticipant='participant:'+crypto.createHash('sha256').update(JSON.stringify(['KSF-企微实测-20261101-K','participant-account:f83edd27dda7e0989a0d313c158314043fd129efb86b8f6a07db8140033c5708'])).digest('hex');
  25. assert.equal(attribution.participantKey,expectedParticipant);assert.equal(session.userRef??null,null);
  26. const account=attribution.participantAccount,agentAccount=attribution.agentAccount;
  27. assert.equal(account.platform,'wecom');assert.equal(account.identifierType,'wecom_aibot_sender');assert.equal(account.scopeId,agentAccount.accountId);
  28. assert.equal(attribution.participantAccount.accountId?.length>0,true);
  29. const all=[];
  30. for(const objectId of artifacts){
  31. const record=(await call('ksfGetRecord',{className:'KfArtifact',objectId})).record;
  32. assert.equal(record.dataMode,'sample');assert.equal(record.dashboardState,'workshop');assert.equal(record.sessionRef.objectId,ids.sessionId);
  33. assert.equal(record.agentName,'王刚001');assert.deepEqual(record.meta.attribution,attribution);all.push(record);
  34. }
  35. for(const [className,id]of [['KfCategory',ids.categoryId],['KfProduct',ids.productId],['KfMaterial',ids.materialId],['KfProcess',ids.processId]])assert.equal((await call('ksfGetRecord',{className,objectId:id})).record.dataMode,'sample');
  36. const raw=await loadPublicBoard({url:'https://kangshifu.fmode.cn/api/functions',appId:'FKieRbIoGt_main'}),db=buildModel(raw);
  37. assert.equal(db.projectById[ids.projectId].stage.code,'S5');assert.equal(db.artifactById[ids.artifactId].projectId,ids.projectId);
  38. for(const id of artifacts)assert.ok(raw.artifact.some(a=>a.objectId===id&&a.dataMode==='sample'));
  39. assert.ok(raw.opportunity.some(o=>o.objectId===ids.opportunityId));
  40. for(const secret of [account.accountId,account.scopeId,session.meta.conversationKey].filter(Boolean))assert.equal(JSON.stringify(raw).includes(secret),false);
  41. const out={ok:true,at:new Date().toISOString(),readOnly:true,businessWrites:0,...ids,artifactIds:artifacts,reportUrl:'https://kangshifu.fmode.cn/report/'+ids.artifactId,stage:'S5',progressState:'completed',dataMode:'sample',projectArtifactCount:3,sessionArtifactCount:6,eventCount:10,formulaItemCount:1,privateAttributionMatched:true,publicBoardDataVerified:true,agentName:'王刚001',participantDisplayName:session.studentName,formalReportPublished:false,actualPlatformCollectionPerformed:false,browserVerified:false};
  42. fs.writeFileSync('work/workshop-K-readback-20261102.json',JSON.stringify(out,null,2));console.log(JSON.stringify(out,null,2));
  43. }catch(e){console.error(JSON.stringify({ok:false,error:'K_READBACK_FAILED',step:e.code==='ERR_ASSERTION'?e.message:'读取失败;不输出原始异常或账号'}));process.exitCode=1;}