CRITICAL FIX: Server would CRASH ON STARTUP (multiple import errors)
REMOVED (2 scripts):
1. scripts/framework-watchdog.js
- Monitored .claude/session-state.json (OUR Claude Code setup)
- Monitored .claude/token-checkpoints.json (OUR file structure)
- Implementers won't have our .claude/ directory
2. scripts/init-db.js
- Created website collections: blog_posts, media_inquiries, case_submissions
- Created website collections: resources, moderation_queue, users, citations
- Created website collections: translations, koha_donations
- Next steps referenced deleted scripts (npm run seed:admin)
REWRITTEN (2 files):
src/models/index.js (29 lines → 27 lines)
- REMOVED imports: Document, BlogPost, MediaInquiry, CaseSubmission, Resource
- REMOVED imports: ModerationQueue, User (all deleted in Phase 2)
- KEPT imports: AuditLog, DeliberationSession, GovernanceLog, GovernanceRule
- KEPT imports: Precedent, Project, SessionState, VariableValue, VerificationLog
- Result: Only framework models exported
src/server.js (284 lines → 163 lines, 43% reduction)
- REMOVED: Imports to deleted middleware (csrf-protection, response-sanitization)
- REMOVED: Stripe webhook handling (/api/koha/webhook)
- REMOVED: Static file caching (for deleted public/ directory)
- REMOVED: Static file serving (public/ deleted in Phase 6)
- REMOVED: CSRF token endpoint
- REMOVED: Website homepage with "auth, documents, blog, admin" references
- REMOVED: Instruction sync (scripts/sync-instructions-to-db.js reference)
- REMOVED: Hardcoded log path (${process.env.HOME}/var/log/tractatus/...)
- REMOVED: Website-specific security middleware
- KEPT: Security headers, rate limiting, CORS, body parsers
- KEPT: API routes, governance services, MongoDB connections
- RESULT: Clean framework-only server
RESULT: Repository can now start without crashes, all imports resolve
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
247 lines
6.4 KiB
JavaScript
Executable file
247 lines
6.4 KiB
JavaScript
Executable file
#!/usr/bin/env node
|
|
|
|
/**
|
|
* User Suggestion Tracker
|
|
*
|
|
* Tracks user technical hypotheses and debugging suggestions so that:
|
|
* - MetacognitiveVerifier can check if user hypothesis was tested
|
|
* - BoundaryEnforcer can flag ignoring user expertise
|
|
* - CrossReferenceValidator can match actions against suggestions
|
|
*
|
|
* Implements inst_049: "Test user hypothesis first"
|
|
*
|
|
* Usage:
|
|
* node scripts/track-user-suggestions.js --add "user hypothesis text"
|
|
* node scripts/track-user-suggestions.js --mark-tested "hypothesis id"
|
|
* node scripts/track-user-suggestions.js --check-untested
|
|
*
|
|
* Copyright 2025 Tractatus Project
|
|
* Licensed under Apache License 2.0
|
|
*/
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const SUGGESTIONS_PATH = path.join(__dirname, '../.claude/user-suggestions.json');
|
|
const SESSION_STATE_PATH = path.join(__dirname, '../.claude/session-state.json');
|
|
|
|
/**
|
|
* Load user suggestions
|
|
*/
|
|
function loadSuggestions() {
|
|
try {
|
|
if (fs.existsSync(SUGGESTIONS_PATH)) {
|
|
return JSON.parse(fs.readFileSync(SUGGESTIONS_PATH, 'utf8'));
|
|
}
|
|
} catch (err) {
|
|
console.warn(`Warning: Could not load suggestions: ${err.message}`);
|
|
}
|
|
|
|
return {
|
|
version: "1.0",
|
|
session_id: null,
|
|
suggestions: [],
|
|
last_updated: new Date().toISOString()
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Save user suggestions
|
|
*/
|
|
function saveSuggestions(data) {
|
|
data.last_updated = new Date().toISOString();
|
|
fs.writeFileSync(SUGGESTIONS_PATH, JSON.stringify(data, null, 2));
|
|
}
|
|
|
|
/**
|
|
* Get current session ID
|
|
*/
|
|
function getCurrentSessionId() {
|
|
try {
|
|
const sessionState = JSON.parse(fs.readFileSync(SESSION_STATE_PATH, 'utf8'));
|
|
return sessionState.session_id;
|
|
} catch (err) {
|
|
return 'unknown';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add new user suggestion/hypothesis
|
|
*/
|
|
function addSuggestion(text) {
|
|
const data = loadSuggestions();
|
|
const sessionId = getCurrentSessionId();
|
|
|
|
// Reset if new session
|
|
if (data.session_id !== sessionId) {
|
|
data.session_id = sessionId;
|
|
data.suggestions = [];
|
|
}
|
|
|
|
// Extract key phrases that indicate technical hypothesis
|
|
const hypothesisIndicators = [
|
|
'could be',
|
|
'might be',
|
|
'issue',
|
|
'problem',
|
|
'try',
|
|
'check',
|
|
'examine',
|
|
'look at',
|
|
'debug',
|
|
'test'
|
|
];
|
|
|
|
const isHypothesis = hypothesisIndicators.some(indicator =>
|
|
text.toLowerCase().includes(indicator)
|
|
);
|
|
|
|
const suggestion = {
|
|
id: `sugg_${Date.now()}`,
|
|
text: text,
|
|
timestamp: new Date().toISOString(),
|
|
tested: false,
|
|
result: null,
|
|
is_hypothesis: isHypothesis,
|
|
priority: isHypothesis ? 'HIGH' : 'MEDIUM'
|
|
};
|
|
|
|
data.suggestions.push(suggestion);
|
|
saveSuggestions(data);
|
|
|
|
console.log(`✅ Tracked user suggestion: ${suggestion.id}`);
|
|
if (isHypothesis) {
|
|
console.log(` 📋 Marked as HYPOTHESIS - should test before alternatives`);
|
|
}
|
|
|
|
return suggestion;
|
|
}
|
|
|
|
/**
|
|
* Mark suggestion as tested
|
|
*/
|
|
function markTested(suggestionId, result = null) {
|
|
const data = loadSuggestions();
|
|
const suggestion = data.suggestions.find(s => s.id === suggestionId);
|
|
|
|
if (!suggestion) {
|
|
console.error(`Error: Suggestion ${suggestionId} not found`);
|
|
return null;
|
|
}
|
|
|
|
suggestion.tested = true;
|
|
suggestion.result = result;
|
|
suggestion.tested_at = new Date().toISOString();
|
|
|
|
saveSuggestions(data);
|
|
|
|
console.log(`✅ Marked suggestion as tested: ${suggestionId}`);
|
|
if (result) {
|
|
console.log(` Result: ${result}`);
|
|
}
|
|
|
|
return suggestion;
|
|
}
|
|
|
|
/**
|
|
* Check for untested hypotheses
|
|
*/
|
|
function checkUntested() {
|
|
const data = loadSuggestions();
|
|
const untested = data.suggestions.filter(s => !s.tested && s.is_hypothesis);
|
|
|
|
if (untested.length === 0) {
|
|
console.log('✅ All user hypotheses have been tested');
|
|
return { hasUntested: false, untested: [] };
|
|
}
|
|
|
|
console.log(`⚠️ ${untested.length} untested user hypothesis(es):`);
|
|
untested.forEach((sugg, i) => {
|
|
console.log(`\n${i + 1}. [${sugg.priority}] ${sugg.id}`);
|
|
console.log(` "${sugg.text}"`);
|
|
console.log(` Suggested: ${new Date(sugg.timestamp).toLocaleString()}`);
|
|
});
|
|
|
|
console.log('\n💡 inst_049: Test user hypotheses BEFORE pursuing alternatives');
|
|
|
|
return { hasUntested: true, untested };
|
|
}
|
|
|
|
/**
|
|
* Get suggestion summary
|
|
*/
|
|
function getSummary() {
|
|
const data = loadSuggestions();
|
|
|
|
const summary = {
|
|
total: data.suggestions.length,
|
|
hypotheses: data.suggestions.filter(s => s.is_hypothesis).length,
|
|
tested: data.suggestions.filter(s => s.tested).length,
|
|
untested: data.suggestions.filter(s => !s.tested).length,
|
|
untested_hypotheses: data.suggestions.filter(s => !s.tested && s.is_hypothesis).length
|
|
};
|
|
|
|
return summary;
|
|
}
|
|
|
|
/**
|
|
* Display summary
|
|
*/
|
|
function displaySummary() {
|
|
const summary = getSummary();
|
|
|
|
console.log('User Suggestion Summary:');
|
|
console.log(` Total suggestions: ${summary.total}`);
|
|
console.log(` Hypotheses: ${summary.hypotheses}`);
|
|
console.log(` Tested: ${summary.tested}`);
|
|
console.log(` Untested: ${summary.untested}`);
|
|
|
|
if (summary.untested_hypotheses > 0) {
|
|
console.log(`\n ⚠️ ${summary.untested_hypotheses} untested hypothesis(es) - violation risk`);
|
|
} else {
|
|
console.log(`\n ✅ All hypotheses tested`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Main
|
|
*/
|
|
function main() {
|
|
const args = process.argv.slice(2);
|
|
|
|
if (args.length === 0 || args.includes('--help')) {
|
|
console.log('User Suggestion Tracker');
|
|
console.log('\nUsage:');
|
|
console.log(' --add "text" Add user suggestion/hypothesis');
|
|
console.log(' --mark-tested ID [result] Mark suggestion as tested');
|
|
console.log(' --check-untested Check for untested hypotheses');
|
|
console.log(' --summary Show summary statistics');
|
|
process.exit(0);
|
|
}
|
|
|
|
if (args.includes('--add')) {
|
|
const index = args.indexOf('--add');
|
|
const text = args[index + 1];
|
|
if (!text) {
|
|
console.error('Error: --add requires suggestion text');
|
|
process.exit(1);
|
|
}
|
|
addSuggestion(text);
|
|
} else if (args.includes('--mark-tested')) {
|
|
const index = args.indexOf('--mark-tested');
|
|
const id = args[index + 1];
|
|
const result = args[index + 2] || null;
|
|
if (!id) {
|
|
console.error('Error: --mark-tested requires suggestion ID');
|
|
process.exit(1);
|
|
}
|
|
markTested(id, result);
|
|
} else if (args.includes('--check-untested')) {
|
|
const result = checkUntested();
|
|
process.exit(result.hasUntested ? 1 : 0);
|
|
} else if (args.includes('--summary')) {
|
|
displaySummary();
|
|
}
|
|
}
|
|
|
|
main();
|