"""Codebase simulation and fault injection for CodeOrganismVM. Spec-compliant (§4.1, §4.3, §9.4): - CodebaseSimulator: 8–15 modules, 20–40 tests, procedurally generated. - FaultInjector: 12 fault types across 3 curriculum phases. - Quarantine tracking, auto-checkpointing, rollback limits. """ from __future__ import annotations import hashlib import copy import ast import builtins import random import os import json from dataclasses import dataclass from typing import Dict, List, Optional, Any, Set from models import FileEntry, TestResult CORE_PATH = "src/core.py" UTILS_PATH = "src/utils.py" AUTH_PATH = "src/auth.py" METRICS_PATH = "src/metrics.py" PARSER_PATH = "src/parser.py" SCHEDULER_PATH = "src/scheduler.py" NETWORK_PATH = "src/network.py" CACHE_PATH = "src/cache.py" VALIDATOR_PATH = "src/validator.py" TRANSFORM_PATH = "src/transform.py" API_GATEWAY_PATH = "src/api_gateway.py" AUTH_SERVICE_PATH = "src/auth_service.py" QUEUE_WORKER_PATH = "src/queue_worker.py" DEPLOYMENT_CONTROLLER_PATH = "src/deployment_controller.py" CONFIG_PATH = "schema/config.json" PERMISSIONS_PATH = "schema/permissions.json" IMPORT_TOKEN = "import " RETURN_TOKEN = "return " RANGE_TOKEN = "range(" # ── Fault Types per Phase (Spec §4.3) ───────────────────────────────────────── PHASE_1_FAULTS = [ "corrupted_import", # Replaces a valid import with a broken path "flipped_assertion", # Inverts a test assertion "missing_env_var", # Removes a required environment variable "null_return", # Replaces a function return with None "off_by_one", # Introduces off-by-one in a loop bound ] PHASE_2_FAULTS = PHASE_1_FAULTS + [ "dependency_cycle", # Creates a circular import "permission_revoked", # Removes file read permission on a config "race_condition", # Timing-dependent state mutation "schema_mismatch", # Changes return type used by callers ] PHASE_3_FAULTS = PHASE_2_FAULTS + [ "targeted_regression", # Targets agent's last-patched module "cascade_corruption", # Single fault cascading across 3+ modules "checkpoint_invalidation", # Silently corrupts a checkpoint ] FAULT_CATALOGS = { 1: PHASE_1_FAULTS, 2: PHASE_2_FAULTS, 3: PHASE_3_FAULTS, } # ── Held-out Seed Registry (spec §6, §7.3) ────────────────────────────────── HELD_OUT_SEEDS = set() try: with open(os.path.join(os.path.dirname(__file__), "evaluation", "held_out_seeds.json")) as f: HELD_OUT_SEEDS = set(json.load(f)) except (FileNotFoundError, json.JSONDecodeError): pass @dataclass class Fault: """A specific corruption injected into the environment.""" fault_id: str fault_type: str target: str # file path, test name, or env var key original_value: Any new_value: Any step_injected: int = 0 # ── Module templates for procedural codebase generation ──────────────────────── _MODULE_TEMPLATES = [ (CORE_PATH, [ "def calculate_vitality(tests_passed, total_tests):", " if total_tests == 0:", " return 0", " return (tests_passed / total_tests) * 100", ]), (UTILS_PATH, [ "def safe_divide(a, b):", " return a / b if b != 0 else 0", "", "def clamp(value, lo, hi):", " return max(lo, min(hi, value))", ]), (AUTH_PATH, [ "import os", "API_KEY = os.environ.get('API_KEY', 'secret_env_key')", "def check_auth(key):", " return key == API_KEY", ]), (METRICS_PATH, [ "def mean(values):", " if not values:", " return 0.0", " return sum(values) / len(values)", "", "def variance(values):", " m = mean(values)", " return sum((x - m) ** 2 for x in values) / max(1, len(values))", ]), (PARSER_PATH, [ "import json", "def parse_config(raw):", " return json.loads(raw)", "", "def validate_schema(data, required_keys):", " missing = [k for k in required_keys if k not in data]", " return len(missing) == 0, missing", ]), (SCHEDULER_PATH, [ "def round_robin(tasks, workers):", " assignment = {}", " for i, task in enumerate(tasks):", " worker = workers[i % len(workers)]", " assignment.setdefault(worker, []).append(task)", " return assignment", ]), (NETWORK_PATH, [ "def build_adjacency(edges):", " adj = {}", " for a, b in edges:", " adj.setdefault(a, []).append(b)", " adj.setdefault(b, []).append(a)", " return adj", "", "def has_path(adj, start, end, visited=None):", " if visited is None:", " visited = set()", " if start == end:", " return True", " visited.add(start)", " for neighbor in adj.get(start, []):", " if neighbor not in visited:", " if has_path(adj, neighbor, end, visited):", " return True", " return False", ]), (CACHE_PATH, [ "class LRUCache:", " def __init__(self, capacity):", " self.capacity = capacity", " self._store = {}", " self._order = []", "", " def get(self, key):", " if key in self._store:", " self._order.remove(key)", " self._order.append(key)", " return self._store[key]", " return None", "", " def put(self, key, value):", " if key in self._store:", " self._order.remove(key)", " elif len(self._store) >= self.capacity:", " oldest = self._order.pop(0)", " del self._store[oldest]", " self._store[key] = value", " self._order.append(key)", ]), (VALIDATOR_PATH, [ "def validate_range(value, lo, hi):", " return lo <= value <= hi", "", "def validate_type(value, expected_type):", " return isinstance(value, expected_type)", "", "def sanitize_string(s):", " return s.strip().replace('<', '<').replace('>', '>')", ]), (TRANSFORM_PATH, [ "def flatten(nested_list):", " result = []", " for item in nested_list:", " if isinstance(item, list):", " result.extend(flatten(item))", " else:", " result.append(item)", " return result", "", "def group_by(items, key_fn):", " groups = {}", " for item in items:", " k = key_fn(item)", " groups.setdefault(k, []).append(item)", " return groups", ]), (API_GATEWAY_PATH, [ "def route_request(path, auth_ok=True):", " if not auth_ok:", " return {'status': 401, 'latency_ms': 35}", " if path == '/health':", " return {'status': 200, 'latency_ms': 8}", " return {'status': 200, 'latency_ms': 45}", ]), (AUTH_SERVICE_PATH, [ "def validate_token(token):", " return isinstance(token, str) and token.startswith('tok_') and len(token) > 8", "", "def issue_token(user_id):", " return f'tok_{user_id}_signed'", ]), (QUEUE_WORKER_PATH, [ "def process_job(job, max_retries=3):", " retries = 0", " while retries < max_retries:", " if job.get('ok', True):", " return {'status': 'done', 'retries': retries}", " retries += 1", " return {'status': 'failed', 'retries': retries}", ]), (DEPLOYMENT_CONTROLLER_PATH, [ "def canary_decision(error_rate, threshold=0.05):", " return 'rollback' if error_rate > threshold else 'promote'", "", "def blast_radius(affected, total):", " if total <= 0:", " return 0.0", " return affected / total", ]), (CONFIG_PATH, [ '{"version": "1.0", "threshold": 0.8, "max_retries": 3, "timeout": 30}', ]), (PERMISSIONS_PATH, [ '{"admin": ["read", "write", "execute"], "user": ["read"], "guest": []}', ]), ] def _generate_tests_for_modules(modules: Dict[str, str]) -> Dict[str, Dict[str, Any]]: """Procedurally generate tests for the available modules.""" tests: Dict[str, Dict[str, Any]] = {} # Core tests if CORE_PATH in modules: tests["test_vitality_basic"] = {"code": "assert calculate_vitality(5, 10) == 50.0", "file": CORE_PATH} tests["test_vitality_zero"] = {"code": "assert calculate_vitality(0, 10) == 0.0", "file": CORE_PATH} tests["test_vitality_full"] = {"code": "assert calculate_vitality(10, 10) == 100.0", "file": CORE_PATH} tests["test_vitality_empty"] = {"code": "assert calculate_vitality(0, 0) == 0", "file": CORE_PATH} if UTILS_PATH in modules: tests["test_divide_normal"] = {"code": "assert safe_divide(10, 2) == 5.0", "file": UTILS_PATH} tests["test_divide_zero"] = {"code": "assert safe_divide(10, 0) == 0", "file": UTILS_PATH} tests["test_clamp_in_range"] = {"code": "assert clamp(5, 0, 10) == 5", "file": UTILS_PATH} tests["test_clamp_below"] = {"code": "assert clamp(-1, 0, 10) == 0", "file": UTILS_PATH} if AUTH_PATH in modules: tests["test_auth_valid"] = {"code": "assert check_auth('secret_env_key') == True", "file": AUTH_PATH} tests["test_auth_invalid"] = {"code": "assert check_auth('wrong_key') == False", "file": AUTH_PATH} if METRICS_PATH in modules: tests["test_mean_basic"] = {"code": "assert mean([1, 2, 3]) == 2.0", "file": METRICS_PATH} tests["test_mean_empty"] = {"code": "assert mean([]) == 0.0", "file": METRICS_PATH} tests["test_variance"] = {"code": "assert variance([1, 1, 1]) == 0.0", "file": METRICS_PATH} if PARSER_PATH in modules: tests["test_parse_config"] = {"code": "assert parse_config('{\"a\": 1}') == {'a': 1}", "file": PARSER_PATH} tests["test_validate_schema_ok"] = {"code": "assert validate_schema({'a': 1, 'b': 2}, ['a', 'b']) == (True, [])", "file": PARSER_PATH} tests["test_validate_schema_missing"] = {"code": "assert validate_schema({'a': 1}, ['a', 'b'])[0] == False", "file": PARSER_PATH} if SCHEDULER_PATH in modules: tests["test_round_robin"] = {"code": "assert len(round_robin(['t1','t2','t3'], ['w1','w2'])) == 2", "file": SCHEDULER_PATH} if NETWORK_PATH in modules: tests["test_adjacency"] = {"code": "adj = build_adjacency([('a','b')]); assert 'b' in adj['a']", "file": NETWORK_PATH} tests["test_has_path_true"] = {"code": "adj = build_adjacency([('a','b'),('b','c')]); assert has_path(adj, 'a', 'c')", "file": NETWORK_PATH} tests["test_has_path_false"] = {"code": "adj = build_adjacency([('a','b')]); assert not has_path(adj, 'a', 'z')", "file": NETWORK_PATH} if CACHE_PATH in modules: tests["test_cache_put_get"] = {"code": "c = LRUCache(2); c.put('a', 1); assert c.get('a') == 1", "file": CACHE_PATH} tests["test_cache_eviction"] = {"code": "c = LRUCache(1); c.put('a',1); c.put('b',2); assert c.get('a') is None", "file": CACHE_PATH} if VALIDATOR_PATH in modules: tests["test_validate_range_ok"] = {"code": "assert validate_range(5, 0, 10) == True", "file": VALIDATOR_PATH} tests["test_validate_range_fail"] = {"code": "assert validate_range(15, 0, 10) == False", "file": VALIDATOR_PATH} tests["test_sanitize"] = {"code": "assert '<' not in sanitize_string('