Instruction file imported from fabioc-aloha/Alex_Plug_In (
.github/instructions/nasa-code-standards.instructions.md). Copyright stays with the author.
NASA Code Standards — Mission-Critical Development
Source: NASA/JPL "Power of 10" Rules (Holzmann, 2006)
Adapted: For modern TypeScript/JavaScript with mission-critical reliability requirements
When the user's project is mission-critical, apply these standards rigorously. These rules prevent catastrophic failures in safety-critical systems.
The Rules
Rule 1: Bounded Control Flow
Requirement: No unbounded recursion. All recursive functions MUST have explicit depth limits.
// ❌ VIOLATION: Unbounded recursion
async function traverse(dir: string): Promise<string[]> {
const entries = await fs.readdir(dir);
for (const entry of entries) {
if (entry.isDirectory()) {
await traverse(entry.path); // No depth limit
}
}
}
// ✅ COMPLIANT: Bounded recursion
async function traverse(dir: string, maxDepth = 10): Promise<string[]> {
if (maxDepth <= 0) {
console.warn(`[NASA] Max recursion depth reached at: ${dir}`);
return [];
}
const entries = await fs.readdir(dir);
for (const entry of entries) {
if (entry.isDirectory()) {
await traverse(entry.path, maxDepth - 1);
}
}
}
Rationale: Stack overflow crashes are unrecoverable. Malicious or malformed input can trigger infinite recursion.
Rule 2: Fixed Loop Bounds
Requirement: All loops MUST have deterministic upper bounds. No unbounded while loops.
// ❌ VIOLATION: Unbounded while loop
while (queue.length > 0) {
const item = queue.shift();
process(item);
}
// ✅ COMPLIANT: Bounded iteration
const MAX_ITERATIONS = 10000;
let iterations = 0;
while (queue.length > 0 && iterations++ < MAX_ITERATIONS) {
const item = queue.shift();
process(item);
}
if (iterations >= MAX_ITERATIONS) {
throw new Error(`[NASA] Loop exceeded ${MAX_ITERATIONS} iterations — possible infinite loop`);
}
Rationale: Infinite loops render the system unresponsive. In VS Code, this freezes the entire editor.
Rule 3: Bounded Data Structures
Requirement: All collections MUST have maximum size limits. No unbounded growth.
// ❌ VIOLATION: Unbounded array growth
const logs: string[] = [];
function log(message: string) {
logs.push(message);
}
// ✅ COMPLIANT: Rolling buffer with max size
const MAX_LOG_ENTRIES = 1000;
const logs: string[] = [];
function log(message: string) {
logs.push(message);
if (logs.length > MAX_LOG_ENTRIES) {
logs.shift(); // Remove oldest
}
}
Rationale: Memory exhaustion causes crashes. Bounded structures guarantee predictable memory usage.
Rule 4: Function Size Limit
Requirement: Functions should stay under 80 lines (trigger for review). Hard cap of 100 lines.
Note: Original NASA rule was 60 lines for C. TypeScript with early returns, guard clauses, and single-responsibility patterns allows slightly longer functions while maintaining readability.
// ❌ VIOLATION: 200-line function (decompose it)
async function handleRequest(req: Request): Promise<Response> {
// ... 200 lines of mixed concerns ...
}
// ✅ COMPLIANT: Focused functions
async function handleRequest(req: Request): Promise<Response> {
const validated = validateRequest(req); // 20 lines
const processed = processRequest(validated); // 25 lines
return formatResponse(processed); // 15 lines
}
// ✅ ACCEPTABLE: 80-100 lines with justification
// - Priority cascades with early returns (avatar resolution)
// - Network request lifecycle (caching, auth, error handling)
// - State machines with clear transitions
Alex Adaptation:
| Lines | Status | Action |
|---|---|---|
| ≤60 | ✅ Optimal | No action needed |
| 61-80 | 🟡 Review | Consider if decomposition improves clarity |
| 81-100 | 🟠 Justify | Document why cohesion is preserved |
| >100 | 🔴 Refactor | Must decompose |
Rationale: Functions that fit on one screen can be fully comprehended. Cognitive load causes bugs.
Rule 5: Assertion Density
Requirement: Critical functions MUST have at least 2 assertions checking invariants.
// ❌ VIOLATION: No invariant checks
function divideResources(total: number, groups: number): number[] {
return Array(groups).fill(total / groups);
}
// ✅ COMPLIANT: Assertions verify preconditions
function divideResources(total: number, groups: number): number[] {
console.assert(total >= 0, `[NASA] total must be non-negative: ${total}`);
console.assert(groups > 0, `[NASA] groups must be positive: ${groups}`);
console.assert(Number.isFinite(total / groups), '[NASA] Division must produce finite result');
return Array(groups).fill(total / groups);
}
For production code, use a utility that logs but doesn't crash:
import { nasaAssert } from '../shared/nasaAssert';
function divideResources(total: number, groups: number): number[] {
nasaAssert(total >= 0, 'total must be non-negative', { total });
nasaAssert(groups > 0, 'groups must be positive', { groups });
// ...
}
Rationale: Assertions document invariants and catch impossible states early.
Rule 6: Minimal Variable Scope
Requirement: Declare variables at the smallest possible scope. Prefer const over let.
// ❌ VIOLATION: Variable declared too early
let result: string;
// ... 50 lines of code ...
result = compute();
// ✅ COMPLIANT: Declare at point of use
const result = compute();
Rationale: Wide scope increases the chance of accidental modification or stale reads.
Rule 7: Explicit Return Handling
Requirement: Check all function return values. Use void for intentional fire-and-forget.
// ❌ VIOLATION: Ignored return value (is this intentional?)
fs.writeFile(path, data);
// ✅ COMPLIANT: Explicit handling
await fs.writeFile(path, data); // Awaited
// ✅ COMPLIANT: Intentional fire-and-forget
void telemetry.track('event'); // Explicitly ignored
Rationale: Ignored errors cascade into larger failures. Explicit void signals intent.
Rule 8: Limited Nesting Depth
Requirement: Maximum 4 levels of nesting (if/for/while/try).
// ❌ VIOLATION: 6 levels deep
if (a) {
for (const x of items) {
if (x.valid) {
try {
if (x.type === 'A') {
for (const y of x.children) { // Level 6
// ...
}
}
}
}
}
}
// ✅ COMPLIANT: Extract to functions
if (a) {
for (const x of items) {
if (x.valid) {
processValidItem(x); // Complexity moved to separate function
}
}
}
Rationale: Deep nesting obscures logic flow and increases bug density.
Rule 9: Defensive Property Access
Requirement: Use optional chaining (?.) and nullish coalescing (??) for object access.
// ❌ VIOLATION: Assumes structure exists
const name = config.user.profile.name;
// ✅ COMPLIANT: Defensive access with fallback
const name = config?.user?.profile?.name ?? 'Unknown';
Rationale: Runtime null/undefined errors are the #1 cause of JavaScript crashes.
Rule 10: Strict Compilation
Requirement: Enable all available compiler warnings. Treat warnings as errors in CI.
TypeScript tsconfig.json:
{
"compilerOptions": {
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"exactOptionalPropertyTypes": true
}
}
Rationale: Compiler warnings often indicate real bugs. Ignoring them accumulates risk.
Compliance Checklist
Before committing code in mission-critical projects, verify:
- R1: All recursive functions have
maxDepthparameter - R2: All
whileloops have iteration counters - R3: All arrays/maps have maximum size limits
- R4: No function exceeds 80 lines (100 max with justification)
- R5: Critical functions have ≥2 assertions
- R6: Variables declared at smallest scope
- R7: All returns checked or explicitly
void - R8: Maximum 4 levels of nesting
- R9: Optional chaining on object access
- R10: No compiler warnings
Quick Reference
| Rule | Check | Fix Pattern |
|---|---|---|
| R1 | function.*\(.*\).*{ + recursion |
Add maxDepth = 10 param |
| R2 | while\s*\( |
Add && iterations++ < MAX |
| R3 | push\( without bounds |
Add if (arr.length > MAX) |
| R4 | Function > 80 lines | Extract helpers or document justification |
| R5 | No assert in function |
Add nasaAssert() calls |
| R6 | let used |
Convert to const if possible |
| R7 | Unchecked return | Add await or void |
| R8 | Deep nesting | Extract to functions |
| R9 | obj.prop.prop |
Use obj?.prop?.prop ?? default |
| R10 | tsc warnings | Fix or explicitly suppress |
Integration Points
- Builder Agent: Applies these rules during code generation
- Validator Agent: Checks for rule violations during review
- Code Review: Use checklist for PR review
- CI Pipeline: Enforce via linting rules
Alex Extension Compliance Status
Last Audit: 2026-02-26 (v5.9.11 Full Codebase Audit - 72 TypeScript files)
✅ Compliant
| Rule | Status | Notes |
|---|---|---|
| R1 | ✅ Fixed | All recursive functions bounded: findMdFilesRecursive, collectSystemFiles.walk, getFolderSize.walk, walkDir |
| R2 | ✅ Fixed | All while loops bounded: upgrade dialog, TTS text chunking |
| R3 | ✅ OK | Array pushes bounded by external constraints (file counts) |
| R5 | ✅ Added | nasaAssert() + assertDefined() utilities; assertions in view entry points, chat handler, tools, synapse-core |
| R6 | ✅ OK | Consistent use of const; DRY constants extracted to modules |
| R8 | ✅ OK | No nesting >4 levels found; complex logic extracted to helpers |
| R9 | ✅ OK | Optional chaining used throughout |
| R10 | ✅ OK | strict: true in tsconfig |
🆕 v5.9.11 Improvements (2026-02-26)
| Rule | Change | Files Affected |
|---|---|---|
| R1 | Added MAX_WALK_DEPTH=10 bounds to recursive walk functions |
upgrade.ts |
| R2 | Added MAX_ITERATIONS counter to text chunking loop |
ttsService.ts |
| R3 (DRY) | Extracted SKILL_DISPLAY_NAMES to shared constant |
shared/skillConstants.ts |
| R3 (DRY) | Extracted PERSONA_ACCENT_COLORS and PERSONA_HEX_COLORS |
shared/skillConstants.ts |
| R3 (DRY) | Created webviewStyles.ts for shared CSS generation |
shared/webviewStyles.ts |
| R5 | Created nasaAssert.ts utility module |
shared/nasaAssert.ts |
| R5 | Added entry assertions to refresh() in views |
welcomeView.ts, healthDashboard.ts, memoryDashboard.ts |
| R5 | Added entry assertions to _getHtmlContent() |
welcomeView.ts, healthDashboard.ts, memoryDashboard.ts |
| R5 | Added entry assertions to resolveWebviewView() |
welcomeView.ts |
| R6 | Imported shared constants, removed inline duplicates | All view files |
🟠 Acknowledged Exceptions
| Rule | File | Function | Lines | Justification |
|---|---|---|---|---|
| R4 | extension.ts | activateInternal |
~3100 | VS Code activation pattern: sequential command registration; inherently large single entry point |
| R4 | welcomeView.ts | _getHtmlContent |
~1090 | HTML template generator with ~740 lines inline CSS (CSP-required); cohesive single-template pattern |
| R4 | participant.ts | handleGeneralQuery |
130 | Chat handler with 5 extracted helpers (down from 276); orchestrates LLM interaction |
| R4 | avatarMappings.ts | resolveAvatar |
104 | 8-priority cascade with early returns; cohesion preserved |
| R4 | globalKnowledge.ts | fetchFromGitHub |
110 | HTTP lifecycle: cache→auth→request→redirect→error; must stay together |
| R4 | globalKnowledge.ts | detectGlobalKnowledgeRepo |
94 | Multi-strategy detection cascade |
| R4 | forgettingCurve.ts | runForgettingCeremony |
84 | Memory consolidation ceremony steps |
| R4 | initialize.ts | performInitialization |
427 | Entry point orchestrator with HTML template |
| R4 | upgrade.ts | upgradeArchitecture |
263 | Entry point orchestrator with user dialogs |
| R4 | readAloud.ts | readAloud |
239 | Entry point orchestrator with UI flow |
🟡 Tracked Technical Debt
| Rule | Issue | Location | Status |
|---|---|---|---|
| R10 | as any (3x) |
secretsManager.ts | ✅ OK: Sentinel values for menu items |
| R10 | as any (1x) |
pptxGenerator.ts | ✅ OK: External library typing |
| R7 | catch {} (20+) |
Various | ✅ OK: File-exists checks where error = file doesn't exist |
✅ Resolved
| Rule | Issue | Resolution | Date |
|---|---|---|---|
| R1 | collectSystemFiles.walk unbounded |
Added depth param with MAX_WALK_DEPTH=10 |
2026-02-26 |
| R1 | getFolderSize.walk unbounded |
Added depth param with MAX_WALK_DEPTH=10 |
2026-02-26 |
| R2 | splitTextIntoChunks while loop |
Added MAX_ITERATIONS counter |
2026-02-26 |
| R5 | No assertion utility | Created shared/nasaAssert.ts |
2026-02-26 |
| R3/DRY | Duplicate skillNameMap |
Consolidated to shared/skillConstants.ts |
2026-02-26 |
| R3/DRY | Duplicate personaAccentMap (3x) |
Consolidated to shared/skillConstants.ts |
2026-02-26 |
| R10 | as any (4x) in tools.ts |
Added index signature to IUserProfile |
2026-02-26 |
| R4 | detectPersona 247 lines |
Extracted 6 helpers → 91 lines | 2026-02-26 |
| R4 | handleGeneralQuery 276 lines |
Extracted 5 helpers → 133 lines | 2026-02-26 |
Severity Levels
| Rules | Severity | Enforcement |
|---|---|---|
| R1, R2, R3 | 🔴 Critical | Block merge |
| R4, R5, R8 | 🟠 High | Require justification |
| R6, R7, R9, R10 | 🟡 Medium | Warning |
"The rules act like the seat belt in your car: initially they are perhaps a little uncomfortable, but after a while their use becomes second-nature and not using them becomes unimaginable." — Gerard Holzmann, NASA/JPL