| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899 |
- // Independently inspect existing records. Only GETs and ksfGetRecord are allowed here.
- import fs from 'node:fs';
- import crypto from 'node:crypto';
- import assert from 'node:assert/strict';
- import {invoke,classRows} from '../server/scripts/platform-client.mjs';
- const taskKey='KSF-商品页面观察-20261102-01';
- const agentKey='agent-account:7c9f85363ca4c5a529a5b363308b065998924e2394e846145a5c62c904506d2e';
- const inputsDirectory='work/current-product-observations-20261102/';
- const archiveFile='work/current-product-archive-20261102.zip';
- const expectedArchive='0ec14dcccbce26bc0fc1a368bfaef4bbc32ea6f0b651ae31df5dd28a8bc0e7a5';
- const imported=[
- {key:'suning',sourceId:'pBQEl6tlfY',evidenceId:'cTo8j9FdIJ',jobId:'QF1TFQG7bY'},
- {key:'huajie',sourceId:'yo2mA_FByU',evidenceId:'dU0wGRdC0D',jobId:'RQoaUYKU8l'},
- ];
- const ptr=(className,objectId)=>({__type:'Pointer',className,objectId});
- const sha=bytes=>crypto.createHash('sha256').update(bytes).digest('hex');
- const read=async(className,objectId)=>{
- const r=await invoke('ksfGetRecord',{className,objectId});
- assert.equal(r.http,200);assert.equal(r.body?.result?.ok,true);
- return r.body.result.data.record;
- };
- let check='local archive';
- try{
- const archive=fs.readFileSync(archiveFile);
- assert.equal(archive.length,614046);assert.equal(sha(archive),expectedArchive);
- const packageReceipt=JSON.parse(fs.readFileSync('work/current-product-observations-package-receipt.json','utf8'));
- const reports=[];
- for(const ids of imported){
- check=ids.key+' records';
- const inputBytes=fs.readFileSync(inputsDirectory+ids.key+'.input.json');
- assert.equal(sha(inputBytes),packageReceipt.inputHashes[ids.key+'.input.json']);
- const input=JSON.parse(inputBytes),row=input.records[0];
- const [source,evidence,job]=await Promise.all([
- read('KfSource',ids.sourceId),read('KfEvidence',ids.evidenceId),read('KfImportJob',ids.jobId),
- ]);
- for(const [field,value]of Object.entries(input.source))assert.deepEqual(source[field]??null,value,ids.key+' source '+field);
- assert.equal(source.contentHash,sha(input.source.rawText));
- assert.equal(source.recordState,'active');
- for(const [field,value]of Object.entries(row.data))assert.deepEqual(evidence[field]??null,value,ids.key+' evidence '+field);
- assert.deepEqual(evidence.sourceRef,ptr('KfSource',ids.sourceId));
- assert.equal(evidence.productRef??null,null);assert.equal(evidence.artifactRef??null,null);
- assert.equal(evidence.recordState,'active');
- assert.equal(evidence.evidenceKind,'retailer_listing_observation');
- assert.equal(evidence.verificationState,'archived_text_and_screenshot_checked');
- assert.equal(evidence.collectedAt??null,null);assert.equal(source.collectedAt??null,null);
- assert.equal(evidence.locator.archiveSha256,sha(archive));
- for(const file of [evidence.locator.textOrigin,evidence.locator.screenshot]){
- assert.equal(sha(fs.readFileSync('work/current-product-archive-20261102/originals/'+file.file)),file.sha256);
- }
- const locator=evidence.locator;
- assert.equal([...source.rawText].slice(locator.startCharacter,locator.endCharacter).join(''),evidence.quote);
- assert.equal(locator.exactCaptureTimestampVerified,false);
- assert.equal(job.status,'succeeded');assert.equal(job.expectedCount,1);assert.equal(job.successCount,1);assert.equal(job.failureCount,0);
- assert.deepEqual(job.inputSourceRef,ptr('KfSource',ids.sourceId));
- assert.equal(job.producer.agent.key,agentKey);assert.equal(job.producer.agent.name,'王刚001');
- check=ids.key+' uniqueness and scope';
- const [sources,evidences,jobs,items,products,artifacts]=await Promise.all([
- classRows('KfSource',{contentHash:source.contentHash,sourceUrl:source.sourceUrl,platform:source.platform,dataMode:'live',recordState:'active'}),
- classRows('KfEvidence',{sourceRef:ptr('KfSource',ids.sourceId)}),
- classRows('KfImportJob',{inputSourceRef:ptr('KfSource',ids.sourceId)}),
- classRows('KfImportItem',{jobRef:ptr('KfImportJob',ids.jobId)}),
- classRows('KfProduct',{sourceRef:ptr('KfSource',ids.sourceId)}),
- classRows('KfArtifact',{sourceRef:ptr('KfSource',ids.sourceId)}),
- ]);
- assert.deepEqual(sources.map(x=>x.objectId),[ids.sourceId]);
- assert.deepEqual(evidences.map(x=>x.objectId),[ids.evidenceId]);
- assert.deepEqual(jobs.map(x=>x.objectId),[ids.jobId]);
- assert.equal(items.length,1);assert.equal(items[0].targetClass,'KfEvidence');
- assert.equal(items[0].targetId,ids.evidenceId);assert.equal(items[0].itemKey,row.itemKey);
- assert.equal(items[0].businessKey,row.externalKey);assert.equal(items[0].status,'succeeded');assert.equal(items[0].operation,'created');
- assert.equal(products.length,0);assert.equal(artifacts.length,0);
- reports.push({...ids,sourceOperation:'created',created:1,unchanged:0,sourceMatchesFixedInput:true,evidenceMatchesFixedInput:true,
- quoteAndUnicodeLocatorMatched:true,archiveHashAndOriginalHashesVerified:true,exactCaptureTimePreservedUnknown:true,
- evidenceKind:evidence.evidenceKind,verificationState:evidence.verificationState,locatorFieldCount:Object.keys(locator).length,
- duplicateSourceCount:sources.length,sourceProductCount:products.length,sourceArtifactCount:artifacts.length,sameAgent:true});
- }
- check='original S1';
- const [artifact,versions]=await Promise.all([
- read('KfArtifact','G8IrkkDG7X'),classRows('KfArtifact',{reportSeriesKey:'KSF-真实资料-20261102-01:S1'}),
- ]);
- const template=JSON.parse(fs.readFileSync('work/first-live-S1-v2-template.json','utf8'));
- for(const field of ['rawText','version','stageCode','title'])assert.deepEqual(artifact[field],template[field]);
- assert.deepEqual(artifact.report.evidence,template.report.evidence);
- assert.deepEqual(artifact.meta.workshop.sourceIds,template.sourceIds);
- assert.deepEqual(versions.map(x=>[x.objectId,x.version]).sort((a,b)=>a[1]-b[1]),[['cOm6c8gg7z',1],['G8IrkkDG7X',2]]);
- const result={ok:true,operation:'page-observations-independently-verified',at:new Date().toISOString(),taskKey,readOnly:true,businessWrites:0,
- dataMode:'live',sourceCount:2,evidenceCount:2,newProductsFromTheseSources:0,newArtifactsFromTheseSources:0,imports:reports,
- archive:{sha256:expectedArchive,bytes:archive.length,verifiedLocalPath:'F:/kangshifu-board/'+archiveFile,remoteArchivePackageAvailability:'not independently verified'},
- originalS1Preserved:true,originalS1ArtifactId:'G8IrkkDG7X',formalReportPublished:false,
- currentStockVerified:false,unitPriceVerified:false,consumerReviewsCollected:false,huajieCurrencyVerified:false};
- fs.writeFileSync('work/page-observations-readback-20261102.json',JSON.stringify(result,null,2)+'\n');
- console.log(JSON.stringify(result,null,2));
- }catch(e){
- const result={ok:false,operation:'page-observations-independent-readback-stopped',check,errorCode:'PAGE_OBSERVATIONS_READBACK_FAILED',
- checkLine:e.stack?.match(/verify-page-observations-readback\.mjs:(\d+):/)?.[1]??null,readOnly:true,businessWrites:0};
- fs.writeFileSync('work/page-observations-readback-20261102.json',JSON.stringify(result,null,2)+'\n');
- console.error(JSON.stringify(result,null,2));process.exitCode=1;
- }
|