05ed037fe8
- 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!
163 lines
5.4 KiB
JavaScript
163 lines
5.4 KiB
JavaScript
#!/usr/bin/env node
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
// EOS Metrics Dashboard — Mäta användning under moratorium
|
|
// Erik-krav: "Mäta: Hur många gånger användes EOS? Hur många STOP-regler utlöstes?"
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
import { readFileSync, existsSync } from 'fs';
|
|
|
|
const METRICS = {
|
|
// Användning
|
|
eosUsage: {
|
|
totalRuns: 0,
|
|
byComponent: {},
|
|
byDate: {}
|
|
},
|
|
// STOP
|
|
stopsTriggered: {
|
|
total: 0,
|
|
byRule: {},
|
|
bySeverity: {}
|
|
},
|
|
// Undantag
|
|
waiversRequested: {
|
|
total: 0,
|
|
approved: 0,
|
|
denied: 0
|
|
},
|
|
// Tider
|
|
resolutionTime: {
|
|
total: 0,
|
|
count: 0,
|
|
average: 0
|
|
},
|
|
// Regressions
|
|
regressionsAvoided: 0,
|
|
// Beslutsändringar
|
|
decisionsChanged: 0
|
|
};
|
|
|
|
class MetricsDashboard {
|
|
constructor() {
|
|
this.loadMetrics();
|
|
}
|
|
|
|
loadMetrics() {
|
|
const path = '/home/bernt/.openclaw/workspace/EOS/metrics.json';
|
|
if (existsSync(path)) {
|
|
const data = JSON.parse(readFileSync(path, 'utf8'));
|
|
Object.assign(METRICS, data);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Visa dashboard
|
|
*/
|
|
show() {
|
|
console.log('╔═══════════════════════════════════════════════════════════════╗');
|
|
console.log('║ EOS METRICS DASHBOARD ║');
|
|
console.log('║ Moratorium-period: Sprint 1-2 ║');
|
|
console.log('╚═══════════════════════════════════════════════════════════════╝');
|
|
console.log();
|
|
|
|
console.log('📊 ANVÄNDNING\n');
|
|
console.log(` Totala körningar: ${METRICS.eosUsage.totalRuns}`);
|
|
console.log(` Per komponent:`);
|
|
for (const [comp, count] of Object.entries(METRICS.eosUsage.byComponent)) {
|
|
console.log(` • ${comp}: ${count}`);
|
|
}
|
|
console.log();
|
|
|
|
console.log('🔴 STOP-REGLER\n');
|
|
console.log(` Totala utlösningar: ${METRICS.stopsTriggered.total}`);
|
|
console.log(` Per regel:`);
|
|
for (const [rule, count] of Object.entries(METRICS.stopsTriggered.byRule)) {
|
|
console.log(` • ${rule}: ${count}`);
|
|
}
|
|
console.log(` Per allvarlighet:`);
|
|
for (const [sev, count] of Object.entries(METRICS.stopsTriggered.bySeverity)) {
|
|
console.log(` • ${sev}: ${count}`);
|
|
}
|
|
console.log();
|
|
|
|
console.log('🟡 DISPENSER\n');
|
|
console.log(` Begärda: ${METRICS.waiversRequested.total}`);
|
|
console.log(` Godkända: ${METRICS.waiversRequested.approved}`);
|
|
console.log(` Avslagna: ${METRICS.waiversRequested.denied}`);
|
|
console.log();
|
|
|
|
console.log('⏱️ LÖSNINGSTID\n');
|
|
console.log(` Genomsnitt: ${METRICS.resolutionTime.average.toFixed(1)} timmar`);
|
|
console.log(` Antal: ${METRICS.resolutionTime.count}`);
|
|
console.log();
|
|
|
|
console.log('🛡️ REGRESSIONER\n');
|
|
console.log(` Undvikna: ${METRICS.regressionsAvoided}`);
|
|
console.log();
|
|
|
|
console.log('🧠 BESLUTSÄNDRINGAR\n');
|
|
console.log(` Utvecklare ändrade beslut efter EOS-analys: ${METRICS.decisionsChanged}`);
|
|
console.log();
|
|
|
|
console.log('═══════════════════════════════════════════════════════════════\n');
|
|
}
|
|
|
|
/**
|
|
* Uppdatera mätvärden (simulerat)
|
|
*/
|
|
simulate() {
|
|
// Simulera data för demonstration
|
|
METRICS.eosUsage.totalRuns = 47;
|
|
METRICS.eosUsage.byComponent = {
|
|
'immutable-truth': 12,
|
|
'engineering-contract': 15,
|
|
'policy-enforcement': 8,
|
|
'engineering-readiness': 5,
|
|
'release-gate': 7
|
|
};
|
|
|
|
METRICS.stopsTriggered.total = 23;
|
|
METRICS.stopsTriggered.byRule = {
|
|
'no-pipeline-deploy': 8,
|
|
'no-server-edit': 5,
|
|
'no-uncommitted': 4,
|
|
'no-migration': 3,
|
|
'no-api-contract': 3
|
|
};
|
|
METRICS.stopsTriggered.bySeverity = {
|
|
'CRITICAL': 5,
|
|
'HIGH': 8,
|
|
'MEDIUM': 7,
|
|
'LOW': 3
|
|
};
|
|
|
|
METRICS.waiversRequested.total = 3;
|
|
METRICS.waiversRequested.approved = 1;
|
|
METRICS.waiversRequested.denied = 2;
|
|
|
|
METRICS.resolutionTime.total = 72;
|
|
METRICS.resolutionTime.count = 18;
|
|
METRICS.resolutionTime.average = 72 / 18;
|
|
|
|
METRICS.regressionsAvoided = 4;
|
|
METRICS.decisionsChanged = 6;
|
|
|
|
this.show();
|
|
}
|
|
}
|
|
|
|
// ── Main ──────────────────────────────────────────────────────────────────
|
|
|
|
const dashboard = new MetricsDashboard();
|
|
const command = process.argv[2] || '--show';
|
|
|
|
if (command === '--show') {
|
|
dashboard.show();
|
|
} else if (command === '--simulate') {
|
|
dashboard.simulate();
|
|
} else {
|
|
console.log('Användning:');
|
|
console.log(' node metrics-dashboard.mjs --show # Visa mätvärden');
|
|
console.log(' node metrics-dashboard.mjs --simulate # Simulera data');
|
|
}
|