field_ios

In-the-field app for Radroots on iOS
git clone https://radroots.dev/git/field_ios.git
Log | Files | Refs | README | LICENSE

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:
MPackage.swift | 1+
MTera.xcodeproj/project.pbxproj | 8++++++++
MTera/Runtime/TeraAddMediaCoordinator.swift | 22----------------------
ATera/Runtime/TeraOpenedMedia.swift | 30++++++++++++++++++++++++++++++
MTeraTests/TeraBackgroundUploadFixtures.swift | 4++++
MTeraTests/TeraMediaOwnershipFFITests.swift | 4++--
ATeraTests/TeraOpenedMediaCloseFixture.swift | 47+++++++++++++++++++++++++++++++++++++++++++++++
ATeraTests/TeraOpenedMediaTests.swift | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mproject.yml | 2++
Mrelease/provenance.json | 2+-
Mtest-fixtures/swiftlint-maintainability-baseline.v1.json | 4++--
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