| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849 |
- // Local in-memory validation of the two delivered inputs; no network or production access.
- import fs from 'node:fs';
- import crypto from 'node:crypto';
- import assert from 'node:assert/strict';
- import {createApplication} from '../server/src/core.mjs';
- import {runWorkshop} from '../skills/ksf-workshop-runtime/scripts/ksf-workshop.mjs';
- const data=JSON.parse(fs.readFileSync('server/references/runtime-data.json','utf8'));
- const rows={},copy=structuredClone;let seq=0;
- const store={
- async transaction(fn){const before=copy(rows);try{return await fn(this);}catch(e){for(const key of Object.keys(rows))delete rows[key];Object.assign(rows,before);throw e;}},
- async lock(){},
- async get(name,id){return copy(rows[name]?.find(r=>r.objectId===id)||null);},
- async list(name,{where={},afterId,limit=200}={}){return copy((rows[name]||[]).filter(r=>Object.entries(where).every(([key,v])=>JSON.stringify(r[key]??null)===JSON.stringify(v))).filter(r=>!afterId||r.objectId>afterId).sort((a,b)=>a.objectId.localeCompare(b.objectId)).slice(0,limit));},
- async create(name,fields){for(const key of Object.keys(fields))assert.ok(data.tables[name][key],name+'.'+key);const row={...copy(fields),objectId:'local'+String(++seq).padStart(7,'0'),createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()};(rows[name]??=[]).push(row);return copy(row);},
- async update(name,id,fields){for(const key of Object.keys(fields))assert.ok(data.tables[name][key],name+'.'+key);const row=rows[name]?.find(r=>r.objectId===id);assert.ok(row);Object.assign(row,copy(fields));return copy(row);}
- };
- const app=createApplication({store,crypto,Parse:{},data,settings:{signingSecret:'local-verification-only'},files:{}});
- const actor={id:'local-input-check',kind:'service',scopes:['source:write','data:read','ingest:write'],projectIds:['*']};
- const call=async(name,p)=>(await app.dispatch(name,JSON.parse(JSON.stringify(p)),actor)).data;
- const agentProfile={key:'agent-account:'+'a'.repeat(64),name:'本地输入校验夹具',role:'workshop',identityBasis:'runtime_config',runtimePlatform:'hermes',channel:'wecom',registeredAt:'2026-11-02T00:00:00Z',account:{platform:'wecom',accountId:'fixture-local-only'}};
- const checks=[];
- for(const key of ['suning','huajie']){
- const task=JSON.parse(fs.readFileSync('work/current-product-observations-20261102/'+key+'.input.json','utf8'));
- assert.equal(task.source.sourceKind,'ecommerce');assert.equal(task.source.dataMode,'live');assert.equal(task.source.collectedAt,null);
- assert.equal(task.records.length,1);const record=task.records[0];assert.equal(record.className,'KfEvidence');assert.equal(record.data.productRef,undefined);
- assert.equal(record.data.collectedAt,null);assert.equal(record.data.evidenceKind,'retailer_listing_observation');
- const locator=record.data.locator;
- assert.equal([...task.source.rawText].slice(locator.startCharacter,locator.endCharacter).join(''),record.data.quote);
- const preflight=await runWorkshop('workshop-dedup',task,{requestId:key+':preflight',call});
- assert.equal(preflight.readOnly,true);
- assert.equal((rows.KfSource??[]).length,key==='suning'?0:1,'preflight does not create a source');
- const result=await runWorkshop('workshop-import',task,{requestId:key+':import',agentProfile,call});
- assert.equal(result.status,'succeeded');assert.equal(result.items.length,1);assert.equal(result.counts.created,1);
- const source=await store.get('KfSource',result.sourceId),evidence=await store.get('KfEvidence',result.items[0].objectId);
- for(const [field,value]of Object.entries(task.source))assert.deepEqual(source[field],value,key+' source '+field);
- for(const [field,value]of Object.entries(record.data))assert.deepEqual(evidence[field],value,key+' evidence '+field);
- assert.equal(evidence.sourceRef.objectId,result.sourceId);assert.equal(evidence.productRef??null,null);
- const replay=structuredClone(task);replay.records[0].externalKey+=':local-reuse-check';
- const reused=await runWorkshop('workshop-import',replay,{requestId:key+':reuse-check',agentProfile,call});
- assert.equal(reused.sourceOperation,'unchanged');assert.equal(reused.counts.created,0);assert.equal(reused.counts.unchanged,1);
- assert.equal(reused.sourceId,result.sourceId);assert.equal(reused.items[0].objectId,result.items[0].objectId);
- checks.push({source:key,inputMatchesSchema:true,importAndReadback:true,quoteUnicodeLocatorMatched:true,unknownTimePreserved:true,duplicateReused:true});
- }
- assert.equal(rows.KfSource.length,2);assert.equal(rows.KfEvidence.length,2);
- for(const name of ['KfCategory','KfProduct','KfSession','KfArtifact','KfProject','KfConcept'])assert.equal((rows[name]??[]).length,0,name);
- const result={ok:true,operation:'page-observation-inputs-validated-locally',at:new Date().toISOString(),scope:'in-memory real backend and workshop wrapper; not production',checks,networkRequests:0,productionBusinessWrites:0,localSourceCount:2,localEvidenceCount:2,localProductCount:0,localReportCount:0};
- fs.writeFileSync('work/current-product-observation-inputs-verified-20261102.json',JSON.stringify(result,null,2)+'\n');
- console.log(JSON.stringify(result,null,2));
|