Skip to content

feat(Throw): add ceiling flight projection app - #293

Open
kyleve wants to merge 130 commits into
mainfrom
codex/throw-v1
Open

feat(Throw): add ceiling flight projection app#293
kyleve wants to merge 130 commits into
mainfrom
codex/throw-v1

Conversation

@kyleve

@kyleve kyleve commented Aug 25, 2026

Copy link
Copy Markdown
Owner

Posted by an AI agent on kve's behalf.

Summary

  • Add Throw, an iPhone and iPad app that projects live aircraft onto a ceiling, external display, or on-device preview.
  • Provide geographic Map and altitude-aware True Sky projection modes with one shared calibration model.
  • Support adsb.lol, local readsb, ADS-B Exchange Personal through RapidAPI, and Flightradar24.
  • Add offline geography, regional Map centers, aircraft silhouettes, route labels, motion prediction, quiet hours, onboarding, and source diagnostics.
  • Harden the original implementation for a real personal beta with typed launch, persistence, source, projection, and lifecycle state.
  • Add bounded TLA+ models for the concurrent state machines that cannot be proved by Swift's type system alone.

Product behavior

  • Map uses great-circle distance and bearing around a selected regional center. A dim observer ring preserves the actual location.
  • True Sky uses WGS84 ECEF and ENU geometry to derive aircraft azimuth and elevation.
  • Preview, full-screen output, and external displays use the same opaque-black projection surface.
  • Quiet standby keeps output black and stops physical polling. Foreground output demand controls the idle timer and polling lifecycle.
  • Cloud sources receive a center rounded to 0.1 degrees. Throw applies exact local filtering after every response.
  • Throw never changes providers automatically after a failure and never combines observations from different source contexts.
  • One playlist controls every output. Air & Space is the only runnable View in this release; Transit remains planned and unavailable.

Shipping hardening

  • The process now owns one typed cold-launch state and gates every controller and projection surface until preferences and credentials load.
  • Controller-scene lifecycle is aggregated across windows. External-display scenes affect output demand but cannot impersonate controller foreground state.
  • Final-background preference flushing waits for active mutations and admitted async producers, retains an iOS background lease, and handles cancellation.
  • Source, observer, onboarding, and ordinary preference changes use failure-atomic transactions with retry or compensating publication behavior.
  • Source and observer context changes retire the exact coordinator lease, invalidate staged frames, and mint a fresh lease when demand remains.
  • Geography-only and layer-disabled states suspend physical polling without destroying the coordinator's experience lease.
  • Polling publications carry an exact activation token and a strictly increasing per-token revision. Delayed updates cannot be relabeled or regress state.
  • Prepared transitions carry one typed context generation. Old prepare, fade, commit, and completion callbacks cannot publish after invalidation.
  • Durable logging attaches once at process composition. Typed pre-attachment failures remain available for postmortem diagnostics.
  • The privacy manifest declares the required UserDefaults reason, and a built-product test verifies the shipped declaration.

Compiler-proved boundaries

  • Stored preferences remain validated domain aggregates. Views commit raw drafts only after validation succeeds.
  • Source validation uses closed credential-free and credential-bearing requests. Unsupported secret and provider combinations cannot compile.
  • Runnable projection identity is closed. Production code cannot make planned Transit executable through a catalog or playlist shortcut.
  • Semantic and projected layer frames carry exact element and line-style families. Aircraft, stars, satellites, Geography, Transit routes, and vehicles cannot cross families.
  • Prepared Transit network data pairs its source revision with its projected frame in one value.
  • Production rendered projections require a coordinator lease and keep semantic input, projected output, observer context, effects, and health in one atomic state.
  • Projected frame erasure occurs once at the ThrowUI presentation boundary. Bumper Bowling guards this boundary and the runtime composition rules.

These changes follow Where's main architecture patterns: create shared resources once, inject them, publish closed state, and keep persistence behind typed transactions.

Formal verification

The PR adds five Throw concerns to the repository's pinned TLC runner. Each concern includes historical broken controls and anti-vacuity reachability checks.

  • ProjectionActivation checks scene demand, quiet and calibration gates, coordinator leases, context renewal, physical polling suspension, stale teardown, and convergence.
  • PreferenceTransactions checks source and observer commits, credential alignment, retry behavior, exact lease retirement, delayed callbacks, and observer/frame consistency.
  • ProjectionContextTransition checks prepared context invalidation, the black-only frame exchange, exact semantic/projected pairing, and writer exclusion during fade-in.
  • PollingPublication checks exact Core tokens, per-token revision order, recovery reads, stale frame rejection, query replacement, and final deactivation.
  • BackgroundPreferencePersistence checks producer admission, quiescent flush completion, cancellation-aware waiters, retry work, and controller-scene lifecycle generations.

All current configurations are verified for their documented finite bounds and assumptions. Every broken control fails its named current invariant.

Compatibility and rollout

  • Throw uses a separate persistence domain. This change does not modify Where data, backups, or CloudKit data.
  • Version-one Throw preferences migrate to the current typed format without repeating onboarding.
  • Existing RapidAPI and Flightradar24 Keychain identifiers remain unchanged.
  • Invalid preferences enter setup repair. Missing credentials never trigger provider fallback.
  • This PR targets a personal beta. Throw/TODOs.md retains the required physical projector, provider-contract, iOS 27 GM, and overnight acceptance work.
  • Public distribution still requires provider authorization and a provider-approved credential architecture.

Review focus

  • Review exact lease renewal across source, observer, quiet, calibration, layer, and scene changes.
  • Review source cancellation, polling token/revision acceptance, and physical polling suspension.
  • Review preference transaction compensation and the final-background quiescence barrier.
  • Review atomic visible projection publication and frame exchange at black.
  • Review typed source, runnable catalog, layer-family, and presentation-erasure boundaries.
  • Review the documented TLA+ source correspondence, assumptions, exclusions, and broken controls.

Testing

  • ./test --everything --review — passed: 2,470 iOS unit tests and all 61 snapshot suites.
  • ./test --no-generate ThrowCoreTests ThrowUITests — passed: 466 tests.
  • ./test --no-generate ThrowTests — passed: 17 tests.
  • ./test --no-generate ThrowUISnapshotTests --review — passed: 13 tests with byte-for-byte matching captures.
  • ./test --architecture-only — passed: 30 rule tests and no violations.
  • ./tla-check ProjectionActivation — passed all 31 cases; largest current bound explored 82,983 generated states.
  • ./tla-check PreferenceTransactions — passed all 13 cases; largest current bound explored 181,368 generated states.
  • ./tla-check ProjectionContextTransition — passed all 13 cases; largest current bound explored 102,734 generated states.
  • ./tla-check PollingPublication — passed all 14 cases; largest current bound explored 79,350 generated states.
  • ./tla-check BackgroundPreferencePersistence — passed all 7 cases; largest reachability bound explored 5,122,617 generated states.
  • TLA tooling tests — passed: 16 Python tests and 7 Ruby tests with 68 assertions.
  • ./swiftformat --lint, ./sf-symbols --lint, ./xcstrings --lint, ./shellcheck, and ./attribution --check — passed.
  • git diff --check — passed.

Add the iOS 26 Throw app, typed projection and layer foundations, explicit ADS-B providers including user-owned RapidAPI credentials, shared external-display runtime, controller experience, and deterministic test coverage.
guard externalDisplayRegistration == nil else { return }

let configuration = Self.externalDisplayConfiguration()
let accessory = UISceneAccessory.externalNonInteractive(

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Posted by an AI agent on kve’s behalf.

Review focus: this registration path compiles against the installed iOS 27 beta SDK, but the final UISceneAccessory lifecycle contract still needs GM-SDK and physical connect/disconnect plus controller-window recreation validation. That release gate is recorded in Throw/TODOs.md.

kyleve added 17 commits August 24, 2026 19:56
Treat the always-available on-device output as ready when selected, while retaining preview-opened state as informational feedback. Show the full-screen Exit control on entry, keep it available to VoiceOver, and cover both behaviors with unit and image snapshots.
Add a macOS command that builds, signs, installs, and launches Throw on an exact paired iPhone or iPad. Preserve the Where installer safety contract with shared fake-device coverage, dependency-free help, a non-mutating dry run, and documented signing setup.
Keep the on-device projection escape control in the tree instead of auto-hiding it behind an undiscoverable tap target. Use a large persistent button and the standard accessibility escape action.
Avoid the iOS 27 Label-inside-LabeledContent layout bug that greedily expands a wrapped status value. Mirror the established device-status workaround with an explicit HStack and a decorative accessibility-hidden symbol.
Commit Xcode’s extracted CFBundleName entry alongside the manually authored Throw Info.plist strings so catalog extraction remains stable.
Replace the coarse v1 map with a deterministic v2 archive generated from pinned Natural Earth 1:10m and 2025 Census boundary and primary-road sources.

Add typed wide, standard, and local detail tiers; source provenance; bounded path densification; cancel-safe shared loading; and category-specific dim rendering behind aircraft. Update documentation, generator coverage, Core/UI tests, and reviewed snapshots.
Replace the tiny aircraft and hairline arc with a larger aircraft and bold projection ribbon. Keep the opaque black field, warm-white mark, and safe margins for small Home Screen sizes.
Render projection labels in a smaller monospaced style at reduced luminance so aircraft marks remain the primary visual signal. Update projection snapshots and guard the styling relationship with a focused unit test.
@kyleve kyleve changed the title feat(Throw): add ceiling flight projection app [NO-CI] feat(Throw): add ceiling flight projection app Aug 25, 2026
kyleve added 10 commits August 25, 2026 13:25
Add FR24 position and inline route decoding, device-only credential settings, cadence controls, onboarding, dashboard status, and provider-specific failure handling. Normalize route availability across providers so unresolved aircraft dim consistently, and filter FR24 ground positions through the shared ground-aircraft policy. Refine projection label prominence and document flight-activity cues in Projection Appearance.
kyleve added 30 commits August 31, 2026 23:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant