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!
207 lines
7.0 KiB
JavaScript
207 lines
7.0 KiB
JavaScript
#!/usr/bin/env node
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
// EOS Dashboard — Enkel textbaserad vy över systemets hälsa
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
import { readFileSync, existsSync, readdirSync } from 'fs';
|
|
|
|
class EOSDashboard {
|
|
constructor() {
|
|
this.data = {
|
|
runtimeContract: this.checkRuntimeContract(),
|
|
policyLayer: this.checkPolicyLayer(),
|
|
releaseGates: this.checkReleaseGates(),
|
|
goldenFailures: this.checkGoldenFailures(),
|
|
drift: this.checkDrift(),
|
|
readiness: this.checkReadiness(),
|
|
decisionCorrectness: this.checkDecisionCorrectness(),
|
|
replayCoverage: this.checkReplayCoverage(),
|
|
activeStops: this.checkActiveStops(),
|
|
engineeringReadiness: this.checkEngineeringReadiness()
|
|
};
|
|
}
|
|
|
|
checkRuntimeContract() {
|
|
try {
|
|
const contract = readFileSync('./RUNTIME-CONTRACT.md', 'utf8');
|
|
return {
|
|
status: '✅',
|
|
version: '1.0',
|
|
invariants: (contract.match(/Invariant/g) || []).length,
|
|
lastUpdated: '2026-07-01'
|
|
};
|
|
} catch {
|
|
return { status: '❌', error: 'Contract not found' };
|
|
}
|
|
}
|
|
|
|
checkPolicyLayer() {
|
|
try {
|
|
const registry = readFileSync('./policy-registry.mjs', 'utf8');
|
|
const policies = (registry.match(/id: 'POL-/g) || []).length;
|
|
return {
|
|
status: '✅',
|
|
policies,
|
|
version: '1.0'
|
|
};
|
|
} catch {
|
|
return { status: '❌', error: 'Registry not found' };
|
|
}
|
|
}
|
|
|
|
checkReleaseGates() {
|
|
return {
|
|
status: '✅',
|
|
policyLayer: 'APPROVED',
|
|
eosRuntime: 'PENDING',
|
|
reasoningGate: 'NOT_OPEN'
|
|
};
|
|
}
|
|
|
|
checkGoldenFailures() {
|
|
try {
|
|
const failures = JSON.parse(readFileSync('./golden-failures.json', 'utf8'));
|
|
const active = failures.failures.filter(f => f.status === 'active').length;
|
|
const resolved = failures.failures.filter(f => f.status === 'resolved').length;
|
|
return {
|
|
status: active > 0 ? '🟡' : '✅',
|
|
active,
|
|
resolved,
|
|
total: failures.failures.length
|
|
};
|
|
} catch {
|
|
return { status: '❌', error: 'Golden failures not found' };
|
|
}
|
|
}
|
|
|
|
checkDrift() {
|
|
try {
|
|
const logs = readdirSync('./stability-logs')
|
|
.filter(f => f.startsWith('stability-') && f.endsWith('.json'));
|
|
|
|
if (logs.length < 2) {
|
|
return { status: '⏳', message: 'Insufficient data' };
|
|
}
|
|
|
|
const latest = JSON.parse(readFileSync(`./stability-logs/${logs[logs.length - 1]}`, 'utf8'));
|
|
const previous = JSON.parse(readFileSync(`./stability-logs/${logs[logs.length - 2]}`, 'utf8'));
|
|
|
|
const drift = latest.metrics.decisionCorrectness - previous.metrics.decisionCorrectness;
|
|
|
|
return {
|
|
status: drift >= 0 ? '✅' : '🔴',
|
|
drift: `${drift}%`,
|
|
days: logs.length
|
|
};
|
|
} catch {
|
|
return { status: '⏳', message: 'No stability logs' };
|
|
}
|
|
}
|
|
|
|
checkReadiness() {
|
|
return {
|
|
status: '⏳',
|
|
gate: 'R0',
|
|
daysRemaining: 7,
|
|
criteria: '7 days stability required'
|
|
};
|
|
}
|
|
|
|
checkDecisionCorrectness() {
|
|
try {
|
|
const report = JSON.parse(readFileSync('./falsification-suite-report-v6.json', 'utf8'));
|
|
const correctness = report.summary.overallDecisionCorrectness;
|
|
return {
|
|
status: correctness >= 95 ? '✅' : '🟡',
|
|
percentage: `${correctness}%`,
|
|
target: '≥95%'
|
|
};
|
|
} catch {
|
|
return { status: '❌', error: 'Report not found' };
|
|
}
|
|
}
|
|
|
|
checkReplayCoverage() {
|
|
try {
|
|
const replay = readFileSync('./decision-replay.mjs', 'utf8');
|
|
const hasRecord = replay.includes('recordDecision');
|
|
const hasReplay = replay.includes('replay');
|
|
return {
|
|
status: hasRecord && hasReplay ? '✅' : '🟡',
|
|
record: hasRecord,
|
|
replay: hasReplay
|
|
};
|
|
} catch {
|
|
return { status: '❌', error: 'Replay not found' };
|
|
}
|
|
}
|
|
|
|
checkActiveStops() {
|
|
try {
|
|
const stops = readFileSync('./stop-register-v2.mjs', 'utf8');
|
|
const count = (stops.match(/STOP/g) || []).length;
|
|
return {
|
|
status: count > 0 ? '🟡' : '✅',
|
|
count,
|
|
note: 'Active STOPs require attention'
|
|
};
|
|
} catch {
|
|
return { status: '❌', error: 'STOP register not found' };
|
|
}
|
|
}
|
|
|
|
checkEngineeringReadiness() {
|
|
return {
|
|
status: '⏳',
|
|
score: 'N/A',
|
|
note: 'Requires 7 days of stability data'
|
|
};
|
|
}
|
|
|
|
render() {
|
|
console.log('╔═══════════════════════════════════════════════════════════════╗');
|
|
console.log('║ EOS DASHBOARD ║');
|
|
console.log('║ System Health Overview ║');
|
|
console.log('╚═══════════════════════════════════════════════════════════════╝');
|
|
console.log();
|
|
|
|
const sections = [
|
|
{ title: 'Runtime Contract', data: this.data.runtimeContract },
|
|
{ title: 'Policy Layer', data: this.data.policyLayer },
|
|
{ title: 'Release Gates', data: this.data.releaseGates },
|
|
{ title: 'Golden Failures', data: this.data.goldenFailures },
|
|
{ title: 'Drift', data: this.data.drift },
|
|
{ title: 'Readiness', data: this.data.readiness },
|
|
{ title: 'Decision Correctness', data: this.data.decisionCorrectness },
|
|
{ title: 'Replay Coverage', data: this.data.replayCoverage },
|
|
{ title: 'Active STOPs', data: this.data.activeStops },
|
|
{ title: 'Engineering Readiness', data: this.data.engineeringReadiness }
|
|
];
|
|
|
|
for (const section of sections) {
|
|
console.log(`${section.title}`);
|
|
console.log('─'.repeat(50));
|
|
|
|
if (section.data.status) {
|
|
console.log(` Status: ${section.data.status}`);
|
|
}
|
|
|
|
for (const [key, value] of Object.entries(section.data)) {
|
|
if (key !== 'status') {
|
|
console.log(` ${key}: ${value}`);
|
|
}
|
|
}
|
|
|
|
console.log();
|
|
}
|
|
|
|
console.log('═══════════════════════════════════════════════════════════════');
|
|
console.log('Last updated:', new Date().toISOString());
|
|
console.log('═══════════════════════════════════════════════════════════════');
|
|
}
|
|
}
|
|
|
|
// CLI
|
|
const dashboard = new EOSDashboard();
|
|
dashboard.render();
|