fix(watch): decode semantic approval outcomes

This commit is contained in:
Vincent Koc
2026-07-12 15:58:00 +02:00
parent a1f0a92b03
commit e4ffa5fd92
4 changed files with 22 additions and 1 deletions

View File

@@ -129,8 +129,9 @@ struct WatchChatStatusLocalizationTests {
}
@Test func `semantic approval outcomes win before legacy decision fallbacks`() {
let parsedOutcome = WatchExecApprovalResolvedMessage.parseTransportOutcome("allowedAlways")
let allowedAlways = WatchExecApprovalOutcome.resolved(
outcome: .allowedAlways,
outcome: parsedOutcome,
legacyText: "Approval denied.",
decision: .deny,
source: "another-reviewer")
@@ -148,6 +149,7 @@ struct WatchChatStatusLocalizationTests {
#expect(allowedAlways.code == .allowedAlways)
#expect(deniedElsewhere.code == .denied)
#expect(unknownElsewhere.code == .resolvedElsewhere)
#expect(WatchExecApprovalResolvedMessage.parseTransportOutcome("future") == nil)
}
@Test func `gateway presentation localizes key and keeps backend override verbatim`() {

View File

@@ -157,6 +157,18 @@ struct WatchApprovalTransportSourceGuardTests {
#expect(!parser.contains("?? []"))
}
@Test func `watch preserves semantic approval outcomes through receiver parsing`() throws {
let receiverSource = try Self.readWatchSource("WatchConnectivityReceiver.swift")
let parser = try Self.extract(
receiverSource,
from: "private static func parseExecApprovalResolvedPayload(",
to: "private static func parseExecApprovalExpiredPayload(")
#expect(parser.contains(
"WatchExecApprovalResolvedMessage.parseTransportOutcome(payload[\"outcome\"])"))
#expect(parser.contains("outcome: outcome"))
}
@Test func `watch reuses exact compound identifier policy`() throws {
let receiverSource = try Self.readWatchSource("WatchConnectivityReceiver.swift")
let storeSource = try Self.readWatchSource("WatchInboxStore.swift")

View File

@@ -470,6 +470,7 @@ final class WatchConnectivityReceiver: NSObject, @unchecked Sendable {
}
guard let approvalId = WatchApprovalID.exact(payload["approvalId"] as? String) else { return nil }
let decision = Self.parseExecApprovalDecision(payload["decision"])
let outcome = WatchExecApprovalResolvedMessage.parseTransportOutcome(payload["outcome"])
let gatewayStableID = WatchGatewayID.exact(payload["gatewayStableID"] as? String)
let resolvedAtMs = (payload["resolvedAtMs"] as? NSNumber)?.int64Value
let source = (payload["source"] as? String)?.trimmingCharacters(in: .whitespacesAndNewlines)
@@ -479,6 +480,7 @@ final class WatchConnectivityReceiver: NSObject, @unchecked Sendable {
approvalId: approvalId,
gatewayStableID: gatewayStableID,
decision: decision,
outcome: outcome,
resolvedAtMs: resolvedAtMs,
source: source,
outcomeText: outcomeText?.isEmpty == false ? outcomeText : nil)

View File

@@ -33,6 +33,11 @@ struct WatchExecApprovalResolvedMessage: Codable, Equatable {
var resolvedAtMs: Int64?
var source: String?
var outcomeText: String?
static func parseTransportOutcome(_ value: Any?) -> WatchExecApprovalTransportOutcome? {
guard let rawValue = value as? String else { return nil }
return WatchExecApprovalTransportOutcome(rawValue: rawValue)
}
}
struct WatchExecApprovalExpiredMessage: Codable, Equatable {