// Read-only verification of the completed sample run; never replays either import. import fs from 'node:fs'; import assert from 'node:assert/strict'; import crypto from 'node:crypto'; import {request,classRows} from '../server/scripts/platform-client.mjs'; import {TASK_KEY,dedupTask} from './workshop-dedup-acceptance.mjs'; const sourceId='V6AS9Qf10d',materialId='SGOF-c5vTo'; const rounds=[ {round:'batch-a',jobId:'2MDXH_CzC5',operation:'created',created:1,unchanged:0,externalKey:TASK_KEY+':material:a',invocationId:'d23c55cc-bea2-4fb6-99a7-df53aca5d8e1',entryInvocationId:'fc6eb96b-6bd7-4aab-96f9-e54cd139d742'}, {round:'batch-b',jobId:'L68OPSHuXW',operation:'unchanged',created:0,unchanged:1,externalKey:TASK_KEY+':material:b',invocationId:'4f984682-6fa7-4696-b29b-b7eb04026676',entryInvocationId:'df418c3a-fbf0-44c1-9b0f-b030b38e01b3'} ]; const pointer=(className,objectId)=>({__type:'Pointer',className,objectId}); const get=(className,id)=>request('GET','/classes/'+className+'/'+encodeURIComponent(id)); try{ const task=dedupTask('a'),contentHash=crypto.createHash('sha256').update(task.source.rawText).digest('hex'); const [source,material,sources,materials,jobs]=await Promise.all([ get('KfSource',sourceId),get('KfMaterial',materialId), classRows('KfSource',{contentHash}),classRows('KfMaterial',{name:task.records[0].data.name}), classRows('KfImportJob',{jobKey:{$regex:TASK_KEY}}) ]); assert.equal(source.objectId,sourceId);assert.equal(material.objectId,materialId); for(const [k,v]of Object.entries(task.source))assert.deepEqual(source[k],v); assert.equal(source.contentHash,contentHash); for(const [k,v]of Object.entries(task.records[0].data))assert.deepEqual(material[k],v); assert.deepEqual(material.sourceRef,pointer('KfSource',sourceId)); assert.equal(sources.length,1);assert.equal(sources[0].objectId,sourceId); assert.equal(materials.length,1);assert.equal(materials[0].objectId,materialId); assert.equal(material.externalKey,rounds[0].externalKey,'reuse preserves original business key'); assert.equal(jobs.length,2);assert.deepEqual(jobs.map(j=>j.objectId).sort(),rounds.map(r=>r.jobId).sort()); const result=[]; for(const round of rounds){ const job=jobs.find(j=>j.objectId===round.jobId),items=await classRows('KfImportItem',{jobRef:pointer('KfImportJob',round.jobId)}); assert.equal(job.status,'succeeded');assert.equal(job.expectedCount,1);assert.equal(job.successCount,1);assert.equal(job.failureCount,0); assert.ok(job.jobKey.endsWith(':'+TASK_KEY+':'+round.round+':item:material')); assert.deepEqual(job.inputSourceRef,pointer('KfSource',sourceId)); const counts=JSON.parse(job.summary).counts; assert.equal(counts.created,round.created);assert.equal(counts.unchanged,round.unchanged); assert.equal(counts.updated,0);assert.equal(counts.failed,0); assert.equal(items.length,1);const item=items[0]; assert.equal(item.itemKey,'material');assert.equal(item.targetClass,'KfMaterial');assert.equal(item.targetId,materialId); assert.equal(item.status,'succeeded');assert.equal(item.operation,round.operation);assert.equal(item.businessKey,round.externalKey); result.push({round:round.round,jobId:round.jobId,sourceId,materialId,created:counts.created,unchanged:counts.unchanged,operation:item.operation}); } assert.deepEqual(jobs[0].producer.agent,jobs[1].producer.agent); assert.equal(jobs[0].producer.agent.key,'agent-account:7c9f85363ca4c5a529a5b363308b065998924e2394e846145a5c62c904506d2e'); const receipt={ok:true,operation:'sample-material-dedup-independently-verified',at:new Date().toISOString(),readOnly:true,businessWrites:0,taskKey:TASK_KEY,sourceId,materialId,rounds:result,exactSourceMatches:sources.length,exactMaterialMatches:materials.length,importJobCount:jobs.length,importItemCount:2,originalMaterialBusinessKeyPreserved:true,sameAgentAttribution:true,dataMode:'sample',actualPlatformCollectionPerformed:false,formalReportPublished:false,invocationEvidence:{basis:'user-forwarded-tool-receipts; IDs not independently authenticated by database',rounds:rounds.map(({round,invocationId,entryInvocationId})=>({round,invocationId,entryInvocationId}))}}; fs.writeFileSync('work/dedup-acceptance-readback-20261102.json',JSON.stringify(receipt,null,2)); console.log(JSON.stringify(receipt,null,2)); }catch{ console.error(JSON.stringify({ok:false,error:'DEDUP_READBACK_FAILED',message:'只读核验未通过;未输出原始异常、账号或凭据。'})); process.exitCode=1; }