- 01-01: Reframe must_haves.truths to user-observable behaviors - 01-01: Remove unimplemented key_link (wiring happens in later phases) - 01-02: Add test case for DATA-04 (custom items at any position) - 01-02: Add must_haves.truths entry for custom item flexibility - 01-02: Document LocalItineraryItem is standalone (no sibling models needed) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
152 lines
5.4 KiB
Markdown
152 lines
5.4 KiB
Markdown
---
|
|
phase: 01-semantic-position-model
|
|
plan: 01
|
|
type: execute
|
|
wave: 1
|
|
depends_on: []
|
|
files_modified:
|
|
- SportsTime/Core/Models/Domain/SortOrderProvider.swift
|
|
- SportsTime/Core/Models/Domain/Trip.swift
|
|
autonomous: true
|
|
|
|
must_haves:
|
|
truths:
|
|
- "Games sort by schedule time within each day"
|
|
- "Items can be inserted at any position (before, between, after existing items)"
|
|
- "Items can be assigned to any trip day by date calculation"
|
|
artifacts:
|
|
- path: "SportsTime/Core/Models/Domain/SortOrderProvider.swift"
|
|
provides: "sortOrder calculation utilities"
|
|
exports: ["initialSortOrder(forGameTime:)", "sortOrderBetween(_:_:)", "sortOrderBefore(_:)", "sortOrderAfter(_:)", "needsNormalization(_:)", "normalize(_:)"]
|
|
- path: "SportsTime/Core/Models/Domain/Trip.swift"
|
|
provides: "Day derivation methods"
|
|
contains: "func dayNumber(for date: Date) -> Int"
|
|
key_links: []
|
|
---
|
|
|
|
<objective>
|
|
Create the sortOrder calculation utilities and day derivation methods that Phase 1 depends on.
|
|
|
|
Purpose: Establish the foundational utilities for semantic position assignment. Games need sortOrder derived from time, travel/custom items need midpoint insertion, and items need day derivation from trip dates.
|
|
|
|
Output: `SortOrderProvider.swift` with all sortOrder utilities, `Trip.swift` extended with day derivation methods.
|
|
</objective>
|
|
|
|
<execution_context>
|
|
@~/.claude/get-shit-done/workflows/execute-plan.md
|
|
@~/.claude/get-shit-done/templates/summary.md
|
|
</execution_context>
|
|
|
|
<context>
|
|
@.planning/PROJECT.md
|
|
@.planning/ROADMAP.md
|
|
@.planning/STATE.md
|
|
@.planning/phases/01-semantic-position-model/01-RESEARCH.md
|
|
|
|
# Existing source files
|
|
@SportsTime/Core/Models/Domain/ItineraryItem.swift
|
|
@SportsTime/Core/Models/Domain/Trip.swift
|
|
</context>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Create SortOrderProvider utility</name>
|
|
<files>SportsTime/Core/Models/Domain/SortOrderProvider.swift</files>
|
|
<action>
|
|
Create a new file `SortOrderProvider.swift` with an enum containing static methods for sortOrder calculation.
|
|
|
|
Include these methods (as specified in 01-RESEARCH.md):
|
|
|
|
1. `initialSortOrder(forGameTime: Date) -> Double`
|
|
- Extract hour and minute from game time
|
|
- Calculate minutes since midnight
|
|
- Return 100.0 + minutesSinceMidnight (range: 100-1540)
|
|
- This ensures games sort by time and leaves room for negative sortOrder items
|
|
|
|
2. `sortOrderBetween(_ above: Double, _ below: Double) -> Double`
|
|
- Return (above + below) / 2.0
|
|
- Simple midpoint calculation
|
|
|
|
3. `sortOrderBefore(_ first: Double) -> Double`
|
|
- Return first - 1.0
|
|
- Creates space before the first item
|
|
|
|
4. `sortOrderAfter(_ last: Double) -> Double`
|
|
- Return last + 1.0
|
|
- Creates space after the last item
|
|
|
|
5. `needsNormalization(_ items: [ItineraryItem]) -> Bool`
|
|
- Sort items by sortOrder
|
|
- Check if any adjacent gap is less than 1e-10
|
|
- Return true if normalization needed
|
|
|
|
6. `normalize(_ items: inout [ItineraryItem])`
|
|
- Sort by current sortOrder
|
|
- Reassign sortOrder as 1.0, 2.0, 3.0... (integer spacing)
|
|
- Updates items in place
|
|
|
|
Use `Calendar.current` for date component extraction. Import Foundation only.
|
|
</action>
|
|
<verify>
|
|
File exists at `SportsTime/Core/Models/Domain/SortOrderProvider.swift` with all 6 methods. Build succeeds:
|
|
```bash
|
|
xcodebuild -project SportsTime.xcodeproj -scheme SportsTime -destination 'platform=iOS Simulator,name=iPhone 17,OS=26.2' build 2>&1 | tail -20
|
|
```
|
|
</verify>
|
|
<done>SortOrderProvider.swift exists with all 6 static methods, project builds without errors</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: Add day derivation methods to Trip</name>
|
|
<files>SportsTime/Core/Models/Domain/Trip.swift</files>
|
|
<action>
|
|
Extend the existing Trip struct with day derivation methods in a new extension at the bottom of the file.
|
|
|
|
Add these methods:
|
|
|
|
1. `func dayNumber(for date: Date) -> Int`
|
|
- Use Calendar.current to get startOfDay for both startDate and target date
|
|
- Calculate days between using dateComponents([.day], from:to:)
|
|
- Return days + 1 (1-indexed)
|
|
|
|
2. `func date(forDay dayNumber: Int) -> Date?`
|
|
- Use Calendar.current to add (dayNumber - 1) days to startDate
|
|
- Return the resulting date
|
|
|
|
Add a comment block explaining:
|
|
- Day 1 = trip.startDate
|
|
- Day 2 = startDate + 1 calendar day
|
|
- Games belong to their start date (even if running past midnight)
|
|
|
|
These methods complement the existing `itineraryDays()` method but work with raw Date values rather than the Trip's stops structure.
|
|
</action>
|
|
<verify>
|
|
Build succeeds and new methods are callable:
|
|
```bash
|
|
xcodebuild -project SportsTime.xcodeproj -scheme SportsTime -destination 'platform=iOS Simulator,name=iPhone 17,OS=26.2' build 2>&1 | tail -20
|
|
```
|
|
</verify>
|
|
<done>Trip.swift has dayNumber(for:) and date(forDay:) methods, project builds without errors</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<verification>
|
|
1. Both files exist and contain expected methods
|
|
2. `xcodebuild build` succeeds with no errors
|
|
3. SortOrderProvider methods are static and accessible as `SortOrderProvider.methodName()`
|
|
4. Trip extension methods are instance methods callable on any Trip value
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- SortOrderProvider.swift exists with 6 static methods for sortOrder calculation
|
|
- Trip.swift extended with dayNumber(for:) and date(forDay:) methods
|
|
- Project builds successfully
|
|
- No changes to existing ItineraryItem.swift (model already has correct fields)
|
|
</success_criteria>
|
|
|
|
<output>
|
|
After completion, create `.planning/phases/01-semantic-position-model/01-01-SUMMARY.md`
|
|
</output>
|