Validate exact Vision boundary values and real-project regression

This commit is contained in:
Mikei386
2026-09-13 10:33:13 +02:00
parent e1457aede1
commit 031dc50b99
3 changed files with 38 additions and 8 deletions
+2 -2
View File
@@ -19,9 +19,9 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.4.1</string> <string>0.4.2</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>6</string> <string>7</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>13.0</string> <string>13.0</string>
<key>NSHighResolutionCapable</key> <key>NSHighResolutionCapable</key>
+4 -3
View File
@@ -924,9 +924,10 @@ final class VideoProcessor: ObservableObject {
if let pose = sample.pose { if let pose = sample.pose {
guard [pose.x, pose.y, pose.height, pose.yaw, pose.roll].allSatisfy({ $0.isFinite }), guard [pose.x, pose.y, pose.height, pose.yaw, pose.roll].allSatisfy({ $0.isFinite }),
(0...1).contains(pose.x), (0...1).contains(pose.y), (0...1).contains(pose.height), (0...1).contains(pose.x), (0...1).contains(pose.y), (0...1).contains(pose.height),
// Vision angles originate as Float; Float.pi is slightly larger than Double.pi. // Vision may return either Float rounding adjacent to pi. Swift Float.pi
abs(pose.yaw) <= Double(Float.pi), abs(pose.roll) <= Double(Float.pi), // is not necessarily the rounding used by Vision; allow 1e-6 radians.
pose.pitch == nil || (pose.pitch!.isFinite && abs(pose.pitch!) <= Double(Float.pi)) else { return false } abs(pose.yaw) <= (.pi + 1e-6), abs(pose.roll) <= (.pi + 1e-6),
pose.pitch == nil || (pose.pitch!.isFinite && abs(pose.pitch!) <= (.pi + 1e-6)) else { return false }
} }
if let color = sample.color { if let color = sample.color {
guard color.luminance.isFinite, (0...1).contains(color.luminance), guard color.luminance.isFinite, (0...1).contains(color.luminance),
+32 -3
View File
@@ -29,6 +29,35 @@ struct RenderIntegration {
@MainActor @MainActor
static func main() async throws { static func main() async throws {
if let path = ProcessInfo.processInfo.environment["GROWTHLAPSE_VALIDATE_PROJECT"] {
let validator = VideoProcessor()
guard let project = validator.loadProject(from: URL(fileURLWithPath: path)) else {
throw TestFailure.failed("Real project validation failed: \(validator.state)")
}
print("PASS real project load: \(project.clips.count) clips")
if ProcessInfo.processInfo.environment["GROWTHLAPSE_TEST_REAL_DRAFT"] == "1" {
let original = try Data(contentsOf: URL(fileURLWithPath: path))
var subset = project
subset.clips = project.clips.filter { $0.displayName.hasPrefix("063") || $0.displayName.hasPrefix("066") }
try require(subset.clips.count == 2, "Expected two selected regression clips")
validator.project = subset
validator.startDraft(settings: SettingsStore.load())
let deadline = Date().addingTimeInterval(180)
while validator.state.isRunning && Date() < deadline {
try await Task.sleep(nanoseconds: 100_000_000)
}
guard let draft = validator.draftOutput else {
validator.cancel()
throw TestFailure.failed("Real draft failed: \(validator.state)\n\(validator.logs.suffix(25).joined(separator: "\n"))")
}
try require(FileManager.default.fileExists(atPath: draft.path), "Real draft missing")
let after = try Data(contentsOf: URL(fileURLWithPath: path))
try require(original == after, "Real draft changed source project")
print("PASS actual affected clips rendered as isolated draft: \(draft.path)")
validator.discardDraft()
return
}
}
try ContinuityChecks.run() try ContinuityChecks.run()
let defaults = RenderSettings() let defaults = RenderSettings()
try require(defaults.inputFolder == nil && defaults.outputFile == nil try require(defaults.inputFolder == nil && defaults.outputFile == nil
@@ -198,7 +227,7 @@ struct RenderIntegration {
// Vision's single-precision ±pi must survive project validation unchanged. // Vision's single-precision ±pi must survive project validation unchanged.
var angleProject = second var angleProject = second
let visionPi = Double(Float.pi) let visionPi = 3.1415927410125732 // Exact value observed in Vision JSON; not Swift Float.pi
angleProject.clips[0].visualAnalysis = ClipVisualAnalysis(sourceSignature: "angle-test", samples: [ angleProject.clips[0].visualAnalysis = ClipVisualAnalysis(sourceSignature: "angle-test", samples: [
VisualSample(time: 0, faceCount: 1, VisualSample(time: 0, faceCount: 1,
pose: FacePose(x: 0.5, y: 0.5, height: 0.3, yaw: visionPi, pose: FacePose(x: 0.5, y: 0.5, height: 0.3, yaw: visionPi,
@@ -210,10 +239,10 @@ struct RenderIntegration {
let accepted = angleLoader.loadProject(from: angleURL) let accepted = angleLoader.loadProject(from: angleURL)
try require(accepted?.clips[0].visualAnalysis == angleProject.clips[0].visualAnalysis, try require(accepted?.clips[0].visualAnalysis == angleProject.clips[0].visualAnalysis,
"Valid Vision Float.pi angles rejected or altered") "Valid Vision Float.pi angles rejected or altered")
angleProject.clips[0].visualAnalysis!.samples[0].pose!.roll = 3.15 angleProject.clips[0].visualAnalysis!.samples[0].pose!.roll = Double.pi + 0.00001
try JSONEncoder().encode(angleProject).write(to: angleURL) try JSONEncoder().encode(angleProject).write(to: angleURL)
try require(angleLoader.loadProject(from: angleURL) == nil, "Out-of-range angle accepted") try require(angleLoader.loadProject(from: angleURL) == nil, "Out-of-range angle accepted")
print("PASS Vision Float.pi project round-trip and invalid-angle rejection") print("PASS Vision exact boundary project round-trip and invalid-angle rejection")
// Exercise failure after normalization, while FFmpeg is producing the final video. // Exercise failure after normalization, while FFmpeg is producing the final video.
let wrapper = root.appendingPathComponent("ffmpeg-fail") let wrapper = root.appendingPathComponent("ffmpeg-fail")