#!/bin/bash # W5 parity/performance gate for the config-selectable WASM backend. # Runs on k-uce. Requires root because the live service reads /etc/uce/settings.cfg. set -euo pipefail cd "$(dirname "$0")/../.." if [ "${EUID:-$(id -u)}" -ne 0 ]; then echo "run_w5.sh must run as root so it can switch /etc/uce/settings.cfg and restart uce.service" >&2 exit 1 fi OUT=${UCE_W5_OUT:-/tmp/uce/wasm-w5} CONFIG=${UCE_CONFIG:-/etc/uce/settings.cfg} mkdir -p "$OUT" BACKUP="$OUT/settings.cfg.before-w5" cp "$CONFIG" "$BACKUP" restore_on_error() { if [ "${UCE_W5_KEEP_BACKEND:-0}" != "1" ]; then cp "$BACKUP" "$CONFIG" systemctl restart uce.service >/dev/null 2>&1 || true fi } trap restore_on_error EXIT set_backend() { local enabled="$1" python3 - "$CONFIG" "$enabled" <<'PY' import sys from pathlib import Path path = Path(sys.argv[1]) enabled = sys.argv[2] s = path.read_text() lines = s.splitlines() found = False for i, line in enumerate(lines): if line.startswith('WASM_BACKEND_ENABLED='): lines[i] = f'WASM_BACKEND_ENABLED={enabled}' found = True if not found: lines.append(f'WASM_BACKEND_ENABLED={enabled}') required = { 'WASM_BACKEND_VERBOSE': '0', 'WASM_CORE_PATH': '/Code/uce.openfu.com/uce/bin/wasm/core.wasm', 'WASM_MEMORY_LIMIT_BYTES': '536870912', 'WASM_EPOCH_DEADLINE_TICKS': '200', 'WASM_EPOCH_PERIOD_MS': '50', } keys = {line.split('=', 1)[0] for line in lines if '=' in line} for key, value in required.items(): if key not in keys: lines.append(f'{key}={value}') path.write_text('\n'.join(lines) + '\n') PY systemctl restart uce.service >/dev/null sleep 1 } summarize_json() { python3 - "$1" <<'PY' import json, sys rows = json.load(open(sys.argv[1])) print(f"{sys.argv[1]}: {sum(1 for r in rows if r.get('ok'))}/{len(rows)}") PY } # Native reference baseline. set_backend 0 python3 tests/run_network_tests.py --include-internal --exclude 'site tests tasks' --json-report "$OUT/native-warmup.json" >/dev/null || true python3 tests/run_network_tests.py --include-internal --json-report "$OUT/native-network.json" python3 tests/wasm_benchmark.py --out-dir "$OUT/native-benchmark" --samples "${UCE_W5_BENCH_SAMPLES:-20}" --timeout 30 >/dev/null # WASM default backend with W5 native fallbacks for host-owned surfaces. set_backend 1 UCE_INCLUDE_WASM_KILL=1 python3 tests/run_network_tests.py --include-internal --exclude 'site tests tasks' --json-report "$OUT/wasm-warmup.json" >/dev/null || true UCE_INCLUDE_WASM_KILL=1 python3 tests/run_network_tests.py --include-internal --json-report "$OUT/wasm-network.json" python3 tests/run_network_tests.py --include-internal --match starter --json-report "$OUT/wasm-starter.json" python3 tests/wasm_benchmark.py \ --out-dir "$OUT/benchmark" \ --backend-label wasm \ --compare-native-json "$OUT/native-benchmark/benchmark.json" \ --samples "${UCE_W5_BENCH_SAMPLES:-20}" \ --timeout 30 python3 tests/wasm_site_audit.py --out-dir "$OUT" >/dev/null python3 - "$OUT" <<'PY' import json, sys from pathlib import Path out = Path(sys.argv[1]) network = json.loads((out / 'wasm-network.json').read_text()) starter = json.loads((out / 'wasm-starter.json').read_text()) bench = json.loads((out / 'benchmark' / 'benchmark.json').read_text()) failures = [r for r in network if not r.get('ok')] + [r for r in starter if not r.get('ok')] + [r for r in bench if not r.get('ok')] structural = [] if len(network) < 80: structural.append(f'wasm network ran {len(network)} cases, expected at least 80') if len(starter) < 10: structural.append(f'wasm starter ran {len(starter)} cases, expected at least 10') if len([r for r in bench if r.get('backend') == 'wasm']) < 3: structural.append('wasm benchmark rows < 3') if failures or structural: print('W5 HARNESS: FAIL') for item in structural: print(item) for item in failures: print(item) raise SystemExit(1) print('W5 HARNESS: PASS') print(f'network_cases={len(network)} starter_cases={len(starter)} benchmark_rows={len(bench)}') print(f'reports={out}') PY if [ "${UCE_W5_KEEP_BACKEND:-0}" = "1" ]; then trap - EXIT printf 'WASM backend left enabled in %s\n' "$CONFIG" else cp "$BACKUP" "$CONFIG" systemctl restart uce.service >/dev/null trap - EXIT fi