#!/usr/bin/env python3 # file: scripts/audit_distribution_layout.py # version: 7 """Audit the static distribution layout expected by supported POCs.""" from __future__ import annotations import argparse import pathlib import sys FORBIDDEN_PATHS = ( "builds", ) REQUIRED_PATHS = ( "crates/apps/game-reflex-poc-desktop/Cargo.toml", "crates/apps/game-snake-poc-desktop/Cargo.toml", "crates/apps/game-reflex-poc-tauri/Cargo.toml", "crates/apps/game-reflex-poc-tauri/package.json", "crates/apps/game-reflex-poc-tauri/tsconfig.json", "crates/apps/game-reflex-poc-tauri/vite.config.ts", "crates/apps/game-reflex-poc-tauri/tauri.conf.json", "crates/apps/game-reflex-poc-tauri/capabilities/default.json", "crates/apps/game-reflex-poc-tauri/icons/icon.png", "crates/apps/game-reflex-poc-tauri/frontend/index.html", "crates/apps/game-reflex-poc-tauri/frontend/ts/main.ts", "crates/apps/game-reflex-poc-wasm/Cargo.toml", "crates/apps/game-snake-poc-wasm/Cargo.toml", "Web/game-snake-poc/package.json", "Web/game-snake-poc/tsconfig.json", "Web/game-snake-poc/vite.config.ts", "Web/game-snake-poc/frontend/main.html", "Web/game-snake-poc/frontend/sass/_simplebar.scss", "Web/game-snake-poc/frontend/sass/main.scss", "Web/game-snake-poc/frontend/ts/main.ts", "Web/game-snake-poc/frontend/ts/assets.ts", "Web/game-snake-poc/frontend/ts/lifecycle.ts", "Web/game-snake-poc/frontend/ts/logging.ts", "Web/game-snake-poc/frontend/ts/provenance.ts", "Android/game-reflex-poc/build.gradle", "Android/game-snake-poc/build.gradle", "scripts/build_android_rust.py", "scripts/build_reflex_tauri_wasm.py", "assets/common", "assets/game-reflex-poc", "assets/game-snake-poc", ) def audit_snake_web_shell(root: pathlib.Path) -> list[str]: """Validate the KSP-derived bounded SimpleBar shell contract.""" violations: list[str] = [] html_path = root / "Web/game-snake-poc/frontend/main.html" app_scss_path = root / "Web/game-snake-poc/frontend/sass/_app.scss" main_ts_path = root / "Web/game-snake-poc/frontend/ts/main.ts" if not html_path.exists() or not app_scss_path.exists() or not main_ts_path.exists(): return violations html = html_path.read_text(encoding="utf-8") app_scss = app_scss_path.read_text(encoding="utf-8") main_ts = main_ts_path.read_text(encoding="utf-8") required_html = ( '
', '
', '
', ) for fragment in required_html: if fragment not in html: violations.append(f"DIST-LAYOUT-003: Snake Web shell missing required HTML contract: {fragment}") if '
' in html: violations.append("DIST-LAYOUT-004: data-simplebar must be attached to the bounded app-content zone, not app-main") required_scss = ( ".app-scrollable {", "height: 100%;", "max-height: 100%;", ) for fragment in required_scss: if fragment not in app_scss: violations.append(f"DIST-LAYOUT-005: Snake Web shell missing required Sass contract: {fragment}") required_ts = ( 'import ResizeObserver from "resize-observer-polyfill";', 'import "simplebar";', ').ResizeObserver = ResizeObserver;', ) for fragment in required_ts: if fragment not in main_ts: violations.append(f"DIST-LAYOUT-006: Snake Web shell missing SimpleBar bootstrap contract: {fragment}") return violations def audit_snake_web_integration(root: pathlib.Path) -> list[str]: """Validate assets, lifecycle, logging and provenance wiring for the Snake Web POC.""" violations: list[str] = [] package_path = root / "Web/game-snake-poc/package.json" vite_path = root / "Web/game-snake-poc/vite.config.ts" main_path = root / "Web/game-snake-poc/frontend/ts/main.ts" lifecycle_path = root / "Web/game-snake-poc/frontend/ts/lifecycle.ts" provenance_path = root / "Web/game-snake-poc/frontend/ts/provenance.ts" wasm_manifest_path = root / "crates/apps/game-snake-poc-wasm/Cargo.toml" wasm_runtime_path = root / "crates/apps/game-snake-poc-wasm/src/runtime.rs" if not all(path.exists() for path in (package_path, vite_path, main_path, lifecycle_path, provenance_path, wasm_manifest_path, wasm_runtime_path)): return violations package = package_path.read_text(encoding="utf-8") vite = vite_path.read_text(encoding="utf-8") main = main_path.read_text(encoding="utf-8") lifecycle = lifecycle_path.read_text(encoding="utf-8") provenance = provenance_path.read_text(encoding="utf-8") wasm_manifest = wasm_manifest_path.read_text(encoding="utf-8") wasm_runtime = wasm_runtime_path.read_text(encoding="utf-8") required_fragments = ( (package, '"vite-plugin-static-copy"', "DIST-LAYOUT-007: Snake Web package must declare static asset packaging"), (vite, 'dest: "common/data", rename: { stripBase: true }', "DIST-LAYOUT-008: common Web assets must retain the common/data namespace without absolute source prefixes"), (vite, 'dest: "game/data", rename: { stripBase: true }', "DIST-LAYOUT-009: game Web assets must retain the game/data namespace without absolute source prefixes"), (main, 'loadSnakeWebAssets()', "DIST-LAYOUT-010: Snake Web startup must load runtime asset probes"), (main, 'bindBrowserLifecycle(session, stage)', "DIST-LAYOUT-011: Snake Web startup must bind browser lifecycle"), (lifecycle, '"visibilitychange"', "DIST-LAYOUT-012: Snake Web lifecycle must observe visibility changes"), (lifecycle, '"pagehide"', "DIST-LAYOUT-013: Snake Web lifecycle must observe pagehide"), (lifecycle, 'ResizeObserver', "DIST-LAYOUT-014: Snake Web lifecycle must observe resize"), (provenance, '"keyboard-mouse"', "DIST-LAYOUT-015: Snake Web provenance must distinguish keyboard/mouse input"), (provenance, '"touch"', "DIST-LAYOUT-016: Snake Web provenance must distinguish touch input"), (wasm_manifest, 'engine-v1-platform-api = { path = "../../engines/engine-v1-platform-api" }', "DIST-LAYOUT-017: Snake WASM adapter must consume the platform provenance API"), (wasm_runtime, 'PlatformFamily::Web', "DIST-LAYOUT-018: Snake WASM provenance must declare Web platform family"), (wasm_runtime, 'ExecutionModel::Wasm', "DIST-LAYOUT-019: Snake WASM provenance must declare WASM execution"), (wasm_runtime, 'RuntimeHost::Browser', "DIST-LAYOUT-020: Snake WASM provenance must declare browser host"), ) for content, fragment, message in required_fragments: if fragment not in content: violations.append(message) return violations def main() -> int: """Validate that every static distribution boundary exists.""" parser = argparse.ArgumentParser() parser.add_argument("--root", default=".", help="workspace root") arguments = parser.parse_args() root = pathlib.Path(arguments.root).resolve() missing: list[str] = [] forbidden_present: list[str] = [] contract_violations: list[str] = [] for relative in REQUIRED_PATHS: if not (root / relative).exists(): missing.append(relative) for relative in FORBIDDEN_PATHS: if (root / relative).exists(): forbidden_present.append(relative) contract_violations.extend(audit_snake_web_shell(root)) contract_violations.extend(audit_snake_web_integration(root)) if missing: for relative in missing: print(f"DIST-LAYOUT-001: missing required path: {relative}", file=sys.stderr) print(f"Distribution layout audit: {len(missing)} violation(s)", file=sys.stderr) return 1 if forbidden_present: for relative in forbidden_present: print(f"DIST-LAYOUT-002: generated path must stay outside repository: {relative}", file=sys.stderr) print(f"Distribution layout audit: {len(forbidden_present)} violation(s)", file=sys.stderr) return 1 if contract_violations: for violation in contract_violations: print(violation, file=sys.stderr) print(f"Distribution layout audit: {len(contract_violations)} violation(s)", file=sys.stderr) return 1 print(f"Distribution layout audit: clean ({len(REQUIRED_PATHS)} required path(s), {len(FORBIDDEN_PATHS)} forbidden path(s) absent)") return 0 if __name__ == "__main__": raise SystemExit(main())