Initial commit: Converge portfolio rationalization app
Next.js app for mapping a customer's competitive tool landscape onto our portfolio and building the consolidation business case: assessment workbench, customer report and Word export, product catalog, competitive knowledge base, dossier import, shareable landscape questionnaires with a review inbox, tool-footprint and business-unit value analysis, and an implementation timeline. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
48
scripts/test-kb-learning.mjs
Normal file
48
scripts/test-kb-learning.mjs
Normal file
@@ -0,0 +1,48 @@
|
||||
const B='http://127.0.0.1:3500';
|
||||
const get=(u)=>fetch(B+u).then(r=>r.json());
|
||||
const put=(u,b)=>fetch(B+u,{method:'PUT',headers:{'Content-Type':'application/json'},body:JSON.stringify(b)}).then(r=>r.json());
|
||||
let pass=0,fail=0; const t=(n,ok)=>{ok?(pass++,console.log(' PASS',n)):(fail++,console.log(' FAIL',n))};
|
||||
|
||||
const kb0 = await get('/api/knowledge-base');
|
||||
t('seeded KB loads', kb0.entries.length >= 630);
|
||||
|
||||
const f5 = kb0.entries.find(e=>e.label==='F5 BIG-IP');
|
||||
t('F5 BIG-IP pre-mapped to Avi', f5 && f5.productIds.includes('ans-avi'));
|
||||
t('seeded entry has no observations', f5.observations.length === 0);
|
||||
|
||||
// Save the seeded assessment -> should learn from its 10 candidates.
|
||||
const a = await get('/api/assessments/northwind-financial');
|
||||
await put('/api/assessments/northwind-financial', a);
|
||||
const kb1 = await get('/api/knowledge-base');
|
||||
|
||||
const learned = kb1.entries.filter(e=>e.observations.length>0);
|
||||
t('learned from all 10 candidates', learned.length === 10);
|
||||
|
||||
const splunk = kb1.entries.find(e=>e.label==='Splunk Enterprise');
|
||||
t('Splunk Enterprise captured', !!splunk);
|
||||
t('Splunk learned our real mapping', splunk.productIds.join()==='vcf-ops-logs,aod-dx-oi');
|
||||
t('Splunk learned switchEase 2', splunk.switchEase === 2);
|
||||
t('Splunk learned savingsPct 45', splunk.savingsPct === 45);
|
||||
t('Splunk learned risks text', /SOC dashboards/.test(splunk.risks));
|
||||
t('observation links back to assessment', splunk.observations[0].assessmentId === 'northwind-financial');
|
||||
|
||||
// Re-saving must update in place, not stack duplicates.
|
||||
await put('/api/assessments/northwind-financial', a);
|
||||
const kb2 = await get('/api/knowledge-base');
|
||||
const splunk2 = kb2.entries.find(e=>e.label==='Splunk Enterprise');
|
||||
t('re-save does not duplicate observations', splunk2.observations.length === 1);
|
||||
t('entry count stable after re-save', kb2.entries.length === kb1.entries.length);
|
||||
|
||||
// A pinned entry must survive learning untouched.
|
||||
const pinTarget = structuredClone(kb2);
|
||||
const p = pinTarget.entries.find(e=>e.label==='Splunk Enterprise');
|
||||
p.pinned = true; p.savingsPct = 99; p.switchEase = 5;
|
||||
await put('/api/knowledge-base', pinTarget);
|
||||
await put('/api/assessments/northwind-financial', a);
|
||||
const kb3 = await get('/api/knowledge-base');
|
||||
const splunk3 = kb3.entries.find(e=>e.label==='Splunk Enterprise');
|
||||
t('curated entry keeps savingsPct', splunk3.savingsPct === 99);
|
||||
t('curated entry keeps switchEase', splunk3.switchEase === 5);
|
||||
|
||||
console.log(`\n${pass} passed, ${fail} failed`);
|
||||
process.exit(fail?1:0);
|
||||
Reference in New Issue
Block a user