Skip to content

Commit ee95570

Browse files
1.0.32
1 parent 18289a1 commit ee95570

20 files changed

+764
-1677
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## 1.0.32
4+
- Replaced simulator cat companion visuals with live gesture visualization overlays (tap/swipe) powered by a local socket stream
5+
- Added selectable touch overlay skins (Laser, Ripple, Aurora, Spark, Ghost) for simulator interaction previews
6+
- Hardened ASC bundle ID recovery for multi-target projects, including safer fallback and clearer selector UX
7+
- Improved release version selection/update flow by ignoring stale historical versions when choosing defaults
8+
- Improved imported project metadata/icon hydration and local blitz-iphone MCP command resolution
9+
310
## 1.0.31
411
- New App Wall showing average review time, rejection ratio, and # rejects until success
512
- Version-aware ASC release workflow with create/update flow and unified version picker
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import Darwin
2+
import Foundation
3+
import Testing
4+
@testable import Blitz
5+
6+
@Test func decodeLiveEventRejectsInvalidTapPayload() {
7+
let json = """
8+
{
9+
"v": 1,
10+
"id": "evt-1",
11+
"tsMs": 1774853265123,
12+
"source": { "client": "test" },
13+
"target": { "platform": "ios", "deviceId": "SIM-1" },
14+
"kind": "tap",
15+
"referenceWidth": 393,
16+
"referenceHeight": 852
17+
}
18+
""".data(using: .utf8)!
19+
20+
#expect(GestureVisualizationEvent.decodeLiveEvent(from: json) == nil)
21+
}
22+
23+
@MainActor
24+
@Test func gestureSocketServiceReceivesLiveEventsAndDedupesByID() async throws {
25+
let root = URL(fileURLWithPath: "/tmp/gv-\(UUID().uuidString.prefix(8))", isDirectory: true)
26+
try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true)
27+
defer { try? FileManager.default.removeItem(at: root) }
28+
29+
let socketURL = root.appendingPathComponent("gesture-events.sock")
30+
let service = GestureVisualizationSocketService(socketURL: socketURL)
31+
defer { service.tearDown() }
32+
33+
let tapEvent: [String: Any] = [
34+
"v": 1,
35+
"id": "evt-1",
36+
"tsMs": 1_774_853_265_123 as Int64,
37+
"source": ["client": "test-client"],
38+
"target": ["platform": "ios", "deviceId": "SIM-1"],
39+
"kind": "tap",
40+
"x": 120,
41+
"y": 240,
42+
"referenceWidth": 393,
43+
"referenceHeight": 852,
44+
]
45+
46+
try sendDatagram(jsonObject: tapEvent, to: socketURL)
47+
try sendDatagram(jsonObject: tapEvent, to: socketURL)
48+
49+
for _ in 0..<50 where service.liveEvents.isEmpty {
50+
try await Task.sleep(for: .milliseconds(10))
51+
}
52+
53+
#expect(service.liveEvents.count == 1)
54+
#expect(service.events(for: "SIM-1").count == 1)
55+
#expect(service.events(for: "OTHER").isEmpty)
56+
}
57+
58+
private func sendDatagram(jsonObject: [String: Any], to socketURL: URL) throws {
59+
let data = try JSONSerialization.data(withJSONObject: jsonObject)
60+
let fd = socket(AF_UNIX, SOCK_DGRAM, 0)
61+
#expect(fd >= 0)
62+
defer { Darwin.close(fd) }
63+
64+
var address = try makeSocketAddress(path: socketURL.path)
65+
let addressLength = socklen_t(address.sun_len)
66+
let sent = data.withUnsafeBytes { buffer in
67+
withUnsafePointer(to: &address) { pointer in
68+
pointer.withMemoryRebound(to: sockaddr.self, capacity: 1) { sockaddrPointer in
69+
sendto(fd, buffer.baseAddress, buffer.count, 0, sockaddrPointer, addressLength)
70+
}
71+
}
72+
}
73+
74+
#expect(sent == data.count)
75+
}
76+
77+
private func makeSocketAddress(path: String) throws -> sockaddr_un {
78+
var address = sockaddr_un()
79+
let maxPathLength = MemoryLayout.size(ofValue: address.sun_path) - 1
80+
guard path.utf8.count <= maxPathLength else {
81+
struct PathError: Error {}
82+
throw PathError()
83+
}
84+
85+
address.sun_len = UInt8(MemoryLayout<sockaddr_un>.size)
86+
address.sun_family = sa_family_t(AF_UNIX)
87+
withUnsafeMutableBytes(of: &address.sun_path) { destination in
88+
path.withCString { source in
89+
destination.copyBytes(from: UnsafeRawBufferPointer(start: source, count: path.utf8.count + 1))
90+
}
91+
}
92+
return address
93+
}

Tests/blitz_tests/SimulatorCatSceneModelTests.swift

Lines changed: 0 additions & 69 deletions
This file was deleted.

docs/2026-03-30-03-review-todo.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# TODO: Review Follow-Ups
2+
3+
Created: `2026-03-30 03:00` local time
4+
5+
## Release blockers
6+
7+
- [P1] Ignore historical rejected versions when picking the default version
8+
- File: `src/managers/asc/ASCReleaseManager.swift:29-34`
9+
- Problem: `selectedVersion` can prefer an older rejected/editable version over the newer live/current version.
10+
- Impact: Overview, Store Listing, Screenshots, and Review can open against the wrong version by default, and later reads/writes can target the stale rejected release until the user manually switches versions.
11+
12+
- [P1] Ignore historical rejected versions when blocking new updates
13+
- File: `src/managers/asc/ASCReleaseManager.swift:21-22`
14+
- Problem: `currentUpdateVersion` treats any historical non-live/non-removed version as an in-flight update.
15+
- Impact: Apps that already shipped a newer live version after an older rejection can be incorrectly blocked from creating the next update.
16+
17+
- [P1] Drop reviewer details from sync payload when sharing is disabled
18+
- File: `src/services/appwall/AppWallSyncDataBuilder.swift:144-151`
19+
- Problem: the sync payload still uploads `rejectionReasons`, `reviewerMessage`, and `guidelineIds` when the user disables reviewer-feedback sharing, and only flips `isPublic` to `false`.
20+
- Impact: sensitive reviewer feedback is still uploaded to the App Wall backend, so the opt-out is not actually honored.
21+
22+
- [P2] Map submission history entries to their actual ASC state
23+
- File: `src/managers/asc/ASCSubmissionHistoryManager.swift:17-22`
24+
- Problem: each `ASCReviewSubmission` is currently recorded as `.submitted` regardless of whether ASC says it is `IN_REVIEW`, `ACCEPTED`, `PROCESSING`, or already live.
25+
- Impact: for apps without an Iris rejection cycle, the Overview submission timeline collapses to repeated `Submitted` rows and loses lifecycle accuracy.
26+
27+
## Suggested order
28+
29+
1. Fix the two `ASCReleaseManager` regressions first, since they affect core version selection and update creation behavior.
30+
2. Fix reviewer-feedback opt-out so disabled sharing truly prevents upload of reviewer details.
31+
3. Restore submission-history state mapping so the lifecycle timeline reflects ASC state transitions again.

docs/TODO.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
App wall - see ranking of longest and shortest submission, see your global ranking lol. heavily tested changes made to both backend ~/superapp/utils/teenybase and engagement focused model parser & view logic here. We can do a LOT better on view

0 commit comments

Comments
 (0)