Repository navigation
Downloads overhaul, iPhone Duo and player rework (1.8.0) - #425
Merged
Merged
Conversation
Downloads overhaul P1, verified and integrated into downloads/overhaul.
Downloads overhaul P2, verified and integrated into downloads/overhaul.
Downloads overhaul P3a, verified and integrated into downloads/overhaul.
Downloads overhaul P3b, verified and integrated into downloads/overhaul.
…385) Downloads overhaul P4, verified and integrated into downloads/overhaul.
…387) Downloads overhaul P5, verified and integrated into downloads/overhaul.
…kes (#388) Downloads overhaul P6, verified and integrated into downloads/overhaul.
….8.0 (#389) Downloads overhaul P7, verified and integrated into downloads/overhaul. Preserve the recorded build 1513 distribution history alongside the 1.8.0 source milestone. Device acceptance remains pending.
Maintainer-approved follow-up to the 1.8.0 row redesign. The target is the `downloads/overhaul` integration branch, not `main`. **What changed** - Finished rows show one summary line instead of the old `Downloaded: <bitrate> avg` line plus a status line. The order is status, resolution, average bitrate, then size plus extras: - `Downloaded • 1080p • 5.7 Mbps avg • 1.6 GB + 12 MB extras` - `Not verified • 1080p • 6.1 Mbps avg • 1.8 GB` Unknown pieces are omitted. The line is a single line with tail truncation, and VoiceOver reads the full text. - No status line has a leading icon any more. Every text line starts at the same edge. Tone colour and words carry the state, and the poster badge is unchanged. - In-progress, paused, failed and waiting rows keep their `Requested: …` line and progress bar. - This applies everywhere the shared row is used: the Offline library, the iOS/visionOS sheet and the Mac sheet. - `docs/DOWNLOADS-OFFLINE.md` and `TESTING-CHECKLIST.md` are updated. **Verification** - PMSKit: 1,752 tests pass. - macOS hosted: 981 tests pass. - Hygiene passes. - P7 parity tests pass. - iPhone hosted: 967/968 pass. `SeasonPlannerIntegrationTests.aRefreshOutageDefersAPlannedRowInsteadOfFailingIt` timed out once at `:392`; this PR doesn't touch that test or the code it covers. - Rendered PNGs of the complete, unverified and downloading rows were checked at normal and narrow widths.
Targets the `downloads/overhaul` integration branch. This is a test-only change. **Root cause:** `aRefreshOutageDefersAPlannedRowInsteadOfFailingIt` inferred completion from transient supervision state: - its one-second retry could overtake the waiter; - supervision ended before deferral persistence finished. This made it time out once on the iPhone simulator. **Fix:** - Waits now use exact-generation completion acknowledgements, with controlled backoff time. - Matching waits found in the same file were converted too. - No assertion was weakened. In a red control, omitting the deferral fails the kept assertions. **Verification:** - PMSKit: 1,640 tests pass. - macOS hosted: 914 tests pass. - iPhone season suite: 3 of 3 runs pass, 11 tests each. - Hygiene passes.
Targets the `downloads/overhaul` integration branch, not `main`. Refs #379. The issue closes when this lands on `main`. After a wake (scene foreground, background-session wake, or a long gap between callbacks), the Downloads header shows **"Updating speed…"** until every active transfer has a sample in one common post-wake window. Before this change it summed a partial set of per-item rates and presented that as the batch speed. - The #224 protection against inflated catch-up rates is kept. - No persisted state is added. - Tests use an injected clock: partial freshness hides the number, full freshness shows the sum, the catch-up guard holds, and the single-item case is covered. **Verification:** PMSKit 1,651 · macOS hosted 914 · hygiene. Physical headset comparison is still pending.
Closes #404. Targets the `downloads/overhaul` integration branch. ### What changed - New setting: **Settings ▸ Downloads ▸ Simultaneous downloads**, with choices 1–5 (default 3, the previous fixed cap). It is available on visionOS, iOS/iPadOS and macOS; tvOS has no Downloads settings. - `DownloadAdmissionPolicy` no longer hard-codes the caps. It takes `DownloadAdmissionLimits`: - total cap: the setting, clamped to 1–5 when read; - static-file lane: `max(1, total - 1)`; - server preparation and live-forward lanes: still 1 each. - `DownloadAdmissionCoordinator` reads the stored value at every gate, including relaunch recovery. It watches only this key and starts an admission pass when the value changes. - Lowering the setting never cancels running transfers. Raising it starts waiting rows when lanes have room. - Updated `docs/DOWNLOADS-OFFLINE.md`, `docs/SETTINGS.md` and `TESTING-CHECKLIST.md`. ### Verification | Check | Result | |---|---| | PMSKit hermetic tests | 1,642 pass | | LabstreamMacTests | 918 pass | | Hygiene tooling tests | 386 pass | Also included: policy pins (clamping, lane caps for each total, existing work kept when lowered) and integration tests for lowering and raising the setting. ### Open gates - Live-backend and physical-device acceptance: not run. They are tracked in #403.
…ness wait #405 added a snapshot-builder call using the old downloadSpeed argument that #406 renamed to aggregateSpeedBytesPerSecond; each PR passed alone. failedHeadRetriesBeforeQueuedSuccessorWithoutPoisoningIt waited 1 s for the head/successor retry to drain, which expired once under full iPhone-suite load. The wait checks liveness, not speed, so it now allows 10 s.
Prefer Pause All while any work is active or requested. Pause current store attempts, withdraw waiting retries, clear retry handoffs, and park Emby preparation through the row-pause path. Keep paused first-start intents distinct from pending admission and disable bulk controls during startup recovery. Closes #410
Retain exact-attempt refill intents across inactivity, count pending finished bodies as planner coverage, and release mutation ownership at replacement resume. Establish connectivity eligibility at baseline and end result observations at actual stop edges. Retire terminal health bookkeeping. Add fake-clock and held-I/O regression coverage for the review interleavings, multi-row timing, stop-edge reports, pause, deletion, and backend sign-out. Update the download behavior and device checklist. Validated with hermetic PMSKit tests, the macos-hosted affected lane using private temporary directories, and ci-hygiene. No simulators booted.
Schedule poster-only hydration for queued, season-planned, and restored active rows using the existing attempt/source-fenced cache. Preserve side-asset accounting and defer heavier assets to their existing paths. Closes #412
… work scheduleEarlyPosters runs on every records refresh; rows already offered now skip attempt admission and media-item construction. Refs #412
…409) A sibling's ordinary continuation can publish the attempt while a health refill waits in backoff. Publication neither halts the range nor revokes admission, so the intent kept polling every 30 s for the rest of the process and wrote a diagnostic each time. Retirement and refill execution now also require a nonterminal lifecycle.
…aption per wait (Refs #414)
The restricted Offline surface mounted its status banner as a top safeAreaInset outside the NavigationStack. On iPhone it clipped the large title and covered the Sign In/Settings toolbar, on iPad it still covered the toolbar, and on visionOS it never rendered. The status is now a "Server unreachable" navigation subtitle (iOS/iPadOS/macOS) or a toolbar label (visionOS, which has no navigation subtitle), and Reconnect is a prominent toolbar action whose accessibility hint carries the full explanation. A DEBUG --ui-testing-fixture offline launch mounts the surface without a server, and a mobile UI test asserts Reconnect, Sign In and Settings stay hittable.
With no job running, AVPlayer's init.mp4 and target-segment requests could reach Emby together: init started a job from zero, the target stalled for about 20 s, and every later segment restarted the encoder, dropping audio each time. Fetch the segment containing the target first so the job already runs there when init arrives. The soak runner now reads prewarm and target-warm facts from the diagnostics JSONL (NSLog does not reach the unified log for the hosted dev app) and fails a run on a restart storm. Mac soak, 20 deep-seek runs each: restart-storm runs 6 -> 4, audio-queue resyncs 61 -> 23, target warm ready 40/40, no render-pipeline failures, every probe passed. The remaining storms are an Emby-side position reset after a mid-file start. Refs #420 #421
…oder logs scripts/scrub-server-logs.py discovers the concrete hosts, addresses, credentials, identifiers, account/device names, library paths, titles, release names and search terms in server and ffmpeg logs (including base64/gzip payloads), replaces them with the repository placeholders, re-encodes payloads, and fails closed when a re-scan of the output still finds anything. Optional --since/--until/--play-session windows pull in the matching transcoder logs. Reports carry category counts only. Closes #423
…e in the iOS player overlay On the unfolded iPhone Duo the scrim was pinned to the safe frame, leaving undimmed stripes under the status strip and over the home-indicator band, and the bottom group stacked its authored 28 pt margin on top of the bottom safe inset. The scrim now covers the full picture in overlay and book; the bottom margin counts from the picture edge (at least 8 pt past the safe edge).
The menu row was six unlabeled circles with Quality hidden behind More. It is now Quality, Subtitles, Audio, Chapters, Speed and Stats as labeled glass capsules: beside the title when they fit, else on their own row under the scrubber, else icon-only circles in the same order. Quality is always present (dimmed when the source only plays at original quality); More is gone. The transport adds smaller −30/+30 circles outside ±10 when the row has room. Verified on the Duo simulator folded (678 pt: labeled row + ±30) and by the full mobile fixture UI suite.
Stats colors: green now means only "plays as-is" on every platform; copy and encode are neutral gray (told apart by title and link label), matching the iOS design spec instead of cyan/orange on visionOS, tvOS and macOS. Connection: any custom DNS name was always "Unknown". Opening Stats now resolves the host on the device and classifies the address against this device's interfaces: same physical subnet is Local; a tunnel subnet, the 100.64.0.0/10 overlay range or Tailscale's IPv6 range is VPN; other private addresses are VPN while a tunnel carries an address, else Local; public is Remote. The host-only answer stays as the fallback, and the host never leaves the resolver.
The soak defaulted to the downloads-overhaul staged app and bundle suffix, so it would not find the app from main or another worktree. Mirror deploy-macos-to-host.sh: the LABSTREAM_MAC_BUNDLE_ID_SUFFIX env, else the current branch, sanitized the same way.
… main - Releases: one current-status summary, a corrected product table (latest processed is 1.8.0 build 1653, not 1.7.2 build 1513) and newest-first build tables for 1.8.0 and 1.7.2. - Downloads plan: status, P7 (#389) and P7.7 marked done; admission caps follow #408/#414. - iPhone Duo plan: player spec revised for labeled menus/±30 (ff57f33), list+detail remnants removed, journal entry for the 2026-10-30..11-02 follow-ups; dated file name. - Downloads/offline, Settings, CODE-MAP, macOS, iOS, playback and the checklist: compact iPhone/iPad rows, no detail page, #414 prep slots and render deadline, #416 speed, new download files, Stats palette/VPN checks. - scripts/README: duo-appresize, research harness, signal host, lease and soak flags. - Index pages, README, CLAUDE.md: Duo, headless playback testing, Xcode lease pointers; dated research note name.
18 tasks
Owner
Author
|
Local checks on head
|
This was referenced Nov 5, 2026
Open
Open
Open
jlipworth
added a commit
that referenced
this pull request
Nov 5, 2026
Records the first 1.8.0 TestFlight build from `main` (`27b6bf5a`, after #425 and #427): it processed VALID on all four platforms and is in Labstream Internal. Also records that the four App Store Connect drafts were renamed from 1.7.2 to 1.8.0 with build 1654 selected (nothing submitted), and adds a note that `--build-number auto` is below the integration-branch builds until `main`'s commit count passes 1654. Docs only. `scripts/ci-hygiene.sh` passed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Lands the 1.8.0
downloads/overhaulbranch onmain. The branch has 142 commits andmainhas not moved since it branched, so this merges with no conflicts.MARKETING_VERSIONis 1.7.2 → 1.8.0. Internal TestFlight builds 1523–1653 are recorded indocs/RELEASES.md.Linked issue
Refs #403 (acceptance and landing). Refs #419, #420, #421, #422, #423.
Affected surface
Verification evidence
scripts/native-test-matrix.py affected --base origin/main.scripts/check-sensitive-paths.py --base origin/mainmatched 15 paths, and I reviewed each one:CLAUDE.md: docs/tooling text;project.pbxproj: only theMARKETING_VERSIONbump;.gitignore: Duo sim/artifact entries;pyproject.toml/uv.lock: numpy added as a dev dependency;mkdocs.yml: one nav line;scripts/ci-hygiene.sh: the reducer guard.Privacy checklist
AI assistance
Claude Opus via Claude Code and GPT via Codex wrote most of the implementation, docs and tooling under maintainer direction. The maintainer did the device testing.
After merge (#403)
v1.8.0on the merge commit.docs/plans/2026-10-16-downloads-overhaul.mdand repair its links.downloads/overhaul.