/**
* ROLE: INFRASTRUCTURE
* PURPOSE: Evidence-based maturity scoring engine with hard-coded rules
* AUTHORITY: ATLAS-GATE MCP Maturity Scoring Specification v1.0
*
* This engine computes organizational maturity across 6 dimensions:
* Reliability, Security, Documentation, Governance, Integration, Performance
*
* CRITICAL RULES:
* - No mutations during scoring (read-only)
* - All scores backed by evidence
* - Level-5 claims blocked unless all gates pass
* - Overall score = min(dimension scores)
* - Hard caps applied for violations
*/
import fs from 'fs';
import path from 'path';
import crypto from 'crypto';
const MATURITY_DIMENSIONS = {
RELIABILITY: 'Reliability',
SECURITY: 'Security',
DOCUMENTATION: 'Documentation',
GOVERNANCE: 'Governance',
INTEGRATION: 'Integration',
PERFORMANCE: 'Performance',
};
const LEVEL_RANGE = { MIN: 1, MAX: 5 };
/**
* Parse audit log (JSONL format)
* @param {string} auditLogPath - Path to audit-log.jsonl
* @returns {Array<Object>} Parsed entries
*/
function parseAuditLog(auditLogPath) {
if (!fs.existsSync(auditLogPath)) {
return [];
}
const lines = fs.readFileSync(auditLogPath, 'utf8').split('\n').filter(l => l.trim());
const entries = [];
for (const line of lines) {
try {
entries.push(JSON.parse(line));
} catch (err) {
throw new Error(`AUDIT_PARSE_ERROR: Failed to parse audit line: ${err.message}`);
}
}
return entries;
}
/**
* Compute metrics from audit log
* @param {Array<Object>} auditEntries - Parsed audit entries
* @returns {Object} Audit metrics
*/
function computeAuditMetrics(auditEntries) {
if (auditEntries.length === 0) {
return {
totalEntries: 0,
failureCount: 0,
failureRate: 0,
tamperedCount: 0,
hashChainBreaks: 0,
policyBypasses: 0,
entryTypes: {},
roleDistribution: {},
};
}
const failures = auditEntries.filter(e => e.error || e.result === 'error').length;
const policyBypasses = auditEntries.filter(e => e.policy_bypass).length;
const roleMap = {};
auditEntries.forEach(e => {
const role = e.role || 'UNKNOWN';
roleMap[role] = (roleMap[role] || 0) + 1;
});
// Hash chain validation: each entry's prevHash should match prior hash
let chainBreaks = 0;
for (let i = 1; i < auditEntries.length; i++) {
const current = auditEntries[i];
const previous = auditEntries[i - 1];
if (current.prevHash && previous.hash && current.prevHash !== previous.hash) {
chainBreaks++;
}
}
return {
totalEntries: auditEntries.length,
failureCount: failures,
failureRate: failures / auditEntries.length,
tamperedCount: chainBreaks,
hashChainBreaks: chainBreaks,
policyBypasses: policyBypasses,
entryTypes: {},
roleDistribution: roleMap,
};
}
/**
* DIMENSION: Reliability
*
* Gates:
* - ≥99% tool invocations audited
* - 0 uncaught exceptions (verified via audit log error codes)
* - No replay failures unresolved
* - Mean time to diagnose ≤ threshold (from audit timestamps)
*
* Caps:
* - Any tamper/divergence → max 3.0
* - Unresolved replay FAIL → max 4.0
*/
function scoreReliability(auditMetrics, errorMetrics, replayResults) {
let score = 5.0;
// Gate 1: Audit coverage ≥99%
if (auditMetrics.totalEntries === 0) {
score = 2.0;
} else {
const auditCoverage = 1 - auditMetrics.failureRate;
if (auditCoverage < 0.99) {
score = Math.min(score, 3.5);
}
}
// Gate 2: Uncaught exceptions count
if (errorMetrics.uncaughtCount > 0) {
score = Math.min(score, 2.0);
}
// Gate 3: Hash chain integrity
if (auditMetrics.hashChainBreaks > 0) {
score = 3.0;
}
// Gate 4: Replay divergence
const replayFailRate = replayResults.failures / Math.max(1, replayResults.total);
if (replayFailRate > 0.01) {
score = Math.min(score, 4.0);
}
return Math.max(LEVEL_RANGE.MIN, Math.min(LEVEL_RANGE.MAX, score));
}
/**
* DIMENSION: Security
*
* Gates:
* - 100% writes pass policy validation
* - 0 policy bypasses
* - Audit chain integrity PASS
* - Human gate enforced for remediation
*
* Caps:
* - Any policy bypass → max 3.0
* - Any audit tamper → max 2.0
*/
function scoreSecurity(policyMetrics, auditMetrics) {
let score = 5.0;
// Gate 1: Policy pass rate = 100%
if (policyMetrics.totalChecks === 0) {
score = 2.0;
} else {
const passRate = policyMetrics.passCount / policyMetrics.totalChecks;
if (passRate < 1.0) {
score = Math.min(score, 3.0);
}
}
// Gate 2: Policy bypasses (violations in audit)
if (policyMetrics.bypassCount > 0) {
score = 3.0;
}
// Gate 3: Audit tamper detection
if (auditMetrics.tamperedCount > 0) {
score = 2.0;
}
return Math.max(LEVEL_RANGE.MIN, Math.min(LEVEL_RANGE.MAX, score));
}
/**
* DIMENSION: Documentation
*
* Gates:
* - Intent coverage ≥95% of written files
* - 0 intent schema violations
* - Non-coder sections present (schema check)
*
* Caps:
* - Unresolved drift → max 3.5
*/
function scoreDocumentation(intentMetrics) {
let score = 5.0;
// Gate 1: Intent coverage ≥95%
if (intentMetrics.totalFiles === 0) {
// Zero files means no audit history = missing evidence
score = 2.0;
} else if (intentMetrics.documentsWithIntent === 0) {
// No intent documents despite files = 0% coverage
score = 1.0;
} else {
const coverage = intentMetrics.documentsWithIntent / intentMetrics.totalFiles;
if (coverage < 0.95) {
// Linear penalty: each 1% below 95% reduces score by 0.1
score = Math.min(score, 5.0 - ((0.95 - coverage) * 10));
}
}
// Gate 2: Schema violations
if (intentMetrics.schemaViolations > 0) {
score = Math.min(score, 3.0);
}
// Gate 3: Non-coder content present
if (!intentMetrics.nonCoderSections) {
score = Math.min(score, 2.0);
}
return Math.max(LEVEL_RANGE.MIN, Math.min(LEVEL_RANGE.MAX, score));
}
/**
* DIMENSION: Governance
*
* Gates:
* - 100% executions tied to approved plan hash
* - 0 executions with hash mismatch
* - All writes path-authorized
*
* Caps:
* - Any execution without approval → max 2.0
*/
function scoreGovernance(auditMetrics, pathAuthMetrics) {
let score = 5.0;
// Gate 1: Plan hash coverage
const planLessEntries = auditMetrics.roleDistribution['INFRASTRUCTURE'] || 0;
const withPlanHash = auditMetrics.totalEntries - planLessEntries;
if (auditMetrics.totalEntries > 0) {
const planCoverage = withPlanHash / auditMetrics.totalEntries;
if (planCoverage < 1.0) {
score = 2.0;
}
}
// Gate 2: Hash mismatches
if (auditMetrics.hashChainBreaks > 0) {
score = 2.0;
}
// Gate 3: Path authorization
if (pathAuthMetrics.unauthorizedPaths > 0) {
score = 2.0;
}
return Math.max(LEVEL_RANGE.MIN, Math.min(LEVEL_RANGE.MAX, score));
}
/**
* DIMENSION: Integration
*
* Gates:
* - Tool ecosystem coverage listed
* - Automated verification gates passing
* - Deterministic configuration
*
* Caps:
* - Manual steps required → max 4.0
*/
function scoreIntegration(toolMetrics) {
let score = 5.0;
// Gate 1: Tool coverage
if (!toolMetrics.tools || toolMetrics.tools.length === 0) {
score = 2.0;
} else if (toolMetrics.tools.length < 5) {
score = 3.0;
}
// Gate 2: Verification gates
if (toolMetrics.gateFailures > 0) {
score = Math.min(score, 3.5);
}
// Gate 3: Manual steps
if (toolMetrics.manualStepsRequired) {
score = Math.min(score, 4.0);
}
return Math.max(LEVEL_RANGE.MIN, Math.min(LEVEL_RANGE.MAX, score));
}
/**
* DIMENSION: Performance
*
* Gates:
* - Policy + lint overhead bounded
* - Replay + audit verify time bounded
* - No performance regressions beyond threshold
*
* Caps:
* - Missing metrics → max 3.0
*/
function scorePerformance(perfMetrics) {
let score = 5.0;
// Gate 1: Metrics present
if (!perfMetrics.policyLatency || !perfMetrics.auditLatency) {
score = 3.0;
} else {
// Bounded check (example thresholds in ms)
if (perfMetrics.policyLatency > 5000) {
score = Math.min(score, 3.0);
}
if (perfMetrics.auditLatency > 10000) {
score = Math.min(score, 3.5);
}
}
// Gate 2: Regression detection
if (perfMetrics.regressionDetected) {
score = Math.min(score, 2.5);
}
return Math.max(LEVEL_RANGE.MIN, Math.min(LEVEL_RANGE.MAX, score));
}
/**
* Main scoring engine: compute all dimensions and overall score
*
* @param {string} workspaceRoot - Absolute workspace root
* @param {Object} options - { auditLogPath, timeWindow }
* @returns {Object} Maturity score report
*/
export function computeMaturityScore(workspaceRoot, options = {}) {
const auditLogPath = options.auditLogPath || path.join(workspaceRoot, 'audit-log.jsonl');
// Parse audit log (only evidence source)
const auditEntries = parseAuditLog(auditLogPath);
const auditMetrics = computeAuditMetrics(auditEntries);
// Placeholder metrics (would be populated from actual systems in production)
const errorMetrics = {
uncaughtCount: 0,
};
const replayResults = {
total: auditMetrics.totalEntries || 1,
failures: 0,
};
const policyMetrics = {
totalChecks: auditMetrics.totalEntries || 1,
passCount: auditMetrics.totalEntries - auditMetrics.policyBypasses,
bypassCount: auditMetrics.policyBypasses,
};
const intentMetrics = {
totalFiles: auditMetrics.totalEntries || 1,
documentsWithIntent: auditMetrics.totalEntries || 1,
schemaViolations: 0,
nonCoderSections: true,
};
const pathAuthMetrics = {
unauthorizedPaths: 0,
};
const toolMetrics = {
tools: ['begin_session', 'write_file', 'read_file', 'list_plans', 'read_audit_log', 'read_prompt'],
gateFailures: 0,
manualStepsRequired: false,
};
const perfMetrics = {
policyLatency: 50, // ms
auditLatency: 100, // ms
regressionDetected: false,
};
// Compute dimension scores
const dimensions = {
[MATURITY_DIMENSIONS.RELIABILITY]: scoreReliability(auditMetrics, errorMetrics, replayResults),
[MATURITY_DIMENSIONS.SECURITY]: scoreSecurity(policyMetrics, auditMetrics),
[MATURITY_DIMENSIONS.DOCUMENTATION]: scoreDocumentation(intentMetrics),
[MATURITY_DIMENSIONS.GOVERNANCE]: scoreGovernance(auditMetrics, pathAuthMetrics),
[MATURITY_DIMENSIONS.INTEGRATION]: scoreIntegration(toolMetrics),
[MATURITY_DIMENSIONS.PERFORMANCE]: scorePerformance(perfMetrics),
};
// Overall = min(dimensions)
const overallScore = Math.min(...Object.values(dimensions));
// Round down dimension scores to 1 decimal place
const roundedDimensions = {};
Object.entries(dimensions).forEach(([dim, score]) => {
roundedDimensions[dim] = Math.floor(score * 10) / 10;
});
const roundedOverall = Math.floor(overallScore * 10) / 10;
return {
timestamp: new Date().toISOString(),
dimensions: roundedDimensions,
overall: roundedOverall,
evidence: {
auditMetrics,
policyMetrics,
intentMetrics,
pathAuthMetrics,
toolMetrics,
perfMetrics,
},
blockingReasons: computeBlockingReasons(dimensions),
};
}
/**
* Compute why not Level-5
* @param {Object} dimensions - Dimension scores
* @returns {Object} Blocking reasons
*/
function computeBlockingReasons(dimensions) {
const reasons = [];
const level5Gates = 5.0;
Object.entries(dimensions).forEach(([dim, score]) => {
if (score < level5Gates) {
reasons.push({
dimension: dim,
score,
blockedBy: score < 3.5 ? 'MAJOR_VIOLATION' : score < 4.5 ? 'UNMET_EVIDENCE' : 'MINOR_GAP',
});
}
});
return reasons;
}
/**
* Explain gap between current and target level
* @param {number} currentLevel - Current overall score
* @param {number} targetLevel - Target level (default 5.0)
* @param {Object} dimensions - Dimension scores
* @returns {Object} Gap analysis
*/
export function explainMaturityGap(currentLevel, targetLevel = 5.0, dimensions) {
const gaps = [];
Object.entries(dimensions).forEach(([dim, score]) => {
if (score < targetLevel) {
const gap = targetLevel - score;
gaps.push({
dimension: dim,
current: score,
target: targetLevel,
gap: Math.round(gap * 10) / 10,
priority: gap > 2 ? 'CRITICAL' : gap > 1 ? 'HIGH' : 'LOW',
});
}
});
return {
currentLevel,
targetLevel,
canReachTarget: currentLevel === targetLevel,
gaps: gaps.sort((a, b) => b.gap - a.gap),
};
}
/**
* Compute hash of scoring result for audit trail
* @param {Object} scoreResult - Result from computeMaturityScore
* @returns {string} SHA256 hash
*/
export function hashScoringResult(scoreResult) {
const canonical = JSON.stringify(scoreResult, null, 0);
return crypto.createHash('sha256').update(canonical).digest('hex');
}