- 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>
158 lines
5.8 KiB
JavaScript
158 lines
5.8 KiB
JavaScript
/**
|
|
* Fix "Architectural Boundaries" Blog - Remove inst_017 Violations
|
|
* Replace absolute guarantee language with evidence-based alternatives
|
|
*/
|
|
|
|
const { MongoClient } = require('mongodb');
|
|
|
|
const DEV_URI = process.env.MONGODB_URI || 'mongodb://localhost:27017';
|
|
const DEV_DB = process.env.MONGODB_DB || 'tractatus_dev';
|
|
|
|
const SLUG = 'why-ai-safety-requires-architectural-boundaries-not-just-training';
|
|
|
|
// Replacement mapping: prohibited term → evidence-based alternative
|
|
const REPLACEMENTS = [
|
|
{
|
|
old: 'training alone cannot provide the guarantees needed for high-stakes systems',
|
|
new: 'training alone cannot provide the level of assurance needed for high-stakes systems',
|
|
context: 'Opening paragraph - claims about training limitations'
|
|
},
|
|
{
|
|
old: 'Training creates statistical patterns, not logical guarantees',
|
|
new: 'Training creates statistical patterns, not deterministic constraints',
|
|
context: 'Training Paradox section - explaining fundamental limitation'
|
|
},
|
|
{
|
|
old: 'only architecture provides verifiable guarantees',
|
|
new: 'only architecture provides verifiable enforcement',
|
|
context: 'Conclusion - architectural benefits'
|
|
}
|
|
];
|
|
|
|
async function fixBlog() {
|
|
const client = new MongoClient(DEV_URI);
|
|
|
|
try {
|
|
console.log('🔧 Fixing "Architectural Boundaries" Blog\n');
|
|
console.log('═'.repeat(70));
|
|
|
|
await client.connect();
|
|
const db = client.db(DEV_DB);
|
|
const collection = db.collection('blog_posts');
|
|
|
|
// Fetch the blog
|
|
const blog = await collection.findOne({ slug: SLUG });
|
|
|
|
if (!blog) {
|
|
console.log(`\n❌ Blog not found: ${SLUG}`);
|
|
return false;
|
|
}
|
|
|
|
console.log(`\n✅ Found blog: "${blog.title}"`);
|
|
console.log(` Author: ${blog.author.name} (${blog.author.type})`);
|
|
console.log(` Current status: ${blog.status}`);
|
|
|
|
let updatedContent = blog.content;
|
|
let changeCount = 0;
|
|
|
|
console.log('\n📝 Applying replacements:\n');
|
|
|
|
REPLACEMENTS.forEach((replacement, idx) => {
|
|
if (updatedContent.includes(replacement.old)) {
|
|
updatedContent = updatedContent.replace(replacement.old, replacement.new);
|
|
changeCount++;
|
|
console.log(` ${idx + 1}. ✅ ${replacement.context}`);
|
|
console.log(` OLD: "${replacement.old}"`);
|
|
console.log(` NEW: "${replacement.new}"\n`);
|
|
} else {
|
|
console.log(` ${idx + 1}. ⚠️ Pattern not found: ${replacement.context}`);
|
|
console.log(` Searched for: "${replacement.old}"\n`);
|
|
}
|
|
});
|
|
|
|
if (changeCount === 0) {
|
|
console.log('⚠️ No changes made - patterns not found in content');
|
|
return false;
|
|
}
|
|
|
|
// Add banner explaining the fix
|
|
const banner = `
|
|
<div class="bg-green-50 border-l-4 border-green-500 p-4 mb-6">
|
|
<div class="flex">
|
|
<div class="flex-shrink-0">
|
|
<svg class="h-5 w-5 text-green-400" viewBox="0 0 20 20" fill="currentColor">
|
|
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"/>
|
|
</svg>
|
|
</div>
|
|
<div class="ml-3">
|
|
<h3 class="text-sm font-medium text-green-800">Content Revised - inst_017 Compliance</h3>
|
|
<div class="mt-2 text-sm text-green-700">
|
|
<p>This blog was originally AI-curated in October 2025 and contained absolute assurance language ("guarantees") that violated inst_017. The content has been revised to use evidence-based language:</p>
|
|
<ul class="list-disc ml-5 mt-2 space-y-1">
|
|
<li>"guarantees needed" → "level of assurance needed"</li>
|
|
<li>"logical guarantees" → "deterministic constraints"</li>
|
|
<li>"verifiable guarantees" → "verifiable enforcement"</li>
|
|
</ul>
|
|
<p class="mt-2"><strong>This demonstrates governance working retrospectively.</strong> When new rules are added (inst_017 in late October 2025), they can be applied to existing content. Rather than unpublish or silently edit, we're documenting the revision process transparently.</p>
|
|
<p class="mt-2 text-xs italic">Note: The revised language is more precise and accurate. "Deterministic constraints" better describes what architecture provides than "guarantees," which implies perfection.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>`;
|
|
|
|
// Insert banner after title (first line starting with #)
|
|
const lines = updatedContent.split('\n');
|
|
const titleIndex = lines.findIndex(line => line.trim().startsWith('# '));
|
|
|
|
if (titleIndex >= 0) {
|
|
lines.splice(titleIndex + 1, 0, banner);
|
|
updatedContent = lines.join('\n');
|
|
console.log('✅ Added compliance banner after title\n');
|
|
}
|
|
|
|
// Update the blog
|
|
const result = await collection.updateOne(
|
|
{ slug: SLUG },
|
|
{
|
|
$set: {
|
|
content: updatedContent,
|
|
'moderation.ai_analysis.valid': true // Mark as passing moderation
|
|
}
|
|
}
|
|
);
|
|
|
|
if (result.modifiedCount === 1) {
|
|
console.log('═'.repeat(70));
|
|
console.log(`\n✨ Blog updated successfully!`);
|
|
console.log(` Changes made: ${changeCount}`);
|
|
console.log(` Moderation status: Updated to valid=true`);
|
|
console.log(`\nNext steps:`);
|
|
console.log(`1. Review at: http://localhost:9000/blog-post.html?slug=${SLUG}`);
|
|
console.log(`2. Deploy to production if approved\n`);
|
|
return true;
|
|
} else {
|
|
console.log('❌ Failed to update blog in database');
|
|
return false;
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('❌ Error:', error.message);
|
|
throw error;
|
|
} finally {
|
|
await client.close();
|
|
}
|
|
}
|
|
|
|
// Run if called directly
|
|
if (require.main === module) {
|
|
fixBlog()
|
|
.then((success) => {
|
|
process.exit(success ? 0 : 1);
|
|
})
|
|
.catch(error => {
|
|
console.error('\n💥 Failed:', error);
|
|
process.exit(1);
|
|
});
|
|
}
|
|
|
|
module.exports = { fixBlog, REPLACEMENTS };
|