Skip to content

Streamline AGENTS.md files and regroup WhereCore sources#89

Merged
kyleve merged 5 commits into
mainfrom
streamline-agents-docs
Jul 15, 2026
Merged

Streamline AGENTS.md files and regroup WhereCore sources#89
kyleve merged 5 commits into
mainfrom
streamline-agents-docs

Conversation

@kyleve

@kyleve kyleve commented Jul 15, 2026

Copy link
Copy Markdown
Owner

What

Trims the largest AGENTS.md files down to invariants, hard-fought lessons, and instructions — dropping structure enumerations agents re-derive from the manifests in their first minute of searching — and regroups WhereCore's flat Sources/ into concern-based subdirectories. One commit per step.

Guiding principle: an AGENTS.md keeps invariants, lessons, conventions, and recipes; it drops module lists, directory trees, and dependency catalogs that mirror Package.swift / Project.swift. The root file's libraries list was already stale (missing WhereIntents and SwiftDataInspector) — proof that content rots.

Commits

  1. GitHub rules — new root GitHub section: use gh for all GitHub interaction; open PRs ready-for-review, never draft; keep open PRs current by pushing each local commit. "Working on PR feedback" now requires replying to a comment when a commit resolves it, and filing deferred feedback durably instead of dropping it.
  2. Root trim — libraries/targets enumerations become pointers at the manifests; directory layout collapses to the module skeleton. The add-a-target recipe, CI-scheme rule, and the double-linking lesson stay verbatim.
  3. Where trim — Modules tree becomes a one-paragraph layering stack; developer-overlay tour and feature narration cut; the stylesheet paragraph now points at WhereUI/AGENTS.md. 222 → 189 lines.
  4. Module trims — WhereUI / WhereCore / WhereIntents lose their Package.swift-mirroring dependency listings; PeriscopeCore loses its directory catalog. All invariants and the full WhereStylesheet guidance stay.
  5. WhereCore regroup — pure git mv, no behavior change: stragglers fold into Backup/, Reminders/, Widgets/, Location/, Evidence/, DataResolution/, Persistence/; new Days/, Reporting/, Journal/, Preferences/ groups. Only WhereServices* and WhereLog remain top-level. Tests stay flat, matching PeriscopeCore.

New lessons codified (mined from the last 30 days of PR review)

Verification

  • ./swiftformat --lint clean; ./sync-agents run after each docs commit
  • Full Stuff-iOS-Tests scheme after the regroup: 1183 tests, 0 failures

Made with Cursor

kyleve and others added 5 commits July 15, 2026 14:43
Add a GitHub section (always use gh; PRs open ready-for-review; keep
open PRs current by pushing each local commit), route the Working on
plans push rule through it, and extend Working on PR feedback: reply to
a comment when a commit resolves it, and file deferred feedback
somewhere durable rather than dropping it.

Plan step: Root AGENTS.md — GitHub rules.

Co-authored-by: Cursor <cursoragent@cursor.com>
Replace the libraries/targets enumerations with pointers at
Package.swift / Project.swift (the stale list was missing WhereIntents
and SwiftDataInspector — proof this content rots) and cut the
directory-layout narrative down to the module skeleton. Keep the
add-a-target recipe, the CI-scheme rule, and the double-linking lesson
verbatim.

Add four conventions mined from the last 30 days of PR review:
synthesized/rename-safe Codable, retained observer tokens with paired
stop(), grouping large flat types into sub-structs/child types, and
protocol-conforming test doubles.

Plan step: Root AGENTS.md — trim enumerations.

Co-authored-by: Cursor <cursoragent@cursor.com>
Shrink the Modules section to one pointer line per module (their own
AGENTS.md files are the authority), drop the developer-overlay tour,
and cut descriptive feature content from the layering bullets while
keeping every enforced rule. Point the stylesheet paragraph at
WhereUI/AGENTS.md instead of duplicating it.

Add two review-mined bullets under SwiftUI views & previews:
accessibility-modal full-screen surfaces (+ focus notifications), and
derive-don't-repeat UI dimensions (preference-key measurement,
ScaledMetric, semantic font styles).

Plan step: Where/AGENTS.md trim.

Co-authored-by: Cursor <cursoragent@cursor.com>
Cut dependency listings that mirror Package.swift and PeriscopeCore's
directory-layout catalog (the folder names are self-describing); keep
every invariant and all WhereStylesheet guidance.

Add one review-mined WhereCore invariant: post-write reconciliation is
defined once — writes/imports route through
DayJournal.reconcileAfterDayChange(), and cross-collaborator hooks are
a single closure (BackupCoordinator.onImport), not injected reconciler
lists.

Plan step: Light trims — WhereUI, WhereCore, PeriscopeCore,
WhereIntents AGENTS.md.

Co-authored-by: Cursor <cursoragent@cursor.com>
Pure file moves, no behavior change. Fold the stragglers into their
existing groups (BackupCoordinator -> Backup/, the three reconcilers ->
Reminders/, WidgetSnapshotPublisher -> Widgets/, LocationIngestor +
LocationSample -> Location/, EvidenceReader -> Evidence/,
DismissedIssue -> DataResolution/, StoreChangeBroadcaster ->
Persistence/) and add four new groups: Days/ (CalendarDay and the
day/calendar helpers), Reporting/ (YearReport, MissingDays,
ReportReader), Journal/ (DayJournal, ManualEntryAudit), and
Preferences/ (WherePreferences, KeyValueStore, InMemoryKeyValueStore).
Only the composition root (WhereServices) and the WhereLog facade stay
at the top level. Tests stay flat, matching PeriscopeCore.

Verified with the full Stuff-iOS-Tests scheme (1183 tests, 0 failures).

Plan step: Regroup WhereCore Sources into subdirectories.

Co-authored-by: Cursor <cursoragent@cursor.com>
@kyleve kyleve merged commit c2fefbb into main Jul 15, 2026
2 checks passed
kyleve added a commit that referenced this pull request Jul 15, 2026
…store-backed tracked regions (#87)

## What & why

Prepares RegionKit for "more locations" ahead of letting users pick their own regions. Two coupled shifts:

1. **Split** the ~2.5 MB monolithic `us-states.geojson` into one GeoJSON file per region, loaded **on demand** — so we only ever parse the regions we track, not the whole US at launch.
2. **Replace** the hardcoded five-case `Region` enum with a **data-driven catalog** (a bundled `regions.json` manifest + a `Region` value type), so any US state (50 + DC + PR) plus Canada/EU are available regions. The user's **tracked** regions live in the synced SwiftData store (WhereCore owns "which"; RegionKit stays the agnostic geometry/lookup engine).

Onboarding's region picker and user-chosen per-region styling are **out of scope** here (designed for, not built).

## What changed

- **RegionKit — data-driven catalog + on-demand geometry**
  - `Region` is now a `Hashable`/`Codable` value type over a stable id (`us-CA`, `canada`, …) with a well-known `.other` and conveniences (`.california`, etc.). `RegionCatalog` loads the bundled `regions.json` manifest (all/name/localizedName/geometry file, canonical order). Adding a region is now **pure data** — a manifest + geojson change generated by `Tools/generate-regions.rb`, no code.
  - `RegionAttributor(for:)` loads only the passed regions' files; `.all` covers the whole catalog, `.shared` the default four. `RegionAttributing` abstracts the engine so the app can supply a live, swappable attributor. `RegionGeometryCatalog.outlines(for:attributor:)` takes an explicit attributor.
- **WhereCore — store-backed, synced tracked regions + live attributor**
  - Tracked regions persist as **one `SDTrackedRegion` row per region** (so concurrent cross-device edits merge instead of last-write-wins), read as a `Set` defaulting to the four until the user chooses.
  - `RegionAttribution` rebuilds the attributor from the tracked set on the store's `changes()` signal (local edit or remote CloudKit import). `WhereServices.make(...)` (async) derives it from the store; the app launch and the App Intents process (`WhereServices.forIntents()`, now async) both attribute against the same synced set. `make(...)` is the **sole public assembly entry**; the synchronous `init` is `@_spi(Testing)` for tests/previews.
- **WhereUI / WhereIntents — catalog-driven**
  - `RegionStyle` is id-keyed with an isolated, disposable bespoke-override table (the seam user-chosen styling will replace). Ordering uses `Region.inCanonicalOrder(_:)` instead of scanning `Region.allCases`.
  - Siri's "pick a region" suggestions and the Spotlight index surface the **tracked** set; `RegionEntity` id resolution stays **full-catalog** (so "days in Texas" answers even when untracked).
- **Backup** — tracked regions round-trip in the archive (additive field; v1 manifests decode to `[]`); `.replace` restores the set exactly, `.merge` unions it.

## Key decisions / tradeoffs

- **Clean id scheme** (`us-CA` vs `california`): existing persisted region raw values change; data is re-exported/re-imported. The `NAME → id` map lives in `Tools/generate-regions.rb`.
- **Localization tradeoff:** region names come from the manifest (with an optional `localizationKey` override), so region names lose static string-catalog extraction — consistent with how the App Intents `RegionEntity` already resolves names at runtime.
- **Attribution priority** is the manifest's canonical order (regions are mutually exclusive at our resolution).

## Deferred (follow-ups)

- The onboarding region picker and user-chosen per-region color/emoji/symbol/tint.
- Seeding semantics (the default four apply only at zero rows; the picker will seed/replace) and materializing the implicit default before the first explicit edit.
- **Untracking a region:** the store currently *deletes* the tracked-region row, which would re-attribute that region's past GPS days to `.other` on re-aggregation (manual days, stored as region sets, are safe). A `TODO` defers the soft-delete (mark inactive + load every ever-tracked region so history stays stable) to the picker work that defines the untrack UX. Not user-reachable today — nothing calls `setTrackedRegion(false)` outside tests.

## Testing

- Full `Stuff-iOS-Tests` scheme green; `./swiftformat --lint` clean.
- New/reworked coverage: catalog + value-type (`RegionTests`), subset-only-loads (`RegionAttributorTests`), rebuild-on-`changes()` + store round-trip (`RegionAttributionTests`, `TrackedRegionStoreTests`), end-to-end `make()` wiring (`WhereServicesTests`), tracked-set entity/suggestions (`RegionEntityTests`), and backup round-trip / legacy-manifest decode (`BackupServiceTests`, `BackupCoordinatorTests`).

## Review pass

- **Self-review:** log (not swallow) tracked-region read failures; deterministic (canonical-ordered) attributor build; surface unknown stored region ids; backup round-trip (above).
- **PR review feedback:** consolidated the RegionKit bundled-data docs into the main `README.md` (removed the separate `Resources/README.md`); documented why `Region`'s `Codable` is hand-written (bare id string vs the synthesized keyed object); made the sync `WhereServices.init` `@_spi(Testing)` so `make()` is the sole public entry; and TODO'd the untrack soft-delete (see Deferred).

## Kept current with `main`

Merged `#85` (CalendarDay), `#86` (Periscope JournalKit), `#88` (backup `onImport` reconcile hook), and `#89` (streamlined AGENTS + WhereCore source regroup). Conflicts resolved: the backup `formatVersion` (kept v2 **and** the additive `trackedRegions` field); the `BackupCoordinatorTests` harness swap (kept both the tracked-region tests and `#88`'s `onImport` hook test); and `Where/AGENTS.md` (took `#89`'s streamlined Modules section, but kept the accurate manifest-backed RegionKit localization note over `#89`'s stale "static keys" wording). My changes rode the source regroup into `Backup/`, `Persistence/`, `Days/`, `DataResolution/`, etc.
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