tractatus/scripts/framework-stats.js
TheFlow f66115a7e9 feat(ffs): add pressure monitoring and auto-compact tracking
Enhanced framework-stats.js to display real session data and prepare for
auto-compact impact analysis.

New Data Displayed:
- Real session statistics (ID, message count, action count, timestamps)
- Actual context pressure monitoring (level, score, last check time)
- Auto-compact events section (ready to log compaction impact)
- Component statistics (CrossReferenceValidator, BashCommandValidator)

Pressure Monitoring:
- Now shows NORMAL (not UNKNOWN)
- Displays last check timestamp and message number
- Tracks token count at pressure check

Auto-Compact Infrastructure:
- Structure ready to log compaction events
- Will track: before/after tokens, reduction %, message #, pressure change
- Currently shows 0 compactions (session hasn't compacted yet)

Component Performance:
- CrossReferenceValidator: 1,462 validations
- BashCommandValidator: 978 validations, 109 blocks

Files: scripts/framework-stats.js (enhanced getSessionStats, report building,
display sections)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-25 09:05:46 +13:00

398 lines
15 KiB
JavaScript
Executable file

#!/usr/bin/env node
/**
* Framework Statistics Reporter
* Displays comprehensive framework statistics for current session
*
* Triggered by "ffs" (Full Framework Stats) codeword
*
* Reports:
* - Session context pressure and token usage
* - Framework service invocation counts
* - Recent audit log entries (last 10)
* - Active instruction statistics
* - Service health/initialization status
*/
const mongoose = require('mongoose');
const path = require('path');
const fs = require('fs');
// Load environment
require('dotenv').config();
// Framework services
const BoundaryEnforcer = require('../src/services/BoundaryEnforcer.service');
const MetacognitiveVerifier = require('../src/services/MetacognitiveVerifier.service');
const ContextPressureMonitor = require('../src/services/ContextPressureMonitor.service');
const CrossReferenceValidator = require('../src/services/CrossReferenceValidator.service');
const InstructionPersistenceClassifier = require('../src/services/InstructionPersistenceClassifier.service');
const PluralisticDeliberationOrchestrator = require('../src/services/PluralisticDeliberationOrchestrator.service');
async function getSessionStats() {
const sessionStatePath = path.join(__dirname, '../.claude/session-state.json');
if (fs.existsSync(sessionStatePath)) {
const sessionState = JSON.parse(fs.readFileSync(sessionStatePath, 'utf8'));
// Extract pressure monitoring data
const pressureData = sessionState.last_framework_activity?.ContextPressureMonitor;
// Extract auto-compact events
const autoCompacts = sessionState.auto_compact_events || [];
// Extract component statistics
const componentStats = sessionState.framework_components || {};
return {
...sessionState,
pressureMonitoring: pressureData,
autoCompactEvents: autoCompacts,
componentStatistics: componentStats
};
}
return null;
}
async function getTokenCheckpoints() {
const checkpointPath = path.join(__dirname, '../.claude/token-checkpoints.json');
if (fs.existsSync(checkpointPath)) {
return JSON.parse(fs.readFileSync(checkpointPath, 'utf8'));
}
return null;
}
async function getInstructionStats() {
const instructionPath = path.join(__dirname, '../.claude/instruction-history.json');
if (fs.existsSync(instructionPath)) {
const history = JSON.parse(fs.readFileSync(instructionPath, 'utf8'));
const active = history.instructions.filter(i => i.active);
const byQuadrant = active.reduce((acc, i) => {
acc[i.quadrant] = (acc[i.quadrant] || 0) + 1;
return acc;
}, {});
const byPersistence = active.reduce((acc, i) => {
acc[i.persistence] = (acc[i.persistence] || 0) + 1;
return acc;
}, {});
return {
total: history.instructions.length,
active: active.length,
inactive: history.instructions.length - active.length,
byQuadrant,
byPersistence,
version: history.version,
lastUpdated: history.last_updated
};
}
return null;
}
async function getAuditLogStats() {
try {
const db = require('../src/utils/db.util');
const collection = await db.getCollection('auditLogs');
// Get total count
const total = await collection.countDocuments();
// Get counts by service
const byService = await collection.aggregate([
{ $group: { _id: '$service', count: { $sum: 1 } } },
{ $sort: { count: -1 } }
]).toArray();
// Get recent entries (last 10)
const recent = await collection.find()
.sort({ timestamp: -1 })
.limit(10)
.toArray();
// Get today's count
const todayStart = new Date();
todayStart.setHours(0, 0, 0, 0);
const todayCount = await collection.countDocuments({
timestamp: { $gte: todayStart }
});
return {
total,
todayCount,
byService: byService.reduce((acc, s) => {
acc[s._id] = s.count;
return acc;
}, {}),
recent: recent.map(r => ({
service: r.service,
action: r.action,
decision: r.decision,
timestamp: r.timestamp,
sessionId: r.context?.sessionId
}))
};
} catch (error) {
console.error('Error fetching audit logs:', error.message);
return null;
}
}
async function main() {
try {
// Connect to MongoDB
await mongoose.connect('mongodb://localhost:27017/tractatus_dev', {
serverSelectionTimeoutMS: 2000
});
// Initialize framework services
await BoundaryEnforcer.initialize();
await MetacognitiveVerifier.initialize();
await ContextPressureMonitor.initialize('framework-stats');
await CrossReferenceValidator.initialize();
await InstructionPersistenceClassifier.initialize();
await PluralisticDeliberationOrchestrator.initialize();
// Gather statistics
const [sessionStats, tokenCheckpoints, instructionStats, auditStats] = await Promise.all([
getSessionStats(),
getTokenCheckpoints(),
getInstructionStats(),
getAuditLogStats()
]);
// Get current pressure stats
const monitorStats = ContextPressureMonitor.getStats();
const pressureHistory = ContextPressureMonitor.getPressureHistory();
const latestPressure = pressureHistory && pressureHistory.length > 0
? pressureHistory[pressureHistory.length - 1]
: null;
// Build report
const report = {
timestamp: new Date().toISOString(),
session: sessionStats ? {
sessionId: sessionStats.session_id,
startTime: sessionStats.started,
messageCount: sessionStats.message_count,
tokenEstimate: sessionStats.token_estimate,
actionCount: sessionStats.action_count,
lastUpdated: sessionStats.last_updated,
initialized: sessionStats.initialized
} : null,
tokenUsage: tokenCheckpoints ? {
budget: tokenCheckpoints.tokenBudget,
checkpoints: tokenCheckpoints.checkpoints,
nextCheckpoint: tokenCheckpoints.checkpoints.find(c => !c.reached)
} : null,
contextPressure: sessionStats?.pressureMonitoring ? {
level: sessionStats.pressureMonitoring.last_level || 'UNKNOWN',
score: sessionStats.pressureMonitoring.last_score || 0,
lastChecked: sessionStats.pressureMonitoring.timestamp,
messageNumber: sessionStats.pressureMonitoring.message,
tokenCount: sessionStats.pressureMonitoring.tokens
} : (latestPressure ? {
level: latestPressure.pressureLevel?.name || 'UNKNOWN',
score: latestPressure.overallScore,
timestamp: latestPressure.timestamp,
metrics: latestPressure.metrics
} : (monitorStats ? {
level: 'UNKNOWN',
score: 0,
stats: monitorStats
} : null)),
autoCompacts: sessionStats?.autoCompactEvents ? {
total: sessionStats.autoCompactEvents.length,
events: sessionStats.autoCompactEvents.map(e => ({
timestamp: e.timestamp,
beforeTokens: e.before_tokens,
afterTokens: e.after_tokens,
reduction: e.reduction_percent,
messageNumber: e.message_number,
pressureBefore: e.pressure_before,
pressureAfter: e.pressure_after
}))
} : { total: 0, events: [] },
componentStats: sessionStats?.componentStatistics ? Object.entries(sessionStats.componentStatistics).map(([name, stats]) => ({
name,
validations: stats.validations_performed,
blocks: stats.blocks_issued,
lastActivity: stats.last_validation,
tokenCount: stats.tokens
})) : [],
instructions: instructionStats,
auditLogs: auditStats ? {
total: auditStats.total,
today: auditStats.todayCount,
byService: auditStats.byService,
recentCount: auditStats.recent.length
} : null,
frameworkServices: {
BoundaryEnforcer: 'ACTIVE',
MetacognitiveVerifier: 'ACTIVE',
ContextPressureMonitor: 'ACTIVE',
CrossReferenceValidator: 'ACTIVE',
InstructionPersistenceClassifier: 'ACTIVE',
PluralisticDeliberationOrchestrator: 'ACTIVE'
}
};
// Output formatted report
console.log('\n╔════════════════════════════════════════════════════════════════╗');
console.log('║ TRACTATUS FRAMEWORK STATISTICS (ffs) ║');
console.log('╚════════════════════════════════════════════════════════════════╝\n');
// Session Info
if (report.session) {
console.log('📊 SESSION');
console.log(` Session ID: ${report.session.sessionId}`);
console.log(` Start Time: ${new Date(report.session.startTime).toLocaleString()}`);
console.log(` Message Count: ${report.session.messageCount}`);
console.log(` Token Estimate: ${report.session.tokenEstimate?.toLocaleString() || 'N/A'}`);
console.log(` Action Count: ${report.session.actionCount || 0}`);
console.log(` Last Updated: ${new Date(report.session.lastUpdated).toLocaleString()}`);
console.log(` Initialized: ${report.session.initialized ? 'Yes' : 'No'}`);
console.log();
}
// Token Usage
if (report.tokenUsage && report.tokenUsage.budget) {
const next = report.tokenUsage.nextCheckpoint;
console.log('🎯 TOKEN BUDGET');
console.log(` Total Budget: ${report.tokenUsage.budget.toLocaleString()}`);
if (next) {
console.log(` Next Checkpoint: ${next.threshold.toLocaleString()} (${next.percentage}%)`);
}
const reached = report.tokenUsage.checkpoints.filter(c => c.reached).length;
console.log(` Checkpoints: ${reached}/${report.tokenUsage.checkpoints.length} reached`);
console.log();
}
// Context Pressure
if (report.contextPressure) {
console.log('⚠️ CONTEXT PRESSURE');
console.log(` Level: ${report.contextPressure.level}`);
console.log(` Overall Score: ${report.contextPressure.score}%`);
if (report.contextPressure.lastChecked) {
console.log(` Last Checked: ${new Date(report.contextPressure.lastChecked).toLocaleString()}`);
console.log(` At Message: #${report.contextPressure.messageNumber}`);
console.log(` Token Count: ${report.contextPressure.tokenCount?.toLocaleString() || 'N/A'}`);
}
if (report.contextPressure.timestamp) {
console.log(` Last Updated: ${new Date(report.contextPressure.timestamp).toLocaleString()}`);
}
if (report.contextPressure.metrics) {
console.log(' Metrics:');
Object.entries(report.contextPressure.metrics).forEach(([metric, data]) => {
if (data && typeof data === 'object' && 'normalized' in data) {
console.log(`${metric}: ${(data.normalized * 100).toFixed(1)}%`);
}
});
}
if (report.contextPressure.stats) {
console.log(' Analysis Count:', report.contextPressure.stats.analysis_count);
}
console.log();
}
// Auto-Compact Events
if (report.autoCompacts) {
console.log('🔄 AUTO-COMPACT EVENTS');
console.log(` Total Compactions: ${report.autoCompacts.total}`);
if (report.autoCompacts.total > 0) {
console.log('\n Recent Compactions:');
report.autoCompacts.events.slice(-5).forEach((event, idx) => {
console.log(`\n ${idx + 1}. ${new Date(event.timestamp).toLocaleString()}`);
console.log(` Message #${event.messageNumber}`);
console.log(` Tokens: ${event.beforeTokens?.toLocaleString()}${event.afterTokens?.toLocaleString()} (${event.reduction}% reduction)`);
if (event.pressureBefore) {
console.log(` Pressure: ${event.pressureBefore}${event.pressureAfter}`);
}
});
} else {
console.log(' No auto-compaction events recorded yet.');
console.log(' (Framework will log compactions as they occur)');
}
console.log();
}
// Component Statistics
if (report.componentStats && report.componentStats.length > 0) {
console.log('🔧 COMPONENT STATISTICS');
report.componentStats.forEach(comp => {
console.log(`\n ${comp.name}:`);
console.log(` Validations: ${comp.validations?.toLocaleString() || 'N/A'}`);
if (comp.blocks !== undefined) {
console.log(` Blocks Issued: ${comp.blocks}`);
}
if (comp.lastActivity) {
console.log(` Last Active: ${new Date(comp.lastActivity).toLocaleString()}`);
}
});
console.log();
}
// Instruction Stats
if (report.instructions) {
console.log('📋 INSTRUCTIONS');
console.log(` Total: ${report.instructions.total}`);
console.log(` Active: ${report.instructions.active}`);
console.log(` Inactive: ${report.instructions.inactive}`);
console.log(` Version: ${report.instructions.version}`);
console.log(' By Quadrant:');
Object.entries(report.instructions.byQuadrant).forEach(([quad, count]) => {
console.log(`${quad}: ${count}`);
});
console.log(' By Persistence:');
Object.entries(report.instructions.byPersistence).forEach(([pers, count]) => {
console.log(`${pers}: ${count}`);
});
console.log();
}
// Audit Logs
if (report.auditLogs) {
console.log('📝 AUDIT LOGS');
console.log(` Total Decisions: ${report.auditLogs.total}`);
console.log(` Today: ${report.auditLogs.today}`);
console.log(' By Service:');
Object.entries(report.auditLogs.byService)
.sort((a, b) => b[1] - a[1])
.forEach(([service, count]) => {
console.log(`${service}: ${count}`);
});
console.log();
}
// Framework Services
console.log('🔧 FRAMEWORK SERVICES');
Object.entries(report.frameworkServices).forEach(([service, status]) => {
const icon = status === 'ACTIVE' ? '✓' : '✗';
console.log(` ${icon} ${service}: ${status}`);
});
console.log();
console.log('╚════════════════════════════════════════════════════════════════╝\n');
// Also output JSON for programmatic access
console.log('\n// JSON OUTPUT FOR PROGRAMMATIC ACCESS:');
console.log(JSON.stringify(report, null, 2));
await mongoose.disconnect();
process.exit(0);
} catch (error) {
console.error('Error generating framework statistics:', error);
await mongoose.disconnect();
process.exit(1);
}
}
main();