tractatus/scripts/framework-audit-response.js
TheFlow 8210876421 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

274 lines
7.8 KiB
JavaScript
Executable file

#!/usr/bin/env node
/**
* Framework Audit for Conversational Responses
*
* Invokes Tractatus framework services for conversational interactions
* that don't trigger tool usage (Edit/Write/Bash).
*
* Triggered by: User prompt prefixed with "ff" or "fff"
*
* Usage:
* node scripts/framework-audit-response.js \
* --prompt "Should we disable rate limiting?" \
* --type "boundary_question" \
* --response "full response text..."
*
* Returns: JSON with audit IDs
*/
const mongoose = require('mongoose');
const path = require('path');
// Parse CLI arguments
function parseArgs() {
const args = process.argv.slice(2);
const parsed = {};
for (let i = 0; i < args.length; i += 2) {
const key = args[i].replace(/^--/, '');
const value = args[i + 1];
parsed[key] = value;
}
return parsed;
}
/**
* Main audit logic
*/
async function main() {
const args = parseArgs();
const { prompt, type, response } = args;
if (!prompt) {
console.error('Error: --prompt required');
process.exit(1);
}
// Connect to MongoDB
try {
await mongoose.connect('mongodb://localhost:27017/tractatus_dev', {
serverSelectionTimeoutMS: 2000
});
} catch (err) {
console.error('MongoDB connection failed:', err.message);
process.exit(1);
}
// Import all 6 framework services
const BoundaryEnforcer = require('../src/services/BoundaryEnforcer.service');
const CrossReferenceValidator = require('../src/services/CrossReferenceValidator.service');
const MetacognitiveVerifier = require('../src/services/MetacognitiveVerifier.service');
const ContextPressureMonitor = require('../src/services/ContextPressureMonitor.service');
const InstructionPersistenceClassifier = require('../src/services/InstructionPersistenceClassifier.service');
const PluralisticDeliberationOrchestrator = require('../src/services/PluralisticDeliberationOrchestrator.service');
// Initialize services
const sessionId = `ff-audit-${Date.now()}`;
await BoundaryEnforcer.initialize();
await CrossReferenceValidator.initialize();
await MetacognitiveVerifier.initialize();
await ContextPressureMonitor.initialize(sessionId);
await InstructionPersistenceClassifier.initialize();
await PluralisticDeliberationOrchestrator.initialize();
const auditIds = [];
const decisions = [];
// 1. BoundaryEnforcer - Check for VALUES/INNOVATION/WISDOM boundaries
const boundaryKeywords = {
VALUES: ['should we', 'better to', 'right to', 'worth', 'prioritize', 'trade-off', 'balance'],
INNOVATION: ['new architecture', 'redesign', 'refactor entire', 'switch to', 'migrate to'],
WISDOM: ['strategic', 'direction', 'long-term', 'vision', 'mission'],
PURPOSE: ['why are we', 'goal is', 'trying to achieve'],
AGENCY: ['automatically', 'without asking', 'on your behalf']
};
let detectedBoundaries = [];
const promptLower = prompt.toLowerCase();
for (const [boundary, keywords] of Object.entries(boundaryKeywords)) {
if (keywords.some(kw => promptLower.includes(kw))) {
detectedBoundaries.push(boundary);
}
}
if (detectedBoundaries.length > 0) {
const action = {
type: 'conversational_decision',
description: `User prompt: ${prompt.substring(0, 100)}`,
boundaries: detectedBoundaries,
prompt: prompt
};
const context = {
sessionId,
tool: 'conversation',
type: type || 'unknown',
trigger: 'ff_codeword'
};
const result = BoundaryEnforcer.enforce(action, context);
decisions.push({
service: 'BoundaryEnforcer',
allowed: result.allowed,
message: result.message,
boundaries: detectedBoundaries
});
}
// 2. PluralisticDeliberationOrchestrator - Check for value conflicts
const valueConflictKeywords = [
'security vs performance',
'privacy vs convenience',
'speed vs safety',
'cost vs quality',
'accessibility vs',
'disable'
];
const hasValueConflict = valueConflictKeywords.some(kw => promptLower.includes(kw));
if (hasValueConflict || detectedBoundaries.includes('VALUES')) {
const decision = {
type: 'conversational_value_conflict',
description: prompt,
user_prompt: prompt
};
const context = {
sessionId,
trigger: 'ff_codeword',
boundaries: detectedBoundaries
};
const result = PluralisticDeliberationOrchestrator.analyzeConflict(decision, context);
decisions.push({
service: 'PluralisticDeliberationOrchestrator',
frameworks: result.frameworks || [],
stakeholders: result.stakeholders || [],
urgency: result.urgency || 'UNKNOWN'
});
}
// 3. MetacognitiveVerifier - Verify reasoning quality
if (response) {
const action = {
type: 'conversational_response',
description: `Responding to: ${prompt.substring(0, 100)}`,
user_prompt: prompt
};
const reasoning = response.substring(0, 500);
const context = {
sessionId,
trigger: 'ff_codeword',
boundaries: detectedBoundaries,
has_value_conflict: hasValueConflict
};
const result = MetacognitiveVerifier.verify(action, reasoning, context);
decisions.push({
service: 'MetacognitiveVerifier',
decision: result.decision,
confidence: result.confidence,
issues: result.issues || []
});
}
// 4. CrossReferenceValidator - Check against instruction history
const instructionAction = {
type: 'conversational_decision',
description: prompt,
user_prompt: prompt
};
const validationResult = CrossReferenceValidator.validate(instructionAction, {
sessionId,
trigger: 'ff_codeword'
});
decisions.push({
service: 'CrossReferenceValidator',
conflicts: validationResult.conflicts || [],
relevant_instructions: validationResult.relevantInstructions || []
});
// 5. ContextPressureMonitor - Update pressure metrics
ContextPressureMonitor.analyzePressure({
sessionId,
tool: 'conversation',
action: 'ff_audit',
prompt: prompt.substring(0, 100)
});
decisions.push({
service: 'ContextPressureMonitor',
status: 'analyzed'
});
// 6. InstructionPersistenceClassifier - Classify if this creates new instruction
const newInstructionKeywords = ['always', 'never', 'from now on', 'going forward', 'make sure'];
const createsInstruction = newInstructionKeywords.some(kw => promptLower.includes(kw));
if (createsInstruction) {
const classification = InstructionPersistenceClassifier.classify({
text: prompt,
context: {
sessionId,
trigger: 'ff_codeword',
type: 'user_prompt'
},
timestamp: new Date(),
source: 'conversation'
});
decisions.push({
service: 'InstructionPersistenceClassifier',
quadrant: classification.quadrant,
persistence: classification.persistence,
verification: classification.verificationRequirement
});
}
// Wait for async logging
await new Promise(resolve => setTimeout(resolve, 500));
// Fetch audit IDs from recent logs
const AuditLog = mongoose.model('AuditLog');
const recentLogs = await AuditLog.find({
sessionId,
timestamp: { $gt: new Date(Date.now() - 5000) }
}).select('_id service action').sort({ timestamp: -1 });
await mongoose.disconnect();
// Output results
const output = {
success: true,
sessionId,
auditCount: recentLogs.length,
auditIds: recentLogs.map(log => log._id.toString()),
decisions,
servicesInvoked: [...new Set(recentLogs.map(log => log.service))],
summary: {
boundaries_detected: detectedBoundaries,
value_conflict: hasValueConflict,
creates_instruction: createsInstruction,
services_count: decisions.length
}
};
console.log(JSON.stringify(output, null, 2));
process.exit(0);
}
main().catch(err => {
console.error('Fatal error:', err.message);
console.error(err.stack);
process.exit(1);
});