Append-only. One line per merge, newest at the bottom. Format:
YYYY-MM-DD — M<N> — <branch> — <sha7> — <one-line summary>; next: <what's next>A fresh contributor (or AI agent) reading from the bottom of this file can answer "where are we?" without needing chat history. See
PROJECT_NEO.mdfor rules andplans/00-roadmap.mdfor the issue list.
- Active issue: M7 (#1055) — Second rebuilt screen (recipe validation). Apply the M0 About-module shape to a sibling Preferences leaf. Lands
main → neo-5.0, same@available(iOS 17.0, *)gating. Plan file not yet drafted; scope captured in the GitLab issue andplans/00-roadmap.md. - Active branch:
main. - Blocked on: —
- Up next: Draft
docs/neo/plans/M7-second-rebuilt-screen.md, then PR. - M2 follow-ups (separate issues, not blocking M7):
- #1065 — D2.3 schema normalization (GRDB v1→v2). Ships any main release after D2.2.
- #1066 — D2.4 Realm removal. Ships post-Neo + 3-month forced-upgrade soak.
- Closed milestones: M0 (#1048), M1 (#1049, neo-5.0), M2 (#1050), M3 (#1051), M4 (#1052), M5 (#1053), M6 (#1054).
- 2026-04-30 — M0 —
aw/neo-m0-shared-context—9dfa0829— PR 1 opened (MR !1334): shared-context layer (T0.1–T0.5). Addsdocs/PROJECT_NEO.md,docs/neo/plans/{00-roadmap,M0-guardrails}.md,docs/neo/DECISIONS.md,docs/neo/STATE.md, AGENTS.md onramp section. Lands onmain. Next: review + merge, then PR 2 (SwiftLint custom rules, T0.6). - 2026-04-30 — M0 —
main—0f133586— PR 1 merged. Foundation context layer in tree. - 2026-04-30 — M0 —
aw/neo-m0-swiftlint-rules—9aab3dc3— PR 2 opened (MR !1335): SwiftLint custom rules (T0.6). Adds 10custom_rules:to.swiftlint.ymlscoped toWindscribe/Features/**andWindscribeTV/Features/**. Verified zero violations on existing code; all 10 rules fire on a probe file (since deleted). Lands onmain. Next: review + merge, then PR 3. - 2026-04-30 — M0 —
main—6b9a6f09— PR 2 merged. - 2026-04-30 — M0 — decision change — ND-005 supersedes ND-003: M0's canonical reference module switches from LookAndFeel to About. Reading the actual LookAndFeel code revealed it was much heavier than the planning doc assumed (374-line VM, 7 deps, sub-router, file I/O); About (57+48 lines, 2 deps, one Combine binding, sheet presentation) better fits M0's "low blast radius, copy-paste-ready template" goal. LookAndFeel becomes a candidate for M7's recipe-validation. M0 plan, PROJECT_NEO.md, 00-roadmap.md, DECISIONS.md, GitLab issue #1048, and the Notion artifact all updated in the same change.
- 2026-04-30 — M0 —
aw/neo-m0-about-reference—929bce27— PR 3 opened (MR !1337): About reference module (T0.7, T0.8, T0.9, T0.12, T0.13). AddsWindscribe/Features/About/{AboutView,AboutViewModel}.swift,Windscribe/Services/Protocols/LookAndFeelObserving.swift,Windscribe/App/Environment+Dependencies.swift,WindscribeTests/Features/AboutTests.swift(first Swift Testing suite). Seam:PreferencesNavigationRouterruntime-branchesif #available(iOS 17.0, *). WindscribeTests deployment target bumped 15.0→17.0 (test-target only). All 6 new tests + 13 parameterised cases pass on iPhone 17 simulator. Lands onmain. Next: review + merge, then PR 4 (tvOS scaffolding, T0.10/T0.11). - 2026-04-30 — M0 —
main—b87bf180— PR 3 merged. - 2026-04-30 — M0 —
aw/neo-m0-tvos-scaffolding—f31768f6— PR 4 opened (MR !1339): tvOS scaffolding + tvOS doc section + scheme wiring (T0.10, T0.11, T0.14). AddsWindscribeTV/Features/andWindscribeTV/Services/Protocols/withREADME.mdplaceholders pointing atdocs/PROJECT_NEO.mdand the iOS About reference. SwiftLint custom rules already match(Windscribe|WindscribeTV)/Features/.*\.swiftso they apply automatically — verified by probe.docs/PROJECT_NEO.md"Applying these patterns to tvOS" section now has explicit pointers to the new directories.Windscribe-Debug.xcscheme,Windscribe-Staging.xcscheme,Windscribe-Release.xcschemeeach get a populated<TestAction>(TestPlans + Testables) so cmd+U works from any scheme. Lands onmain. Next: review + merge → close M0. - 2026-04-30 — M0 —
main—27390bce— PR 4 merged. M0 closed (#1048). GitLab issue #1048 closed withQAlabel; CI-fix detour issue #1061 also closed. All four M0 PRs landed: !1334 (shared context), !1335 (SwiftLint custom rules), !1337 (About reference module), !1339 (tvOS scaffolding + scheme wiring). Next: M1 (#1049) — iOS 18 / tvOS 18 floor + Swift 6-ready build settings, onneo-5.0only. - 2026-05-01 — M2 —
aw/realm-to-grdb—c9345b37— Realm→GRDB branch rebased on post-keychainmain(Phases 1–5 of the rebase). Driver: !1323 (#1040) shipped today, moving sessions/credentials/auth-hash into the Keychain — branch had to drop the four orphaned entity families (Session, OldSession, OpenVPN/IKEv2 credentials) from Records, schema, migrator, and parity suite. Surviving GRDB scope: 14 entity families. !1311 description refreshed; milestone + labels (project-neo,lands-on::main,area::persistence) attached. All gates green: 81/81 tests pass. Long-tail launch cadence locked in (ND-007): D2.2 ships tomainas the Pre-Neo release, D2.3 (schema normalization) follows, D2.4 (Realm removal) waits on Neo + 3-month forced-upgrade soak via/CheckUpdate. Next: M2 alignment review with team; phase-7 doc sync (00-roadmap.md, DECISIONS.md ND-006 + ND-007, agent memory, Notion artifact). Branch retainsaw/realm-to-grdbname (not renamed toaw/neo-m2-*) to preserve !1311's 23 review notes including Andre's substantive feedback on the schema/Records design. - 2026-05-05 — M2 —
main—f1233062— !1311 merged. D2.2 (Realm→GRDB migration) shipped. GRDB now production for the 14 entity families that survived the keychain consolidation; Realm +RealmToGRDBMigratorstay linked through Pre-Neo and Neo as migration source + fallback. The MR also folded in the /CheckUpdateforce_upgradegate (Pre-Neo release introduces the mechanism, not yet enforced — see ND-007). Force-upgrade clears the 24h cooldown so users below Pre-Neo will be re-prompted on every cold launch once the gate is flipped post-Neo. M2 #1050 closed (scope was D2.1 + D2.2; the follow-ups are tracked under #1065 (D2.3 schema normalization) and #1066 (D2.4 Realm removal)). Next: M3 (#1051) — DI modernization with constructor injection +@Environmentshims, landsmain → neo-5.0. - 2026-05-06 — M3 —
aw/neo-m3-di-shims—a29f935a— Single PR landing T3.1–T3.5 opened as MR !1361 againstmain: SwiftLint ruleneo_no_assembler_resolve(Features/** scope), five service protocols + thinLegacy*adapters inWindscribe/Services/Protocols/(VPNConnecting,ServerProviding,CredentialStoring,PreferencesReading,SessionProviding), five@Entryslots inWindscribe/App/Environment+Dependencies.swift,M3ServiceProtocolMockabilityTests(5 mockability sanity tests), and general@unchecked Sendablelegacy-adapter pattern documented indocs/PROJECT_NEO.mdso adapter inline comments stay one-line. M3 plan file added todocs/neo/plans/M3-di-modernization.md. Build clean; lint clean (zero violations); 18/18 tests green (5 new + M0 About). Acceptance:grep -rn "Assembler\.resolve\|import Swinject" Windscribe/Features WindscribeTV/Featuresreturns zero. Lands onmain. Next: review + merge → close M3. - 2026-05-06 — M3 —
main—ba1c1bee— !1361 merged. M3 closed (#1051). Five service-protocol shims (VPNConnecting,ServerProviding,CredentialStoring,PreferencesReading,SessionProviding) + their@Entryslots are in tree;Assembler.resolveis forbidden inFeatures/**by lint. PR also folded in: M0/M3 file-header normalization to the standard codebase format,## Routingsection indocs/PROJECT_NEO.mdintroducing the Screen/View/Route convention on top ofNavigationStack, rename ofAboutView→AboutScreen(outer DI hub) with the inner private rendering view becomingAboutView, and the@unchecked Sendablecleanup tracked as T4.5 in #1052 / Notion roadmap. M2 cadence:main → neo-5.0periodic merge picks this up. Next: M4 (#1052) — Async/Sendable boundaries; plan inplans/M4-async-sendable-boundaries.md. - 2026-05-07 — M4 —
main—3901c93e— PR 1 merged (MR !1365): T4.1 + T4.4.WSNetServerAPIType(40 methods) +WSNetPingManagerType(1 method) Swift-protocol mirrors over the Obj-C generated WSNet classes, conformed via empty extension; all consumers (APIManagerImpl,WireguardAPIManagerImpl,ControlPlane,LocalPingManagerImpl, both tunnel providers,ContainerResolver,ShowLocationIntentHandler) and DI sites (CoreModule,WireguardModule,AppModulesCommon) now depend on the protocols.docs/PROJECT_NEO.mdgains theCombine → AsyncSequenceguideline + protocol-naming convention (*ingfor capability protocols,*Typefor legacy Obj-C bridge mirrors only).WindscribeTests/Features/AdapterStreamEquivalenceTests.swift(7 tests) pins the M0/M3 adapter contracts (initial value yielded, ordered updates, independent streams per access), mutation-verified. Next: PR 2 (T4.2 —VPNConnecting.statusUpdatesAsyncStream). - 2026-05-07 — M4 —
main—507d8c01— PR 2 merged (MR !1371): T4.2.VPNConnectinggrowsvar statusUpdates: AsyncStream<VPNConnectionState>sourced fromVPNStateRepository.vpnInfo(the legacyCurrentValueSubjectfed byNEVPNStatusDidChange).LegacyVPNConnectortakesstateRepository: VPNStateRepositoryat composition;Environment+Dependencies.swiftresolves it.AdapterStreamEquivalenceTestsextended with 3 VPN tests (initial-when-nil, initial-when-seeded, ordered updates), mutation-verified..swiftlint.yml.claudeexclusion folded in. Next: PR 3 (T4.5 — retire@unchecked Sendable). - 2026-05-08 — M4 —
main—e1c86ba5— PR 3 merged (MR !1369): T4.5.@unchecked Sendableretired from all 6Legacy*adapters inWindscribe/Services/Protocols/; 7 legacy protocols (LookAndFeelRepositoryType,Preferences,CredentialsRepository,VPNManager,LocationListRepository,UserSessionRepository,VPNStateRepository) nowSendabledirectly; 4 retroactive value-type conformances onServerCredentialsModel,LocationModel,DatacenterModel,SessionModel(+ helper typesServerMachineModel,DisabledServerModel,SipCountModel,ServerInventoryModel) moved to directSendableon their definition files;@unchecked Sendable is allowed at the legacy-adapter seamsubsection deleted fromdocs/PROJECT_NEO.md.grep -rn "@unchecked Sendable" Windscribe/Services/Protocols/returns zero. Next: PR 4 (T4.3 — tunnel async lifecycle,neo-5.0only) — needs hardware smoke testing. - 2026-05-11 — M4 —
neo-5.0—e5259595— PR 4 merged (MR !1379): T4.3.startTunnel/stopTunnel/sleep/handleAppMessageasync overrides in bothPacketTunnelandWireGuardTunnelproviders; PacketTunnel bridges viawithCheckedThrowingContinuationto*Internalhelpers; vestigialstopHandler+ dead#if os(macOS) exit(0)template hack removed. Hardware smoke test passed across OpenVPN/IKEv2/WireGuard. M4 closed (#1052). Next: M5 (#1053) — Testing modernization (Swift Testing adoption + mock patterns + GRDB in-memory fixtures + optional macOS test target). Landsmain → neo-5.0. Plan file TBD. - 2026-05-11 — M5 —
aw/neo-m5—fd93b53— Single bundled PR (T5.1 + T5.2 + T5.3) opened againstmain. T5.1: verified CI'sfastlane test(scan + xcodebuild under Xcode 26.3) treats@Testsuites as first-class XCResult — no code change. T5.2:## Testing mockssection indocs/PROJECT_NEO.mdcovering struct + actor patterns; newActorMockCredentialStoringinWindscribeTests/Features/MockPatternTests.swiftas the canonical actor mock (none existed in tree). T5.3:## GRDB test fixturessection citingPingDataRecordTestsandGRDBLocalDatabaseParityTestsas canonical in-memoryDatabaseQueueexamples from M2 D2.2 (!1311). - 2026-05-11 — M5 —
main—d8be3a9e— !1387 merged. M5 closed (#1053). All three tasks (T5.1–T5.3) landed in a single bundled PR. Post-merge fix6ca871a3corrected actor mock conformance (letfor sync nonisolated getters;private(set) varonly for actor-isolated mutable state) — caught by CI's test-target build, missed locally becauseWindscribe-Debugscheme's BuildAction excludesWindscribeTests. Mock-tooling research captured: stick with hand-rolled mocks (AI-maintained); macro libraries like Mockable (v0.6.2, pre-1.0) don't yet justify the dependency given AI handles the boilerplate cost. Next: M6 (#1054) — Tunnel cleanup: IKEv2 consolidation (main → neo-5.0) + SiriIntents removal + tunnel-guard cleanup (neo-5.0only). - 2026-05-11 — M6 —
main—26b4005d— PR 1 merged (MR !1390): T6.1. Deleted orphanedWindscribe/Managers/VPN/Utils/VPNManagerUtils+IKEV2Credentials.swift— file was never inproject.pbxproj's compile sources, had zero callers, and contained auserSettings.allowLanetypo. Roadmap's "two assembly sites" premise was incorrect: the live IKEv2 path throughIKEv2VPNConfiguration.buildProtocol+applySettingsis already the single consolidated assembly site. Behavior unchanged. M6 plan file added. - 2026-05-11 — M6 —
neo-5.0—47eb946d— PR 2 merged (MR !1392): T6.2. SiriIntents extension target deleted via Rubyxcodeprojgem (Pythonpbxprojmangled 14 unrelated quoted IDs on round-trip — reverted to gem). Removed: PBXNativeTarget + 3 build configs + XCConfigurationList + build phases + 70 build-file refs + Handlers/* + VPN Managers/* + Info.plist + entitlements + main app's dependency + Embed Foundation Extensions reference. Kept:SiriIntents/SiriIntents.xcstrings+ per-localeSiriOldIntents.intentdefinition/.strings(referenced by the main app target for the AppIntentsCustomIntentMigratedAppIntentseam). pbxproj SiriIntents refs: 37 → 11. Team follow-up: regenerate provisioning profiles to dropcom.windscribe.SiriIntentsbundle ID. - 2026-05-12 — M6 —
neo-5.0—c9d8adf3— PR 3 merged (MR !1391): T6.3. Docs-only — all 7#available(iOS 1[5-7]guards already removed by M1 PR2 (fbfa74df) when the iOS/tvOS floor was lifted to 18. M6 closed (#1054). Lesson logged: surveys forneo-5.0-only work must run onneo-5.0, notmain— the floor differs. Next: M7 (#1055) — Second rebuilt screen (recipe validation),main → neo-5.0.