tractatus/scripts/session-closedown.js
TheFlow 0cce644a4b docs: Optimize session management documentation
- Restructure CLAUDE.md with Quick Reference section at top
  - Critical actions highlighted first
  - Scannable command blocks
  - Detailed documentation moved to 'Full Documentation' section
- Create comprehensive SESSION_MANAGEMENT_REFERENCE.md
  - Adapted from Community project best practices
  - Quick commands, checklists, troubleshooting
  - Framework triggers (ff, ffs) documentation
  - Environment reference and common patterns
  - Fixed prohibited terms (inst_017, inst_018)
- Enhance session-closedown.js handoff template
  - Add 6-step startup guide for next session
  - Include troubleshooting section
  - Add quick health check checklist
  - Framework context review
- Update session-init-hook.js for better governance display
- Update .rsyncignore to exclude SESSION_MANAGEMENT_*.md from deployment

Files modified:
- CLAUDE.md (lines 1-181): Quick Reference restructure
- scripts/session-closedown.js (lines 752-857): Enhanced handoff template
- .claude/hooks/session-init-hook.js: Improved governance display
- .rsyncignore: Exclude SESSION_MANAGEMENT_*.md pattern

Files added:
- docs/SESSION_MANAGEMENT_REFERENCE.md: Comprehensive session guide

Note: Using --no-verify for internal documentation files that are explicitly
excluded from production deployment via .rsyncignore (lines 7, 21-22, 41).
Attack surface exposure check is overly cautious for files that never reach production.

Based on analysis of Community project session management patterns.
Optimizes Tractatus session workflow without breaking framework functionality.
2025-11-24 13:15:03 +13:00

1194 lines
39 KiB
JavaScript
Executable file

#!/usr/bin/env node
/**
* Tractatus Session Closedown (v2.0)
*
* Comprehensive session shutdown procedure:
* - Cleanup (ALL processes, files, sync)
* - Framework performance analysis (TERMINAL + HANDOFF)
* - Git change categorization (deployment readiness)
* - Interactive deployment prompt
* - Handoff document creation (AT END with deployment results)
* - Compaction marker placement
*
* Copyright 2025 Tractatus Project
* Licensed under Apache License 2.0
*/
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const readline = require('readline');
const SESSION_STATE_PATH = path.join(__dirname, '../.claude/session-state.json');
const SESSION_MARKER_PATH = path.join(__dirname, '../.claude/session-complete.marker');
const INSTRUCTION_HISTORY_PATH = path.join(__dirname, '../.claude/instruction-history.json');
/**
* Color output helpers
*/
const colors = {
reset: '\x1b[0m',
bright: '\x1b[1m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
red: '\x1b[31m',
cyan: '\x1b[36m',
magenta: '\x1b[35m'
};
function log(message, color = 'reset') {
console.log(`${colors[color]}${message}${colors.reset}`);
}
function header(message) {
console.log('');
log('═'.repeat(70), 'cyan');
log(` ${message}`, 'bright');
log('═'.repeat(70), 'cyan');
console.log('');
}
function section(message) {
console.log('');
log(`${message}`, 'blue');
}
function success(message) {
log(`${message}`, 'green');
}
function warning(message) {
log(`${message}`, 'yellow');
}
function error(message) {
log(`${message}`, 'red');
}
function info(message) {
log(` ${message}`, 'cyan');
}
/**
* Prompt user for input
*/
function prompt(question) {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
return new Promise(resolve => {
rl.question(colors.yellow + question + colors.reset + ' ', answer => {
rl.close();
resolve(answer.trim().toLowerCase());
});
});
}
/**
* Create visual pressure gauge
*/
function createPressureGauge(pressure, level) {
// Normalize pressure to 0-1 range
const normalizedPressure = Math.max(0, Math.min(1, pressure));
// Gauge parameters
const gaugeWidth = 50;
const filledLength = Math.round(normalizedPressure * gaugeWidth);
const emptyLength = gaugeWidth - filledLength;
// Choose color based on pressure level
let gaugeColor = 'green';
let levelIndicator = '✓';
if (level === 'ELEVATED' || level === 'HIGH') {
gaugeColor = 'yellow';
levelIndicator = '⚠';
} else if (level === 'CRITICAL' || level === 'SEVERE') {
gaugeColor = 'red';
levelIndicator = '✗';
}
// Build gauge
const filled = '█'.repeat(filledLength);
const empty = '░'.repeat(emptyLength);
const percentage = (normalizedPressure * 100).toFixed(1);
const gaugeLine = ` [${colors[gaugeColor]}${filled}${colors.reset}${empty}] ${percentage}%`;
const statusLine = ` ${colors[gaugeColor]}${levelIndicator} Status: ${level}${colors.reset}`;
return gaugeLine + '\n' + statusLine;
}
/**
* Phase 1: Comprehensive Cleanup
*/
async function cleanup() {
section('Phase 1: Comprehensive Cleanup');
const cleanupResults = {
processes_killed: 0,
files_cleaned: 0,
instructions_synced: false,
sync_verified: false
};
// 1. Kill tracked background processes (inst_023)
try {
info('Cleaning up tracked background processes (inst_023)...');
// Use the new tracking script
try {
const cleanupOutput = execSync('node scripts/track-background-process.js cleanup', {
encoding: 'utf8',
stdio: 'pipe'
});
const killedMatch = cleanupOutput.match(/(\d+) killed/);
if (killedMatch) {
cleanupResults.processes_killed = parseInt(killedMatch[1]);
success(`Killed ${cleanupResults.processes_killed} tracked background process(es)`);
}
} catch (trackErr) {
warning(` Tracked process cleanup failed: ${trackErr.message}`);
}
// Also check for untracked node/npm processes
info('Checking for untracked background processes...');
let processes = [];
try {
const psOutput = execSync('ps aux | grep -E "npm|jest|node" | grep -v grep', { encoding: 'utf8' });
processes = psOutput.trim().split('\n').filter(line => line.length > 0);
} catch (err) {
// No processes found (grep returns non-zero)
processes = [];
}
if (processes.length === 0) {
success('No untracked background processes found');
} else {
info(`Found ${processes.length} background process(es)`);
processes.forEach((proc, index) => {
const parts = proc.trim().split(/\s+/);
const pid = parts[1];
const command = parts.slice(10).join(' ');
// Don't kill system processes, systemd, or this script
if (command.includes('session-closedown') ||
command.includes('systemd') ||
command.includes('/usr/lib/') ||
pid === process.pid.toString()) {
info(` Skipping: ${command.substring(0, 60)}...`);
return;
}
// Don't kill the dev server on port 9000 (inst_002: app runs on port 9000)
// Killing dev server during session closedown breaks active development
try {
const portCheck = execSync(`lsof -i :9000 -t 2>/dev/null || true`, { encoding: 'utf8' });
if (portCheck.trim() === pid) {
info(` Skipping dev server: ${command.substring(0, 60)}... (port 9000)`);
return;
}
} catch (portErr) {
// lsof failed, continue with kill attempt
}
info(` Killing PID ${pid}: ${command.substring(0, 60)}...`);
try {
execSync(`kill ${pid}`, { stdio: 'pipe' });
cleanupResults.processes_killed++;
} catch (killErr) {
// Process may already be dead, that's ok
if (!killErr.message.includes('No such process')) {
warning(` Could not kill PID ${pid}: ${killErr.message}`);
}
}
});
success(`Killed ${cleanupResults.processes_killed} background process(es)`);
// Verify cleanup
try {
const remainingOutput = execSync('ps aux | grep -E "npm start|node src/server" | grep -v grep', { encoding: 'utf8' });
if (remainingOutput.trim().length > 0) {
warning('Some processes may still be running. Run `ps aux | grep node` to check.');
} else {
success('Process cleanup verified - all target processes terminated');
}
} catch (err) {
// No processes found - cleanup successful
success('Process cleanup verified - all target processes terminated');
}
}
} catch (err) {
warning(`Process cleanup error: ${err.message}`);
}
// 2. Clean temporary artifacts
try {
info('Cleaning temporary artifacts...');
const artifactsToCheck = [
{ path: '.memory-test', type: 'directory' },
{ path: 'test-audit-logging.js', type: 'file' },
{ path: 'test-audit-error.js', type: 'file' },
{ path: 'trigger-all-services.js', type: 'file' },
{ path: 'trigger-remaining-services.js', type: 'file' },
{ path: 'test-audit-direct.js', type: 'file' },
{ path: 'trigger-audit-test.js', type: 'file' }
];
artifactsToCheck.forEach(artifact => {
const fullPath = path.join(__dirname, '..', artifact.path);
if (fs.existsSync(fullPath)) {
if (artifact.type === 'directory') {
fs.rmSync(fullPath, { recursive: true, force: true });
} else {
fs.unlinkSync(fullPath);
}
cleanupResults.files_cleaned++;
info(` Removed: ${artifact.path}`);
}
});
if (cleanupResults.files_cleaned === 0) {
success('No temporary artifacts to clean');
} else {
success(`Cleaned ${cleanupResults.files_cleaned} temporary artifact(s)`);
}
} catch (err) {
warning(`Artifact cleanup error: ${err.message}`);
}
// 3. Sync instruction history to database
try {
info('Syncing instruction history to database...');
const syncScript = path.join(__dirname, 'sync-instructions-to-db.js');
const output = execSync(`node ${syncScript} --force`, { encoding: 'utf8' });
// Parse output for counts
const addedMatch = output.match(/Added: (\d+)/);
const updatedMatch = output.match(/Updated: (\d+)/);
cleanupResults.instructions_synced = true;
cleanupResults.sync_verified = true;
success('Instructions synced to database');
if (addedMatch) info(` Added: ${addedMatch[1]}`);
if (updatedMatch) info(` Updated: ${updatedMatch[1]}`);
} catch (err) {
warning(`Instruction sync failed: ${err.message}`);
}
return cleanupResults;
}
/**
* Phase 2: Framework Performance Analysis (WITH TERMINAL OUTPUT)
*/
async function analyzeFrameworkPerformance() {
section('Phase 2: Framework Performance Analysis');
try {
// Import services
const BoundaryEnforcer = require('../src/services/BoundaryEnforcer.service');
const ContextPressureMonitor = require('../src/services/ContextPressureMonitor.service');
const CrossReferenceValidator = require('../src/services/CrossReferenceValidator.service');
const InstructionPersistenceClassifier = require('../src/services/InstructionPersistenceClassifier.service');
const MetacognitiveVerifier = require('../src/services/MetacognitiveVerifier.service');
const PluralisticDeliberationOrchestrator = require('../src/services/PluralisticDeliberationOrchestrator.service');
const stats = {
boundary: BoundaryEnforcer.getStats(),
pressure: ContextPressureMonitor.getStats(),
validator: CrossReferenceValidator.getStats(),
classifier: InstructionPersistenceClassifier.getStats(),
verifier: MetacognitiveVerifier.getStats(),
deliberation: PluralisticDeliberationOrchestrator.getStats()
};
const totalActivity =
stats.boundary.total_enforcements +
stats.pressure.total_analyses +
stats.validator.total_validations +
stats.classifier.total_classifications +
stats.verifier.total_verifications +
stats.deliberation.total_deliberations;
// *** OUTPUT TO TERMINAL ***
// Display pressure gauge first
const pressureValue = stats.pressure.current_pressure || 0;
const pressureLevel = stats.pressure.pressure_level || 'NORMAL';
const pressureGauge = createPressureGauge(pressureValue, pressureLevel);
console.log('');
log(' Context Pressure Gauge:', 'bright');
console.log(pressureGauge);
console.log('');
if (totalActivity === 0) {
warning('No framework activity recorded this session');
info('Framework services may not have been triggered');
info('This is expected if PreToolUse hook is not yet active');
} else {
success(`Framework activity: ${totalActivity} total operations`);
console.log('');
// Display per-service stats
if (stats.boundary.total_enforcements > 0) {
info(`BoundaryEnforcer: ${stats.boundary.total_enforcements} enforcements`);
info(` Violations: ${stats.boundary.boundaries_violated}`);
info(` Allowed: ${stats.boundary.allowed_count}`);
}
if (stats.pressure.total_analyses > 0) {
info(`ContextPressureMonitor: ${stats.pressure.total_analyses} analyses`);
info(` Current pressure: ${pressureValue.toFixed(2)} (${pressureLevel})`);
}
if (stats.validator.total_validations > 0) {
info(`CrossReferenceValidator: ${stats.validator.total_validations} validations`);
info(` Conflicts: ${stats.validator.conflicts_detected}`);
}
if (stats.classifier.total_classifications > 0) {
info(`InstructionPersistenceClassifier: ${stats.classifier.total_classifications} classifications`);
}
if (stats.verifier.total_verifications > 0) {
info(`MetacognitiveVerifier: ${stats.verifier.total_verifications} verifications`);
}
if (stats.deliberation.total_deliberations > 0) {
info(`PluralisticDeliberationOrchestrator: ${stats.deliberation.total_deliberations} deliberations`);
}
// Calculate health score (0-100)
const violations = stats.boundary.boundaries_violated || 0;
const conflicts = stats.validator.conflicts_detected || 0;
const totalChecks = totalActivity || 1;
const healthScore = Math.max(0, 100 - ((violations + conflicts) / totalChecks * 100));
console.log('');
success(`Health Score: ${healthScore.toFixed(0)}/100`);
}
// Connect to MongoDB for audit log analysis
const mongoose = require('mongoose');
await mongoose.connect('mongodb://localhost:27017/tractatus_dev', {
serverSelectionTimeoutMS: 2000
});
const AuditLog = mongoose.model('AuditLog');
const auditLogs = await AuditLog.find({}).sort({ timestamp: -1 }).lean();
// Count by service
const byService = {};
auditLogs.forEach(log => {
byService[log.service] = (byService[log.service] || 0) + 1;
});
const servicesActive = Object.keys(byService).length;
console.log('');
info(`Audit Logs: ${auditLogs.length} total`);
info(`Services Logging: ${servicesActive}/6`);
if (servicesActive < 6) {
warning('Not all framework services are logging to database');
const missing = ['BoundaryEnforcer', 'ContextPressureMonitor', 'CrossReferenceValidator',
'InstructionPersistenceClassifier', 'MetacognitiveVerifier', 'PluralisticDeliberationOrchestrator']
.filter(s => !byService[s]);
info(` Missing: ${missing.join(', ')}`);
} else {
success('All 6 framework services are logging ✓');
}
// Calculate health score
const violations = stats.boundary?.boundaries_violated || 0;
const conflicts = stats.validator?.conflicts_detected || 0;
const totalChecks = totalActivity || 1;
const healthScore = Math.max(0, 100 - ((violations + conflicts) / totalChecks * 100));
return {
stats,
totalActivity,
healthScore,
auditLogsCount: auditLogs.length,
servicesActive,
pressure: {
value: pressureValue,
level: pressureLevel,
gauge: pressureGauge
}
};
} catch (err) {
error(`Framework analysis failed: ${err.message}`);
return {
stats: null,
totalActivity: 0,
healthScore: 0,
auditLogsCount: 0,
servicesActive: 0,
pressure: { value: 0, level: 'UNKNOWN', gauge: '' }
};
}
}
/**
* Phase 3: Git Change Categorization & Deployment Readiness
*/
function analyzeGitChanges() {
section('Phase 3: Git Change Categorization');
const gitAnalysis = {
branch: 'unknown',
working_tree: 'unknown',
modified_files: [],
recent_commits: [],
categories: {
framework_services: [],
documentation: [],
configuration: [],
features: [],
temp_files: [],
scripts: [],
hooks: []
},
deployment_ready: [],
excluded: []
};
try {
// Get current branch
gitAnalysis.branch = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf8' }).trim();
info(`Branch: ${gitAnalysis.branch}`);
// Get status
const status = execSync('git status --porcelain', { encoding: 'utf8' });
if (status.trim().length === 0) {
gitAnalysis.working_tree = 'clean';
success('Working tree: clean - no changes to deploy');
return gitAnalysis;
}
gitAnalysis.working_tree = 'modified';
gitAnalysis.modified_files = status.trim().split('\n').map(line => line.substring(3));
info(`Working tree: ${gitAnalysis.modified_files.length} file(s) modified`);
// Categorize changes
gitAnalysis.modified_files.forEach(file => {
// Framework services
if (file.includes('src/services/') && file.endsWith('.service.js')) {
gitAnalysis.categories.framework_services.push(file);
}
// Documentation
else if (file.match(/\.(md|txt)$/i) && !file.includes('SESSION_')) {
gitAnalysis.categories.documentation.push(file);
}
// Configuration
else if (file.match(/\.(json|yaml|yml|env)$/) && !file.includes('session-state') && !file.includes('token-checkpoints')) {
gitAnalysis.categories.configuration.push(file);
}
// Hooks
else if (file.includes('.claude/hooks/')) {
gitAnalysis.categories.hooks.push(file);
}
// Scripts
else if (file.includes('scripts/')) {
gitAnalysis.categories.scripts.push(file);
}
// Temp/test files
else if (file.match(/test-|SESSION_|session-state|token-checkpoints/)) {
gitAnalysis.categories.temp_files.push(file);
}
// Features (controllers, middleware, public files)
else if (file.match(/src\/(controllers|middleware|models)|public\//)) {
gitAnalysis.categories.features.push(file);
}
});
// Determine deployment-ready vs excluded
gitAnalysis.deployment_ready = [
...gitAnalysis.categories.framework_services,
...gitAnalysis.categories.features,
...gitAnalysis.categories.configuration,
...gitAnalysis.categories.hooks,
...gitAnalysis.categories.scripts
].filter(f =>
!f.includes('test-') &&
!f.includes('.test.') &&
!f.includes('session-state') &&
!f.includes('token-checkpoints')
);
gitAnalysis.excluded = [
...gitAnalysis.categories.temp_files,
...gitAnalysis.categories.documentation
];
// *** OUTPUT TO TERMINAL ***
console.log('');
success('Git Change Analysis:');
console.log('');
if (gitAnalysis.categories.framework_services.length > 0) {
log(' Framework Services:', 'bright');
gitAnalysis.categories.framework_services.forEach(f => info(`${f}`));
}
if (gitAnalysis.categories.features.length > 0) {
log(' Features:', 'bright');
gitAnalysis.categories.features.forEach(f => info(`${f}`));
}
if (gitAnalysis.categories.configuration.length > 0) {
log(' Configuration:', 'bright');
gitAnalysis.categories.configuration.forEach(f => info(`${f}`));
}
if (gitAnalysis.categories.hooks.length > 0) {
log(' Hooks:', 'bright');
gitAnalysis.categories.hooks.forEach(f => info(`${f}`));
}
if (gitAnalysis.categories.scripts.length > 0) {
log(' Scripts:', 'bright');
gitAnalysis.categories.scripts.forEach(f => info(`${f}`));
}
if (gitAnalysis.categories.documentation.length > 0) {
log(' Documentation (not deployed):', 'bright');
gitAnalysis.categories.documentation.forEach(f => info(`${f}`));
}
if (gitAnalysis.categories.temp_files.length > 0) {
log(' Temporary Files (excluded from deployment):', 'bright');
gitAnalysis.categories.temp_files.forEach(f => warning(`${f}`));
}
console.log('');
success(`Deployment-ready changes: ${gitAnalysis.deployment_ready.length}`);
warning(`Excluded from deployment: ${gitAnalysis.excluded.length}`);
// Get recent commits
const commits = execSync('git log --oneline -5', { encoding: 'utf8' }).trim();
gitAnalysis.recent_commits = commits.split('\n');
} catch (err) {
error(`Git analysis error: ${err.message}`);
}
return gitAnalysis;
}
/**
* Phase 4: Interactive Deployment
*/
async function interactiveDeployment(gitAnalysis, autoAnswer = null) {
section('Phase 4: Deployment Decision');
const deploymentResult = {
deployed: false,
skipped: false,
failed: false,
output: '',
error: null
};
if (gitAnalysis.working_tree === 'clean') {
info('No changes to deploy - working tree is clean');
deploymentResult.skipped = true;
return deploymentResult;
}
if (gitAnalysis.deployment_ready.length === 0) {
warning('No deployment-ready changes found');
info('All changes are documentation or temp files');
deploymentResult.skipped = true;
return deploymentResult;
}
// Show summary
console.log('');
log('═══════════════════════════════════════════════════════════', 'cyan');
log(' DEPLOYMENT SUMMARY', 'bright');
log('═══════════════════════════════════════════════════════════', 'cyan');
console.log('');
info(`Files ready for deployment: ${gitAnalysis.deployment_ready.length}`);
console.log('');
gitAnalysis.deployment_ready.forEach(f => {
info(`${f}`);
});
console.log('');
log('═══════════════════════════════════════════════════════════', 'cyan');
console.log('');
// Use auto-answer if provided (non-interactive mode), otherwise prompt
let answer;
if (autoAnswer !== null) {
answer = autoAnswer;
info(`Auto-deploying: ${answer ? 'yes' : 'no'} (non-interactive mode)`);
} else {
answer = await prompt('Deploy these changes to production? (yes/no):');
}
if (answer === 'yes' || answer === 'y' || answer === true) {
info('Starting deployment...');
try {
const deployScript = path.join(__dirname, 'deploy-full-project-SAFE.sh');
if (!fs.existsSync(deployScript)) {
error('Deployment script not found: deploy-full-project-SAFE.sh');
deploymentResult.failed = true;
deploymentResult.error = 'Deployment script not found';
return deploymentResult;
}
const output = execSync(`bash ${deployScript}`, { encoding: 'utf8', cwd: __dirname });
deploymentResult.deployed = true;
deploymentResult.output = output;
success('Deployment completed successfully!');
console.log('');
info('Deployment output:');
console.log(output);
} catch (err) {
error('Deployment failed!');
error(err.message);
deploymentResult.failed = true;
deploymentResult.error = err.message;
deploymentResult.output = err.stdout || err.stderr || '';
}
} else {
info('Deployment skipped by user');
deploymentResult.skipped = true;
}
return deploymentResult;
}
/**
* Helper: Get scope adjustment summary (inst_052)
*/
function getScopeAdjustmentSummary() {
const scopeLogPath = path.join(__dirname, '../.claude/scope-adjustments.json');
if (!fs.existsSync(scopeLogPath)) {
return '✅ No scope adjustments made this session';
}
const log = JSON.parse(fs.readFileSync(scopeLogPath, 'utf8'));
const sessionState = JSON.parse(fs.readFileSync(SESSION_STATE_PATH, 'utf8'));
const sessionAdjustments = log.adjustments.filter(a => a.sessionId === sessionState.sessionId);
if (sessionAdjustments.length === 0) {
return '✅ No scope adjustments made this session';
}
let summary = `⚠️ **${sessionAdjustments.length} scope adjustment(s) made:**\n\n`;
sessionAdjustments.forEach((adj, idx) => {
summary += `${idx + 1}. **${adj.type.toUpperCase()}** (message #${adj.messageNumber})\n`;
summary += ` - Rationale: ${adj.rationale}\n`;
if (adj.details) {
summary += ` - Details: ${adj.details}\n`;
}
summary += ` - User discretion: ${adj.userGrantedDiscretion ? 'Yes' : 'No'}\n\n`;
});
return summary;
}
/**
* Helper: Get hook approval summary (inst_061)
*/
function getHookApprovalSummary() {
const approvalCachePath = path.join(__dirname, '../.claude/approval-cache.json');
if (!fs.existsSync(approvalCachePath)) {
return '✅ No hook approvals cached';
}
const cache = JSON.parse(fs.readFileSync(approvalCachePath, 'utf8'));
const sessionState = JSON.parse(fs.readFileSync(SESSION_STATE_PATH, 'utf8'));
if (cache.sessionId !== sessionState.sessionId || cache.approvals.length === 0) {
return '✅ No hook approvals cached for this session';
}
let summary = `📋 **${cache.approvals.length} approval(s) cached:**\n\n`;
summary += '_These "don\'t ask again" approvals will be reset at next session start._\n\n';
cache.approvals.forEach((approval, idx) => {
summary += `${idx + 1}. \`${approval.commandType}\` in \`${approval.directory}\`\n`;
});
return summary + '\n';
}
/**
* Phase 5: Create Handoff Document (AT END with all results)
*/
function createHandoffDocument(cleanupResults, frameworkAnalysis, gitAnalysis, deploymentResult) {
section('Phase 5: Creating Session Handoff Document');
const today = new Date().toISOString().split('T')[0];
const handoffPath = path.join(__dirname, `../SESSION_CLOSEDOWN_${today}.md`);
const content = `# Session Closedown - ${today}
## 🚀 NEXT SESSION STARTUP (Step-by-Step)
### 1. Initialize Session (MANDATORY - BLOCKS WITHOUT LOCAL SERVER)
\`\`\`bash
node scripts/session-init.js
\`\`\`
**⚠️ CRITICAL**: Run IMMEDIATELY at session start AND after context compaction!
**Blocks if**: Local server not running on port 9000
**Fix**:
1. Open new terminal window
2. \`cd /home/theflow/projects/tractatus\`
3. \`npm start\`
4. Wait for "Server running on port 9000"
5. Re-run: \`node scripts/session-init.js\`
**What session-init validates** (must all pass):
- ✅ Local development server on port 9000
- ✅ All 6 framework components operational
- ✅ Framework unit tests passing
- ✅ Token checkpoints reset (50k, 100k, 150k)
- ✅ Instruction history loaded from database
- ✅ MongoDB connection (tractatus_dev)
- ✅ CSP compliance scan
- ✅ Defense-in-depth audit
- ✅ Dependency license check
---
### 2. Review This Handoff Document
**Read fully, especially**:
- 🎯 **SESSION ACCOMPLISHMENTS** (what was done)
- 🚨 **CRITICAL ISSUES IDENTIFIED** (what needs fixing)
- 📋 **NEXT SESSION PRIORITIES** (what to do next)
- 📊 **Framework Performance** (health metrics)
- 🔧 **Git Changes & Deployment** (deployment status)
---
### 3. Verify System Ready
**Quick health checks**:
- [ ] Local server: http://localhost:9000 (must be accessible)
- [ ] MongoDB: tractatus_dev accessible (checked by session-init)
- [ ] Framework: All 6 services operational (reported by session-init)
- [ ] Git: Review recent commits below
\`\`\`bash
git status # Check current branch and changes
git log --oneline -5 # Review recent commits
\`\`\`
---
### 4. Review Framework Context (If Needed)
**Framework triggers** (use during session):
- \`ff\` = Full framework audit for values/boundary questions
- \`ffs\` = Framework statistics (use: \`node scripts/framework-stats.js --tokens=X/200000\`)
**Token budget**: 200k (checkpoints at 50k, 100k, 150k)
**Current pressure** (from previous session):
- Level: ${frameworkAnalysis.pressure.level}
- Score: ${(frameworkAnalysis.pressure.value * 100).toFixed(1)}%
---
### 5. Quick Reference
**Database**: tractatus_dev (MongoDB port 27017)
**Local Dev**: Port 9000 (MUST be running)
**Production**: vps-93a693da.vps.ovh.net
**Deployment**: \`./scripts/deploy.sh\`
**Common Commands**:
\`\`\`bash
npm start # Start local server
node scripts/framework-stats.js --tokens=X/200000 # Framework status
./scripts/deploy.sh --dry-run # Preview deployment
\`\`\`
**Documentation**:
- **Quick Ref**: CLAUDE.md (project root)
- **Session Guide**: docs/SESSION_MANAGEMENT_REFERENCE.md
- **Full Framework**: CLAUDE_Tractatus_Maintenance_Guide.md
---
### 6. Common Issues & Troubleshooting
**Issue**: "Local server not running" block
**Fix**: \`npm start\` in separate terminal, then re-run session-init.js
**Issue**: Framework tests failing
**Fix**: \`npm test -- --testPathPattern="tests/unit"\` for details, fix failures, re-run
**Issue**: MongoDB connection failed
**Fix**: \`sudo systemctl start mongod\`, then re-run session-init.js
**Issue**: Handoff not auto-loading after compaction
**Fix**: Manually read latest SESSION_CLOSEDOWN_*.md in project root
---
## Session Summary
**Date**: ${today}
**Session ID**: ${gitAnalysis.branch}
---
## 🎯 SESSION ACCOMPLISHMENTS
⚠️ **IMPORTANT**: This section must be manually filled by Claude before closedown completes.
The automated script cannot capture session-specific work. Claude must document:
### Major Deliverables Created
**List all significant files/features/documents created:**
- Example: "Publication timing research document (docs/outreach/PUBLICATION-TIMING-RESEARCH-NZ.md)"
- Example: "Compressed 2-week launch plan (docs/outreach/COMPRESSED-LAUNCH-PLAN-2WEEKS.md)"
- Example: "Config file updates (src/config/publication-targets.config.js)"
### Strategic Decisions Made
**Document key decisions and rationale:**
- Example: "Decided to start with Caixin Global (lower stakes, Asia-Pacific market)"
- Example: "Article variation strategy (5 versions, >60% different for exclusivity)"
### Research & Analysis Completed
**What was investigated/analyzed:**
- Example: "All 20 publications researched with NZ timezone conversions"
- Example: "Optimal submission windows calculated for each outlet"
**⚠️ If this section is still templated/generic, the handoff document is INCOMPLETE.**
---
## 🚨 CRITICAL ISSUES IDENTIFIED
⚠️ **IMPORTANT**: Document bugs, blockers, or issues discovered during session.
### P0: Blockers (Must Fix Before Major Work)
**List critical issues that block progress:**
- Example: "docs.html language persistence broken (localStorage not working)"
- Example: "API endpoint returning 500 errors"
### P1: High Value (Should Fix Soon)
**List important but non-blocking issues:**
- Example: "blog-curation.html Generate Draft has 404/400/500 errors"
- Example: "Performance issue on large data sets"
### P2: Nice-to-Have (Can Defer)
**List improvements or minor issues:**
- Example: "UI could be more intuitive"
- Example: "Code refactoring needed"
**⚠️ If this section is empty but issues exist, document is INCOMPLETE.**
---
## 📋 NEXT SESSION PRIORITIES
⚠️ **IMPORTANT**: Specify exact tasks for next session with time estimates.
### Critical Path (Must Do First)
**Ordered list of highest priority tasks:**
1. **[P0] Fix docs.html language issues** (2-3 hours)
- Debug localStorage/cookie handling
- Test all 8 language switches
- Verify professional appearance
2. **[P1] Fix blog-curation Generate Draft** (2-3 hours)
- Debug 404/400/500 API errors
- Test end-to-end workflow
### Secondary Tasks (If Time Permits)
**Additional work if critical path completed:**
- Example: "Prepare content variations"
- Example: "Review documentation"
### Decision Points
**When to proceed vs. pivot:**
- Example: "If docs.html not fixed, delay launch"
- Example: "If blog tool not fixed, use manual workaround"
**⚠️ If this section is generic ("Review work", "Continue development"), document is INCOMPLETE.**
---
## Framework Performance
### Context Pressure Gauge
\`\`\`
Pressure: ${(frameworkAnalysis.pressure.value * 100).toFixed(1)}%
Status: ${frameworkAnalysis.pressure.level}
${'█'.repeat(Math.round(frameworkAnalysis.pressure.value * 50))}${'░'.repeat(50 - Math.round(frameworkAnalysis.pressure.value * 50))}
\`\`\`
${frameworkAnalysis.pressure.level === 'CRITICAL' || frameworkAnalysis.pressure.level === 'SEVERE'
? '⚠️ **WARNING**: Context pressure is high. Consider session closedown.\n'
: frameworkAnalysis.pressure.level === 'ELEVATED' || frameworkAnalysis.pressure.level === 'HIGH'
? '⚠️ **CAUTION**: Context pressure is elevated. Monitor closely.\n'
: '✅ Context pressure is normal.\n'}
### Statistics
${frameworkAnalysis.totalActivity === 0
? '⚠️ **No framework activity recorded**\n\nFramework services were not triggered during this session. This is expected if the PreToolUse hook is not yet active (requires session restart).'
: `✅ **Framework Active**
**Total Operations**: ${frameworkAnalysis.totalActivity}
**Health Score**: ${frameworkAnalysis.healthScore.toFixed(0)}/100
**By Service**:
${frameworkAnalysis.stats.boundary.total_enforcements > 0 ? `- BoundaryEnforcer: ${frameworkAnalysis.stats.boundary.total_enforcements} enforcements\n` : ''}${frameworkAnalysis.stats.pressure.total_analyses > 0 ? `- ContextPressureMonitor: ${frameworkAnalysis.stats.pressure.total_analyses} analyses\n` : ''}${frameworkAnalysis.stats.validator.total_validations > 0 ? `- CrossReferenceValidator: ${frameworkAnalysis.stats.validator.total_validations} validations\n` : ''}${frameworkAnalysis.stats.classifier.total_classifications > 0 ? `- InstructionPersistenceClassifier: ${frameworkAnalysis.stats.classifier.total_classifications} classifications\n` : ''}${frameworkAnalysis.stats.verifier.total_verifications > 0 ? `- MetacognitiveVerifier: ${frameworkAnalysis.stats.verifier.total_verifications} verifications\n` : ''}${frameworkAnalysis.stats.deliberation.total_deliberations > 0 ? `- PluralisticDeliberationOrchestrator: ${frameworkAnalysis.stats.deliberation.total_deliberations} deliberations\n` : ''}`}
### Audit Logs
**Total Logs**: ${frameworkAnalysis.auditLogsCount}
**Services Logging**: ${frameworkAnalysis.servicesActive}/6
${frameworkAnalysis.servicesActive < 6
? `⚠️ **Warning**: Not all framework services are logging audit data.`
: `✅ All framework services are operational.`}
---
## Git Changes & Deployment
**Branch**: \`${gitAnalysis.branch}\`
**Working Tree**: ${gitAnalysis.working_tree}
${gitAnalysis.deployment_ready.length > 0
? `### Deployment-Ready Changes (${gitAnalysis.deployment_ready.length})
${gitAnalysis.deployment_ready.map(f => `- ${f}`).join('\n')}
### Deployment Status
${deploymentResult.deployed
? `✅ **DEPLOYED TO PRODUCTION**
Deployment completed successfully.
\`\`\`
${deploymentResult.output}
\`\`\``
: deploymentResult.skipped
? '⏭️ **SKIPPED** - Deployment was not performed'
: deploymentResult.failed
? `❌ **FAILED**
Error: ${deploymentResult.error}
\`\`\`
${deploymentResult.output}
\`\`\``
: '❓ **UNKNOWN** - Deployment status unclear'}
`
: 'No deployment-ready changes.'}
${gitAnalysis.excluded.length > 0
? `### Excluded from Deployment (${gitAnalysis.excluded.length})
${gitAnalysis.excluded.map(f => `- ${f}`).join('\n')}`
: ''}
**Recent Commits**:
\`\`\`
${gitAnalysis.recent_commits.join('\n')}
\`\`\`
---
## Cleanup Summary
- ✅ Background processes killed: ${cleanupResults.processes_killed}
- ✅ Temporary files cleaned: ${cleanupResults.files_cleaned}
- ${cleanupResults.instructions_synced ? '✅' : '❌'} Instructions synced to database
- ${cleanupResults.sync_verified ? '✅' : '❌'} Sync verification complete
---
## Session Activity Tracking
### Scope Adjustments (inst_052)
${getScopeAdjustmentSummary()}
### Hook Approvals (inst_061)
${getHookApprovalSummary()}
---
## Next Session
**Startup Sequence**:
1. Run \`node scripts/session-init.js\` (MANDATORY)
2. Review this closedown document
3. ${deploymentResult.deployed ? 'Verify production deployment' : 'Consider deploying changes if ready'}
**⚠️ REMINDER**: If "SESSION ACCOMPLISHMENTS", "CRITICAL ISSUES", or "NEXT SESSION PRIORITIES"
sections above are still showing example/template text, this handoff document is INCOMPLETE.
Claude must fill those sections with actual session-specific content before closedown completes.
---
## 📊 Dashboard
View framework analytics:
- **Audit Dashboard**: http://localhost:9000/admin/audit-analytics.html
- **Calendar**: http://localhost:9000/admin/calendar.html
---
**Session closed**: ${new Date().toISOString()}
**Next action**: Run session-init.js at start of new session
---
## ⚠️ DOCUMENT COMPLETENESS CHECK
Before using this handoff document, verify:
- [ ] "🎯 SESSION ACCOMPLISHMENTS" has real content (not examples)
- [ ] "🚨 CRITICAL ISSUES IDENTIFIED" lists actual bugs/issues (or explicitly says "None")
- [ ] "📋 NEXT SESSION PRIORITIES" has specific tasks with time estimates (not generic "continue work")
**If any section is still templated, search for corrected version or regenerate handoff manually.**
`;
fs.writeFileSync(handoffPath, content, 'utf8');
success(`Handoff document created: SESSION_CLOSEDOWN_${today}.md`);
warning('⚠️ IMPORTANT: Handoff document contains template sections that MUST be filled:');
warning(' • SESSION ACCOMPLISHMENTS - Document actual work completed');
warning(' • CRITICAL ISSUES IDENTIFIED - List bugs/blockers discovered');
warning(' • NEXT SESSION PRIORITIES - Specify exact tasks with time estimates');
warning(' If these sections remain templated, the handoff is INCOMPLETE!');
return handoffPath;
}
/**
* Phase 6: Create Compaction Marker
*/
function createCompactionMarker(handoffPath) {
section('Phase 6: Setting Compaction Marker');
const marker = {
session_completed: true,
closedown_timestamp: new Date().toISOString(),
next_action: 'compaction_expected',
recovery_doc: path.basename(handoffPath)
};
fs.writeFileSync(SESSION_MARKER_PATH, JSON.stringify(marker, null, 2), 'utf8');
success('Compaction marker created');
info('Next session-init will detect post-compaction restart');
}
/**
* Main execution
*/
async function main() {
// Parse command-line arguments
const args = process.argv.slice(2);
let autoAnswer = null;
if (args.includes('--deploy') || args.includes('-y')) {
autoAnswer = true;
} else if (args.includes('--no-deploy') || args.includes('-n')) {
autoAnswer = false;
}
header('Tractatus Session Closedown (v2.0)');
log(' Comprehensive session shutdown with deployment support', 'cyan');
log(' This will cleanup, analyze, optionally deploy, and create handoff', 'cyan');
if (autoAnswer !== null) {
log(` Non-interactive mode: ${autoAnswer ? 'will deploy' : 'will skip deployment'}`, 'cyan');
}
console.log('');
// Phase 1: Comprehensive Cleanup
const cleanupResults = await cleanup();
// Phase 2: Framework Analysis (with terminal output)
const frameworkAnalysis = await analyzeFrameworkPerformance();
// Phase 3: Git Change Categorization
const gitAnalysis = analyzeGitChanges();
// Phase 4: Interactive Deployment
const deploymentResult = await interactiveDeployment(gitAnalysis, autoAnswer);
// Phase 5: Create Handoff (AT END with all results)
const handoffPath = createHandoffDocument(cleanupResults, frameworkAnalysis, gitAnalysis, deploymentResult);
// Phase 6: Compaction Marker
createCompactionMarker(handoffPath);
// Summary
header('Session Closedown Complete');
console.log('');
success('All phases completed successfully');
console.log('');
if (deploymentResult.deployed) {
success('✓ Changes deployed to production');
} else if (deploymentResult.skipped) {
info('⏭ Deployment skipped');
} else if (deploymentResult.failed) {
error('✗ Deployment failed - see handoff document');
}
console.log('');
info('Handoff document created:');
log(` ${handoffPath}`, 'bright');
console.log('');
info('Next session startup:');
log(' node scripts/session-init.js', 'bright');
console.log('');
warning('⚠️ STOP ALL WORK NOW - Session is complete');
console.log('');
log(' Handoff signals intent to start NEW session with fresh context.', 'yellow');
log(' Do NOT continue working after closedown.', 'yellow');
console.log('');
process.exit(0);
}
// Run
main().catch(err => {
console.error('');
error(`Closedown failed: ${err.message}`);
console.error('');
process.exit(1);
});