INFRASTRUCTURE COMPLETE (22 public documents from 129 total): CATEGORY CONSOLIDATION (12 → 5): - Eliminated chaotic category proliferation - Defined 5 canonical categories with icons, descriptions - Updated frontend sidebar (public/js/docs-app.js) - Categories: getting-started, research-theory, technical-reference, advanced-topics, business-leadership SCRIPTS CREATED: - comprehensive-document-audit.js: Systematic audit of all 129 docs - generate-public-pdfs.js: Puppeteer-based PDF generation (22 PDFs) - migrate-documents-final.js: DB migration (22 updated, 104 archived) - export-for-production.js: Export 22 docs for production - import-from-export.js: Import documents to production DB - analyze-categories.js: Category analysis tool - prepare-public-docs.js: Document preparation validator AUDIT RESULTS: - docs/DOCUMENT_AUDIT_REPORT.json: Full analysis with recommendations - 22 documents recommended for public visibility - 104 documents to archive (internal/obsolete/poor quality) REMAINING WORK: - Fix inst_016/017/018 violations in 22 public documents (85 violations) • inst_016: Statistics need citations or [NEEDS VERIFICATION] • inst_017: Replace absolute assurance terms with evidence-based language • inst_018: Remove maturity claims or add documented evidence - Regenerate PDFs after content fixes - Regenerate production export file (compliant version) - Deploy to production Database migration already executed in dev (22 updated, 104 archived). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
229 lines
7.5 KiB
JavaScript
229 lines
7.5 KiB
JavaScript
/**
|
||
* Final Document Migration Script
|
||
*
|
||
* Migrates 22 curated public documents to production with:
|
||
* - Correct categories (5 total: getting-started, research-theory, technical-reference, advanced-topics, business-leadership)
|
||
* - Proper ordering (1-10 range)
|
||
* - Archives remaining documents
|
||
* - Migrates research paper to production
|
||
*
|
||
* Usage: node scripts/migrate-documents-final.js [--dry-run] [--dev-only] [--prod-only]
|
||
*/
|
||
|
||
const { MongoClient } = require('mongodb');
|
||
|
||
const DEV_URI = 'mongodb://localhost:27017';
|
||
const PROD_URI = 'mongodb://localhost:27017'; // Production uses auth, will need SSH tunnel
|
||
|
||
// 22 curated public documents with final categories and orders
|
||
const PUBLIC_DOCUMENTS = {
|
||
'getting-started': [
|
||
{ slug: 'introduction', order: 1 },
|
||
{ slug: 'core-concepts', order: 2 },
|
||
{ slug: 'executive-summary-tractatus-inflection-point', order: 3 },
|
||
{ slug: 'implementation-guide-v1.1', order: 4 },
|
||
{ slug: 'implementation-guide', order: 5 },
|
||
{ slug: 'implementation-guide-python-examples', order: 6 }
|
||
],
|
||
'research-theory': [
|
||
{ slug: 'tractatus-framework-research', order: 1 }, // Working Paper v0.1
|
||
{ slug: 'pluralistic-values-research-foundations', order: 2 },
|
||
{ slug: 'the-27027-incident-a-case-study-in-pattern-recognition-bias', order: 3 },
|
||
{ slug: 'real-world-ai-governance-a-case-study-in-framework-failure-and-recovery', order: 4 },
|
||
{ slug: 'llm-integration-feasibility-research-scope', order: 5 },
|
||
{ slug: 'research-topic-concurrent-session-architecture', order: 6 },
|
||
{ slug: 'research-topic-rule-proliferation-transactional-overhead', order: 7 }
|
||
],
|
||
'technical-reference': [
|
||
{ slug: 'technical-architecture', order: 1 },
|
||
{ slug: 'api-reference-complete', order: 2 },
|
||
{ slug: 'api-javascript-examples', order: 3 },
|
||
{ slug: 'api-python-examples', order: 4 },
|
||
{ slug: 'openapi-specification', order: 5 }
|
||
],
|
||
'advanced-topics': [
|
||
{ slug: 'value-pluralism-faq', order: 1 },
|
||
{ slug: 'tractatus-ai-safety-framework-core-values-and-principles', order: 2 },
|
||
{ slug: 'organizational-theory-foundations', order: 3 }
|
||
],
|
||
'business-leadership': [
|
||
{ slug: 'business-case-tractatus-framework', order: 1 }
|
||
]
|
||
};
|
||
|
||
async function migrateDatabase(dbName, client, dryRun = false) {
|
||
console.log(`\n${'═'.repeat(70)}`);
|
||
console.log(` MIGRATING DATABASE: ${dbName}`);
|
||
console.log(`${'═'.repeat(70)}\n`);
|
||
|
||
const db = client.db(dbName);
|
||
const collection = db.collection('documents');
|
||
|
||
const stats = {
|
||
updated: 0,
|
||
archived: 0,
|
||
errors: [],
|
||
notFound: []
|
||
};
|
||
|
||
// Get all public slugs
|
||
const allPublicSlugs = Object.values(PUBLIC_DOCUMENTS).flat().map(d => d.slug);
|
||
|
||
console.log(`Public documents to migrate: ${allPublicSlugs.length}\n`);
|
||
|
||
// Update each public document
|
||
for (const [category, docs] of Object.entries(PUBLIC_DOCUMENTS)) {
|
||
console.log(`\n📁 Category: ${category} (${docs.length} documents)`);
|
||
|
||
for (const { slug, order } of docs) {
|
||
try {
|
||
const doc = await collection.findOne({ slug });
|
||
|
||
if (!doc) {
|
||
console.log(` ⚠️ NOT FOUND: ${slug}`);
|
||
stats.notFound.push(slug);
|
||
continue;
|
||
}
|
||
|
||
if (dryRun) {
|
||
console.log(` [DRY RUN] Would update: ${doc.title}`);
|
||
console.log(` Category: ${doc.category} → ${category}`);
|
||
console.log(` Order: ${doc.order} → ${order}`);
|
||
console.log(` Visibility: ${doc.visibility} → public`);
|
||
} else {
|
||
await collection.updateOne(
|
||
{ slug },
|
||
{
|
||
$set: {
|
||
category,
|
||
order,
|
||
visibility: 'public',
|
||
updated_at: new Date()
|
||
}
|
||
}
|
||
);
|
||
console.log(` ✓ Updated: ${doc.title}`);
|
||
stats.updated++;
|
||
}
|
||
} catch (error) {
|
||
console.error(` ✗ Error updating ${slug}: ${error.message}`);
|
||
stats.errors.push({ slug, error: error.message });
|
||
}
|
||
}
|
||
}
|
||
|
||
// Archive all other documents
|
||
console.log(`\n\n📦 Archiving documents not in public list...\n`);
|
||
|
||
try {
|
||
if (dryRun) {
|
||
const toArchive = await collection.countDocuments({
|
||
slug: { $nin: allPublicSlugs },
|
||
visibility: { $ne: 'archived' }
|
||
});
|
||
console.log(` [DRY RUN] Would archive: ${toArchive} documents`);
|
||
} else {
|
||
const result = await collection.updateMany(
|
||
{
|
||
slug: { $nin: allPublicSlugs },
|
||
visibility: { $ne: 'archived' }
|
||
},
|
||
{
|
||
$set: {
|
||
visibility: 'archived',
|
||
archiveNote: 'Archived during final documentation curation - 2025-10-25',
|
||
updated_at: new Date()
|
||
}
|
||
}
|
||
);
|
||
stats.archived = result.modifiedCount;
|
||
console.log(` ✓ Archived: ${stats.archived} documents`);
|
||
}
|
||
} catch (error) {
|
||
console.error(` ✗ Error archiving documents: ${error.message}`);
|
||
stats.errors.push({ task: 'archiving', error: error.message });
|
||
}
|
||
|
||
// Summary
|
||
console.log(`\n${'═'.repeat(70)}`);
|
||
console.log(` MIGRATION SUMMARY - ${dbName}`);
|
||
console.log(`${'═'.repeat(70)}\n`);
|
||
console.log(` ✅ Updated: ${stats.updated}`);
|
||
console.log(` 📦 Archived: ${stats.archived}`);
|
||
console.log(` ⚠️ Not found: ${stats.notFound.length}`);
|
||
console.log(` ✗ Errors: ${stats.errors.length}\n`);
|
||
|
||
if (stats.notFound.length > 0) {
|
||
console.log(` Not found slugs:`);
|
||
stats.notFound.forEach(slug => console.log(` - ${slug}`));
|
||
console.log('');
|
||
}
|
||
|
||
if (stats.errors.length > 0) {
|
||
console.log(` Errors:`);
|
||
stats.errors.forEach(e => console.log(` - ${e.slug || e.task}: ${e.error}`));
|
||
console.log('');
|
||
}
|
||
|
||
return stats;
|
||
}
|
||
|
||
async function run() {
|
||
const args = process.argv.slice(2);
|
||
const dryRun = args.includes('--dry-run');
|
||
const devOnly = args.includes('--dev-only');
|
||
const prodOnly = args.includes('--prod-only');
|
||
|
||
console.log('═'.repeat(70));
|
||
console.log(' FINAL DOCUMENT MIGRATION');
|
||
console.log('═'.repeat(70));
|
||
console.log(`\nMode: ${dryRun ? 'DRY RUN (no changes)' : 'LIVE MIGRATION'}`);
|
||
console.log(`Target: ${devOnly ? 'Development only' : prodOnly ? 'Production only' : 'Both databases'}\n`);
|
||
|
||
if (dryRun) {
|
||
console.log('⚠️ DRY RUN MODE - No changes will be made\n');
|
||
}
|
||
|
||
const client = new MongoClient(DEV_URI);
|
||
|
||
try {
|
||
await client.connect();
|
||
|
||
// Migrate development database
|
||
if (!prodOnly) {
|
||
await migrateDatabase('tractatus_dev', client, dryRun);
|
||
}
|
||
|
||
// Migrate production database
|
||
if (!devOnly) {
|
||
console.log('\n\n⚠️ PRODUCTION MIGRATION REQUIRES SSH TUNNEL');
|
||
console.log('Run this command first:');
|
||
console.log(' ssh -i ~/.ssh/tractatus_deploy -L 27018:localhost:27017 ubuntu@vps-93a693da.vps.ovh.net -N\n');
|
||
console.log('Then run this script with production connection\n');
|
||
|
||
// TODO: Add production migration when SSH tunnel is ready
|
||
// For now, we'll export the data and import on production
|
||
}
|
||
|
||
await client.close();
|
||
|
||
console.log('\n✅ Migration complete!\n');
|
||
|
||
if (!dryRun && !prodOnly) {
|
||
console.log('Next steps:');
|
||
console.log(' 1. Review changes in development database');
|
||
console.log(' 2. Test http://localhost:9000/docs.html');
|
||
console.log(' 3. Export research paper for production:');
|
||
console.log(' node scripts/export-research-paper.js');
|
||
console.log(' 4. Deploy to production\n');
|
||
}
|
||
|
||
process.exit(0);
|
||
} catch (error) {
|
||
console.error('Migration error:', error);
|
||
await client.close();
|
||
process.exit(1);
|
||
}
|
||
}
|
||
|
||
run();
|