#!/usr/bin/env node /** * Scope Adjustment Logger - Enforces inst_052 * Tracks when Claude Code adjusts implementation scope * * Usage: node scripts/log-scope-adjustment.js [details] * * Types: reduce, expand, defer, optimize */ const fs = require('fs'); const path = require('path'); const SESSION_STATE = path.join(__dirname, '../.claude/session-state.json'); const SCOPE_LOG = path.join(__dirname, '../.claude/scope-adjustments.json'); function loadScopeLog() { if (!fs.existsSync(SCOPE_LOG)) { return { adjustments: [] }; } return JSON.parse(fs.readFileSync(SCOPE_LOG, 'utf8')); } function saveScopeLog(log) { fs.writeFileSync(SCOPE_LOG, JSON.stringify(log, null, 2)); } function getSessionInfo() { if (fs.existsSync(SESSION_STATE)) { const state = JSON.parse(fs.readFileSync(SESSION_STATE, 'utf8')); return { sessionId: state.sessionId, messageCount: state.messageCount }; } return { sessionId: 'unknown', messageCount: 0 }; } function logAdjustment(type, rationale, details) { const log = loadScopeLog(); const session = getSessionInfo(); const entry = { timestamp: new Date().toISOString(), sessionId: session.sessionId, messageNumber: session.messageCount, type, rationale, details: details || null, userGrantedDiscretion: false // Set to true if user explicitly granted 'full discretion' }; log.adjustments.push(entry); saveScopeLog(log); console.log(`\nāœ… Scope adjustment logged (inst_052)\n`); console.log(` Type: ${type}`); console.log(` Rationale: ${rationale}`); if (details) { console.log(` Details: ${details}`); } console.log(` Session: ${session.sessionId} #${session.messageCount}\n`); } function listAdjustments() { const log = loadScopeLog(); if (log.adjustments.length === 0) { console.log('\nāœ… No scope adjustments this session\n'); return; } console.log(`\nšŸ“‹ Scope Adjustments (${log.adjustments.length} total)\n`); console.log('━'.repeat(70)); log.adjustments.forEach((adj, i) => { console.log(`\n${i + 1}. ${adj.type.toUpperCase()} (${new Date(adj.timestamp).toLocaleString()})`); console.log(` Session: ${adj.sessionId} #${adj.messageNumber}`); console.log(` Rationale: ${adj.rationale}`); if (adj.details) { console.log(` Details: ${adj.details}`); } console.log(` User Discretion: ${adj.userGrantedDiscretion ? 'Yes' : 'No'}`); }); console.log('\n' + '━'.repeat(70) + '\n'); } function checkRestrictions(rationale, details) { // inst_052: NEVER adjust these areas const prohibitedAreas = [ 'security architecture', 'credentials', 'media response', 'third-party', 'authentication', 'authorization' ]; const combinedText = (rationale + ' ' + (details || '')).toLowerCase(); const violations = prohibitedAreas.filter(area => combinedText.includes(area)); if (violations.length > 0) { console.log(`\nāš ļø WARNING (inst_052): Scope adjustments prohibited for:\n`); violations.forEach(v => console.log(` • ${v}`)); console.log(`\nIf user has not granted 'full discretion', do NOT proceed.\n`); process.exit(1); } } function main() { const command = process.argv[2]; if (!command || command === 'list') { listAdjustments(); return; } if (command === 'log') { const type = process.argv[3]; const rationale = process.argv[4]; const details = process.argv[5]; if (!type || !rationale) { console.log('Usage: log-scope-adjustment.js log [details]'); console.log(''); console.log('Types:'); console.log(' reduce - Reduce scope for efficiency'); console.log(' expand - Expand scope for completeness'); console.log(' defer - Defer work to later phase'); console.log(' optimize - Optimize implementation approach'); process.exit(1); } // Check for prohibited adjustments (inst_052) checkRestrictions(rationale, details); logAdjustment(type, rationale, details); } else { console.log('Usage: log-scope-adjustment.js [log|list]'); console.log(''); console.log('Commands:'); console.log(' log [details] - Log a scope adjustment'); console.log(' list - List all adjustments this session'); } } main();