tractatus/scripts/hook-validators/framework-integration-hook.js
TheFlow 65784f02f8 feat(blog): integrate Tractatus framework governance into blog publishing
Implements architectural enforcement of governance rules (inst_016/017/018/079)
for all external communications. Publication blocked at API level if violations
detected.

New Features:
- Framework content checker script with pattern matching for prohibited terms
- Admin UI displays framework violations with severity indicators
- Manual "Check Framework" button for pre-publication validation
- API endpoint /api/blog/check-framework for real-time content analysis

Governance Rules Added:
- inst_078: "ff" trigger for manual framework invocation in conversations
- inst_079: Dark patterns prohibition (sovereignty principle)
- inst_080: Open source commitment enforcement (community principle)
- inst_081: Pluralism principle with indigenous framework recognition

Session Management:
- Fix session-init.js infinite loop (removed early return after tests)
- Add session-closedown.js for comprehensive session handoff
- Refactor check-csp-violations.js to prevent parent process exit

Framework Services:
- Enhanced PluralisticDeliberationOrchestrator with audit logging
- Updated all 6 services with consistent initialization patterns
- Added framework invocation scripts for blog content validation

Files: blog.controller.js:1211-1305, blog.routes.js:77-82,
blog-curation.html:61-72, blog-curation.js:320-446

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-25 08:47:31 +13:00

216 lines
6.3 KiB
JavaScript
Executable file

#!/usr/bin/env node
/**
* Framework Integration Hook
*
* Automatically invokes framework services during Claude Code tool execution.
* This hook runs on every tool use and routes to appropriate framework services.
*
* Integrated Services:
* - BoundaryEnforcer: Security, architectural, cross-project boundaries
* - ContextPressureMonitor: Token/message pressure tracking
* - CrossReferenceValidator: Instruction compliance validation
* - MetacognitiveVerifier: Decision reasoning verification
* - InstructionPersistenceClassifier: New instruction classification
* - PluralisticDeliberationOrchestrator: Value conflict deliberation
*/
const path = require('path');
const fs = require('fs');
// Parse command line arguments
const args = process.argv.slice(2);
const toolName = args[0]; // 'Edit', 'Write', 'Read', 'Bash', etc.
const toolArgsJson = args[1]; // JSON string of tool arguments
// Exit early if no args (allow execution)
if (!toolName || !toolArgsJson) {
process.exit(0);
}
let toolArgs;
try {
toolArgs = JSON.parse(toolArgsJson);
} catch (err) {
// Invalid JSON, allow execution
process.exit(0);
}
/**
* Main framework integration logic
*/
async function integrateFramework() {
const mongoose = require('mongoose');
// Connect to MongoDB
try {
await mongoose.connect('mongodb://localhost:27017/tractatus_dev', {
serverSelectionTimeoutMS: 2000
});
} catch (err) {
// MongoDB not available, skip framework (allow execution)
process.exit(0);
}
// Import framework services
const BoundaryEnforcer = require('../../src/services/BoundaryEnforcer.service');
const ContextPressureMonitor = require('../../src/services/ContextPressureMonitor.service');
const CrossReferenceValidator = require('../../src/services/CrossReferenceValidator.service');
const MetacognitiveVerifier = require('../../src/services/MetacognitiveVerifier.service');
const sessionId = 'claude-code-session-' + new Date().toISOString().split('T')[0];
try {
// Route to appropriate framework service based on tool
switch (toolName) {
case 'Edit':
case 'Write':
await handleFileModification(toolArgs, sessionId);
break;
case 'Bash':
await handleBashCommand(toolArgs, sessionId);
break;
case 'Read':
await handleFileRead(toolArgs, sessionId);
break;
default:
// Unknown tool, allow execution
break;
}
await mongoose.disconnect();
process.exit(0); // Allow execution
} catch (err) {
console.error('[Framework Hook] Error:', err.message);
await mongoose.disconnect();
// If framework service blocks, exit with code 1
if (err.blocked) {
process.exit(1); // Block execution
}
process.exit(0); // Allow execution on errors
}
}
/**
* Handle file modifications (Edit, Write tools)
*/
async function handleFileModification(args, sessionId) {
const BoundaryEnforcer = require('../../src/services/BoundaryEnforcer.service');
const CrossReferenceValidator = require('../../src/services/CrossReferenceValidator.service');
const MetacognitiveVerifier = require('../../src/services/MetacognitiveVerifier.service');
const filePath = args.file_path || args.path || 'unknown';
const content = args.new_string || args.content || '';
// Check boundaries
const boundaryContext = {
sessionId,
action: 'file_modification',
target: filePath,
description: `Modify ${path.basename(filePath)}`,
metadata: {
tool: 'Edit/Write',
contentLength: content.length
}
};
try {
await BoundaryEnforcer.checkBoundaries(boundaryContext);
} catch (err) {
if (err.message.includes('boundary')) {
throw { blocked: true, reason: err.message };
}
}
// Validate against instructions (if modifying governance files)
const governanceFiles = ['CLAUDE.md', 'instruction-history.json', 'auth.middleware.js', 'auth.controller.js'];
const isGovernanceFile = governanceFiles.some(f => filePath.includes(f));
if (isGovernanceFile) {
await CrossReferenceValidator.validateAgainstInstructions({
sessionId,
action: 'modify_governance_file',
description: `Modifying ${path.basename(filePath)}`,
context: { file: filePath }
});
}
// Metacognitive verification for security-critical files
const securityFiles = ['auth', 'security', 'credential', 'jwt', 'password'];
const isSecurityFile = securityFiles.some(keyword => filePath.toLowerCase().includes(keyword));
if (isSecurityFile) {
await MetacognitiveVerifier.verifyDecision({
sessionId,
action: 'modify_security_file',
reasoning: `Modifying security-critical file: ${filePath}`,
context: {
file: filePath,
security_impact: true,
requires_approval: true
}
});
}
}
/**
* Handle Bash command execution
*/
async function handleBashCommand(args, sessionId) {
const BoundaryEnforcer = require('../../src/services/BoundaryEnforcer.service');
const command = args.command || '';
// Check for cross-project commands
const crossProjectPatterns = ['/family-history/', '/sydigital/', 'cd ../'];
const isCrossProject = crossProjectPatterns.some(pattern => command.includes(pattern));
if (isCrossProject) {
await BoundaryEnforcer.checkBoundaries({
sessionId,
action: 'bash_command',
target: command,
description: 'Cross-project bash command',
metadata: {
command: command.substring(0, 100)
}
});
}
}
/**
* Handle file reads
*/
async function handleFileRead(args, sessionId) {
// File reads are generally allowed, just track context pressure
const ContextPressureMonitor = require('../../src/services/ContextPressureMonitor.service');
// Update pressure tracking (passive monitoring)
// This doesn't block, just logs
try {
const sessionState = JSON.parse(
fs.readFileSync(path.join(__dirname, '../../.claude/session-state.json'), 'utf8')
);
await ContextPressureMonitor.analyzeContext({
sessionId,
tokens: sessionState.token_estimate || 0,
budget: 200000,
messages: sessionState.message_count || 0
});
} catch (err) {
// Ignore pressure monitoring errors
}
}
// Run integration
integrateFramework().catch(err => {
console.error('[Framework Hook] Fatal error:', err.message);
process.exit(0); // Allow execution on fatal errors
});