| @@ -6,7 +6,7 @@ ports, geolocation, subdomains, availability). The next several releases invest |
| 6 | 6 | in *reach and surfacing* — getting that data onto more iOS surfaces and into more |
| 7 | 7 | workflows — rather than adding raw protocol checks. |
| 8 | 8 | |
| 9 | | Current version: `v4.8.3`. |
| 9 | Current version: `v4.9.0`. |
| 10 | 10 | |
| 11 | 11 | ## v4.4.1 Patch: Release Readiness — ✅ shipped |
| 12 | 12 | |
| @@ -185,6 +185,65 @@ hits on SwiftUI `$binding` shorthand in `AuditModeView`, which cannot be |
| 185 | 185 | renamed. These want a *Won't Fix* / *Safe* resolution in SonarCloud rather than |
| 186 | 186 | a code change. |
| 187 | 187 | |
| 188 | ## v4.9.0 Minor: Accessibility, Appearance & Engineering Health — ✅ shipped |
| 189 | |
| 190 | Goal: make the app usable by every iOS user — full accessibility pass (#21), |
| 191 | light mode, and the engineering scaffolding to keep both from regressing. |
| 192 | |
| 193 | - **Semantic colour system** — every hard-coded colour replaced with adaptive |
| 194 | colorsets in `Shared/Colors.xcassets` (Any/Dark + High Contrast variants), |
| 195 | shared by app, widget, and share extension via the synchronized `Shared` |
| 196 | group. Every status colour clears WCAG AA on its page, its card, and its |
| 197 | badge surface, in both schemes; measured, not asserted. The accent is now |
| 198 | blue (`#0000FF` light / `#4DA3FF` dark), split into foreground |
| 199 | (`StatusInfo`), fill (`AccentFill`), and on-fill (`AppOnAccent`) roles |
| 200 | because one value cannot serve as both text-on-dark and fill-behind-white. |
| 201 | `AppStatusTone` pairs each status foreground with an authored surface. |
| 202 | - **Light mode unlocked** — the 16 scattered `.preferredColorScheme(.dark)` |
| 203 | calls removed; appearance (System/Light/Dark) is applied once at the |
| 204 | `WindowGroup` and exposed under Settings → Display. `.secondary` (3.29:1 on a |
| 205 | light card) replaced with `AppTextSecondary` across 191 sites. |
| 206 | - **Dynamic Type & reflow** — `Label`-clipped empty-state titles fixed, the |
| 207 | 44pt tap-target floor enforced (`AppCopyButton` was 30×30; |
| 208 | `controlMinHeight` was 42), `CardView`'s horizontal-scroll default flipped |
| 209 | to reflow, dense rows (`WatchlistRowView`, `BatchResultRowView`, |
| 210 | `PortfolioExpiryRow`) and the collapsible section headers rebuilt on |
| 211 | `ViewThatFits` so badges and buttons can never letter-wrap vertically, and |
| 212 | the widget clamped at `accessibility1` (fixed canvas, no scroll). |
| 213 | - **VoiceOver** — labels on every icon-only control (label-in-name preserved |
| 214 | for Voice Control), selected-state on all toggles, badges read as one word, |
| 215 | heading-rotor navigation, dense rows collapsed to one element with the |
| 216 | detail on the More Content rotor (`accessibilityCustomContent`), technical |
| 217 | strings (DNS records, cipher suites) spoken with punctuation, and lookup/ |
| 218 | sweep completion announcements. Widget rows read as a single phrase. |
| 219 | - **Colour independence, motion, transparency** — widget status uses the badge |
| 220 | symbol vocabulary instead of colour-only dots; `differentiateWithoutColor` |
| 221 | adds symbols/borders on demand; all five animation sites honour |
| 222 | `reduceMotion`; the one material honours `reduceTransparency`. |
| 223 | - **Accessibility audit harness** — `DomainDigUITests` runs |
| 224 | `performAccessibilityAudit()` over every primary screen at default and |
| 225 | AccessibilityXXXL, on CI (newest runtime, clean merge-result checkout) and |
| 226 | locally (`Scripts/audit-a11y.sh`, real floor runtime, wired to an opt-in |
| 227 | pre-push hook). `DOMAIN_DIG_SEED_FIXTURES` seeds deterministic in-memory |
| 228 | rows so the dense paths actually render under audit. The **enforcement |
| 229 | ratchet is engaged**: named findings in six categories fail CI, with |
| 230 | narrowly characterised, always-logged noise suppressions. Manual |
| 231 | verification checklist in `Docs/ACCESSIBILITY_VERIFICATION.md`; findings |
| 232 | burndown 20 → 11 with every remaining item characterised as system noise. |
| 233 | - **Swift 6 language mode** (#27) — all three product targets build under |
| 234 | `SWIFT_VERSION = 6.0` with zero warnings. `SMTPChannel` became an actor |
| 235 | (fixing a real `CheckedContinuation` double-resume hazard), |
| 236 | `SweepActivityController` stores a Sendable activity id, and the remaining |
| 237 | isolation issues were resolved layer by layer. The UITests target stays on |
| 238 | Swift 5 (XCTest override isolation), recorded as a decision. |
| 239 | - **Project hygiene** — the misleading project-level deployment target |
| 240 | (26.2 shadowing the real 17.6) reconciled; CI selects simulators |
| 241 | floor-aware instead of first-match. |
| 242 | |
| 243 | Deferred: the Phase 6 manual device passes (VoiceOver walkthrough, Voice |
| 244 | Control, iPad Full Keyboard Access, Liquid Glass runtime check) are tracked in |
| 245 | `Docs/ACCESSIBILITY_VERIFICATION.md` and #21 — they close on device, not in CI. |
| 246 | |
| 188 | 247 | ## v5.0.0 Major: Contract Stabilization & Engineering Health |
| 189 | 248 | |
| 190 | 249 | Goal: earn long-term compatibility promises — and pay down the debt that the |
| @@ -194,10 +253,11 @@ feature releases above will accumulate. |
| 194 | 253 | and settings. |
| 195 | 254 | - Stabilize the public local API response contract; document compatibility |
| 196 | 255 | guarantees and planned deprecations. |
| 197 | | - **Establish a test target.** The project currently has no XCTest target and no |
| 198 | | tests; add one and cover the deterministic core first — `DomainReportBuilder`, |
| 199 | | `DomainReportExporter`, `DomainDataPortabilityService` (merge/replace dedup), |
| 200 | | and `DiffService` — before locking down external contracts. |
| 256 | - **Extend the test net to the deterministic core.** v4.9.0 established |
| 257 | `DomainDigUITests` (accessibility audit + enforcement gate); unit coverage of |
| 258 | `DomainReportBuilder`, `DomainReportExporter`, `DomainDataPortabilityService` |
| 259 | (merge/replace dedup), and `DiffService` is still needed before locking down |
| 260 | external contracts. |
| 201 | 261 | - **Decompose the god-files** behind that test net: `DomainViewModel.swift` |
| 202 | 262 | (~4.7k lines) and `ContentView.swift` (~3.8k lines) into focused units |
| 203 | 263 | (audit, monitoring, workflows, portability). |