#!/usr/bin/env python3 """Render the documentation from the same digest-scoped data used by the store.""" import argparse from collections import Counter import json from pathlib import Path ROOT = Path(__file__).resolve().parents[1] def cell(value): if isinstance(value, list): value = ', '.join(str(v) for v in value) or 'none detected' return str(value).replace('|', '|').replace('\n', ' ').replace('<', '<') def render(data): counts = Counter(p['status'] for p in data['plugins']) lines = ['# Official Decky store compatibility with Framey', '', f"Snapshot: {data['checkedAtUtc']}; {len(data['plugins'])} current visible official plugins from {data['source']}.", '', 'This table and both store views use [`ui/framey-compatibility.json`](../ui/framey-compatibility.json). ' 'Results apply only to the exact store ID, version and SHA-256. A changed digest/version is **unverified**. ' 'Regenerate this document with `python3 scripts/framey-compatibility-doc.py`; use `--check` in review.', '', f"**Works: {counts['works']} · Partial: {counts['partial']} · Broken: {counts['broken']} · N/A: {counts['na']}.**", '', '- **Works** requires verified useful plugin behavior with its real backend. Read the reason for the verified scope and remaining limits; it does not imply worn-VR verification.', '- **Partial** means only a subset or a local fixture scope was verified, often just frontend/settings initialization. The remaining backend/device functionality is unverified; read the reason for the exact scope.', '- **Broken** means a concrete archive, frontend or Steam dependency blocks the audited version. An artificial backend/network denial alone is not evidence that the real backend is broken.', '- **N/A** means the plugin targets hardware or a display/UI surface that Framey does not provide. The store disables installation for these versions.', '', '## Verification limits', '', f"All exact archives were hash-checked and statically inspected. The local Chromium host used Framey commit `{data['hostCommit']}`, React 18.3.1 and an opaque `allow-scripts` iframe. " 'Each frontend was attempted for 1.2 seconds, including React effects. All plugin backend calls, fetches and websockets were denied. ' 'Some plugins attempt mutating actions on mount; none reached a backend. Initialization (`ready`) does not guarantee React rendered, and delayed errors/actions may occur after the observation window. ' 'The JSON preserves initializer errors, capped console observations and attempted method names.', '', 'The optional full-catalog fake-Frame audit exercises the real HTTP/SSH installer, receipt, frontend bytes and removal, ' 'or expected rejection. It uses a private disposable Compose project with all plugin backend execution stubbed. ' 'It checks archive transport and safeguards, not Python/native execution. Run it with:', '', '```sh', 'python3 scripts/framey-audit-store.py --cache /tmp/framey-archives --output /tmp/framey-observations.json', 'python3 scripts/framey-audit-fake.py --cache /tmp/framey-archives --output /tmp/framey-fake/results.json', 'python3 scripts/framey-audit-browser.py --cache /tmp/framey-archives', '```', '', 'Open the browser audit URL in local Chromium, run `runAudit()` and inspect/download `results`. All backend/network actions remain denied.', '', 'The current published digests are pinned in the JSON; if the store changed, retain/download those exact archives for reproduction. ' 'Audit downloads permit larger ZIPs for inspection; production installer limits remain 50 MiB ZIP / 150 MiB unpacked / 30 MiB per member.', '', 'After the VR job released the shared lock, this audit acquired it and used a private temporary Decky 3.3.0 ARM64 user service. ' 'Read-only ProtonDB `get_setting` and Steam Status `get_settings` calls succeeded through the live Steam CEF websocket. ' 'The service and private base were removed and the lock released; normal managed services stayed inactive, battery was 100 → 99, ' 'and no power setting was changed. [Redacted results](evidence/framey-official-backend-2026-10-25.json) ' 'record exactly what ran. A [2026-10-26 follow-up](evidence/framey-events-backend-2026-10-26.json) ' 'verified default Notebook drawing/save/reopen across a real backend restart and Simple Timer start/cancel, ' 'countdown/completion events, a visible toast and persisted recents/subtle mode. ' 'Only private test settings were written. Simple Timer remains partial because its own expired-timer startup ' 'raises a missing `timer_task` error; sound/suspend are unsupported. ' 'A [local audio follow-up](evidence/framey-audio-backends-2026-10-26.md) exercised Volume Mixer, Volume Boost and Mixer ' 'through real Decky 3.3.0 amd64 backends on private silent virtual audio targets. Sliders, numeric volume entry, ' 'independent server readbacks and Mixer filter persistence across a runtime restart passed. ' 'An [ARM64 audio follow-up](evidence/framey-audio-arm64-2026-10-26.md) verified the unmodified official backends in actual Decky 3.3.0 on the Frame user audio session. Volume Mixer and Mixer now qualify as works for per-app volume: Chromium controls changed only a named silent stream, with independent Pulse readbacks. That run left Volume Boost partial because sink writes were denied. A [Volume Boost follow-up](evidence/framey-volume-boost-arm64-2026-10-26.md) now verifies linked/separate channel controls, re-link and reopen through the actual ARM64 backend. Independent Pulse reads confirmed 125%/150% gain writes while the default sink stayed muted; exact original volume/mute was restored. Volume Boost qualifies as works for sink controls. Audible output, Bluetooth playback and worn VR remain unverified. ' 'A [running-context follow-up](evidence/framey-running-context-2026-10-26.md) supplies detached running-app/main-app reads and relays actual Steam lifetime callbacks while a panel is open. Real Frame checks verified an empty list, registration/cleanup and the exact Discord Status ARM64 backend reporting no IPC connection. Nonempty games and transitions were synthetic fixtures; real game events, Discord activity and worn VR remain unverified. Discord Status moves to partial; no new works claim is made. ' 'A [library context follow-up](evidence/framey-library-context-2026-10-26.md) read 1,106 app overviews, 895 game IDs ' 'and the current public Steam ID from real Frame CEF under the shared lock. Local Chromium replayed this detached snapshot ' 'to render Deck Settings game selection, Steamback\'s empty save panel and PlayTime statistics/settings. ' 'Steamback and PlayTime used actual Decky 3.3.0 amd64 backends in an isolated container; their ARM64 backends and automatic game hooks remain unverified. ' 'Shotty\'s frontend now starts, but its published backend fails on missing `click`; it stays broken. ' 'A [chunked frontend follow-up](evidence/framey-deck-shelves-browser-2026-10-26.md) loaded Deck Shelves 2.0.0 ' 'through a managed JavaScript module route and rendered its settings in an opaque local Chromium panel. ' 'Its backend was denied; Steam Home shelves and worn VR remain unverified. ' 'A [local module lookup follow-up](evidence/framey-module-lookup-2026-10-26.md) supplies a finite registry of Framey-local controls and CSS. TabMaster QAM/docs now render; Steam library-tab editing remains unavailable. That pass exposed Junk-Store executable-script extraction failures; the follow-up below repairs them. SteamGridDB still requires Steam context-menu internals and DeckSP still fails its published MobX fallback. That pass tested TabMaster/Junk-Store in actual isolated amd64 Decky, without ARM64 or worn-VR coverage. A [script entrypoint follow-up](evidence/framey-script-entrypoints-2026-10-26.md) grants owner execute to shebang scripts and ZIP-declared executables without copying archive privilege/write bits. Junk-Store now passes static menu/backend calls in actual Decky 3.3.0 ARM64 and local Chromium Games/Epic navigation, back and reopen. It moves to partial: About still crashes on missing installed-app metadata, Legendary is absent, and login/game operations remain unverified. Existing installations require update/reinstall to repair permissions. A [read-only installed-metadata follow-up](evidence/framey-installed-context-2026-10-26.md) now repairs the About crash. The library snapshot copies only Steam-supplied installed booleans into detached metadata, preserving unknown values as undefined. Junk-Store About/Dependencies, Back and reopen render in local Chromium with actual Frame library data and the official ARM64 backend. It remains partial: dependency/login/game operations, RSS, the optional websocket and worn VR are unverified. Beyond the documented checks, official backends remain unexecuted. ' 'The separate VR job proves Frame Control/sample compositor rendering, not any official plugin. ' 'No worn-VR official-plugin result is claimed. ' 'A [local UI follow-up](evidence/framey-ui-fallbacks-2026-10-26.json) rendered Pause Games and Tailscale Control settings ' 'with all backend/network actions denied; it does not verify process pausing or Tailscale changes. ' 'A [read-only Steam bridge follow-up](evidence/framey-steam-reads-2026-10-26.json) verified actual Frame country, ' 'install folders and system information, plus IsThereAnyDeal\'s country dropdown in local Chromium. ' 'The installed-plugin status was fixture-shaped in that relay; plugin backends stayed denied and the deployed headset HTTP endpoint remains unverified. ' 'A [Web Browser frontend follow-up](evidence/framey-web-browser-2026-10-26.md) verified its exact archive now initializes with an inert null Steam React-root lookup. Its GamepadUI CDP/browser backend path remains unavailable, so it stays broken. ' 'A [dialog and activation follow-up](evidence/framey-dialog-controls-2026-10-26.md) fixes DFL Focusable pointer/keyboard activation and confirmation descriptions, cancel/disabled actions, scoped close callbacks and nested dialogs. ' 'AlarMe silent timer ticks/pause/cancel, private preset save/cancel-confirm/delete and stopwatch start/lap/pause/reset/reopen pass in local Chromium with its official Decky 3.3.0 ARM64 backend. ' 'AlarMe stays partial: audio, alarms/reminders, sleep inhibition, Steam overlays and worn VR are unverified; notifications require the panel to remain open. ' 'Earlier focused checks cover [ProtonDB](evidence/framey-browser-2026-10-25.md), ' '[Steam Status/cache](evidence/framey-cache-browser-2026-10-25.md), ' '[Storage Cleaner](evidence/framey-api-v1-browser-2026-10-25.md), and ' '[legacy MusicControl](evidence/framey-legacy-2026-10-25.md).', '', '## Every current plugin', '', 'The API column shows manifest / actual bundled frontend API. Many manifests say v1 while their bundle connects API2. ' 'Missing manifest API is labelled legacy; an unrecognized bundle is unknown. Globals and hardware are static signals, not exhaustive dependencies.', '', '| Plugin / version | Manifest / bundle API | Status | Reason | Verified by |', '| --- | --- | --- | --- | --- |'] for p in data['plugins']: lines.append('| '+ ' | '.join(map(cell, [f"{p['id']}: {p['name']} {p['version']}", f"{p['api']} / {p['frontendApi']}", 'N/A' if p['status']=='na' else p['status'], p['reason'], p['verification']]))+' |') lines += ['', '## API, UI and backend inventory', '', 'DFL includes exports imported through decky-frontend-lib / @decky/ui. Steam stores and router/toaster/QAM signals are listed separately. ' 'No signal means the static scan did not detect one, not that no dependency exists. Native binaries are classified by ELF machine or Windows MZ header; ' 'Python files and source links are preserved in the JSON.', '', '| Plugin | SteamClient methods | DFL / @decky/ui exports | Other Steam globals / UI surfaces | Backend | Hardware / OS signals |', '| --- | --- | --- | --- | --- | --- |'] for p in data['plugins']: native = sorted({n['arch'] for n in p['native']}) lines.append('| '+' | '.join(map(cell, [p['name'],p['steamClient'],p['dfl'],p['globals']+p.get('uiSurfaces',[]), p['backend']+('; '+', '.join(native) if native else ''),p['hardware']]))+' |') lines += ['', '## Native payload portability', '', 'All published Linux native payloads in this snapshot are x86_64; no published aarch64 payload was found. ' 'The three Windows DLLs belong to Decky-Framegen. The installer still rejects these archives. ' 'Apart from the explicitly described LocalSend experiment, ARM64 builds were not attempted: the constraints below remain unresolved.', '', '[LocalSend ARM64 build/runtime evidence](evidence/framey-localsend-arm64-2026-10-26.md) ' 'covers a reproducible MIT helper build and its isolated real-Frame protocol 2.0 info response. ' 'The official x86 archive remains blocked; full plugin integration and file transfers are unverified.', '', '| Plugin | Native payloads | ARM64 result / remaining blocker |', '| --- | --- | --- |'] for p in data['plugins']: if p['native']: binaries = [n['file'].removeprefix(p['folder']+'/') for n in p['native']] if len(binaries)>5: binaries = binaries[:5]+[f"… {len(binaries)} total; full list in JSON"] lines.append('| '+' | '.join(map(cell,[p['name'],binaries,p['nativePort']]))+' |') lines += ['', '## Evidence and maintenance', '', 'The canonical JSON contains full archive hashes, native paths, source URLs, frontend observations and fake-Frame outcomes. ' 'Store compatibility is advisory except known installation/hardware blockers; removal always remains available. ' 'A panel retains its compatibility reason after the initializer reports ready. Upstream fixes require a new digest-scoped audit. ' 'Do not mark a plugin works based on archive installation, fake backend replies or initializer completion.', ''] return '\n'.join(lines) def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('--check', action='store_true') args = parser.parse_args() output = ROOT/'docs/framey-compatibility.md' expected = render(json.loads((ROOT/'ui/framey-compatibility.json').read_text(encoding='utf-8'))) if args.check: if not output.exists() or output.read_text(encoding='utf-8') != expected: raise SystemExit('Compatibility documentation differs from canonical store data') else: output.write_text(expected, encoding='utf-8') if __name__ == '__main__': main()