# Offline Fortune Teller ## Current integration (2026-10-31) The seated tarot scene now calls the bundled neural worker again. The visual session had replaced process startup, polling and interpretation with stubs; keeping `fortune-engine.exe` alone did not make that scene AI-enabled. MASM owns question input, selection of three distinct major arcana, orientation, animation, IPC, process lifetime, response validation, pagination and rendering. Only local neural inference/text generation runs in the approved C++ worker. The crystal-ball lottery is unchanged and does not invoke the model. ## Answers and interaction Enter a question of up to 240 CP1251 characters. Submission commits three cards and starts the worker while the normal shuffle/deal/flip animation continues. The first explanation waits if inference has not finished. Rendering and exit remain responsive. Continue advances a fully displayed page; it does not skip dealing or flip animations. All interpretation pages require Continue, so a long answer cannot disappear before it is read. Again starts a new independent reading. The worker returns four Russian sections: situation, obstacle, direction, and overall advice. A grammar fixes the first three headings to the actual supplied card names, positions and orientations. Each body is bounded to 80-220 characters and ends with punctuation. The body itself is model-generated, not a canned card description. Grammar prevents structural/card-heading errors; it does **not** prove that every interpretation is sensible. Semantic quality still needs human review. Each native bubble page wraps words within nine 23-character rows. Missing model, startup failure, broken pipes, invalid/oversized frames, incomplete output and a 180-second wait produce visible errors, not fake successful readings. Exit/Selection close the worker and its pipes; no model is loaded for the crystal ball or walking. No questions or answers are written to the player profile or runtime logs. ## Model and distribution - Qwen3-4B-Instruct-2507, Q4_K_M GGUF, Apache-2.0. - Exactly 2,497,281,120 bytes; pinned revision and SHA-256: `ai/model.json`. - Pinned llama.cpp source, CPU-only x64 worker, AVX baseline, static MSVC runtime. - About 3 GB working set in the earlier baseline; 8 GB system RAM is a practical starting point, not a verified minimum. - Generation is not instant: the first updated development-machine sample took about 55 seconds. Hardware and question length affect this substantially. - No cloud API, Ollama, Python runtime, listening port, runtime downloader or GPU driver requirement. The game must ship with the actual GGUF in `ai/models/`. `tools/fortune_ai/build.ps1` builds the worker and verifies the model. Its explicit `-DownloadModel` option is a developer/release preparation action only. The GGUF and vendor build files are ignored by Git. After cloning or copying the repository, double-click **`download_fortune_model.bat`** in the repository root. No Python, Git LFS or administrator access is required. The setup uses Windows PowerShell and `curl.exe` (current Windows 10/11), requires Internet and about 3 GB free space. For unattended setup: ```powershell .\download_fortune_model.bat --no-pause ``` The setup downloads from pinned ModelScope/Hugging Face revisions, resumes partial downloads where supported and falls back to the next source. It checks size and SHA-256 from `ai/model.json` before replacing the destination. An existing valid model is verified without network access. Failed downloads do not replace an existing destination; rerun setup to retry. URLs, size and hash are versioned in the manifest. The game never invokes setup or downloads weights at runtime. The legacy Python download entry point and build script's `-DownloadModel` option delegate to the same PowerShell implementation. Complete offline release ZIPs still bundle the real weights and need no setup download. `python tools/fortune_ai/package.py` builds `dist/Assembler Casino Offline.zip` with launcher, game, assets, worker, prompts, licenses and the verified weights. `--check-only` validates inputs without making an archive. Use this full ZIP for another PC. The old C# self-extracting installer is not suitable for embedding the 2.5 GB weights; the existing launcher is C#, not assembly. ## Protocol Inherited anonymous pipes, no shell or HTTP. Request: five little-endian DWORDs (`FCQ1`, question byte length, three card IDs), then CP1251 question bytes. IDs 0-21 are upright; 22-43 reversed. Worker limit: 768 question bytes, distinct cards. Response: three DWORDs (`FCR1`, status, text byte length), then CP1251 text, capped at 8192 bytes. Status 0 is ready, 1 complete answer, 2 error. Legacy status 3 (token-limited output) is rejected rather than displayed as a finished reading. Complete answers have exactly four nonempty newline-separated sections. Native polling waits only for bytes already available and never blocks on partial frames. ## Verification ```powershell python -B tools/tests/check_fortune_ai.py python -B tools/tests/check_fortune_session_ai.py python -B tools/tests/check_fortune_session_ai.py --with-model python -B tools/tests/check_hall_expansion.py ``` Python test dependencies: `tools/tests/requirements.txt`. Native tests require the MASM/MSVC x86 toolchain. Real-model tests also require the bundled weights. - Worker test checks actual Russian inference, exact card headings/orientations, four complete bounded sections, independent requests and oversized input. - Native test exercises actual submission, split headers/bodies, parser, paging, oversized frames, broken pipes, timeout and cleanup with controlled pipe frames. - `--with-model` exercises real WM_CHAR input, assembly-selected request data, child/model response and all four reading stages through native UI controls. - Hall regression preserves shuffle/deal/flip artwork, crystal-ball validation, number tracking, navigation, bowling and other existing scenes. Fictional test questions, answers and captures stay under ignored `build/`. Automated format checks do not certify tarot predictions or replace desktop QA.