Files
boc/SIL/validation/provenance-audit.mjs
T
Bernt 05ed037fe8 pilot.landvex.com: HTTPS + Full Stack Verified
- DNS: pilot.landvex.com -> 16.170.83.169
- TLS: Let's Encrypt certificate (expires 2026-09-30)
- Nginx: reverse proxy with SSL termination
- API: https://pilot.landvex.com/api/v1/missions
- UI: https://pilot.landvex.com/
- Upload: POST /api/v1/missions/import (multipart/form-data)

Verified:
 https://pilot.landvex.com/health
 https://pilot.landvex.com/version
 https://pilot.landvex.com/api/v1/missions (list)
 https://pilot.landvex.com/api/v1/missions/:id (get)
 POST /api/v1/missions/import (video upload)
 UI loads with title 'LandveX Intelligence Lab'

Next: Pilot 001 — Break the system!
2026-07-02 17:34:19 +00:00

241 lines
8.1 KiB
JavaScript

#!/usr/bin/env node
// ═══════════════════════════════════════════════════════════════════════════
// SIL Validation — Fråga 2: Kan SIL motivera sina slutsatser?
// Granskar 50 slumpmässiga analyser för provenance completeness
// ═══════════════════════════════════════════════════════════════════════════
import { readFileSync, existsSync, writeFileSync } from 'fs';
const SHADOW_LOG = '/home/bernt/.openclaw/workspace/SIL/shadow-log.jsonl';
const AUDIT_RESULTS = '/home/bernt/.openclaw/workspace/SIL/validation/provenance-audit-results.jsonl';
/**
* Checklista för provenance completeness
*/
const PROVENANCE_CHECKLIST = [
{
id: 'rule',
question: 'Vilken regel användes?',
check: (analysis) => analysis.provenance?.trace?.steps?.some(s => s.type === 'rule')
},
{
id: 'observation',
question: 'Vilka observationer användes?',
check: (analysis) => analysis.provenance?.trace?.steps?.some(s => s.type === 'observation')
},
{
id: 'artifacts',
question: 'Vilka artefakter användes?',
check: (analysis) => analysis.evidence?.static?.length > 0
},
{
id: 'nodes',
question: 'Vilka noder traverserades?',
check: (analysis) => analysis.provenance?.trace?.steps?.some(s => s.type === 'traversal')
},
{
id: 'verified',
question: 'Hur stor del var verifierad?',
check: (analysis) => {
const conclusions = analysis.provenance?.trace?.conclusions || [];
if (conclusions.length === 0) return false;
const verified = conclusions.filter(c => c.verified).length;
return verified / conclusions.length >= 0.5; // Minst hälften verifierad
}
},
{
id: 'inferred',
question: 'Hur stor del var inferens?',
check: (analysis) => {
const conclusions = analysis.provenance?.trace?.conclusions || [];
if (conclusions.length === 0) return false;
const inferred = conclusions.filter(c => c.inferred).length;
return inferred / conclusions.length <= 0.5; // Max hälften inferens
}
}
];
class ProvenanceAuditor {
constructor() {
this.analyses = this.loadAnalyses();
}
loadAnalyses() {
if (!existsSync(SHADOW_LOG)) return [];
return readFileSync(SHADOW_LOG, 'utf8')
.split('\n')
.filter(line => line.trim())
.map(line => {
try { return JSON.parse(line); } catch { return null; }
})
.filter(Boolean);
}
/**
* Granska N slumpmässiga analyser
*/
audit(sampleSize = 50) {
// Välj slumpmässiga analyser
const shuffled = [...this.analyses].sort(() => Math.random() - 0.5);
const sample = shuffled.slice(0, Math.min(sampleSize, shuffled.length));
console.log(`🔍 Granskar provenance för ${sample.length} analyser...\n`);
const results = [];
for (const analysis of sample) {
const audit = this.auditAnalysis(analysis);
results.push(audit);
}
const report = this.generateReport(results);
this.saveResults(results);
this.printReport(report);
return report;
}
/**
* Granska en enskild analys
*/
auditAnalysis(analysis) {
const checks = [];
let passed = 0;
let total = PROVENANCE_CHECKLIST.length;
for (const check of PROVENANCE_CHECKLIST) {
const result = check.check(analysis);
checks.push({
id: check.id,
question: check.question,
passed: result
});
if (result) passed++;
}
const completeness = Math.round(passed / total * 100);
return {
analysisId: analysis.analysisId || analysis.timestamp,
timestamp: analysis.timestamp,
checks,
completeness,
passed,
total,
// Kategorisera
quality: completeness >= 90 ? 'EXCELLENT' :
completeness >= 70 ? 'GOOD' :
completeness >= 50 ? 'FAIR' : 'POOR'
};
}
/**
* Generera rapport
*/
generateReport(results) {
const total = results.length;
if (total === 0) {
return { error: 'Inga analyser att granska' };
}
const avgCompleteness = results.reduce((a, r) => a + r.completeness, 0) / total;
const byQuality = {
EXCELLENT: results.filter(r => r.quality === 'EXCELLENT').length,
GOOD: results.filter(r => r.quality === 'GOOD').length,
FAIR: results.filter(r => r.quality === 'FAIR').length,
POOR: results.filter(r => r.quality === 'POOR').length
};
// Per-check resultat
const byCheck = {};
for (const check of PROVENANCE_CHECKLIST) {
const passed = results.filter(r =>
r.checks.find(c => c.id === check.id)?.passed
).length;
byCheck[check.id] = {
question: check.question,
passed,
total,
rate: Math.round(passed / total * 100) + '%'
};
}
return {
timestamp: new Date().toISOString(),
sampleSize: total,
avgCompleteness: Math.round(avgCompleteness) + '%',
byQuality,
byCheck,
// Success-kriterium
meetsCriteria: avgCompleteness >= 90
};
}
printReport(report) {
console.log('╔═══════════════════════════════════════════════════════════════╗');
console.log('║ VALIDATION: FRÅGA 2 ║');
console.log('║ Kan SIL motivera sina slutsatser? ║');
console.log('╚═══════════════════════════════════════════════════════════════╝');
console.log();
if (report.error) {
console.log(`${report.error}\n`);
return;
}
console.log('📊 PROVENANCE COMPLETENESS\n');
console.log(` Genomsnitt: ${report.avgCompleteness}`);
console.log(` Analyser granskade: ${report.sampleSize}`);
console.log();
console.log('📈 KVALITETSFÖRDELNING\n');
console.log(` EXCELLENT (≥90%): ${report.byQuality.EXCELLENT}`);
console.log(` GOOD (70-89%): ${report.byQuality.GOOD}`);
console.log(` FAIR (50-69%): ${report.byQuality.FAIR}`);
console.log(` POOR (<50%): ${report.byQuality.POOR}`);
console.log();
console.log('✅ PER CHECK\n');
for (const [id, data] of Object.entries(report.byCheck)) {
const icon = parseFloat(data.rate) >= 90 ? '✅' : '⚠️';
console.log(` ${icon} ${data.question}`);
console.log(` ${data.passed}/${data.total} (${data.rate})`);
}
console.log();
console.log('🎯 SUCCESS-KRITERIUM\n');
console.log(` Krav: ≥90% completeness`);
console.log(` Resultat: ${report.avgCompleteness}`);
console.log(` ${report.meetsCriteria ? '✅ UPPFYLLT' : '❌ EJ UPPFYLLT'}`);
console.log();
console.log('═══════════════════════════════════════════════════════════════\n');
}
saveResults(results) {
for (const result of results) {
writeFileSync(AUDIT_RESULTS, JSON.stringify(result) + '\n', { flag: 'a' });
}
}
}
// ── Main ──────────────────────────────────────────────────────────────────
const auditor = new ProvenanceAuditor();
const command = process.argv[2] || '--audit';
if (command === '--audit') {
const sampleSize = parseInt(process.argv[3]) || 50;
auditor.audit(sampleSize);
} else if (command === '--checklist') {
console.log('📋 PROVENANCE CHECKLIST\n');
for (const check of PROVENANCE_CHECKLIST) {
console.log(`${check.question}`);
}
} else {
console.log('Användning:');
console.log(' node provenance-audit.mjs --audit [n] # Granska N analyser');
console.log(' node provenance-audit.mjs --checklist # Visa checklista');
}