# Diagnostics and problem reports Two ways users feed results back, both without a GitHub token: - **Share working recipe…** (game menu, `frameport share-recipe `): saves the recipe as a user catalog entry and opens a prefilled issue from `.github/ISSUE_TEMPLATE/working-config.yml`. A maintainer checks it and adds the label `catalog-accepted`. Then `.github/workflows/catalog-from-issue.yml` runs `scripts/catalog_from_issue.py`, which reads only the YAML block, validates it, and writes `catalog/games/.yaml`, and the workflow opens a PR. - The PR step needs Settings → Actions → "Allow GitHub Actions to create and approve pull requests". - Create the labels `working-config`, `catalog-accepted` and `bug` once. - **Report a problem…** / **Collect logs** (game menu, Settings, the failure pop-up, `frameport diag report|collect`): writes a redacted zip and opens a prefilled `bug-report.yml` issue. - GitHub has no API for issue attachments, so the user drags the zip in (25 MB max; the bundle stays under 24 MB). - Prefilled links are capped at about 7.5k characters. Free text is trimmed first; the recipe is never cut. Code: `src/frameport/diag/` (`redact.py`, `bundle.py`, `issue.py`), agent command `collect_diag` (agent ≥ 21), `Target.collect_diag`, `core/applog.py` (app log + saved job logs). ## Bundle layout (schema 1) ``` README.md what's where (for whoever opens it) manifest.json versions (app, agent, tools, SteamOS build, Proton), games, warnings, redaction counts app/app.log the app's log (/logs/app.log, rotated 2 MB × 3) app/jobs/*.log saved GUI job logs (/logs/jobs, last 30): build, install, test, ... app/settings.json library settings, catalog sources app/display.json Flet/Flutter versions and last window state; on native Windows, display layout, resolution, refresh rate, GPU driver metadata and up to 60 recent display/device System event records (last 30 minutes; timestamps, providers and IDs only) frame/info.json agent `info` (SteamOS build, Lepton, Proton, installed games, kernel keys) frame/host.json OpenXR runtime + explicit layers, podman containers, containers.conf, uptime frame/XRService-*.log the Frame's OpenXR runtime (SteamVR XRService) log, newest games//entry.json library entry: analysis, recipe, build checks, installs, last_test (store text dropped) games//recipe.yaml the recipe in catalog form; catalog-.yaml = the catalog entry it came from games//triage.json newest local launch log re-triaged with the bundling app's signatures games//logs/*.log launch-test logs kept on the PC (last 5) games//package/ stand-in for the game files (no content): apk_files.json every APK entry + size AndroidManifest.xml decoded manifest elf.json per lib/*.so: DT_NEEDED, ovr*/xr*/vrapi_/gl*/JNI exports + imports files.json, pe.json Rift: file list; PE imports / delay imports of the exe and VR DLLs games//target/ from the Frame (or the PC): launch.sh, settings.conf, deployment.json, launch.log, launch-test.log (PC VR), lepton-steamlaunch-.log, logcat-{main,crash,system,...}.log, ReviveInjector.txt / steam-.log / game-log-N.txt (PC VR), files.json (+ missing) (game-log-N.txt: Unreal Saved/Logs + crash summaries, Unity Player.log / Player-prev.log / output_log.txt + crash error.log from the Proton prefix, agent v67) threads.txt (agent v79): saved while a Quest game runs (e.g. hangs), each thread's state, CPU ms over 2 s, kernel wait and syscall, plus its TCP sockets (remote = loopback / local / internet + port, no addresses); read once from /proc, the game isn't paused games//target/shaders/ shader dumps (agent v72), when the game wrote any: fp_vk_shaders/ adapter vk_shader_dump=1 (Vulkan shim): _.spv + index.txt fp_spirv/ adapter zink_shader_dump=1 (OpenGL ES, shader-fix layer under Zink): _.spv ``` Each log keeps at most its last 4 MB (2 MB per file from the Frame). Shader dumps, SPIR-V unchanged (compiled game shaders, not redacted): Vulkan (agent v74) every module the game's newest run (the last `# start` in `index.txt`) created, last used first, each up to 4 MB and up to 30 MB in all, with that run's index lines, so a module created well before a GPU hang comes along too (if the zip would pass 24 MB, the least recently used ones are left out after the logs were cut); OpenGL ES (no index): the newest modules (by time written) up to 4 MB. `index.txt` (Vulkan) lists every vkCreateShaderModule as ` _.spv new|known|again|failed`; match the unix time with the kernel's `hangcheck detected gpu lockup` line (this-boot-kernel.txt). All modules stay in the game's storage on the Frame (`Android/data//files/fp_vk_shaders/`, Files tab → the game's storage). Display queries run only while collecting logs. The Windows event query has a five-second timeout and runs without a console window; the result distinguishes no matching events from a failed or timed-out query. Window visibility, focus and completed move/resize events are recorded in `app.log`, with UTC timestamps for comparison with Windows events. There is no display polling loop or change to display settings. Empty System event results do not rule out a rendering or monitor-link problem. ## Redaction `diag/redact.py` runs on every file and on the issue text. - **Exact values:** the data dir → ``, home dirs → ``, user names → ``, PC and Frame host names and saved Frame addresses → ``, Steam account ids from the Frame's `info` and the PC's Steam → ``, the folders holding the user's game dumps → ``. - **Patterns:** IPv4 addresses (first octet ≥ 10, so version numbers survive), IPv6, MAC, SteamID64, `userdata/`, email addresses (file names like `x@123.txt` excluded), and any `/home/`, `/Users/`, `C:\Users\` or `/mnt/c/Users/`. - **Kept:** generic accounts that identify no one: `steamos`, `steamuser` (Proton), `root`, `deck`. ## Debugging from a bundle (no game, no Frame, no GUI) 1. `frameport diag inspect ` (`--json` for everything). It prints the versions and warnings, the last launch test, and a fresh triage of the newest launch log with the current `catalog/triage.yaml`. 2. Match the findings and log lines against `docs/PLAYBOOK.md` (symptom → cause → fix) and `docs/FRAME_RUNTIME.md`. 3. Check the analysis in `entry.json` (engine, XR API, `extra`: missing ovr symbols, features, Unreal version) and `package/elf.json` against the heuristics in CLAUDE.md. Compare `recipe.yaml` with catalog games that use the same engine and API. 4. Compare `manifest.json → env.frame.build_id` with the build the docs describe: SteamOS updates change the runtime. 5. A new failure signature means adding a patch module, a `triage.yaml` signature, a PLAYBOOK row and a unit test (see Conventions). Then `diag inspect` on the same zip should report it.