Files
KArtSell.Aegis/docs/Design/kbx-foundation-v36/scripts/validate-telemetry-governance.mjs
T

26 lines
2.8 KiB
JavaScript

import fs from 'node:fs'
import path from 'node:path'
import { spawnSync } from 'node:child_process'
const gen=spawnSync(process.execPath,['scripts/generate-telemetry-contracts.mjs'],{stdio:'inherit'});if(gen.status!==0)process.exit(gen.status??1)
const manifest=JSON.parse(fs.readFileSync('generated/telemetry-manifest.json','utf8'))
const source=JSON.parse(fs.readFileSync('contracts/telemetry/kbx.telemetry.json','utf8'))
const errors=[]
if(manifest.events.length<20)errors.push('telemetry catalog unexpectedly small')
if(!manifest.metrics.some(x=>x.key==='manual_intervention_rate'))errors.push('Manual Intervention Rate metric missing')
if(source.principles.noSensitiveData!==true||source.principles.noRawBusinessData!==true)errors.push('privacy principles must prohibit sensitive/raw business data')
const forbidden=/(phone|address|name|orderNo|customer|itemCode|barcode|keyword|query|email|entityId)/i
for(const e of manifest.events)for(const a of e.allowedAttributes??[])if(forbidden.test(a))errors.push(`forbidden telemetry attribute: ${e.name}.${a}`)
for(const e of manifest.events.filter(x=>x.requiresDuration))if(!['task.complete','task.abandon','command.succeeded','command.failed','excel.import.completed','excel.import.failed','exception.resolved'].includes(e.name))errors.push(`review duration event: ${e.name}`)
const migration=fs.readFileSync('backend/Database/Migrations/20260808_011_kbx_ux_telemetry.sql','utf8')
for(const table of ['kbx.ux_events','kbx.ux_business_outcomes'])if(!migration.includes(table))errors.push(`migration missing ${table}`)
const appFiles=[]
function walk(d){for(const e of fs.readdirSync(d,{withFileTypes:true})){const p=path.join(d,e.name);e.isDirectory()?walk(p):appFiles.push(p)}}walk('apps/web/src')
for(const file of appFiles.filter(x=>/\.(ts|vue)$/.test(x))){const text=fs.readFileSync(file,'utf8');if(/kbxTelemetry\.track\([^'\"]/.test(text))errors.push(`${file}: dynamic telemetry event names are forbidden`)}
const ts=fs.readFileSync('packages/kbx-contracts/src/generated/telemetryCatalog.ts','utf8'),cs=fs.readFileSync('backend/Shared/Telemetry/Generated/KbxTelemetryCatalog.g.cs','utf8')
const tsha=ts.match(/kbxTelemetrySourceSha256 = '([a-f0-9]+)'/)?.[1], cssha=cs.match(/SourceSha256 = "([a-f0-9]+)"/)?.[1]
if(!tsha||tsha!==cssha)errors.push('TS/C# telemetry source SHA mismatch')
if(!manifest.events.some(x=>x.name==='experiment.exposed'))errors.push('experiment exposure event missing')
if(!fs.existsSync('apps/web/src/modules/common/ux-metrics/UxMetricsPage.vue'))errors.push('COMMON-UX-001 reference screen missing')
if(errors.length){console.error('KBX telemetry governance FAILED');errors.forEach(x=>console.error(' - '+x));process.exit(1)}
console.log(`KBX telemetry governance PASS (${manifest.events.length} events, ${manifest.metrics.length} metrics)`)