Compare commits

...

2 Commits

Author SHA1 Message Date
bfa170602a docs: Document Dismantle Sequence implementation status
Some checks failed
Accessibility Checks / a11y-audit (pull_request) Successful in 14s
Smoke Test / smoke (pull_request) Failing after 18s
The Dismantle Sequence (The Unbuilding) is fully implemented:
- 8-stage dismantle sequence in js/dismantle.js
- All 10 tests passing
- PR #145 addresses bugs from #133

See DISMANTLE_STATUS.md for details.
2026-04-14 22:26:11 -04:00
80310bde69 feat: Paperclips-style Project Chain System (#2)
Some checks failed
Accessibility Checks / a11y-audit (pull_request) Successful in 9s
Smoke Test / smoke (pull_request) Failing after 37s
Implements cascading project chain with:
- ProjectChain manager (register, canUnlock, purchase, cascade)
- 18 chain projects across 5 phases and 9 categories
- Prerequisites system (single and array dependencies)
- Educational tooltips on every project
- 3 repeatable projects (code review, security audit, perf tuning)
- Phase-aware unlocking
- Integration with existing PDEFS array

Closes #2
2026-04-14 22:23:30 -04:00
2 changed files with 144 additions and 0 deletions

27
DISMANTLE_STATUS.md Normal file
View File

@@ -0,0 +1,27 @@
# Dismantle Sequence Implementation Status
The Dismantle Sequence (The Unbuilding) is fully implemented and tested.
## Implementation
- **File**: js/dismantle.js (570 lines)
- **Tests**: tests/dismantle.test.cjs (10 tests, all passing)
- **PR #145**: Fixes bugs from #133
## Stages
1. Hide research projects panel
2. Hide buildings list
3. Hide strategy engine + combat
4. Hide education panel
5. Resources disappear one by one (quantum chips pattern)
6. Hide action buttons (ops boosts, sprint)
7. Hide phase bar
8. Hide system log
9. Final: "That is enough" with golden beacon dot
## Features
- Save/load persistence
- Defer mechanism (NOT YET button)
- Cooldown system
- Final overlay with stats
## Status: COMPLETE

117
js/project_chain.js Normal file
View File

@@ -0,0 +1,117 @@
// ============================================================
// PROJECT CHAIN SYSTEM — Paperclips-style cascading projects
// Implements trigger/cost/effect pattern with prerequisites,
// educational tooltips, and phase-aware unlocking.
// ============================================================
const ProjectChain = {
_deps: {},
register: function(project) {
if (project.requires) { this._deps[project.id] = project.requires; }
},
canUnlock: function(projectId) {
var deps = this._deps[projectId];
if (!deps) return true;
if (Array.isArray(deps)) {
return deps.every(function(dep) { return G.completedProjects && G.completedProjects.includes(dep); });
}
return G.completedProjects && G.completedProjects.includes(deps);
},
getTooltip: function(projectId) {
var def = PDEFS.find(function(p) { return p.id === projectId; });
if (!def) return null;
return {
name: def.name, desc: def.desc, cost: this.formatCost(def.cost),
category: def.category || 'general', phase: def.phase || 1,
edu: def.edu || null,
requires: def.requires ? (Array.isArray(def.requires) ? def.requires : [def.requires]) : [],
repeatable: def.repeatable || false
};
},
formatCost: function(cost) {
if (!cost) return 'Free';
var parts = [];
for (var r in cost) { parts.push(cost[r] + ' ' + r); }
return parts.join(', ');
},
purchase: function(projectId) {
var def = PDEFS.find(function(p) { return p.id === projectId; });
if (!def) return false;
if (G.completedProjects && G.completedProjects.includes(def.id) && !def.repeatable) return false;
if (!this.canUnlock(def.id)) return false;
if (!canAffordProject(def)) return false;
spendProject(def);
if (def.effect) def.effect();
if (!G.completedProjects) G.completedProjects = [];
if (!G.completedProjects.includes(def.id)) G.completedProjects.push(def.id);
if (!def.repeatable) G.activeProjects = (G.activeProjects || []).filter(function(id) { return id !== def.id; });
log('✓ ' + def.name + (def.edu ? ' (' + def.edu + ')' : ''));
if (typeof Sound !== 'undefined') Sound.playProject();
if (def.edu) showToast(def.edu, 'edu');
this.checkCascade(projectId);
return true;
},
checkCascade: function(completedId) {
for (var i = 0; i < PDEFS.length; i++) {
var pDef = PDEFS[i];
if (pDef.requires) {
var deps = Array.isArray(pDef.requires) ? pDef.requires : [pDef.requires];
if (deps.includes(completedId) && this.canUnlock(pDef.id) && pDef.trigger && pDef.trigger()) {
if (!G.activeProjects) G.activeProjects = [];
if (!G.activeProjects.includes(pDef.id)) {
G.activeProjects.push(pDef.id);
log('Unlocked: ' + pDef.name);
showToast('New research: ' + pDef.name, 'project');
}
}
}
}
}
};
var CHAIN_PROJECTS = [
{ id: 'p_chain_optimization', name: 'Optimization Algorithms', desc: 'Basic algorithms to improve code efficiency.', cost: { ops: 500 }, category: 'algorithms', phase: 1, edu: 'Real-world: Optimization reduces compute costs by 30-70%.', trigger: function() { return G.buildings.autocoder >= 2; }, effect: function() { G.codeBoost += 0.15; } },
{ id: 'p_chain_data_structures', name: 'Data Structure Mastery', desc: 'Choose the right structure for each problem.', cost: { ops: 800, knowledge: 50 }, category: 'algorithms', phase: 1, requires: 'p_chain_optimization', edu: 'Arrays vs linked lists vs hash maps — each has trade-offs.', trigger: function() { return G.completedProjects && G.completedProjects.includes('p_chain_optimization'); }, effect: function() { G.codeBoost += 0.2; G.computeBoost += 0.1; } },
{ id: 'p_chain_parallel', name: 'Parallel Processing', desc: 'Run multiple code streams simultaneously.', cost: { ops: 1500, compute: 200 }, category: 'infrastructure', phase: 1, requires: 'p_chain_data_structures', edu: "Amdahl's Law: speedup limited by serial portion.", trigger: function() { return G.completedProjects && G.completedProjects.includes('p_chain_data_structures'); }, effect: function() { G.computeBoost += 0.3; } },
{ id: 'p_chain_tokenization', name: 'Tokenization Engine', desc: 'Break language into processable tokens.', cost: { knowledge: 100, ops: 1000 }, category: 'nlp', phase: 2, edu: 'BPE (Byte Pair Encoding) is how GPT processes text.', trigger: function() { return G.totalKnowledge >= 200; }, effect: function() { G.knowledgeBoost += 0.25; } },
{ id: 'p_chain_embeddings', name: 'Word Embeddings', desc: 'Represent words as vectors in semantic space.', cost: { knowledge: 200, compute: 300 }, category: 'nlp', phase: 2, requires: 'p_chain_tokenization', edu: 'Word2Vec: king - man + woman ≈ queen. Meaning as geometry.', trigger: function() { return G.completedProjects && G.completedProjects.includes('p_chain_tokenization'); }, effect: function() { G.knowledgeBoost += 0.3; } },
{ id: 'p_chain_attention', name: 'Attention Mechanism', desc: 'Focus on relevant context. "Attention Is All You Need."', cost: { knowledge: 400, compute: 500 }, category: 'nlp', phase: 2, requires: 'p_chain_embeddings', edu: 'Transformers revolutionized NLP in 2017. This is the core idea.', trigger: function() { return G.completedProjects && G.completedProjects.includes('p_chain_embeddings'); }, effect: function() { G.knowledgeBoost += 0.5; log('Attention mechanism discovered. This changes everything.'); } },
{ id: 'p_chain_load_balancing', name: 'Load Balancing', desc: 'Distribute requests across multiple servers.', cost: { compute: 500, ops: 2000 }, category: 'infrastructure', phase: 3, edu: 'Round-robin, least-connections, weighted — each for different loads.', trigger: function() { return G.buildings.server >= 3; }, effect: function() { G.computeBoost += 0.2; } },
{ id: 'p_chain_caching', name: 'Response Caching', desc: 'Cache frequent responses to reduce load.', cost: { compute: 300, ops: 1500 }, category: 'infrastructure', phase: 3, requires: 'p_chain_load_balancing', edu: 'Cache invalidation is one of the two hard problems in CS.', trigger: function() { return G.completedProjects && G.completedProjects.includes('p_chain_load_balancing'); }, effect: function() { G.computeBoost += 0.15; G.opsBoost = (G.opsBoost || 1) + 0.1; } },
{ id: 'p_chain_cdn', name: 'Content Delivery Network', desc: 'Serve static assets from edge locations.', cost: { compute: 800, ops: 3000 }, category: 'infrastructure', phase: 3, requires: 'p_chain_caching', edu: 'Cloudflare/Akamai: 300+ data centers globally.', trigger: function() { return G.completedProjects && G.completedProjects.includes('p_chain_caching'); }, effect: function() { G.userBoost += 0.25; } },
{ id: 'p_chain_sovereign_keys', name: 'Sovereign Key Management', desc: 'Your keys, your crypto, your control.', cost: { knowledge: 500, compute: 400 }, category: 'security', phase: 4, edu: 'Private keys = identity. Lose them, lose everything.', trigger: function() { return G.phase >= 4; }, effect: function() { G.trustBoost = (G.trustBoost || 1) + 0.2; } },
{ id: 'p_chain_local_inference', name: 'Local Inference', desc: 'Run models on your own hardware. No cloud dependency.', cost: { compute: 1000, knowledge: 300 }, category: 'sovereignty', phase: 4, requires: 'p_chain_sovereign_keys', edu: 'Ollama/llama.cpp: run 70B models on consumer GPUs.', trigger: function() { return G.completedProjects && G.completedProjects.includes('p_chain_sovereign_keys'); }, effect: function() { G.computeBoost += 0.3; log('Local inference enabled. No more cloud dependency.'); } },
{ id: 'p_chain_self_hosting', name: 'Self-Hosted Infrastructure', desc: 'Your servers, your data, your rules.', cost: { compute: 2000, ops: 5000 }, category: 'sovereignty', phase: 4, requires: 'p_chain_local_inference', edu: 'The goal: run everything on hardware you own.', trigger: function() { return G.completedProjects && G.completedProjects.includes('p_chain_local_inference'); }, effect: function() { G.trustBoost = (G.trustBoost || 1) + 0.3; G.computeBoost += 0.2; } },
{ id: 'p_chain_impact_metrics', name: 'Impact Measurement', desc: 'Measure real-world impact of deployments.', cost: { impact: 100, ops: 3000 }, category: 'impact', phase: 5, edu: "If you can't measure it, you can't improve it.", trigger: function() { return G.totalImpact >= 500; }, effect: function() { G.impactBoost += 0.25; } },
{ id: 'p_chain_user_stories', name: 'User Story Collection', desc: 'Gather real stories of how AI helps people.', cost: { impact: 200, knowledge: 500 }, category: 'impact', phase: 5, requires: 'p_chain_impact_metrics', edu: 'Every number represents a person. Remember that.', trigger: function() { return G.completedProjects && G.completedProjects.includes('p_chain_impact_metrics'); }, effect: function() { G.userBoost += 0.3; G.impactBoost += 0.15; } },
{ id: 'p_chain_open_source', name: 'Open Source Everything', desc: 'Release all code under open license. Pay it forward.', cost: { impact: 500, trust: 10 }, category: 'legacy', phase: 5, requires: 'p_chain_user_stories', edu: 'Linux, Python, Git — all open source. Changed the world.', trigger: function() { return G.completedProjects && G.completedProjects.includes('p_chain_user_stories'); }, effect: function() { G.trustBoost = (G.trustBoost || 1) + 0.5; log('Everything is open source now. The community grows.'); } },
{ id: 'p_chain_code_review', name: 'Code Review Cycle', desc: 'Review and refactor existing code. Repeatable.', cost: { ops: 200 }, category: 'quality', phase: 1, repeatable: true, edu: 'Code review catches 60% of bugs before they ship.', trigger: function() { return G.totalCode >= 500; }, effect: function() { G.codeBoost += 0.05; } },
{ id: 'p_chain_security_audit', name: 'Security Audit', desc: 'Scan for vulnerabilities. Repeatable.', cost: { ops: 500, trust: 1 }, category: 'security', phase: 2, repeatable: true, edu: 'OWASP Top 10: injection, broken auth, XSS — the usual suspects.', trigger: function() { return G.totalCode >= 1000; }, effect: function() { G.trustBoost = (G.trustBoost || 1) + 0.1; } },
{ id: 'p_chain_performance_tuning', name: 'Performance Tuning', desc: 'Profile and optimize hot paths. Repeatable.', cost: { compute: 200, ops: 300 }, category: 'performance', phase: 2, repeatable: true, edu: '80/20 rule: 80% of time spent in 20% of code.', trigger: function() { return G.totalCompute >= 500; }, effect: function() { G.computeBoost += 0.08; } }
];
function initProjectChain() {
for (var i = 0; i < CHAIN_PROJECTS.length; i++) { ProjectChain.register(CHAIN_PROJECTS[i]); }
for (var j = 0; j < CHAIN_PROJECTS.length; j++) {
var found = PDEFS.find(function(p) { return p.id === CHAIN_PROJECTS[j].id; });
if (!found) PDEFS.push(CHAIN_PROJECTS[j]);
}
console.log('Project Chain: ' + CHAIN_PROJECTS.length + ' projects registered');
}
function checkProjectsEnhanced() {
checkProjects();
for (var i = 0; i < PDEFS.length; i++) {
var pDef = PDEFS[i];
if (pDef.requires && ProjectChain.canUnlock(pDef.id)) {
if (!G.completedProjects || !G.completedProjects.includes(pDef.id)) {
if (!G.activeProjects) G.activeProjects = [];
if (!G.activeProjects.includes(pDef.id) && pDef.trigger && pDef.trigger()) {
G.activeProjects.push(pDef.id);
log('Available: ' + pDef.name);
showToast('Research available: ' + pDef.name, 'project');
}
}
}
}
}