Skip to content

Build out the Where tax tracking app#6

Open
kyleve wants to merge 5 commits intomainfrom
feat/where-tax-tracking-app
Open

Build out the Where tax tracking app#6
kyleve wants to merge 5 commits intomainfrom
feat/where-tax-tracking-app

Conversation

@kyleve
Copy link
Copy Markdown
Owner

@kyleve kyleve commented Apr 7, 2026

Summary

  • build out the Where app foundation with ledger-driven tax-day modeling, local persistence, and background location tracking bridges
  • add manual correction, evidence, and export workflows including share/preview support and richer PDF/plaintext reporting
  • polish the manual screen with day grouping, outcome-change highlighting, and report activity state backed by focused tests

Test plan

  • swift build
  • ./ide
  • xcodebuild -workspace Stuff.xcworkspace -scheme WhereCoreTests -destination 'platform=iOS Simulator,name=iPhone 17' test
  • xcodebuild -workspace Stuff.xcworkspace -scheme WhereDataTests -destination 'platform=iOS Simulator,name=iPhone 17' test
  • xcodebuild -workspace Stuff.xcworkspace -scheme Where -destination 'platform=iOS Simulator,name=iPhone 17' build
  • xcodebuild -workspace Stuff.xcworkspace -scheme Stuff-Workspace -destination 'platform=iOS Simulator,name=iPhone 17' -only-testing:WhereTests test
  • xcodebuild -workspace Stuff.xcworkspace -scheme WhereUITests -destination 'platform=iOS Simulator,name=iPhone 17' test

Made with Cursor


Note

High Risk
High risk because it introduces background location tracking, scheduled background refresh, local persistence, and notification scheduling—areas prone to privacy, battery, and data integrity issues.

Overview
Builds out the Where app foundation by introducing a new WhereData module and expanding WhereCore with domain models/protocols for location samples, jurisdictions, manual entries/evidence, sync checkpoints, and tracking state.

Adds ledger-based policies (TaxDayCalculator, YearLedgerBuilder) plus controllers for year progress snapshots, exporting (plaintext + generated PDF), manual entry/evidence import (including package manifests/backfill), reset, sync checkpoints, and background tracking state management backed by JSON-on-disk repositories.

Wires the iOS app to run background location monitoring and app refresh (CLLocationManager bridge, BGTaskScheduler coordinator), schedules gap notifications, updates Info.plist for background modes/location usage, and adds new UI surfaces (dashboard/history/manual entry helpers) with extensive new WhereCoreTests/WhereDataTests and updated project/package configuration (new product/target, macOS platform, shared test scheme).

Reviewed by Cursor Bugbot for commit 60d1a5e. Bugbot is set up for automated code reviews on this repo. Configure here.

kyleve added 5 commits April 6, 2026 19:51
Explain the app's purpose and day-counting model so the feature-level instructions capture the domain context as well as the project layout.

Made-with: Cursor
Add the Where data module, shared UI test scheme, and the first day-level ledger model so the app can render a real dashboard from mergeable tracked and manual state records.

Made-with: Cursor
Wire the app through local storage, background location monitoring, and evidence-backed corrections so the initial Where experience can track tax days end to end.

Made-with: Cursor
Make it easier to backfill historical travel and recover from confusing local state by adding bulk/package manual imports alongside an in-app data reset path.

Made-with: Cursor
@kyleve
Copy link
Copy Markdown
Owner Author

kyleve commented Apr 8, 2026

cursor review

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 60d1a5e. Configure here.


guard
let administrativeArea = placemark.administrativeArea,
let state = USState(rawValue: administrativeArea.uppercased())
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Reverse geocoder always returns unknown for US states

High Severity

CLPlacemark.administrativeArea returns full state names like "California" or "New York", but USState(rawValue:) expects two-letter abbreviations like "CA" or "NY". Calling .uppercased() on the full name produces "CALIFORNIA", which never matches any USState raw value. Every US location will resolve to .unknown, making automatic jurisdiction tracking completely non-functional.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 60d1a5e. Configure here.

}

self?.handle(refreshTask)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Background task never completed when self is nil

Medium Severity

In the register closure, if self is nil when the background task fires, self?.handle(refreshTask) silently no-ops without ever calling setTaskCompleted on the task. The system expects every delivered BGTask to be completed; failing to do so can cause the OS to throttle or stop scheduling future background refresh tasks for this app.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 60d1a5e. Configure here.

@kyleve
Copy link
Copy Markdown
Owner Author

kyleve commented Apr 8, 2026

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 60d1a5e2b8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +35 to +37
await attachmentRepository.save(attachment)
await fileStore.save(data, for: attachment)
return attachment
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Verify single evidence writes before returning success

importEvidence(manualEntryID:...) saves attachment metadata first and then unconditionally returns the new attachment without confirming the blob write succeeded. If the file write fails (for example due to disk/full I/O issues), callers still see a successful import, but the attachment becomes unreadable later and the repository contains dangling metadata; this silently corrupts evidence state.

Useful? React with 👍 / 👎.

Comment on lines +195 to +196
let candidateURL = evidenceDirectory.appending(path: filename)
if FileManager.default.fileExists(atPath: candidateURL.path) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Validate manifest evidence paths stay in package scope

Package evidence filenames are used directly with evidenceDirectory.appending(path: filename) and accepted based only on fileExists, so a manifest entry like ../secret.txt is treated as valid evidence. That allows path traversal outside the intended evidence/ folder (and potentially outside the package directory) and imports unintended local files.

Useful? React with 👍 / 👎.

Comment on lines +18 to +21
let interval = max(request.deliverAt.timeIntervalSinceNow, 1)
let trigger = UNTimeIntervalNotificationTrigger(
timeInterval: interval,
repeats: false,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Drop past-due reminder dates instead of firing instantly

Scheduling clamps negative intervals to 1 second, so any reminder date already in the past is delivered immediately. Because gap scheduling can generate one reminder per missed day, reopening after a long tracking gap can produce a burst of immediate notifications rather than a sensible future schedule.

Useful? React with 👍 / 👎.

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