Imported from ytakahashi/step-mossaic (
AGENTS.md). Install upstream withnpx skills add ytakahashi/step-mossaic. Copyright stays with the author.
AGENTS.md
Guidance for agents working in this repository. See README.md for project
structure, verification, and formatting commands.
Project / Xcode Workflow
The StepMossaic.xcodeproj uses Xcode 16 synchronized groups
(PBXFileSystemSynchronizedRootGroup). New source/test files added under a
target's folder are included automatically — do not hand-edit project.pbxproj
to register them. Just create the file in the correct folder (mirroring the
existing tree) and it builds.
Comment Conventions
Comments capture what the code cannot say for itself — intent and rationale, not a restatement of the code. They split by audience.
Doc comments (///): the contract
Document every type and public API with a doc comment describing what it guarantees and why it exists — never how it is implemented.
- On a type: the design role it plays. e.g.
Daykeys daily data so that two timestamps on the same local day compare and hash as equal. - On a method: the behavioral contract — inclusive/exclusive bounds, the meaning
of
nil, thepreconditions, and how edge cases resolve. A short bullet list is preferred over prose when there are several rules. - This is where rules from the design doc become the code's contract. State the rule, not the design-doc vocabulary (no "Phase 1", "section 6", etc.).
Inline comments (//): the non-obvious why
Inside a body, comment only what is not evident from the code itself. Do not paraphrase what a line does. Three things are worth a line:
- Design intent / trade-offs — a choice the code cannot reveal. e.g. why
RelativeScalerranks against distinct values (tier, not frequency); whyDay.addingre-normalizes withstartOfDay(avoids DST drift). - Non-obvious edges — the reason behind a guard or expression, e.g.
max(count - 1, 1), the level clamp, or afirstAvailableDay == nilbranch. - Invariants — the
preconditionmessage declares the programmer-error contract.
Above all: preserve design intent
If a decision is not readable from the code — a formula chosen over an alternative, a defensive guard, a boundary convention — leave the rationale in a comment. This is the highest-value comment to write.
Testing Conventions
Structure: Arrange / Act / Assert
Write each test in AAA order with explicit section comments:
@Test("Normalizes any timestamp to the start of its local day")
func dayNormalizesToStartOfLocalDay() {
// Arrange
let calendar = TestCalendar.utc
let components = DateComponents(year: 2026, month: 6, day: 25, hour: 23, minute: 59)
let date = calendar.date(from: components)!
// Act
let day = Day(containing: date, calendar: calendar)
// Assert
#expect(day.start == calendar.startOfDay(for: date))
}
- When a phase is a single self-evident line, collapse it into a combined
// Act & Assertrather than padding empty sections.
Intent: @Test display name
Give every test a @Test("...") display name stating the behavior it
guarantees (the what).
Verification points: why comments
Add a one-line comment only where an edge case is non-obvious, explaining what the case proves, not restating the code. Examples:
- Using a 23:59 input proves the time-of-day is dropped, not merely preserved.
- Deriving month length from the next month is what makes leap February 29 days.
- A
.japanesecalendar would read2026as an era year if year/month were not forced to Gregorian.
Do not annotate every assertion; obvious checks stay uncommented.
Grouping and helpers
- Keep tests as free
@Testfunctions. - Share deterministic fixtures via
Tests/.../Supportto reuse the same code instead of re-deriving dates inline. - Domain logic is deterministic: inject
Calendarand dates explicitly; never rely onDate()orCalendar.currentin tests.
Layout: mirror the source tree
Each test target mirrors the folder structure of the code it covers for
both the domain package (StepMossaicDomain) and the app (StepMossaic).
Shared fixtures can be in a Support folder under the target.
