tractatus/scripts/track-user-suggestions.js
TheFlow 2298d36bed fix(submissions): restructure Economist package and fix article display
- Create Economist SubmissionTracking package correctly:
  * mainArticle = full blog post content
  * coverLetter = 216-word SIR— letter
  * Links to blog post via blogPostId
- Archive 'Letter to The Economist' from blog posts (it's the cover letter)
- Fix date display on article cards (use published_at)
- Target publication already displaying via blue badge

Database changes:
- Make blogPostId optional in SubmissionTracking model
- Economist package ID: 68fa85ae49d4900e7f2ecd83
- Le Monde package ID: 68fa2abd2e6acd5691932150

Next: Enhanced modal with tabs, validation, export

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

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

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();