Files
boc/EOS/architecture-drift.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

187 lines
5.4 KiB
JavaScript

#!/usr/bin/env node
// ═══════════════════════════════════════════════════════════════════════════
// Architecture Drift Detector — Verifierar att implementation följer kontrakt
// ═══════════════════════════════════════════════════════════════════════════
import { readFileSync } from 'fs';
/**
* Kontraktets invariants
*/
const CONTRACT = {
executionOrder: [
'PLANNER',
'CONTEXT',
'MEMORY',
'KNOWLEDGE',
'INTENT',
'EOS',
'DEVELOPER',
'REVIEWER',
'COMMIT',
'OPERATOR'
],
requiredPhases: ['PLANNER', 'EOS', 'DEVELOPER'],
forbiddenTransitions: [
{ from: 'DEVELOPER', to: 'EOS', reason: 'EOS måste alltid köras före Developer' }
],
requiredChecks: {
'EOS': ['passed', 'blockedBy', 'reason']
}
};
/**
* Extrahera exekveringsordning från Runtime-kod
*/
function extractExecutionOrder(runtimeCode) {
const order = [];
const methodPattern = /async run(\w+)\(/g;
let match;
while ((match = methodPattern.exec(runtimeCode)) !== null) {
const phase = match[1].toUpperCase();
if (!order.includes(phase)) {
order.push(phase);
}
}
return order;
}
/**
* Verifiera exekveringsordning
*/
function verifyExecutionOrder(actualOrder) {
const errors = [];
// Kontrollera att alla obligatoriska faser finns
for (const required of CONTRACT.requiredPhases) {
// EOS kan heta EOS eller EOSCHECK
const found = actualOrder.some(phase =>
phase === required ||
(required === 'EOS' && phase.includes('EOS'))
);
if (!found) {
errors.push(`Missing required phase: ${required}`);
}
}
// Kontrollera att ordningen stämmer med kontraktet
let contractIndex = 0;
for (const phase of actualOrder) {
const expectedIndex = CONTRACT.executionOrder.indexOf(phase);
if (expectedIndex === -1) continue; // Okänd fas, hoppa över
if (expectedIndex < contractIndex) {
errors.push(`Phase ${phase} is out of order. Expected after ${CONTRACT.executionOrder[contractIndex]}`);
} else {
contractIndex = expectedIndex;
}
}
// Kontrollera förbjudna övergångar
for (let i = 0; i < actualOrder.length - 1; i++) {
const from = actualOrder[i];
const to = actualOrder[i + 1];
for (const forbidden of CONTRACT.forbiddenTransitions) {
if (from === forbidden.from && to === forbidden.to) {
errors.push(`Forbidden transition: ${from}${to}. ${forbidden.reason}`);
}
}
}
return errors;
}
/**
* Verifiera att EOS-check alltid körs före Developer
*/
function verifyEOSBeforeDeveloper(runtimeCode) {
const errors = [];
// Hitta runEOSCheck och runDeveloper
const eosIndex = runtimeCode.indexOf('runEOSCheck');
const devIndex = runtimeCode.indexOf('runDeveloper');
if (eosIndex === -1) {
errors.push('runEOSCheck not found in Runtime');
}
if (devIndex === -1) {
errors.push('runDeveloper not found in Runtime');
}
if (eosIndex !== -1 && devIndex !== -1 && eosIndex > devIndex) {
errors.push('runEOSCheck must be called before runDeveloper');
}
return errors;
}
/**
* Verifiera att Runtime inte har direktåtkomst till Policy Registry
*/
function verifyMemoryIsolation(runtimeCode) {
const errors = [];
// Kontrollera att Runtime inte modifierar Policy Registry direkt
if (runtimeCode.includes('policyRegistry.') && runtimeCode.includes('=')) {
errors.push('Runtime may not modify Policy Registry directly');
}
return errors;
}
/**
* Huvudfunktion för drift-detektering
*/
export function detectArchitectureDrift(runtimePath) {
const runtimeCode = readFileSync(runtimePath, 'utf8');
const executionOrder = extractExecutionOrder(runtimeCode);
const orderErrors = verifyExecutionOrder(executionOrder);
const eosErrors = verifyEOSBeforeDeveloper(runtimeCode);
const isolationErrors = verifyMemoryIsolation(runtimeCode);
const allErrors = [...orderErrors, ...eosErrors, ...isolationErrors];
return {
drift: allErrors.length,
errors: allErrors,
executionOrder,
passed: allErrors.length === 0
};
}
/**
* CLI-användning
*/
if (process.argv[1] === new URL(import.meta.url).pathname) {
const runtimePath = process.argv[2] || './agent-runtime-v10.mjs';
console.log('═══════════════════════════════════════════════════════════════');
console.log(' ARCHITECTURE DRIFT DETECTOR');
console.log('═══════════════════════════════════════════════════════════════\n');
const result = detectArchitectureDrift(runtimePath);
console.log(`Runtime: ${runtimePath}`);
console.log(`Execution Order: ${result.executionOrder.join(' → ')}`);
console.log(`Drift: ${result.drift}`);
if (result.errors.length > 0) {
console.log('\n❌ ERRORS:');
for (const error of result.errors) {
console.log(` - ${error}`);
}
process.exit(1);
} else {
console.log('\n✅ No architecture drift detected');
process.exit(0);
}
}