Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
395 commits
Select commit Hold shift + click to select a range
74528a3
fix(ios): gate reconnect on completed handshake and clear finished re…
Quick104 Sep 4, 2026
e60cda6
Merge pull request #239 from Silo-Server/t3code/speed-up-tvos-backdrop
Quick104 Sep 4, 2026
d4d5211
fix(notifications): renew the display token before expiry and retry d…
Quick104 Sep 4, 2026
8449f6d
Merge pull request #234 from Silo-Server/t3code/handle-remote-disconn…
Quick104 Sep 4, 2026
16cf917
docs(tvos): clarify focus engine and remote guidance
Quick104 Sep 4, 2026
69c1693
fix(notifications): drop the display token when the identity moves
Quick104 Sep 4, 2026
4c40de4
fix(notifications): keep the display token across a cold-launch retarget
Quick104 Sep 4, 2026
bf9f1a7
fix(notifications): keep display-token metadata paired with the Keych…
Quick104 Sep 4, 2026
8278f19
fix(notifications): retry the display fetch with the access token once
Quick104 Sep 4, 2026
aa31e69
Merge pull request #240 from Silo-Server/t3code/fix-notification-meta…
Quick104 Sep 4, 2026
b234d0b
fix(tvos): hand top-menu Down focus to left-most content
Quick104 Sep 4, 2026
b698459
fix(tvos): defer content focus request after top-menu teardown
Quick104 Sep 4, 2026
b984452
Merge pull request #242 from Silo-Server/t3code/tvos-leftmost-down-focus
Quick104 Sep 4, 2026
4a3bbb6
fix(tvos): keep episode rail focus on horizontal edges
Quick104 Sep 4, 2026
2a29136
fix(tvos): fence episode rail edges with native focus guides
Quick104 Sep 4, 2026
c169192
Merge pull request #243 from Silo-Server/t3code/fix-series-episode-ca…
Quick104 Sep 4, 2026
ff2bdf7
fix(tvos): replace detail menus with instant popovers
Quick104 Sep 4, 2026
5d1dfe8
fix(tvos): expose popover highlight to VoiceOver and keep tall panels…
Quick104 Sep 4, 2026
9ea2108
Merge pull request #244 from Silo-Server/t3code/tvos-audio-subtitles-…
Quick104 Sep 4, 2026
cb09544
fix(ios): enlarge Continue Watching cards
Quick104 Sep 4, 2026
25d2ecd
Merge pull request #245 from Silo-Server/claude/continue-watching-car…
Quick104 Sep 4, 2026
f6171e2
fix(player): resolve the initial subtitle intent in combined ordinal …
Quick104 Sep 4, 2026
9f82eeb
chore(deps): move AetherEngine to a Silo-Server fork at 6.67.2 and fi…
Quick104 Sep 4, 2026
ce8209d
fix(ios): restore quick-play on Continue Watching still cards (#249)
Quick104 Sep 4, 2026
1acdd7b
docs(readme): refresh iOS sample screenshots from the demo server (#250)
Quick104 Sep 4, 2026
f705f22
Clean up release launch paths and preserve deep links (#171)
zZebrahz Sep 4, 2026
9e47f46
fix(player): keep embedded stream 0 selectable and align the signatur…
Quick104 Sep 4, 2026
3c32225
refactor: remove obsolete Apple client code and test scaffolding (#251)
Quick104 Sep 4, 2026
fa3bbe4
fix(player): select native subtitles and preserve sidecar timing (#252)
Quick104 Sep 5, 2026
e2420f0
feat(player): render styled ASS subtitles locally (#255)
Quick104 Sep 5, 2026
dbd292b
Replace the static ASS subtitle library with source packaging (#258)
Quick104 Sep 5, 2026
e76edf5
Preserve tvOS Settings pane focus targets
Quick104 Sep 5, 2026
42b8050
fix(tvos): confirm detail menu selections on the first press
zZebrahz Sep 6, 2026
f1147f3
Merge pull request #260 from Silo-Server/fix/tvos-detail-menu-selection
Quick104 Sep 6, 2026
2545e6c
Merge pull request #259 from Silo-Server/codex/tvos-settings-category…
Quick104 Sep 6, 2026
8758027
docs: sync trademark policy with siloserver.org
Quick104 Sep 6, 2026
36c1beb
docs: tighten policy wording after review
Quick104 Sep 6, 2026
d03865a
docs: scope lowercase naming to command-line binaries
Quick104 Sep 6, 2026
7e04dc3
Merge pull request #262 from Silo-Server/docs/brand-guidance-sync
Quick104 Sep 6, 2026
3f91162
fix(tvos): improve top-menu responsiveness
Quick104 Sep 6, 2026
cdcadff
fix(tvos): stabilize continuous series episode navigation
Quick104 Sep 6, 2026
71c21a6
fix(tvos): use native focus in playback option dialogs
Quick104 Sep 6, 2026
daf6867
Merge pull request #263 from Silo-Server/codex/tvos-top-menu-response
Quick104 Sep 6, 2026
a2ebd4e
Merge pull request #265 from Silo-Server/codex/tvos-playback-dialog-s…
Quick104 Sep 6, 2026
c21b1f8
fix(tvos): clear initial episode loading after hierarchy failure
Quick104 Sep 6, 2026
6a3f7a4
Merge pull request #264 from Silo-Server/codex/tvos-series-episode-na…
Quick104 Sep 6, 2026
fd5ebed
docs: allow wordplay names in trademark policy (#266)
Quick104 Sep 6, 2026
0d7ab88
fix(ios): stop keyboard returning after playback from search
Quick104 Sep 6, 2026
8f65b26
Merge pull request #269 from Silo-Server/fix/ios-search-keyboard-afte…
Quick104 Sep 7, 2026
bc45b25
perf(tvos): omit unused season artwork
Quick104 Sep 7, 2026
f86aa13
fix: preserve series loading state and initial tvOS focus
Quick104 Sep 7, 2026
afbd4ed
fix: retain series selection through cache misses and retries
Quick104 Sep 7, 2026
adf7daf
fix: complete hierarchy retries and respect action focus
Quick104 Sep 7, 2026
c5977ac
Merge pull request #272 from Silo-Server/t3code/fix-series-detail-loa…
Quick104 Sep 7, 2026
1c5446f
Merge pull request #271 from Silo-Server/codex/artwork-metadata-indep…
Quick104 Sep 7, 2026
ade6e22
fix(tvos): preserve episode rail position across paging
Quick104 Sep 7, 2026
106cb97
fix(tvos): smooth season carousel scrolling across paging
Quick104 Sep 7, 2026
9ddc4ca
Merge pull request #273 from Silo-Server/t3code/smooth-season-carouse…
Quick104 Sep 7, 2026
9d99c4c
fix(tvos): smooth related movies scrolling
Quick104 Sep 7, 2026
411c21f
Merge pull request #274 from Silo-Server/t3code/smooth-related-movies…
Quick104 Sep 7, 2026
e6aba93
fix(tvos): restore top-row focus after menu selection
Quick104 Sep 7, 2026
58b111e
fix(tvos): cancel stale menu entry focus requests
Quick104 Sep 7, 2026
004e4be
fix(tvos): cancel collection focus claims while loading
Quick104 Sep 7, 2026
a8894d2
Merge pull request #275 from Silo-Server/t3code/restore-top-row-focus
Quick104 Sep 7, 2026
d6f5d4e
fix(tvos): prevent repeated episode carousel animations
Quick104 Sep 7, 2026
71d9ae2
fix(tvos): clamp episode scrolling after page changes
Quick104 Sep 7, 2026
463c140
Merge pull request #276 from Silo-Server/t3code/discord-report
Quick104 Sep 7, 2026
a5bddfd
Fix tvOS continue watching episode selection
Quick104 Sep 10, 2026
f31ca26
Merge pull request #277 from Silo-Server/fix/continue-watching-return…
Quick104 Sep 10, 2026
1f31fe4
fix(auth): recover stale remembered servers
neurekadev Sep 12, 2026
ce4f744
fix(auth): harden stale server recovery
neurekadev Sep 12, 2026
71299aa
Merge pull request #284 from neurekadev/fix/280-stale-server-recovery
Quick104 Sep 12, 2026
e12a2f8
build(tests): add SiloTVTests target and stop relisting fixtures
Quick104 Sep 10, 2026
00ad5ca
test: add shared StubURLProtocol and migrate the private stubs onto it
Quick104 Sep 10, 2026
b2a9380
ci: run SiloTVTests on a tvOS simulator
Quick104 Sep 10, 2026
8dcc7c3
feat(auth): add one credential identity comparator and owner fence
Quick104 Sep 10, 2026
36c2bf5
fix(auth): record a breadcrumb at every session-persistence collapse …
Quick104 Sep 12, 2026
3e6ca12
Merge branch 'apiv2-replay/tvos-tests' into apiv2-replay/wire
Quick104 Sep 12, 2026
d28f8e8
fix(auth): treat authorityChanged as an identity change in restored-s…
Quick104 Sep 12, 2026
48ff6f6
feat(shared): add DurableCommandStore for every v2 write surface
Quick104 Sep 12, 2026
e7b8257
feat(networking): add the API v2 wire layer, probe, fixtures, and con…
Quick104 Sep 12, 2026
dbda477
test(apiv2): port the wire-layer tests onto the shared StubURLProtocol
Quick104 Sep 12, 2026
12878da
Merge branch 'apiv2-replay/identity' into apiv2-replay/wire
Quick104 Sep 12, 2026
c18202c
fix(auth): keep durable authority across token rotation and roll back…
Quick104 Sep 12, 2026
30f806a
fix(shared): reap expired durable records on every read
Quick104 Sep 12, 2026
0518227
test: release cancelled StubURLProtocol gate waiters
Quick104 Sep 12, 2026
ecb829e
Merge branch 'apiv2-replay/tvos-tests' into apiv2-replay/wire
Quick104 Sep 12, 2026
74907d2
fix(pairing): restore URL and profile when the registry commit fails too
Quick104 Sep 12, 2026
166a6b9
Merge branch 'apiv2-replay/identity' into apiv2-replay/wire
Quick104 Sep 12, 2026
cbff56f
Merge pull request #286 from Silo-Server/apiv2-replay/tvos-tests
Quick104 Sep 12, 2026
559da8f
Merge pull request #285 from Silo-Server/apiv2-replay/identity
Quick104 Sep 12, 2026
006f189
Merge remote-tracking branch 'origin/apiv2' into apiv2-replay/wire
Quick104 Sep 12, 2026
7e88ec5
chore(docs): drop the untracked apiv2 playback planning note
Quick104 Sep 12, 2026
1db6d5e
Merge pull request #287 from Silo-Server/apiv2-replay/wire
Quick104 Sep 12, 2026
76cf1c3
fix(tvos): stabilize subtitle search and align AI subtitle dialogs
Quick104 Sep 13, 2026
b371b1c
Merge pull request #288 from Silo-Server/fix/tvos-subtitle-dialogs
Quick104 Sep 13, 2026
b9a8963
fix(settings): use BCP-47 original-language sentinel and labels
Quick104 Sep 13, 2026
acb9581
fix(settings): add regional BCP-47 language options
Quick104 Sep 13, 2026
c0aa395
fix(settings): address review feedback
Quick104 Sep 13, 2026
e85d89d
Merge pull request #289 from Silo-Server/t3code/bcp47-language-select…
Quick104 Sep 13, 2026
258fca6
fix(ios): dismiss search keyboard before presenting detail and player
Quick104 Sep 15, 2026
587bae1
Merge pull request #290 from Silo-Server/t3code/75d69fda
Quick104 Sep 15, 2026
eca5ad3
fix(ios): keep iPhone on the tab layout while the player is in landscape
Quick104 Sep 16, 2026
6870c1a
Merge pull request #292 from Silo-Server/fix/ios-search-keyboard-over…
Quick104 Sep 16, 2026
3179969
fix(tvos): give empty pages a focus owner so the remote can't strand
Quick104 Sep 16, 2026
0ca7352
Merge pull request #293 from Silo-Server/t3code/fix/tvos-empty-favori…
Quick104 Sep 16, 2026
0c59132
fix(apiv2): address Macroscope and Codex review findings
Quick104 Sep 16, 2026
83af4c0
fix(apiv2): address CodeRabbit review findings
Quick104 Sep 16, 2026
13cd9a8
fix(apiv2): address second-round review findings
Quick104 Sep 16, 2026
dce8ced
fix(apiv2): address third-round review findings
Quick104 Sep 16, 2026
415f7ae
fix(apiv2): address fourth-round review findings
Quick104 Sep 16, 2026
94502cd
fix(apiv2): address fifth-round review findings
Quick104 Sep 16, 2026
a9647f2
fix(apiv2): preserve rollback credentials and validate response ident…
Quick104 Sep 16, 2026
feeb1c6
fix(auth): reconcile failed profile restoration and simplify login cl…
Quick104 Sep 16, 2026
143b0da
Merge pull request #294 from Silo-Server/apiv2
Quick104 Sep 16, 2026
e50197e
fix(artwork): resolve URLs against their supplying server (#296)
Quick104 Sep 16, 2026
de3b68f
fix(catalog): preserve library scope in detail and watch reads (#297)
Quick104 Sep 16, 2026
0631d6d
chore(deps): update AetherEngine to 7.1.0 and show DV conversion (#298)
Quick104 Sep 17, 2026
2efb081
fix(player): switch subtitles locally and enable original playback on…
Quick104 Sep 17, 2026
1c37195
fix(auth): make logout and server selection reliable (#302)
Quick104 Sep 19, 2026
9fa1d9a
fix(detail): show selected version metadata (#301)
Rhainland Sep 19, 2026
ffc396d
Refactor Apple client architecture
Quick104 Sep 20, 2026
5e5f44f
Adopt adaptive iOS sheet backgrounds
Quick104 Sep 20, 2026
c23903c
Unify media card state actions and refresh cached lists
Quick104 Sep 20, 2026
e350f4d
feat(remote): recognize servers across addresses and fix SiloRemote r…
Quick104 Sep 21, 2026
37199fa
fix(tvos): restore fixed typography sizes
Quick104 Sep 22, 2026
dd77b02
fix(playback): refresh HLS, subtitle and font credentials in place (#…
zenjabba Sep 22, 2026
81f27dc
fix(ios): close the player when Picture in Picture starts from its bu…
Quick104 Sep 22, 2026
647aa2e
test(apiv2): pin contract fixtures to an explicit server commit (#349)
Quick104 Sep 23, 2026
b3b90a1
refactor(api): share one APIv2Client from SiloAPI (#350)
Quick104 Sep 23, 2026
9fade54
ci: block new /api/v1 paths in app sources (#351)
Quick104 Sep 23, 2026
fc31513
refactor(api): delete dead v1 reads and the unrouted timeline client …
Quick104 Sep 23, 2026
0b6bd88
fix(apiv2): decode v2 models as the server sends them (#353)
Quick104 Sep 23, 2026
2000ee9
chore(tests): delete unused media fixtures (#354)
Quick104 Sep 23, 2026
45315c2
fix(connection): explain v1-only servers instead of reporting them un…
Quick104 Sep 23, 2026
178e9a0
fix(auth): refresh sessions through /api/v2/auth/refresh (#356)
Quick104 Sep 23, 2026
00dba12
fix(connection): probe /api/v1/health without credentials (#357)
Quick104 Sep 23, 2026
e39d74c
feat(auth): validate servers and restored sessions through v2 (#358)
Quick104 Sep 23, 2026
b217760
feat(auth): sign in and sign out through v2 (#359)
Quick104 Sep 23, 2026
f69e854
feat(auth): run tvOS QR sign-in on v2 (#360)
Quick104 Sep 23, 2026
311dca6
feat(pairing): pair devices through v2 (#361)
Quick104 Sep 23, 2026
10cea14
feat(remote): approve and deny SiloRemote handoffs through v2 (#362)
Quick104 Sep 23, 2026
c1e6ee7
fix(settings): drop the v1 string-setting fallback (#363)
Quick104 Sep 23, 2026
678f396
chore(settings): vendor settings contract revision 8 (#364)
Quick104 Sep 23, 2026
5a85ef3
feat(settings): read settings capabilities and effective values from …
Quick104 Sep 23, 2026
dd9db56
feat(settings): write setting values through v2 (#366)
Quick104 Sep 23, 2026
997d706
feat(settings): store subtitle and audio track preferences through v2…
Quick104 Sep 23, 2026
3cef393
feat(settings): read overlay config from v2 (#368)
Quick104 Sep 23, 2026
2eebb40
feat(onboarding): run the onboarding tour on v2 (#369)
Quick104 Sep 23, 2026
3b43e64
feat(downloads): remove downloads saved by earlier versions (#370)
Quick104 Sep 23, 2026
f6c1aa1
feat(progress): upload audiobook and offline progress through v2 sync…
Quick104 Sep 23, 2026
d2281bc
feat(downloads): manage downloads through the v2 registry (#372)
Quick104 Sep 23, 2026
17f3a45
feat(downloads): fetch manifests, assets and files from v2 (#373)
Quick104 Sep 23, 2026
44c1706
feat(downloads): sync download subscriptions through v2 (#374)
Quick104 Sep 23, 2026
9872cec
feat(downloads): re-read watch state from v2 progress (#375)
Quick104 Sep 23, 2026
538076d
feat(playback): share v2 playback capabilities and installation id (#…
Quick104 Sep 23, 2026
7a05523
feat(playback): run video and audiobook sessions and media URLs on v2…
Quick104 Sep 23, 2026
793b22c
feat(playback): open the control socket with a v2 ticket (#378)
Quick104 Sep 23, 2026
37e63c9
feat(home): load home sections and dismissals from v2 (#379)
Quick104 Sep 23, 2026
3d5f933
feat(catalog): load similar and discover rows from v2 (#380)
Quick104 Sep 23, 2026
35a6b17
feat(catalog): move filters, calendar and trailer refresh to v2 (#381)
Quick104 Sep 23, 2026
010d347
feat(catalog): page catalog queries with v2 cursors (#382)
Quick104 Sep 23, 2026
6e666bf
feat(library): browse library sections and collections on v2 (#383)
Quick104 Sep 23, 2026
628ccf0
feat(people): load people and refresh metadata through v2 (#384)
Quick104 Sep 23, 2026
905ba74
feat(lists): page favorites and watchlist from v2 (#385)
Quick104 Sep 23, 2026
017b984
feat(collections): manage personal collections through v2 (#386)
Quick104 Sep 23, 2026
4ebd278
feat(library): read and toggle favorite, watchlist and watched throug…
Quick104 Sep 23, 2026
1856715
feat(profiles): list, create, verify and edit profiles through v2 (#388)
Quick104 Sep 23, 2026
0dfd329
feat(requests): list and submit media requests through v2 (#389)
Quick104 Sep 23, 2026
277dcc7
feat(metadata): read metadata AI status and translate descriptions th…
Quick104 Sep 23, 2026
0860218
feat(subtitles): search, download and manage subtitles on v2 (#391)
Quick104 Sep 23, 2026
2b2a319
feat(subtitles): run AI subtitle jobs on v2 (#392)
Quick104 Sep 23, 2026
a1b29f2
feat(push): register Apple push through v2 (#393)
Quick104 Sep 23, 2026
af820e6
feat(push): fetch notification display data from v2 (#394)
Quick104 Sep 23, 2026
8cb7c53
feat(notifications): sync notification state through v2 (#395)
Quick104 Sep 23, 2026
65a6c74
feat(diagnostics): read diagnostics capabilities from v2 (#396)
Quick104 Sep 23, 2026
feb51c2
feat(diagnostics): upload diagnostics reports through v2 (#397)
Quick104 Sep 23, 2026
44d9989
refactor(networking): delete the v1 transport (#398)
Quick104 Sep 23, 2026
b0a9fd5
ci(discord): post main commits to the Discord commit feed (#400)
Quick104 Sep 23, 2026
f4dc8de
test(apiv2): cover the v2 paths the migration left untested (#401)
Quick104 Sep 23, 2026
536d490
feat(player): add never/ask/always intro skip modes (#399)
Quick104 Sep 23, 2026
9b7fdd1
feat(playback): use profile-wide seek intervals (#402)
Quick104 Sep 23, 2026
4e61efa
feat(watch-party): add iOS and tvOS rooms and synchronized playback (…
Quick104 Sep 24, 2026
5d9dc76
feat(settings): show the Experimental section to everyone
Quick104 Sep 24, 2026
5ef59fa
feat(links): open Watch Party invitations through silo:// links (#412)
Quick104 Sep 24, 2026
80e8099
fix(profiles): serialize profile launch state to stop picker crash (#…
Quick104 Sep 24, 2026
314d9d1
refactor(storage): move persisted continuum identifiers to silo names…
Quick104 Sep 24, 2026
ca6fea3
fix(watch-party): join the start barrier and stop redundant ready res…
neurekadev Sep 25, 2026
f228bd5
fix(watch-party): keep stalls under two seconds local (#424)
neurekadev Sep 25, 2026
1fc38d5
fix(watch-party): converge on the room like the web client (#425)
neurekadev Sep 25, 2026
3d50ab6
feat(siri): open Silo Search from Siri on Apple TV and iPhone (#417)
Quick104 Sep 25, 2026
8f3eb53
fix(detail): land on the watched or next episode after leaving the pl…
neurekadev Sep 25, 2026
44d414d
feat(player): keep TrueHD Atmos heights through Aether's APAC renderi…
Quick104 Sep 25, 2026
02b8f04
chore(deps): pin AetherEngine to the TrueHD Atmos merge commit (#456)
Quick104 Sep 25, 2026
52dd14a
fix(settings): describe TrueHD Atmos as Silo's compressed conversion …
Quick104 Sep 25, 2026
3940d88
fix(watch-party): let the host switch titles and leave a finished pla…
neurekadev Sep 26, 2026
8eb8125
fix(watch-party): converge small drift by rate on direct play (#464)
neurekadev Sep 26, 2026
29716f2
fix(settings): correct the TrueHD Atmos fallback text and oamd notice…
Quick104 Sep 26, 2026
2e3d6d3
fix(player): pick up AetherEngine's TrueHD Atmos sync fix (#494)
Quick104 Sep 26, 2026
ddbde6a
chore(apiv2): resync vendored v2 fixtures to server 83ac7a9 (#496)
Quick104 Sep 26, 2026
b4121bb
feat(audiobooks): build the audiobook detail page from the shared det…
Quick104 Sep 26, 2026
8c29a05
fix(audiobooks): open the player over the detail page and let it swip…
Quick104 Sep 26, 2026
a63c511
fix(detail): keep side swipes inside the tvOS episode carousel (#510)
Quick104 Sep 26, 2026
2f64f3e
fix(ipad): restore sidebar navigation and use tabs outside full scree…
Quick104 Sep 26, 2026
193390a
feat(diagnostics): log how focus leaves the tvOS episode carousel (#517)
Quick104 Sep 27, 2026
543399c
fix(diagnostics): locate SwiftUI focus items so the carousel trace lo…
Quick104 Sep 27, 2026
f142c37
fix(search): show actor and director results on iOS and tvOS (#519)
Quick104 Sep 27, 2026
fb8809d
chore(deps): bump rubyzip from 2.4.1 to 3.4.0 (#455)
dependabot[bot] Sep 27, 2026
10a7732
fix(ios): centre a larger play button and fold rotate/lock into the p…
Quick104 Sep 27, 2026
37dad98
test(ios): accept the glass-tinted play disc colour on iOS 26.2 (#526)
Quick104 Sep 27, 2026
89c015c
fix(detail): drive the tvOS Series episode row with native focus (#522)
Quick104 Sep 27, 2026
7c3a65c
fix(tvos): ignore swipe-tail commands that trigger focus jumps (#523)
Quick104 Sep 27, 2026
85f93d5
fix(player): keep a tvOS timeline scrub from losing focus to the skip…
Quick104 Sep 27, 2026
66f8194
fix(tvos): remove the 700 ms cross-axis gate on swipe-tail commands (…
Quick104 Sep 27, 2026
9affafd
fix: link the privacy policy without a trailing slash (#529)
zZebrahz Sep 27, 2026
01ff70d
build(ci): move release tooling to Ruby 3.3.12 (#530)
Quick104 Sep 27, 2026
a3575f9
fix(ipad): let iPadOS draw the selected sidebar row (#532)
Quick104 Sep 27, 2026
bd255d1
fix(tvos): center the Next Up hero and On Deck row on one column (#535)
Quick104 Sep 28, 2026
fabd444
Merge upstream Silo-Server/silo-apple main into Prairie
Sep 28, 2026
b5b2b45
fix(sync): pin ViewInspector 0.10.3, port Live TV transport and Quick…
Sep 28, 2026
60d5b72
fix(sync): restore Prairie Live TV wiring and trickplay hooks lost in…
Sep 28, 2026
ab58059
fix(sync): build the v2 catalog projection, macOS Live TV lists and C…
JonahMMay Sep 28, 2026
661175f
fix(ci): stub the v2 contract gate on the networking host's Connectio…
JonahMMay Sep 28, 2026
5f4c3a4
fix(ci): drop the removed SubtitleProvidersStatus from the host's Pra…
JonahMMay Sep 28, 2026
103d3e5
fix(ci): match ImageSizeCapability.refresh(retryFailed:) in the host …
JonahMMay Sep 28, 2026
f5e11f3
test(ci): retarget Prairie gate-fill tests at the post-sync session APIs
JonahMMay Sep 28, 2026
917c199
test(ci): run upstream's API v2 tests on the networking host
JonahMMay Sep 28, 2026
4fafde5
test(ci): keep app-bound v2 suites out of the networking host
JonahMMay Sep 28, 2026
e3b080f
test: drop Prairie model tests for the v1 wire types the API v2 sync …
JonahMMay Sep 28, 2026
39643d3
test(ci): follow ServerEntry/settings API changes in the host suites
JonahMMay Sep 28, 2026
7276c5c
test(ci): give the host the value types the v2 catalog suites assert on
JonahMMay Sep 28, 2026
0e32085
test: update Prairie networking tests for upstream's session and regi…
JonahMMay Sep 28, 2026
034c682
test(ci): run more upstream suites on the networking host
JonahMMay Sep 28, 2026
02235ee
test: cover the API v2 catalog read projection
JonahMMay Sep 28, 2026
f0349e4
test: cover API v2 playback models; fix a doubled server URL in a tok…
JonahMMay Sep 28, 2026
f854fe0
test: cover API v2 wire models, catalog queries and progress sync
JonahMMay Sep 28, 2026
974dcc6
ci: exclude the API v2 client transport from the Networking coverage …
JonahMMay Sep 28, 2026
67605d3
test: cover metadata flights, server identity reads and the v2 plan p…
JonahMMay Sep 28, 2026
ddba1a2
test: cover TokenStore's canonical account sessions
JonahMMay Sep 28, 2026
869c8af
test: cover catalog presentation shapes and Watch Party wire models
JonahMMay Sep 28, 2026
49cb0a1
test: cover subtitle search/download models and v2 playback request b…
JonahMMay Sep 28, 2026
8352908
test: build the replan and route-event requests the v2 bodies wrap
JonahMMay Sep 28, 2026
99f8ed3
ci: list the unexecuted Networking lines after the unit-test run
JonahMMay Sep 28, 2026
72ff7b5
test: cover TokenStore and ServerRegistry fail-closed paths
JonahMMay Sep 28, 2026
302f8ec
test: give the failure-suite temporary scope a profile proof
JonahMMay Sep 28, 2026
c250813
ci: keep the uncovered-lines listing from failing the job
JonahMMay Sep 28, 2026
f39d476
test: build the Prairie networking tests in the app test bundles too
JonahMMay Sep 28, 2026
3214a34
fix(livetv): let HTTPClient send Prairie's v1 Live TV routes in debug…
JonahMMay Sep 28, 2026
5e6322a
fix(artwork): keep the signed query when picking a format sibling of …
JonahMMay Sep 28, 2026
572c09c
test: fix Prairie app-bundle tests the regression workflow now runs
JonahMMay Sep 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
53 changes: 53 additions & 0 deletions .github/workflows/ci-scripts.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: CI scripts

on:
pull_request:
paths:
- 'scripts/ci/**'
- 'scripts/sync-apiv2-fixtures*.sh'
- '.github/workflows/ci-scripts.yml'
- 'iosApp/iosApp/**'
- 'iosApp/TopShelf/**'
- 'iosApp/NotificationService/**'
- 'iosApp/DownloadsActivity/**'
- 'iosApp/Tests/**'
push:
branches: [main]
paths:
- 'scripts/ci/**'
- 'scripts/sync-apiv2-fixtures*.sh'
- '.github/workflows/ci-scripts.yml'
- 'iosApp/iosApp/**'
- 'iosApp/TopShelf/**'
- 'iosApp/NotificationService/**'
- 'iosApp/DownloadsActivity/**'
- 'iosApp/Tests/**'
workflow_dispatch:

permissions:
contents: read

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Test release input parsing
run: |
bash scripts/ci/resolve-marketing-version.test.sh
bash scripts/ci/resolve-platform.test.sh
- name: Test release source archive
run: python3 scripts/ci/package-release-source.test.py
- name: Test subtitle packaging validation
run: python3 scripts/ci/validate-subtitle-packaging.test.py
- name: Test API v2 fixture sync
run: bash scripts/sync-apiv2-fixtures.test.sh
- name: Test the /api/v1 path guard
run: bash scripts/ci/check-no-api-v1.test.sh
- name: Block new /api/v1 paths in app sources
run: bash scripts/ci/check-no-api-v1.sh
202 changes: 202 additions & 0 deletions .github/workflows/player-regression.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
name: Apple regression

on:
pull_request:
paths:
- 'iosApp/**'
- '.github/workflows/player-regression.yml'
push:
branches: [main]
paths:
- 'iosApp/**'
- '.github/workflows/player-regression.yml'
workflow_dispatch:
inputs:
baseline_ref:
description: Optional unchanged upstream commit for a comparative iOS run (the tvOS test target may not exist there)
type: string
required: false
record_preview:
description: Also record a synthetic playback clip after a manually requested build
type: boolean
default: false
ios_only:
description: Build and validate only the iOS simulator app for an iOS-only change
type: boolean
default: false

permissions:
contents: read

concurrency:
group: player-regression-${{ github.ref }}-${{ inputs.baseline_ref || 'head' }}
cancel-in-progress: true

jobs:
validate:
runs-on: macos-15
timeout-minutes: 40
strategy:
fail-fast: false
matrix:
include: >-
${{ fromJSON((inputs.ios_only || inputs.baseline_ref) &&
'[{"scheme":"Prairie","destination":"platform=iOS Simulator,name=iPhone 17 Pro","action":"test","platform":"iOS","test_target":"PrairieTests"}]' ||
'[{"scheme":"Prairie","destination":"platform=iOS Simulator,name=iPhone 17 Pro","action":"test","platform":"iOS","test_target":"PrairieTests"},
{"scheme":"PrairieTV","destination":"platform=tvOS Simulator,name=Apple TV 4K (3rd generation)","action":"test","platform":"tvOS","test_target":"PrairieTVTests"},
{"scheme":"PrairieMac","destination":"generic/platform=macOS","action":"build"}]') }}
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
ref: ${{ inputs.baseline_ref || github.sha }}
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '26.3'
- name: Prepare simulator
if: matrix.action == 'test'
timeout-minutes: 10
shell: bash
env:
PLATFORM: ${{ matrix.platform }}
run: |
set -euo pipefail
# Hosted images do not always have a usable pre-created device.
# Match the selected Xcode SDK and reuse one explicit destination.
# iOS and tvOS differ only in SDK name, runtime prefix, and device.
case "$PLATFORM" in
iOS)
sdk=iphonesimulator
runtime_prefix=com.apple.CoreSimulator.SimRuntime.iOS-
device_type=com.apple.CoreSimulator.SimDeviceType.iPhone-17-Pro
destination_platform="iOS Simulator"
;;
tvOS)
sdk=appletvsimulator
runtime_prefix=com.apple.CoreSimulator.SimRuntime.tvOS-
device_type=com.apple.CoreSimulator.SimDeviceType.Apple-TV-4K-3rd-generation-4K
destination_platform="tvOS Simulator"
;;
*)
echo "::error::Unknown simulator platform $PLATFORM"
exit 1
;;
esac
runtime_version=$(xcrun --sdk "$sdk" --show-sdk-version)
find_runtime() {
xcrun simctl list runtimes --json | jq -r --arg version "$runtime_version" --arg prefix "$runtime_prefix" \
'[.runtimes[] | select(.isAvailable and .version == $version and
(.identifier | startswith($prefix)))][0].identifier // empty'
}
runtime_id=$(find_runtime)
if [ -z "$runtime_id" ]; then
xcodebuild -downloadPlatform "$PLATFORM" -buildVersion "$runtime_version"
runtime_id=$(find_runtime)
fi
if [ -z "$runtime_id" ]; then
echo "::error::No available $PLATFORM $runtime_version simulator runtime"
exit 1
fi
simulator_id=$(xcrun simctl create "Prairie-Player-Regression-$PLATFORM" \
"$device_type" "$runtime_id")
echo "PRAIRIE_SIMULATOR_ID=$simulator_id" >> "$GITHUB_ENV"
echo "PRAIRIE_TEST_DESTINATION=platform=$destination_platform,id=$simulator_id" >> "$GITHUB_ENV"
xcrun simctl boot "$simulator_id"
xcrun simctl bootstatus "$simulator_id" -b
- name: Generate Xcode project
run: |
set -euo pipefail
curl -fsSL -o /tmp/xcodegen.zip https://github.com/yonaskolb/XcodeGen/releases/download/2.43.0/xcodegen.zip
# Pin the official 2.43.0 release asset before unpacking/executing it.
echo "a4847ed77d3341a4d24049bc4424a3babca4c94ff1dcaaee923eaca2b32c678f /tmp/xcodegen.zip" | shasum -a 256 -c -
unzip -q /tmp/xcodegen.zip -d /tmp/xcodegen-dist
/tmp/xcodegen-dist/xcodegen/bin/xcodegen generate --spec iosApp/project.yml
- name: Build player
id: build
env:
SCHEME: ${{ matrix.scheme }}
DESTINATION: ${{ matrix.destination }}
ACTION: ${{ matrix.action }}
run: |
set -o pipefail
if [ "$ACTION" = test ]; then
# Simulator-only ad-hoc signing supplies the application identifier
# required by Keychain. No certificate or release secret is used.
xcodebuild build-for-testing -project iosApp/Prairie.xcodeproj -scheme "$SCHEME" \
-destination "$PRAIRIE_TEST_DESTINATION" -derivedDataPath /tmp/prairie-derived \
CODE_SIGNING_ALLOWED=YES CODE_SIGN_IDENTITY=- | tee /tmp/player-build.log
else
xcodebuild build -project iosApp/Prairie.xcodeproj -scheme "$SCHEME" \
-destination "$DESTINATION" -derivedDataPath /tmp/prairie-derived \
-resultBundlePath /tmp/player-validation.xcresult \
CODE_SIGNING_ALLOWED=NO | tee /tmp/player-validation.log
fi
- name: Package simulator tests for focused visual verification
if: matrix.action == 'test' && matrix.platform == 'iOS' && !inputs.baseline_ref
run: ditto -c -k --keepParent /tmp/prairie-derived/Build/Products /tmp/Prairie-simulator-tests.zip
- name: Upload compiled simulator tests
if: matrix.action == 'test' && matrix.platform == 'iOS' && !inputs.baseline_ref
uses: actions/upload-artifact@v4
with:
name: Prairie-simulator-tests
path: /tmp/Prairie-simulator-tests.zip
retention-days: 3
- name: Run complete simulator suite
if: matrix.action == 'test'
timeout-minutes: 12
env:
SCHEME: ${{ matrix.scheme }}
TEST_TARGET: ${{ matrix.test_target }}
run: |
set -o pipefail
xcodebuild test-without-building -project iosApp/Prairie.xcodeproj -scheme "$SCHEME" \
-destination "$PRAIRIE_TEST_DESTINATION" -derivedDataPath /tmp/prairie-derived \
-only-testing:"$TEST_TARGET" \
-parallel-testing-enabled NO \
-test-timeouts-enabled YES -maximum-test-execution-time-allowance 60 \
-resultBundlePath /tmp/player-validation.xcresult \
CODE_SIGNING_ALLOWED=YES CODE_SIGN_IDENTITY=- | tee /tmp/player-validation.log
- name: Record synthetic preview expansion and successor playback
if: matrix.action == 'test' && matrix.platform == 'iOS' && !inputs.baseline_ref && steps.build.outcome == 'success' && !cancelled() && github.event_name == 'workflow_dispatch' && inputs.record_preview
timeout-minutes: 10
shell: bash
run: |
set -euo pipefail
# Reuse the compiled test bundle. This records only the bounded
# synthetic-video test, not a second build or the full test suite.
# XCTest can shut down the simulator after the full suite. Boot the
# exact recording destination before starting the recorder.
simulator_id="$PRAIRIE_SIMULATOR_ID"
simulator_state=$(xcrun simctl list devices available --json | jq -r \
--arg id "$simulator_id" '.devices[][] | select(.udid == $id) | .state')
if [ "$simulator_state" != Booted ]; then
xcrun simctl boot "$simulator_id"
fi
xcrun simctl bootstatus "$simulator_id" -b
xcrun simctl io "$simulator_id" recordVideo /tmp/preview-transition.mp4 &
recorder_pid=$!
trap 'kill -INT "$recorder_pid" 2>/dev/null || true; wait "$recorder_pid" || true' EXIT
xcodebuild test-without-building -project iosApp/Prairie.xcodeproj -scheme Prairie \
-destination "platform=iOS Simulator,id=$simulator_id" \
-derivedDataPath /tmp/prairie-derived \
-parallel-testing-enabled NO \
-destination-timeout 60 \
-test-timeouts-enabled YES -maximum-test-execution-time-allowance 60 \
-only-testing:PrairieTests/PlayerSurfaceLayoutTests/testPlayingPreviewExpandsWithoutReplacingItemOrLosingItsLayer \
-resultBundlePath /tmp/preview-recording.xcresult CODE_SIGNING_ALLOWED=YES CODE_SIGN_IDENTITY=-
kill -INT "$recorder_pid"
wait "$recorder_pid"
trap - EXIT
test -s /tmp/preview-transition.mp4
- name: Upload validation evidence
if: always()
uses: actions/upload-artifact@v4
with:
name: player-validation-${{ matrix.scheme }}
path: |
/tmp/player-build.log
/tmp/player-validation.log
/tmp/player-validation.xcresult
/tmp/preview-transition.mp4
/tmp/preview-recording.xcresult
retention-days: 7
60 changes: 60 additions & 0 deletions .github/workflows/release-source.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: Publish release source

on:
workflow_call:
inputs:
release_tag:
required: true
type: string
outputs:
source_url:
value: ${{ jobs.source.outputs.source_url }}

permissions:
contents: write

concurrency:
group: release-source-${{ inputs.release_tag }}
cancel-in-progress: false

jobs:
source:
runs-on: ubuntu-latest
outputs:
source_url: ${{ steps.publish.outputs.source_url }}
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Package exact app and library sources
run: python3 scripts/ci/package-release-source.py "$RUNNER_TEMP/release-source"
- name: Publish source before distributing binaries
id: publish
env:
GH_TOKEN: ${{ github.token }}
RELEASE_TAG: ${{ inputs.release_tag }}
run: |
set -euo pipefail
if ! gh release view "$RELEASE_TAG" >/dev/null 2>&1; then
# The sideload workflow may create the same tag's release first.
FLAGS=()
if [[ "$RELEASE_TAG" == source-* ]]; then FLAGS+=(--latest=false); fi
gh release create "$RELEASE_TAG" --target "$GITHUB_SHA" \
--title "$RELEASE_TAG" \
"${FLAGS[@]}" \
--notes "Release source and rebuild instructions are in the Prairie-source archive." \
|| gh release view "$RELEASE_TAG" >/dev/null
fi
IS_DRAFT="$(gh release view "$RELEASE_TAG" --json isDraft --jq '.isDraft')"
if [[ "$IS_DRAFT" == "true" ]]; then
echo "::error::Source release $RELEASE_TAG is a draft. Publish it before distributing binaries."
exit 1
fi
ASSET="Prairie-source-${GITHUB_SHA}.tar.gz"
gh release upload "$RELEASE_TAG" "$RUNNER_TEMP/release-source/$ASSET" --clobber
SOURCE_URL="$(gh release view "$RELEASE_TAG" --json assets --jq ".assets[] | select(.name == \"$ASSET\") | .url")"
test -n "$SOURCE_URL"
echo "source_url=$SOURCE_URL" >> "$GITHUB_OUTPUT"
17 changes: 13 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ concurrency:
group: testflight-release
cancel-in-progress: false

# Least privilege: the jobs only check out code and talk to Apple via the ASC
# API key. They never use GITHUB_TOKEN to write to the repo.
# Apple build jobs only read the repository. The source publication job gets
# contents: write so it can attach rebuild sources before binary distribution.
permissions:
contents: read

Expand All @@ -38,6 +38,13 @@ env:
TESTFLIGHT_NOTIFY_EXTERNAL_TESTERS: "true"

jobs:
source:
permissions:
contents: write
uses: ./.github/workflows/release-source.yml
with:
release_tag: ${{ github.event_name == 'push' && github.ref_name || format('source-{0}', github.sha) }}

# Resolve the target platform from either the dispatch input or the tag's
# +ios / +tvos build-metadata suffix, so both trigger paths share one gate.
setup:
Expand Down Expand Up @@ -84,7 +91,7 @@ jobs:
BUILD_NUMBERS_FILE="$GITHUB_OUTPUT" bundle exec fastlane ios reserve_build_numbers

ios:
needs: [setup, build-numbers]
needs: [setup, build-numbers, source]
# Skip only when the selection is tvOS-only. 'both' and 'ios' both run iOS.
# No status function in the if -> implicit success() gate on needs, so a
# failed build-numbers job skips this build.
Expand Down Expand Up @@ -139,13 +146,14 @@ jobs:
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
APP_STORE_CONNECT_API_KEY_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY }}
TESTFLIGHT_EXTERNAL_GROUPS: ${{ secrets.TESTFLIGHT_EXTERNAL_GROUPS }}
PRAIRIE_RELEASE_SOURCE_URL: ${{ needs.source.outputs.source_url }}

tvos:
# No longer needs: ios — build numbers are reserved up front, so tvOS runs in
# parallel with iOS rather than after it. (Trade-off: on a both run, tvOS now
# releases even if iOS fails; the platforms' build-number sequences are
# independent, so a gap is harmless.)
needs: [setup, build-numbers]
needs: [setup, build-numbers, source]
# Skip only when the selection is iOS-only. Implicit success() gate on needs.
if: ${{ needs.setup.outputs.platform != 'ios' }}
runs-on: macos-15
Expand Down Expand Up @@ -198,3 +206,4 @@ jobs:
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
APP_STORE_CONNECT_API_KEY_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY }}
TESTFLIGHT_EXTERNAL_GROUPS: ${{ secrets.TESTFLIGHT_EXTERNAL_GROUPS }}
PRAIRIE_RELEASE_SOURCE_URL: ${{ needs.source.outputs.source_url }}
13 changes: 11 additions & 2 deletions .github/workflows/sideload-ipa.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,22 @@ jobs:
gh release create "$TAG" \
--target "$GITHUB_SHA" \
--title "$TITLE" \
--notes "Unsigned iOS/tvOS IPAs for third-party signing / sideloading. See docs/release/sideloading.md."
--notes "Unsigned iOS/tvOS IPAs for third-party signing / sideloading. See docs/release/sideloading.md. The Prairie-source archive contains the matching source and rebuild instructions." \
|| gh release view "$TAG" >/dev/null
fi
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
echo "Releasing as $TAG (build $BUILD)"

source:
needs: release
permissions:
contents: write
uses: ./.github/workflows/release-source.yml
with:
release_tag: ${{ needs.release.outputs.tag }}

build:
needs: [setup, release]
needs: [setup, release, source]
runs-on: macos-15
# Only the release-upload step (tag builds) needs write; scope it to the job
# rather than the whole workflow to keep the rest at least privilege.
Expand Down
Loading
Loading