Skip to content

App Store shippability: release-readiness prereqs, pre-ship audits, CI, and submission mechanics #92

Open

Description

@jlipworth

Goal and scope

Track App Store readiness for Labstream's coordinated four-platform set: visionOS, universal iOS/iPadOS, tvOS, and macOS. Canonical status and detailed acceptance checks: docs/RELEASES.md.

Current source versus distribution

  • Source: 1.7.1 (build 1) across all four apps and matching PMSKit fallback.
  • Current merged main includes P7 initialization hardening (Harden experimental P7 fallback initialization identity #320) and GPL logo cleanup (docs: use GPLv3 logo without tagline #321). The P7 HDR10-base candidate remains default-off, DEBUG macOS only, not native P7 Dolby Vision support or Release enablement.
  • Latest repository-recorded processed distribution: 1.6.1 (build 2) for all four platform archives, from abd1ddcac351. This is not a fresh App Store Connect query.
  • Distribution identity: org.labstream.Labstream, one universal-purchase record with four platform versions; iPhone and iPad share the iOS archive. The old personal-namespace visionOS record is historical, not the current publication identity.
  • No current 1.7.1 archive, upload, hardware acceptance, or submission is established by this update. Check live App Store Connect state before choosing build numbers or uploading.

Completed foundations (bounded evidence)

  • Public source, support/privacy documentation, licensing and required disclosures exist.
  • Prior four-platform 1.6.1 build-2 archive processing is recorded; this does not certify the current source.
  • Latest merged P7 hardening and logo PR checks passed; physical and broader codec acceptance remain separate.
  • Dedicated reviewer Jellyfin infrastructure in App Review: provision an isolated dedicated Jellyfin demo environment #280 has validated public-path TLS, authentication, catalog/artwork, range playback, reset and external reachability. Physical TestFlight journey remains open.

Next work, in order

1. Release codec confidence

2. Exact release candidate and TestFlight

  • Verify current App Store Connect versions/build numbers and supported archive toolchain; do not infer account state from repository records.
  • Freeze the public release commit after accepted fixes and run the required hermetic/native/hygiene checks.
  • Produce clean signed Release archives for all four platforms; verify identity, versions, entitlements, architectures, minimum OS and device families.
  • Validate/upload the authorized candidate and verify processing/build selection for every submitted platform. Rebuild if the release source changes.
  • Physical Vision Pro TestFlight journey: sign-in, browse/playback, seek, subtitles/audio, Cinema, lifecycle and diagnostics.
  • Physical iPhone and iPad TestFlight journeys: navigation, playback, downloads, lifecycle and accessibility.
  • Physical Apple TV TestFlight journey: remote/focus, playback, long play, HDR/audio routing and lifecycle (no downloads).
  • Mac TestFlight journey: sandboxed sign-in/local-network access, playback, windows, keyboard/media controls, downloads and accessibility.
  • Deferred by user decision: Cold launch without connectivity blocks completed offline downloads #259 (disconnected cold-launch/local-download acceptance). Keep it open and do not count deferral as a pass; it is outside the current active pre-release work queue.

3. Screenshots and reviewer journey

4. Account and submission gates

  • Recheck current agreements, trader declaration/verification, pricing, territories and release method with the Account Holder.
  • Complete product-page metadata, privacy/export answers and accessibility review against the actual candidate. Resolve Release privacy: reconcile project-operated review demo and collection disclosures #325 (review/demo-service privacy disclosure) and Privacy manifest: declare production systemUptime API use #326 (missing SystemBootTime required-reason declaration); the previously recorded Data Not Collected answer is not newly certified.
  • Verify the exact corresponding GPL source and release notes are public; create release tags only when authorized.
  • Obtain explicit final storefront/submission approval; submit only accepted platform versions.

Acceptance and reporting

This issue remains open until the chosen platform submission scope is accepted and submitted, or an explicit go/no-go is recorded. A clean repository, closed implementation issue, green CI or uploaded build alone is not App Store readiness. Preserve historical comments as point-in-time evidence; the old source/distribution topology in the original body is superseded by this reconciliation. No archive upload or App Store submission is claimed by this checklist update.

Activity

  1. jlipworth commented on Jun 24, 2026

    @jlipworth
    OwnerAuthor

    App Review server-access: use the public Jellyfin demo (verified — no infra to build)

    Follow-up to the reviewer-access research above. Decision: point App Review at the public Jellyfin demo server rather than standing up our own. This eliminates the entire build-a-demo-server task (domain purchase, DNS zones, Traefik routing, a Jellyfin pod, sourcing safe content, securing the deployment) — none of it is needed.

    Why the public demo works

    • Live and vanilla-reachable. https://demo.jellyfin.org/stable returns HTTP 200 over HTTPS with a publicly-trusted cert (TLS verify = 0), Jellyfin Stable Demo v10.11.11. That's exactly the "HTTPS / port 443 / fixed real DNS / system-trusted cert" setup Apple DTS requires — it sidesteps the DDNS/self-signed/non-443 trap that got a self-hosted app rejected 10+ times (see prior comment).
    • Credentials are trivial for a reviewer: username demo, empty password. Server resets at the top of each hour, so any reviewer change reverts.
    • Content is copyright-clean — Blender open movies (Caminandes, etc.) and public-domain films. Curated by the Jellyfin project, so media licensing isn't our exposure.

    Verified against VisionPlay's actual request shapes (PMSKit)

    Replicated the app's exact Jellyfin flow (JellyfinAuth.authenticateByNameRequest → views → items → PlaybackInfo → stream) against the demo:

    • Auth: demo + "Pw":"" → AccessToken issued. (The auth path sends an empty Pw with no guard, so blank-password login goes through at the network layer.)
    • Libraries: 4 views returned (Shows, Movies, Music, Playlists).
    • Browse: movie listing returns items.
    • Playback: PlaybackInfo returns a media source (h264/mp4); the stream URL serves real bytes — HTTP 206, video/mp4.

    So core functionality (sign in → browse → play) is fully exercisable by a reviewer with no server of ours.

    One open item

    • Confirm the login screen accepts a blank password field (UI-level; the networking layer that carries "Pw":"" is already verified). A single manual tap-through covers this.

    Risk + fallback

    The demo is third-party and resets hourly. It's been stable for years, but if it's ever down mid-review we get a 2.1 bounce. Fallback: a throwaway Jellyfin pod behind our existing Traefik (which already issues Let's Encrypt certs on 443, so the "vanilla network" requirement is met for free) — kept as a documented backup, not built unless needed.

    Multi-backend note

    We do not need separate Plex/Emby/Jellyfin demo servers. Guideline 2.1 requires the reviewer to exercise the app's core functionality end-to-end; one working backend path does that. Plex/Emby live integrations don't each need their own reviewer-reachable server for the first submission.

    Draft App Review Notes (for App Store Connect)

    VisionPlay is an unofficial third-party client for self-hosted Plex, Jellyfin, and Emby media servers; it has no backend of its own and connects to a server the user provides. It is not affiliated with or endorsed by Plex, Jellyfin, or Emby.

    To review without your own server, use the public Jellyfin demo:

    1. Launch VisionPlay and choose Jellyfin.
    2. Server address: https://demo.jellyfin.org/stable
    3. Username: demo · Password: (leave blank)
    4. Sign in, then browse Movies and play any title (e.g. "Caminandes: Llama Drama") to verify streaming/playback.

    Note: this public demo server resets at the top of every hour, so any settings change reverts automatically.

    Sources: https://demo.jellyfin.org/stable/users/public; Apple Developer Forums reviewer-cannot-connect-to-server (DDNS).

  2. jlipworth commented on Jun 24, 2026

    @jlipworth
    OwnerAuthor

    Trademark / branding sign-off (third-party client) — verdict: compliant, one action item

    Reviewed both halves: (A) what each rights-holder's terms permit for a third-party client, and (B) an audit of what VisionPlay actually ships. Net: the app is already trademark-clean. The only required change is adding a "not affiliated" disclaimer (in-app + App Store description). No rename, no icon change, no logo removal needed.

    A. What each service permits

    • Plex — Nominative/descriptive use only: you may say the app works with Plex, but may not use Plex logos or look-and-feel (their gold-on-black palette, typography) without prior written approval, and may not imply endorsement. VisionPlay does none of the prohibited things. ✅
    • Jellyfin — Don't use "Jellyfin" in the app name (and avoid "Jelly[word]"/"[word]fin"), don't use their logo as the icon; "a Jellyfin client" in the description and the color gradient on an original logo are allowed. App name is "VisionPlay", icon is original. ✅
    • Emby (the strict, proprietary one) — Emby staff have explicitly approved this exact pattern. In their dev forum, for a third-party app using the public Emby REST API against user-hosted servers, referencing "Emby" descriptively in the store listing, with no Emby logo and a not-affiliated disclaimer, the Emby Team responded: "Yes, as you've laid it out there, that all sounds okay." They approved a disclaimer of the form: "[App] is an independent third-party app and is not affiliated with, endorsed by, or officially supported by Emby Media." VisionPlay matches this pattern. ✅

    B. Audit of what VisionPlay ships

    • App icon / logo: original art — tri-color (blue/amber/red) angled bars + "VisionPlay" wordmark. Resembles none of the three marks (not Plex's gold chevron, not Jellyfin's purple-gradient triangle, not Emby's emblem) and borrows none of their palettes. ✅
    • No service logos bundled anywhere in Assets.xcassets (only AppIcon, VisionPlayGlyph, VisionPlayLogo). ✅
    • Login / backend selection uses SF Symbols + text labels ("Sign in with Plex", "Sign in with Jellyfin", "Sign in with Emby Connect") — no brand logos. ✅
    • Brand-name usage in UI strings is uniformly descriptive/nominative ("your Plex library", "No Plex servers discovered", "Sign in to a different Jellyfin server", "plex.tv/link"). Nothing implies affiliation or endorsement. ✅
    • Minor note (non-issue): the app's accent color is its own DS.Brand.amber, used as a global accent — it is not Plex's brand palette applied to Plex branding, so it isn't "copying look-and-feel."

    Required action — add a not-affiliated disclaimer

    Single combined wording covering all three (mirrors the Emby-approved phrasing):

    VisionPlay is an unofficial, independent third-party app. It is not affiliated with, endorsed by, sponsored by, or officially supported by Plex, Inc., the Jellyfin project, or Emby Media. "Plex", "Jellyfin", and "Emby" are trademarks of their respective owners and are used here only to indicate compatibility.

    Placement:

    1. In-app — Settings / About screen (a static legal line).
    2. App Store description — include the same sentence in the metadata.

    Standing rules to not regress

    • Keep using brand names descriptively only; never imply endorsement.
    • No Plex/Jellyfin/Emby logos in the app, the icon, App Store screenshots, or marketing — keep using text labels / SF Symbols.
    • If we ever want more than nominative use (e.g. a service logo on a picker), get prior written permission from that service first (Plex and Emby both require it).

    Status

    • Naming: compliant (Rename app/project from VisionPlex to VisionPlay #52 rename). ✅
    • Icon / logos / nominative usage: audited, compliant. ✅
    • Per-service terms: reviewed; Emby (the strict one) has an explicit staff-approved precedent for this pattern. ✅
    • Open: add the disclaimer in-app (small code change to the About/Settings view) + in App Store description. Then this prereq is closed.

    Sources: Plex Trademarks & Guidelines; Jellyfin Branding Guidelines; Emby 3rd-party REST API + branding thread (staff approval).

  3. jlipworth commented on Jun 30, 2026

    @jlipworth
    OwnerAuthor

    App Store signing update — Developer Program active

    Apple Developer Program membership is now active and the App Store distribution-signing path is unblocked.

    Verified locally, with sensitive/account-specific identifiers omitted here:

    • An Apple Distribution certificate now exists and is visible to command-line signing.
    • Project signing remains CODE_SIGN_STYLE = Automatic.
    • Local Signing.local.xcconfig is present in both the main worktree and downloads-refactor worktree with the paid developer team configured. The file is gitignored and not tracked.
    • com.jlipworth.VisionPlay can now be exported with App Store distribution signing.
    • Xcode/App Store Connect created the Store provisioning profile during export.

    Successful export proof:

    • Produced a distribution-signed VisionPlay.ipa.
    • Verified signature shape:
      • Identifier=com.jlipworth.VisionPlay
      • Authority=Apple Distribution: <redacted>
      • TeamIdentifier=<redacted>

    Remaining next steps:

    1. Create the App Store Connect app record for com.jlipworth.VisionPlay.
    2. Upload the first build / TestFlight candidate.
    3. Fill metadata, privacy/support URLs, screenshots, review notes, and App Privacy answers.
    4. Increment CURRENT_PROJECT_VERSION for every subsequent TestFlight/App Store upload.

    Current repo version at the time of this check: MARKETING_VERSION = 1.3.5, CURRENT_PROJECT_VERSION = 1.

  4. jlipworth commented on Jul 5, 2026

    @jlipworth
    OwnerAuthor

    App Store rollout checkpoint — paused for rename

    Stopping the App Store Connect rollout here because the public app name needs to change before the first ASC app record/build upload.

    Verified today

    • App Store Connect API key auth works locally.
    • No ASC app records currently exist for this account (/v1/apps returned empty).
    • The registered Bundle ID exists in the Developer/ASC API:
      • com.jlipworth.VisionPlay
      • bundle resource id SKQWLRL5Z3
      • platform reported as UNIVERSAL
    • Local project still has:
      • PRODUCT_BUNDLE_IDENTIFIER = com.jlipworth.VisionPlay
      • MARKETING_VERSION = 1.3.5
      • CURRENT_PROJECT_VERSION = 1
    • Local ASC API key was installed outside the repo under ~/.private_keys/ with 0600 perms; no key material was printed or committed.

    Important App Store Connect constraints confirmed from Apple docs

    • SKU is permanent once the app is added to the account; choose a neutral SKU, not a throwaway/old-name SKU.
    • Bundle ID cannot be changed after uploading a build. It may be editable before a build upload, but do not rely on that for the rollout path.
    • The public app name is editable/metadata, but name availability is checked when creating the app record.

    Recommended next path after rename

    1. Decide the final public app name and whether the bundle id should remain com.jlipworth.VisionPlay or be changed before ASC creation.
      • Keeping the old bundle id is technically fine if only the public name changes; bundle id is not customer-facing.
      • If the bundle id should also be renamed, do it before creating/uploading the ASC build.
    2. Create the ASC app record manually in App Store Connect UI (Apps → + → New App), because public ASC API access did not expose initial app-record creation.
    3. Use a neutral permanent SKU, e.g. vp-visionos-2026 or another non-name-specific identifier.
    4. Do not upload any build until the app record name/bundle id are final enough to keep.
    5. After the ASC app record exists, re-check it via the API key, then continue with archive/validate/upload/TestFlight.

    Remaining non-code setup still expected

    • Publish/enable the docs site so the privacy/support URLs return 200 instead of 404:
      • https://jlipworth.github.io/VisionPlay/privacy/
      • https://jlipworth.github.io/VisionPlay/support/
    • Then fill ASC metadata, App Privacy (Data Not Collected), support/privacy URLs, and App Review notes using the public Jellyfin demo path.
  5. jlipworth commented on Jul 5, 2026

    @jlipworth
    OwnerAuthor

    Version bump checkpoint — first TestFlight train now 1.4.0 (1)

    Bumped the App Store/TestFlight candidate from 1.3.5 to 1.4.0 after the Labstream rename.

    Changed and pushed:

    • MARKETING_VERSION = 1.4.0 in both Debug/Release project settings
    • CURRENT_PROJECT_VERSION = 1 left unchanged because this is a new marketing version and no successful upload for 1.4.0 exists yet
    • PMSKit.version = "1.4.0"
    • Sanity test pin updated to 1.4.0

    Verification:

    • cd PMSKit && swift test passed: 1192 tests
    • Simulator smoke passed via scripts/agent-sim-run.sh launch-home-passive
    • Built Debug-xrsimulator bundle verified:
      • CFBundleShortVersionString = 1.4.0
      • CFBundleVersion = 1
      • CFBundleIdentifier = com.jlipworth.Labstream

    Git:

    • Commit: 6b8b98d (Bump app version to 1.4.0)
    • Tag: v1.4.0 pushed

    Next upload should be a fresh archive/export from this commit/tag. Ignore any prior 1.3.5 (1) awaiting-upload placeholder created by the earlier export probe; it was not uploaded and the active candidate is now 1.4.0 (1).

  6. jlipworth commented on Jul 5, 2026

    @jlipworth
    OwnerAuthor

    Resume checklist for next session — ASC metadata, demo screenshots, first TestFlight upload

    Pausing here to resume on 2026-07-07. Current candidate is Labstream 1.4.0 (1) on main, tag v1.4.0, bundle id com.jlipworth.Labstream.

    1. App Store Connect app/version setup

    • Confirm App Information:
      • Name: Labstream
      • Bundle ID: com.jlipworth.Labstream
      • SKU: permanent/neutral value already chosen in ASC
    • Create/select version page: 1.4.0 for visionOS.
    • Ignore the earlier 1.3.5 (1) awaiting-upload placeholder from export probing; it was not uploaded. The active train is 1.4.0 (1).

    2. URLs before metadata submission

    Need public 200s before final ASC metadata/review submission:

    • Privacy Policy URL: https://jlipworth.github.io/Labstream/privacy/
    • Support URL: https://jlipworth.github.io/Labstream/support/

    If they still 404, publish/enable the MkDocs/GitHub Pages site first.

    3. Demo screenshots / App Store images needed

    Need App Store-safe screenshots/images using non-private demo content. Use the public Jellyfin demo where possible:

    • Server/login flow with https://demo.jellyfin.org/stable
    • Home/browse grid showing public demo media
    • Movie detail page for a public-domain / Blender demo title
    • Playback/player controls
    • Cinema/immersive mode if it can be captured cleanly
    • Offline downloads screen only if it does not imply private media; use demo/sample titles or skip
    • Settings/About page if useful to show privacy/no-tracking/disclaimer

    Screenshot hygiene:

    • No personal Plex/Jellyfin/Emby server names, IPs, usernames, real media titles, library names, tokens, device IDs, or home-network details.
    • No Plex/Jellyfin/Emby logos in screenshots except descriptive text labels already present in the UI.
    • Prefer public Jellyfin demo content, reset hourly, username demo, blank password.
    • Verify exact required visionOS screenshot sizes/counts in ASC UI during upload; do not rely on stale guessed dimensions.

    4. App Review Notes draft to paste

    Use this reviewer path unless it needs tweaks in ASC:

    Labstream is an unofficial third-party client for self-hosted Plex, Jellyfin, and Emby media servers; it has no backend of its own and connects to a server the user provides. It is not affiliated with or endorsed by Plex, Jellyfin, or Emby.

    To review without your own server, use the public Jellyfin demo:

    1. Launch Labstream and choose Jellyfin.
    2. Server address: https://demo.jellyfin.org/stable
    3. Username: demo · Password: leave blank
    4. Sign in, browse Movies, and play any title to verify streaming/playback.

    Note: this public demo server resets at the top of every hour, so any settings change reverts automatically.

    5. Metadata still to paste/finalize

    • Subtitle, keywords, promotional text, description from earlier App Store shippability: release-readiness prereqs, pre-ship audits, CI, and submission mechanics #92 draft, updated from VisionPlay → Labstream.
    • Add not-affiliated disclaimer to public description:
      • Labstream is an unofficial, independent third-party app. It is not affiliated with, endorsed by, sponsored by, or officially supported by Plex, Inc., the Jellyfin project, or Emby Media. “Plex”, “Jellyfin”, and “Emby” are trademarks of their respective owners and are used only to indicate compatibility.
    • App Privacy: expected Data Not Collected, matching the privacy manifest.
    • Age rating/category/support contact fields.

    6. Build/upload path

    Before upload, create a fresh archive/export from commit 6b8b98d / tag v1.4.0:

    • Version: 1.4.0
    • Build: 1
    • Bundle: com.jlipworth.Labstream

    Known Xcode export quirk from today:

    • app-store-connect export with symbols enabled hit a local rsync packaging failure.
    • Export with uploadSymbols=false produced a distribution-signed IPA successfully.
    • If symbols are required, try Xcode Organizer or separate symbol upload; otherwise proceed with the verified no-symbol export path for first TestFlight.

    7. After upload

    • Wait for ASC processing.
    • Add the build to internal TestFlight.
    • Install TestFlight build on the Vision Pro and do a quick smoke: launch, Jellyfin demo login, browse, play.
    • For any second upload under version 1.4.0, increment CURRENT_PROJECT_VERSION to 2 first.
  7. added
    priority:p1High priority; release/publication blocker or major user impact
    status:needs-reconcileIssue facts or acceptance criteria may lag the current repository
    securitySecurity, privacy, credentials, trust boundaries, or sensitive data
    on Aug 22, 2026
  8. jlipworth commented on Aug 22, 2026

    @jlipworth
    OwnerAuthor

    App Store rollout checkpoint — Labstream bundle rename unblocked and export-verified

    Continuing from the pause-for-rename checkpoint: the public rename is now carried through the repo and App Store signing path.

    Repo / GitHub

    • GitHub remote is now jlipworth/Labstream.
    • Pushed the Labstream rename commits to main:
      • app/bundle/log subsystem rename to Labstream
      • login brand header update
      • Labstream logo wordmark update

    Bundle ID / local app identity

    • Local project now uses:
      • PRODUCT_BUNDLE_IDENTIFIER = com.jlipworth.Labstream
      • INFOPLIST_KEY_CFBundleDisplayName = Labstream
      • MARKETING_VERSION = 1.3.5
      • CURRENT_PROJECT_VERSION = 1
    • Built app Info.plist verified:
      • CFBundleIdentifier = com.jlipworth.Labstream
      • CFBundleDisplayName = Labstream

    Validation

    • scripts/ci-hygiene.sh passed.
    • cd PMSKit && swift test passed after clearing stale SwiftPM module cache left from the old path rename (/path/to/user/visionplay -> /path/to/user/labstream): 1192 tests passed.
    • Simulator smoke passed with the new bundle id via scripts/agent-sim-run.sh launch-home-passive.

    App Store signing/export

    • Release archive for generic visionOS succeeds for com.jlipworth.Labstream.
    • Xcode automatic provisioning can see/create the new App ID and Store provisioning profile.
    • App Store Connect export now produces a distribution-signed IPA when symbol upload is disabled:
      • Identifier: com.jlipworth.Labstream
      • Authority: Apple Distribution
      • Store provisioning profile, no device UDIDs
      • get-task-allow = false

    Note on Xcode export quirk

    The first app-store-connect export attempt with symbols enabled failed during IPA creation because Xcode's packaging step invoked /usr/bin/rsync with extended-attribute flags that this macOS/openrsync combo rejected. Signing/provisioning had already succeeded. Retrying with uploadSymbols = false produced the IPA successfully. If dSYMs/symbols are required for the first TestFlight upload, handle symbol upload separately or use Xcode Organizer if it avoids the local rsync packaging bug.

    Headset data note

    Because the bundle id changed from com.jlipworth.VisionPlay to com.jlipworth.Labstream, the renamed TestFlight build is a different app/container. Existing offline downloads do not migrate automatically; the old app/download container was intentionally removed on-device before continuing.

    Next step

    Ready to upload the first TestFlight build for 1.3.5 (1) from the export-verified archive/IPA, or re-archive immediately before upload if we want a fresh timestamped build artifact.


    Recreated during the pre-publication privacy scrub. Original comment created 2026-07-05T19:20:31Z.

  9. 1 remaining item

  10. jlipworth commented on Aug 22, 2026

    @jlipworth
    OwnerAuthor

    Research: legal/trademark review + App Review server-access strategy

    Working two of the non-code prereqs from the checklist. (#273 history gate is being handled separately. Privacy-policy + support-URL content will live in the docs/mkdocs refactor — see #69 — rather than as standalone files here. Apple Developer enrollment is not started yet and is the long pole, since archive/TestFlight are blocked on it.)

    1. Legal / trademark — naming & branding for an unofficial 3rd-party client

    Bottom line: the app name is already clean. "VisionPlay" contains none of "Plex", "Jelly…fin", or "Emby". The #52 rename away from VisionPlex was exactly the move all three trademark policies require — a name containing "Plex" would have been a direct violation. No name change needed.

    What each rights-holder requires of third-party clients:

    • Plex (strictest on marks). You may not register/use a name containing "Plex", may not use Plex marks in a way implying partnership/endorsement, and may not copy Plex's look-and-feel (their color combinations, graphic design, typography) or use Plex logos without prior written approval. Factual/nominative interoperability statements ("a client for Plex servers") are the safe lane; logos and brand styling are not. Also governed by Plex's Terms of Service / API terms for third-party clients.
    • Jellyfin (most permissive). Don't use "Jellyfin" in the app name, and avoid "Jelly[word]" / "[word]fin" constructions; don't use the Jellyfin logo as the app icon. You may say "a Jellyfin client" in the description and may use their color gradient on an original logo. Must stay in good community standing and not facilitate piracy. "VisionPlay" is fine.
    • Emby (the one to scrutinize). Emby's server/software is proprietary (unlike GPL Jellyfin) and Emby owns all its marks; using the Emby REST API + "Emby" branding in a store listing is an explicitly sensitive topic in their own community. Treat Emby support as the highest-risk of the three: descriptive use only, no logo, and we should read Emby's API/license terms for third-party-client permission before listing Emby support prominently.

    Recommended actions (all metadata/policy, no code beyond the icon check):

    1. Keep the name "VisionPlay". ✔ (done via Rename app/project from VisionPlex to VisionPlay #52)
    2. Add an explicit disclaimer in the App Store description and somewhere in-app: "Unofficial. Not affiliated with, endorsed, or sponsored by Plex, Jellyfin, or Emby." Reference the three names descriptively only ("compatible with Plex, Jellyfin, and Emby media servers").
    3. Use no Plex/Jellyfin/Emby logos in the app icon or marketing. Audit the current icon/color palette to confirm it's original (not Plex orange/black, not the Jellyfin gradient-as-icon).
    4. Before submission, read each service's third-party/API terms (Plex ToS, Jellyfin community standards, Emby license + API terms) and record the sign-off.
    5. Optional: courtesy written OK from Plex/Emby if we ever want more than nominative use of their marks.
    6. Apple-side: Guideline 5.2 (IP) means brand names in app metadata must be nominative and non-confusing — the "unofficial / not affiliated" framing above covers this.

    2. App Review can't reach a private server — strategy

    This is the top rejection risk (Guideline 2.1 App Completeness drives ~40% of unresolved review issues). Findings from Apple's guidelines + developer forums:

    • A demo video is NOT a safe substitute. Apple now states demo videos of functionality that is "geo-locked or otherwise restricted are not accepted." Plan for the reviewer to actually run the app end-to-end, not watch a recording.
    • The required path is a reachable demo account + live backend. Apple: provide "an active demo account or fully-featured demo mode … and enable backend services so that they're live and accessible during review," with setup details in App Review Notes.
    • ⚠️ Most important, directly applicable finding: an app that connected to a self-hosted server was rejected 10+ times with "cannot connect to server" — the cause was dynamic DNS (DDNS). The hostname resolved fine on a home network but SERVFAIL'd on Apple's corporate network. Apple DTS ("Quinn") prescribed a "vanilla network setup": HTTPS, port 443, a fixed real DNS name, and a system-trusted TLS certificate. This is exactly the trap a Plex/Jellyfin/Emby self-hoster falls into (DDNS hostnames, non-standard ports, self-signed certs).

    Recommendation: stand up a dedicated demo server for review, configured as a vanilla setup — real registered domain on port 443 over HTTPS with a publicly-trusted (e.g. Let's Encrypt) cert, not DDNS / a custom port / a self-signed cert — preloaded with copyright-clean sample media, and put demo credentials + a one-line "open app → it's pre-pointed at this server → sign in" note in App Review Notes. Keep it live through the whole review window.

    The most bulletproof option is an in-app demo/guest mode (a bundled sample catalog so the reviewer needs no server at all), but that's code and would warrant its own issue if we go that route. The demo-server approach above needs no app changes and is the lower-effort first attempt.

    Net

    • Naming/trademark: already compliant; remaining work is a disclaimer line, an icon/branding audit, and reading the three services' API/ToS (Emby = highest scrutiny). All metadata, not code.
    • Reviewer access: solvable with a vanilla-configured demo server + credentials in review notes; avoid DDNS/self-signed/non-443, and don't rely on a demo video.

    Sources: Plex Trademarks & Guidelines; Jellyfin Branding Guidelines; Emby License / 3rd-party API + branding thread; Apple App Review Guidelines; Apple Developer Forums reviewer-cannot-connect-to-server / DDNS and demo-video-not-sufficient.


    Recreated during the pre-publication privacy scrub. Original comment created 2026-06-24T09:05:45Z.

  11. jlipworth commented on Aug 22, 2026

    @jlipworth
    OwnerAuthor

    Session update — enrollment kicked off + archive-readiness verified

    Apple Developer Program

    • Enrolled — payment submitted, membership pending activation (Individual). This is the gate for everything: TestFlight, the App Store record, and the long-lived distribution cert.
    • Verified current local signing state: only an Apple Development cert on a free personal team — no Apple Distribution cert, and a 7-day provisioning profile (free-team expiry). Confirms the paid membership is what unlocks distribution signing + the 1-year profiles. CODE_SIGN_STYLE = Automatic already, so Xcode will mint the distribution cert/profile automatically once the membership activates.

    Archive-readiness — verified, nothing to fix in the repo

    Spot-checked the things that actually cause submission/validation rejections; all already in place:

    • ✅ Privacy manifest (VisionPlay/PrivacyInfo.xcprivacy) complete: NSPrivacyTracking=false, no collected data types, and all three required-reason APIs declared — UserDefaults CA92.1, file timestamp DDA9.1, disk space 85F4.1.
    • ✅ Export compliance — ITSAppUsesNonExemptEncryption=NO in Config/Info.plist (skips the per-upload encryption question).
    • ✅ Layered app icon present (Back + Front; valid for visionOS).
    • ✅ Local-network usage string + scoped ATS (NSAllowsLocalNetworking).
    • ✅ GPLv3 §7 additional permission (APP-STORE-EXCEPTION.md) resolves the FSF/VLC App-Store-distribution conflict while preserving copyleft.

    Stale fact to update in the issue body

    • MARKETING_VERSION is now 1.2.1, CURRENT_PROJECT_VERSION = 1 (issue body says 1.0). Reminder: each TestFlight upload needs a unique build number, so bump CURRENT_PROJECT_VERSION per upload.

    Remaining path (all account/portal, gated on activation)

    1. Membership activates → sign the Apple ID into Xcode → distribution cert + 1-year profile auto-mint.
    2. Create the App Store Connect app record (com.jlipworth.VisionPlay, platform visionOS). App-name availability for "VisionPlay" still to be confirmed in ASC (residual from the trademark line); have a fallback ("VisionPlay for Plex").
    3. Release archive → validate → upload.
    4. TestFlight internal tester (instant, no review) → install via TestFlight app on the Vision Pro.

    Gate reminder: public submission remains blocked on #273 (history sensitive-info audit + filter-repo). A private internal TestFlight build publishes nothing externally, so it isn't blocked by #273 — but the public App Store step is.

    Listing copy drafted (paste into ASC when the version page exists)

    • Subtitle (≤30): Your media server, in 3D
    • Keywords (≤100): plex,jellyfin,emby,media,cinema,movies,tv,streaming,home theater,offline,player,server
    • Promotional text: Stream your Plex, Jellyfin, and Emby library on Apple Vision Pro — with a true immersive Cinema mode, offline downloads, and quality you control.
    • Description:

      VisionPlay is a native Apple Vision Pro client for your own Plex, Jellyfin, and Emby media server. Sign in, browse your libraries, and watch in a custom cinema player built for visionOS.

      • Immersive Cinema mode — expand any title into an app-owned theater surface with full transport, scrubbing, chapters, and Up Next
      • Server-aware quality — Direct Play / Maximum where possible, or pick an explicit bitrate rung
      • Offline downloads — keep originals when they play locally, or compatible server-rendered copies, with resume and integrity checks
      • TV done right — Show → Season → Episode browsing, Skip Intro / Skip Credits, autoplay with countdown across seasons
      • Resume half-watched titles, subtitles by language, chapters, 0.5×–2× speed, and progress sync back to your server
      • Music — Plexamp-style browse and audio playback that keeps going in the background

      Your server, your media, your headset. Secrets stay in the Keychain on-device — VisionPlay collects no data and includes no tracking.

    • App Privacy answer: Data Not Collected (matches the privacy manifest).
    • TestFlight "What to Test": Sign in to your Plex/Jellyfin/Emby server, browse, and play a movie and a TV episode. Try Cinema mode, scrubbing/resume, Skip Intro, and an offline download.
    • Remember to append the not-affiliated disclaimer (already in the in-app About footer) to the public description.

    Recreated during the pre-publication privacy scrub. Original comment created 2026-06-27T09:26:10Z.

  12. jlipworth commented on Aug 22, 2026

    @jlipworth
    OwnerAuthor

    2026-08-21 initial App Store / TestFlight preflight

    Grounded the current main candidate and attempted the first signed visionOS archive.

    Repository-controlled preflight — pass

    • Commit: c037eb964d4cb4e99305fc94fa8834a3c9fad4b4 (clean)
    • Scheme/platform: Labstream, Release, generic visionOS device
    • Bundle ID: com.jlipworth.Labstream
    • Version/build: 1.6.0 (1)
    • Unsigned Release device build: succeeded
    • Built bundle contains one privacy manifest; public privacy/support URLs both return HTTP 200.
    • Current manifest remains: no tracking, no collected-data types, required-reason declarations for UserDefaults, file timestamps, and disk space.
    • Export compliance/local-network/scoped ATS keys are present.

    Signed archive attempt — blocked on local Apple account state

    Ran the real archive with automatic provisioning:

    xcodebuild ... -destination generic/platform=visionOS -allowProvisioningUpdates archive
    

    Result:

    Signing for "Labstream" requires a development team. Select a development team in the Signing & Capabilities editor.

    Current machine inventory has no Xcode Apple account/team, usable signing identity, provisioning profile, or ASC API key. The earlier successful signing/export comments are historical; those credentials/artifacts are not present now. No repository change is required—the user needs to sign the paid Apple ID into Xcode → Settings → Accounts. After that, rerun the archive and let automatic signing mint/select the distribution assets.

    Toolchain

    • Installed: Xcode 27 beta 4, build 27A5228h
    • Apple explicitly permits beta-4 SDK builds for internal/external TestFlight.
    • Treat this toolchain as a TestFlight path, not the final customer App Store submission toolchain; use a currently App-Store-supported non-beta Xcode for production submission.

    Once account access is restored

    1. Discover/set the paid team locally (gitignored Signing.local.xcconfig if needed).
    2. Fresh signed 1.6.0 (1) archive.
    3. Validate/export; if the known symbol-packaging rsync failure recurs, export with uploadSymbols=false and handle dSYMs separately/through Organizer.
    4. Verify or create the ASC visionOS app record, upload, wait for processing, and add to internal TestFlight.
    5. Install on Vision Pro and smoke the public Jellyfin demo path.
    6. Increment the build number before any retry upload under 1.6.0.

    No build number bump was made: 1.6.0 (1) remains valid if it has never been uploaded.

  13. jlipworth commented on Aug 22, 2026

    @jlipworth
    OwnerAuthor

    Follow-up: signing restored; archive/export pass; upload reached ASC but toolchain was rejected

    After the paid Apple ID was restored in Xcode:

    • Created a local, gitignored Signing.local.xcconfig for the paid team.
    • Automatic provisioning created/selected a development certificate and provisioning profile for com.jlipworth.Labstream.
    • Signed Release archive for visionOS succeeded.
    • App Store Connect export succeeded, including Labstream.ipa.
    • Upload authenticated, analyzed the package, and reached App Store Connect.
    • ASC then rejected it with: “Unsupported SDK or Xcode version.”

    The archive was built with Xcode 27 beta 4 (27A5228h). Although Apple had previously enabled beta 4 for TestFlight, current server-side acceptance has rolled forward; this build is no longer accepted. No app/package validation defect was reported before that toolchain rejection.

    Next gate

    Install supported stable Xcode 26.6 (preferred for the production path) or the currently accepted Xcode 27 beta/RC, switch xcode-select, then create a fresh archive/export/upload. The current beta-4 archive cannot be repaired in place because the SDK/toolchain is embedded in the uploaded build.

    Local candidate artifacts:

    • Archive/export root: /tmp/labstream-appstore-archive-20260821-224534
    • Exported IPA: export/Labstream.ipa

    Since ASC rejected the upload rather than accepting a build, keep 1.6.0 (1) for the fresh-toolchain retry unless ASC unexpectedly shows build 1 after processing.

  14. jlipworth commented on Aug 22, 2026

    @jlipworth
    OwnerAuthor

    Initial TestFlight deployment complete — 2026-08-21

    The first Labstream visionOS build is now in App Store Connect/TestFlight.

    Toolchain/install

    • Replaced Xcode 27 beta 4 with Xcode 27 beta 5 (27A5237l) from Apple Developer Downloads.
    • Xcode first-launch/system components completed.
    • Installed beta-5 iOS, tvOS, and visionOS simulator runtimes.
    • Retained beta-4 runtimes intentionally so the existing worktree/golden simulators remain usable.
    • Moved the downloaded XIP installer to Trash.
    • Active developer dir is /Applications/Xcode-beta.app/Contents/Developer; first-launch status is clean.
    • Repo remains clean.

    Archive/upload

    • Fresh signed Release visionOS archive: succeeded
    • SDK: visionOS 27 beta 5 (24M5347a)
    • App: Labstream 1.6.0 (1)
    • Bundle ID: com.jlipworth.Labstream
    • App Store Connect upload: succeeded
    • ASC processing: completed
    • TestFlight status: Ready to Submit, expires in 90 days

    App Store Connect reconciliation

    • Existing visionOS version page changed from stale 1.0 to 1.6.0.
    • Created internal group Internal Testers with automatic distribution enabled.
    • Build 1.6.0 (1) is attached to the group.
    • Added the Account Holder as the first internal tester; invitation status is Invited.

    Remaining gates

    1. Account Holder accepts the newly updated Apple Developer Program License Agreement. ASC says this is required to update/submit apps.
    2. Accept/open the TestFlight invite on Vision Pro, install 1.6.0 (1), and smoke: launch → public Jellyfin demo login → browse → play.
    3. Complete App Store metadata/screenshots/privacy/accessibility/pricing/review fields before public review.
    4. Any retry upload under 1.6.0 must use build 2 or higher.

    Local archive root:
    /tmp/labstream-appstore-archive-20260821-231104-xcode27b5

  15. jlipworth commented on Aug 22, 2026

    @jlipworth
    OwnerAuthor

    1.6.1 coordinated source milestone + release runbook draft

    Prepared the next source milestone as 1.6.1 (1) across all four native targets (visionOS, universal iOS/iPadOS, macOS preview, tvOS preview) and synchronized the PMSKit fallback version. This does not upload 1.6.1 or change the distribution scope; ASC/TestFlight still contains visionOS 1.6.0 (1) only.

    Validation completed on the uncommitted working tree:

    • 12/12 app target configurations report MARKETING_VERSION = 1.6.1; all builds remain CURRENT_PROJECT_VERSION = 1.
    • PMSKit: 1,662 tests passed (live probes excluded by the canonical hermetic command).
    • Repository hygiene: 293 tests passed; strict docs, links, anchors, and Mermaid checks passed.
    • Clean Debug builds succeeded for visionOS, iOS/iPadOS, macOS, and tvOS.
    • Every generated bundle reports 1.6.1 (1).
    • visionOS, iPadOS, and tvOS simulator install/launch/screenshot smokes passed with no fatal/crash/assert log matches.

    Documentation drafted in docs/RELEASES.md and linked from README/MkDocs. It records the platform-specific distribution state, version/build semantics, repository/binary checks, screenshots and metadata, TestFlight/App Review, privacy/export compliance, Account Holder agreement, EU trader status, and public-release closeout. The umbrella issue body has also been replaced with the current Labstream facts/checklist; historical details remain in comments.

    Still deliberately deferred: installing the existing 1.6.0 (1) TestFlight build on Vision Pro. Human/account gates remain the current agreement acceptance, trader/storefront decision, and final ASC business/review fields.

  16. jlipworth commented on Aug 22, 2026

    @jlipworth
    OwnerAuthor

    Split the reviewer-backend work into #280: a dedicated isolated Jellyfin environment with stable HTTPS/DNS, least-privileged non-expiring review credentials, licensed sample media, deterministic reset, external health checks, and no personal server/data exposure. The public Jellyfin project demo remains a development/fallback path, but the App Store submission should not depend exclusively on third-party demo infrastructure.

  17. jlipworth commented on Sep 6, 2026

    @jlipworth
    OwnerAuthor

    The targeted code/history sweep found that this issue body predates the current documented universal-purchase topology and processed build-2 archives (see docs/RELEASES.md). Please reconcile this existing umbrella rather than create a duplicate release issue; keep uploaded-candidate state distinct from current source and preserve all unfulfilled platform/hardware/review gates. This sweep did not query App Store Connect and does not advance account-side release status. Focused tracking for the already documented full macOS hosted regression failures is now #299. New sweep findings #292–#298 are individually scoped follow-ups, not release-readiness certification.

  18. jlipworth commented on Sep 15, 2026

    @jlipworth
    OwnerAuthor

    Release codec sweep follow-up is tracked separately: #322 (Emby P8 deep-seek failure), #323 (P5 forced-transcode startup and delayed Jellyfin worker cleanup), and #324 (HEVC Rext/4:4:4 Original startup across backends). Investigation branch: codex/release-codec-sweep-triage. Current checkpoint: 39 bounded macOS DEBUG runs, 18 transport passes / 15 blocked / 6 failed; these are not visual or release-acceptance counts. Queue halted on bounded cleanup failure; the worker subsequently exited naturally and no test workers remained at final check. Subtitle burn-in, remaining combinations and hardware acceptance stay open. #259 is explicitly deferred by the user. No experimental P7 candidate enablement or release upload is implied.

  19. jlipworth commented on Sep 15, 2026

    @jlipworth
    OwnerAuthor

    Completed a source-level disclosure/checklist audit on codex/prerelease-disclosure-audit (separate from playback work). Findings #325 and #326 are recorded; current privacy/export/accessibility certification remains unchecked rather than inferred from historical processed builds. #259 is explicitly deferred. Public support/privacy HTTPS endpoints returned 200. Screenshot branch 7f93e1e was reviewed, with nine screenshot tooling tests passing; final captures, attribution/age-suitability review and TestFlight journey remain open. Docs hygiene and 1,707 hermetic PMSKit tests pass. No App Store Connect query, account edit, merge, upload or submission was performed.

  20. jlipworth commented on Sep 16, 2026

    @jlipworth
    OwnerAuthor

    Privacy tracking clarification: #325 now separates ordinary on-device client diagnostics, explicit support sharing, and the optional project-operated reviewer/demo service. Additional source review identified no automatic diagnostic-upload path in the reviewed implementation. #280 owns the demo-service retention/deletion/backup/access evidence; #325 owns accurate wording and final owner-approved disclosure mapping. This does not require auditing arbitrary user-selected media servers or changing Data Not Collected solely because local logs exist.

  21. jlipworth commented on Sep 29, 2026

    @jlipworth
    OwnerAuthor

    PR #330 merged: consolidated licensed demo-media provenance/capture planning and remaining release-gate corrections, preserving the already merged privacy changes. Official license pages and Apple screenshot guidance were rechecked; local tooling/PMSKit/docs checks and all PR checks passed. This is documentation/spec/test work only: no final screenshots, live asset-hash audit, account edits, upload or hardware acceptance. #259 stays deferred; #280/#325/#326 acceptance remains open.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestinfraRepo / tooling / releasepriority:p1High priority; release/publication blocker or major user impactsecuritySecurity, privacy, credentials, trust boundaries, or sensitive datastatus:needs-reconcileIssue facts or acceptance criteria may lag the current repository

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions