feat(framework): add "ffs" trigger for framework statistics display
Implements inst_082 - on-demand framework operational metrics viewer. New Features: - framework-stats.js script displays comprehensive session statistics - Reports: session state, token usage, context pressure, instructions, audit logs - Formatted console output + JSON for programmatic access - Complementary to "ff" (Full Framework audit) trigger Statistics Reported: - Session: ID, message count, start time, status - Token Budget: usage, checkpoints (25%/50%/75%), next milestone - Context Pressure: level, overall score, metric breakdown - Instructions: total/active counts by quadrant and persistence - Audit Logs: total decisions, today's count, breakdown by service - Service Status: all 6 framework services (ACTIVE confirmation) Usage: User types "ffs" → Claude runs node scripts/framework-stats.js Files: scripts/framework-stats.js (new), CLAUDE.md:66-88, .claude/instruction-history.json (inst_082) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
fecc868797
commit
04d62ff92a
3 changed files with 402 additions and 0 deletions
24
CLAUDE.md
24
CLAUDE.md
|
|
@ -63,6 +63,30 @@ node scripts/framework-audit-response.js \
|
|||
|
||||
**See**: inst_078 in instruction-history.json
|
||||
|
||||
## 🔍 FRAMEWORK TRIGGER: "ffs"
|
||||
|
||||
When user types **ffs**, display full framework statistics:
|
||||
|
||||
```bash
|
||||
node scripts/framework-stats.js
|
||||
```
|
||||
|
||||
**Purpose**: On-demand visibility into framework operational metrics during session
|
||||
|
||||
**Reports**:
|
||||
- Session state (ID, message count, status)
|
||||
- Token usage & checkpoints (25%, 50%, 75%)
|
||||
- Context pressure level & metrics
|
||||
- Instruction counts (by quadrant/persistence)
|
||||
- Audit log counts (by service)
|
||||
- Framework service status (all 6 services)
|
||||
|
||||
**Output**: Formatted report + JSON for programmatic access
|
||||
|
||||
**When**: User wants to see framework health/activity at any point in session
|
||||
|
||||
**See**: inst_082 in instruction-history.json
|
||||
|
||||
---
|
||||
|
||||
## 🎯 QUICK REFERENCE
|
||||
|
|
|
|||
71
scripts/add-inst-082-ffs-trigger.js
Executable file
71
scripts/add-inst-082-ffs-trigger.js
Executable file
|
|
@ -0,0 +1,71 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Add inst_082: "ffs" Framework Stats Trigger
|
||||
* Adds instruction about the "ffs" codeword for viewing framework statistics
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const INSTRUCTION_FILE = path.join(__dirname, '../.claude/instruction-history.json');
|
||||
|
||||
// Load current instruction history
|
||||
const history = JSON.parse(fs.readFileSync(INSTRUCTION_FILE, 'utf8'));
|
||||
|
||||
// New instruction
|
||||
const newInstruction = {
|
||||
"id": "inst_082",
|
||||
"text": "When user types 'ffs' (Full Framework Stats), invoke framework-stats.js script to display comprehensive session statistics. Usage: node scripts/framework-stats.js. Reports: session state, token usage & checkpoints, context pressure level, instruction counts by quadrant/persistence, audit log counts by service, framework service status. Output formatted report + JSON for programmatic access.",
|
||||
"timestamp": new Date().toISOString(),
|
||||
"quadrant": "SYSTEM",
|
||||
"persistence": "HIGH",
|
||||
"temporal_scope": "PROJECT",
|
||||
"verification_required": "OPTIONAL",
|
||||
"explicitness": 0.95,
|
||||
"source": "user",
|
||||
"session_id": "2025-10-25-ffs-trigger-implementation",
|
||||
"parameters": {
|
||||
"trigger": "ffs",
|
||||
"script": "scripts/framework-stats.js",
|
||||
"purpose": "framework_statistics_display",
|
||||
"reports": [
|
||||
"session_state",
|
||||
"token_usage",
|
||||
"context_pressure",
|
||||
"instruction_stats",
|
||||
"audit_logs",
|
||||
"service_status"
|
||||
]
|
||||
},
|
||||
"active": true,
|
||||
"notes": "Complements 'ff' trigger (inst_078). Provides on-demand visibility into framework operational metrics."
|
||||
};
|
||||
|
||||
// Check if inst_082 already exists
|
||||
const existingIndex = history.instructions.findIndex(i => i.id === 'inst_082');
|
||||
|
||||
if (existingIndex >= 0) {
|
||||
console.log('⚠️ inst_082 already exists - updating...');
|
||||
history.instructions[existingIndex] = newInstruction;
|
||||
} else {
|
||||
console.log('✅ Adding new instruction: inst_082');
|
||||
history.instructions.push(newInstruction);
|
||||
}
|
||||
|
||||
// Update metadata
|
||||
history.version = "4.1";
|
||||
history.last_updated = new Date().toISOString();
|
||||
|
||||
// Write back
|
||||
fs.writeFileSync(INSTRUCTION_FILE, JSON.stringify(history, null, 2));
|
||||
|
||||
console.log('✅ inst_082 added successfully');
|
||||
console.log('📄 File:', INSTRUCTION_FILE);
|
||||
console.log('📊 Total instructions:', history.instructions.length);
|
||||
console.log('\nInstruction content:');
|
||||
console.log(' ID:', newInstruction.id);
|
||||
console.log(' Trigger:', newInstruction.parameters.trigger);
|
||||
console.log(' Script:', newInstruction.parameters.script);
|
||||
console.log(' Persistence:', newInstruction.persistence);
|
||||
console.log(' Quadrant:', newInstruction.quadrant);
|
||||
307
scripts/framework-stats.js
Executable file
307
scripts/framework-stats.js
Executable file
|
|
@ -0,0 +1,307 @@
|
|||
#!/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)) {
|
||||
return JSON.parse(fs.readFileSync(sessionStatePath, 'utf8'));
|
||||
}
|
||||
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.sessionId,
|
||||
startTime: sessionStats.startTime,
|
||||
messageCount: sessionStats.messageCount,
|
||||
status: sessionStats.status
|
||||
} : null,
|
||||
|
||||
tokenUsage: tokenCheckpoints ? {
|
||||
budget: tokenCheckpoints.tokenBudget,
|
||||
checkpoints: tokenCheckpoints.checkpoints,
|
||||
nextCheckpoint: tokenCheckpoints.checkpoints.find(c => !c.reached)
|
||||
} : null,
|
||||
|
||||
contextPressure: latestPressure ? {
|
||||
level: latestPressure.pressureLevel?.name || 'UNKNOWN',
|
||||
score: latestPressure.overallScore,
|
||||
timestamp: latestPressure.timestamp,
|
||||
metrics: latestPressure.metrics
|
||||
} : (monitorStats ? {
|
||||
level: 'UNKNOWN',
|
||||
score: 0,
|
||||
stats: monitorStats
|
||||
} : null),
|
||||
|
||||
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(` Status: ${report.session.status}`);
|
||||
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.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();
|
||||
}
|
||||
|
||||
// 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();
|
||||
Loading…
Add table
Reference in a new issue