commit b0c62230dc4a614938e38ba218a1c01812814220
parent 5ceb37f04ff229f98cbc797673d58f493376b18e
Author: triesap <tyson@radroots.org>
Date: Wed, 9 Sep 2026 14:16:43 +0000
ios: make opened media lifetime explicit
- Protect the native file collection with a checked Sendable mutex owner.
- Preserve Rust handles through repeated close and late foreign completion.
- Test concurrent close, deinit, partial-open cleanup, cancellation and timeout.
- Verify sanitizer regressions, standalone gates and generated project freshness.
Diffstat:
11 files changed, 171 insertions(+), 27 deletions(-)
diff --git a/Package.swift b/Package.swift
@@ -60,6 +60,7 @@ let package = Package(
"Runtime/TeraGeneratedRuntimeBackend.swift",
"Runtime/TeraLifecycleCoordinator.swift",
"Runtime/TeraLifecycleBridge.swift",
+ "Runtime/TeraOpenedMedia.swift",
"Runtime/TeraPreparedMediaHandle.swift",
"Runtime/TeraRuntimeBoundedTask.swift",
"Runtime/TeraRuntimeClient.swift",
diff --git a/Tera.xcodeproj/project.pbxproj b/Tera.xcodeproj/project.pbxproj
@@ -11,6 +11,7 @@
1D45B3D566A0A60063190854 /* TeraApp in Frameworks */ = {isa = PBXBuildFile; productRef = E666175A800272732A27CBEB /* TeraApp */; };
229C9AC991E67663DA53D339 /* TeraRuntimeBoundedTaskTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A4FFC0023C620B68D0EC0ED /* TeraRuntimeBoundedTaskTests.swift */; };
2479571FA99A7962794999C4 /* TeraSupportingStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0636AEDEB50DDDD328374A9 /* TeraSupportingStoreTests.swift */; };
+ 2A68D8FEEC3B88D47D696589 /* TeraOpenedMediaCloseFixture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74FCF1C4A8A7137623BBE223 /* TeraOpenedMediaCloseFixture.swift */; };
2AEAFDD0EECA3B7F799B1287 /* TeraScopedAddTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A756C16ACFABBD36C48DF62 /* TeraScopedAddTests.swift */; };
2B50FA35AD753EFA15CF00CD /* TeraRuntimeBackpressureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8591841AD9AB9B718A37EB47 /* TeraRuntimeBackpressureTests.swift */; };
2C6DDB502DFA11C2CBCA49C4 /* TeraApp in Frameworks */ = {isa = PBXBuildFile; productRef = A1979630FE6BC343F0E59F24 /* TeraApp */; };
@@ -25,6 +26,7 @@
671EF50DB4EFBC25AABF26DC /* TeraLifecycleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C890BDE885536BC2AB215393 /* TeraLifecycleTests.swift */; };
6B0BE8E92892EF60B8E996A5 /* TeraRuntimeResourceFixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0A51F9AF2E0803264E07FBB /* TeraRuntimeResourceFixtures.swift */; };
6F53FF88A29F8DF93F074EB4 /* TeraBackgroundUploadFixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61D8C0835D5A1D5C36D80020 /* TeraBackgroundUploadFixtures.swift */; };
+ 6FED2D2255CC702B33CDC760 /* TeraOpenedMediaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B10B1F3C7FCD9A72F04FC00 /* TeraOpenedMediaTests.swift */; };
7035433B676A50A4801A8DFC /* TeraRuntimeInvalidationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73EBD10E201ECA26DCED523F /* TeraRuntimeInvalidationTests.swift */; };
70417FB635F06CC9829FB38C /* TeraClockTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A506546B0EC1792240C36F7 /* TeraClockTests.swift */; };
772A9B1AD8DE1D2E0969F285 /* TeraCalendarFFICompatibilityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B808E67E85CD36E49C38B6F /* TeraCalendarFFICompatibilityTests.swift */; };
@@ -98,6 +100,7 @@
6967B3EAC4CF1A410B26DD1A /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
6B8677670E203FF68EC88983 /* TeraRootShellTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TeraRootShellTests.swift; sourceTree = "<group>"; };
73EBD10E201ECA26DCED523F /* TeraRuntimeInvalidationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TeraRuntimeInvalidationTests.swift; sourceTree = "<group>"; };
+ 74FCF1C4A8A7137623BBE223 /* TeraOpenedMediaCloseFixture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TeraOpenedMediaCloseFixture.swift; sourceTree = "<group>"; };
794D475C70BA8ED994D1CA66 /* TeraTodayStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TeraTodayStoreTests.swift; sourceTree = "<group>"; };
7C0836F5D5F71F9A54795C57 /* TeraSessionGenerationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TeraSessionGenerationTests.swift; sourceTree = "<group>"; };
8591841AD9AB9B718A37EB47 /* TeraRuntimeBackpressureTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TeraRuntimeBackpressureTests.swift; sourceTree = "<group>"; };
@@ -106,6 +109,7 @@
93A3358AFC23C567DB9CB02F /* TeraErrorRecoveryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TeraErrorRecoveryTests.swift; sourceTree = "<group>"; };
98E969BCFF7CED33A1D4A040 /* TeraStateMigrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TeraStateMigrationTests.swift; sourceTree = "<group>"; };
999BDCEF144A19F35D048D15 /* TeraTests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = TeraTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 9B10B1F3C7FCD9A72F04FC00 /* TeraOpenedMediaTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TeraOpenedMediaTests.swift; sourceTree = "<group>"; };
9ED6D3E35C3235B6068E1902 /* TeraScopeBackend.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TeraScopeBackend.swift; sourceTree = "<group>"; };
9F22CFABCF27A28408F68D25 /* TeraAddStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TeraAddStoreTests.swift; sourceTree = "<group>"; };
9F54FC4930051FC4611B37D3 /* tera */ = {isa = PBXFileReference; lastKnownFileType = folder; name = tera; path = .; sourceTree = SOURCE_ROOT; };
@@ -201,6 +205,8 @@
61B6F0B16BFD8F046E9C163F /* TeraMediaStoreTests.swift */,
02F322CF98F8BEB908B93215 /* TeraMutationAdmissionTests.swift */,
21DD785439F415278214D746 /* TeraObservationCoalescingTests.swift */,
+ 74FCF1C4A8A7137623BBE223 /* TeraOpenedMediaCloseFixture.swift */,
+ 9B10B1F3C7FCD9A72F04FC00 /* TeraOpenedMediaTests.swift */,
E351F52E77C74A4E99095E45 /* TeraRemoteQualificationTests.swift */,
6B8677670E203FF68EC88983 /* TeraRootShellTests.swift */,
8591841AD9AB9B718A37EB47 /* TeraRuntimeBackpressureTests.swift */,
@@ -446,6 +452,8 @@
CDBE38E6B521611436F28858 /* TeraMediaStoreTests.swift in Sources */,
BB71614D2A6017C071A39BED /* TeraMutationAdmissionTests.swift in Sources */,
AC33144E09CB0384C4FB090C /* TeraObservationCoalescingTests.swift in Sources */,
+ 2A68D8FEEC3B88D47D696589 /* TeraOpenedMediaCloseFixture.swift in Sources */,
+ 6FED2D2255CC702B33CDC760 /* TeraOpenedMediaTests.swift in Sources */,
81AF9DDA0E64DC4EEFCEF25D /* TeraRemoteQualificationTests.swift in Sources */,
9AD968F0B37C64B5AF8D9A68 /* TeraRootShellTests.swift in Sources */,
2B50FA35AD753EFA15CF00CD /* TeraRuntimeBackpressureTests.swift in Sources */,
diff --git a/Tera/Runtime/TeraAddMediaCoordinator.swift b/Tera/Runtime/TeraAddMediaCoordinator.swift
@@ -48,28 +48,6 @@ extension TeraAddMediaHandling {
func reconcileBackgroundUploads(drafts _: [TeraDraftStatus]) async throws {}
}
-final class TeraOpenedMedia: @unchecked Sendable {
- let handles: [TeraPreparedMediaHandle]
- private var files: [FileHandle]
-
- init(handles: [TeraPreparedMediaHandle], files: [FileHandle]) {
- self.handles = handles
- self.files = files
- }
-
- deinit {
- close()
- }
-
- func close() {
- let active = files
- files.removeAll()
- for file in active {
- try? file.close()
- }
- }
-}
-
actor TeraAddMediaCoordinator: TeraAddMediaHandling {
private let roots: RadrootsAppleFileRoots
private let picker: any RadrootsMediaPicker
diff --git a/Tera/Runtime/TeraOpenedMedia.swift b/Tera/Runtime/TeraOpenedMedia.swift
@@ -0,0 +1,30 @@
+import Foundation
+import Synchronization
+
+/// Owns the native originals until exactly one caller takes them for close.
+/// Immutable Rust handles retain their independent files through late FFI work.
+final class TeraOpenedMedia: Sendable {
+ let handles: [TeraPreparedMediaHandle]
+ private let files: Mutex<[FileHandle]>
+
+ init(handles: [TeraPreparedMediaHandle], files: [FileHandle]) {
+ self.handles = handles
+ self.files = Mutex(files)
+ }
+
+ deinit {
+ close()
+ }
+
+ func close() {
+ let active = files.withLock { files in
+ let active = files
+ files.removeAll()
+ return active
+ }
+ // File I/O occurs outside the short ownership-transfer critical section.
+ for file in active {
+ try? file.close()
+ }
+ }
+}
diff --git a/TeraTests/TeraBackgroundUploadFixtures.swift b/TeraTests/TeraBackgroundUploadFixtures.swift
@@ -43,6 +43,10 @@ final class BackgroundUploadFixture: @unchecked Sendable {
try? FileManager.default.removeItem(at: root)
}
+ var stagedFileURL: URL {
+ roots.stagedBlobsRoot.appendingPathComponent(media.sha256)
+ }
+
func coordinator(transfer: any RadrootsBackgroundTransfer) -> TeraAddMediaCoordinator {
TeraAddMediaCoordinator(
roots: roots,
diff --git a/TeraTests/TeraMediaOwnershipFFITests.swift b/TeraTests/TeraMediaOwnershipFFITests.swift
@@ -108,7 +108,7 @@ final class TeraMediaOwnershipFFITests: XCTestCase {
case .cancelled: XCTAssertFalse(timeout)
case .completed: XCTFail("The foreign work is still paused")
}
- opened.close()
+ await TeraOpenedMediaCloseFixture.closeConcurrently(opened)
XCTAssertNil(task.settlement())
await pause.resume.open()
let late = await task.settle()
@@ -117,7 +117,7 @@ final class TeraMediaOwnershipFFITests: XCTestCase {
}
}
-private struct MediaOwnershipFixture: Sendable {
+struct MediaOwnershipFixture: Sendable {
let root: URL
let bytes = Data([137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 2, 0, 0, 0, 2])
private let publicKey = "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
diff --git a/TeraTests/TeraOpenedMediaCloseFixture.swift b/TeraTests/TeraOpenedMediaCloseFixture.swift
@@ -0,0 +1,47 @@
+import Darwin
+import Foundation
+@testable import TeraApp
+
+enum TeraOpenedMediaCloseFixture {
+ static func closeConcurrently(_ owner: TeraOpenedMedia) async {
+ await withTaskGroup(of: Void.self) { group in
+ for _ in 0 ..< 64 {
+ group.addTask {
+ for _ in 0 ..< 64 {
+ owner.close()
+ }
+ }
+ }
+ }
+ }
+}
+
+/// The unique fixture stays linked throughout inspection. An inode comparison
+/// remains valid if another simulator task reuses a released descriptor slot.
+struct TeraOpenFileProbe: Sendable {
+ private let device: Int32
+ private let inode: UInt64
+
+ init(url: URL) throws {
+ var value = stat()
+ guard Darwin.lstat(url.path, &value) == 0 else { throw ProbeError.unavailable }
+ device = value.st_dev
+ inode = value.st_ino
+ }
+
+ func owns(_ descriptor: Int32) -> Bool {
+ var value = stat()
+ return Darwin.fstat(descriptor, &value) == 0
+ && value.st_dev == device && value.st_ino == inode
+ }
+
+ var descriptorCount: Int {
+ // The operating system bounds the descriptor table; no pathname is opened
+ // by this scan, and descriptors belonging to other files are ignored.
+ (0 ..< getdtablesize()).reduce(0) { count, descriptor in
+ count + (owns(descriptor) ? 1 : 0)
+ }
+ }
+
+ private enum ProbeError: Error { case unavailable }
+}
diff --git a/TeraTests/TeraOpenedMediaTests.swift b/TeraTests/TeraOpenedMediaTests.swift
@@ -0,0 +1,74 @@
+import Foundation
+@testable import TeraApp
+import XCTest
+
+final class TeraOpenedMediaTests: XCTestCase {
+ func testConcurrentRepeatedCloseLeavesOnlyTheUsableRustOwner() async throws {
+ let fixture = try MediaOwnershipFixture()
+ defer { fixture.remove() }
+ let runtime = try await fixture.runtime()
+ let original = try fixture.original()
+ let descriptor = original.fileDescriptor
+ let probe = try TeraOpenFileProbe(url: fixture.root.appendingPathComponent("original.png"))
+ let opened = try TeraOpenedMedia(
+ handles: [TeraPreparedMediaHandle(media: fixture.media, fileDescriptor: UInt64(descriptor))],
+ files: [original]
+ )
+ XCTAssertEqual(probe.descriptorCount, 2)
+ await TeraOpenedMediaCloseFixture.closeConcurrently(opened)
+ XCTAssertFalse(probe.owns(descriptor))
+ XCTAssertEqual(probe.descriptorCount, 1)
+ let saved = try await fixture.save(runtime, handle: XCTUnwrap(opened.handles.first))
+ XCTAssertEqual(saved.form?.media.first?.sha256, fixture.media.sha256)
+ _ = try await runtime.shutdown()
+ }
+
+ func testDeinitClosesTheOriginalAndReleasesTheLastRustHandle() throws {
+ let fixture = try MediaOwnershipFixture()
+ defer { fixture.remove() }
+ let original = try fixture.original()
+ let descriptor = original.fileDescriptor
+ let probe = try TeraOpenFileProbe(url: fixture.root.appendingPathComponent("original.png"))
+ var opened: TeraOpenedMedia? = try TeraOpenedMedia(
+ handles: [TeraPreparedMediaHandle(media: fixture.media, fileDescriptor: UInt64(descriptor))],
+ files: [original]
+ )
+ weak let weakOwner = opened
+ XCTAssertEqual(opened?.handles.count, 1)
+ XCTAssertEqual(probe.descriptorCount, 2)
+ opened = nil
+ XCTAssertNil(weakOwner)
+ XCTAssertFalse(probe.owns(descriptor))
+ XCTAssertEqual(probe.descriptorCount, 0)
+ }
+
+ func testProductionPartialOpenFailureReleasesBothNativeAndRustResources() async throws {
+ let fixture = try BackgroundUploadFixture()
+ defer { fixture.remove() }
+ let coordinator = fixture.coordinator(transfer: BackgroundTransferHarness())
+ let probe = try TeraOpenFileProbe(url: fixture.stagedFileURL)
+ var control: TeraOpenedMedia? = try await coordinator.open([fixture.media])
+ XCTAssertEqual(probe.descriptorCount, 2)
+ control?.close()
+ control = nil
+ XCTAssertEqual(probe.descriptorCount, 0)
+ let missing = missingMedia(fixture.media)
+ for _ in 0 ..< 16 {
+ do {
+ let unexpected = try await coordinator.open([fixture.media, missing])
+ unexpected.close()
+ XCTFail("The second staged file does not exist")
+ } catch {}
+ XCTAssertEqual(probe.descriptorCount, 0)
+ }
+ }
+
+ private func missingMedia(_ media: TeraPreparedMedia) -> TeraPreparedMedia {
+ let missing = String(repeating: "f", count: 64)
+ return TeraPreparedMedia(
+ opaqueReference: "media:\(missing)", remoteURL: nil, sha256: missing,
+ mediaType: media.mediaType, byteSize: media.byteSize, width: media.width,
+ height: media.height, alt: media.alt, preparedAtUnixSeconds: media.preparedAtUnixSeconds
+ )
+ }
+}
diff --git a/project.yml b/project.yml
@@ -74,6 +74,8 @@ targets:
- path: TeraTests/TeraMediaStoreTests.swift
- path: TeraTests/TeraMediaFileFixture.swift
- path: TeraTests/TeraMediaOwnershipFFITests.swift
+ - path: TeraTests/TeraOpenedMediaCloseFixture.swift
+ - path: TeraTests/TeraOpenedMediaTests.swift
- path: TeraTests/TeraAddStoreTests.swift
- path: TeraTests/TeraBackgroundUploadFixtures.swift
- path: TeraTests/TeraMutationAdmissionTests.swift
diff --git a/release/provenance.json b/release/provenance.json
@@ -6,7 +6,7 @@
"info_plist_sha256": "15ef08b1cdd1096cfb9eeaf5be5bf8f814807a7ca9350bbbb47860fa72ec13ef",
"privacy_manifest_sha256": "a331d51864743ebe4e00dd22360b4a538b6b3ac26a6b3eb54094e60a36959a12",
"sbom_sha256": "6b5ce897d5273290febc8b831663e12dea759cb0084f182ba7949e1c593fc410",
- "xcode_project_sha256": "23e7bfd1ca7e73501d5e5f65dcb245e98bfd821234dd87adb2f22a495921626a"
+ "xcode_project_sha256": "d3f7dcba94b3ab8a35c5f7d8a641eca4b6f2529147cc3dbe086b591105af0aff"
},
"disposition": "unsigned",
"platforms": [
diff --git a/test-fixtures/swiftlint-maintainability-baseline.v1.json b/test-fixtures/swiftlint-maintainability-baseline.v1.json
@@ -1 +1 @@
-[{"text":" init(","violation":{"ruleDescription":"Function bodies should not span too many lines","location":{"line":83,"character":3,"file":"Tera\/App\/TeraAppModel.swift"},"reason":"Initializer body should span 50 lines or less excluding comments and whitespace: currently spans 52 lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","severity":"error"}},{"text":"actor TeraAddMediaCoordinator: TeraAddMediaHandling {","violation":{"ruleDescription":"Type bodies should not span too many lines","location":{"line":73,"character":1,"file":"Tera\/Runtime\/TeraAddMediaCoordinator.swift"},"reason":"Actor body should span 250 lines or less excluding comments and whitespace: currently spans 330 lines","ruleIdentifier":"type_body_length","ruleName":"Type Body Length","severity":"error"}},{"text":"#endif","violation":{"ruleDescription":"Files should not span too many lines.","location":{"line":480,"character":1,"file":"Tera\/Runtime\/TeraAddMediaCoordinator.swift"},"reason":"File should contain 400 lines or less: currently contains 480","ruleIdentifier":"file_length","ruleName":"File Length","severity":"error"}},{"text":"private final class TeraGeneratedRuntimeBackend: TeraRuntimeBackend, @unchecked Sendable {","violation":{"ruleDescription":"Type bodies should not span too many lines","location":{"line":111,"character":15,"file":"Tera\/Runtime\/TeraGeneratedRuntimeBackend.swift"},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 545 lines","ruleIdentifier":"type_body_length","ruleName":"Type Body Length","severity":"error"}},{"text":"}","violation":{"ruleDescription":"Files should not span too many lines.","location":{"line":1640,"character":1,"file":"Tera\/Runtime\/TeraGeneratedRuntimeBackend.swift"},"reason":"File should contain 1000 lines or less: currently contains 1640","ruleIdentifier":"file_length","ruleName":"File Length","severity":"error"}},{"text":"actor TeraRuntimeClient {","violation":{"ruleDescription":"Type bodies should not span too many lines","location":{"line":291,"character":1,"file":"Tera\/Runtime\/TeraRuntimeClient.swift"},"reason":"Actor body should span 350 lines or less excluding comments and whitespace: currently spans 787 lines","ruleIdentifier":"type_body_length","ruleName":"Type Body Length","severity":"error"}},{"text":" func changes(bufferCapacity: Int = 16) async throws -> AsyncStream<TeraRuntimeChange> {","violation":{"ruleDescription":"Function bodies should not span too many lines","location":{"line":703,"character":3,"file":"Tera\/Runtime\/TeraRuntimeClient.swift"},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 70 lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","severity":"error"}},{"text":"}","violation":{"ruleDescription":"Files should not span too many lines.","location":{"line":1159,"character":1,"file":"Tera\/Runtime\/TeraRuntimeClient.swift"},"reason":"File should contain 1000 lines or less: currently contains 1159","ruleIdentifier":"file_length","ruleName":"File Length","severity":"error"}},{"text":"}","violation":{"ruleDescription":"Files should not span too many lines.","location":{"line":1210,"character":1,"file":"Tera\/Runtime\/TeraRuntimeModels.swift"},"reason":"File should contain 1000 lines or less: currently contains 1210","ruleIdentifier":"file_length","ruleName":"File Length","severity":"error"}},{"text":"final class TeraAddStore: ObservableObject {","violation":{"ruleDescription":"Type bodies should not span too many lines","location":{"line":11,"character":7,"file":"Tera\/State\/TeraAddStore.swift"},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 731 lines","ruleIdentifier":"type_body_length","ruleName":"Type Body Length","severity":"error"}},{"text":" func retract(_ card: TeraTodayCard) async {","violation":{"ruleDescription":"Function bodies should not span too many lines","location":{"line":459,"character":3,"file":"Tera\/State\/TeraAddStore.swift"},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 51 lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","severity":"error"}},{"text":"}","violation":{"ruleDescription":"Files should not span too many lines.","location":{"line":796,"character":1,"file":"Tera\/State\/TeraAddStore.swift"},"reason":"File should contain 400 lines or less: currently contains 796","ruleIdentifier":"file_length","ruleName":"File Length","severity":"error"}},{"text":"actor TeraConfigurationStore {","violation":{"ruleDescription":"Type bodies should not span too many lines","location":{"line":78,"character":1,"file":"Tera\/State\/TeraConfigurationStore.swift"},"reason":"Actor body should span 350 lines or less excluding comments and whitespace: currently spans 468 lines","ruleIdentifier":"type_body_length","ruleName":"Type Body Length","severity":"error"}},{"text":" func load() throws -> TeraAppConfiguration {","violation":{"ruleDescription":"Function bodies should not span too many lines","location":{"line":148,"character":5,"file":"Tera\/State\/TeraConfigurationStore.swift"},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 109 lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","severity":"error"}},{"text":"}","violation":{"ruleDescription":"Files should not span too many lines.","location":{"line":759,"character":1,"file":"Tera\/State\/TeraConfigurationStore.swift"},"reason":"File should contain 400 lines or less: currently contains 759","ruleIdentifier":"file_length","ruleName":"File Length","severity":"error"}},{"text":"actor TeraSessionStore {","violation":{"ruleDescription":"Type bodies should not span too many lines","location":{"line":39,"character":1,"file":"Tera\/State\/TeraSessionStore.swift"},"reason":"Actor body should span 350 lines or less excluding comments and whitespace: currently spans 390 lines","ruleIdentifier":"type_body_length","ruleName":"Type Body Length","severity":"error"}},{"text":" private func start(acceptingReconfiguration: Bool) async -> TeraSessionPhase {","violation":{"ruleDescription":"Complexity of function bodies should be limited.","location":{"line":125,"character":11,"file":"Tera\/State\/TeraSessionStore.swift"},"reason":"Function should have complexity 10 or less; currently complexity is 13","ruleIdentifier":"cyclomatic_complexity","ruleName":"Cyclomatic Complexity","severity":"error"}},{"text":"}","violation":{"ruleDescription":"Files should not span too many lines.","location":{"line":452,"character":1,"file":"Tera\/State\/TeraSessionStore.swift"},"reason":"File should contain 400 lines or less: currently contains 452","ruleIdentifier":"file_length","ruleName":"File Length","severity":"error"}},{"text":"struct TeraAddView: View {","violation":{"ruleDescription":"Type bodies should not span too many lines","location":{"line":4,"character":1,"file":"Tera\/Views\/TeraAddView.swift"},"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 454 lines","ruleIdentifier":"type_body_length","ruleName":"Type Body Length","severity":"error"}},{"text":"}","violation":{"ruleDescription":"Files should not span too many lines.","location":{"line":560,"character":1,"file":"Tera\/Views\/TeraAddView.swift"},"reason":"File should contain 400 lines or less: currently contains 560","ruleIdentifier":"file_length","ruleName":"File Length","severity":"error"}},{"text":"struct TeraSettingsView: View {","violation":{"ruleDescription":"Type bodies should not span too many lines","location":{"line":365,"character":1,"file":"Tera\/Views\/TeraSupportingViews.swift"},"reason":"Struct body should span 250 lines or less excluding comments and whitespace: currently spans 259 lines","ruleIdentifier":"type_body_length","ruleName":"Type Body Length","severity":"error"}},{"text":"}","violation":{"ruleDescription":"Files should not span too many lines.","location":{"line":629,"character":1,"file":"Tera\/Views\/TeraSupportingViews.swift"},"reason":"File should contain 400 lines or less: currently contains 629","ruleIdentifier":"file_length","ruleName":"File Length","severity":"error"}},{"text":"}","violation":{"ruleDescription":"Files should not span too many lines.","location":{"line":493,"character":1,"file":"Tera\/Views\/TeraTodayView.swift"},"reason":"File should contain 400 lines or less: currently contains 493","ruleIdentifier":"file_length","ruleName":"File Length","severity":"error"}},{"text":"final class TeraAddStoreTests: XCTestCase {","violation":{"ruleDescription":"Type bodies should not span too many lines","location":{"line":6,"character":7,"file":"TeraTests\/TeraAddStoreTests.swift"},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 665 lines","ruleIdentifier":"type_body_length","ruleName":"Type Body Length","severity":"error"}},{"text":"private actor AddBackend: TeraRuntimeBackend {","violation":{"ruleDescription":"Type bodies should not span too many lines","location":{"line":844,"character":9,"file":"TeraTests\/TeraAddStoreTests.swift"},"reason":"Actor body should span 350 lines or less excluding comments and whitespace: currently spans 492 lines","ruleIdentifier":"type_body_length","ruleName":"Type Body Length","severity":"error"}},{"text":" private func makeStatus(","violation":{"ruleDescription":"Number of function parameters should be low.","location":{"line":1280,"character":11,"file":"TeraTests\/TeraAddStoreTests.swift"},"reason":"Function should have 5 parameters or less: it currently has 8","ruleIdentifier":"function_parameter_count","ruleName":"Function Parameter Count","severity":"error"}},{"text":"}","violation":{"ruleDescription":"Files should not span too many lines.","location":{"line":1431,"character":1,"file":"TeraTests\/TeraAddStoreTests.swift"},"reason":"File should contain 1000 lines or less: currently contains 1431","ruleIdentifier":"file_length","ruleName":"File Length","severity":"error"}},{"text":"final class TeraRemoteQualificationTests: XCTestCase {","violation":{"ruleDescription":"Type bodies should not span too many lines","location":{"line":7,"character":7,"file":"TeraTests\/TeraRemoteQualificationTests.swift"},"reason":"Class body should span 250 lines or less excluding comments and whitespace: currently spans 307 lines","ruleIdentifier":"type_body_length","ruleName":"Type Body Length","severity":"error"}},{"text":" func testQualificationRejectsAmbiguousOrUnsafeHarnessValues() {","violation":{"ruleDescription":"Function bodies should not span too many lines","location":{"line":45,"character":3,"file":"TeraTests\/TeraRemoteQualificationTests.swift"},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 94 lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","severity":"error"}},{"text":" func testAuthorizationEvidenceIsRedactedEphemeralAndRelaunchCleaned() throws {","violation":{"ruleDescription":"Function bodies should not span too many lines","location":{"line":212,"character":3,"file":"TeraTests\/TeraRemoteQualificationTests.swift"},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 53 lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","severity":"error"}},{"text":"final class TeraRuntimeClientTests: XCTestCase {","violation":{"ruleDescription":"Type bodies should not span too many lines","location":{"line":4,"character":7,"file":"TeraTests\/TeraRuntimeClientTests.swift"},"reason":"Class body should span 250 lines or less excluding comments and whitespace: currently spans 298 lines","ruleIdentifier":"type_body_length","ruleName":"Type Body Length","severity":"error"}},{"text":"final class TeraStateMigrationTests: XCTestCase {","violation":{"ruleDescription":"Type bodies should not span too many lines","location":{"line":6,"character":7,"file":"TeraTests\/TeraStateMigrationTests.swift"},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 580 lines","ruleIdentifier":"type_body_length","ruleName":"Type Body Length","severity":"error"}},{"text":" func testRelayValidationMatchesRuntimeProfiles() throws {","violation":{"ruleDescription":"Function bodies should not span too many lines","location":{"line":7,"character":5,"file":"TeraTests\/TeraStateMigrationTests.swift"},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 61 lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","severity":"error"}},{"text":"}","violation":{"ruleDescription":"Files should not span too many lines.","location":{"line":622,"character":1,"file":"TeraTests\/TeraStateMigrationTests.swift"},"reason":"File should contain 400 lines or less: currently contains 622","ruleIdentifier":"file_length","ruleName":"File Length","severity":"error"}},{"text":"private actor SupportingBackend: TeraRuntimeBackend {","violation":{"ruleDescription":"Type bodies should not span too many lines","location":{"line":207,"character":9,"file":"TeraTests\/TeraSupportingStoreTests.swift"},"reason":"Actor body should span 250 lines or less excluding comments and whitespace: currently spans 253 lines","ruleIdentifier":"type_body_length","ruleName":"Type Body Length","severity":"error"}},{"text":"}","violation":{"ruleDescription":"Files should not span too many lines.","location":{"line":487,"character":1,"file":"TeraTests\/TeraSupportingStoreTests.swift"},"reason":"File should contain 400 lines or less: currently contains 487","ruleIdentifier":"file_length","ruleName":"File Length","severity":"error"}},{"text":"final class TeraRemoteQualificationUITests: XCTestCase {","violation":{"ruleDescription":"Type bodies should not span too many lines","location":{"line":4,"character":7,"file":"TeraUITests\/TeraRemoteQualificationUITests.swift"},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 1493 lines","ruleIdentifier":"type_body_length","ruleName":"Type Body Length","severity":"error"}},{"text":" func testLocalSocialFiveFlowScenario() throws {","violation":{"ruleDescription":"Function bodies should not span too many lines","location":{"line":62,"character":3,"file":"TeraUITests\/TeraRemoteQualificationUITests.swift"},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 73 lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","severity":"error"}},{"text":" func testLocalSocialDeterministicPersonas() throws {","violation":{"ruleDescription":"Function bodies should not span too many lines","location":{"line":174,"character":3,"file":"TeraUITests\/TeraRemoteQualificationUITests.swift"},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 66 lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","severity":"error"}},{"text":" func testRemoteBlossomUploadAndRecovery() throws {","violation":{"ruleDescription":"Function bodies should not span too many lines","location":{"line":247,"character":3,"file":"TeraUITests\/TeraRemoteQualificationUITests.swift"},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 54 lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","severity":"error"}},{"text":" private func expectedAddFieldLabel(_ identifier: String, type: String) -> String {","violation":{"ruleDescription":"Complexity of function bodies should be limited.","location":{"line":573,"character":11,"file":"TeraUITests\/TeraRemoteQualificationUITests.swift"},"reason":"Function should have complexity 10 or less; currently complexity is 18","ruleIdentifier":"cyclomatic_complexity","ruleName":"Cyclomatic Complexity","severity":"error"}},{"text":" private func preparePhotoUpdate(_ app: XCUIApplication, marker: String) -> XCUIElement? {","violation":{"ruleDescription":"Complexity of function bodies should be limited.","location":{"line":767,"character":11,"file":"TeraUITests\/TeraRemoteQualificationUITests.swift"},"reason":"Function should have complexity 10 or less; currently complexity is 11","ruleIdentifier":"cyclomatic_complexity","ruleName":"Cyclomatic Complexity","severity":"error"}},{"text":" private func preparePhotoUpdate(_ app: XCUIApplication, marker: String) -> XCUIElement? {","violation":{"ruleDescription":"Function bodies should not span too many lines","location":{"line":767,"character":11,"file":"TeraUITests\/TeraRemoteQualificationUITests.swift"},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 66 lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","severity":"error"}},{"text":" static func environment(","violation":{"ruleDescription":"Function bodies should not span too many lines","location":{"line":1736,"character":10,"file":"TeraUITests\/TeraRemoteQualificationUITests.swift"},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 67 lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","severity":"error"}},{"text":"}","violation":{"ruleDescription":"Files should not span too many lines.","location":{"line":2212,"character":1,"file":"TeraUITests\/TeraRemoteQualificationUITests.swift"},"reason":"File should contain 1000 lines or less: currently contains 2212","ruleIdentifier":"file_length","ruleName":"File Length","severity":"error"}}]
-\ No newline at end of file
+[{"text":" init(","violation":{"ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","reason":"Initializer body should span 50 lines or less excluding comments and whitespace: currently spans 52 lines","severity":"error","location":{"line":83,"character":3,"file":"Tera\/App\/TeraAppModel.swift"},"ruleName":"Function Body Length"}},{"text":"actor TeraAddMediaCoordinator: TeraAddMediaHandling {","violation":{"ruleDescription":"Type bodies should not span too many lines","severity":"error","location":{"line":51,"file":"Tera\/Runtime\/TeraAddMediaCoordinator.swift","character":1},"reason":"Actor body should span 250 lines or less excluding comments and whitespace: currently spans 330 lines","ruleIdentifier":"type_body_length","ruleName":"Type Body Length"}},{"text":"#endif","violation":{"ruleName":"File Length","ruleIdentifier":"file_length","severity":"error","location":{"character":1,"file":"Tera\/Runtime\/TeraAddMediaCoordinator.swift","line":458},"reason":"File should contain 400 lines or less: currently contains 458","ruleDescription":"Files should not span too many lines."}},{"text":"private final class TeraGeneratedRuntimeBackend: TeraRuntimeBackend, @unchecked Sendable {","violation":{"severity":"error","reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 545 lines","ruleDescription":"Type bodies should not span too many lines","location":{"file":"Tera\/Runtime\/TeraGeneratedRuntimeBackend.swift","line":111,"character":15},"ruleIdentifier":"type_body_length","ruleName":"Type Body Length"}},{"text":"}","violation":{"reason":"File should contain 1000 lines or less: currently contains 1640","ruleName":"File Length","ruleDescription":"Files should not span too many lines.","severity":"error","ruleIdentifier":"file_length","location":{"line":1640,"character":1,"file":"Tera\/Runtime\/TeraGeneratedRuntimeBackend.swift"}}},{"text":"actor TeraRuntimeClient {","violation":{"ruleDescription":"Type bodies should not span too many lines","severity":"error","ruleIdentifier":"type_body_length","location":{"file":"Tera\/Runtime\/TeraRuntimeClient.swift","line":291,"character":1},"reason":"Actor body should span 350 lines or less excluding comments and whitespace: currently spans 787 lines","ruleName":"Type Body Length"}},{"text":" func changes(bufferCapacity: Int = 16) async throws -> AsyncStream<TeraRuntimeChange> {","violation":{"ruleIdentifier":"function_body_length","severity":"error","location":{"character":3,"file":"Tera\/Runtime\/TeraRuntimeClient.swift","line":703},"ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 70 lines"}},{"text":"}","violation":{"reason":"File should contain 1000 lines or less: currently contains 1159","location":{"character":1,"line":1159,"file":"Tera\/Runtime\/TeraRuntimeClient.swift"},"ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","ruleName":"File Length","severity":"error"}},{"text":"}","violation":{"location":{"character":1,"line":1210,"file":"Tera\/Runtime\/TeraRuntimeModels.swift"},"ruleDescription":"Files should not span too many lines.","reason":"File should contain 1000 lines or less: currently contains 1210","severity":"error","ruleIdentifier":"file_length","ruleName":"File Length"}},{"text":"final class TeraAddStore: ObservableObject {","violation":{"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 731 lines","ruleDescription":"Type bodies should not span too many lines","ruleName":"Type Body Length","location":{"character":7,"file":"Tera\/State\/TeraAddStore.swift","line":11},"severity":"error","ruleIdentifier":"type_body_length"}},{"text":" func retract(_ card: TeraTodayCard) async {","violation":{"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 51 lines","location":{"line":459,"character":3,"file":"Tera\/State\/TeraAddStore.swift"},"ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length","ruleIdentifier":"function_body_length","severity":"error"}},{"text":"}","violation":{"ruleDescription":"Files should not span too many lines.","ruleName":"File Length","reason":"File should contain 400 lines or less: currently contains 796","severity":"error","ruleIdentifier":"file_length","location":{"line":796,"character":1,"file":"Tera\/State\/TeraAddStore.swift"}}},{"text":"actor TeraConfigurationStore {","violation":{"ruleDescription":"Type bodies should not span too many lines","ruleName":"Type Body Length","location":{"line":78,"file":"Tera\/State\/TeraConfigurationStore.swift","character":1},"reason":"Actor body should span 350 lines or less excluding comments and whitespace: currently spans 468 lines","ruleIdentifier":"type_body_length","severity":"error"}},{"text":" func load() throws -> TeraAppConfiguration {","violation":{"severity":"error","ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines","location":{"line":148,"file":"Tera\/State\/TeraConfigurationStore.swift","character":5},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 109 lines","ruleName":"Function Body Length"}},{"text":"}","violation":{"severity":"error","ruleIdentifier":"file_length","reason":"File should contain 400 lines or less: currently contains 759","ruleDescription":"Files should not span too many lines.","location":{"file":"Tera\/State\/TeraConfigurationStore.swift","character":1,"line":759},"ruleName":"File Length"}},{"text":"actor TeraSessionStore {","violation":{"location":{"character":1,"file":"Tera\/State\/TeraSessionStore.swift","line":39},"reason":"Actor body should span 350 lines or less excluding comments and whitespace: currently spans 390 lines","ruleIdentifier":"type_body_length","ruleDescription":"Type bodies should not span too many lines","ruleName":"Type Body Length","severity":"error"}},{"text":" private func start(acceptingReconfiguration: Bool) async -> TeraSessionPhase {","violation":{"ruleName":"Cyclomatic Complexity","location":{"file":"Tera\/State\/TeraSessionStore.swift","character":11,"line":125},"ruleIdentifier":"cyclomatic_complexity","ruleDescription":"Complexity of function bodies should be limited.","severity":"error","reason":"Function should have complexity 10 or less; currently complexity is 13"}},{"text":"}","violation":{"severity":"error","location":{"line":452,"character":1,"file":"Tera\/State\/TeraSessionStore.swift"},"ruleIdentifier":"file_length","ruleName":"File Length","reason":"File should contain 400 lines or less: currently contains 452","ruleDescription":"Files should not span too many lines."}},{"text":"struct TeraAddView: View {","violation":{"ruleName":"Type Body Length","reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 454 lines","location":{"file":"Tera\/Views\/TeraAddView.swift","line":4,"character":1},"severity":"error","ruleIdentifier":"type_body_length","ruleDescription":"Type bodies should not span too many lines"}},{"text":"}","violation":{"ruleIdentifier":"file_length","ruleDescription":"Files should not span too many lines.","location":{"line":560,"character":1,"file":"Tera\/Views\/TeraAddView.swift"},"severity":"error","ruleName":"File Length","reason":"File should contain 400 lines or less: currently contains 560"}},{"text":"struct TeraSettingsView: View {","violation":{"location":{"file":"Tera\/Views\/TeraSupportingViews.swift","line":365,"character":1},"ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","severity":"error","ruleName":"Type Body Length","reason":"Struct body should span 250 lines or less excluding comments and whitespace: currently spans 259 lines"}},{"text":"}","violation":{"location":{"character":1,"file":"Tera\/Views\/TeraSupportingViews.swift","line":629},"ruleName":"File Length","reason":"File should contain 400 lines or less: currently contains 629","severity":"error","ruleIdentifier":"file_length","ruleDescription":"Files should not span too many lines."}},{"text":"}","violation":{"location":{"file":"Tera\/Views\/TeraTodayView.swift","character":1,"line":493},"reason":"File should contain 400 lines or less: currently contains 493","ruleDescription":"Files should not span too many lines.","ruleName":"File Length","ruleIdentifier":"file_length","severity":"error"}},{"text":"final class TeraAddStoreTests: XCTestCase {","violation":{"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 665 lines","location":{"file":"TeraTests\/TeraAddStoreTests.swift","character":7,"line":6},"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length"}},{"text":"private actor AddBackend: TeraRuntimeBackend {","violation":{"ruleIdentifier":"type_body_length","ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","location":{"character":9,"file":"TeraTests\/TeraAddStoreTests.swift","line":844},"reason":"Actor body should span 350 lines or less excluding comments and whitespace: currently spans 492 lines"}},{"text":" private func makeStatus(","violation":{"location":{"line":1280,"file":"TeraTests\/TeraAddStoreTests.swift","character":11},"ruleIdentifier":"function_parameter_count","severity":"error","reason":"Function should have 5 parameters or less: it currently has 8","ruleDescription":"Number of function parameters should be low.","ruleName":"Function Parameter Count"}},{"text":"}","violation":{"location":{"character":1,"file":"TeraTests\/TeraAddStoreTests.swift","line":1431},"ruleDescription":"Files should not span too many lines.","ruleName":"File Length","ruleIdentifier":"file_length","reason":"File should contain 1000 lines or less: currently contains 1431","severity":"error"}},{"text":"final class TeraRemoteQualificationTests: XCTestCase {","violation":{"ruleName":"Type Body Length","severity":"error","location":{"line":7,"file":"TeraTests\/TeraRemoteQualificationTests.swift","character":7},"reason":"Class body should span 250 lines or less excluding comments and whitespace: currently spans 307 lines","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length"}},{"text":" func testQualificationRejectsAmbiguousOrUnsafeHarnessValues() {","violation":{"severity":"error","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 94 lines","location":{"character":3,"file":"TeraTests\/TeraRemoteQualificationTests.swift","line":45},"ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length"}},{"text":" func testAuthorizationEvidenceIsRedactedEphemeralAndRelaunchCleaned() throws {","violation":{"location":{"file":"TeraTests\/TeraRemoteQualificationTests.swift","character":3,"line":212},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 53 lines","ruleName":"Function Body Length","ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines","severity":"error"}},{"text":"final class TeraRuntimeClientTests: XCTestCase {","violation":{"location":{"character":7,"line":4,"file":"TeraTests\/TeraRuntimeClientTests.swift"},"ruleIdentifier":"type_body_length","ruleDescription":"Type bodies should not span too many lines","severity":"error","reason":"Class body should span 250 lines or less excluding comments and whitespace: currently spans 298 lines","ruleName":"Type Body Length"}},{"text":"final class TeraStateMigrationTests: XCTestCase {","violation":{"ruleName":"Type Body Length","reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 580 lines","location":{"character":7,"file":"TeraTests\/TeraStateMigrationTests.swift","line":6},"ruleDescription":"Type bodies should not span too many lines","severity":"error","ruleIdentifier":"type_body_length"}},{"text":" func testRelayValidationMatchesRuntimeProfiles() throws {","violation":{"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 61 lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","severity":"error","location":{"line":7,"file":"TeraTests\/TeraStateMigrationTests.swift","character":5},"ruleDescription":"Function bodies should not span too many lines"}},{"text":"}","violation":{"ruleDescription":"Files should not span too many lines.","severity":"error","ruleName":"File Length","ruleIdentifier":"file_length","location":{"line":622,"file":"TeraTests\/TeraStateMigrationTests.swift","character":1},"reason":"File should contain 400 lines or less: currently contains 622"}},{"text":"private actor SupportingBackend: TeraRuntimeBackend {","violation":{"reason":"Actor body should span 250 lines or less excluding comments and whitespace: currently spans 253 lines","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","severity":"error","ruleName":"Type Body Length","location":{"line":207,"file":"TeraTests\/TeraSupportingStoreTests.swift","character":9}}},{"text":"}","violation":{"ruleName":"File Length","ruleDescription":"Files should not span too many lines.","location":{"file":"TeraTests\/TeraSupportingStoreTests.swift","line":487,"character":1},"ruleIdentifier":"file_length","reason":"File should contain 400 lines or less: currently contains 487","severity":"error"}},{"text":"final class TeraRemoteQualificationUITests: XCTestCase {","violation":{"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 1493 lines","ruleIdentifier":"type_body_length","location":{"line":4,"file":"TeraUITests\/TeraRemoteQualificationUITests.swift","character":7},"severity":"error","ruleName":"Type Body Length","ruleDescription":"Type bodies should not span too many lines"}},{"text":" func testLocalSocialFiveFlowScenario() throws {","violation":{"ruleDescription":"Function bodies should not span too many lines","location":{"character":3,"file":"TeraUITests\/TeraRemoteQualificationUITests.swift","line":62},"ruleName":"Function Body Length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 73 lines","ruleIdentifier":"function_body_length","severity":"error"}},{"text":" func testLocalSocialDeterministicPersonas() throws {","violation":{"severity":"error","ruleIdentifier":"function_body_length","location":{"file":"TeraUITests\/TeraRemoteQualificationUITests.swift","line":174,"character":3},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 66 lines","ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length"}},{"text":" func testRemoteBlossomUploadAndRecovery() throws {","violation":{"ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length","severity":"error","location":{"file":"TeraUITests\/TeraRemoteQualificationUITests.swift","line":247,"character":3},"ruleIdentifier":"function_body_length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 54 lines"}},{"text":" private func expectedAddFieldLabel(_ identifier: String, type: String) -> String {","violation":{"severity":"error","location":{"line":573,"file":"TeraUITests\/TeraRemoteQualificationUITests.swift","character":11},"reason":"Function should have complexity 10 or less; currently complexity is 18","ruleName":"Cyclomatic Complexity","ruleIdentifier":"cyclomatic_complexity","ruleDescription":"Complexity of function bodies should be limited."}},{"text":" private func preparePhotoUpdate(_ app: XCUIApplication, marker: String) -> XCUIElement? {","violation":{"ruleIdentifier":"cyclomatic_complexity","ruleName":"Cyclomatic Complexity","location":{"character":11,"line":767,"file":"TeraUITests\/TeraRemoteQualificationUITests.swift"},"severity":"error","reason":"Function should have complexity 10 or less; currently complexity is 11","ruleDescription":"Complexity of function bodies should be limited."}},{"text":" private func preparePhotoUpdate(_ app: XCUIApplication, marker: String) -> XCUIElement? {","violation":{"ruleIdentifier":"function_body_length","ruleName":"Function Body Length","location":{"line":767,"file":"TeraUITests\/TeraRemoteQualificationUITests.swift","character":11},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 66 lines","severity":"error","ruleDescription":"Function bodies should not span too many lines"}},{"text":" static func environment(","violation":{"ruleIdentifier":"function_body_length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 67 lines","severity":"error","ruleDescription":"Function bodies should not span too many lines","location":{"line":1736,"file":"TeraUITests\/TeraRemoteQualificationUITests.swift","character":10},"ruleName":"Function Body Length"}},{"text":"}","violation":{"ruleName":"File Length","location":{"line":2212,"file":"TeraUITests\/TeraRemoteQualificationUITests.swift","character":1},"reason":"File should contain 1000 lines or less: currently contains 2212","ruleDescription":"Files should not span too many lines.","severity":"error","ruleIdentifier":"file_length"}}]
+\ No newline at end of file