CycleWingman 1.3: plan the right day
cyclewingmanreleaseengineering
CycleWingman has always answered what kind of day is it. The question people actually arrive with is narrower and harder: when should I do this specific thing? Version 1.3 answers that one — and starts doing something with the notes 1.2 let you write. Here's what shipped, and the parts that were harder than they look.
What's new
- Plan something: pick what you're planning — a date night, a serious talk, a big ask, seeing other people — and the app ranks the days ahead for that specific thing, because the day that suits a party is not the day that suits a difficult conversation. Each suggestion opens straight into its day. Free ranks the same seven days the calendar already shows and tells you outright when a better day sits further out; Wingman+ looks across 45.
- Saved plans: keep a day you picked and the calendar marks it with the plan's own icon. Free — it's your decision, not a forecast.
- Journal: every day note for a partner, newest first, grouped by month, each carrying the forecast colour that day ran on. Free, permanently — it's your own writing.
- What your notes add up to (Wingman+): which cycle phase your hard days cluster in, where the best ones land, how long making up tends to take, and the tag you mark most.
- A forecast that tunes itself (Wingman+): once there are enough notes, the mood estimate shifts per cycle phase toward what you actually logged for this relationship.
- Lock-screen widgets on iPhone — circular, rectangular and inline, in the accessory slots.
- Backup & restore (Wingman+): export everything to a file and restore it on a new phone. Nothing is uploaded; the file goes wherever you send it.
- Your partner, your way (Wingman+): any emoji as the partner's glyph, and a hue that retints the app.
- Week start is now a setting — and no longer hard-coded to Monday.
- Calendar: swipe left and right to change month, and scroll back through history properly — a bug meant the previous month could vanish on the 1st.
Still not a medical device, still not for contraception or fertility, and still no servers: notes, patterns and calibration are computed and stored on your phone. A subscription lapse clears the tuning without touching a single note.
Under the hood
A planner that had to be talked out of becoming a fertility app
The first working version was three lines of obvious code: score every day ahead for the chosen intent, sort, take the top three. It produced an excellent-looking list and a genuinely bad feature.
Scores move smoothly across a cycle, so the three highest days are almost always consecutive — one good stretch sliced into three rows. Worse, for most intents that stretch lands in the same place every month, and the app would have been quietly pointing at the ovulation window and calling it date night. CycleWingman deliberately isn't a fertility tool: no ovulation planning, no conception framing, nothing that would drag a 4+ lifestyle app into health-and-medical review.
So suggestions are now forced at least four days apart. That single constraint is doing two jobs at once — it makes the list genuinely useful (three different windows to choose between rather than Tuesday, Wednesday and Thursday), and it is the guardrail that keeps the feature on the right side of a line we care about. The planner also refuses to flatter: a stretch with nothing good in it comes back labelled as one, rather than dressed up as the best of a bad month. And verdicts are words, never the number — printing "73/100" for an estimate built on a cycle average would imply a precision that doesn't exist.
Where a personalised forecast is allowed to be computed
Calibration is the feature we were most careful with. The idea is small: if your notes say her mood in the luteal phase consistently runs better than the model predicts, nudge the estimate. The interesting part is where that arithmetic runs.
The forecast engine exists twice by design — the TypeScript original and a Swift mirror in WingmanCore that drives the watch and the widgets — kept honest by golden-fixture parity tests. The obvious implementation is to let the engine read the notes and derive the offsets itself. That would have broken quietly: the watch only ever receives today's note, because the connectivity payload has a size ceiling. An engine deriving calibration from whatever logs it could see would compute one number on the phone and a different one on the wrist, for the same day, with no error anywhere.
So the split is deliberate. The phone computes the offsets from the full history and stores them on the partner's profile; the engine only applies them. Applying is forecast behaviour, so it is mirrored in Swift and pinned by dedicated fixture profiles — every surface shows the same number because they all read the same precomputed result.
Floors, so it says "not yet" instead of guessing
Anything that claims to find a pattern in a handful of data points is lying, and the failure is invisible: three notes will happily produce a confident-sounding sentence. So the thresholds are load-bearing. No pattern is claimed below eight logged days — under that the card says how many more it needs. Calibration wants twelve notes overall and four in a given phase before it touches that phase, shifts the estimate by at most one point, and damps what it does apply by half. It is designed to be barely noticeable and hard to be wrong with.
One product decision worth naming: free users see their first pattern in full, not a blurred teaser. Patterns are computed for everyone anyway, and "it learns your relationship" is impossible to evaluate before paying for it. A real finding from your own notes is a more honest preview than a smudged card — and the locked rows say plainly how many are left.
A week that doesn't start on Monday
The calendar and every date picker were hard-coded to Monday. That is simply wrong in the US, Canada and Japan, and the app is English-only but sold worldwide, so there is no single correct answer to hard-code. New and existing installs now seed the week start from the device's own locale, with Monday as a fallback on older iOS versions that don't expose it, and Settings can override it. Small feature; it touched every grid in the app.
