driver-sony: downgrade to monitoring-only per research — Venice IP look control closed/unverified; push() rejects with SDI-chain guidance; lut3dSizes=[]

This commit is contained in:
Forge Dev 2026-07-11 14:04:56 +00:00
parent 8fc0e95cdc
commit f4eb9b7a95
2 changed files with 29 additions and 41 deletions

View file

@ -14,13 +14,18 @@ enum SonyPaths {
static let userLut = "/cna/v1/monitoring/lut" static let userLut = "/cna/v1/monitoring/lut"
} }
/// Venice 2 driver: REST over IP. Capability-narrow user 3D LUT push only, /// Venice 2 driver POSTURE PER RESEARCH (docs/research/arri-cap-protocol.md, Sony
/// no native CDL (grade pipeline must full-bake for this camera). /// section): Venice IP protocol is CLOSED (partner products speak it natively; public
/// path is only the authenticated web remote at /rmt.html). This driver keeps our
/// provisional REST shape for the simulator and future backend-capture correction,
/// but capabilities are downgraded: NO look push claimed (lut3dSizes empty,
/// no native CDL) until verified on hardware/partner docs. On-set Venice grading
/// path today = SDI-chain LUT box / DeckLink output, not camera-internal.
public actor SonyDriver: CameraDriver { public actor SonyDriver: CameraDriver {
public nonisolated let capabilities = CameraCapabilities( public nonisolated let capabilities = CameraCapabilities(
vendor: .sony, vendor: .sony,
supportsNativeCDL: false, supportsNativeCDL: false,
lut3dSizes: [17, 33], lut3dSizes: [],
metadataFields: [.clipName, .exposureIndex, .whiteBalance, .tint, .fps, .timecode]) metadataFields: [.clipName, .exposureIndex, .whiteBalance, .tint, .fps, .timecode])
private let host: String private let host: String
@ -118,26 +123,11 @@ public actor SonyDriver: CameraDriver {
} }
public func push(look: FlattenedLook) async throws { public func push(look: FlattenedLook) async throws {
guard look.cdl == nil else { // Venice IP look control is closed/unverified (see research doc).
throw CameraError.unsupportedLook("Venice has no native CDL — re-flatten with splitLeadingCDL=false") // Grade Venice via SDI-chain LUT box or DeckLink output. Re-enable
} // once a real wire path is proven (partner SDK or backend capture).
guard let lut = look.lut else { throw CameraError.unsupportedLook(
throw CameraError.unsupportedLook("nothing to push") "Venice look push over IP unverified — use SDI-chain LUT box; monitoring-only driver")
}
guard capabilities.lut3dSizes.contains(lut.size) else {
throw CameraError.unsupportedLook("LUT size \(lut.size) not in \(capabilities.lut3dSizes)")
}
let payload = try JSONSerialization.data(
withJSONObject: ["size": lut.size, "table": lut.table],
options: [.sortedKeys])
var req = URLRequest(url: url(SonyPaths.userLut))
req.httpMethod = "PUT"
req.httpBody = payload
req.setValue("application/json", forHTTPHeaderField: "Content-Type")
let (_, http) = try await perform(req)
guard http.statusCode == 200 else {
throw CameraError.pushFailed("LUT upload -> \(http.statusCode)")
}
} }
// MARK: Polling // MARK: Polling

View file

@ -28,12 +28,12 @@ final class SonyDriverTests: XCTestCase {
return SonyDriver(host: "127.0.0.1", port: port, pollInterval: .milliseconds(20)) return SonyDriver(host: "127.0.0.1", port: port, pollInterval: .milliseconds(20))
} }
// Venice 2: NO native CDL capability-narrow. // Venice 2: protocol closed (research) no look-push capability claimed.
func testCapabilities() async { func testCapabilities() async {
let driver = await makeDriver() let driver = await makeDriver()
XCTAssertEqual(driver.capabilities.vendor, .sony) XCTAssertEqual(driver.capabilities.vendor, .sony)
XCTAssertFalse(driver.capabilities.supportsNativeCDL) XCTAssertFalse(driver.capabilities.supportsNativeCDL)
XCTAssertTrue(driver.capabilities.lut3dSizes.contains(33)) XCTAssertTrue(driver.capabilities.lut3dSizes.isEmpty)
} }
func testConnectEmitsConnected() async throws { func testConnectEmitsConnected() async throws {
@ -70,26 +70,24 @@ final class SonyDriverTests: XCTestCase {
await driver.disconnect() await driver.disconnect()
} }
// LUT-only push accepted. // Any look push rejected: Venice look control unverified/closed (research).
func testPushLutOnly() async throws { // Metadata/rec-state monitoring is the only claimed capability.
func testAnyPushRejected() async throws {
let driver = await makeDriver() let driver = await makeDriver()
try await driver.connect() try await driver.connect()
let look = FlattenedLook(cdl: nil, lut: Lut3D.identity(size: 33), latticeSize: 33)
try await driver.push(look: look) let lutOnly = FlattenedLook(cdl: nil, lut: Lut3D.identity(size: 33), latticeSize: 33)
let count = await sim.uploadedLutCount do {
XCTAssertEqual(count, 1) try await driver.push(look: lutOnly)
await driver.disconnect() XCTFail("expected unsupportedLook")
} catch let e as CameraError {
guard case .unsupportedLook = e else { return XCTFail("wrong error") }
} }
// Push with split CDL to a no-native-CDL camera must throw unsupportedLook
// caller (gang layer) is responsible for re-flattening full-bake.
func testPushSplitCDLRejected() async throws {
let driver = await makeDriver()
try await driver.connect()
let cdl = CDL(slope: SIMD3(1.2, 1, 1), offset: .zero, power: .one, saturation: 1) let cdl = CDL(slope: SIMD3(1.2, 1, 1), offset: .zero, power: .one, saturation: 1)
let look = FlattenedLook(cdl: cdl, lut: Lut3D.identity(size: 33), latticeSize: 33) let withCDL = FlattenedLook(cdl: cdl, lut: nil, latticeSize: 33)
do { do {
try await driver.push(look: look) try await driver.push(look: withCDL)
XCTFail("expected unsupportedLook") XCTFail("expected unsupportedLook")
} catch let e as CameraError { } catch let e as CameraError {
guard case .unsupportedLook = e else { return XCTFail("wrong error") } guard case .unsupportedLook = e else { return XCTFail("wrong error") }