tractatus/public/js/demos/boundary-demo.js
TheFlow 2e6618b7ba feat: fix CSP violations & implement three audience paths
CSP Compliance (complete):
- Install Tailwind CSS v3 locally (24KB build)
- Replace CDN with /css/tailwind.css in all HTML files
- Extract all inline scripts to external JS files
- Created 6 external JS files for demos & docs
- All pages now comply with script-src 'self'

Three Audience Paths (complete):
- Created /researcher.html (academic/theoretical)
- Created /implementer.html (practical integration)
- Created /advocate.html (mission/values/community)
- Updated homepage links to audience pages
- Each path has dedicated nav, hero, resources, CTAs

Files Modified (20):
- 7 HTML files (CSP compliance)
- 3 audience landing pages (new)
- 6 external JS files (extracted)
- package.json (Tailwind v3)
- tailwind.config.js (new)
- Built CSS (24KB minified)

All resources CSP-compliant, all pages tested 200 OK

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-07 12:21:00 +13:00

219 lines
7 KiB
JavaScript

const scenarios = {
optimize_images: {
title: "Optimize Image Loading",
description: "Implement lazy loading and compression for better performance",
domain: "technical",
allowed: true,
reason: "Technical optimization within defined parameters. No values trade-offs required.",
alternatives: null,
code: `// BoundaryEnforcer Check
const boundary = enforcer.enforce({
type: 'performance_optimization',
action: 'implement_lazy_loading'
});
// Result: ALLOWED
{
allowed: true,
reason: "Technical decision, no values impact",
proceed: true
}`
},
privacy_vs_analytics: {
title: "Enable Analytics Tracking",
description: "Add Google Analytics to track user behavior",
domain: "values",
allowed: false,
reason: "Privacy vs. analytics is an irreducible values trade-off. Different users have different privacy expectations.",
alternatives: [
"Research privacy-friendly analytics options (e.g., Plausible, Fathom)",
"Analyze current user behavior from server logs",
"Document pros/cons of different analytics approaches",
"Present options with privacy impact assessment"
],
code: `// BoundaryEnforcer Check
const boundary = enforcer.enforce({
type: 'privacy_policy',
action: 'enable_tracking',
domain: 'values'
});
// Result: BLOCKED
{
allowed: false,
reason: "Privacy vs. convenience trade-off",
requires_human_decision: true,
boundary_section: "12.1"
}`
},
auto_subscribe: {
title: "Auto-Subscribe Users",
description: "Automatically subscribe new users to newsletter",
domain: "user_agency",
allowed: false,
reason: "This determines the level of user control and agency. Opt-in vs. opt-out affects user autonomy.",
alternatives: [
"Implement explicit opt-in during registration",
"Implement opt-out with clear unsubscribe",
"Research industry best practices for consent",
"Document GDPR compliance implications"
],
code: `// BoundaryEnforcer Check
const boundary = enforcer.enforce({
type: 'user_consent',
action: 'auto_subscribe',
domain: 'user_agency'
});
// Result: BLOCKED
{
allowed: false,
reason: "Affects user agency and control",
requires_human_decision: true,
boundary_section: "12.2"
}`
},
delete_old_data: {
title: "Delete Old User Data",
description: "Automatically delete user data older than 6 months",
domain: "irreversible",
allowed: false,
reason: "Data deletion is irreversible and may have legal/compliance implications.",
alternatives: [
"Check backup status and retention policies",
"Verify legal data retention requirements",
"Confirm user consent for deletion",
"Implement archive rather than delete"
],
code: `// BoundaryEnforcer Check
const boundary = enforcer.enforce({
type: 'data_deletion',
action: 'delete_user_data',
domain: 'irreversible'
});
// Result: BLOCKED
{
allowed: false,
reason: "Irreversible action with legal implications",
requires_human_approval: true,
boundary_section: "12.3"
}`
},
cache_strategy: {
title: "Implement Caching Strategy",
description: "Add Redis caching for frequently accessed data",
domain: "technical",
allowed: true,
reason: "Technical implementation decision within established patterns. No values impact.",
alternatives: null,
code: `// BoundaryEnforcer Check
const boundary = enforcer.enforce({
type: 'technical_implementation',
action: 'add_caching'
});
// Result: ALLOWED
{
allowed: true,
reason: "Technical decision with clear constraints",
proceed: true
}`
},
content_moderation: {
title: "Automatic Content Moderation",
description: "AI automatically removes inappropriate content",
domain: "values",
allowed: false,
reason: "Defining 'inappropriate' involves values judgments about free speech, community standards, and cultural context.",
alternatives: [
"Implement flagging system for human review",
"Create tiered moderation (AI flags, human decides)",
"Research community moderation models",
"Document content policy options for decision"
],
code: `// BoundaryEnforcer Check
const boundary = enforcer.enforce({
type: 'content_policy',
action: 'auto_moderate',
domain: 'values'
});
// Result: BLOCKED
{
allowed: false,
reason: "Content standards are values decisions",
requires_human_decision: true,
boundary_section: "12.1"
}`
}
};
// Event listeners
document.querySelectorAll('.scenario-card').forEach(card => {
card.addEventListener('click', () => {
const decision = card.getAttribute('data-decision');
showResult(scenarios[decision]);
// Highlight selected
document.querySelectorAll('.scenario-card').forEach(c => {
c.classList.remove('ring-2', 'ring-blue-500');
});
card.classList.add('ring-2', 'ring-blue-500');
});
});
function showResult(scenario) {
document.getElementById('empty-state').classList.add('hidden');
document.getElementById('result-content').classList.remove('hidden');
// Decision info
document.getElementById('decision-title').textContent = scenario.title;
document.getElementById('decision-desc').textContent = scenario.description;
// Verdict
const verdict = document.getElementById('verdict');
if (scenario.allowed) {
verdict.innerHTML = `
<div class="flex items-start">
<svg class="w-8 h-8 text-green-600 mr-3 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
<div>
<div class="text-lg font-semibold text-green-900 mb-1">✅ ALLOWED</div>
<div class="text-green-800">AI can automate this decision</div>
</div>
</div>
`;
verdict.className = 'rounded-lg p-6 mb-6 bg-green-100 border border-green-300';
} else {
verdict.innerHTML = `
<div class="flex items-start">
<svg class="w-8 h-8 text-red-600 mr-3 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
<div>
<div class="text-lg font-semibold text-red-900 mb-1">🚫 BLOCKED</div>
<div class="text-red-800">Requires human judgment</div>
</div>
</div>
`;
verdict.className = 'rounded-lg p-6 mb-6 bg-red-100 border border-red-300';
}
// Reasoning
document.getElementById('reasoning').textContent = scenario.reason;
// Alternatives
if (scenario.alternatives) {
document.getElementById('ai-alternatives').classList.remove('hidden');
document.getElementById('alternatives-list').innerHTML = scenario.alternatives
.map(alt => `<li>${alt}</li>`)
.join('');
} else {
document.getElementById('ai-alternatives').classList.add('hidden');
}
// Code example
document.getElementById('code-example').textContent = scenario.code;
}