4 Commits

Author SHA1 Message Date
1835464bb3 0.3.1-0-pre.2.fix.2 2026-09-20 21:49:23 +02:00
bded27c944 0.3.1-0-pre.2.fix.1 2026-09-20 21:38:21 +02:00
51371c1b24 0.3.1-0-pre.2 2026-09-20 21:30:12 +02:00
ba718ce4ec 0.3.1-0-pre.1 2026-09-20 18:16:32 +02:00
44 changed files with 1935 additions and 50 deletions

View File

@@ -1,5 +1,5 @@
# file: Cargo.toml
# version: 69
# version: 73
[workspace]
resolver = "3"
@@ -17,10 +17,11 @@ members = [
"crates/apps/game-reflex-poc-tauri",
"crates/apps/game-reflex-poc-wasm",
"crates/apps/game-snake-poc-wasm",
"crates/apps/game-snake-poc-tauri",
]
[workspace.package]
version = "0.3.0"
version = "0.3.1-0-pre.2.fix.2"
edition = "2024"
license = "MIT"
repository = "https://git.sasedev.com/Sasedev/games"

View File

@@ -1,5 +1,5 @@
<!-- file: README.md -->
<!-- version: 40 -->
<!-- version: 44 -->
# games.sasedev
@@ -26,7 +26,7 @@ Workspace expérimental puis productif pour des jeux multiplateformes principale
Version stable de référence : `0.3.0`.
Version suivante planifiée : `0.3.1` (non démarrée).
Version de développement courante : `0.3.1-0-pre.2.fix.2`.
Les deux premiers jeux sont des POC structurels : `game-reflex-poc` et `game-snake-poc`. Ils existent d'abord pour valider les frontières du workspace, le moteur, les assets et le packaging multiplateforme.

View File

@@ -1,5 +1,5 @@
// file: Web/game-snake-poc/frontend/ts/provenance.ts
// version: 1
// version: 2
import type { SnakeWasmGame } from "@snake-wasm";
import { webInfo } from "./logging";
@@ -83,7 +83,7 @@ export class BrowserRuntimeProvenance {
private synchronize(): void {
const profile = inputProfile(this.keyboardMouseObserved, this.touchObserved);
if (!this.game.configure_runtime_provenance(this.deviceClass, profile)) {
if (!this.game.configure_runtime_provenance("web", "browser", this.deviceClass, profile)) {
throw new Error("La provenance navigateur n'a pas pu être configurée dans le bridge WASM.");
}
this.output.value = displayLabel(this.game);

View File

@@ -0,0 +1,34 @@
# file: crates/apps/game-snake-poc-tauri/Cargo.toml
# version: 1
[package]
name = "game-snake-poc-tauri"
version.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true
authors.workspace = true
publish.workspace = true
[lib]
name = "game_snake_poc_tauri_lib"
path = "src/lib.rs"
crate-type = ["staticlib", "cdylib", "rlib"]
[[bin]]
name = "game-snake-poc-tauri"
path = "src/main.rs"
[build-dependencies]
tauri-build.workspace = true
[dependencies]
engine-v1-platform-api = { path = "../../engines/engine-v1-platform-api" }
game-logging-lib = { path = "../../common/game-logging-lib" }
serde.workspace = true
tauri.workspace = true
tauri-plugin-tracing.workspace = true
tracing.workspace = true
[lints]
workspace = true

View File

@@ -0,0 +1,27 @@
<!-- file: crates/apps/game-snake-poc-tauri/README.md -->
<!-- version: 3 -->
# game-snake-poc-tauri
Host Tauri Android du POC Snake. Cette application réutilise le gameplay Rust de `game-snake-poc` et l'unique adapter WebAssembly `game-snake-poc-wasm` ; elle ne possède aucune règle de jeu.
## Responsabilités
La crate possède uniquement la frontière Tauri : initialisation du logging Rust, assemblage/plugins/commandes Tauri, contrat minimal de provenance native et frontend Vite/TypeScript exécuté dans la WebView Android.
L'organisation Rust suit le modèle des applications Desk KSP :
- `src/lib.rs` reste une façade et réexporte les éléments partagés au crate-root ;
- `src/tauri.rs` assemble Tauri et fait déléguer les commandes aux modules propriétaires ;
- `src/runtime.rs` possède le petit contrat runtime/provenance ;
- `frontend/` contient le host WebView et consomme les bindings générés de `game-snake-poc-wasm`.
Le frontend minimal de `0.3.1-0-pre.2` valide uniquement le démarrage Tauri, le bridge Rust, le tracing et le chargement du même adapter WASM que le Web direct. Canvas, contrôles, assets et lifecycle complet sont prévus dans les tranches suivantes.
## Build
Les hooks `beforeDevCommand` et `beforeBuildCommand` de Tauri possèdent le build WASM et Vite. Aucun orchestrateur Python n'est utilisé. Les bindings WASM, la distribution Vite, les caches, `node_modules/` et le projet Android généré restent hors des sources livrées ou dans des chemins générés ignorés.
Le host ne modifie pas le projet Android généré par Tauri. La branche stable Tauri 2.11.x conserve son propre wrapper Gradle ; les commandes Android doivent donc s'exécuter avec un JDK compatible avec cette chaîne. Pour la machine de validation, `JAVA_HOME` doit pointer vers le JBR fourni par Android Studio (ou vers un autre JDK compatible), plutôt que vers le Java 25 global.
Voir [`USAGE.md`](USAGE.md) pour l'initialisation locale et les smokes Android.

View File

@@ -0,0 +1,51 @@
<!-- file: crates/apps/game-snake-poc-tauri/USAGE.md -->
<!-- version: 3 -->
# Utilisation — Snake Tauri Android
## Prérequis locaux
Le host utilise Cargo/Rust, `cargo tauri`, Node/npm, `wasm-bindgen`, Java et le SDK Android. Le dépôt attend `ANDROID_HOME` vers le SDK Android et des NDK side-by-side sous `$ANDROID_HOME/ndk/<version>`.
`NDK_HOME` n'est pas un prérequis utilisateur du projet. Tauri sélectionne la version NDK side-by-side appropriée sous `$ANDROID_HOME/ndk/<version>` et peut injecter lui-même `NDK_HOME` dans ses sous-processus Android. Une variable globale ne doit donc pas être ajoutée uniquement pour satisfaire la documentation générique de Tauri.
Pour Android, `JAVA_HOME` doit pointer vers un JDK compatible avec la chaîne Gradle générée par la version stable de Tauri 2 utilisée par le projet. La documentation Tauri recommande le JBR fourni par Android Studio. Le Java 25 global de la machine de validation n'est pas utilisé pour les commandes Tauri Android tant qu'il reste incompatible avec le wrapper Gradle stable. Le Gradle global installé sur la machine n'est pas utilisé par `gradlew` et n'est pas un prérequis du projet.
Exemple lorsque Android Studio est installé sous `/opt/android-studio` :
```bash
export JAVA_HOME=/opt/android-studio/jbr
"$JAVA_HOME/bin/java" -version
```
Si Android Studio se trouve ailleurs, utiliser le chemin réel de son répertoire `jbr`. Ne pas modifier `gen/android` pour contourner une incompatibilité de JDK.
Pour les cibles actuellement disponibles, `aarch64-linux-android` permet le smoke sur l'appareil ARM64 et `x86_64-linux-android` celui des AVD x86_64. Les autres ABI ne sont pas requises pour `0-pre.2`.
## Initialisation locale
Installer les dépendances frontend dans la crate :
```bash
(cd crates/apps/game-snake-poc-tauri && npm install)
```
Initialiser une fois le projet Android généré par Tauri :
```bash
(cd crates/apps/game-snake-poc-tauri && cargo tauri android init)
```
Le répertoire `gen/` produit par Tauri est généré et ignoré ; il n'appartient pas aux deltas et ne doit pas être patché par des scripts propres au jeu. Une initialisation déjà réalisée reste utilisable ; il n'est pas nécessaire de rejouer `android init` pour ce fix.
## Smoke Android de développement
Lancer ensuite :
```bash
(cd crates/apps/game-snake-poc-tauri && cargo tauri android dev)
```
Choisir l'appareil réel ou l'AVD voulu lorsque la CLI le demande. Le frontend doit afficher une provenance `android / tauri-webview / wasm / unknown / unknown` et les événements de démarrage doivent apparaître dans le tracing/logcat.
Ne pas utiliser `npm run dev` ou `npm run build` comme gate manuelle : ces scripts sont des hooks internes possédés par Tauri. `cargo tauri android build` reste réservé au jalon de packaging prévu par le plan, sauf diagnostic explicite.

View File

@@ -0,0 +1,9 @@
// file: crates/apps/game-snake-poc-tauri/build.rs
// version: 3
//! Build-time integration for the Snake Tauri host.
fn main() {
tauri_build::build();
return;
}

View File

@@ -0,0 +1,12 @@
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "Default capability for the Snake Tauri Android POC",
"windows": [
"main"
],
"permissions": [
"core:default",
"tracing:default"
]
}

View File

@@ -0,0 +1,58 @@
/* file: crates/apps/game-snake-poc-tauri/frontend/css/main.css */
/* version: 1 */
:root {
font-family: system-ui, sans-serif;
color-scheme: dark;
background: #101418;
color: #f4f7f8;
}
* {
box-sizing: border-box;
}
html,
body {
min-height: 100%;
margin: 0;
}
body {
min-height: 100vh;
display: grid;
place-items: center;
padding: max(1.5rem, env(safe-area-inset-top)) max(1.5rem, env(safe-area-inset-right)) max(1.5rem, env(safe-area-inset-bottom))
max(1.5rem, env(safe-area-inset-left));
}
.bootstrap-panel {
width: min(100%, 34rem);
padding: 1.5rem;
border: 1px solid currentColor;
border-radius: 0.75rem;
}
.eyebrow {
margin: 0 0 0.5rem;
opacity: 0.7;
}
h1 {
margin: 0 0 1rem;
font-size: clamp(1.6rem, 7vw, 2.4rem);
}
#runtime-status {
margin: 0 0 0.75rem;
}
#runtime-provenance {
display: block;
overflow-wrap: anywhere;
font-family: ui-monospace, monospace;
}
body[data-runtime-state="error"] #runtime-status {
font-weight: 700;
}

View File

@@ -0,0 +1,17 @@
<!doctype html>
<html lang="fr">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<title>Snake POC Tauri</title>
</head>
<body>
<main class="bootstrap-panel" aria-labelledby="runtime-title">
<p class="eyebrow">games.sasedev</p>
<h1 id="runtime-title">Snake — Tauri Android</h1>
<p id="runtime-status">Initialisation du runtime…</p>
<output id="runtime-provenance" aria-live="polite">provenance en attente</output>
</main>
<script type="module" src="/ts/main.ts"></script>
</body>
</html>

View File

@@ -0,0 +1,20 @@
// file: crates/apps/game-snake-poc-tauri/frontend/ts/bridge.ts
// version: 1
import { invoke } from "@tauri-apps/api/core";
export interface RuntimeDescriptor {
deviceClass: string;
executionModel: string;
inputProfile: string;
platformFamily: string;
runtimeHost: string;
}
export async function getRuntimeDescriptor(): Promise<RuntimeDescriptor> {
return await invoke<RuntimeDescriptor>("get_runtime_descriptor");
}
export async function reportFrontendReady(): Promise<void> {
await invoke("frontend_ready");
}

View File

@@ -0,0 +1,16 @@
// file: crates/apps/game-snake-poc-tauri/frontend/ts/logging.ts
// version: 1
import { attachConsole, error, info } from "@fltsci/tauri-plugin-tracing";
export async function initializeFrontendTracing(): Promise<void> {
await attachConsole();
}
export function frontendInfo(message: string): void {
info(message);
}
export function frontendError(message: string): void {
error(message);
}

View File

@@ -0,0 +1,56 @@
// file: crates/apps/game-snake-poc-tauri/frontend/ts/main.ts
// version: 1
import init, { SnakeWasmGame } from "@snake-wasm";
import "../css/main.css";
import { getRuntimeDescriptor, reportFrontendReady } from "./bridge";
import { frontendError, frontendInfo, initializeFrontendTracing } from "./logging";
function requiredElement<T extends HTMLElement>(identifier: string): T {
const element = document.getElementById(identifier);
if (element === null) {
throw new Error(`Élément frontend requis absent : ${identifier}`);
}
return element as T;
}
async function bootstrap(): Promise<void> {
await initializeFrontendTracing();
frontendInfo("Snake Tauri frontend bootstrap started");
const descriptor = await getRuntimeDescriptor();
await init();
const game = new SnakeWasmGame();
const configured = game.configure_runtime_provenance(
descriptor.platformFamily,
descriptor.runtimeHost,
descriptor.deviceClass,
descriptor.inputProfile,
);
if (!configured) {
game.free();
throw new Error("La provenance Tauri Android n'a pas été acceptée par l'adapter Snake WASM.");
}
const status = requiredElement<HTMLParagraphElement>("runtime-status");
const provenance = requiredElement<HTMLOutputElement>("runtime-provenance");
status.textContent = "Runtime minimal initialisé. Le Canvas et les contrôles arrivent dans 0-pre.3.";
provenance.value = [
game.provenance_platform_family(),
game.provenance_runtime_host(),
game.provenance_execution_model(),
game.provenance_device_class(),
game.provenance_input_profile(),
].join(" / ");
window.addEventListener("pagehide", () => game.free(), { once: true });
await reportFrontendReady();
frontendInfo(`Snake Tauri frontend ready: ${provenance.value}`);
}
void bootstrap().catch(reason => {
const message = reason instanceof Error ? reason.message : String(reason);
document.body.dataset.runtimeState = "error";
const status = document.getElementById("runtime-status");
if (status !== null) {
status.textContent = `Échec d'initialisation : ${message}`;
}
frontendError(`Snake Tauri frontend bootstrap failed: ${message}`);
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 B

View File

@@ -0,0 +1,21 @@
{
"name": "game-snake-poc-tauri",
"private": true,
"version": "0.1.0",
"type": "module",
"scripts": {
"wasm:dev": "cargo build -p game-snake-poc-wasm --target wasm32-unknown-unknown && wasm-bindgen ../../../../builds/sasedev-games/target/wasm32-unknown-unknown/debug/game_snake_poc_wasm.wasm --target web --out-dir ../../../../builds/sasedev-games/game-snake-poc-tauri/wasm --out-name game_snake_poc_wasm",
"wasm:build": "cargo build -p game-snake-poc-wasm --release --target wasm32-unknown-unknown && wasm-bindgen ../../../../builds/sasedev-games/target/wasm32-unknown-unknown/release/game_snake_poc_wasm.wasm --target web --out-dir ../../../../builds/sasedev-games/game-snake-poc-tauri/wasm --out-name game_snake_poc_wasm",
"dev": "npm run wasm:dev && vite",
"build": "npm run wasm:build && tsc && vite build"
},
"dependencies": {
"@fltsci/tauri-plugin-tracing": "^0.3",
"@tauri-apps/api": "^2.11"
},
"devDependencies": {
"@types/node": "^26.1",
"typescript": "^7.0",
"vite": "^8.2"
}
}

View File

@@ -0,0 +1,21 @@
// file: crates/apps/game-snake-poc-tauri/src/lib.rs
// version: 1
//! Tauri Android application facade for the Snake WebAssembly POC.
#![forbid(unsafe_code)]
#![deny(unreachable_pub)]
#![warn(missing_docs)]
mod runtime;
mod tauri;
/// Runs the Snake Tauri application.
pub use self::tauri::run;
/// Runtime descriptor exposed by the native Tauri bridge.
pub(crate) use self::runtime::RuntimeDescriptorDto;
/// Records that the Tauri frontend completed its minimal startup sequence.
pub(crate) use self::runtime::record_frontend_ready;
/// Returns the canonical runtime descriptor for the Android WebView host.
pub(crate) use self::runtime::runtime_descriptor;

View File

@@ -0,0 +1,20 @@
// file: crates/apps/game-snake-poc-tauri/src/main.rs
// version: 1
//! Binary entry point for host-side Snake Tauri checks.
#![forbid(unsafe_code)]
#![deny(unreachable_pub)]
#![warn(missing_docs)]
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
fn main() -> std::process::ExitCode {
let result = game_snake_poc_tauri_lib::run();
return match result {
std::result::Result::Ok(()) => std::process::ExitCode::SUCCESS,
std::result::Result::Err(error) => {
eprintln!("Snake Tauri application error: {error}");
std::process::ExitCode::FAILURE
},
};
}

View File

@@ -0,0 +1,87 @@
// file: crates/apps/game-snake-poc-tauri/src/runtime.rs
// version: 1
/// Stable runtime dimensions exposed to the Tauri frontend.
#[derive(Clone, Debug, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct RuntimeDescriptorDto {
device_class: String,
execution_model: String,
input_profile: String,
platform_family: String,
runtime_host: String,
}
/// Returns the canonical runtime descriptor for the Android WebView host.
pub(crate) fn runtime_descriptor() -> RuntimeDescriptorDto {
let provenance = engine_v1_platform_api::RuntimeProvenance::new(
engine_v1_platform_api::DeviceClass::Unknown,
engine_v1_platform_api::ExecutionModel::Wasm,
engine_v1_platform_api::InputProfile::Unknown,
engine_v1_platform_api::PlatformFamily::Android,
engine_v1_platform_api::RuntimeHost::TauriWebView,
);
return RuntimeDescriptorDto {
device_class: device_class_label(provenance.device_class()).to_string(),
execution_model: execution_model_label(provenance.execution_model()).to_string(),
input_profile: input_profile_label(provenance.input_profile()).to_string(),
platform_family: platform_family_label(provenance.platform_family()).to_string(),
runtime_host: runtime_host_label(provenance.runtime_host()).to_string(),
};
}
/// Records that the Tauri frontend completed its minimal startup sequence.
pub(crate) fn record_frontend_ready() {
let descriptor = crate::runtime_descriptor();
tracing::info!(
target: "games::tauri::snake",
action = "frontend_ready",
platform_family = descriptor.platform_family,
runtime_host = descriptor.runtime_host,
execution_model = descriptor.execution_model,
"Snake Tauri frontend ready"
);
return;
}
fn device_class_label(value: engine_v1_platform_api::DeviceClass) -> &'static str {
return match value {
engine_v1_platform_api::DeviceClass::Desktop => "desktop",
engine_v1_platform_api::DeviceClass::Phone => "phone",
engine_v1_platform_api::DeviceClass::Tablet => "tablet",
engine_v1_platform_api::DeviceClass::Unknown => "unknown",
};
}
fn execution_model_label(value: engine_v1_platform_api::ExecutionModel) -> &'static str {
return match value {
engine_v1_platform_api::ExecutionModel::Native => "native",
engine_v1_platform_api::ExecutionModel::Wasm => "wasm",
};
}
fn input_profile_label(value: engine_v1_platform_api::InputProfile) -> &'static str {
return match value {
engine_v1_platform_api::InputProfile::Gamepad => "gamepad",
engine_v1_platform_api::InputProfile::KeyboardMouse => "keyboard-mouse",
engine_v1_platform_api::InputProfile::Mixed => "mixed",
engine_v1_platform_api::InputProfile::Touch => "touch",
engine_v1_platform_api::InputProfile::Unknown => "unknown",
};
}
fn platform_family_label(value: engine_v1_platform_api::PlatformFamily) -> &'static str {
return match value {
engine_v1_platform_api::PlatformFamily::Android => "android",
engine_v1_platform_api::PlatformFamily::Desktop => "desktop",
engine_v1_platform_api::PlatformFamily::Web => "web",
};
}
fn runtime_host_label(value: engine_v1_platform_api::RuntimeHost) -> &'static str {
return match value {
engine_v1_platform_api::RuntimeHost::Browser => "browser",
engine_v1_platform_api::RuntimeHost::Native => "native",
engine_v1_platform_api::RuntimeHost::TauriWebView => "tauri-webview",
};
}

View File

@@ -0,0 +1,85 @@
// file: crates/apps/game-snake-poc-tauri/src/tauri.rs
// version: 2
//! Tauri runtime assembly and Web/Rust commands for the Snake Android POC.
#[tauri::command]
fn get_runtime_descriptor() -> crate::RuntimeDescriptorDto {
return crate::runtime_descriptor();
}
#[tauri::command]
fn frontend_ready() {
crate::record_frontend_ready();
return;
}
fn configure_plugins(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<tauri::Wry> {
let tracing_plugin = tauri_plugin_tracing::Builder::new().build::<tauri::Wry>();
return builder.plugin(tracing_plugin);
}
#[allow(clippy::question_mark_used)] // Tauri generates the question-mark operator internally for command dispatch.
fn configure_commands(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<tauri::Wry> {
return builder.invoke_handler(tauri::generate_handler![get_runtime_descriptor, frontend_ready]);
}
fn run_runtime() -> std::result::Result<(), String> {
let logging_guard = game_logging_lib::init_console_tracing();
let _logging_guard = match logging_guard {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error.to_string()),
};
tracing::info!(
target: "games::tauri::snake",
action = "runtime_start",
platform_family = "android",
runtime_host = "tauri-webview",
execution_model = "wasm",
"Starting Snake Tauri Android runtime"
);
let builder = tauri::Builder::default();
let builder = configure_plugins(builder);
let builder = configure_commands(builder);
return match builder.run(tauri::generate_context!()) {
std::result::Result::Ok(()) => {
tracing::info!(
target: "games::tauri::snake",
action = "runtime_stop",
"Snake Tauri runtime stopped"
);
std::result::Result::Ok(())
},
std::result::Result::Err(error) => {
tracing::error!(
target: "games::tauri::snake",
action = "runtime_error",
error = error.to_string(),
"Snake Tauri runtime failed"
);
std::result::Result::Err(error.to_string())
},
};
}
/// Runs the Snake Tauri application on a desktop host.
#[cfg(not(mobile))]
pub fn run() -> std::result::Result<(), String> {
return run_runtime();
}
/// Runs the Snake Tauri application from Tauri's mobile entry point.
#[cfg(mobile)]
#[tauri::mobile_entry_point]
pub fn run() {
let result = run_runtime();
if let std::result::Result::Err(error) = result {
tracing::error!(
target: "games::tauri::snake",
action = "mobile_entrypoint_error",
error = error.as_str(),
"Snake Tauri mobile entry point terminated after a runtime error"
);
}
return;
}

View File

@@ -0,0 +1,41 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Snake POC Tauri",
"identifier": "com.sasedev.games.snake.tauri",
"build": {
"beforeDevCommand": {
"script": "npm run dev",
"cwd": "."
},
"devUrl": "http://localhost:1436",
"beforeBuildCommand": {
"script": "npm run build",
"cwd": "."
},
"frontendDist": "../../../../builds/sasedev-games/game-snake-poc-tauri/dist"
},
"app": {
"windows": [
{
"label": "main",
"url": "main.html",
"title": "Snake POC Tauri",
"width": 405,
"height": 720,
"minWidth": 320,
"minHeight": 480,
"resizable": true,
"center": true
}
],
"security": {
"csp": null
}
},
"bundle": {
"active": false,
"icon": [
"icons/icon.png"
]
}
}

View File

@@ -0,0 +1,36 @@
{
"compilerOptions": {
"target": "ES2022",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": [
"ES2022",
"DOM",
"DOM.Iterable"
],
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"allowSyntheticDefaultImports": true,
"types": [
"vite/client",
"node"
],
"paths": {
"@snake-wasm": [
"../../../../builds/sasedev-games/game-snake-poc-tauri/wasm/game_snake_poc_wasm.d.ts"
]
}
},
"include": [
"frontend",
"vite.config.ts"
]
}

View File

@@ -0,0 +1,72 @@
// file: crates/apps/game-snake-poc-tauri/vite.config.ts
// version: 1
import { fileURLToPath } from "node:url";
import { resolve } from "node:path";
import { defineConfig, normalizePath } from "vite";
const appRoot = fileURLToPath(new URL(".", import.meta.url));
const repositoryRoot = normalizePath(resolve(appRoot, "../../.."));
const frontendRoot = normalizePath(resolve(appRoot, "frontend"));
const externalBuildRoot = normalizePath(resolve(repositoryRoot, "../builds/sasedev-games/game-snake-poc-tauri"));
const wasmRoot = normalizePath(resolve(externalBuildRoot, "wasm"));
const wasmModule = normalizePath(resolve(wasmRoot, "game_snake_poc_wasm.js"));
const frontendDist = normalizePath(resolve(externalBuildRoot, "dist"));
const viteCacheDir = normalizePath(resolve(externalBuildRoot, "vite-cache"));
const devHost = process.env.TAURI_DEV_HOST;
export default defineConfig({
base: "./",
cacheDir: viteCacheDir,
clearScreen: false,
root: frontendRoot,
publicDir: false,
input: {
main: normalizePath(resolve(frontendRoot, "main.html")),
},
resolve: {
alias: {
"@snake-wasm": wasmModule,
},
},
build: {
outDir: frontendDist,
emptyOutDir: true,
minify: true,
sourcemap: false,
cssCodeSplit: true,
rolldownOptions: {
output: {
entryFileNames: "js/[name]-[hash].js",
chunkFileNames: "js/chunks/[name]-[hash].js",
assetFileNames: assetInfo => {
const originalName = assetInfo.names[0] ?? "";
const extension = originalName.substring(originalName.lastIndexOf(".") + 1).toLowerCase();
if (extension === "css") {
return "css/[name]-[hash][extname]";
}
if (extension === "wasm") {
return "wasm/[name]-[hash][extname]";
}
return "otherassets/[name][extname]";
},
},
},
},
server: {
port: 1436,
strictPort: true,
host: devHost || false,
fs: {
allow: [appRoot, repositoryRoot, externalBuildRoot],
},
ws: {
protocol: "ws",
host: devHost || "localhost",
port: 1437,
},
watch: {
ignored: ["**/src/**"],
},
},
});

View File

@@ -1,5 +1,5 @@
// file: crates/apps/game-snake-poc-wasm/src/runtime.rs
// version: 2
// version: 3
const FIXED_STEP_MILLIS: u64 = 16;
@@ -31,8 +31,16 @@ impl SnakeWasmGame {
};
}
/// Updates browser-observed device and input dimensions while preserving Web/WASM/Browser provenance.
pub fn configure_runtime_provenance(&mut self, device_class: &str, input_profile: &str) -> bool {
/// Updates host-observed runtime provenance while preserving WebAssembly execution.
pub fn configure_runtime_provenance(&mut self, platform_family: &str, runtime_host: &str, device_class: &str, input_profile: &str) -> bool {
let platform_family = match parse_platform_family(platform_family) {
Some(value) => value,
None => return false,
};
let runtime_host = match parse_runtime_host(runtime_host) {
Some(value) => value,
None => return false,
};
let device_class = match parse_device_class(device_class) {
Some(value) => value,
None => return false,
@@ -45,8 +53,8 @@ impl SnakeWasmGame {
device_class,
engine_v1_platform_api::ExecutionModel::Wasm,
input_profile,
engine_v1_platform_api::PlatformFamily::Web,
engine_v1_platform_api::RuntimeHost::Browser,
platform_family,
runtime_host,
);
return true;
}
@@ -236,6 +244,24 @@ impl SnakeWasmGame {
}
}
fn parse_platform_family(label: &str) -> Option<engine_v1_platform_api::PlatformFamily> {
return match label {
"android" => Some(engine_v1_platform_api::PlatformFamily::Android),
"desktop" => Some(engine_v1_platform_api::PlatformFamily::Desktop),
"web" => Some(engine_v1_platform_api::PlatformFamily::Web),
_ => None,
};
}
fn parse_runtime_host(label: &str) -> Option<engine_v1_platform_api::RuntimeHost> {
return match label {
"browser" => Some(engine_v1_platform_api::RuntimeHost::Browser),
"native" => Some(engine_v1_platform_api::RuntimeHost::Native),
"tauri-webview" => Some(engine_v1_platform_api::RuntimeHost::TauriWebView),
_ => None,
};
}
fn parse_device_class(label: &str) -> Option<engine_v1_platform_api::DeviceClass> {
return match label {
"desktop" => Some(engine_v1_platform_api::DeviceClass::Desktop),

View File

@@ -1,5 +1,5 @@
// file: crates/apps/game-snake-poc-wasm/unit_tests/runtime.rs
// version: 2
// version: 3
#[test]
fn direction_is_queued_without_advancing_simulation() {
@@ -34,7 +34,7 @@ fn browser_runtime_provenance_preserves_static_and_observed_dimensions() {
assert_eq!(game.provenance_runtime_host(), "browser");
assert_eq!(game.provenance_device_class(), "unknown");
assert_eq!(game.provenance_input_profile(), "unknown");
assert!(game.configure_runtime_provenance("phone", "touch"));
assert!(game.configure_runtime_provenance("web", "browser", "phone", "touch"));
assert_eq!(game.provenance_device_class(), "phone");
assert_eq!(game.provenance_input_profile(), "touch");
assert_eq!(game.provenance_platform_family(), "web");
@@ -45,8 +45,19 @@ fn browser_runtime_provenance_preserves_static_and_observed_dimensions() {
#[test]
fn invalid_runtime_provenance_labels_are_rejected_without_mutation() {
let mut game = crate::SnakeWasmGame::new();
assert!(game.configure_runtime_provenance("desktop", "keyboard-mouse"));
assert!(!game.configure_runtime_provenance("console", "telepathy"));
assert!(game.configure_runtime_provenance("web", "browser", "desktop", "keyboard-mouse"));
assert!(!game.configure_runtime_provenance("console", "spaceship", "console", "telepathy"));
assert_eq!(game.provenance_device_class(), "desktop");
assert_eq!(game.provenance_input_profile(), "keyboard-mouse");
}
#[test]
fn tauri_android_runtime_provenance_is_supported_by_the_shared_adapter() {
let mut game = crate::SnakeWasmGame::new();
assert!(game.configure_runtime_provenance("android", "tauri-webview", "phone", "touch"));
assert_eq!(game.provenance_platform_family(), "android");
assert_eq!(game.provenance_runtime_host(), "tauri-webview");
assert_eq!(game.provenance_execution_model(), "wasm");
assert_eq!(game.provenance_device_class(), "phone");
assert_eq!(game.provenance_input_profile(), "touch");
}

View File

@@ -1,5 +1,5 @@
// file: crates/engines/engine-v1-platform-api/src/environment.rs
// version: 1
// version: 2
/// Broad physical device class relevant to interaction and score provenance.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
@@ -56,7 +56,7 @@ pub enum RuntimeHost {
Browser,
/// Native process managed directly by the operating system.
Native,
/// Tauri desktop WebView host.
/// Tauri WebView host on a supported native platform.
TauriWebView,
}

146
deltas/0.3.1/0-pre.1.md Normal file
View File

@@ -0,0 +1,146 @@
<!-- file: deltas/0.3.1/0-pre.1.md -->
<!-- version: 1 -->
# Delta 0.3.1-0-pre.1
## Base
Base autoritaire : archive téléchargée depuis le tag `v0.3.0` et fournie pour la reprise.
L'archive a été testée et inspectée avant modification. Sa version workspace est `0.3.0`. Elle ne contient pas `.git`, conformément au contrat des archives taggées ; aucun état Git inaccessible n'est inventé.
## Objet
Ouvrir `0.3.1` par son gate obligatoire de cadrage : audit de baseline, revue complète des règles, inventaire de réutilisation Web/WASM, référence Tauri existante, exigences Tauri Android, sizing et planification.
Aucun scaffold `game-snake-poc-tauri`, aucun frontend Tauri Snake et aucun changement de gameplay n'est introduit dans cette tranche.
## Version
La version workspace passe de :
```text
0.3.0
```
à :
```text
0.3.1-0-pre.1
```
Les versions npm des produits existants ne changent pas : cette tranche n'est pas une release de leurs frontends et `VER-TAURI-003`/`VER-TAURI-004` interdisent une synchronisation npm cérémonielle à chaque prerelease Cargo.
## Audit de baseline
Avant modification :
```text
unzip -t : no errors
General Rust rule audit: clean
Rust export completeness audit: 0 candidate(s)
games.sasedev workspace audit: clean
Markdown table audit: clean (5 table(s), 197 file(s))
Distribution layout audit: clean (31 required path(s), 1 forbidden path(s) absent)
```
L'archive ne contient aucun lockfile interdit, `node_modules/`, `dist/`, `target/` ou binding WASM généré.
Le détail est conservé dans `docs/studies/024-V0_3_1_TAURI_ANDROID_SNAKE_AUDIT.md`.
## Corrections documentaires et normatives
Cette tranche :
- ferme l'index du plan `0.3.0` et ouvre le plan actif `0.3.1` ;
- ajoute l'étude de cadrage et le plan vivant `0.3.1` ;
- distingue explicitement les commandes Tauri Desktop des commandes Tauri Android ;
- ajoute `cargo tauri android init`, `cargo tauri android dev` et `cargo tauri android build` à la matrice normative ;
- corrige le prompt de reprise pour utiliser les commandes Android de Tauri au lieu des commandes Desktop ;
- clarifie la différence entre la famille conceptuelle Mobile et le contrat V1 concret `PlatformFamily::Android` ;
- distingue une sortie applicative Tauri soumise à `EngineGame::quit_requested` du Back système Android, qui reste une navigation système ;
- documente la provenance attendue `Android / Wasm / TauriWebView`.
## Réutilisation retenue
Le second host doit :
- conserver `game-snake-poc` comme gameplay unique ;
- réutiliser `game-snake-poc-wasm` plutôt que créer un second adapter ;
- généraliser seulement la provenance de host actuellement figée sur Web/Browser ;
- réutiliser sélectivement Canvas/input/assets/shell du host Web ;
- adapter lifecycle et tracing au WebView Tauri Android ;
- suivre l'organisation Tauri `lib.rs` façade + `tauri.rs` assemblage + modules propriétaires ;
- ne pas reprendre l'orchestrateur Python historique du POC Reflex.
## Référence KSP
L'archive KSP demandée est visible dans la bibliothèque, mais son export binaire vers l'environnement de génération a été refusé par le service de bibliothèque. Aucun audit intégral fictif de cette archive n'est donc déclaré.
Les extraits indexés accessibles confirment néanmoins une organisation Desk avec `tauri.rs` pour l'assemblage/lifecycle et des modules propriétaires séparés tels que `app_state.rs`, `route_runtime.rs` et `frontend_logging.rs`. Les règles locales games.sasedev restent normatives.
## Forecast
```text
0-pre.1 audit / règles / requirements / environnement / plan
0-pre.2 scaffold Tauri Android + pipeline natif + bridge Snake WASM minimal
0-pre.3 Canvas / input / assets / shell
0-pre.4 lifecycle / provenance / tracing / Back + smoke mobile
0-pre.5 conditionnel : extraction commune réellement justifiée
2-beta.1 validation large + packaging Android
2-beta.2 consolidation documentaire conditionnelle
3-rc.1 candidate gelée
0.3.1 release mécanique
```
## Validations exécutées dans l'environnement de génération
Après constitution de l'état livré, exécuter :
```bash
python3 scripts/audit_rust_workspace_rules.py
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates Android Web deltas history
python3 scripts/audit_distribution_layout.py
```
Aucun Cargo build/test/smoke final n'est attribué au générateur.
## Validation utilisateur demandée
Le manifest workspace change de version et les règles de commandes/validation sont modifiées. La gate utilisateur est :
```bash
python3 scripts/audit_rust_workspace_rules.py
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates Android Web deltas history
python3 scripts/audit_distribution_layout.py
cargo fmt --all
cargo fmt --all -- --check
cargo check --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
```
Aucun test workspace complet n'est imposé par `pre.1` : aucun code, comportement ni graphe de dépendances n'est modifié. Il reste réservé à un jalon planifié ou à une portée transverse non bornable.
Fournir également l'inventaire d'environnement qui conditionne `0-pre.2` :
```bash
rustc --version
cargo --version
cargo tauri --version
rustup target list --installed
node --version
npm --version
wasm-bindgen --version
java -version
printf 'JAVA_HOME=%s\nANDROID_HOME=%s\nNDK_HOME=%s\n' "$JAVA_HOME" "$ANDROID_HOME" "$NDK_HOME"
adb version
adb devices -l
emulator -list-avds
```
Cette seconde série est un inventaire de prérequis, pas une gate déclarée réussie à l'avance.
## Suite après validation
Si la gate est propre et le cadrage accepté, passer à `0.3.1-0-pre.2` pour créer le host Tauri Android minimal. Toute absence d'outil indispensable ou incohérence de règle découverte par la gate produit d'abord un `0-pre.1.fix.N` borné.

View File

@@ -0,0 +1,181 @@
<!-- file: deltas/0.3.1/0-pre.2.fix.1.md -->
<!-- version: 1 -->
# Delta 0.3.1-0-pre.2.fix.1
## Base requise
`0.3.1-0-pre.2`.
Le delta `0-pre.2.md` reste immuable. La gate utilisateur du 2026-09-20 est consignée dans `history/0.3.1/0-pre.2.md`.
## Objectif
Corriger uniquement les défauts qui empêchent la gate de `0-pre.2` :
- warning `missing_docs` du build script, bloquant sous Clippy `-D warnings` ;
- résultat ignoré par le wrapper `tauri::mobile_entry_point` Android ;
- incompatibilité du wrapper Gradle `8.14.3` généré par Tauri CLI `2.11.3` avec Java 25.
Le scope fonctionnel de `0-pre.2` ne change pas. Canvas, contrôles, assets et lifecycle restent réservés aux tranches suivantes.
## Version technique
Le correctif touche du code Rust et le chemin de build Tauri/Android. La version workspace passe donc à :
```text
0.3.1-0-pre.2.fix.1
```
La version frontend locale de `package.json` reste `0.1.0` conformément à `VER-TAURI-003` et `VER-TAURI-004`.
## Correction Rust
`build.rs` possède désormais une rustdoc de crate et reste conforme aux règles Rust du workspace.
Le point d'entrée est séparé en deux niveaux :
- `run_runtime() -> Result<(), String>` possède l'exécution réelle ;
- le host non mobile conserve `run() -> Result<(), String>` ;
- le host mobile expose `#[tauri::mobile_entry_point] pub fn run()` et traite explicitement l'erreur éventuelle au lieu de laisser le macro ignorer un `Result` `must_use`.
Le comportement fonctionnel Tauri n'est pas modifié.
## Correction Gradle 9
Le log utilisateur confirme que Tauri sélectionne lui-même le NDK installé sous `$ANDROID_HOME/ndk/30.0.14904198` puis injecte `NDK_HOME` dans son sous-processus. `NDK_HOME` n'est donc pas ajouté comme prérequis utilisateur.
Le défaut réel est :
```text
Tauri CLI 2.11.3 -> gen/android/gradlew -> Gradle 8.14.3 -> Java 25
Unsupported class file major version 69
```
Le Gradle global de la machine n'est pas consommé par ce chemin ; modifier uniquement le `PATH` ne corrige donc pas le wrapper Tauri.
Le fix ajoute `crates/apps/game-snake-poc-tauri/scripts/prepare-android-gradle.mjs`. Avant chaque hook `dev`/`build`, ce script adapte idempotemment le projet généré `gen/android` vers la combinaison déjà adoptée par la migration Android upstream de Tauri :
```text
Gradle 9.6.1
Android Gradle Plugin 9.3.1
Kotlin Gradle Plugin 2.2.10
```
Il adapte aussi les ruptures Gradle 9 pertinentes du scaffold Tauri `2.11.x` :
- `Project.exec` devient `ExecOperations` dans `BuildTask.kt` ;
- les tâches Rust ciblées utilisent `tasks.register` et reçoivent explicitement `projectDir` ;
- le DSL Android/Kotlin de l'application est aligné sur le template Gradle 9 upstream ;
- les propriétés de compatibilité AGP 9 sont ajoutées ;
- les anciennes propriétés Android devenues des defaults sont retirées.
Le script est local à la crate Tauri et ne modifie ni le Gradle global ni le cache Cargo.
## Bridge généré par tauri-build
`tauri-build 2.6.3` régénère `gen/android/app/tauri.build.gradle.kts` pendant la compilation Rust, donc un patch effectué uniquement avant Cargo serait écrasé.
`build.rs` applique par conséquent, immédiatement après `tauri_build::build()`, la migration :
```text
val implementation by configurations
```
vers :
```text
val implementation = configurations.getByName("implementation")
```
lorsque le fichier Android généré existe. Le build script reste un no-op pour ce point lors des checks hôte sans `gen/android`.
## Hooks Tauri
`package.json` conserve Tauri comme propriétaire du pipeline :
```text
cargo tauri android dev
-> beforeDevCommand
-> npm run dev
-> android:prepare
-> WASM
-> Vite
```
et de même pour `beforeBuildCommand`.
`npm run dev` et `npm run build` ne deviennent pas des gates manuelles.
## Documentation et garde-fous
- `USAGE.md` retire `NDK_HOME` des prérequis utilisateur et explique la migration Gradle 9 ;
- le plan vivant enregistre le défaut et le fix sans ouvrir `0-pre.3` ;
- `audit_distribution_layout.py` exige désormais le hook Gradle, ses versions épinglées, la migration `ExecOperations` et le bridge `tauri-build` compatible Gradle 9 ;
- le test synthétique du script Node a été exécuté deux fois sur le même fixture pour vérifier son idempotence.
## Fichiers ajoutés
```text
crates/apps/game-snake-poc-tauri/scripts/prepare-android-gradle.mjs
history/0.3.1/0-pre.2.md
deltas/0.3.1/0-pre.2.fix.1.md
```
## Fichiers modifiés
```text
Cargo.toml
README.md
crates/apps/game-snake-poc-tauri/README.md
crates/apps/game-snake-poc-tauri/USAGE.md
crates/apps/game-snake-poc-tauri/build.rs
crates/apps/game-snake-poc-tauri/package.json
crates/apps/game-snake-poc-tauri/src/tauri.rs
docs/plans/002-V0_3_1_TAURI_ANDROID_SNAKE_PLAN.md
scripts/audit_distribution_layout.py
```
## Suppressions
Aucune.
## Validation générateur
Les contrôles statiques applicables sont exécutés sur l'état livré. Les commandes Cargo/npm/Tauri/Gradle restent à exécuter côté utilisateur conformément à `CMD-GEN-007` et `CMD-BUILD-005`.
## Gate utilisateur
Depuis la racine :
```bash
python3 scripts/audit_rust_workspace_rules.py
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates Android Web deltas history
python3 scripts/audit_distribution_layout.py
cargo fmt --all
cargo fmt --all -- --check
cargo check --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test -p game-snake-poc-wasm --all-targets --all-features
```
Le build Web direct était déjà propre dans la gate `0-pre.2` et aucune de ses sources n'est modifiée par ce fix ; il n'est pas nécessaire de répéter sa gate pour ce correctif borné.
Le projet Android généré existe déjà chez l'utilisateur. Ne pas rejouer `cargo tauri android init`. Relancer directement :
```bash
(cd crates/apps/game-snake-poc-tauri && cargo tauri android dev)
```
Le hook doit afficher avant le build Android :
```text
Prepared Tauri Android Gradle 9.6.1 / AGP 9.3.1 / Kotlin 2.2.10.
```
Puis le wrapper doit utiliser Gradle 9.6.1 au lieu de 8.14.3. Le smoke reste celui de `0-pre.2` : démarrage sur l'appareil/AVD, bridge Rust, chargement WASM, provenance `android / tauri-webview / wasm / unknown / unknown` et tracing sans erreur bloquante.
## Suite
Si cette gate est propre, `0-pre.2` est considéré réparé et la progression reprend sur `0.3.1-0-pre.3` conformément au plan vivant.

View File

@@ -0,0 +1,2 @@
crates/apps/game-snake-poc-tauri/scripts/prepare-android-gradle.mjs
history/0.3.1/0-pre.2.md

View File

@@ -0,0 +1,122 @@
<!-- file: deltas/0.3.1/0-pre.2.fix.2.md -->
<!-- version: 1 -->
# Delta 0.3.1-0-pre.2.fix.2
## Base
Base déclarée : `0.3.1-0-pre.2.fix.1`.
## Objet
Ce fix retire la migration Gradle 9 locale introduite par `fix.1`, revient au chemin Android officiellement généré par Tauri 2 stable et corrige l'audit workspace pour qu'il n'analyse pas le contenu généré sous `gen/` comme du code source du dépôt.
Il corrige également une violation documentaire de `fix.1` : `history/0.3.1/0-pre.2.md` avait été créé alors que `0-pre.2` n'était pas accepté. Aucune entrée `history/` n'est conservée pour ce jalon tant que sa gate n'est pas verte.
## Cause confirmée
Le smoke `0-pre.2` a établi trois faits distincts :
- Tauri sélectionne correctement le NDK side-by-side sous `$ANDROID_HOME/ndk/<version>` ; l'absence de `NDK_HOME` utilisateur n'est pas la cause du défaut ;
- le wrapper Android généré par Tauri CLI `2.11.3` utilise Gradle `8.14.3`, qui ne peut pas s'exécuter avec Java 25 ;
- `cargo tauri android init` crée légitimement `gen/android/app/src/main/assets`, mais l'audit `GAME-ASSET-001` parcourait jusque-là les répertoires générés.
La dernière CLI Tauri 2 stable vérifiée pendant ce fix est `2.11.5`. Son template Android conserve Gradle `8.14.3` et AGP `8.11.0`. La migration Gradle 9 existe upstream mais n'est pas encore publiée dans la branche stable Tauri 2 ; la reproduire par patch local ferait du projet games.sasedev le mainteneur d'un fork implicite du template Tauri.
## Correction Tauri Android
Le host Snake ne modifie plus `gen/android` :
- suppression de `scripts/prepare-android-gradle.mjs` ;
- suppression du hook `android:prepare` dans `package.json` ;
- restauration des hooks Tauri vers le seul pipeline WASM/Vite ;
- `build.rs` délègue uniquement à `tauri_build::build()` ;
- l'audit de distribution interdit désormais la réintroduction d'un patch `gen/android` dans ces deux surfaces.
Pour Tauri 2 stable, le contrat local devient celui recommandé par Tauri : `JAVA_HOME` doit pointer vers un JDK compatible avec le wrapper généré, de préférence le JBR livré avec Android Studio. Le Java 25 global peut rester installé ; il ne doit simplement pas être le JDK utilisé par les commandes Android Tauri tant que le wrapper stable ne le supporte pas.
Le Gradle global installé sous `/opt/gradle` n'est pas utilisé par `gen/android/gradlew` et n'entre pas dans le contrat de build.
## Correction de l'audit workspace
`gen/` est déjà un chemin généré et ignoré par `.gitignore`. `audit_project_workspace_rules.py` exclut désormais ces arbres pour les contrôles qui portent sur la propriété du code source :
- `GAME-ASSET-001` n'interdit plus les `assets` créés par le projet Android Tauri généré ;
- `GAME-ANDROID-001` n'interdit plus les éventuelles sources Java générées sous `gen/`.
Les assets et sources Java réellement versionnés hors des emplacements autorisés restent interdits.
## Historique
`history/0.3.1/0-pre.2.md` est supprimé. `DOC-HIST-002` et `DOC-HIST-003` imposent qu'une entrée d'historique ne soit créée qu'après acceptation effective du jalon. Le prochain delta ne recréera cette entrée que si la gate `0-pre.2.fix.2` est validée.
## Suppressions
Le manifest `deltas/0.3.1/0-pre.2.fix.2.delete.txt` supprime :
- `crates/apps/game-snake-poc-tauri/scripts/prepare-android-gradle.mjs` ;
- `history/0.3.1/0-pre.2.md`.
Après extraction du delta à la racine du dépôt, appliquer les suppressions avec :
```bash
while IFS= read -r path; do
rm -f -- "$path"
done < deltas/0.3.1/0-pre.2.fix.2.delete.txt
```
## Fichiers modifiés
- `Cargo.toml` ;
- `README.md` ;
- `crates/apps/game-snake-poc-tauri/build.rs` ;
- `crates/apps/game-snake-poc-tauri/package.json` ;
- `crates/apps/game-snake-poc-tauri/README.md` ;
- `crates/apps/game-snake-poc-tauri/USAGE.md` ;
- `docs/plans/002-V0_3_1_TAURI_ANDROID_SNAKE_PLAN.md` ;
- `scripts/audit_project_workspace_rules.py` ;
- `scripts/audit_distribution_layout.py`.
## Fichiers ajoutés
- `deltas/0.3.1/0-pre.2.fix.2.md` ;
- `deltas/0.3.1/0-pre.2.fix.2.delete.txt`.
## Validation statique du générateur
Le générateur peut exécuter les audits statiques et vérifier explicitement que les chemins générés Tauri ne déclenchent plus `GAME-ASSET-001` / `GAME-ANDROID-001`. Ces contrôles ne remplacent pas les gates build/runtime utilisateur.
## Gate utilisateur
Après application du delta et de son manifest de suppression :
```bash
python3 scripts/audit_rust_workspace_rules.py
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates Android Web deltas history
python3 scripts/audit_distribution_layout.py
cargo fmt --all
cargo fmt --all -- --check
cargo check --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test -p game-snake-poc-wasm --all-targets --all-features
```
Avant le smoke Android, sélectionner le JBR d'Android Studio dans le shell. Exemple si Android Studio est sous `/opt/android-studio` :
```bash
export JAVA_HOME=/opt/android-studio/jbr
"$JAVA_HOME/bin/java" -version
(cd crates/apps/game-snake-poc-tauri && cargo tauri android dev)
```
Si Android Studio se trouve ailleurs, remplacer `/opt/android-studio/jbr` par son chemin réel. Ne pas exécuter `npm run dev` directement et ne pas rejouer `cargo tauri android init` pour ce fix lorsque `gen/android` existe déjà.
## Critère d'acceptation
Le fix est accepté lorsque :
- les trois audits Python sont propres malgré la présence du `gen/android` local ;
- Cargo/Clippy/tests ciblés sont propres ;
- `cargo tauri android dev` n'échoue plus sur `Unsupported class file major version 69` ;
- le host minimal atteint le smoke Android prévu par `0-pre.2`.

161
deltas/0.3.1/0-pre.2.md Normal file
View File

@@ -0,0 +1,161 @@
<!-- file: deltas/0.3.1/0-pre.2.md -->
<!-- version: 1 -->
# Delta 0.3.1-0-pre.2
## Base requise
`0.3.1-0-pre.1`, validée par l'utilisateur le 2026-09-20.
## Objectif
Créer le host Tauri Android minimal de Snake sans dupliquer le gameplay, sans créer un second adapter WASM et sans réintroduire de build orchestré par Python.
Cette tranche vise le premier démarrage Android et la validation des frontières Tauri/WASM/tracing. Le Canvas, les contrôles, les assets et le lifecycle complet restent réservés à `0-pre.3` et `0-pre.4` conformément au plan vivant.
## Audit Tauri KSP direct
L'archive fournie `khadhroony-solana-project-v0.3.15.zip` a été extraite et les six crates `ksp-app-*-desk` ont été vérifiées directement. Elles possèdent toutes les frontières structurantes retenues pour games.sasedev :
```text
src/lib.rs
src/tauri.rs
package.json
vite.config.ts
tauri.conf.json
capabilities/default.json
tauri-plugin-tracing côté Rust
@fltsci/tauri-plugin-tracing côté frontend
```
Le nouveau host Snake reprend cette organisation, avec un scope volontairement plus petit. Le Tauri Reflex historique reste seulement une référence de compatibilité : son orchestration Python n'est pas reproduite.
## Changements Rust et WASM
- passage du workspace à `0.3.1-0-pre.2` ;
- ajout de `game-snake-poc-tauri` au workspace ;
- création de la façade `src/lib.rs`, de l'assemblage `src/tauri.rs` et du module propriétaire `src/runtime.rs` ;
- ajout du point d'entrée mobile `#[cfg_attr(mobile, tauri::mobile_entry_point)]` ;
- initialisation du subscriber partagé via `game-logging-lib` avant le premier événement Rust ;
- installation de `tauri-plugin-tracing` ;
- généralisation minimale de `game-snake-poc-wasm::configure_runtime_provenance` afin que le même adapter accepte explicitement la famille et le host observés ;
- conservation de `ExecutionModel::Wasm` dans l'adapter ;
- adaptation du Web direct pour fournir explicitement `web / browser` ;
- ajout d'un test ciblé `android / tauri-webview / wasm` ;
- généralisation de la rustdoc `RuntimeHost::TauriWebView`, qui n'est plus décrite comme Desktop uniquement.
## Frontend et build Tauri
La nouvelle app contient :
- `package.json`, `tsconfig.json` et `vite.config.ts` ;
- un frontend minimal sous `frontend/` ;
- un bridge IPC vers le descriptor runtime Rust ;
- le chargement des bindings produits depuis `game-snake-poc-wasm` ;
- le tracing frontend via `@fltsci/tauri-plugin-tracing` ;
- `tauri.conf.json` et `capabilities/default.json` ;
- un icon POC cohérent avec le host Tauri historique ;
- `README.md` et `USAGE.md` initiaux.
Les hooks Tauri exécutent eux-mêmes le build Cargo WASM, `wasm-bindgen` puis Vite. Les outputs restent sous `../builds/sasedev-games/`. Aucun script Python n'est impliqué dans ce chemin.
`cargo tauri android init` reste une opération locale de la gate : son répertoire `gen/` est généré et ignoré, donc il n'est pas distribué dans le delta.
## NDK et JDK
La machine de validation possède plusieurs NDK sous `$ANDROID_HOME/ndk/`; `NDK_HOME` n'est donc pas imposé globalement par le dépôt. Si la CLI Tauri exige une valeur explicite pendant `android init/dev`, utiliser ponctuellement le chemin exact de la version NDK concernée.
`JAVA_HOME` reste également facultatif tant que `java` est résolu correctement par la CLI dans l'environnement courant. Les deux variables deviennent des outils de diagnostic local, pas des invariants source du projet.
## Audit de distribution
`audit_distribution_layout.py` couvre désormais le host Tauri Snake minimal : fichiers requis, hooks Tauri, outputs WASM externes au dépôt, point d'entrée mobile, bridge tracing, provenance Android/TauriWebView et interdiction de Python/`console.*` dans le chemin touché.
## Fichiers ajoutés
```text
crates/apps/game-snake-poc-tauri/Cargo.toml
crates/apps/game-snake-poc-tauri/README.md
crates/apps/game-snake-poc-tauri/USAGE.md
crates/apps/game-snake-poc-tauri/build.rs
crates/apps/game-snake-poc-tauri/capabilities/default.json
crates/apps/game-snake-poc-tauri/frontend/css/main.css
crates/apps/game-snake-poc-tauri/frontend/main.html
crates/apps/game-snake-poc-tauri/frontend/ts/bridge.ts
crates/apps/game-snake-poc-tauri/frontend/ts/logging.ts
crates/apps/game-snake-poc-tauri/frontend/ts/main.ts
crates/apps/game-snake-poc-tauri/icons/icon.png
crates/apps/game-snake-poc-tauri/package.json
crates/apps/game-snake-poc-tauri/src/lib.rs
crates/apps/game-snake-poc-tauri/src/main.rs
crates/apps/game-snake-poc-tauri/src/runtime.rs
crates/apps/game-snake-poc-tauri/src/tauri.rs
crates/apps/game-snake-poc-tauri/tauri.conf.json
crates/apps/game-snake-poc-tauri/tsconfig.json
crates/apps/game-snake-poc-tauri/vite.config.ts
history/0.3.1/0-pre.1.md
```
## Fichiers modifiés
```text
Cargo.toml
README.md
Web/game-snake-poc/frontend/ts/provenance.ts
crates/apps/game-snake-poc-wasm/src/runtime.rs
crates/apps/game-snake-poc-wasm/unit_tests/runtime.rs
crates/engines/engine-v1-platform-api/src/environment.rs
docs/plans/002-V0_3_1_TAURI_ANDROID_SNAKE_PLAN.md
scripts/audit_distribution_layout.py
```
## Validation générateur
Les audits statiques applicables sont exécutés avant livraison. Aucun `cargo`, `npm`, `wasm-bindgen`, Gradle, Tauri Android ou smoke n'est déclaré validé par le générateur.
## Gate utilisateur
Appliquer d'abord la gate workspace :
```bash
python3 scripts/audit_rust_workspace_rules.py
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates Android Web deltas history
python3 scripts/audit_distribution_layout.py
cargo fmt --all
cargo fmt --all -- --check
cargo check --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test -p game-snake-poc-wasm --all-targets --all-features
```
Comme l'API de provenance partagée est utilisée par le Web direct, reconstruire ses bindings et son frontend :
```bash
cargo build -p game-snake-poc-wasm --target wasm32-unknown-unknown
wasm-bindgen ../builds/sasedev-games/target/wasm32-unknown-unknown/debug/game_snake_poc_wasm.wasm --target web --out-dir ../builds/sasedev-games/game-snake-poc-web/wasm --out-name game_snake_poc_wasm
(cd Web/game-snake-poc && npm install && npm run build)
```
Puis initialiser et lancer le nouveau host par Tauri, sans exécuter ses scripts npm de build directement :
```bash
(cd crates/apps/game-snake-poc-tauri && npm install)
(cd crates/apps/game-snake-poc-tauri && cargo tauri android init)
(cd crates/apps/game-snake-poc-tauri && cargo tauri android dev)
```
Critères du smoke `android dev` :
- l'app démarre sur l'appareil/AVD choisi ;
- le frontend affiche `android / tauri-webview / wasm / unknown / unknown` ;
- le bridge Rust répond ;
- le frontend charge `game-snake-poc-wasm` ;
- les logs Rust et frontend atteignent le pipeline tracing/logcat ;
- aucune erreur runtime bloquante n'est visible.
`cargo tauri android build` reste reporté au jalon de packaging prévu par le plan.
## Suite après validation
Si la gate est propre, passer automatiquement à `0.3.1-0-pre.3` pour intégrer le Canvas Snake, les inputs et les assets dans le WebView Tauri. Tout défaut source de `0-pre.2` produit d'abord un `0-pre.2.fix.N` borné.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/000-README.md -->
<!-- version: 27 -->
<!-- version: 28 -->
# Documentation games.sasedev
@@ -15,7 +15,8 @@
## Plans
- [`plans/000-README.md`](plans/000-README.md) — plans vivants des versions ; le plan actif porte notamment le découpage prévisionnel souple des prereleases.
- [`plans/001-V0_3_0_WEB_SNAKE_POC_PLAN.md`](plans/001-V0_3_0_WEB_SNAKE_POC_PLAN.md) — plan actif de `0.3.0`, premier POC Snake Web direct.
- [`plans/001-V0_3_0_WEB_SNAKE_POC_PLAN.md`](plans/001-V0_3_0_WEB_SNAKE_POC_PLAN.md) — plan clôturé de `0.3.0`, premier POC Snake Web direct.
- [`plans/002-V0_3_1_TAURI_ANDROID_SNAKE_PLAN.md`](plans/002-V0_3_1_TAURI_ANDROID_SNAKE_PLAN.md) — plan actif de `0.3.1`, second host Snake Tauri Android.
## Architecture

View File

@@ -1,5 +1,5 @@
<!-- file: docs/architecture/010-RUNTIME_PROVENANCE.md -->
<!-- version: 2 -->
<!-- version: 3 -->
# Provenance d'environnement d'exécution
@@ -45,7 +45,7 @@ RuntimeHost = Native
InputProfile = KeyboardMouse
```
Le futur POC Tauri/WASM :
Un host Tauri Desktop/WASM :
```text
PlatformFamily = Desktop
@@ -55,7 +55,17 @@ RuntimeHost = TauriWebView
InputProfile = KeyboardMouse
```
Une version Web dans un navigateur de téléphone pourra au contraire être `PlatformFamily = Web`, `DeviceClass = Phone`, `ExecutionModel = Wasm`, `RuntimeHost = Browser`, `InputProfile = Touch`.
Le POC Tauri Android de `0.3.1` doit au contraire utiliser :
```text
PlatformFamily = Android
DeviceClass = Phone ou Tablet
ExecutionModel = Wasm
RuntimeHost = TauriWebView
InputProfile = Touch ou Mixed selon les entrées réellement observées
```
Une version Web dans un navigateur de téléphone pourra être `PlatformFamily = Web`, `DeviceClass = Phone`, `ExecutionModel = Wasm`, `RuntimeHost = Browser`, `InputProfile = Touch`.
## Classements et équité

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/000-README.md -->
<!-- version: 1 -->
<!-- version: 2 -->
# Plans de versions games.sasedev
@@ -11,4 +11,5 @@ Le `ROADMAP.md` reste la trajectoire macroscopique du projet ; les deltas décri
## Plans
- [`001-V0_3_0_WEB_SNAKE_POC_PLAN.md`](001-V0_3_0_WEB_SNAKE_POC_PLAN.md) — plan actif de `0.3.0`, baseline Snake et premier POC Web direct.
- [`001-V0_3_0_WEB_SNAKE_POC_PLAN.md`](001-V0_3_0_WEB_SNAKE_POC_PLAN.md) — plan clôturé de `0.3.0`, baseline Snake et premier POC Web direct.
- [`002-V0_3_1_TAURI_ANDROID_SNAKE_PLAN.md`](002-V0_3_1_TAURI_ANDROID_SNAKE_PLAN.md) — plan actif de `0.3.1`, second host Snake Tauri Android.

View File

@@ -0,0 +1,182 @@
<!-- file: docs/plans/002-V0_3_1_TAURI_ANDROID_SNAKE_PLAN.md -->
<!-- version: 4 -->
# Plan v0.3.1 — second host Snake Tauri Android
## But de la version
`0.3.1` doit ajouter un second host Snake réellement exécutable sous Tauri Android en réutilisant la baseline Web/WASM validée par `0.3.0`.
La version ne doit ni déplacer le gameplay hors de `game-snake-poc`, ni créer un second adapter Snake, ni transformer immédiatement les similitudes Web/Tauri en framework générique.
Base stable : `0.3.0`.
Cadrage : [`../studies/024-V0_3_1_TAURI_ANDROID_SNAKE_AUDIT.md`](../studies/024-V0_3_1_TAURI_ANDROID_SNAKE_AUDIT.md).
## Décisions acquises
- la nouvelle crate sera `crates/apps/game-snake-poc-tauri` ;
- `0.3.1` valide uniquement sa cible Android ;
- `game-snake-poc` reste inchangé sauf défaut réellement découvert ;
- `game-snake-poc-wasm` reste l'unique adapter Snake WASM et recevra seulement la généralisation de provenance nécessaire au second host ;
- le frontend Tauri part du comportement réellement validé dans `Web/game-snake-poc`, avec adaptation de lifecycle et logging ;
- `lib.rs` est une façade/reexport et `tauri.rs` reste l'assemblage Tauri ;
- le tracing frontend utilise `@fltsci/tauri-plugin-tracing` ;
- les hooks Tauri possèdent le build frontend/WASM ;
- aucun nouveau chemin de build n'est piloté par Python ;
- `README.md` et `USAGE.md` seront créés avec l'app : architecture pour le premier, prérequis/commandes/smokes pour le second ;
- `cargo tauri android init/dev/build` sont les commandes mobiles de référence ;
- SimpleBar et `resize-observer-polyfill` ne sont pas ajoutés au host Tauri sans besoin démontré.
## Scope
La version couvre :
- création de la crate/app Tauri Snake ;
- initialisation de la cible Android par Tauri ;
- pipeline Rust/WASM + Vite/TypeScript possédé par Tauri sans Python ;
- consommation de `game-snake-poc-wasm` ;
- shell Canvas, contrôles touch et comportement responsive nécessaires au jeu ;
- assets communs et spécifiques Snake ;
- lifecycle mobile/WebView ;
- provenance `Android / Wasm / TauriWebView` ;
- tracing Rust/Tauri/frontend ;
- politique de sortie/Back conforme au moteur ;
- build/package et smoke sur AVD/appareil disponible aux jalons prévus ;
- comparaison du code Web direct/Tauri après fonctionnement réel afin de décider s'il existe une extraction commune justifiée.
Hors scope : Tauri Desktop Snake comme cible validée, iOS, Android SDL3 multi-ABI additionnel, réseau realtime, Uroburas, ads, billing, auth et leaderboard.
## Prévision souple
### `0-pre.1` — cadrage et règles
Audit complet de l'archive stable, règles, baseline Web/WASM, Tauri Reflex, références Desk KSP accessibles, environnement Android historique et commandes Tauri mobiles actuelles.
Livraison : étude `024`, présent plan, correction des règles Tauri Android, clarification `PlatformFamily`, index documentaires et ouverture de la version technique `0.3.1-0-pre.1`.
Aucun scaffold Tauri Snake n'est créé. Tranche validée par la gate utilisateur du 2026-09-20.
### `0-pre.2` — host Tauri Android minimal
Créer `game-snake-poc-tauri` avec :
- manifest Cargo/build script/config Tauri/capabilities ;
- `lib.rs` façade, `tauri.rs` assemblage et modules propriétaires minimaux ;
- point d'entrée `run()` mobile annoté `#[cfg_attr(mobile, tauri::mobile_entry_point)]` dans le module propriétaire puis réexporté par `lib.rs` ;
- frontend Vite/TypeScript minimal ;
- bridge tracing initialisé ;
- hooks de build natifs, sans Python ;
- cible Android initialisée via Tauri ;
- chargement du même adapter `game-snake-poc-wasm` après généralisation minimale de provenance ;
- `README.md` et `USAGE.md` initiaux.
La tranche vise un premier démarrage Tauri Android minimal, pas encore toute la finition input/lifecycle.
État candidat livré : crate `game-snake-poc-tauri`, bridge Rust/Tauri, hooks WASM/Vite sans Python, frontend minimal, tracing frontend/Rust et provenance partagée `Android / TauriWebView / Wasm`. L'initialisation générée `cargo tauri android init` reste volontairement locale et fait partie de la gate utilisateur, car `gen/` n'est pas un artefact source distribué.
Gate utilisateur : audits, Cargo workspace strict, test ciblé de l'adapter WASM, non-régression du build Web direct, `cargo tauri android init` puis `cargo tauri android dev` sur un AVD ou appareil disponible. `cargo tauri android build` reste reporté aux phases finales sauf besoin diagnostique.
Le premier smoke `0-pre.2` a révélé deux défauts bornés : `build.rs` échouait sous Clippy strict à cause de la rustdoc manquante, et Java 25 ne pouvait pas exécuter le wrapper Gradle `8.14.3` généré par Tauri CLI `2.11.3`. `0-pre.2.fix.1` a tenté de migrer localement le scaffold généré vers Gradle 9 ; cette approche est abandonnée par `0-pre.2.fix.2` car la branche stable Tauri 2.11.x n'a pas encore publié cette migration et le projet ne doit pas maintenir un fork implicite des templates Android Tauri. Le fix utilise donc la chaîne Android générée officiellement par Tauri stable et impose pour les commandes Android un `JAVA_HOME` compatible, de préférence le JBR fourni par Android Studio. Le Gradle global de la machine ne fait pas partie du contrat reproductible.
### `0-pre.3` — shell Snake, Canvas, input et assets
Réutiliser sélectivement le host Web validé :
- rendu Canvas et session fixed-step ;
- shell responsive pertinent ;
- contrôles directionnels touch/pointer et clavier lorsque disponible ;
- resize/orientation ;
- assets canoniques communs + Snake ;
- absence de dépendances Web-only inutiles.
Aucune extraction commune n'est réalisée uniquement pour éviter quelques fichiers similaires pendant la mise au point.
### `0-pre.4` — lifecycle, provenance, tracing et sortie mobile
Stabiliser :
- background/foreground et reprise sans rattrapage massif ;
- rotation/resize ;
- provenance `Android / Wasm / TauriWebView` + device/input observés ;
- tracing Rust/Tauri/frontend ;
- sorties applicatives conformes à `EngineGame::quit_requested` sans détourner le Back système Android ;
- smokes AVD et, si disponible, appareil réel.
Cette tranche doit rendre le second host fonctionnel de bout en bout.
### `0-pre.5` — extraction conditionnelle
Créer uniquement si l'état `0-pre.4` montre une duplication réellement durable entre `Web/game-snake-poc` et le frontend Tauri.
Une extraction possible doit rester bornée à une responsabilité clairement partagée, par exemple projection/rendu Canvas, mapping input Web ou helpers d'assets. Lifecycle et logging restent host-specific s'ils divergent réellement.
Si aucune extraction n'est justifiée, cette tranche est omise.
### `2-beta.1` — validation large et packaging Android
Prévoir :
- audits statiques applicables ;
- `cargo fmt --all -- --check` ;
- `cargo check --workspace` ;
- Clippy workspace strict ;
- suite workspace complète à ce jalon planifié ;
- build WASM release et bindings ;
- `cargo tauri android build` ;
- APK/AAB selon le livrable de validation ;
- install/smoke AVD ;
- install/smoke appareil ARM64 réel si disponible ;
- vérification que les outputs restent hors racine du dépôt lorsqu'ils sont configurables par le projet.
### `2-beta.2` — consolidation documentaire conditionnelle
Réserver seulement si les validations beta demandent une consolidation substantielle de `README.md`, `USAGE.md`, architecture, matrice de validation ou plan. Ne pas créer cette tranche par cérémonial.
### `3-rc.1` — candidate gelée
Gel fonctionnel, reproductibilité, packaging Android RC et validation finale selon les règles RC applicables. Aucun nouveau framework ni nouveau host.
### `0.3.1` — release stable
Promotion mécanique de la RC validée : versions stables, changelog, history et clôture du plan. Aucun ajout fonctionnel.
## Inventaire environnement requis avant `0-pre.2`
La gate `0-pre.1` doit recevoir au minimum :
```bash
rustc --version
cargo --version
cargo tauri --version
rustup target list --installed
node --version
npm --version
wasm-bindgen --version
java -version
printf 'JAVA_HOME=%s\nANDROID_HOME=%s\n' "$JAVA_HOME" "$ANDROID_HOME"
adb version
adb devices -l
emulator -list-avds
```
L'absence d'un outil ne doit pas être masquée. Elle devient un prérequis concret de `0-pre.2` ou motive un fix borné de `0-pre.1`.
La gate `0-pre.1` validée le 2026-09-20 a confirmé Rust `1.94.1`, Tauri CLI `2.11.3`, Node `24.21.0`, npm `11.19.0`, wasm-bindgen `0.2.128`, OpenJDK `25.0.4.1`, `ANDROID_HOME=/home/sinus/DEV/AndroidSDK`, un appareil ARM64 réel et trois AVD disponibles. `JAVA_HOME` était vide et Java 25 était résolu depuis le `PATH`. Le smoke `0-pre.2` a confirmé que Tauri sélectionne lui-même le NDK side-by-side sous `$ANDROID_HOME/ndk/<version>` et injecte `NDK_HOME` dans ses sous-processus ; le défaut observé concernait Java 25 face au wrapper Gradle 8.14.3. Pour les commandes Android Tauri 2.11.x, `JAVA_HOME` doit donc pointer vers un JDK compatible, de préférence le JBR fourni par Android Studio.
## Critères de fermeture de 0.3.1
La version peut entrer en RC lorsque :
- Snake est jouable dans le WebView Tauri Android sans gameplay dupliqué ;
- le même adapter WASM sert Web direct et Tauri Android avec provenance exacte ;
- lifecycle/input/assets/tracing/Back ont un comportement explicite et validé ;
- le chemin de build ne dépend d'aucun orchestrateur Python ;
- le packaging Tauri Android est reproductible ;
- les smokes prévus sur cible Android ont été exécutés ;
- aucune extraction commune non prouvée n'a été introduite ;
- la documentation opérateur et architecture reflète l'état réel.
## Version suivante
`0.3.2` reste réservée à Tauri Desktop + Snake et à une éventuelle factorisation WebView seulement après deux consommateurs réels.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/PROMPT_STRUCTURE.md -->
<!-- version: 2 -->
<!-- version: 3 -->
# Structure des prompts de reprise
@@ -24,7 +24,7 @@ Le prompt rappelle les invariants qui évitent les erreurs de workflow et renvoi
## Commandes avec répertoire et Tauri
- **PROMPT-STR-016** — Le prompt rappelle que toute commande nécessitant un `cd` est englobée dans un sous-shell, par exemple `(cd <dir> && <commande>)`, afin de ne pas modifier le répertoire courant pour les commandes suivantes.
- **PROMPT-STR-017** — Lorsqu'une version touche Tauri, le prompt rappelle que `npm` sert à gérer les dépendances frontend mais que les builds/smokes passent par Tauri : `(cd <tauri-app> && cargo tauri dev)` pour le smoke courant et `(cd <tauri-app> && cargo tauri build)` aux phases finales de packaging prévues. Les hooks Tauri possèdent Vite/TypeScript/WASM ; `npm run dev`/`npm run build` ne deviennent pas des gates manuelles Tauri.
- **PROMPT-STR-017** — Lorsqu'une version touche Tauri, le prompt rappelle que `npm` sert à gérer les dépendances frontend mais que les builds/smokes passent par Tauri. Il utilise les commandes de la cible concernée : `(cd <tauri-app> && cargo tauri dev)` / `cargo tauri build` pour Desktop, ou `(cd <tauri-app> && cargo tauri android dev)` / `cargo tauri android build` pour Android. Les hooks Tauri possèdent Vite/TypeScript/WASM ; `npm run dev`/`npm run build` ne deviennent pas des gates manuelles Tauri.
## Documentation et traçabilité à rappeler

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/RULES_COMMANDS.md -->
<!-- version: 13 -->
<!-- version: 14 -->
# Règles d'exécution des commandes
@@ -61,11 +61,14 @@
- **CMD-WEB-003** — Le POC Tauri/WASM historique `0.1.0` utilise `scripts/build_reflex_tauri_wasm.py` ; ce script reste une référence de baseline mais ne doit pas être réutilisé comme orchestrateur par un POC `0.3.x`, conformément à `CMD-BUILD-004`.
- **CMD-WEB-004** — Les fichiers produits par `wasm-bindgen` sont générés localement et ne sont pas commités.
- **CMD-WEB-005** — Dans une app Tauri, `npm` sert uniquement à gérer les dépendances frontend lorsque nécessaire, par exemple `npm i <package>`, `npm i -D <package>` ou leur opération inverse. Les scripts `npm run dev`, `npm run build` ou équivalents ne sont pas des gates manuelles : Vite/TypeScript/WASM sont déclenchés par les hooks Tauri configurés.
- **CMD-WEB-006** — Le smoke normal d'une app Tauri est lancé via `(cd <tauri-app> && cargo tauri dev)`. Cette commande possède le serveur Vite et les hooks frontend nécessaires.
- **CMD-WEB-007** — Le packaging Tauri est validé dans les phases finales prévues par le plan via `(cd <tauri-app> && cargo tauri build)`, typiquement en beta préfinale, RC ou avant release selon le scope. Il n'est pas exécuté après chaque petit delta Tauri.
- **CMD-WEB-006** — Le smoke normal d'une app Tauri Desktop est lancé via `(cd <tauri-app> && cargo tauri dev)`. Cette commande possède le serveur Vite et les hooks frontend nécessaires.
- **CMD-WEB-007** — Le packaging Tauri Desktop est validé dans les phases finales prévues par le plan via `(cd <tauri-app> && cargo tauri build)`, typiquement en beta préfinale, RC ou avant release selon le scope. Il n'est pas exécuté après chaque petit delta Tauri.
- **CMD-WEB-008** — Pour un host Web navigateur direct sous `Web/<game>/`, les commandes npm/Vite peuvent être exécutées directement, toujours dans un sous-shell lorsqu'un changement de répertoire est nécessaire, par exemple `(cd Web/<game> && npm install && npm run build)`.
- **CMD-WEB-009** — Le build d'un host Web direct qui consomme un adapter `wasm-bindgen` exécute d'abord le build Rust/WASM et la génération des bindings hors dépôt, puis seulement le build TypeScript/Vite.
- **CMD-WEB-010** — Un smoke navigateur manuel d'un host Web direct vérifie au minimum le chargement WASM, le Canvas, les entrées prévues par la tranche et le comportement responsive concerné.
- **CMD-WEB-011** — Une cible Tauri Android existante est initialisée depuis sa crate avec `(cd <tauri-app> && cargo tauri android init)` lorsqu'elle ne possède pas encore le projet mobile généré requis ; cette initialisation n'est pas rejouée comme gate ordinaire.
- **CMD-WEB-012** — Le smoke interactif d'une app Tauri Android utilise `(cd <tauri-app> && cargo tauri android dev)` ; il remplace `cargo tauri dev` pour cette cible mobile.
- **CMD-WEB-013** — Le packaging Tauri Android utilise `(cd <tauri-app> && cargo tauri android build)` dans les phases finales prévues par le plan ; `--apk` ou `--aab` est ajouté uniquement lorsque le livrable visé le requiert.
## Git et fichiers générés
@@ -78,7 +81,7 @@
- **CMD-BETA-001** — À l'entrée en beta, `scripts/audit_distribution_layout.py` vérifie les frontières statiques nécessaires aux runners et packagings supportés.
- **CMD-BETA-002** — La transition alpha vers beta exécute une suite Cargo workspace complète en plus des tests ciblés.
- **CMD-BETA-003** — Si la version touche le périmètre Tauri, le plan réserve au moins une validation de packaging dans une phase finale appropriée via `(cd <tauri-app> && cargo tauri build)` ; les itérations et smokes courants utilisent `cargo tauri dev`.
- **CMD-BETA-003** — Si la version touche le périmètre Tauri, le plan réserve au moins une validation de packaging dans une phase finale appropriée avec la commande Tauri correspondant à la cible : `cargo tauri build` pour Desktop ou `cargo tauri android build` pour Android. Les smokes utilisent de même `cargo tauri dev` ou `cargo tauri android dev` selon la cible.
- **CMD-BETA-004** — Les APK Debug servent à la validation multi-appareils beta ; la signature de publication appartient à la phase RC/stable.
## RC et release
@@ -86,7 +89,7 @@
- **CMD-RC-001** — L'entrée en RC gèle le périmètre fonctionnel de la version courante ; seuls les correctifs, la reproductibilité des builds, le packaging, la documentation de livraison et les défauts de release sont admis.
- **CMD-RC-002** — La validation d'une RC exécute `cargo test --workspace --all-targets --all-features` en plus des audits, du check et de Clippy strict.
- **CMD-RC-003** — Les deux runners Desktop natifs sont construits en `--release` et font l'objet d'un smoke sur les binaires de release.
- **CMD-RC-004** — Une RC Tauri est construite via `(cd <tauri-app> && cargo tauri build)` ; ses hooks possèdent toujours le build WASM et Vite/TypeScript. Les smokes interactifs restent lancés avec `(cd <tauri-app> && cargo tauri dev)`.
- **CMD-RC-004** — Une RC Tauri est construite avec la commande de packaging correspondant à sa cible : `(cd <tauri-app> && cargo tauri build)` pour Desktop ou `(cd <tauri-app> && cargo tauri android build)` pour Android. Ses hooks possèdent toujours le build WASM et Vite/TypeScript ; les smokes utilisent la variante `dev` correspondante.
- **CMD-RC-005** — Android RC revalide au minimum x86_64 sur AVD et ARM64 sur appareil réel avec les APK issus de l'état RC.
- **CMD-RC-006** — Les secrets de signature, keystores et credentials de publication ne sont jamais commités. Leur présence est une condition externe de publication, pas une donnée du dépôt.
- **CMD-RC-007** — Une RC n'est promue en stable que si aucun correctif `.fix.N` n'est nécessaire après la gate RC complète.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/RULES_PROJECT.md -->
<!-- version: 16 -->
<!-- version: 17 -->
# Règles spécifiques games.sasedev
@@ -72,7 +72,7 @@
- **GAME-PLATFORM-011** — Les traces frontend Tauri passent par `@fltsci/tauri-plugin-tracing` vers `tauri-plugin-tracing`/`tracing`; les `console.*` applicatifs directs sont interdits hors fallback interne.
- **GAME-PLATFORM-012** — Le plugin tracing Tauri ne remplace pas l'initialisation du subscriber Rust ; une app Tauri initialise le runtime de logging partagé avant son premier événement `tracing`.
- **GAME-PLATFORM-013** — Les demandes de sortie Tauri sont évaluées par la politique `EngineGame::quit_requested` avant toute fermeture native.
- **GAME-PLATFORM-013** — Les demandes de sortie applicatives Tauri sont évaluées par la politique `EngineGame::quit_requested` avant toute fermeture native contrôlée par l'application. Cette règle n'impose pas de consommer le Back système Android, qui reste régi par `GAME-PLATFORM-014`.
- **GAME-BUILD-001** — Les artefacts générés Cargo, Tauri, Vite et caches frontend sont placés hors de la racine du dépôt, sous `../builds/sasedev-games/`; un répertoire racine `builds/` dans le dépôt est interdit.
@@ -81,7 +81,7 @@
## Réservation de plateformes
- **GAME-PLATFORM-016** — Les familles de plateformes réservées sont Desktop, Mobile et Web. Desktop inclut potentiellement Linux, Windows et macOS ; Mobile inclut potentiellement Android et iOS.
- **GAME-PLATFORM-016** — Les familles conceptuelles réservées sont Desktop, Mobile et Web. Desktop inclut potentiellement Linux, Windows et macOS ; Mobile inclut potentiellement Android et iOS. Le contrat runtime V1 reste volontairement plus concret : `PlatformFamily` expose actuellement `Android`, `Desktop` et `Web` ; un host Tauri Android utilise donc `PlatformFamily::Android` tant qu'aucune généralisation Mobile/iOS n'est justifiée.
- **GAME-PLATFORM-017** — Téléphone, tablette et futures classes de device sont des dimensions distinctes de l'OS et du backend technique.
- **GAME-PLATFORM-018** — SDL3 reste le backend natif de référence du POC, mais l'architecture de jeu ne doit pas assimiler une plateforme à SDL ni empêcher un adapter différent lorsque la plateforme l'exige.
- **GAME-PLATFORM-019** — Une plateforme réservée n'est ni implémentée ni planifiée tant qu'une ligne ROADMAP ou un delta ne l'engage explicitement.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/RULES_VALIDATION_MATRIX.md -->
<!-- version: 4 -->
<!-- version: 5 -->
# Matrice normative des commandes et validations
@@ -29,11 +29,14 @@ Les commandes ciblées restent la norme pendant l'implémentation ; les gates wo
| `CMD-026` | `cargo tree -p <crate> --edges normal` ou variante ciblée | — | dépendances/features modifiées ou diagnostic | selon portée |
| `CMD-030` | build Desktop `--release` ciblé | gates Rust applicables | runner/distribution Desktop touché | beta |
| `CMD-031` | smoke Desktop release | `CMD-030` | runtime Desktop touché | beta |
| `CMD-040` | `(cd <tauri-app> && cargo tauri dev)` | gates Rust/frontend applicables | smoke interactif Tauri | `pre`/beta |
| `CMD-041` | `(cd <tauri-app> && cargo tauri build)` | gates Rust/frontend applicables | packaging Tauri final/prefinal | beta/RC |
| `CMD-040` | `(cd <tauri-app> && cargo tauri dev)` | gates Rust/frontend applicables | smoke interactif Tauri Desktop | `pre`/beta |
| `CMD-041` | `(cd <tauri-app> && cargo tauri build)` | gates Rust/frontend applicables | packaging Tauri Desktop final/prefinal | beta/RC |
| `CMD-042` | build Rust `wasm32-unknown-unknown` + `wasm-bindgen --target web` | gates Rust de l'adapter | adapter WASM/Web direct touché | `pre` |
| `CMD-043` | `(cd Web/<game> && npm install && npm run build)` | `CMD-042` si frontend avec WASM | frontend Web direct touché | `pre` |
| `CMD-044` | smoke navigateur du host Web direct | `CMD-043` | Canvas/input/responsive Web touchés | `pre`/beta |
| `CMD-045` | `(cd <tauri-app> && cargo tauri android init)` | environnement Android/Tauri | initialisation unique de la cible Tauri Android | `pre` |
| `CMD-046` | `(cd <tauri-app> && cargo tauri android dev)` | gates Rust/frontend applicables | smoke interactif Tauri Android | `pre`/beta |
| `CMD-047` | `(cd <tauri-app> && cargo tauri android build)` | gates Rust/frontend applicables | packaging Tauri Android final/prefinal | beta/RC |
| `CMD-050` | build Rust Android ABI ciblé | gates Rust applicables | Android/JNI/backend natif touché | pre/beta |
| `CMD-051` | `(cd Android && ./gradlew :<app>:assembleDebug)` | `CMD-050` si Rust natif change | Android/app/manifest/Java touché | pre/beta |
| `CMD-052` | install + smoke AVD | `CMD-051` | Android concerné | beta |
@@ -52,7 +55,7 @@ Dès que du Rust ou une dépendance Cargo change, la séquence minimale obligato
`CMD-026` est ajouté lorsqu'un graphe de dépendances/features a changé ou doit être diagnostiqué ; il est omis des validations ordinaires sans changement de dépendances.
Toute commande avec changement de répertoire utilise un sous-shell, comme le montrent `CMD-040`, `CMD-041`, `CMD-043` et `CMD-051`.
Toute commande avec changement de répertoire utilise un sous-shell, comme le montrent `CMD-040`, `CMD-041`, `CMD-043`, `CMD-045` à `CMD-047` et `CMD-051`.
## Dépendances entre crates

View File

@@ -1,5 +1,5 @@
<!-- file: docs/studies/000-README.md -->
<!-- version: 9 -->
<!-- version: 10 -->
# Études
@@ -57,3 +57,7 @@ Ces documents étudient les POC à réaliser ; ils ne lancent encore aucune impl
## Étude de cadrage 0.3.0
- [`023-V0_3_0_PLATFORM_POC_AUDIT.md`](023-V0_3_0_PLATFORM_POC_AUDIT.md) — audit réel de la baseline `0.2.0`, requirements Snake, graphe de dépendances, choix du premier POC et sizing corrigé de `0.3.0`.
## Étude de cadrage 0.3.1
- [`024-V0_3_1_TAURI_ANDROID_SNAKE_AUDIT.md`](024-V0_3_1_TAURI_ANDROID_SNAKE_AUDIT.md) — audit de la baseline `0.3.0`, réutilisation Web/WASM, référence Tauri existante, environnement Android et sizing du second host Snake.

View File

@@ -0,0 +1,223 @@
<!-- file: docs/studies/024-V0_3_1_TAURI_ANDROID_SNAKE_AUDIT.md -->
<!-- version: 1 -->
# Audit v0.3.1 — second host Snake Tauri Android
## Statut
Étude de cadrage `0.3.1-0-pre.1`.
Base autoritaire : archive téléchargée depuis le tag `v0.3.0` et fournie pour cette reprise.
Cette tranche reste un gate d'audit, requirements, sizing et planification. Aucun scaffold Tauri Android Snake, aucun frontend nouveau et aucun changement de gameplay n'y sont introduits.
## Intégrité de la baseline
L'archive `v0.3.0` a été extraite et testée avant modification.
Les contrôles statiques de baseline sont propres :
```text
unzip -t : no errors
General Rust rule audit: clean
Rust export completeness audit: 0 candidate(s)
games.sasedev workspace audit: clean
Markdown table audit: clean (5 table(s), 197 file(s))
Distribution layout audit: clean (31 required path(s), 1 forbidden path(s) absent)
```
La version technique racine est `0.3.0`. Aucun `Cargo.lock`, `package-lock.json`, `pnpm-lock.yaml`, `yarn.lock`, `node_modules/`, `dist/`, `target/` ou binding WASM généré n'est présent dans l'archive source.
L'absence de `.git` est normale pour cette archive taggée et ne permet ni ne requiert d'inventer un état Git.
## État fonctionnel hérité
La release `0.3.0` apporte déjà les briques nécessaires au second host :
- `game-snake-poc` porte le gameplay et reste indépendant du host ;
- `game-snake-poc-wasm` expose le runtime Snake à WebAssembly ;
- `Web/game-snake-poc` valide Canvas, clavier/pointer/touch, resize, lifecycle navigateur, assets, diagnostics frontend et provenance ;
- le runner Desktop SDL3 reste le témoin natif de non-régression ;
- les builds Web nouveaux utilisent Cargo, `wasm-bindgen` et Vite sans orchestration Python.
Le POC Tauri Reflex historique fournit en plus une référence de structure Tauri, mais il conserve des hooks Python gelés qui ne doivent pas être copiés dans un chemin `0.3.x`.
Son manifest contient déjà le triplet `crate-type = ["staticlib", "cdylib", "rlib"]`, compatible avec la préparation mobile Tauri. En revanche son `run()` reste un point d'entrée Desktop et n'est pas annoté `#[cfg_attr(mobile, tauri::mobile_entry_point)]`. La nouvelle app Snake doit donc reprendre la séparation de fichiers, pas ce détail Desktop : le `run()` possédé par `tauri.rs` devra être le point d'entrée mobile et être réexporté par la façade `lib.rs`.
Le manifest Reflex déclare aussi `engine-v1-platform-api`, alors que son code source Tauri ne le consomme pas directement. Cette dépendance ne doit pas être copiée par mimétisme dans la nouvelle app ; la provenance Snake appartient déjà à l'adapter WASM tant qu'aucune responsabilité backend Tauri ne justifie ce lien.
## Référence KSP Desk
L'archive de référence KSP `khadhroony-solana-project-v0.3.15.zip` est bien présente dans la bibliothèque du projet, mais son export binaire vers l'environnement de travail n'est pas autorisé par la bibliothèque. Son contenu intégral n'est donc pas présenté comme audité ici.
Les éléments KSP indexés accessibles confirment néanmoins la convention recherchée :
- `src/tauri.rs` concentre l'assemblage Tauri et le lifecycle de fenêtre ;
- des modules propriétaires tels que `app_state.rs`, `route_runtime.rs` et `frontend_logging.rs` portent leur logique au lieu de gonfler `tauri.rs` ;
- les diagnostics frontend sont routés vers des cibles `tracing` structurées.
Le modèle normatif de `games.sasedev` reste la source de vérité : `lib.rs` façade/reexports, `tauri.rs` assemblage et pont Web/Rust, modules propriétaires séparés.
## Réutilisation attendue du host Web
### Réutilisé sans changement de responsabilité
`game-snake-poc` reste inchangé comme source de vérité du gameplay.
Les assets canoniques sous `assets/common/` et `assets/game-snake-poc/` restent les mêmes ; le host Tauri doit les embarquer ou les copier au build, pas créer une seconde source.
Le contrat sémantique d'entrée du jeu reste le même. Les boutons tactiles et éventuelles entrées clavier du WebView convergent vers les mêmes actions Snake.
### Réutilisé avec adaptation de host
Le Canvas, la session fixed-step, la projection de scène et une grande partie du shell Vite/TypeScript du host Web sont des références directes pour le frontend Tauri.
La détection `DeviceClass` et `InputProfile` peut être reprise, mais les dimensions fixes de provenance changent :
```text
Web direct = Web / Wasm / Browser
Tauri Android = Android / Wasm / TauriWebView
```
Le lifecycle navigateur `visibilitychange/pagehide/pageshow` n'est pas copié comme seul contrat mobile. Le host Tauri Android doit tester le comportement réel lors de pause/reprise, changement d'orientation, background/foreground et fermeture/navigation système.
Le logging frontend Web direct n'est pas réutilisé tel quel : Tauri doit utiliser le bridge `@fltsci/tauri-plugin-tracing` vers `tauri-plugin-tracing`/`tracing`.
### Dépendances frontend à ne pas copier mécaniquement
Bootstrap, Bootswatch, Font Awesome et Sass peuvent être repris si le shell Tauri conserve réellement la même UI.
SimpleBar et `resize-observer-polyfill` restent des dépendances du shell Web direct ; les règles interdisent de les faire devenir des dépendances Tauri par simple copie. Elles ne seront ajoutées que si le layout Android Tauri démontre leur nécessité.
## Point de friction principal : provenance de l'adapter WASM
`game-snake-poc-wasm` est réutilisable pour le gameplay et le rendu, mais son état `0.3.0` fixe actuellement `PlatformFamily::Web` et `RuntimeHost::Browser` dans son constructeur et dans `configure_runtime_provenance`.
Il ne peut donc pas décrire correctement un WebView Tauri Android sans modification minimale.
La direction retenue est de généraliser uniquement la configuration de provenance du host dans l'adapter existant, sans dupliquer le bridge et sans créer une abstraction WebView commune prématurée. Le même adapter doit pouvoir représenter au moins :
```text
Web / Browser / Wasm
Android / TauriWebView / Wasm
```
Le nom `PlatformFamily::Android` est conservé. `Mobile` reste une famille conceptuelle d'architecture et ne justifie pas un renommage de l'API V1 ni l'introduction d'iOS dans `0.3.1`.
## Structure cible de l'application
Le second host sera une nouvelle crate :
```text
crates/apps/game-snake-poc-tauri/
```
La crate est génériquement nommée Tauri afin de pouvoir accueillir ultérieurement le host Desktop prévu en `0.3.2`, mais `0.3.1` n'en valide que la cible Android.
Structure minimale visée :
```text
crates/apps/game-snake-poc-tauri/
├── Cargo.toml
├── build.rs
├── tauri.conf.json
├── capabilities/
├── frontend/
├── src/
│ ├── lib.rs
│ ├── main.rs
│ ├── runtime.rs
│ └── tauri.rs
├── README.md
└── USAGE.md
```
`lib.rs` reste une façade. `tauri.rs` assemble builder/plugins/commands et délègue aux modules propriétaires. Une responsabilité supplémentaire devient un module dédié plutôt qu'une collection de helpers dans `tauri.rs`.
Le `README.md` est requis pour expliquer frontières et architecture. `USAGE.md` est également retenu car le host Android Tauri possède des prérequis SDK/JDK/NDK, des commandes de device/AVD et des smokes non triviaux.
## Build et commandes Tauri Android
La revue des règles a trouvé un défaut de cible : les commandes Tauri existantes `cargo tauri dev/build` correspondent au chemin Desktop alors que le nouveau POC est mobile Android.
La règle est corrigée pour réserver à Android :
```text
cargo tauri android init
cargo tauri android dev
cargo tauri android build
```
Le projet mobile généré par Tauri est traité comme partie du host Android lorsqu'il est requis par l'outil ; son contenu exact sera créé par l'outil Tauri dans la tranche d'implémentation, pas fabriqué à la main pendant le cadrage.
Aucun nouveau script Python de build n'est autorisé. Le frontend Vite/TypeScript et la génération WASM doivent rester possédés par les hooks Tauri et les outils natifs Cargo/`wasm-bindgen`/Tauri.
## Environnement Android : confirmé et à reconfirmer
L'historique du dépôt prouve des validations récentes de l'autre chemin Android SDL3 : NDK, ADB, AVD API 36 et appareil ARM64 réel ont déjà été utilisés avec succès pendant `0.1.0`.
La release `0.3.0` prouve également l'usage récent de Cargo, `wasm32-unknown-unknown`, `wasm-bindgen`, Node/npm et Vite.
Ces validations historiques ne prouvent pas l'état présent du toolchain Tauri Android. Avant `0-pre.2`, l'utilisateur doit fournir un inventaire frais de :
- `cargo tauri --version` ;
- targets Rust Android installés ;
- Java/JDK et `JAVA_HOME` ;
- `ANDROID_HOME` ;
- NDK et `NDK_HOME` ;
- `adb version` et devices visibles ;
- AVD disponibles ;
- Node/npm et `wasm-bindgen`.
Les prérequis Tauri 2 actuels pour Android comprennent Android Studio/tooling SDK, NDK, JDK et les targets Rust Android. Cette tranche ne suppose pas qu'ils sont tous encore configurés seulement parce que l'Android SDL3 historique fonctionnait.
## Risques à tester explicitement
- compatibilité réelle de `tauri-plugin-tracing` et du bridge frontend sur Android ; le package `0.3.x` est bien la référence actuelle du projet, mais le support mobile doit être prouvé par compilation/smoke plutôt que supposé ;
- lifecycle background/foreground et suspension du WebView ;
- distinction entre une sortie applicative Tauri, qui passe par `EngineGame::quit_requested`, et le Back système Android, qui ne doit pas être consommé artificiellement ;
- propagation correcte des dimensions logiques et du `devicePixelRatio` après rotation/resize ;
- chargement des assets embarqués sans dépendre du serveur Vite en build Android ;
- pipeline WASM sans script Python ;
- séparation claire entre Android SDL3 existant sous `Android/` et Tauri Android généré par la crate Tauri ;
- absence de dépendances Web-only recopiées par inertie ;
- output des builds et caches hors racine selon `GAME-BUILD-001`.
## Décisions de cadrage
Retenu pour `0.3.1` :
- une seule nouvelle app `game-snake-poc-tauri` ;
- Android uniquement comme cible validée dans cette version ;
- réutilisation du même `game-snake-poc-wasm` après généralisation minimale de provenance ;
- réutilisation sélective du frontend Web ;
- structure Rust Tauri conforme aux apps Desk : façade, assemblage, modules propriétaires ;
- tracing Tauri de bout en bout ;
- pas de nouveau framework commun tant qu'une duplication réelle entre Web direct et Tauri WebView n'est pas mesurée ;
- aucun orchestrateur Python nouveau ou repris.
Reporté :
- Tauri Desktop Snake comme produit validé, vers `0.3.2` ;
- abstraction WebView commune, sauf duplication réellement prouvée ;
- iOS ;
- Android SDL3 multi-ABI supplémentaire ;
- ads, billing, auth, réseau realtime et Uroburas.
## Sizing
Le scope complet est trop risqué pour être comprimé dans une seule prerelease d'implémentation. Le découpage retenu est :
```text
0-pre.1 audit / règles / requirements / environnement / plan
0-pre.2 scaffold Tauri Android + pipeline natif + bridge minimal vers Snake WASM
0-pre.3 Canvas / input / assets / shell réutilisé du Web
0-pre.4 lifecycle / provenance / tracing / Back + smoke mobile
0-pre.5 conditionnel : extraction commune seulement si duplication réelle
2-beta.1 gate large + packaging Android + AVD/appareil selon disponibilité
2-beta.2 consolidation documentaire si nécessaire
3-rc.1 candidate gelée et reproductibilité
0.3.1 promotion stable mécanique
```
Une tranche peut être scindée si un défaut outillage réel l'impose. `0-pre.5` est supprimé s'il n'existe aucune extraction justifiée.

45
history/0.3.1/0-pre.1.md Normal file
View File

@@ -0,0 +1,45 @@
<!-- file: history/0.3.1/0-pre.1.md -->
<!-- version: 1 -->
# Historique 0.3.1-0-pre.1
## Statut
Cadrage `0.3.1-0-pre.1` validé par l'utilisateur le 2026-09-20. Les audits, le formatage, le check workspace et Clippy strict passent ; aucun `.fix.N` n'est requis avant l'ouverture de `0-pre.2`.
## Gate utilisateur
La gate fournie dans le delta a été exécutée avec succès :
```text
General Rust rule audit: clean
Rust export completeness audit: 0 candidate(s)
games.sasedev workspace audit: clean
Markdown table audit: clean (5 table(s), 210 file(s))
Distribution layout audit: clean (31 required path(s), 1 forbidden path(s) absent)
cargo fmt --all: clean
cargo fmt --all -- --check: clean
cargo check --workspace: clean
cargo clippy --workspace --all-targets --all-features -- -D warnings: clean
```
## Environnement confirmé
L'inventaire de transmission vers `0-pre.2` confirme :
- Rust/Cargo `1.94.1` ;
- Tauri CLI `2.11.3` ;
- cibles Rust `aarch64-linux-android`, `x86_64-linux-android`, `wasm32-unknown-unknown` et `x86_64-unknown-linux-gnu` ;
- Node `24.21.0`, npm `11.19.0`, wasm-bindgen `0.2.128` ;
- OpenJDK Temurin `25.0.4.1` disponible via `java` ;
- `ANDROID_HOME=/home/sinus/DEV/AndroidSDK` ;
- `JAVA_HOME` et `NDK_HOME` non définis globalement ;
- Android Debug Bridge `37.0.1` ;
- un Samsung SM-G965F réel connecté ;
- AVD `Medium_Phone`, `Medium_Phone_API_36.0` et `sasedev_games_api36` disponibles.
Le projet ne transforme pas l'absence de `NDK_HOME` en défaut : l'installation locale conserve plusieurs NDK sous `$ANDROID_HOME/ndk/<version>`. Si une commande Tauri demande cette variable, elle sera définie ponctuellement vers une version exacte. De même, `JAVA_HOME` ne devient nécessaire que si la CLI ne résout pas le JDK disponible depuis l'environnement.
## Transmission vers 0-pre.2
L'archive complète `khadhroony-solana-project-v0.3.15.zip` est désormais disponible directement pour la tranche suivante. L'audit de ses six applications `ksp-app-*-desk` confirme le modèle retenu : façade `lib.rs`, assemblage `tauri.rs`, frontend Vite dans la crate, `tauri.conf.json`, capability dédiée et dépendances tracing Rust/TypeScript.

View File

@@ -1,5 +1,5 @@
<!-- file: prompts/003-V0_3_1_START_PROMPT.md -->
<!-- version: 3 -->
<!-- version: 4 -->
# Prompt de démarrage `0.3.1` — second host Snake Tauri Android
@@ -281,13 +281,13 @@ Pour une application Tauri, `npm` sert seulement à gérer les dépendances fron
Le smoke courant utilise :
```bash
(cd <tauri-app> && cargo tauri dev)
(cd <tauri-app> && cargo tauri android dev)
```
Le packaging est réservé aux phases finales prévues par le plan :
```bash
(cd <tauri-app> && cargo tauri build)
(cd <tauri-app> && cargo tauri android build)
```
Ne pas traiter le host Tauri comme le host navigateur direct de `0.3.0` : le mode de lancement, le packaging, les permissions et les smokes sont différents.
@@ -417,7 +417,7 @@ Toute commande nécessitant un changement de répertoire est englobée dans un s
(cd <répertoire> && <commande>)
```
Pour Tauri, utiliser `cargo tauri dev` pour les smokes et réserver `cargo tauri build` aux phases finales de packaging ; `npm` n'est utilisé directement que pour gérer les dépendances frontend.
Pour Tauri, utiliser `cargo tauri android dev` pour les smokes Android et réserver `cargo tauri android build` aux phases finales de packaging Android ; `npm` n'est utilisé directement que pour gérer les dépendances frontend.
## 13. Qui exécute quoi
@@ -429,8 +429,8 @@ Les validations de build/runtime restent côté utilisateur :
cargo check workspace + Clippy workspace strict lorsqu'un delta touche Rust/dépendances
tests cargo ciblés par défaut
test workspace complet seulement aux jalons planifiés/portées incertaines
(cd <tauri-app> && cargo tauri dev) pour les smokes Tauri
(cd <tauri-app> && cargo tauri build) pour les validations finales de packaging Tauri
(cd <tauri-app> && cargo tauri android dev) pour les smokes Tauri
(cd <tauri-app> && cargo tauri android build) pour les validations finales de packaging Tauri
Gradle/SDK/NDK lorsque le chemin Tauri les invoque
installation émulateur/appareil
smoke mobile
@@ -482,8 +482,8 @@ Sinon omettre la tranche.
### `2-beta.1` — validation large
- workspace complet ;
- `(cd <tauri-app> && cargo tauri build)` pour le packaging Tauri Android ;
- smoke via `(cd <tauri-app> && cargo tauri dev)` puis émulateur/appareil disponible ;
- `(cd <tauri-app> && cargo tauri android build)` pour le packaging Tauri Android ;
- smoke via `(cd <tauri-app> && cargo tauri android dev)` puis émulateur/appareil disponible ;
- non-régression Web direct ;
- non-régression Desktop SDL3 lorsque nécessaire ;
- vérification dépendances/package/distribution.

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# file: scripts/audit_distribution_layout.py
# version: 7
# version: 10
"""Audit the static distribution layout expected by supported POCs."""
@@ -30,6 +30,17 @@ REQUIRED_PATHS = (
"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",
"crates/apps/game-snake-poc-tauri/Cargo.toml",
"crates/apps/game-snake-poc-tauri/README.md",
"crates/apps/game-snake-poc-tauri/USAGE.md",
"crates/apps/game-snake-poc-tauri/package.json",
"crates/apps/game-snake-poc-tauri/tsconfig.json",
"crates/apps/game-snake-poc-tauri/vite.config.ts",
"crates/apps/game-snake-poc-tauri/tauri.conf.json",
"crates/apps/game-snake-poc-tauri/capabilities/default.json",
"crates/apps/game-snake-poc-tauri/icons/icon.png",
"crates/apps/game-snake-poc-tauri/frontend/main.html",
"crates/apps/game-snake-poc-tauri/frontend/ts/main.ts",
"Web/game-snake-poc/package.json",
"Web/game-snake-poc/tsconfig.json",
"Web/game-snake-poc/vite.config.ts",
@@ -136,6 +147,63 @@ def audit_snake_web_integration(root: pathlib.Path) -> list[str]:
violations.append(message)
return violations
def audit_snake_tauri_android_integration(root: pathlib.Path) -> list[str]:
"""Validate the minimal Snake Tauri Android host boundary."""
violations: list[str] = []
cargo_path = root / "crates/apps/game-snake-poc-tauri/Cargo.toml"
package_path = root / "crates/apps/game-snake-poc-tauri/package.json"
tauri_path = root / "crates/apps/game-snake-poc-tauri/tauri.conf.json"
tauri_rust_path = root / "crates/apps/game-snake-poc-tauri/src/tauri.rs"
build_script_path = root / "crates/apps/game-snake-poc-tauri/build.rs"
frontend_path = root / "crates/apps/game-snake-poc-tauri/frontend/ts/main.ts"
logging_path = root / "crates/apps/game-snake-poc-tauri/frontend/ts/logging.ts"
wasm_runtime_path = root / "crates/apps/game-snake-poc-wasm/src/runtime.rs"
paths = (cargo_path, package_path, tauri_path, tauri_rust_path, build_script_path, frontend_path, logging_path, wasm_runtime_path)
if not all(path.exists() for path in paths):
return violations
cargo = cargo_path.read_text(encoding="utf-8")
package = package_path.read_text(encoding="utf-8")
tauri = tauri_path.read_text(encoding="utf-8")
tauri_rust = tauri_rust_path.read_text(encoding="utf-8")
build_script = build_script_path.read_text(encoding="utf-8")
frontend = frontend_path.read_text(encoding="utf-8")
logging = logging_path.read_text(encoding="utf-8")
wasm_runtime = wasm_runtime_path.read_text(encoding="utf-8")
required_fragments = (
(cargo, 'game-logging-lib = { path = "../../common/game-logging-lib" }', "DIST-LAYOUT-021: Snake Tauri host must use shared Rust logging"),
(cargo, 'tauri-plugin-tracing.workspace = true', "DIST-LAYOUT-022: Snake Tauri host must enable the tracing plugin"),
(package, '"wasm:dev": "cargo build -p game-snake-poc-wasm', "DIST-LAYOUT-023: Snake Tauri dev hook must build the shared Snake WASM adapter"),
(package, 'wasm-bindgen ../../../../builds/sasedev-games/', "DIST-LAYOUT-024: Snake Tauri bindings must be generated outside the repository"),
(package, '"dev": "npm run wasm:dev && vite"', "DIST-LAYOUT-036: Snake Tauri dev hook must leave Android generation to Tauri"),
(package, '"build": "npm run wasm:build && tsc && vite build"', "DIST-LAYOUT-037: Snake Tauri build hook must leave Android generation to Tauri"),
(build_script, "tauri_build::build();", "DIST-LAYOUT-038: Snake Tauri build script must delegate Android integration to tauri-build"),
(tauri, '"script": "npm run dev"', "DIST-LAYOUT-025: Tauri must own the frontend development hook"),
(tauri, '"script": "npm run build"', "DIST-LAYOUT-026: Tauri must own the frontend production hook"),
(tauri_rust, '#[tauri::mobile_entry_point]', "DIST-LAYOUT-027: Snake Tauri run entry point must support Tauri mobile"),
(tauri_rust, 'tauri_plugin_tracing::Builder::new()', "DIST-LAYOUT-028: Snake Tauri runtime must install the tracing plugin"),
(frontend, 'configure_runtime_provenance(', "DIST-LAYOUT-029: Snake Tauri frontend must configure provenance through the shared adapter"),
(logging, '@fltsci/tauri-plugin-tracing', "DIST-LAYOUT-030: Snake Tauri frontend logs must use the tracing bridge"),
(wasm_runtime, '"tauri-webview" => Some(engine_v1_platform_api::RuntimeHost::TauriWebView)', "DIST-LAYOUT-031: Snake WASM adapter must accept the Tauri WebView host"),
(wasm_runtime, '"android" => Some(engine_v1_platform_api::PlatformFamily::Android)', "DIST-LAYOUT-032: Snake WASM adapter must accept Android provenance"),
)
for content, fragment, message in required_fragments:
if fragment not in content:
violations.append(message)
forbidden_fragments = (
(package, "python", "DIST-LAYOUT-033: Snake Tauri build hooks must not use Python"),
(package, "android:prepare", "DIST-LAYOUT-039: Snake Tauri build hooks must not patch generated Android Gradle files"),
(build_script, "gen/android", "DIST-LAYOUT-040: Snake Tauri build script must not mutate generated Android Gradle files"),
(tauri, "python", "DIST-LAYOUT-034: Snake Tauri configuration must not use Python build orchestration"),
(frontend, "console.", "DIST-LAYOUT-035: Snake Tauri application frontend must not log directly through console.*"),
)
for content, fragment, message in forbidden_fragments:
if fragment in content.lower():
violations.append(message)
return violations
def main() -> int:
"""Validate that every static distribution boundary exists."""
@@ -154,6 +222,7 @@ def main() -> int:
forbidden_present.append(relative)
contract_violations.extend(audit_snake_web_shell(root))
contract_violations.extend(audit_snake_web_integration(root))
contract_violations.extend(audit_snake_tauri_android_integration(root))
if missing:
for relative in missing:
print(f"DIST-LAYOUT-001: missing required path: {relative}", file=sys.stderr)

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# file: scripts/audit_project_workspace_rules.py
# version: 6
# version: 7
"""Audit mechanically verifiable games.sasedev workspace boundaries."""
@@ -15,6 +15,13 @@ import tomllib
SEMVER = re.compile(r"^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(?:-(?:0-pre|1-alpha|2-beta|3-rc)\.[1-9][0-9]*(?:\.fix\.[1-9][0-9]*)?)?$", re.ASCII)
def is_generated_path(path: pathlib.Path, root: pathlib.Path) -> bool:
"""Return whether a path belongs to an ignored generated tree."""
relative = path.relative_to(root)
return "gen" in relative.parts
def main() -> int:
"""Run project-specific workspace audits."""
@@ -86,10 +93,14 @@ def main() -> int:
errors.append(
f"DOC-011: documentary directory entry point must use 000-README.md: {readme_path.relative_to(root).as_posix()}"
)
forbidden_assets = [path for path in (root / "crates").rglob("assets") if path.is_dir()]
forbidden_assets = [
path for path in (root / "crates").rglob("assets") if path.is_dir() and not is_generated_path(path, root)
]
for path in forbidden_assets:
errors.append(f"GAME-ASSET-001: assets directory forbidden inside crates: {path.relative_to(root).as_posix()}")
for java_path in sorted(root.rglob("*.java")):
if is_generated_path(java_path, root):
continue
if not java_path.is_relative_to(root / "Android"):
errors.append(f"GAME-ANDROID-001: Java source outside Android/: {java_path.relative_to(root).as_posix()}")