Skip to content

feat(Where): add independent stays and configurable forecasts - #316

Open
kyleve wants to merge 4 commits into
mainfrom
codex/planned-stay-itinerary
Open

kyleve wants to merge 4 commits into
mainfrom
codex/planned-stay-itinerary

Conversation

@kyleve

@kyleve kyleve commented Sep 14, 2026

Copy link
Copy Markdown
Owner

Posted by an AI agent on the user's behalf.

Summary

  • User-facing: Plan independent stays in any supported region, with exact dates or flexible arrival and last-day windows. Edit completed plans, see overlap warnings, and choose Past travel pattern or one Home region for unplanned days.
  • User-facing: Show annual day and percentage ranges, planned destinations with no recorded visits, and distinct planned, possible, and Home presence in Calendar and Timeline. Future itinerary years remain selectable. Hiding estimates preserves the itinerary and Home choice.
  • Internal: Resolve revisions and deletion tombstones per stay, persist Home in a separate generation-scoped register, and carry both through SwiftData, Inspector, reset, and backup imports.
  • Internal: Connect the planning screens in the developer diagram and draw navigation lines in bounded, visible sections so the expanded catalog stays within iOS texture limits.

Why

The previous planner could only extend the current stay. It could not account for later return trips or a user's expected home between trips. Independent dates make those estimates editable without changing automatic tracking or recorded history.

Design decisions

Forecasts count unique recorded region/day pairs through today, then project tomorrow through December 31. For each region, the lower bound uses its shortest stays and other regions' longest stays; the upper bound reverses those choices. Each region deduplicates overlapping days. Historical forecasts retain the April 1 threshold; Home forecasts are available from January 1.

App-shell image fixtures use independent report models for each display configuration and await the ordinary activation path before capture. Their initial data matches the store that activation reads. A fixed January clock keeps welcome-overlay captures independent of long-calendar scroll positioning.

The planning snapshot belongs to the scene. Once a read starts, closing its requesting sheet does not discard its success or failure. Already-cancelled requests do not supersede an active read, and older completions cannot overwrite newer results.

Range endpoints describe possible choices of entered dates, without probability claims. Planned and gap component bounds can arise from different date choices and cannot be added endpoint by endpoint. Annual estimates remain limited to the current year.

Review focus

  • Opposite-extrema range calculation and cancellation when a flexible stay is in Home.
  • Independent last-writer ordering, stale deletion imports, Home nil revisions, and generation reset isolation.
  • Calendar and Timeline distinguish projections from recorded presence, including VoiceOver descriptions and individual stay identity.
  • Flyover keeps one graph coordinate system across drawing sections to preserve line continuity, modal dashes, and labels.

⚠️ Breaking changes

Backup format v6 and the SwiftData planning shape replace the singular stay register. There is no in-app migration of the previous store shape.

Compatibility

Export before upgrading the app, run Where/Tools/upgrade-backup.rb on the archive, and replace-import the upgraded archive. Update every syncing installation before editing plans: older builds can delete independent stays through their whole-register operation.

Legacy revisions share one reserved stay ID. Conversion preserves revision UUIDs, timestamps, and tombstones, and derives exact arrival from the revision's UTC Gregorian update day, capped at its existing last day.

Testing

  • After merging origin/main (537fadc0), ./test WhereCoreTests WhereUITests: 1,141 tests passed, plus architecture checks and 13 backup-upgrader tests (39 assertions). The merge adopts Xcode build 27A266a and connects the app-wide welcome action to the independent-stay editor.
  • After the merge, LocationsView, PlannedStayEditor, and RootView snapshot suites passed in the focused four-suite run. ./test --snapshots --only WhereUISnapshotTests/MainTabsSnapshotTests --no-generate --no-build --review then passed all 16 captures after reviewing and recording 15 updated references. The welcome fixtures use a fixed January clock and independent models for each display configuration.
  • ./test --no-generate WhereUITests: 503 tests passed after the cancellation fix. The three new gated regressions first failed against the previous implementation and now pass. They cover cancellation before a read starts, cancellation during a successful read, cancellation during a failed read, and rejection of stale completions.
  • ./test --all: 2,049 tests passed. Includes architecture configuration/rule tests/lint and backup-upgrader regressions.
  • ./test --no-generate --no-build WhereUITests: 502 tests passed after the presentation fixes.
  • Offline upgrader regression: 13 tests, 39 assertions passed, including deterministic legacy identities, UTC Gregorian dates, tombstones, and asset preservation.
  • upgrade_and_verify.rb on a synthetic v5 ZIP: archive integrity and preservation checks passed; the upgraded v6 archive loaded through the real BackupService.readArchive test.
  • ./test --snapshots --only-file /tmp/planned-stays-snapshot-suites.txt --no-generate --no-build --review: all 10 suites passed in 7m7s. Scope: CalendarContentView, EstimatedTimeFeaturesView, LocationsView, ManualDayView, PlannedStayEditor, PlannedStaysView, PlanningRegionPickerView, PresenceTimelineList, RootView, and YearView snapshot suites. Reviewed light/dark, iPad, accessibility text, VoiceOver annotations, empty/multiple/flexible/overlapping plans, Home mode, and future-year navigation.
  • ./test --only FlyoverTests --only WhereUITests/WhereFlyoverCatalogTests --no-generate: 48 tests passed, including bounded drawing coverage and stable tile identities.
  • ./test --snapshots --only FlyoverSnapshotTests/FlyoverSnapshotTests --only WhereUISnapshotTests/WhereFlyoverViewSnapshotTests --no-generate --no-build --review: both suites passed. Reviewed the restored Where connectors and tile boundaries; all five shared captures remain unchanged. No drawing-texture allocation errors remain.
  • ./test --snapshots --only WhereUISnapshotTests/DeveloperOverlaySnapshotTests --no-generate --review: passed after the prior CI measurement timeout; no reference changes.
  • NYC acceptance case passes exactly: New York 94–105 days and California 260–271 days.
  • ./swiftformat --lint, ./sf-symbols --lint, ./xcstrings --lint, and git diff --check: passed.
  • Live VoiceOver and physical-device interaction were not exercised; accessibility verification uses the rendered semantic annotations and model tests.

Backlog reconciliation

Fixed and archived the existing calendar date clipping and YearView accessibility-width issues. Retained the existing Elsewhere inflection and bounded welcome-capture issues. Filed intermittent initial calendar positioning observed in app-shell snapshots for separate investigation. Filed the pre-existing native iPad Save-button glass capture artifact, which also appears in the old editor reference and does not improve with extra settling.

Replace the singular stay register with independently revised itineraries and a separate Home policy. Add exact and flexible date editing, current-year range forecasts, calendar and timeline projections, and v6 backup conversion with deterministic legacy identity.

Validated with 2,049 unit tests, a 502-test UI follow-up, 13 backup-upgrader regressions, the real backup loader, architecture checks, and visual review. Final snapshot assertion run is in progress against the reviewed references.
Draw graph connectors in bounded, viewport-filtered surfaces so the planned
stay screens cannot push the drawing texture beyond iOS allocation limits.
Keep graph coordinates across sections to preserve curves, labels and dashes.
Connect Locations to the planner and editor in the developer catalog.

Add coverage for the previously failing graph size, fractional edges, stable
identities and complete coverage. Refresh the reviewed Where graph reference.
Keep the scene's latest planning read eligible to publish after its requesting
sheet is cancelled. Reject already-cancelled requests before they supersede
active work, and preserve sequence ordering for success and failure results.

Add deterministic gated regressions for cancelled initial success, cancelled
refresh failure with retained data, and already-cancelled callers. All three
fail against the previous implementation.
Preserve app-wide region welcomes and route their planning shortcut to the independent-stay editor. Adopt main's Xcode pin and typed location results.

Resolve documentation and obsolete welcome snapshot conflicts. Give app-shell captures consistent per-configuration data and await activation before capture.

Validation: 1,141 WhereCore/WhereUI tests, architecture checks, and 13 backup-upgrader tests passed. LocationsView, PlannedStayEditor, RootView, and MainTabs snapshot suites passed; reviewed updated MainTabs references. SwiftFormat, symbol, and string-catalog lints passed.
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