diff --git a/.agents/skills/tech-debt-sweep/judged-fine.md b/.agents/skills/tech-debt-sweep/judged-fine.md index df0271c06..209ad9c67 100644 --- a/.agents/skills/tech-debt-sweep/judged-fine.md +++ b/.agents/skills/tech-debt-sweep/judged-fine.md @@ -11,6 +11,58 @@ genuinely wrong, say so to the user rather than quietly re-litigating it. Format: one `##` block per sweep date, one bullet per area, each naming the reason it stays. +## 2026-11-12 + +Swept the 18 merges that landed after the 2026-11-11 sweep (#5098, #5111, #5218 +to #5224, #5228 to #5238); #5217 was that sweep's own finding and is excluded as +its output. Gate step 1 was clean: `bun knip` reports no unused files or exports +(only four config hints), `bun lint` passes every rule, `bun type-check` passes. +One finding, shipped as the zone-less-primary fix in the macOS +`CalendarTimeZoneHint` mirror. Everything below was examined and kept. + +- **The day-view column fallback chain, web vs macOS** (#5229, #5232). + `DayCalendarColumns.swift` resolves its no-events fallback as "first primary, + then first ordered calendar", while web's `getDayViewCalendars` goes through + `getDefaultTargetCalendar`, which additionally requires the primary to be a + *writable provider* calendar and falls back to the local calendar before the + first ordered one. So a user whose primary is read-only gets a different + single fallback column on each platform. Real, but not a sweep's to settle: + mirroring web needs `isWritableProviderCalendar` and `getLocalCalendar` + semantics CompassKit does not model, which is a contract decision, and #5232 + is a same-day parity follow-up to #5229 that extends rather than reworks it. + Flagged for a human instead. + +- **`EdgeFocusHint.swift` mirroring `edge-focus-hint.parts.ts`** (#5231). + The three `modeAnnouncements` strings and the `Tab` keycap are restated as + Swift literals where web derives them from `KEYMAP.edgeFocus.hotkey`. Inherent + duplication of the `remainderMasterId` kind (2026-11-10): CompassKit cannot + import `@compass/core`, and the two sides render different shapes anyway + (keycap parts vs prose). Landed today and still being extended by #5234; + not a lead. + +- **`wholeEventMoveKeys` hardcoding the timed arrow list** in + `edge-focus-hint.parts.ts` (#5231), beside `edgeMoveKeys` deriving its timed + case from `KEYMAP.moveEvent.timedEdgeKeycaps`. Looks like the `WEEKS_PER_ROW` + shape, but there is no owning export being drifted from: `KEYMAP.moveEvent` + publishes `keycaps` (a two-key teaching list) and `timedEdgeKeycaps`, not the + five-key whole-event list. Naming one to remove a one-line literal is a fix + larger than the problem. + +- **The sub-hour relative-time copy change** (#5098). Touched 13 files across + web and Swift to say "min" instead of "minutes", including three `connect` + copy modules. Wide but mechanical, and the shared copy already lives in one + module per surface. + +- **`self-host/rolling-backend.sh` drain probe** (#5220, #5222). 93 added lines + of shell with a bounded probe loop and a posix-safe status readback. Load-bearing + mess of the `date-picker-keyboard-dom.util.ts` kind: ugly because `/bin/sh` + portability and container draining are ugly. Four new `.test.sh` suites pin it. + +- **`sync-token-unsupported` throttling** (#5218, #5219). Adds a snapshot + throttle and an etag probe normalizer next to the 2026-11-11 entry's retry + constants. Extends that area rather than restating it; the constants are still + imported, not re-literalled. + ## 2026-11-11 Swept the 9 merges that landed after the 2026-11-10 sweep (#5209 to #5216 plus diff --git a/apps/calendar-macos/CompassKit/Sources/CompassKit/Calendar/CalendarTimeZoneHint.swift b/apps/calendar-macos/CompassKit/Sources/CompassKit/Calendar/CalendarTimeZoneHint.swift index 9948ffe6e..459b5e65d 100644 --- a/apps/calendar-macos/CompassKit/Sources/CompassKit/Calendar/CalendarTimeZoneHint.swift +++ b/apps/calendar-macos/CompassKit/Sources/CompassKit/Calendar/CalendarTimeZoneHint.swift @@ -2,16 +2,27 @@ import Foundation /// Best IANA zone from connected calendars (web `pickCalendarTimeZoneHint`). public enum CalendarTimeZoneHint { + /// Web tests `calendar.timeZone` for truthiness, so a calendar carrying no + /// zone (or an empty one) is not a candidate at all. Keeping that in one + /// place is what stops the primary preference below from being consumed by + /// a zone-less primary. + private static func usableZone(of calendar: CompassCalendar) -> String? { + guard let zone = calendar.timeZone?.rawValue, !zone.isEmpty else { + return nil + } + return zone + } + public static func pick(from calendars: [CompassCalendar]) -> String? { - if let primary = calendars.first(where: { $0.isPrimary }), - let zone = primary.timeZone?.rawValue, + if let primary = calendars.first(where: { $0.isPrimary && usableZone(of: $0) != nil }), + let zone = usableZone(of: primary), TimeZoneFormatting.isValidTimeZone(zone) { return zone } for calendar in calendars { - guard let zone = calendar.timeZone?.rawValue, + guard let zone = usableZone(of: calendar), TimeZoneFormatting.isValidTimeZone(zone), !TimeZoneFormatting.isUtcLikeTimeZone(zone) else { continue } @@ -19,7 +30,7 @@ public enum CalendarTimeZoneHint { } for calendar in calendars { - guard let zone = calendar.timeZone?.rawValue, + guard let zone = usableZone(of: calendar), TimeZoneFormatting.isValidTimeZone(zone) else { continue } return zone diff --git a/apps/calendar-macos/CompassKitTests/CalendarTimeZoneHintTests.swift b/apps/calendar-macos/CompassKitTests/CalendarTimeZoneHintTests.swift index 973e78a65..12f87f368 100644 --- a/apps/calendar-macos/CompassKitTests/CalendarTimeZoneHintTests.swift +++ b/apps/calendar-macos/CompassKitTests/CalendarTimeZoneHintTests.swift @@ -2,7 +2,12 @@ import CompassKit import XCTest final class CalendarTimeZoneHintTests: XCTestCase { - func testPrimaryHintSurvivesHiddenCalendar() { + private func makeCalendar( + id: String, + isPrimary: Bool, + isVisible: Bool = true, + timeZone: String? + ) -> CompassCalendar { let capabilities = CompassCalendarCapabilities( canInviteAttendees: false, canManage: false, @@ -12,7 +17,7 @@ final class CalendarTimeZoneHintTests: XCTestCase { canWrite: true, conferenceKinds: [] ) - let primary = CompassCalendar( + return CompassCalendar( access: .owner, accountEmail: "a@example.com", backgroundColor: "#ffffff", @@ -21,30 +26,27 @@ final class CalendarTimeZoneHintTests: XCTestCase { createsGoogleMeet: false, description: "", foregroundColor: "#000000", - id: "primary", + id: id, isActive: true, + isPrimary: isPrimary, + isVisible: isVisible, + name: id, + provider: "google", + timeZone: timeZone.map { IANATimeZone(rawValue: $0) } + ) + } + + func testPrimaryHintSurvivesHiddenCalendar() { + let primary = makeCalendar( + id: "primary", isPrimary: true, isVisible: false, - name: "Primary", - provider: "google", - timeZone: IANATimeZone(rawValue: "America/Denver") + timeZone: "America/Denver" ) - let visible = CompassCalendar( - access: .owner, - accountEmail: "a@example.com", - backgroundColor: "#ffffff", - capabilities: capabilities, - conference: nil, - createsGoogleMeet: false, - description: "", - foregroundColor: "#000000", + let visible = makeCalendar( id: "visible", - isActive: true, isPrimary: false, - isVisible: true, - name: "Visible", - provider: "google", - timeZone: IANATimeZone(rawValue: "America/New_York") + timeZone: "America/New_York" ) XCTAssertEqual( @@ -52,4 +54,33 @@ final class CalendarTimeZoneHintTests: XCTestCase { "America/Denver" ) } + + /// Shared vector with web `calendar-timezone-hint.test.ts`. A zone-less + /// primary must not consume the primary preference: the second account's + /// primary wins over the earlier non-primary zone. + func testZonelessPrimaryDoesNotConsumeThePrimaryPreference() { + let calendars = [ + makeCalendar(id: "acctA-primary", isPrimary: true, timeZone: nil), + makeCalendar(id: "acctA-shared", isPrimary: false, timeZone: "America/Chicago"), + makeCalendar(id: "acctB-primary", isPrimary: true, timeZone: "America/New_York"), + ] + + XCTAssertEqual( + CalendarTimeZoneHint.pick(from: calendars), + "America/New_York" + ) + } + + /// An empty zone is not a usable hint, matching web truthiness. + func testEmptyPrimaryZoneFallsThroughToARegionalZone() { + let calendars = [ + makeCalendar(id: "primary", isPrimary: true, timeZone: ""), + makeCalendar(id: "other", isPrimary: false, timeZone: "America/Chicago"), + ] + + XCTAssertEqual( + CalendarTimeZoneHint.pick(from: calendars), + "America/Chicago" + ) + } } diff --git a/apps/calendar-web/src/timezone/calendar-timezone-hint.test.ts b/apps/calendar-web/src/timezone/calendar-timezone-hint.test.ts index 919c81392..9aaa5c495 100644 --- a/apps/calendar-web/src/timezone/calendar-timezone-hint.test.ts +++ b/apps/calendar-web/src/timezone/calendar-timezone-hint.test.ts @@ -52,6 +52,29 @@ describe("pickCalendarTimeZoneHint", () => { expect(pickCalendarTimeZoneHint(calendars)).toBe("America/New_York"); }); + // Shared vector with macOS `CalendarTimeZoneHintTests.swift`. A zone-less + // primary must not consume the primary preference. + it("prefers a later primary zone over an earlier non-primary zone", () => { + const calendars = [ + createMockCalendar({ + name: "AcctA primary", + timeZone: null, + isPrimary: true, + }), + createMockCalendar({ + name: "AcctA shared", + timeZone: TimeZoneSchema.parse("America/Chicago"), + isPrimary: false, + }), + createMockCalendar({ + name: "AcctB primary", + timeZone: TimeZoneSchema.parse("America/New_York"), + isPrimary: true, + }), + ]; + expect(pickCalendarTimeZoneHint(calendars)).toBe("America/New_York"); + }); + it("skips UTC when another calendar has a regional zone", () => { const calendars = [ createMockCalendar({