mirror of
https://github.com/saphid/frame-control.git
synced 2026-10-04 22:00:10 +02:00
Keep worker notes and proof logs out of the repository
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
1b5f540a66
commit
3b36feff52
10 files changed
-515
No files matched your search
@@ -1,6 +0,0 @@
|
||||
/proof-cache/
|
||||
/amazon.html
|
||||
/aptoide-terms.html
|
||||
/itch-game.html
|
||||
/meta.html
|
||||
/uptodown-terms.html
|
||||
@@ -1,64 +0,0 @@
|
||||
# APK search
|
||||
|
||||
- Scope: dynamic source aggregator, additive server APIs, Android search view; no device calls.
|
||||
- Source metadata stays unknown when missing. Unknown-package names only group with other unknown packages (avoids ambiguous package attribution).
|
||||
- Queries use daemon workers with at most one in-flight request per source; deadlines don't wait for stuck workers.
|
||||
- Independent review delegated to parent per task brief; no workers launched.
|
||||
|
||||
## Implementation
|
||||
|
||||
- `ui/apk_sources/search.py`: discovers KIND modules, parallel daemon queries (12 s deadline), bounded per-source workers, grouped offers, fit/rank/filter logic, persisted source enablement, repo adapter and install adapter.
|
||||
- `ui/server.py`: GET `/api/sources`, GET `/api/search?q=&vr=true|false&installable=true|false&source=`, POST `/api/sources/install` and POST `/api/sources` with actions `add`, `remove`, `enable`.
|
||||
- `ui/index.html`: unified Find apps in Android tab, source/VR/Flat/Installable chips, offer picker, metadata, jobs, Sources panel. Old catalogue DOM remains hidden for existing report/icon code; only the unified search is visible.
|
||||
- `_demo.py` is discovered only with `FRAME_APK_SEARCH_DEMO=1`; it cannot download. `tests/search_preview.py` serves the real UI/search endpoints and rejects all device endpoints and writes.
|
||||
|
||||
## Evidence
|
||||
|
||||
- `python3 -m unittest discover -s tests`: 179 tests passed on Python 3.9.6, exit 0. Log `/tmp/apk-search-suite.log`.
|
||||
- `node --check /tmp/apk-search-evidence/ui.js`: exit 0; script extracted from index.html.
|
||||
- `git diff --check`: exit 0.
|
||||
- Python 3.9 grammar parse: search.py, _demo.py, server.py, test_apk_search.py and search_preview.py passed; actual suite interpreter also Python 3.9.6.
|
||||
- Started `FRAME_APK_SEARCH_DEMO=1 python3 tests/search_preview.py` locally; used T3 preview at http://127.0.0.1:8795/#android (1280x800).
|
||||
- Browser assertions: two grouped apps, source picker updates install choice, VR excludes flat, Flat excludes VR, source filter keeps one offer, search query narrows results, pending install disables its button after re-render. Passed.
|
||||
- Inspected screenshots: `/tmp/apk-search-evidence/search.png`, `/tmp/apk-search-evidence/sources.png`. Other panels show intentional device-access errors in the preview.
|
||||
- Tests cover dynamic module discovery, grouping (including ambiguous names), ranking, fit, timeout/failure isolation, persistent enablement, endpoint validation, repo callbacks, background install with mocked frame_android.install, conditional artwork, and OBB support/refusal.
|
||||
|
||||
## Parent integration / unverified
|
||||
|
||||
- No source modules from sibling branches are present yet. Real network listings/downloads, signatures, merged repo persistence and physical installation were not exercised. No SSH/device installation performed.
|
||||
- Assumes future `frame_android.install_obb(package, paths)`; reconcile with vr-library worker's actual signature. Artwork is passed only when install explicitly declares that parameter. OBB-required apps fail before APK installation when helper is absent.
|
||||
- `app/package.json` currently copies ui with only `*.py` / `*.html`; parent must include `apk_sources/**/*.py` in packaged resources when integrating source workers. Kept package config outside this worker's scope.
|
||||
- No cross-provider reviewer launched: task explicitly forbids delegation and assigns integration/review to the parent.
|
||||
- Source metadata unknowns do not imply compatibility or verification. Unknown-package entries only group with other unknown-package entries with the same normalized name.
|
||||
|
||||
## Store redesign (follow-up)
|
||||
|
||||
- Read `/tmp/vrapk/p5-redesign.md` and common ground rules in full. Consulted Human Interface Craft, especially purpose/information, hierarchy, progressive disclosure and familiar navigation.
|
||||
- Discover now owns the Android tab's full width; device controls/reports remain under On your Frame. Artwork cards, a featured app, browse rows, debounced search, friendly filters/count/empty state and skeletons replace the technical listing.
|
||||
- Details use a native dialog with banner/icon, creator, description, screenshots with keyboard/arrow controls, badges, primary installation action and friendly source choices. Technical identifiers and compatibility facts are collapsed.
|
||||
- Sources use a separate native settings dialog with aligned switches, source initials, descriptions, trust labels and repository form. A failed source produces a quiet human-readable notice.
|
||||
- `_images.py` registers only source-entry artwork, returns opaque handles, permits HTTP(S) raster images only, rejects private/link-local/reserved IPs (including redirected targets), connects to the validated IP with TLS hostname checking, limits images to 8 MiB and bounds its memory cache to 64 MiB / registry to 4096 handles. Browser requests are same-origin `/source-image/<opaque handle>`; arbitrary URLs are never accepted by the HTTP endpoint.
|
||||
- New GET `/api/sources/details?source=&id=` supplies richer details. Search decorates offers with `artwork` and a plain-language `verdict`.
|
||||
- Optional source metadata is documented in search.py: `images: {icon, banner, screenshots}`, developer, description, popularity, open_source, requires_meta_services, frame_tested. Only explicit `frame_tested=True` earns Works on the Frame. Installability alone says Ready to try. No fabricated popularity labels when a source provides no ranking data.
|
||||
- Background jobs accept an optional progress reporter; source installs report Downloading and Installing. The UI displays a percentage only if supplied by a job. Current shared download() interface provides no byte progress, so real sources show truthful indeterminate stages, not fabricated percentages.
|
||||
- Demo listings include real recorded public artwork plus clearly documented illustrative listing metadata. Preview installer alone simulates percentages and completion; it never calls frame_android.install or SSH. Repo toggles in preview use an isolated temporary settings file.
|
||||
|
||||
### Visual review and evidence
|
||||
|
||||
- Iteration 1: inspected browse and detail screenshots; found too much vertical space above the app rows and description. Reduced hero/banner heights and header spacing.
|
||||
- Iteration 2: inspected wide and narrow layouts; moved desktop search beside the heading, placed a full popular row before the short VR row, compacted the disconnected-headset notice for browsing, aligned settings switches, preserved radio focus after detail refresh and improved progress text contrast.
|
||||
- Final visual inspection: 1440x1050 desktop and 390x844 narrow viewport, two narrow columns (172px each), document width 380px inside a 390px viewport (no horizontal overflow).
|
||||
- Final PNGs in `/tmp/apk-search-evidence/v2/`: browse-home.png, search-results.png, app-details.png, install-progress.png, sources-sheet.png, empty-state.png, narrow-window.png. Iteration screenshots retained there too.
|
||||
- Browser checks via T3 preview at http://127.0.0.1:8795/#android: six grouped apps; no package/API/ABI/engine/demo jargon in browse; typing `world` yields three apps after debounce; app details contain three screenshots and two source choices; source selection updates installation target and keeps keyboard focus; disabling itch.io removes its notice and persists for subsequent searches; simulated install displays Downloading 43%, then completion and Open in Steam; empty search renders illustrated recovery; narrow two-column layout has no horizontal overflow.
|
||||
- `FRAME_APK_SEARCH_DEMO=1 python3 tests/search_preview.py` started the local server used above. Real device endpoints rejected.
|
||||
- `python3 -m unittest discover -s tests`: 188 tests passed on Python 3.9.6, exit 0. Final log `/tmp/apk-search-evidence/v2/unittest.log`.
|
||||
- `node --check /tmp/apk-search-evidence/v2/ui.js`: exit 0 (inline script extracted from final index.html).
|
||||
- Python 3.9 grammar parse: seven changed/new Python files passed. `git diff --check`: exit 0.
|
||||
|
||||
### Still unverified / parent integration
|
||||
|
||||
- Real source modules, real repository add/remove writes, real downloads and physical headset launch/install are not tested. No SSH or device installation performed.
|
||||
- Image fetch transport tested with mocks; preview serves recorded images through the actual HTTP image endpoint/cache. Live asset files were fetched separately to create fixtures; live proxy TLS/redirect behavior across provider CDNs remains unverified.
|
||||
- Percentages in install-progress.png are explicitly simulated by the preview harness. Real provider byte-progress integration needs an extension to the shared download interface; stage reporting works now.
|
||||
- Source workers must provide `images` and creator/description metadata for rich listings; fallback gradients/initials work without them. Frame-tested/popularity signals must be backed by source evidence, not inferred from installability.
|
||||
- The earlier packaging (`apk_sources/**/*.py`) and install_obb signature integration notes still apply. No Electron build or cross-provider review run; parent owns integration/review and this brief prohibits delegation.
|
||||
@@ -1,69 +0,0 @@
|
||||
# more-sources
|
||||
|
||||
Scope: only this worktree/branch; no delegation, SSH, installation, push, PR or
|
||||
issue writes. Parent performs integration and independent review per brief.
|
||||
|
||||
Decisions: implement GitHub curated public APK releases and itch.io RSS page
|
||||
links. itch robots exclude keyed download pages used by /tmp/vrapk/itchdl.py;
|
||||
no bypass. Topic results are not automatically trusted. Curated Open Brush and
|
||||
SuperTux prereleases must be explicitly allowed; discovered during fixture tests.
|
||||
No shared files changed. Default GitHub search makes no network request.
|
||||
|
||||
Evidence (2026-09-28):
|
||||
- Read all six prerequisite files and the full brief.
|
||||
- Fetched itch terms, root/author robots and OpenXR RSS with FrameControl UA.
|
||||
- Anonymous GitHub returned 403 rate-limit; authenticated gh API reads succeeded.
|
||||
- GitHub fixtures record upstream Khronos, Open Brush and SuperTux releases.
|
||||
- `python3 .claude/prove-more-sources.py`: GitHub search/download succeeded,
|
||||
published SHA-256 matched; `python3 ui/frame_android.py info` exited 0.
|
||||
Overall script exit 1 because subsequent itch RSS request returned HTTP 429.
|
||||
A second invocation had the same outcome; no further live itch retries.
|
||||
- Download: `.claude/proof-cache/f24bbe8ba6f6339fca658628868ba8189cbc33390d6ac508f69d76fb67b5fa34.apk`.
|
||||
Package org.khronos.openxr.hello_xr.vulkan; 1.1.63/1063; API 24; arm64;
|
||||
OpenXR. No runtime compatibility claim.
|
||||
- Initial whole suite: 174 tests, 1 failed (prerelease handling). After explicit
|
||||
curated prerelease support: 174 tests passed, exit 0. Final rerun below.
|
||||
|
||||
Unverified: live itch search completion (429), itch download/info (disallowed
|
||||
flow), Open Brush/SuperTux downloads, topic live adapter search (API fixture
|
||||
capture succeeded), headset runtime, UI integration, independent provider
|
||||
review (explicit implementation brief prohibits delegation and assigns review
|
||||
to parent). No claim that any reviewer/model participated.
|
||||
|
||||
Research HTML and local downloaded APKs are local evidence only, not committed.
|
||||
Recorded fixtures retain public source data, not credentials. The proof script
|
||||
uses gh's token in memory and overrides cache into this worktree.
|
||||
|
||||
Final verification:
|
||||
- Python version: 3.9.6.
|
||||
- `python3 -m unittest discover -s tests > .claude/tests-more-sources.log 2>&1`:
|
||||
174 tests passed in 5.569s, real exit 0.
|
||||
- `git diff --check`: exit 0.
|
||||
- Final artifact: docs/apk-sources.md plus two source modules, a private HTTPS
|
||||
helper, curated JSON, recorded fixtures and tests. Evidence scripts/logs stay
|
||||
in .claude; research HTML and APK cache are explicitly ignored there.
|
||||
|
||||
## Artwork follow-up
|
||||
|
||||
Added curated icon/images metadata and plain-language summaries. Icons use
|
||||
publisher repository assets pinned to inspected commits. Open Brush's banner
|
||||
is its README image; three screenshots are from its README-linked Steam page.
|
||||
SuperTux's banner/screenshot is the upstream gameplay preview in the port's
|
||||
README, not a Quest capture. hello_xr has its actual Vulkan launcher icon and
|
||||
repository social banner; no real screenshot was found in its repository or
|
||||
README, so screenshots stays empty rather than mislabeling branding.
|
||||
|
||||
Topic search uses owner.avatar_url and the requested GitHub social-preview
|
||||
pattern, retaining curated artwork when a curated app is discovered by topic.
|
||||
Unknown repository details use GitHub's owner.png avatar endpoint and the same
|
||||
social banner without an extra API request. Existing itch cover behavior is
|
||||
unchanged; tests now assert icon/banner equality and empty screenshots because
|
||||
the recorded RSS provides no separate screenshots.
|
||||
|
||||
Validation: all nine distinct curated artwork URLs returned HTTP 200, image
|
||||
Content-Type and image magic. Of six topic artwork URLs, five returned images
|
||||
and LWJGL's social preview returned HTTP 429. Recorded in
|
||||
`tests/fixtures/more_sources/artwork-check.json`; no repeated retry.
|
||||
`python3 -m unittest discover -s tests`: 176 passed in 5.879s, real exit 0.
|
||||
`git diff --check`: exit 0. No UI rendering/headset testing or independent
|
||||
review; parent retains integration/review, and delegation remains prohibited.
|
||||
@@ -1,55 +0,0 @@
|
||||
# SideQuest implementation notes
|
||||
|
||||
2026-09-28. Worktree steam-frame-sidequest, branch sidequest. No delegation,
|
||||
Frame mutations, installs, launches, pushes or issue edits.
|
||||
|
||||
- Read shared source interface, APK/VR docs, catalogue README and Python backend.
|
||||
- SideQuest robots: crawl delay 3; disallow /search/, /user/*, /sideload/*.
|
||||
- Current /terms Angular text (main-4MMXZRXL.js): Prohibited Activities (i)
|
||||
prohibits scraping; (xi) limits access to provided/authorised technologies;
|
||||
(xii) forbids bypass. Public API address is not permission for a third-party
|
||||
integration. Page-only source; no automated store downloads or metadata crawl.
|
||||
- api.sidequestvr.com/robots.txt returned HTTP 403. First shared JS chunk also
|
||||
returned 403. No attempt to bypass either response.
|
||||
- Public SideQuest desktop source cloned inside .claude/research for inspection.
|
||||
/install-from-key takes a website-issued token and returns apps[].urls[] with
|
||||
provider APK/OBB/Github Release/Mod and link_url. Do not reproduce token flow.
|
||||
- Two SSH read-only attempts to frame timed out (exit 255). Exact host-side
|
||||
/sdcard mapping cannot be claimed. internal/<package> is private app data,
|
||||
not evidence of an OBB mapping. Use the running container's /sdcard path for
|
||||
OBB writes, without launching it; backup only documented internal/<package>.
|
||||
- Scope: OBB helper/CLI, private-data backup/restore helper/CLI, compliant
|
||||
SideQuest page-only source. No search UI, artwork installer or install edits.
|
||||
- Cross-provider review not launched: task explicitly forbids delegation;
|
||||
parent brief reserves integration and review for the parent.
|
||||
|
||||
## Implementation and verification
|
||||
|
||||
- Added ui/frame_android_data.py and frame/android/app-data.py; additive wrappers
|
||||
and CLI branches only in frame_android.py (install/_install unchanged).
|
||||
- OBB transfers to an already-running named container, SHA-256 check before
|
||||
per-file rename. No claimed host sdcard mapping or device persistence.
|
||||
- Backup/restore covers private internal/<package> only, requires a stopped
|
||||
instance, uses podman unshare, validates archive paths/types/package/instance,
|
||||
preserves numeric owners/modes, retains the prior data directory on restore.
|
||||
- SideQuest adapter intentionally raises a page-only SourceError on search and
|
||||
download; details gives a numeric listing page with unknown facts, images
|
||||
schema and downloadable=False. Needs aggregate search to surface the error.
|
||||
- docs/sidequest.md contains source links, feature comparison, command examples,
|
||||
terms/robots findings and outstanding device/API questions.
|
||||
- Fixture tests/fixtures/sidequest-policy.json records observed policy excerpts;
|
||||
no API response is fabricated.
|
||||
- `python3 -m unittest discover -s tests`: final run 181 tests, OK (exit 0).
|
||||
Includes real local shell execution of the OBB checksum/publish sequence,
|
||||
rejecting a changed input without replacing the previous file; archive
|
||||
round-trip/retained previous save, 0600 backup, malformed archive rejection.
|
||||
No test contacts the network or Frame.
|
||||
- `ast.parse(..., feature_version=(3,9))`: four implementation files passed.
|
||||
Runtime python3 is Xcode Python 3.9.
|
||||
- `python3 ui/frame_android.py install-obb` and `... backup-data`: both exit 1
|
||||
with the intended required-arguments error, without contacting Frame.
|
||||
- `git diff --check`: passed before commit.
|
||||
- No SideQuest game downloaded and no `info <download>` run: terms blocked that
|
||||
requested E2E. No Frame app was installed or launched; no live OBB, namespace
|
||||
ownership or restore acceptance test. Independent review reserved for parent,
|
||||
per this task's explicit no-delegation instruction.
|
||||
@@ -1,80 +0,0 @@
|
||||
# User repositories
|
||||
|
||||
Scope: ui/apk_sources/fdroid.py, fixture tests and docs/apk-repos.md. No headset access.
|
||||
No delegation or independent reviewer launched: task explicitly forbids delegation;
|
||||
parent integrates and reviews. Existing catalogue API stays unchanged.
|
||||
|
||||
Decisions:
|
||||
- Support F-Droid signed v2 and v1, HTTPS only, RSA PKCS#1 CMS/JAR verification.
|
||||
- Pin operator certificate fingerprints. Without a supplied fingerprint, verify
|
||||
the complete signature chain of hashes on first use, then persist that signer.
|
||||
- Reuse frame_catalog._IndexReader and _reduce_index; keep authenticated source
|
||||
cache separate from legacy unauthenticated catalogue cache to avoid laundering trust.
|
||||
- Sources list compatible builds (Android <=30, arm64 or no native code), as
|
||||
existing catalogue reducer does. This is compatibility filtering, not a runtime guarantee.
|
||||
- No Obtainium export import or new unsigned JSON format in this source.
|
||||
|
||||
Research: downloaded F-Droid API/setup docs, Obtainium and SideQuest READMEs,
|
||||
Izzy repo page and entry.jar via HTTPS. Izzy's published fingerprint matched
|
||||
pure-Python CMS validation: 3BF0D6ABFEAE2F401707B6D966BE743BF0EEE49C2561B9BA39073711F628937A.
|
||||
|
||||
## Final verification
|
||||
|
||||
All commands below ran in /Users/saphid/projects/steam-frame-userrepo on user-repos.
|
||||
|
||||
- `python3 --version`: Python 3.9.6.
|
||||
- `python3 -m unittest discover -s tests -p test_fdroid_sources.py`: initially
|
||||
13 tests, OK, exit 0. Added a cache-corruption test afterward.
|
||||
- Final `python3 -m unittest discover -s tests`: 180 tests in 6.866s, OK,
|
||||
exit 0 (includes 14 source tests and existing catalogue/version tests).
|
||||
- `python3 ui/apk_sources/fdroid.py add 'https://apt.izzysoft.de/fdroid/repo?fingerprint=3BF0D6ABFEAE2F401707B6D966BE743BF0EEE49C2561B9BA39073711F628937A' --name 'IzzyOnDroid verification'`: exit 0;
|
||||
saved fdroid-user-57e98c13877f14fdea65 with the published pin.
|
||||
- `python3 ui/apk_sources/fdroid.py search fdroid-user-57e98c13877f14fdea65 'tinymusicplayer'`:
|
||||
exit 0; com.martinmimigames.tinymusicplayer, version 1.3 / code 4,
|
||||
GPL-3.0-only, 16,520 bytes.
|
||||
- `python3 ui/apk_sources/fdroid.py download fdroid-user-57e98c13877f14fdea65 com.martinmimigames.tinymusicplayer`:
|
||||
exit 0, verified true. Independent hashlib readback matched
|
||||
d7bcb24d101b04beb3394b695b24be4e2c3d6ed702f1d0e06bc4dd707f64d86a.
|
||||
- Direct `_fetch` + `_jar` calls on F-Droid main/archive entry.jar: exit 0;
|
||||
both matched the published 43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab pin.
|
||||
- `.claude/user-repos-proof.json` retains live CLI results and APK readback.
|
||||
Live APK remains in the per-user apk-sources cache; the added source remains
|
||||
in the per-user apk-repos.json, as requested for the real add/search/download run.
|
||||
|
||||
Not verified: headset installation/runtime, native UI/server integration (sibling
|
||||
worker), real v1-only server (offline signed fixture covers fallback), executing
|
||||
the fdroidserver publishing instructions, full F-Droid main/archive index/APK
|
||||
downloads (their live signed entry jars were checked). No independent reviewer
|
||||
was run because this task forbids delegation and assigns review to the parent.
|
||||
|
||||
Known limits / follow-up questions: only one RSA-2048–8192 JAR signer supported;
|
||||
no ECDSA/DSA/PSS or section-only SF signatures; no index timestamp rollback or
|
||||
expiry policy, automated key rotation or cross-process settings-write locking.
|
||||
The settings API serializes threads and publishes atomically. Should a later
|
||||
change add explicit rollback policy and broader JAR algorithms? Parent may
|
||||
choose UI wording for TOFU; this source already returns trust_on_first_use.
|
||||
|
||||
## Artwork follow-up
|
||||
|
||||
Added `images: {icon, banner, screenshots}`, matching top-level `icon`,
|
||||
`developer` from authorName, and HTML/entity-aware one-line summaries. Artwork
|
||||
prefers en-US per field, then the first populated locale. Phone screenshots
|
||||
precede seven-inch screenshots, with at most six unique URLs. v2 supports both
|
||||
`screenshots.phone/sevenInch` and the older phoneScreenshots/sevenInchScreenshots
|
||||
field names. v1 localized filenames are resolved under package/locale, with
|
||||
legacy top-level icons resolved under icons/. Missing art remains null/empty.
|
||||
|
||||
No frame_catalog edit was necessary: this source already rereads raw metadata
|
||||
after using the shared compatibility reducer. Incremented the source cache
|
||||
schema so old entries refresh immediately rather than hiding artwork for a day.
|
||||
Tests exercise v1/v2 metadata, cache round-trips and migration, locale fallback,
|
||||
missing fields, legacy icon paths, screenshot bounds and summary cleanup.
|
||||
|
||||
Follow-up verification (Python 3.9.6, branch user-repos):
|
||||
- `python3 -m unittest discover -s tests -p test_fdroid_sources.py`: 19 tests,
|
||||
0.046s, OK, exit 0.
|
||||
- `python3 -m unittest discover -s tests`: 185 tests, 5.081s, OK, exit 0.
|
||||
- `git diff --check`: exit 0.
|
||||
No live image fetch or redesigned store rendering was exercised; these remain
|
||||
with the parent/UI integration. No independent review or delegation performed,
|
||||
as explicitly requested. No new open implementation questions.
|
||||
@@ -1,126 +0,0 @@
|
||||
# vr-library implementation notes
|
||||
|
||||
Scope: `/tmp/vrapk/p1.md` plus parent updates mandating all-entrypoint artwork,
|
||||
SteamGridDB, designed fallback art, settings/backfill and two visual iterations.
|
||||
Worktree `/Users/saphid/projects/steam-frame-vrlib`, branch `vr-library`.
|
||||
No delegation, push, PR or issue edits. Parent owns independent review and integration.
|
||||
|
||||
## Implementation
|
||||
|
||||
- Initial commit `c06b328`: shared artwork, collection handling, launcher
|
||||
supervision, APK icon fallback and tests. Follow-up replaces its bitmap
|
||||
artwork implementation with Steam Chromium canvas + Motiva Sans.
|
||||
- `ui/frame_steamgriddb.py`: optional API provider, exact title (or trailing VR)
|
||||
match, highest-scored returned static/non-NSFW artwork, separate portrait
|
||||
and wide requests. No key means no requests/warnings. Saved settings are
|
||||
atomic 0600 on POSIX; API never returns the key; auth redirects disabled.
|
||||
- Precedence: provider, source slots/banner/feature graphic/screenshots, APK
|
||||
icon/generated art. All five outputs have fixed Steam sizes. Host Python
|
||||
stays stdlib-only and Python 3.9 compatible; Frame renders consistently
|
||||
regardless of host OS. Package filters include both new JS resources.
|
||||
- `frame/android/library_artwork.js`: dominant-colour gradient, blurred icon
|
||||
backdrop, large icon/shadow, real font, no title in hero, transparent logo.
|
||||
Removes only opaque near-black matte connected to icon corners. Native
|
||||
icons remain original; opaque foreground app tiles have rounded corners.
|
||||
- `apply_library` is mandatory for APK and native-title installs. CLI, upload,
|
||||
catalogue, versions, web install and source install seam share it. Native
|
||||
devkit executable/runtime is preserved. Failed initial art application
|
||||
removes a newly created shortcut; no success with incomplete art.
|
||||
- Refresh CLI/API/settings button repairs installed Android entries without
|
||||
reinstalling/stopping, uses cached source art, queries SGDB again if enabled,
|
||||
repairs missing shortcuts, and reports batch errors independently.
|
||||
- Details: name/icon/VR flag, sort-as, Android/Android VR collections or native
|
||||
Sideloaded, Installation details note preserving other notes. No supported
|
||||
arbitrary description/store-page/developer/achievement metadata found.
|
||||
Notes are keyed by sanitized name (Steam limitation: equal-name collisions).
|
||||
- Device discovery: custom-art type 4 is broken on this Steam client: it logs
|
||||
Unknown asset type and overwrites wide art with the icon. Use types 0–3 and
|
||||
SetShortcutIcon separately. Confirmed actual cache after correction.
|
||||
- Launcher retains its supervising shell under Steam, traps TERM/INT/HUP,
|
||||
stops only its own container, kills its child group, preserves exit status.
|
||||
Lock/pre-existing container guards prevent duplicate session cleanup.
|
||||
- VR attribution discovery: Lepton uses SteamAppId for both stable context and
|
||||
Android SteamVR identity. New shortcut.id + LEPTON_ENV_SteamAppId separates
|
||||
them using Lepton's existing passthrough; container/data paths unchanged.
|
||||
On-device source mounting.sh applies LEPTON_ENV_* after its regular setenv.
|
||||
|
||||
## Visual critique and iterations
|
||||
|
||||
Evidence `/tmp/vrlib-evidence/design-v1`, `design-v2`, `design-v3` (15 PNGs each).
|
||||
Open Saber Plus/SuperTux icons came from authorized APKs. AntennaPod is a
|
||||
preview only using the official F-Droid icon; it was not installed/launched.
|
||||
|
||||
1. v1: real typography/gradient already improves over old bitmap output, but
|
||||
Open Saber has a black square matte, and SuperTux palette looks muddy.
|
||||
2. v2: removed connected black matte; rounded the opaque AntennaPod foreground.
|
||||
Inspected all three posters. SuperTux still muted; title line balance weak.
|
||||
3. v3: lifted sampled saturation and balanced two-line labels. Inspected all
|
||||
three posters plus final all-slot sheet. Large recognisable artwork, readable
|
||||
typography, richer colours, textless hero and transparent title logo. Icon
|
||||
source resolution still limits detail; source/SGDB art remains preferable.
|
||||
|
||||
Final sheet `/tmp/vrlib-evidence/artwork-preview-final.png` is an artwork
|
||||
preview, NOT a Steam UI screenshot. Rows: portrait, wide, hero, logo/icon.
|
||||
|
||||
## Device verification (2026-09-28, build 20260925.6191901, SteamVR 2.18.1)
|
||||
|
||||
Steam was initially unavailable (old notes/evidence), then recovered. Both
|
||||
APKs were reinstalled and refreshed successfully with zero library warnings:
|
||||
|
||||
- Open Saber Plus: org.godotengine.open_saber_plus, instance 2802929330,
|
||||
shortcut 3346865537, game ID 14374678025558032384.
|
||||
- SuperTux: org.supertux.supertux2, instance 2811892472,
|
||||
shortcut 2883168793, game ID 12383115674816348160.
|
||||
|
||||
`steam-cache-final.log`: both actual Steam cache sets are 600x900, 920x430,
|
||||
3840x1240, 1280x480, with app icon 256x256. `steam-details-targets.json`:
|
||||
both correct names/sort-as, Android + Android VR, existing Played preserved.
|
||||
Native managed note readback result 1 (success), saved as steam-notes-final.json.
|
||||
|
||||
Open Saber first session: Steam tracked it for 32 seconds; process and
|
||||
container remained alive until only SteamClient TerminateApp was called.
|
||||
After identity fix, a second session remained alive at 22 seconds (Android
|
||||
PID 992), SteamVR identified steam.app.3346865537, and screenshot shows the
|
||||
actual game scene instead of blank Resume tile. Steam Stop removed tracked
|
||||
process and container within ~5 seconds. No direct podman-stop fallback was
|
||||
used for this verification. Same data paths; existing game play count shown
|
||||
in capture, but no separate save-file sentinel added to the real game.
|
||||
Evidence: opensaber-identity-session.log, opensaber-identity-headset.png,
|
||||
opensaber-running.log, opensaber-steam-stop.log, opensaber-headset-running.png.
|
||||
|
||||
SuperTux: Steam Play tracked the wrapper for ~17 seconds. SDLClipboardHandler
|
||||
crashes with NullPointerException on missing ClipboardManager during activity
|
||||
creation. Lepton and supervisor then cleaned up; it never reached a VR scene.
|
||||
Steam Stop was issued after the crash, so sustained SuperTux Stop is NOT proven.
|
||||
Evidence: supertux-running.log, supertux-lepton.log, supertux-shot.json.
|
||||
|
||||
Other test activity appeared on the device during checks (other Android
|
||||
container and Gravitas). Neither was stopped or modified. Final Open Saber
|
||||
preflight had no Android containers; other desktop overlays later appeared
|
||||
in its headset capture. No global VR standby/dashboard settings changed.
|
||||
Direct Steam UI Page.captureScreenshot timed out; no library UI screenshot.
|
||||
|
||||
## Automated verification and limits
|
||||
|
||||
- Whole suite: `python3 -m unittest discover -s tests`, Python 3.9.6. Final
|
||||
result: **206 tests OK, 10.294 seconds, exit 0**. Log:
|
||||
`/tmp/vrlib-evidence/tests-final.log`.
|
||||
- Offline entrypoint tests exercise real shared install/render/configure flow
|
||||
with SSH/API mocked: CLI, upload, catalogue, versions, web download, source
|
||||
seam, native title and refresh. Provider ranking/failure/settings tests.
|
||||
- Node contract test runs actual renderer against explicitly synthetic canvas,
|
||||
validates all PNG dimensions and hero/logo text placement. This canvas is
|
||||
also used by fakeframe; transparent fixture images are not visual evidence.
|
||||
- Launcher tests assert stable context plus shortcut passthrough, signals,
|
||||
normal exit, duplicate guard and saved-data sentinel. Earlier real Linux
|
||||
setsid/flock fixture run: 3 tests OK (linux-launcher-tests.log).
|
||||
- `bash -n`, Node syntax checks, Python AST feature_version=(3,9), diff checks.
|
||||
- Docker E2E not run: `docker info --format '{{.ServerVersion}}'` exits 1;
|
||||
daemon socket /var/run/docker.sock does not exist.
|
||||
- Authenticated SGDB lookup/download unverified (no key configured).
|
||||
- Windows/Linux packaged binaries not built/launched; filters tested.
|
||||
- Native devkit art uses shared tested seam; no additional native title was
|
||||
installed on device. Sibling source-search endpoint not in this worktree:
|
||||
only its public installer contract is tested.
|
||||
- Independent review not spawned: explicit brief forbids delegation and assigns
|
||||
parent review/integration. No other provider/model participation claimed.
|
||||
@@ -1,36 +0,0 @@
|
||||
org.khronos.openxr.hello_xr.vulkan · 1.1.63 (code 1063)
|
||||
Minimum: Android 7.0 (API 24)
|
||||
ABIs: arm64-v8a, armeabi-v7a, x86, x86_64
|
||||
Lepton can install this APK. Features may still need services Lepton lacks.
|
||||
VR app
|
||||
Uses OpenXR (good).
|
||||
GitHub search: [{"source": "github", "id": "KhronosGroup/OpenXR-SDK-Source", "package": null, "name": "hello_xr", "summary": "Khronos OpenXR sample (Vulkan and OpenGL ES)", "icon": null, "images": {"icon": null, "banner": null, "screenshots": []}, "page": "https://github.com/KhronosGroup/OpenXR-SDK-Source", "version": null, "version_code": null, "min_sdk": null, "abis": null, "vr": true, "size": null, "free": true, "license": "Apache-2.0", "updated": null, "downloadable": true}]
|
||||
GitHub download: {"apk": "/Users/saphid/projects/steam-frame-moresrc/.claude/proof-cache/f24bbe8ba6f6339fca658628868ba8189cbc33390d6ac508f69d76fb67b5fa34.apk", "obb": [], "sha256": "f24bbe8ba6f6339fca658628868ba8189cbc33390d6ac508f69d76fb67b5fa34", "verified": true}
|
||||
info exit: 0
|
||||
Traceback (most recent call last):
|
||||
File "/Users/saphid/projects/steam-frame-moresrc/ui/apk_sources/_web.py", line 47, in read
|
||||
with open_url(url, hosts, headers) as r:
|
||||
File "/Users/saphid/projects/steam-frame-moresrc/ui/apk_sources/_web.py", line 37, in open_url
|
||||
return urllib.request.build_opener(Redirect(hosts)).open(
|
||||
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/urllib/request.py", line 523, in open
|
||||
response = meth(req, response)
|
||||
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/urllib/request.py", line 632, in http_response
|
||||
response = self.parent.error(
|
||||
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/urllib/request.py", line 561, in error
|
||||
return self._call_chain(*args)
|
||||
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/urllib/request.py", line 494, in _call_chain
|
||||
result = func(*args)
|
||||
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/urllib/request.py", line 641, in http_error_default
|
||||
raise HTTPError(req.full_url, code, msg, hdrs, fp)
|
||||
urllib.error.HTTPError: HTTP Error 429: Too Many Requests
|
||||
|
||||
The above exception was the direct cause of the following exception:
|
||||
|
||||
Traceback (most recent call last):
|
||||
File "/Users/saphid/projects/steam-frame-moresrc/.claude/prove-more-sources.py", line 18, in <module>
|
||||
entries = itch.search(itch.sources()[0], 'off nominal')
|
||||
File "/Users/saphid/projects/steam-frame-moresrc/ui/apk_sources/itch.py", line 58, in search
|
||||
for entry in _parse(source, _web.read(url, ('itch.io',))):
|
||||
File "/Users/saphid/projects/steam-frame-moresrc/ui/apk_sources/_web.py", line 62, in read
|
||||
raise SourceError('Source refused access or reached its rate limit; try later (GitHub accepts FRAME_GITHUB_TOKEN)') from e
|
||||
apk_sources.SourceError: Source refused access or reached its rate limit; try later (GitHub accepts FRAME_GITHUB_TOKEN)
|
||||
@@ -1,24 +0,0 @@
|
||||
import json, os, subprocess, sys
|
||||
from pathlib import Path
|
||||
sys.path.insert(0, str(Path.cwd() / 'ui'))
|
||||
from apk_sources import github, itch, _web
|
||||
proof = Path.cwd() / '.claude' / 'proof-cache'
|
||||
proof.mkdir(exist_ok=True)
|
||||
_web.cache = lambda: str(proof)
|
||||
token = subprocess.run(['gh', 'auth', 'token'], capture_output=True, text=True, check=True).stdout.strip()
|
||||
os.environ['FRAME_GITHUB_TOKEN'] = token
|
||||
s = github.sources()[0]
|
||||
entries = github.search(s, 'hello')
|
||||
print('GitHub search:', json.dumps(entries))
|
||||
r = github.download(s, entries[0]['id'])
|
||||
print('GitHub download:', json.dumps(r))
|
||||
p = subprocess.run(['python3', 'ui/frame_android.py', 'info', r['apk']])
|
||||
print('info exit:', p.returncode)
|
||||
assert p.returncode == 0
|
||||
entries = itch.search(itch.sources()[0], 'off nominal')
|
||||
print('itch.io search:', json.dumps(entries))
|
||||
assert entries and entries[0]['downloadable'] is False
|
||||
try:
|
||||
itch.download(itch.sources()[0], entries[0]['id'])
|
||||
except Exception as e:
|
||||
print('itch.io download correctly refused:', e)
|
||||
@@ -1,5 +0,0 @@
|
||||
................................................................................................................................................................................
|
||||
----------------------------------------------------------------------
|
||||
Ran 176 tests in 5.879s
|
||||
|
||||
OK
|
||||
@@ -1,50 +0,0 @@
|
||||
{
|
||||
"add": {
|
||||
"id": "fdroid-user-57e98c13877f14fdea65",
|
||||
"kind": "fdroid",
|
||||
"name": "IzzyOnDroid verification",
|
||||
"url": "https://apt.izzysoft.de/fdroid/repo/",
|
||||
"builtin": false,
|
||||
"enabled": true,
|
||||
"trust": "user",
|
||||
"fingerprint": "3bf0d6abfeae2f401707b6d966be743bf0eee49c2561b9ba39073711f628937a",
|
||||
"trust_on_first_use": false
|
||||
},
|
||||
"search": [
|
||||
{
|
||||
"source": "fdroid-user-57e98c13877f14fdea65",
|
||||
"id": "com.martinmimigames.tinymusicplayer",
|
||||
"package": "com.martinmimigames.tinymusicplayer",
|
||||
"name": "Tiny Music Player",
|
||||
"summary": "Android 1.0+ minimal (",
|
||||
"icon": "https://apt.izzysoft.de/fdroid/repo/com.martinmimigames.tinymusicplayer/en-US/icon.png",
|
||||
"page": "https://martinmimigames.github.io/projects/tiny-music-player/index.html",
|
||||
"vr": null,
|
||||
"free": true,
|
||||
"license": "GPL-3.0-only",
|
||||
"downloadable": true,
|
||||
"version": "1.3",
|
||||
"version_code": 4,
|
||||
"min_sdk": 1,
|
||||
"abis": [],
|
||||
"size": 16520,
|
||||
"updated": "2023-02-04"
|
||||
}
|
||||
],
|
||||
"download": {
|
||||
"apk": "/Users/saphid/Library/Caches/Frame Control/apk-sources/d7bcb24d101b04beb3394b695b24be4e2c3d6ed702f1d0e06bc4dd707f64d86a.apk",
|
||||
"obb": [],
|
||||
"sha256": "d7bcb24d101b04beb3394b695b24be4e2c3d6ed702f1d0e06bc4dd707f64d86a",
|
||||
"verified": true
|
||||
},
|
||||
"independent_readback": {
|
||||
"size": 16520,
|
||||
"sha256": "d7bcb24d101b04beb3394b695b24be4e2c3d6ed702f1d0e06bc4dd707f64d86a"
|
||||
},
|
||||
"python": "3.9.6",
|
||||
"suite": "python3 -m unittest discover -s tests: 180 tests, 6.866s, OK, exit 0",
|
||||
"builtins_entry_signatures": {
|
||||
"fdroid": "43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab",
|
||||
"fdroid-archive": "43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab"
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user