Expand onboarding and adaptive keyboard intelligence

Add resilient usage analytics, OOBE gateway flows, clipboard semantic ranking, purchase recovery, style learning, and managed current-information search.
This commit is contained in:
Rocky
2026-08-22 16:33:18 +08:00
parent ac374631ae
commit e5a83843db
162 changed files with 23574 additions and 1013 deletions
@@ -38,8 +38,11 @@ final class AnalyticsUploadCoordinatorTests: XCTestCase {
let topLevel = try XCTUnwrap(
JSONSerialization.jsonObject(with: request.body) as? [String: Any]
)
XCTAssertEqual(Set(topLevel.keys), ["events"])
XCTAssertEqual((topLevel["events"] as? [Any])?.count, 2)
XCTAssertEqual(Set(topLevel.keys), ["installationId", "events"])
XCTAssertEqual(topLevel["installationId"] as? String, analyticsTestUUID(1).uuidString.lowercased())
let eventObjects = try XCTUnwrap(topLevel["events"] as? [[String: Any]])
XCTAssertEqual(eventObjects.count, 2)
XCTAssertTrue(eventObjects.allSatisfy { !$0.keys.contains("installationId") })
}
func testCountMismatchRetriesWithoutMutatingPayloadOrEventID() async throws {
@@ -262,6 +265,39 @@ final class AnalyticsUploadCoordinatorTests: XCTestCase {
XCTAssertEqual(requests.count, 1)
}
func testCancellationReleasesLeasesWithoutSchedulingRetry() async throws {
let clock = AnalyticsTestWallClock()
let repository = try await makeRepository(clock: clock, eventCount: 1)
let network = CancellableAnalyticsNetwork()
let coordinator = makeCoordinator(
repository: repository,
network: network,
clock: clock
)
let upload = Task {
await coordinator.uploadAvailableEvents()
}
for _ in 0..<100 {
if await network.didStart() {
break
}
try await Task.sleep(for: .milliseconds(10))
}
let didStart = await network.didStart()
XCTAssertTrue(didStart)
upload.cancel()
await upload.value
let snapshot = await repository.debugSnapshot()
XCTAssertEqual(snapshot.pendingEvents.first?.attemptCount, 0)
let recovered = await repository.leaseBatch(
ownerID: "after-cancellation",
configuration: uploadConfiguration()
)
XCTAssertEqual(recovered?.events.count, 1)
}
private func makeRepository(
clock: AnalyticsTestWallClock,
eventCount: Int,
@@ -306,3 +342,18 @@ final class AnalyticsUploadCoordinatorTests: XCTestCase {
)
}
}
private actor CancellableAnalyticsNetwork: AnalyticsNetworking {
private var started = false
func send(_ request: AnalyticsHTTPRequest) async throws -> AnalyticsHTTPResponse {
_ = request
started = true
try await Task.sleep(for: .seconds(30))
return analyticsSuccessResponse(accepted: 1)
}
func didStart() -> Bool {
started
}
}