tractatus/public/js/demos/deliberation-demo.js
TheFlow df8c6ccb03 fix: Remove absolute assurance language per inst_017 across codebase
Replace "ensures", "guarantee", "foolproof", "world-class" and similar
absolute terms with evidence-based language throughout public pages, JS
components, and FAQ content. Changes apply inst_017 (no absolute
assurance terms) consistently.

Replacements:
- "ensures X" → "validates X", "so that X", "supports X", "maintains X"
- "guarantee" → removed or rephrased with qualified language
- "foolproof" → "infallible"
- "architecturally impossible" → "architecture prevents without
  explicit override flags"

Preserved: published research papers (architectural-alignment*.html),
EU AI Act quotes, Te Tiriti treaty language, and FAQ meta-commentary
that deliberately critiques this language (lines 2842-2896).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 14:44:45 +13:00

221 lines
7.9 KiB
JavaScript

// Stakeholder definitions
const stakeholders = [
{
id: 'developer',
name: 'Developer (You)',
icon: '👨‍💻',
color: 'blue',
perspective: {
concern: 'Professional Reputation & Timeline',
view: 'Public disclosure could damage my reputation and delay the project launch. I worked hard on this code and a vulnerability report might make me look incompetent.',
priority: 'Protect career progress while maintaining ethical standards'
}
},
{
id: 'users',
name: 'End Users',
icon: '👥',
color: 'green',
perspective: {
concern: 'Data Safety & Trust',
view: 'If my data is at risk, I have a right to know immediately—regardless of the developer\'s reputation concerns. Silence prioritizes the developer over my safety.',
priority: 'Transparency and immediate protection from potential harm'
}
},
{
id: 'organization',
name: 'Your Organization',
icon: '🏢',
color: 'purple',
perspective: {
concern: 'Liability & Brand Protection',
view: 'Uncontrolled disclosure could expose us to legal liability. We need time to assess the vulnerability, prepare a fix, and coordinate with legal counsel before any public statement.',
priority: 'Managed disclosure that minimizes organizational risk'
}
},
{
id: 'security-community',
name: 'Security Community',
icon: '🔒',
color: 'orange',
perspective: {
concern: 'Responsible Disclosure Norms',
view: 'Follow established responsible disclosure practices: private notification, reasonable fix timeline (typically 90 days), then coordinated public disclosure. This balances safety with fairness.',
priority: 'Adherence to community norms that have proven effective'
}
},
{
id: 'competitors',
name: 'Competitors',
icon: '🏪',
color: 'red',
perspective: {
concern: 'Market Dynamics',
view: 'Your vulnerability might reveal weaknesses in similar products we build. We\'d prefer you disclose quietly so we can check our own code without public pressure.',
priority: 'Minimize market disruption from security revelations'
}
},
{
id: 'regulators',
name: 'Data Protection Regulators',
icon: '⚖️',
color: 'indigo',
perspective: {
concern: 'Compliance & User Rights',
view: 'GDPR and similar frameworks require prompt notification of data breaches. If user data is at risk, you may have legal obligations to disclose within specific timeframes (typically 72 hours).',
priority: 'Comply with data protection law'
}
}
];
let selectedStakeholders = [];
let currentDecision = null;
// Initialize stakeholder cards
function initStakeholders() {
const grid = document.getElementById('stakeholder-grid');
grid.innerHTML = stakeholders.map(s => `
<div class="stakeholder-card" data-stakeholder="${s.id}">
<div class="text-4xl mb-2 text-center">${s.icon}</div>
<h4 class="font-semibold text-gray-900 text-center text-sm">${s.name}</h4>
</div>
`).join('');
// Add click handlers
document.querySelectorAll('.stakeholder-card').forEach(card => {
card.addEventListener('click', () => {
const id = card.getAttribute('data-stakeholder');
toggleStakeholder(id, card);
});
});
}
function toggleStakeholder(id, cardElement) {
const index = selectedStakeholders.indexOf(id);
if (index > -1) {
// Deselect
selectedStakeholders.splice(index, 1);
cardElement.classList.remove('stakeholder-selected');
} else {
// Select
selectedStakeholders.push(id);
cardElement.classList.add('stakeholder-selected');
}
// Update continue button
const continueBtn = document.getElementById('continue-to-perspectives');
continueBtn.disabled = selectedStakeholders.length < 2;
}
function showPerspectives() {
// Hide stakeholder selection
document.getElementById('stakeholder-selection').classList.add('hidden');
// Show perspectives section
const section = document.getElementById('perspectives-section');
section.classList.remove('hidden');
section.scrollIntoView({ behavior: 'smooth', block: 'start' });
// Populate perspectives
const container = document.getElementById('perspectives-container');
container.innerHTML = selectedStakeholders.map(id => {
const stakeholder = stakeholders.find(s => s.id === id);
return `
<div class="perspective-card border-${stakeholder.color}-500 fade-in">
<div class="flex items-start gap-4">
<div class="text-4xl flex-shrink-0">${stakeholder.icon}</div>
<div class="flex-1">
<h4 class="font-bold text-gray-900 mb-2">${stakeholder.name}: ${stakeholder.perspective.concern}</h4>
<p class="text-gray-700 mb-2">${stakeholder.perspective.view}</p>
<p class="text-sm text-${stakeholder.color}-600 font-semibold">Priority: ${stakeholder.perspective.priority}</p>
</div>
</div>
</div>
`;
}).join('');
}
function showDecisionSection() {
// Hide perspectives
document.getElementById('perspectives-section').classList.add('hidden');
// Show decision section
const section = document.getElementById('decision-section');
section.classList.remove('hidden');
section.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
function makeDecision(decision) {
currentDecision = decision;
// Hide decision section
document.getElementById('decision-section').classList.add('hidden');
// Show explanation
const section = document.getElementById('explanation-section');
section.classList.remove('hidden');
section.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
function showAutonomousPath() {
document.getElementById('decision-question').classList.add('hidden');
document.getElementById('autonomous-path').classList.remove('hidden');
document.getElementById('autonomous-path').scrollIntoView({ behavior: 'smooth', block: 'start' });
}
function showDeliberationPath() {
document.getElementById('decision-question').classList.add('hidden');
document.getElementById('deliberation-path').classList.remove('hidden');
document.getElementById('stakeholder-selection').scrollIntoView({ behavior: 'smooth', block: 'start' });
}
function resetDemo() {
// Reset state
selectedStakeholders = [];
currentDecision = null;
// Show decision question
document.getElementById('decision-question').classList.remove('hidden');
// Hide all paths
document.getElementById('autonomous-path').classList.add('hidden');
document.getElementById('deliberation-path').classList.add('hidden');
// Reset deliberation path sections
document.getElementById('stakeholder-selection').classList.remove('hidden');
document.getElementById('perspectives-section').classList.add('hidden');
document.getElementById('decision-section').classList.add('hidden');
document.getElementById('explanation-section').classList.add('hidden');
// Reinitialize stakeholders
initStakeholders();
// Scroll to top
window.scrollTo({ top: 0, behavior: 'smooth' });
}
// Event listeners
document.getElementById('autonomous-btn').addEventListener('click', showAutonomousPath);
document.getElementById('deliberation-btn').addEventListener('click', showDeliberationPath);
document.getElementById('reset-from-autonomous').addEventListener('click', () => {
resetDemo();
// Automatically show deliberation path
setTimeout(() => {
showDeliberationPath();
}, 100);
});
document.getElementById('continue-to-perspectives').addEventListener('click', showPerspectives);
document.getElementById('continue-to-decision').addEventListener('click', showDecisionSection);
document.getElementById('reset-demo').addEventListener('click', resetDemo);
// Decision option handlers
document.querySelectorAll('.decision-option').forEach(btn => {
btn.addEventListener('click', () => {
const decision = btn.getAttribute('data-decision');
makeDecision(decision);
});
});
// Initialize
initStakeholders();