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>
274 lines
7.8 KiB
JavaScript
Executable file
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);
|
|
});
|