diff --git a/BisonNotes AI/BisonNotes AI.xcodeproj/project.pbxproj b/BisonNotes AI/BisonNotes AI.xcodeproj/project.pbxproj index 6c063b3..11ae855 100644 --- a/BisonNotes AI/BisonNotes AI.xcodeproj/project.pbxproj +++ b/BisonNotes AI/BisonNotes AI.xcodeproj/project.pbxproj @@ -33,6 +33,20 @@ 14FDF90E2E3F8D5600BBD2FA /* AWSTranscribe in Frameworks */ = {isa = PBXBuildFile; productRef = 14FDF90D2E3F8D5600BBD2FA /* AWSTranscribe */; }; 14FDF9102E3F8D5600BBD2FA /* AWSTranscribeStreaming in Frameworks */ = {isa = PBXBuildFile; productRef = 14FDF90F2E3F8D5600BBD2FA /* AWSTranscribeStreaming */; }; 14FDF9122E3F90FB00BBD2FA /* AWSBedrockRuntime in Frameworks */ = {isa = PBXBuildFile; productRef = 14FDF9112E3F90FB00BBD2FA /* AWSBedrockRuntime */; }; + AC0000000000000000000030 /* AWSBedrock in Frameworks */ = {isa = PBXBuildFile; productRef = AC0000000000000000000020 /* AWSBedrock */; }; + AC0000000000000000000031 /* AWSClientRuntime in Frameworks */ = {isa = PBXBuildFile; productRef = AC0000000000000000000021 /* AWSClientRuntime */; }; + AC0000000000000000000032 /* AWSS3 in Frameworks */ = {isa = PBXBuildFile; productRef = AC0000000000000000000022 /* AWSS3 */; }; + AC0000000000000000000033 /* AWSTranscribe in Frameworks */ = {isa = PBXBuildFile; productRef = AC0000000000000000000023 /* AWSTranscribe */; }; + AC0000000000000000000034 /* AWSTranscribeStreaming in Frameworks */ = {isa = PBXBuildFile; productRef = AC0000000000000000000024 /* AWSTranscribeStreaming */; }; + AC0000000000000000000035 /* AWSBedrockRuntime in Frameworks */ = {isa = PBXBuildFile; productRef = AC0000000000000000000025 /* AWSBedrockRuntime */; }; + AC0000000000000000000036 /* Textual in Frameworks */ = {isa = PBXBuildFile; productRef = AC0000000000000000000026 /* Textual */; }; + AC0000000000000000000037 /* FluidAudio in Frameworks */ = {isa = PBXBuildFile; productRef = AC0000000000000000000027 /* FluidAudio */; }; + AC0000000000000000000038 /* MLXLLM in Frameworks */ = {isa = PBXBuildFile; productRef = AC0000000000000000000028 /* MLXLLM */; }; + AC0000000000000000000039 /* MLXLMCommon in Frameworks */ = {isa = PBXBuildFile; productRef = AC0000000000000000000029 /* MLXLMCommon */; }; + AC000000000000000000003A /* llama.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 143196D02F128D16003BA61E /* llama.xcframework */; }; + AC000000000000000000003B /* llama.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 143196D02F128D16003BA61E /* llama.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + AC000000000000000000003C /* WatchRecordingMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1485FED92E5272FA0044121F /* WatchRecordingMessage.swift */; }; + AC000000000000000000003D /* WatchRecordingState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1485FEDA2E5272FA0044121F /* WatchRecordingState.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -133,6 +147,17 @@ name = "Embed Controls Extension"; runOnlyForDeploymentPostprocessing = 0; }; + AC0000000000000000000005 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + AC000000000000000000003B /* llama.xcframework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ @@ -153,6 +178,7 @@ 14EA428C2E7F5ECA0059271B /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; }; 14EA428E2E7F5ECA0059271B /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; 14EA47E72E7F7C1E0059271B /* BisonNotes AI ControlsExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "BisonNotes AI ControlsExtension.entitlements"; sourceTree = ""; }; + AC0000000000000000000001 /* BisonNotes AI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "BisonNotes AI.app"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ @@ -192,6 +218,14 @@ ); target = 14EA428A2E7F5ECA0059271B /* BisonNotes AI ControlsExtension */; }; + AC0000000000000000000006 /* Exceptions for "BisonNotes AI" folder in "BisonNotes AI macOS" target */ = { + isa = PBXFileSystemSynchronizedBuildFileExceptionSet; + membershipExceptions = ( + Info.plist, + LaunchScreen.storyboard, + ); + target = AC0000000000000000000010 /* BisonNotes AI macOS */; + }; /* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ @@ -230,6 +264,7 @@ isa = PBXFileSystemSynchronizedRootGroup; exceptions = ( 14DBC8812E34FE1800DAD442 /* Exceptions for "BisonNotes AI" folder in "BisonNotes AI" target */, + AC0000000000000000000006 /* Exceptions for "BisonNotes AI" folder in "BisonNotes AI macOS" target */, 14EA42A52E7F60650059271B /* Exceptions for "BisonNotes AI" folder in "BisonNotes AI ControlsExtension" target */, ); path = "BisonNotes AI"; @@ -336,6 +371,24 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + AC0000000000000000000003 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + AC0000000000000000000034 /* AWSTranscribeStreaming in Frameworks */, + AC0000000000000000000037 /* FluidAudio in Frameworks */, + AC0000000000000000000032 /* AWSS3 in Frameworks */, + AC0000000000000000000035 /* AWSBedrockRuntime in Frameworks */, + AC0000000000000000000036 /* Textual in Frameworks */, + AC0000000000000000000038 /* MLXLLM in Frameworks */, + AC0000000000000000000039 /* MLXLMCommon in Frameworks */, + AC0000000000000000000033 /* AWSTranscribe in Frameworks */, + AC000000000000000000003A /* llama.xcframework in Frameworks */, + AC0000000000000000000031 /* AWSClientRuntime in Frameworks */, + AC0000000000000000000030 /* AWSBedrock in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -383,6 +436,7 @@ isa = PBXGroup; children = ( 14DBC83D2E34F7B500DAD442 /* BisonNotes AI.app */, + AC0000000000000000000001 /* BisonNotes AI.app */, 14DBC84F2E34F7B600DAD442 /* BisonNotes AITests.xctest */, 14DBC8592E34F7B600DAD442 /* BisonNotes AIUITests.xctest */, 1485FEA52E526FB10044121F /* BisonNotes AI Watch App.app */, @@ -617,6 +671,39 @@ productReference = 14EA428B2E7F5ECA0059271B /* BisonNotes AI ControlsExtension.appex */; productType = "com.apple.product-type.app-extension"; }; + AC0000000000000000000010 /* BisonNotes AI macOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = AC0000000000000000000011 /* Build configuration list for PBXNativeTarget "BisonNotes AI macOS" */; + buildPhases = ( + AC0000000000000000000002 /* Sources */, + AC0000000000000000000003 /* Frameworks */, + AC0000000000000000000004 /* Resources */, + AC0000000000000000000005 /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + fileSystemSynchronizedGroups = ( + 14DBC83F2E34F7B500DAD442 /* BisonNotes AI */, + ); + name = "BisonNotes AI macOS"; + packageProductDependencies = ( + AC0000000000000000000020 /* AWSBedrock */, + AC0000000000000000000021 /* AWSClientRuntime */, + AC0000000000000000000022 /* AWSS3 */, + AC0000000000000000000023 /* AWSTranscribe */, + AC0000000000000000000024 /* AWSTranscribeStreaming */, + AC0000000000000000000025 /* AWSBedrockRuntime */, + AC0000000000000000000026 /* Textual */, + AC0000000000000000000027 /* FluidAudio */, + AC0000000000000000000028 /* MLXLLM */, + AC0000000000000000000029 /* MLXLMCommon */, + ); + productName = "BisonNotes AI macOS"; + productReference = AC0000000000000000000001 /* BisonNotes AI.app */; + productType = "com.apple.product-type.application"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -625,7 +712,7 @@ attributes = { BuildIndependentTargetsInParallel = 1; LastSwiftUpdateCheck = 2640; - LastUpgradeCheck = 2610; + LastUpgradeCheck = 2660; TargetAttributes = { 1433F5432F7C9E44002AB9D6 = { CreatedOnToolsVersion = 26.4; @@ -681,6 +768,7 @@ projectRoot = ""; targets = ( 14DBC83C2E34F7B500DAD442 /* BisonNotes AI */, + AC0000000000000000000010 /* BisonNotes AI macOS */, 14DBC84E2E34F7B600DAD442 /* BisonNotes AITests */, 14DBC8582E34F7B600DAD442 /* BisonNotes AIUITests */, 1485FEA42E526FB10044121F /* BisonNotes AI Watch App */, @@ -757,6 +845,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + AC0000000000000000000004 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -827,6 +922,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + AC0000000000000000000002 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + AC000000000000000000003C /* WatchRecordingMessage.swift in Sources */, + AC000000000000000000003D /* WatchRecordingState.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -874,7 +978,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 4W55VW7UXX; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "BisonNotes Watch Widget/Info.plist"; @@ -906,7 +1010,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 4W55VW7UXX; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "BisonNotes Watch Widget/Info.plist"; @@ -937,7 +1041,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = "BisonNotes Share/BisonNotes Share.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 4W55VW7UXX; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "BisonNotes Share/Info.plist"; @@ -967,7 +1071,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = "BisonNotes Share/BisonNotes Share.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 4W55VW7UXX; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "BisonNotes Share/Info.plist"; @@ -999,7 +1103,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = "BisonNotes AI Controls/BisonNotes AI Controls.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 4W55VW7UXX; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; @@ -1034,7 +1138,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = "BisonNotes AI Controls/BisonNotes AI Controls.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 4W55VW7UXX; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; @@ -1067,7 +1171,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 4W55VW7UXX; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 2.2; @@ -1087,7 +1191,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 4W55VW7UXX; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 2.2; @@ -1106,7 +1210,7 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 4W55VW7UXX; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 2.2; @@ -1125,7 +1229,7 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 4W55VW7UXX; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 2.2; @@ -1275,7 +1379,7 @@ CODE_SIGN_ENTITLEMENTS = "BisonNotes AI/BisonNotes AI.entitlements"; "CODE_SIGN_ENTITLEMENTS[sdk=macosx*]" = "BisonNotes AI/BisonNotes AI Catalyst.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 4W55VW7UXX; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = NO; @@ -1319,7 +1423,7 @@ CODE_SIGN_ENTITLEMENTS = "BisonNotes AI/BisonNotes AI.entitlements"; "CODE_SIGN_ENTITLEMENTS[sdk=macosx*]" = "BisonNotes AI/BisonNotes AI Catalyst.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 4W55VW7UXX; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = NO; @@ -1358,7 +1462,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 4W55VW7UXX; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 18.5; @@ -1381,7 +1485,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 4W55VW7UXX; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 18.5; @@ -1403,7 +1507,7 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 4W55VW7UXX; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 2.2; @@ -1424,7 +1528,7 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 4W55VW7UXX; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 2.2; @@ -1448,7 +1552,7 @@ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; CODE_SIGN_ENTITLEMENTS = "BisonNotes AI ControlsExtension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 4W55VW7UXX; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "BisonNotes AI Controls/Info.plist"; @@ -1486,7 +1590,7 @@ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; CODE_SIGN_ENTITLEMENTS = "BisonNotes AI ControlsExtension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 4W55VW7UXX; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "BisonNotes AI Controls/Info.plist"; @@ -1517,6 +1621,84 @@ }; name = Release; }; + AC0000000000000000000012 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + APS_ENVIRONMENT = development; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; + CODE_SIGN_ENTITLEMENTS = "BisonNotes AI/BisonNotes AI Catalyst.entitlements"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 9; + DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_TEAM = 4W55VW7UXX; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "BisonNotes AI/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = "BisonNotes AI"; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 15.0; + MARKETING_VERSION = 2.2; + OTHER_LDFLAGS = ( + "$(inherited)", + "-Xlinker", + "-no_warn_duplicate_libraries", + ); + PRODUCT_BUNDLE_IDENTIFIER = "Bison-Networking.BisonNotes-AI"; + PRODUCT_NAME = "BisonNotes AI"; + REGISTER_APP_GROUPS = YES; + SDKROOT = macosx; + SUPPORTED_PLATFORMS = macosx; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + AC0000000000000000000013 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + APS_ENVIRONMENT = production; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; + CODE_SIGN_ENTITLEMENTS = "BisonNotes AI/BisonNotes AI Catalyst.entitlements"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 9; + DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_TEAM = 4W55VW7UXX; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "BisonNotes AI/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = "BisonNotes AI"; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 15.0; + MARKETING_VERSION = 2.2; + OTHER_LDFLAGS = ( + "$(inherited)", + "-Xlinker", + "-no_warn_duplicate_libraries", + ); + PRODUCT_BUNDLE_IDENTIFIER = "Bison-Networking.BisonNotes-AI"; + PRODUCT_NAME = "BisonNotes AI"; + REGISTER_APP_GROUPS = YES; + SDKROOT = macosx; + SUPPORTED_PLATFORMS = macosx; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -1610,6 +1792,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + AC0000000000000000000011 /* Build configuration list for PBXNativeTarget "BisonNotes AI macOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + AC0000000000000000000012 /* Debug */, + AC0000000000000000000013 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ @@ -1698,6 +1889,56 @@ package = 14FDF9062E3F8D5600BBD2FA /* XCRemoteSwiftPackageReference "aws-sdk-swift" */; productName = AWSBedrockRuntime; }; + AC0000000000000000000020 /* AWSBedrock */ = { + isa = XCSwiftPackageProductDependency; + package = 14FDF9062E3F8D5600BBD2FA /* XCRemoteSwiftPackageReference "aws-sdk-swift" */; + productName = AWSBedrock; + }; + AC0000000000000000000021 /* AWSClientRuntime */ = { + isa = XCSwiftPackageProductDependency; + package = 14FDF9062E3F8D5600BBD2FA /* XCRemoteSwiftPackageReference "aws-sdk-swift" */; + productName = AWSClientRuntime; + }; + AC0000000000000000000022 /* AWSS3 */ = { + isa = XCSwiftPackageProductDependency; + package = 14FDF9062E3F8D5600BBD2FA /* XCRemoteSwiftPackageReference "aws-sdk-swift" */; + productName = AWSS3; + }; + AC0000000000000000000023 /* AWSTranscribe */ = { + isa = XCSwiftPackageProductDependency; + package = 14FDF9062E3F8D5600BBD2FA /* XCRemoteSwiftPackageReference "aws-sdk-swift" */; + productName = AWSTranscribe; + }; + AC0000000000000000000024 /* AWSTranscribeStreaming */ = { + isa = XCSwiftPackageProductDependency; + package = 14FDF9062E3F8D5600BBD2FA /* XCRemoteSwiftPackageReference "aws-sdk-swift" */; + productName = AWSTranscribeStreaming; + }; + AC0000000000000000000025 /* AWSBedrockRuntime */ = { + isa = XCSwiftPackageProductDependency; + package = 14FDF9062E3F8D5600BBD2FA /* XCRemoteSwiftPackageReference "aws-sdk-swift" */; + productName = AWSBedrockRuntime; + }; + AC0000000000000000000026 /* Textual */ = { + isa = XCSwiftPackageProductDependency; + package = 1435711B2F2137E1000BFF00 /* XCRemoteSwiftPackageReference "textual" */; + productName = Textual; + }; + AC0000000000000000000027 /* FluidAudio */ = { + isa = XCSwiftPackageProductDependency; + package = 14FA00032F30000000BBD2FA /* XCRemoteSwiftPackageReference "FluidAudio" */; + productName = FluidAudio; + }; + AC0000000000000000000028 /* MLXLLM */ = { + isa = XCSwiftPackageProductDependency; + package = 14B0A0032F80000000BBD2FA /* XCRemoteSwiftPackageReference "mlx-swift-lm" */; + productName = MLXLLM; + }; + AC0000000000000000000029 /* MLXLMCommon */ = { + isa = XCSwiftPackageProductDependency; + package = 14B0A0032F80000000BBD2FA /* XCRemoteSwiftPackageReference "mlx-swift-lm" */; + productName = MLXLMCommon; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 14DBC8352E34F7B500DAD442 /* Project object */; diff --git a/BisonNotes AI/BisonNotes AI.xcodeproj/xcshareddata/xcschemes/BisonNotes AI ControlsExtension.xcscheme b/BisonNotes AI/BisonNotes AI.xcodeproj/xcshareddata/xcschemes/BisonNotes AI ControlsExtension.xcscheme index b68a5b8..5ec68c0 100644 --- a/BisonNotes AI/BisonNotes AI.xcodeproj/xcshareddata/xcschemes/BisonNotes AI ControlsExtension.xcscheme +++ b/BisonNotes AI/BisonNotes AI.xcodeproj/xcshareddata/xcschemes/BisonNotes AI ControlsExtension.xcscheme @@ -1,6 +1,6 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BisonNotes AI/BisonNotes AI.xcodeproj/xcshareddata/xcschemes/BisonNotes AI.xcscheme b/BisonNotes AI/BisonNotes AI.xcodeproj/xcshareddata/xcschemes/BisonNotes AI.xcscheme index afdd8cd..caaab30 100644 --- a/BisonNotes AI/BisonNotes AI.xcodeproj/xcshareddata/xcschemes/BisonNotes AI.xcscheme +++ b/BisonNotes AI/BisonNotes AI.xcodeproj/xcshareddata/xcschemes/BisonNotes AI.xcscheme @@ -1,6 +1,6 @@ Bool { + func completeLaunchSetup() { // Set notification delegate UNUserNotificationCenter.current().delegate = self @@ -28,8 +34,6 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele AppLog.shared.markLaunch() NSLog("βœ… AppDelegate initialized - notification delegate set") - - return true } // MARK: - MetricKit @@ -101,7 +105,7 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele if categoryIdentifier == "RESUME_RECORDING" { Task { @MainActor in - guard let recorderVM = AppDelegate.recorderViewModel else { + guard let recorderVM = AppDelegateCore.recorderViewModel else { AppLog.shared.general("AudioRecorderViewModel not available for notification action", level: .error) completionHandler() return @@ -139,10 +143,24 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { // Show notification even when app is in foreground - if #available(iOS 14.0, *) { - completionHandler([.banner, .sound, .badge]) - } else { - completionHandler([.alert, .sound, .badge]) - } + completionHandler([.banner, .sound, .badge]) + } +} + +#if canImport(UIKit) +class AppDelegate: AppDelegateCore, UIApplicationDelegate { + + func application(_ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool { + completeLaunchSetup() + return true + } +} +#else +class AppDelegate: AppDelegateCore, NSApplicationDelegate { + + func applicationDidFinishLaunching(_ notification: Notification) { + completeLaunchSetup() } } +#endif diff --git a/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-128x128.png b/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-128x128.png new file mode 100644 index 0000000..670e7c9 Binary files /dev/null and b/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-128x128.png differ diff --git a/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-128x128@2x.png b/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-128x128@2x.png new file mode 100644 index 0000000..1ba17bf Binary files /dev/null and b/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-128x128@2x.png differ diff --git a/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-16x16.png b/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-16x16.png new file mode 100644 index 0000000..03a3181 Binary files /dev/null and b/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-16x16.png differ diff --git a/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-16x16@2x.png b/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-16x16@2x.png new file mode 100644 index 0000000..1610d54 Binary files /dev/null and b/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-16x16@2x.png differ diff --git a/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-256x256.png b/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-256x256.png new file mode 100644 index 0000000..1ba17bf Binary files /dev/null and b/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-256x256.png differ diff --git a/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-256x256@2x.png b/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-256x256@2x.png new file mode 100644 index 0000000..d6b0dae Binary files /dev/null and b/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-256x256@2x.png differ diff --git a/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-32x32.png b/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-32x32.png new file mode 100644 index 0000000..1610d54 Binary files /dev/null and b/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-32x32.png differ diff --git a/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-32x32@2x.png b/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-32x32@2x.png new file mode 100644 index 0000000..ff07625 Binary files /dev/null and b/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-32x32@2x.png differ diff --git a/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-512x512.png b/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-512x512.png new file mode 100644 index 0000000..d6b0dae Binary files /dev/null and b/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-512x512.png differ diff --git a/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-512x512@2x.png b/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-512x512@2x.png new file mode 100644 index 0000000..263449c Binary files /dev/null and b/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-512x512@2x.png differ diff --git a/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/Contents.json b/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/Contents.json index f954e2d..0d0b2d1 100644 --- a/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/BisonNotes AI/BisonNotes AI/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -29,6 +29,66 @@ "idiom" : "universal", "platform" : "ios", "size" : "1024x1024" + }, + { + "filename" : "AppIcon-mac-16x16.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "16x16" + }, + { + "filename" : "AppIcon-mac-16x16@2x.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "16x16" + }, + { + "filename" : "AppIcon-mac-32x32.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "32x32" + }, + { + "filename" : "AppIcon-mac-32x32@2x.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "32x32" + }, + { + "filename" : "AppIcon-mac-128x128.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "128x128" + }, + { + "filename" : "AppIcon-mac-128x128@2x.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "128x128" + }, + { + "filename" : "AppIcon-mac-256x256.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "256x256" + }, + { + "filename" : "AppIcon-mac-256x256@2x.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "256x256" + }, + { + "filename" : "AppIcon-mac-512x512.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "512x512" + }, + { + "filename" : "AppIcon-mac-512x512@2x.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "512x512" } ], "info" : { diff --git a/BisonNotes AI/BisonNotes AI/BackgroundProcessingManager.swift b/BisonNotes AI/BisonNotes AI/BackgroundProcessingManager.swift index 7ee393a..e0f1a41 100644 --- a/BisonNotes AI/BisonNotes AI/BackgroundProcessingManager.swift +++ b/BisonNotes AI/BisonNotes AI/BackgroundProcessingManager.swift @@ -8,11 +8,15 @@ import Foundation import SwiftUI import UserNotifications +#if canImport(UIKit) import UIKit +#endif import CoreData import AVFoundation import AVKit +#if canImport(BackgroundTasks) import BackgroundTasks +#endif // MARK: - Processing Job Models @@ -310,17 +314,25 @@ class BackgroundProcessingManager: ObservableObject { // and accessing .batteryState spams "Error retrieving battery status" to the log. // Applies to both Mac Catalyst and "Designed for iPad" on Apple Silicon. fileprivate static var batteryLevelString: String { - if UIDevice.isRunningOnMac { + if PlatformDevice.isRunningOnMac { return "n/a (Mac)" } + #if canImport(UIKit) return "\(UIDevice.current.batteryLevel)" + #else + return "n/a" + #endif } fileprivate static var batteryStateString: String { - if UIDevice.isRunningOnMac { + if PlatformDevice.isRunningOnMac { return "n/a (Mac)" } + #if canImport(UIKit) return "\(UIDevice.current.batteryState.rawValue)" + #else + return "n/a" + #endif } // MARK: - Published Properties @@ -341,7 +353,7 @@ class BackgroundProcessingManager: ObservableObject { private var cancellationReason: String? /// Maps job ID β†’ old summary ID for regeneration jobs (delete old summary before saving new) private var regenerationSummaryIds: [UUID: UUID] = [:] - private var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid + private var backgroundTaskID: PlatformBackgroundTask.ID = .invalid private var backgroundTaskStartTime: Date? private var backgroundTimeMonitor: Task? private var staleJobMonitor: Task? @@ -1724,21 +1736,21 @@ class BackgroundProcessingManager: ObservableObject { NotificationCenter.default.addObserver( self, selector: #selector(appDidEnterBackground), - name: UIApplication.didEnterBackgroundNotification, + name: PlatformLifecycle.didEnterBackgroundNotification, object: nil ) NotificationCenter.default.addObserver( self, selector: #selector(appWillEnterForeground), - name: UIApplication.willEnterForegroundNotification, + name: PlatformLifecycle.willEnterForegroundNotification, object: nil ) NotificationCenter.default.addObserver( self, selector: #selector(appWillTerminate), - name: UIApplication.willTerminateNotification, + name: PlatformLifecycle.willTerminateNotification, object: nil ) } @@ -1804,6 +1816,7 @@ class BackgroundProcessingManager: ObservableObject { /// Schedule background processing task for queued jobs private func scheduleBackgroundProcessingIfNeeded() async { + #if os(iOS) && !targetEnvironment(macCatalyst) guard !activeJobs.filter({ $0.status == .queued }).isEmpty else { return } let request = BGProcessingTaskRequest(identifier: "com.bisonai.audio-processing") @@ -1817,6 +1830,8 @@ class BackgroundProcessingManager: ObservableObject { } catch { AppLog.shared.backgroundProcessing("Failed to schedule background processing: \(error.localizedDescription)", level: .error) } + #endif + // macOS: jobs keep running in-process; no scheduler needed. } private func handleAppForegrounding() async { @@ -2180,10 +2195,10 @@ class BackgroundProcessingManager: ObservableObject { } private func enableBackgroundAudioKeepAliveIfNeeded() async { - #if targetEnvironment(macCatalyst) + #if targetEnvironment(macCatalyst) || os(macOS) return #else - guard UIApplication.shared.applicationState != .active else { + guard !PlatformApp.isActive else { AppLog.shared.backgroundProcessing("Skipping keep-alive audio while app is active", level: .debug) return } @@ -2199,7 +2214,7 @@ class BackgroundProcessingManager: ObservableObject { backgroundAudioKeepAliveActive = true AppLog.shared.backgroundProcessing("Playback audio session configured for background processing") - let backgroundTime = UIApplication.shared.backgroundTimeRemaining + let backgroundTime = PlatformBackgroundTask.remainingTime if backgroundTime != Double.greatestFiniteMagnitude { AppLog.shared.backgroundProcessing("After audio session config: \(Int(backgroundTime))s background time", level: .debug) } else { @@ -2214,7 +2229,7 @@ class BackgroundProcessingManager: ObservableObject { } private func disableBackgroundAudioKeepAliveIfNeeded() async { - #if targetEnvironment(macCatalyst) + #if targetEnvironment(macCatalyst) || os(macOS) return #else guard backgroundAudioKeepAliveActive || keepAlivePlayer != nil else { return } @@ -2234,7 +2249,9 @@ class BackgroundProcessingManager: ObservableObject { // MARK: - Background Task Management private func beginBackgroundTask() async { - #if targetEnvironment(macCatalyst) + #if os(macOS) + beginMacProcessingActivity() + #elseif targetEnvironment(macCatalyst) // Mac apps don't get suspended by the OS, so the iOS background-task // machinery (UIApplication.beginBackgroundTask, AVAudioSession-backed // keep-alive audio) is unnecessary here and just spams the log with @@ -2249,12 +2266,13 @@ class BackgroundProcessingManager: ObservableObject { // Create descriptive task name based on current job let taskName = if let currentJob = currentJob { - "AudioProcessing-\(currentJob.type.displayName.replacingOccurrences(of: " ", with: ""))-\(currentJob.recordingName.prefix(20))" + "AudioProcessing-\(currentJob.type.displayName.replacingOccurrences(of: " ", with: ""))-" + + "\(currentJob.recordingName.prefix(20))" } else { "AudioProcessing-JobQueue" } - backgroundTaskID = UIApplication.shared.beginBackgroundTask(withName: taskName) { [weak self] in + backgroundTaskID = PlatformBackgroundTask.begin(name: taskName) { [weak self] in AppLog.shared.backgroundProcessing("Background task is about to expire", level: .error) Task { @MainActor in await self?.handleBackgroundTaskExpiration() @@ -2270,7 +2288,7 @@ class BackgroundProcessingManager: ObservableObject { AppLog.shared.backgroundProcessing("Started background task: \(backgroundTaskID.rawValue)") // Check remaining background time immediately - let remainingTime = UIApplication.shared.backgroundTimeRemaining + let remainingTime = PlatformBackgroundTask.remainingTime if remainingTime == Double.greatestFiniteMagnitude { AppLog.shared.backgroundProcessing("Background time: Unlimited (likely in foreground or audio session active)", level: .debug) } else { @@ -2294,8 +2312,42 @@ class BackgroundProcessingManager: ObservableObject { #endif } + #if os(macOS) + private func beginMacProcessingActivity() { + guard backgroundTaskID == .invalid else { + AppLog.shared.backgroundProcessing( + "macOS processing activity already running: \(backgroundTaskID.rawValue)", + level: .debug + ) + return + } + + let activityName = if let currentJob { + "AudioProcessing-\(currentJob.type.displayName.replacingOccurrences(of: " ", with: ""))-" + + "\(currentJob.recordingName.prefix(20))" + } else { + "AudioProcessing-JobQueue" + } + backgroundTaskID = PlatformBackgroundTask.begin(name: activityName) + backgroundTaskStartTime = Date() + AppLog.shared.backgroundProcessing( + "Started macOS processing activity: \(backgroundTaskID.rawValue)", + level: .debug + ) + } + #endif + private func endBackgroundTask() async { - #if targetEnvironment(macCatalyst) + #if os(macOS) + guard backgroundTaskID != .invalid else { return } + AppLog.shared.backgroundProcessing( + "Ending macOS processing activity: \(backgroundTaskID.rawValue)", + level: .debug + ) + PlatformBackgroundTask.end(backgroundTaskID) + backgroundTaskID = .invalid + backgroundTaskStartTime = nil + #elseif targetEnvironment(macCatalyst) // beginBackgroundTask is a no-op on Catalyst; nothing to tear down. return #else @@ -2307,7 +2359,7 @@ class BackgroundProcessingManager: ObservableObject { if backgroundTaskID != .invalid { AppLog.shared.backgroundProcessing("Ending background task: \(backgroundTaskID.rawValue)") - UIApplication.shared.endBackgroundTask(backgroundTaskID) + PlatformBackgroundTask.end(backgroundTaskID) backgroundTaskID = .invalid backgroundTaskStartTime = nil @@ -2329,7 +2381,7 @@ class BackgroundProcessingManager: ObservableObject { private func monitorBackgroundTime() { guard backgroundTaskID != .invalid else { return } - let remainingTime = UIApplication.shared.backgroundTimeRemaining + let remainingTime = PlatformBackgroundTask.remainingTime // Skip monitoring and refreshing if we have unlimited time (app is likely in foreground or has special privileges/audio session active) guard remainingTime != Double.greatestFiniteMagnitude else { return } @@ -2375,6 +2427,10 @@ class BackgroundProcessingManager: ObservableObject { /// Refresh the background task to avoid iOS warnings about long-running tasks /// This ends the current task and immediately starts a new one private func refreshBackgroundTask() async { + #if os(macOS) || targetEnvironment(macCatalyst) + // Mac activities cover the whole queue and do not expire on a timer. + return + #else guard backgroundTaskID != .invalid else { return } AppLog.shared.backgroundProcessing("Refreshing background task to avoid iOS 30-second warning", level: .debug) @@ -2384,7 +2440,7 @@ class BackgroundProcessingManager: ObservableObject { // End the current background task let oldTaskID = backgroundTaskID - UIApplication.shared.endBackgroundTask(backgroundTaskID) + PlatformBackgroundTask.end(backgroundTaskID) backgroundTaskID = .invalid backgroundTaskStartTime = nil AppLog.shared.backgroundProcessing("Ended old task: \(oldTaskID.rawValue)", level: .debug) @@ -2394,6 +2450,7 @@ class BackgroundProcessingManager: ObservableObject { // Don't cancel the monitor, we'll keep using it await beginBackgroundTask() } + #endif } // MARK: - Notifications diff --git a/BisonNotes AI/BisonNotes AI/BisonNotesAIApp.swift b/BisonNotes AI/BisonNotes AI/BisonNotesAIApp.swift index c204fe3..47eabdf 100644 --- a/BisonNotes AI/BisonNotes AI/BisonNotesAIApp.swift +++ b/BisonNotes AI/BisonNotes AI/BisonNotesAIApp.swift @@ -6,8 +6,12 @@ // import SwiftUI +#if canImport(UIKit) import UIKit +#endif +#if canImport(BackgroundTasks) import BackgroundTasks +#endif import UserNotifications import AppIntents import WidgetKit @@ -20,12 +24,18 @@ import Darwin struct BisonNotesAIApp: App { let persistenceController = PersistenceController.shared @StateObject private var appCoordinator = AppDataCoordinator() + @StateObject private var recorderVM = AudioRecorderViewModel() @StateObject private var fileImportManager = FileImportManager() @StateObject private var transcriptImportManager = TranscriptImportManager() @State private var hasQueuedParakeetStartupRepair = false + @FocusedValue(\.summaryExportAction) private var summaryExportAction // Phase 6: Register AppDelegate for notification handling + #if canImport(UIKit) @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate + #else + @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate + #endif /// Performs one-time migration of AWS Bedrock settings from legacy model identifiers /// This ensures UserDefaults is updated rather than migrating on every access @@ -379,7 +389,7 @@ struct BisonNotesAIApp: App { return } - guard UIApplication.shared.isProtectedDataAvailable else { + guard PlatformApp.isProtectedDataAvailable else { return } @@ -526,11 +536,12 @@ struct BisonNotesAIApp: App { var body: some Scene { WindowGroup { ContentView() + .environmentObject(recorderVM) .environmentObject(appCoordinator) .environmentObject(fileImportManager) .environmentObject(transcriptImportManager) .environment(\.managedObjectContext, persistenceController.container.viewContext) - .onReceive(NotificationCenter.default.publisher(for: UIApplication.didFinishLaunchingNotification)) { _ in + .onReceive(NotificationCenter.default.publisher(for: PlatformLifecycle.didFinishLaunchingNotification)) { _ in requestBackgroundAppRefreshPermission() #if !targetEnvironment(macCatalyst) setupWatchConnectivity() @@ -543,13 +554,13 @@ struct BisonNotesAIApp: App { appCoordinator.reconcileiCloudIfEnabled(reason: "app launch", force: true) } .onOpenURL(perform: handleOpenURL) - .onReceive(NotificationCenter.default.publisher(for: UIApplication.didEnterBackgroundNotification)) { _ in + .onReceive(NotificationCenter.default.publisher(for: PlatformLifecycle.didEnterBackgroundNotification)) { _ in AppLog.shared.markCleanShutdown() } - .onReceive(NotificationCenter.default.publisher(for: UIApplication.willTerminateNotification)) { _ in + .onReceive(NotificationCenter.default.publisher(for: PlatformLifecycle.willTerminateNotification)) { _ in AppLog.shared.markCleanShutdown() } - .onReceive(NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification)) { _ in + .onReceive(NotificationCenter.default.publisher(for: PlatformLifecycle.didBecomeActiveNotification)) { _ in AppLog.shared.markSessionActive() // Clear badge when the user actively opens the app. Using the // scene-phase notification here (rather than AppDelegate @@ -570,34 +581,45 @@ struct BisonNotesAIApp: App { NSLog("πŸ“Ž Darwin notification received from Share Extension") scanSharedContainerForImports(trigger: .pendingToken) } + .nativeMainWindowSizing() } + #if os(macOS) + .defaultSize(width: 1_100, height: 720) + .windowResizability(.contentMinSize) + #endif .commands { // MARK: - Mac Menu Bar Commands + // Keep the system undo/redo and pasteboard groups untouched so + // focused TextField/TextEditor controls retain standard Edit-menu behavior. CommandGroup(replacing: .newItem) { Button("New Recording") { - NotificationCenter.default.post(name: NSNotification.Name("ToggleRecording"), object: nil) + postRecordingCommand(named: "ToggleRecording") } - .keyboardShortcut("r", modifiers: .command) + .keyboardShortcut("n", modifiers: .command) Divider() Button("Import Audio...") { - NotificationCenter.default.post(name: NSNotification.Name("ImportAudioFromMenu"), object: nil) + postRecordingCommand(named: "ImportAudioFromMenu") } .keyboardShortcut("i", modifiers: .command) Button("Import Transcript...") { - NotificationCenter.default.post(name: NSNotification.Name("ImportTranscriptFromMenu"), object: nil) + postRecordingCommand(named: "ImportTranscriptFromMenu") } .keyboardShortcut("i", modifiers: [.command, .shift]) Button("Import From Link...") { - let switchName = NSNotification.Name("SwitchToRecordTabForImport") - let importName = NSNotification.Name("ImportFromLinkFromMenu") - NotificationCenter.default.post(name: switchName, object: nil) - NotificationCenter.default.post(name: importName, object: nil) + postRecordingCommand(named: "ImportFromLinkFromMenu") } .keyboardShortcut("l", modifiers: [.command, .shift]) + + Divider() + + Button("Export Summary...") { + summaryExportAction?.perform() + } + .disabled(summaryExportAction == nil) } CommandGroup(after: .sidebar) { @@ -619,6 +641,100 @@ struct BisonNotesAIApp: App { .keyboardShortcut("3", modifiers: .command) } } + + #if os(macOS) + Settings { + SettingsView() + .environmentObject(recorderVM) + .environmentObject(appCoordinator) + .environment(\.managedObjectContext, persistenceController.container.viewContext) + .frame(minWidth: 680, minHeight: 600) + } + .defaultSize(width: 760, height: 700) + + WindowGroup("Summary", id: NativeWindowID.summary, for: UUID.self) { $recordingID in + if let recordingID { + NativeSummaryWindowView(recordingID: recordingID) + .environmentObject(appCoordinator) + .environment(\.managedObjectContext, persistenceController.container.viewContext) + } else { + ContentUnavailableView( + "Summary Not Available", + systemImage: "doc.text.magnifyingglass", + description: Text("Choose a summary from the main window.") + ) + } + } + .defaultSize(width: 760, height: 700) + .windowResizability(.contentMinSize) + + WindowGroup("Transcript", id: NativeWindowID.transcript, for: UUID.self) { $recordingID in + if let recordingID { + NativeTranscriptWindowView(recordingID: recordingID) + .environmentObject(recorderVM) + .environmentObject(appCoordinator) + .environment(\.managedObjectContext, persistenceController.container.viewContext) + } + } + .defaultSize(width: 820, height: 720) + .windowResizability(.contentMinSize) + + WindowGroup("Recording", id: NativeWindowID.recording, for: UUID.self) { $recordingID in + if let recordingID { + NativeRecordingWindowView(recordingID: recordingID) + .environmentObject(recorderVM) + .environmentObject(appCoordinator) + .environment(\.managedObjectContext, persistenceController.container.viewContext) + } + } + .defaultSize(width: 720, height: 680) + .windowResizability(.contentMinSize) + + Window("Recordings", id: NativeWindowID.recordings) { + RecordingsListView() + .environment(\.isEmbeddedInSplitView, false) + .environmentObject(recorderVM) + .environmentObject(appCoordinator) + .environment(\.managedObjectContext, persistenceController.container.viewContext) + .frame(minWidth: 720, minHeight: 520) + } + .defaultSize(width: 900, height: 720) + .windowResizability(.contentMinSize) + + WindowGroup("Location", id: NativeWindowID.location, for: LocationData.self) { $locationData in + if let locationData { + LocationDetailView(locationData: locationData) + .frame(minWidth: 560, minHeight: 480) + } + } + .defaultSize(width: 680, height: 620) + .windowResizability(.contentMinSize) + + Window("Background Processing", id: NativeWindowID.backgroundProcessing) { + BackgroundProcessingView() + .frame(minWidth: 620, minHeight: 500) + } + .defaultSize(width: 760, height: 680) + .windowResizability(.contentMinSize) + + WindowGroup("Processing Job", id: NativeWindowID.processingJob, for: UUID.self) { $jobID in + if let jobID { + NativeProcessingJobWindowView(jobID: jobID) + } + } + .defaultSize(width: 620, height: 540) + .windowResizability(.contentMinSize) + #endif + } + + private func postRecordingCommand(named name: String) { + NotificationCenter.default.post( + name: NSNotification.Name("SwitchToRecordTabForImport"), + object: nil + ) + DispatchQueue.main.async { + NotificationCenter.default.post(name: NSNotification.Name(name), object: nil) + } } /// Tracks the last URL processed by handleOpenURL to prevent double imports @@ -864,6 +980,7 @@ struct BisonNotesAIApp: App { } private func setupBackgroundTasks() { + #if os(iOS) && !targetEnvironment(macCatalyst) // Register background task identifiers BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.bisonai.audio-processing", using: nil) { task in handleBackgroundProcessing(task: task as! BGProcessingTask) @@ -872,14 +989,21 @@ struct BisonNotesAIApp: App { BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.bisonai.app-refresh", using: nil) { task in handleAppRefresh(task: task as! BGAppRefreshTask) } + #endif + // macOS: no BGTaskScheduler β€” the app keeps running; jobs continue in-process. } private func requestBackgroundAppRefreshPermission() { + #if os(iOS) && !targetEnvironment(macCatalyst) // Background app refresh is now handled via BGTaskScheduler in setupBackgroundTasks() // No need for the deprecated setMinimumBackgroundFetchInterval AppLog.shared.general("Background app refresh configured via BGTaskScheduler") + #else + AppLog.shared.general("Mac background jobs continue in-process", level: .debug) + #endif } + #if os(iOS) && !targetEnvironment(macCatalyst) private func handleBackgroundProcessing(task: BGProcessingTask) { AppLog.shared.general("Background processing task started: \(task.identifier)") @@ -930,6 +1054,7 @@ struct BisonNotesAIApp: App { task.setTaskCompleted(success: true) } } + #endif private func setupWatchConnectivity() { AppLog.shared.general("setupWatchConnectivity() called in BisonNotesAIApp") @@ -974,7 +1099,7 @@ struct BisonNotesAIApp: App { AppShortcuts.updateAppShortcutParameters() } - #if !targetEnvironment(macCatalyst) + #if os(iOS) && !targetEnvironment(macCatalyst) if #available(iOS 18.0, *) { if let plugInsURL = Bundle.main.builtInPlugInsURL, let _ = try? FileManager.default.contentsOfDirectory(at: plugInsURL, includingPropertiesForKeys: nil) { @@ -1007,3 +1132,14 @@ struct BisonNotesAIApp: App { } #endif } + +private extension View { + @ViewBuilder + func nativeMainWindowSizing() -> some View { + #if os(macOS) + frame(minWidth: 860, minHeight: 560) + #else + self + #endif + } +} diff --git a/BisonNotes AI/BisonNotes AI/ContentView.swift b/BisonNotes AI/BisonNotes AI/ContentView.swift index 062d093..8a3b518 100644 --- a/BisonNotes AI/BisonNotes AI/ContentView.swift +++ b/BisonNotes AI/BisonNotes AI/ContentView.swift @@ -9,7 +9,7 @@ import SwiftUI struct ContentView: View { - @StateObject private var recorderVM = AudioRecorderViewModel() + @EnvironmentObject private var recorderVM: AudioRecorderViewModel @Environment(\.scenePhase) private var scenePhase @Environment(\.horizontalSizeClass) private var horizontalSizeClass @EnvironmentObject var appCoordinator: AppDataCoordinator @@ -147,6 +147,7 @@ struct ContentView: View { NavigationStack { OnDeviceLLMSettingsView() } + .nativeMacModalSizing(width: 760, height: 700) } .alert("Switched to Parakeet", isPresented: $showingWhisperKitSwitchedAlert) { Button("OK") { } @@ -173,6 +174,7 @@ struct ContentView: View { NavigationStack { FluidAudioSettingsView() } + .nativeMacModalSizing(width: 760, height: 700) } .alert("Download Complete", isPresented: Binding( get: { downloadMonitor.showingCompletionAlert && !recorderVM.isRecording }, @@ -421,6 +423,7 @@ struct ContentView: View { #Preview { ContentView() + .environmentObject(AudioRecorderViewModel()) .environmentObject(AppDataCoordinator()) .environmentObject(FileImportManager()) .environmentObject(TranscriptImportManager()) diff --git a/BisonNotes AI/BisonNotes AI/DeviceCapabilities.swift b/BisonNotes AI/BisonNotes AI/DeviceCapabilities.swift index 7a9bd4a..2fc8294 100644 --- a/BisonNotes AI/BisonNotes AI/DeviceCapabilities.swift +++ b/BisonNotes AI/BisonNotes AI/DeviceCapabilities.swift @@ -6,7 +6,9 @@ // import Foundation +#if canImport(UIKit) import UIKit +#endif struct DeviceCapabilities { @@ -40,7 +42,7 @@ struct DeviceCapabilities { /// does not expose a direct capability API, so gate the setup guidance by /// known device identifier families and keep Mac Catalyst/iPad hidden. static var supportsActionButton: Bool { - #if targetEnvironment(macCatalyst) + #if targetEnvironment(macCatalyst) || os(macOS) return false #else guard UIDevice.current.userInterfaceIdiom == .phone else { @@ -127,11 +129,15 @@ struct DeviceCapabilities { report += "On-Device LLM Support: \(supportsOnDeviceLLM ? "βœ…" : "❌")\n" report += "Action Button Support: \(supportsActionButton ? "βœ…" : "❌")\n" + #if os(macOS) + report += "macOS Version: \(ProcessInfo.processInfo.operatingSystemVersionString)\n" + #else if #available(iOS 16.0, *) { report += "iOS Version: βœ… (16.0+)\n" } else { report += "iOS Version: ❌ (< 16.0)\n" } + #endif return report } diff --git a/BisonNotes AI/BisonNotes AI/DocumentExportPicker.swift b/BisonNotes AI/BisonNotes AI/DocumentExportPicker.swift deleted file mode 100644 index a9392f7..0000000 --- a/BisonNotes AI/BisonNotes AI/DocumentExportPicker.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// DocumentExportPicker.swift -// BisonNotes AI -// -// UIViewControllerRepresentable wrapping UIDocumentPickerViewController for exporting files. -// Used to archive audio recordings to iCloud Drive through the system -// document picker. The archive service rejects non-iCloud destinations. -// - -import SwiftUI -import UniformTypeIdentifiers - -struct DocumentExportPicker: UIViewControllerRepresentable { - let urls: [URL] - let onCompletion: (Bool, [URL]) -> Void - - func makeCoordinator() -> Coordinator { - Coordinator(onCompletion: onCompletion) - } - - func makeUIViewController(context: Context) -> UIDocumentPickerViewController { - let picker = UIDocumentPickerViewController(forExporting: urls) - picker.delegate = context.coordinator - picker.shouldShowFileExtensions = true - return picker - } - - func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: Context) {} - - class Coordinator: NSObject, UIDocumentPickerDelegate { - let onCompletion: (Bool, [URL]) -> Void - - init(onCompletion: @escaping (Bool, [URL]) -> Void) { - self.onCompletion = onCompletion - } - - func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { - onCompletion(true, urls) - } - - func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) { - onCompletion(false, []) - } - } -} diff --git a/BisonNotes AI/BisonNotes AI/DocumentPickerCoordinator.swift b/BisonNotes AI/BisonNotes AI/DocumentPickerCoordinator.swift deleted file mode 100644 index ca666a3..0000000 --- a/BisonNotes AI/BisonNotes AI/DocumentPickerCoordinator.swift +++ /dev/null @@ -1,217 +0,0 @@ -// -// DocumentPickerCoordinator.swift -// Audio Journal -// -// Handles document picker for audio file import -// - -import Foundation -import UIKit -import SwiftUI -import UniformTypeIdentifiers - -// MARK: - Document Picker Coordinator - -class DocumentPickerCoordinator: NSObject, ObservableObject { - @Published var selectedURLs: [URL] = [] - @Published var isShowingPicker = false - - private var completionHandler: (([URL]) -> Void)? - - func selectAudioFiles(completion: @escaping ([URL]) -> Void) { - self.completionHandler = completion - self.isShowingPicker = true - } - - func selectTextFiles(completion: @escaping ([URL]) -> Void) { - self.completionHandler = completion - self.isShowingPicker = true - } - - func selectVideoFiles(completion: @escaping ([URL]) -> Void) { - self.completionHandler = completion - self.isShowingPicker = true - } - - func handleSelectedURLs(_ urls: [URL]) { - selectedURLs = urls - completionHandler?(urls) - completionHandler = nil - isShowingPicker = false - } -} - -// MARK: - Document Picker View Controller - -class AudioDocumentPickerViewController: UIDocumentPickerViewController { - private let coordinator: DocumentPickerCoordinator - - init(coordinator: DocumentPickerCoordinator) { - self.coordinator = coordinator - - // Create supported audio types - var supportedTypes: [UTType] = [UTType.audio] - - // Add specific audio formats if available - if let m4aType = UTType(filenameExtension: "m4a") { - supportedTypes.append(m4aType) - } - if let mp3Type = UTType(filenameExtension: "mp3") { - supportedTypes.append(mp3Type) - } - if let wavType = UTType(filenameExtension: "wav") { - supportedTypes.append(wavType) - } - - super.init(forOpeningContentTypes: supportedTypes, asCopy: true) - - self.delegate = coordinator - self.allowsMultipleSelection = true - self.shouldShowFileExtensions = true - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Document Picker Delegate - -extension DocumentPickerCoordinator: UIDocumentPickerDelegate { - func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { - // Handle the selected URLs - handleSelectedURLs(urls) - } - - func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) { - // Handle cancellation - handleSelectedURLs([]) - } -} - -// MARK: - SwiftUI Document Picker - -struct AudioDocumentPicker: UIViewControllerRepresentable { - @Binding var isPresented: Bool - let coordinator: DocumentPickerCoordinator - - func makeUIViewController(context: Context) -> AudioDocumentPickerViewController { - return AudioDocumentPickerViewController(coordinator: coordinator) - } - - func updateUIViewController(_ uiViewController: AudioDocumentPickerViewController, context: Context) { - // No updates needed - } -} - -// MARK: - Text Document Picker View Controller - -class TextDocumentPickerViewController: UIDocumentPickerViewController { - private let coordinator: DocumentPickerCoordinator - - init(coordinator: DocumentPickerCoordinator) { - self.coordinator = coordinator - - // Create supported text and document types - var supportedTypes: [UTType] = [ - UTType.plainText, - UTType.text, - UTType.pdf // Add PDF support - ] - - // Add specific text formats if available - if let txtType = UTType(filenameExtension: "txt") { - supportedTypes.append(txtType) - } - if let mdType = UTType(filenameExtension: "md") { - supportedTypes.append(mdType) - } - if let markdownType = UTType(filenameExtension: "markdown") { - supportedTypes.append(markdownType) - } - - // Add Word document types - // DOCX - Office Open XML Document - if let docxType = UTType(filenameExtension: "docx") { - supportedTypes.append(docxType) - } - // Also try the standard Microsoft Word type - supportedTypes.append(UTType(importedAs: "org.openxmlformats.wordprocessingml.document")) - // Legacy DOC format (limited support - will show warning) - if let docType = UTType(filenameExtension: "doc") { - supportedTypes.append(docType) - } - - super.init(forOpeningContentTypes: supportedTypes, asCopy: true) - - self.delegate = coordinator - self.allowsMultipleSelection = true - self.shouldShowFileExtensions = true - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SwiftUI Text Document Picker - -struct TextDocumentPicker: UIViewControllerRepresentable { - @Binding var isPresented: Bool - let coordinator: DocumentPickerCoordinator - - func makeUIViewController(context: Context) -> TextDocumentPickerViewController { - return TextDocumentPickerViewController(coordinator: coordinator) - } - - func updateUIViewController(_ uiViewController: TextDocumentPickerViewController, context: Context) { - // No updates needed - } -} - -// MARK: - Video Document Picker View Controller - -class VideoDocumentPickerViewController: UIDocumentPickerViewController { - private let coordinator: DocumentPickerCoordinator - - init(coordinator: DocumentPickerCoordinator) { - self.coordinator = coordinator - - var supportedTypes: [UTType] = [.movie, .video] - - if let mp4Type = UTType(filenameExtension: "mp4") { - supportedTypes.append(mp4Type) - } - if let movType = UTType(filenameExtension: "mov") { - supportedTypes.append(movType) - } - if let m4vType = UTType(filenameExtension: "m4v") { - supportedTypes.append(m4vType) - } - - super.init(forOpeningContentTypes: supportedTypes, asCopy: true) - - self.delegate = coordinator - self.allowsMultipleSelection = true - self.shouldShowFileExtensions = true - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SwiftUI Video Document Picker - -struct VideoDocumentPicker: UIViewControllerRepresentable { - @Binding var isPresented: Bool - let coordinator: DocumentPickerCoordinator - - func makeUIViewController(context: Context) -> VideoDocumentPickerViewController { - return VideoDocumentPickerViewController(coordinator: coordinator) - } - - func updateUIViewController(_ uiViewController: VideoDocumentPickerViewController, context: Context) { - // No updates needed - } -} diff --git a/BisonNotes AI/BisonNotes AI/EnhancedAudioSessionManager.swift b/BisonNotes AI/BisonNotes AI/EnhancedAudioSessionManager.swift index fb016d3..bc15660 100644 --- a/BisonNotes AI/BisonNotes AI/EnhancedAudioSessionManager.swift +++ b/BisonNotes AI/BisonNotes AI/EnhancedAudioSessionManager.swift @@ -7,8 +7,15 @@ import Foundation import AVFoundation +#if os(macOS) +import AudioToolbox +import CoreAudio +#endif +#if canImport(UIKit) import UIKit +#endif +#if os(iOS) /// Enhanced audio session manager for recording, playback, and background operations. class EnhancedAudioSessionManager: NSObject, ObservableObject { @@ -512,6 +519,300 @@ class EnhancedAudioSessionManager: NSObject, ObservableObject { } } +#else + +// AVAudioSession does not exist on native macOS. AVAudioEngine records without +// a session, while input discovery and selection use AVCaptureDevice + Core Audio. + +/// Minimal stand-in for AVAudioSessionPortDescription so the shared audio stack +/// compiles on native macOS. Callers only use portName, uid, and portType. +final class AVAudioSessionPortDescription: NSObject { + struct Port: Equatable { + let rawValue: String + static let builtInMic = Port(rawValue: "BuiltInMic") + static let bluetoothHFP = Port(rawValue: "BluetoothHFP") + static let headsetMic = Port(rawValue: "HeadsetMic") + static let usbAudio = Port(rawValue: "USBAudio") + } + + let portName: String + let uid: String + let portType: Port + let audioDeviceID: AudioDeviceID + + init(portName: String, uid: String, portType: Port, audioDeviceID: AudioDeviceID) { + self.portName = portName + self.uid = uid + self.portType = portType + self.audioDeviceID = audioDeviceID + } +} + +class EnhancedAudioSessionManager: NSObject, ObservableObject { + @Published var isConfigured = false + @Published var isMixedAudioEnabled = false + @Published var isBackgroundRecordingEnabled = false + @Published var lastError: AudioProcessingError? + + private var preferredInputDeviceID: AudioDeviceID? + private var configuredInputDeviceID: AudioDeviceID? + private var inputDeviceMonitor: MacInputDeviceMonitor? + + deinit { + stopInputDeviceMonitoring() + } + + func configureMixedAudioSession() async throws { + isConfigured = true + isMixedAudioEnabled = true + isBackgroundRecordingEnabled = false + } + + func configureBackgroundRecording() async throws { + isConfigured = true + isMixedAudioEnabled = false + isBackgroundRecordingEnabled = true + } + + func configurePlaybackSession() async throws { + isConfigured = true + isMixedAudioEnabled = false + isBackgroundRecordingEnabled = false + } + + func configureBackgroundProcessingSession() async throws { + isConfigured = true + isMixedAudioEnabled = true + isBackgroundRecordingEnabled = false + } + + func restoreAudioSession() async throws {} + + func deactivateSession() async throws { + isConfigured = false + isMixedAudioEnabled = false + isBackgroundRecordingEnabled = false + } + + func setPreferredInput(_ input: AVAudioSessionPortDescription) async throws { + guard getAvailableInputs().contains(where: { $0.audioDeviceID == input.audioDeviceID }) else { + let error = AudioProcessingError.audioSessionConfigurationFailed( + "The selected microphone is no longer available." + ) + lastError = error + throw error + } + + preferredInputDeviceID = input.audioDeviceID + AppLog.shared.audioSession("Preferred Mac input set to: \(input.portName) (\(input.uid))") + } + + func clearPreferredInput() async throws { + preferredInputDeviceID = nil + AppLog.shared.audioSession("Preferred Mac input cleared; using the system default microphone") + } + + func getAvailableInputs() -> [AVAudioSessionPortDescription] { + let defaultDeviceID = Self.defaultInputDeviceID() + let discoverySession = AVCaptureDevice.DiscoverySession( + deviceTypes: [.microphone, .external], + mediaType: .audio, + position: .unspecified + ) + + var seenDeviceIDs = Set() + let inputs = discoverySession.devices.compactMap { device -> AVAudioSessionPortDescription? in + guard let deviceID = Self.audioDeviceID(forUID: device.uniqueID), + seenDeviceIDs.insert(deviceID).inserted else { + return nil + } + + return AVAudioSessionPortDescription( + portName: device.localizedName, + uid: device.uniqueID, + portType: Self.portType(for: deviceID), + audioDeviceID: deviceID + ) + } + + return inputs.sorted { lhs, rhs in + if lhs.audioDeviceID == defaultDeviceID { return true } + if rhs.audioDeviceID == defaultDeviceID { return false } + return lhs.portName.localizedCaseInsensitiveCompare(rhs.portName) == .orderedAscending + } + } + + func getActiveInput() -> AVAudioSessionPortDescription? { + let inputs = getAvailableInputs() + if let preferredInputDeviceID, + let preferredInput = inputs.first(where: { $0.audioDeviceID == preferredInputDeviceID }) { + return preferredInput + } + + guard let defaultDeviceID = Self.defaultInputDeviceID() else { + return inputs.first + } + return inputs.first(where: { $0.audioDeviceID == defaultDeviceID }) ?? inputs.first + } + + /// The device a newly created recording engine should use. A disconnected + /// preferred device automatically falls back to the current system default. + func resolvedInputDeviceID() -> AudioDeviceID? { + let availableDeviceIDs = Set(getAvailableInputs().map(\.audioDeviceID)) + if let preferredInputDeviceID, availableDeviceIDs.contains(preferredInputDeviceID) { + return preferredInputDeviceID + } + return Self.defaultInputDeviceID() + } + + /// True when the engine is still bound to the device the current preference + /// resolves to. Device-list and default-input listeners use this to ignore + /// unrelated audio-device changes. + func recordingInputNeedsRecovery() -> Bool { + guard let configuredInputDeviceID else { return false } + return configuredInputDeviceID != resolvedInputDeviceID() + } + + func clearConfiguredInputDevice() { + configuredInputDeviceID = nil + } + + /// Watches both the system default input and the complete Core Audio device + /// list. The latter is required for a selected non-default USB/Bluetooth mic. + func startInputDeviceMonitoring(onChange: @escaping () -> Void) { + stopInputDeviceMonitoring() + let monitor = MacInputDeviceMonitor(onChange: onChange) + monitor.start() + inputDeviceMonitor = monitor + } + + func stopInputDeviceMonitoring() { + inputDeviceMonitor?.stop() + inputDeviceMonitor = nil + } + + /// Applies the selected Mac input to this engine without changing the + /// user's system-wide default input device. + func configureInputDevice(for engine: AVAudioEngine) throws { + guard let deviceID = resolvedInputDeviceID() else { + let error = AudioProcessingError.audioSessionConfigurationFailed("No microphone is available.") + lastError = error + throw error + } + guard let audioUnit = engine.inputNode.audioUnit else { + let error = AudioProcessingError.audioSessionConfigurationFailed( + "The microphone audio unit could not be created." + ) + lastError = error + throw error + } + + var mutableDeviceID = deviceID + let status = AudioUnitSetProperty( + audioUnit, + kAudioOutputUnitProperty_CurrentDevice, + kAudioUnitScope_Global, + 0, + &mutableDeviceID, + UInt32(MemoryLayout.size) + ) + guard status == noErr else { + let systemError = NSError(domain: NSOSStatusErrorDomain, code: Int(status)) + let error = AudioProcessingError.audioSessionConfigurationFailed( + "Failed to select the microphone: \(systemError.localizedDescription)" + ) + lastError = error + throw error + } + configuredInputDeviceID = deviceID + + let inputName = getAvailableInputs() + .first(where: { $0.audioDeviceID == deviceID })? + .portName ?? "system default" + AppLog.shared.audioSession("Configured AVAudioEngine input: \(inputName)") + } + + private static func defaultInputDeviceID() -> AudioDeviceID? { + var deviceID = AudioDeviceID(kAudioObjectUnknown) + var address = AudioObjectPropertyAddress( + mSelector: kAudioHardwarePropertyDefaultInputDevice, + mScope: kAudioObjectPropertyScopeGlobal, + mElement: kAudioObjectPropertyElementMain + ) + var size = UInt32(MemoryLayout.size) + let status = AudioObjectGetPropertyData( + AudioObjectID(kAudioObjectSystemObject), + &address, + 0, + nil, + &size, + &deviceID + ) + guard status == noErr, deviceID != kAudioObjectUnknown else { return nil } + return deviceID + } + + private static func audioDeviceID(forUID value: String) -> AudioDeviceID? { + var uid = value as CFString + var deviceID = AudioDeviceID(kAudioObjectUnknown) + var address = AudioObjectPropertyAddress( + mSelector: kAudioHardwarePropertyDeviceForUID, + mScope: kAudioObjectPropertyScopeGlobal, + mElement: kAudioObjectPropertyElementMain + ) + + let status: OSStatus = withUnsafeMutablePointer(to: &uid) { uidPointer in + withUnsafeMutablePointer(to: &deviceID) { deviceIDPointer in + var translation = AudioValueTranslation( + mInputData: UnsafeMutableRawPointer(uidPointer), + mInputDataSize: UInt32(MemoryLayout.size), + mOutputData: UnsafeMutableRawPointer(deviceIDPointer), + mOutputDataSize: UInt32(MemoryLayout.size) + ) + var size = UInt32(MemoryLayout.size) + return AudioObjectGetPropertyData( + AudioObjectID(kAudioObjectSystemObject), + &address, + 0, + nil, + &size, + &translation + ) + } + } + + guard status == noErr, deviceID != kAudioObjectUnknown else { return nil } + return deviceID + } + + private static func portType(for deviceID: AudioDeviceID) -> AVAudioSessionPortDescription.Port { + var transportType: UInt32 = 0 + var address = AudioObjectPropertyAddress( + mSelector: kAudioDevicePropertyTransportType, + mScope: kAudioObjectPropertyScopeGlobal, + mElement: kAudioObjectPropertyElementMain + ) + var size = UInt32(MemoryLayout.size) + let status = AudioObjectGetPropertyData(deviceID, &address, 0, nil, &size, &transportType) + guard status == noErr else { return .headsetMic } + + switch transportType { + case kAudioDeviceTransportTypeBuiltIn: + return .builtInMic + case kAudioDeviceTransportTypeBluetooth, kAudioDeviceTransportTypeBluetoothLE: + return .bluetoothHFP + case kAudioDeviceTransportTypeUSB: + return .usbAudio + default: + return .headsetMic + } + } + + func handleAudioInterruption(_ notification: Notification) {} +} + +#endif + // MARK: - Error Types enum AudioProcessingError: Error, LocalizedError { diff --git a/BisonNotes AI/BisonNotes AI/EnhancedErrorHandlingSystem.swift b/BisonNotes AI/BisonNotes AI/EnhancedErrorHandlingSystem.swift index b6cd705..f96f144 100644 --- a/BisonNotes AI/BisonNotes AI/EnhancedErrorHandlingSystem.swift +++ b/BisonNotes AI/BisonNotes AI/EnhancedErrorHandlingSystem.swift @@ -145,10 +145,16 @@ class EnhancedErrorHandler: ObservableObject { } private func getDeviceInfo() -> DeviceInfo { - let device = UIDevice.current + #if canImport(UIKit) + let model = UIDevice.current.model + let systemVersion = UIDevice.current.systemVersion + #else + let model = "Mac" + let systemVersion = ProcessInfo.processInfo.operatingSystemVersionString + #endif return DeviceInfo( - model: device.model, - systemVersion: device.systemVersion, + model: model, + systemVersion: systemVersion, appVersion: Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "Unknown", availableMemory: getAvailableMemory(), availableStorage: getAvailableStorage() diff --git a/BisonNotes AI/BisonNotes AI/EnhancedLoggingSystem.swift b/BisonNotes AI/BisonNotes AI/EnhancedLoggingSystem.swift index d3330f4..99d0cb3 100644 --- a/BisonNotes AI/BisonNotes AI/EnhancedLoggingSystem.swift +++ b/BisonNotes AI/BisonNotes AI/EnhancedLoggingSystem.swift @@ -7,7 +7,9 @@ // import Foundation +#if canImport(UIKit) import UIKit +#endif import os.log import AVFoundation @@ -316,12 +318,18 @@ class AppLog { } func generateDiagnosticReport() -> DiagnosticReport { - let device = UIDevice.current + #if canImport(UIKit) + let model = UIDevice.current.model + let systemVersion = UIDevice.current.systemVersion + #else + let model = "Mac" + let systemVersion = ProcessInfo.processInfo.operatingSystemVersionString + #endif return DiagnosticReport( timestamp: Date(), deviceInfo: DeviceDiagnosticInfo( - model: device.model, - systemVersion: device.systemVersion, + model: model, + systemVersion: systemVersion, appVersion: Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "Unknown", memoryUsage: Self.currentMemoryUsage, storageInfo: Self.freeStorageGB @@ -366,6 +374,7 @@ extension AppLog { } // Bridge old EnhancedLogger structured methods + #if os(iOS) func logAudioSessionConfiguration(_ category: AVAudioSession.Category, mode: AVAudioSession.Mode, options: AVAudioSession.CategoryOptions) { audioSession("Configuring audio session - Category: \(category), Mode: \(mode), Options: \(options)") } @@ -375,6 +384,7 @@ extension AppLog { func logAudioSessionRouteChange(_ reason: AVAudioSession.RouteChangeReason) { audioSession("Audio route change: \(reason)") } + #endif func logChunkingStart(_ fileURL: URL, strategy: ChunkingStrategy) { chunking("Starting chunking for \(fileURL.lastPathComponent) with strategy: \(strategy)") } diff --git a/BisonNotes AI/BisonNotes AI/EnhancedTranscriptionManager.swift b/BisonNotes AI/BisonNotes AI/EnhancedTranscriptionManager.swift index 7e413f7..f774237 100644 --- a/BisonNotes AI/BisonNotes AI/EnhancedTranscriptionManager.swift +++ b/BisonNotes AI/BisonNotes AI/EnhancedTranscriptionManager.swift @@ -10,7 +10,9 @@ import Speech import AVFoundation import Combine import SwiftUI // Added for @AppStorage +#if canImport(UIKit) import UIKit +#endif // MARK: - Transcription Progress @@ -69,7 +71,7 @@ class EnhancedTranscriptionManager: NSObject, ObservableObject { private var speechRecognizer: SFSpeechRecognizer? private var currentTask: SFSpeechRecognitionTask? private let chunkingService = AudioFileChunkingService() - private var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid + private var backgroundTaskID: PlatformBackgroundTask.ID = .invalid private var backgroundTaskStartTime: Date? private var backgroundTaskRefreshTimer: Task? @@ -288,7 +290,7 @@ class EnhancedTranscriptionManager: NSObject, ObservableObject { private func beginBackgroundTask() { guard backgroundTaskID == .invalid else { return } - backgroundTaskID = UIApplication.shared.beginBackgroundTask(withName: "WhisperTranscription") { [weak self] in + backgroundTaskID = PlatformBackgroundTask.begin(name: "WhisperTranscription") { [weak self] in Task { @MainActor in self?.endBackgroundTask() } @@ -298,9 +300,11 @@ class EnhancedTranscriptionManager: NSObject, ObservableObject { backgroundTaskStartTime = Date() AppLog.shared.transcription("Started background task for Whisper: \(backgroundTaskID.rawValue)", level: .debug) - // Start a timer to refresh the background task every 25 seconds - // to avoid iOS warnings about tasks running >30 seconds + #if os(iOS) && !targetEnvironment(macCatalyst) + // Only iOS background tasks expire. Mac uses one ProcessInfo activity + // for the full transcription instead of refreshing every 25 seconds. startBackgroundTaskRefreshTimer() + #endif } } @@ -311,7 +315,7 @@ class EnhancedTranscriptionManager: NSObject, ObservableObject { if backgroundTaskID != .invalid { AppLog.shared.transcription("Ending background task for Whisper: \(backgroundTaskID.rawValue)", level: .debug) - UIApplication.shared.endBackgroundTask(backgroundTaskID) + PlatformBackgroundTask.end(backgroundTaskID) backgroundTaskID = .invalid backgroundTaskStartTime = nil } @@ -344,13 +348,13 @@ class EnhancedTranscriptionManager: NSObject, ObservableObject { // End the current task let oldTaskID = backgroundTaskID - UIApplication.shared.endBackgroundTask(backgroundTaskID) + PlatformBackgroundTask.end(backgroundTaskID) backgroundTaskID = .invalid backgroundTaskStartTime = nil AppLog.shared.transcription("Ended old task: \(oldTaskID.rawValue)", level: .debug) // Immediately start a new one - backgroundTaskID = UIApplication.shared.beginBackgroundTask(withName: "WhisperTranscription") { [weak self] in + backgroundTaskID = PlatformBackgroundTask.begin(name: "WhisperTranscription") { [weak self] in Task { @MainActor in self?.endBackgroundTask() } diff --git a/BisonNotes AI/BisonNotes AI/FileImportManager.swift b/BisonNotes AI/BisonNotes AI/FileImportManager.swift index 1e8b389..effd745 100644 --- a/BisonNotes AI/BisonNotes AI/FileImportManager.swift +++ b/BisonNotes AI/BisonNotes AI/FileImportManager.swift @@ -7,7 +7,9 @@ import Foundation @preconcurrency import AVFoundation +#if canImport(UIKit) import UIKit +#endif import SwiftUI import CoreData diff --git a/BisonNotes AI/BisonNotes AI/FluidAudio/FluidAudioSettingsView.swift b/BisonNotes AI/BisonNotes AI/FluidAudio/FluidAudioSettingsView.swift index 493a89b..fca5e7d 100644 --- a/BisonNotes AI/BisonNotes AI/FluidAudio/FluidAudioSettingsView.swift +++ b/BisonNotes AI/BisonNotes AI/FluidAudio/FluidAudioSettingsView.swift @@ -8,6 +8,171 @@ struct FluidAudioSettingsView: View { @Environment(\.dismiss) private var dismiss var body: some View { + #if os(macOS) + nativeMacContent + #else + standardContent + #endif + } + + #if os(macOS) + private var nativeMacContent: some View { + ScrollView { + VStack(alignment: .leading, spacing: 20) { + VStack(alignment: .leading, spacing: 6) { + Text("On-Device Transcription") + .font(.largeTitle.bold()) + Text("Run Parakeet locally using Apple silicon acceleration.") + .font(.subheadline) + .foregroundStyle(.secondary) + } + + nativeSettingsCard( + title: "Engine", + systemImage: "waveform", + tint: .orange + ) { + Toggle(isOn: $enableFluidAudio) { + VStack(alignment: .leading, spacing: 3) { + Text("Enable FluidAudio") + .fontWeight(.semibold) + Text("Uses NVIDIA Parakeet for private, on-device transcription.") + .font(.caption) + .foregroundStyle(.secondary) + } + } + .toggleStyle(.switch) + + Divider() + + HStack(alignment: .center, spacing: 20) { + VStack(alignment: .leading, spacing: 3) { + Text("Model") + .fontWeight(.semibold) + Text("Choose the Parakeet model used for transcription.") + .font(.caption) + .foregroundStyle(.secondary) + } + + Spacer(minLength: 24) + + Picker("Model", selection: $selectedModelVersion) { + ForEach(FluidAudioModelInfo.ModelVersion.allCases, id: \.self) { version in + Text(version.displayName) + .tag(version.rawValue) + } + } + .labelsHidden() + .frame(width: 240) + .onChange(of: selectedModelVersion) { _, _ in + manager.invalidateForVersionChange() + } + } + } + + if enableFluidAudio { + nativeSettingsCard( + title: "Model Status", + systemImage: "shippingbox", + tint: .blue + ) { + HStack(spacing: 12) { + VStack(alignment: .leading, spacing: 3) { + Text(manager.isModelReady ? "Ready to Transcribe" : "Model Not Downloaded") + .fontWeight(.semibold) + Text(manager.isModelReady + ? "The selected model is available on this Mac." + : "Download the model before using on-device transcription.") + .font(.caption) + .foregroundStyle(.secondary) + } + + Spacer() + + Label( + manager.isModelReady ? "Ready" : "Not Ready", + systemImage: manager.isModelReady + ? "checkmark.circle.fill" + : "arrow.down.circle" + ) + .font(.caption.weight(.semibold)) + .foregroundColor(manager.isModelReady ? .green : .secondary) + } + + if manager.isDownloading { + ProgressView(value: manager.downloadProgress) + .progressViewStyle(.linear) + } + + if !manager.currentStatus.isEmpty { + Text(manager.currentStatus) + .font(.caption) + .foregroundStyle(.secondary) + } + + HStack(spacing: 10) { + if manager.isDownloading { + Button("Cancel Download", role: .destructive) { + manager.cancelDownload() + } + } else { + Button("Download / Prepare Model") { + prepareModel() + } + .disabled(manager.isModelReady) + } + + if manager.isModelReady { + Button("Delete Model", role: .destructive) { + manager.deleteModel() + } + } + } + } + } + + Label { + Text( + "Audio stays on this Mac. Enabling FluidAudio does not remove " + + "or reconfigure your other transcription engines." + ) + .font(.caption) + .foregroundStyle(.secondary) + } icon: { + Image(systemName: "lock.shield.fill") + .foregroundStyle(.green) + } + .padding(16) + .frame(maxWidth: .infinity, alignment: .leading) + .background(.quaternary.opacity(0.5), in: RoundedRectangle(cornerRadius: 12)) + } + .frame(maxWidth: 680) + .frame(maxWidth: .infinity, alignment: .top) + .padding(28) + } + .background(Color(.systemGroupedBackground)) + } + + private func nativeSettingsCard( + title: String, + systemImage: String, + tint: Color, + @ViewBuilder content: () -> Content + ) -> some View { + VStack(alignment: .leading, spacing: 16) { + Label(title, systemImage: systemImage) + .font(.headline) + .foregroundStyle(tint) + + content() + } + .padding(18) + .frame(maxWidth: .infinity, alignment: .leading) + .background(.quaternary.opacity(0.45), in: RoundedRectangle(cornerRadius: 14)) + } + #endif + + private var standardContent: some View { Form { Section("Engine") { Toggle("Enable FluidAudio (Parakeet)", isOn: $enableFluidAudio) @@ -54,13 +219,7 @@ struct FluidAudioSettingsView: View { } } else { Button("Download / Prepare Model") { - Task { - do { - try await manager.downloadAndPrepareModel() - } catch { - manager.currentStatus = "Failed: \(error.localizedDescription)" - } - } + prepareModel() } } @@ -89,4 +248,14 @@ struct FluidAudioSettingsView: View { } } } + + private func prepareModel() { + Task { + do { + try await manager.downloadAndPrepareModel() + } catch { + manager.currentStatus = "Failed: \(error.localizedDescription)" + } + } + } } diff --git a/BisonNotes AI/BisonNotes AI/GoogleAIStudioSettingsView.swift b/BisonNotes AI/BisonNotes AI/GoogleAIStudioSettingsView.swift index 36f93ea..e53125b 100644 --- a/BisonNotes AI/BisonNotes AI/GoogleAIStudioSettingsView.swift +++ b/BisonNotes AI/BisonNotes AI/GoogleAIStudioSettingsView.swift @@ -30,7 +30,7 @@ struct GoogleAIStudioSettingsView: View { ] var body: some View { - NavigationStack { + PlatformSettingsNavigationStack { Form { Section(header: Text("API Configuration")) { VStack(alignment: .leading, spacing: 8) { @@ -122,6 +122,7 @@ struct GoogleAIStudioSettingsView: View { .disabled(apiKey.isEmpty || isTestingConnection) } } + .nativeMacSettingsFormStyle() .scrollContentBackground(.hidden) .background(Color(.systemGroupedBackground)) .navigationTitle("Google AI Studio") diff --git a/BisonNotes AI/BisonNotes AI/Info.plist b/BisonNotes AI/BisonNotes AI/Info.plist index b72d7dc..039a8df 100644 --- a/BisonNotes AI/BisonNotes AI/Info.plist +++ b/BisonNotes AI/BisonNotes AI/Info.plist @@ -82,7 +82,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 2.2 + $(MARKETING_VERSION) CFBundleVersion $(CURRENT_PROJECT_VERSION) LSApplicationQueriesSchemes diff --git a/BisonNotes AI/BisonNotes AI/LocationDetailView.swift b/BisonNotes AI/BisonNotes AI/LocationDetailView.swift index 4e35d7f..b8f6bd7 100644 --- a/BisonNotes AI/BisonNotes AI/LocationDetailView.swift +++ b/BisonNotes AI/BisonNotes AI/LocationDetailView.swift @@ -125,7 +125,7 @@ struct LocationDetailView: View { } private func copyCoordinates() { - UIPasteboard.general.string = locationData.coordinateString + PlatformPasteboard.string = locationData.coordinateString } } diff --git a/BisonNotes AI/BisonNotes AI/LogExporter.swift b/BisonNotes AI/BisonNotes AI/LogExporter.swift index d7ef204..c682926 100644 --- a/BisonNotes AI/BisonNotes AI/LogExporter.swift +++ b/BisonNotes AI/BisonNotes AI/LogExporter.swift @@ -8,9 +8,15 @@ import Foundation import OSLog +#if canImport(UIKit) import UIKit +#else +import AppKit +#endif import SwiftUI +#if canImport(MessageUI) import MessageUI +#endif // MARK: - Log Exporter @@ -30,10 +36,17 @@ struct LogExporter { var sections = [String]() // ── Header ── + #if canImport(UIKit) // Capture UIDevice info on the main thread (UIKit is main-thread-only) let (deviceModel, systemVersion) = await MainActor.run { (UIDevice.current.model, UIDevice.current.systemVersion) } + let platformName = "iOS" + #else + let deviceModel = "Mac" + let systemVersion = ProcessInfo.processInfo.operatingSystemVersionString + let platformName = "macOS" + #endif let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "?" let buildNumber = Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "?" let previousCrash = AppLog.shared.previousSessionCrashed @@ -41,7 +54,7 @@ struct LogExporter { let header = """ BisonNotes AI Diagnostic Log App Version: \(appVersion) (\(buildNumber)) - Device: \(deviceModel), iOS \(systemVersion) + Device: \(deviceModel), \(platformName) \(systemVersion) Exported: \(formatter.string(from: Date())) Previous session crashed: \(previousCrash ? "YES" : "No") """ @@ -127,6 +140,7 @@ struct LogExporter { // MARK: - Log Email Presenter +#if os(iOS) /// Presents MFMailComposeViewController directly from the UIKit window, /// bypassing SwiftUI's sheet stack to avoid "only a single sheet" conflicts. /// Falls back to UIActivityViewController if Mail is not configured. @@ -207,3 +221,29 @@ class LogEmailPresenter: NSObject, MFMailComposeViewControllerDelegate { return vc } } +#else +/// Presents diagnostic logs through the native macOS sharing-service picker. +@MainActor +final class LogEmailPresenter: NSObject { + static let shared = LogEmailPresenter() + + func presentLogEmail( + logFileURL: URL, + onPresented: @escaping () -> Void = {}, + onDismiss: @escaping () -> Void + ) { + let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "?" + let didPresent = PlatformSharingPresenter.shared.present( + items: [logFileURL], + subject: "BisonNotes AI Diagnostic Report - v\(appVersion)", + onPresented: onPresented, + onDismiss: onDismiss + ) + if !didPresent { + NSWorkspace.shared.activateFileViewerSelecting([logFileURL]) + onPresented() + onDismiss() + } + } +} +#endif diff --git a/BisonNotes AI/BisonNotes AI/MLXSwiftEngine.swift b/BisonNotes AI/BisonNotes AI/MLXSwiftEngine.swift index ff00b25..07c6660 100644 --- a/BisonNotes AI/BisonNotes AI/MLXSwiftEngine.swift +++ b/BisonNotes AI/BisonNotes AI/MLXSwiftEngine.swift @@ -197,13 +197,66 @@ final class MLXSwiftEngine: SummarizationEngine, ConnectionTestable { } } +// MARK: - Response Cleanup + +/// Removes reasoning-channel output that some thinking-capable models include +/// in their decoded response. Summary parsing must only receive the final answer. +enum MLXSwiftResponseCleaner { + private static let reasoningTags = ["think", "analysis", "reasoning"] + + static func stripThinking(from text: String) -> String { + var cleaned = text + + for tag in reasoningTags { + cleaned = cleaned.replacingOccurrences( + of: "(?is)<\(tag)>.*?", + with: "", + options: .regularExpression + ) + + // A response can hit its token limit before the closing tag. Never + // surface a partial reasoning trace as the generated summary. + if let openTag = cleaned.range(of: "<\(tag)>", options: .caseInsensitive) { + cleaned.removeSubrange(openTag.lowerBound...) + } + } + + cleaned = stripProseReasoningPreamble(from: cleaned) + return cleaned.trimmingCharacters(in: .whitespacesAndNewlines) + } + + private static func stripProseReasoningPreamble(from text: String) -> String { + let reasoningPrefix = + #"(?is)^\s*(?:(?:here(?:'|’)s|here is)\s+(?:a\s+|the\s+|my\s+)?"# + + #"(?:thinking|reasoning)(?:\s+process)?|(?:thinking|reasoning)(?:\s+process)?)\s*:"# + guard text.range(of: reasoningPrefix, options: .regularExpression) != nil else { + return text + } + + if let summaryHeader = text.range(of: #"(?im)^##\s+summary\s*$"#, options: .regularExpression) { + return String(text[summaryHeader.lowerBound...]) + } + + let finalAnswerMarker = + #"(?im)^\s*(?:(?:here(?:'|’)s|here is)\s+the\s+)?"# + + #"final\s+(?:answer|response|summary)\s*:\s*"# + if let finalAnswer = text.range(of: finalAnswerMarker, options: .regularExpression) { + return String(text[finalAnswer.upperBound...]) + } + + return text + } +} + // MARK: - Conditional MLXLLM Implementation #if canImport(MLXLLM) && canImport(MLXLMCommon) import MLXLLM import MLX import MLXLMCommon +#if canImport(UIKit) import UIKit +#endif import os // MARK: MLX Memory Configuration for iOS @@ -265,6 +318,11 @@ extension MLXSwiftDownloadManager { // MARK: MLX Service Actor private actor MLXSwiftService { + private static let thinkingTokenAllowance = 4_096 + #if os(macOS) + private static let thinkingModelId = "prism-ml/Ternary-Bonsai-27B-mlx-2bit" + #endif + private var modelContainer: ModelContainer? private var loadedModelId: String? private var memoryObserver: NSObjectProtocol? @@ -281,7 +339,7 @@ private actor MLXSwiftService { guard memoryObserver == nil else { return } let observer = NotificationCenter.default.addObserver( - forName: UIApplication.didReceiveMemoryWarningNotification, + forName: PlatformLifecycle.didReceiveMemoryWarningNotification, object: nil, queue: .main ) { [weak self] _ in @@ -347,7 +405,10 @@ private actor MLXSwiftService { // Use a hard cap well below the device context window to keep peak memory // manageable. MLX loads the full model into Metal buffers (no mmap), so // every token of KV cache and activation memory is additive. - let inputLimit = min(Self.mlxMaxInputTokens, max(1500, configuredContextTokens - configuredMaxTokens - 700)) + let inputLimit = min( + Self.mlxMaxInputTokens, + max(1_500, configuredContextTokens - configuredGenerationTokenBudget - 700) + ) AppLog.shared.summarization("[MLXSwift] Transcript: \(tokenCount) tokens, input limit: \(inputLimit) tokens/chunk") @@ -534,6 +595,8 @@ private actor MLXSwiftService { CRITICAL: - Extract ONLY information that appears in the transcript itself + - Think carefully enough to catch every explicit task, reminder, deadline, title topic, and important detail + - Keep reasoning inside the model's thinking channel; after it closes, return only the final formatted sections - Do NOT generate placeholder text, examples, or generic content - Do NOT include tasks, reminders, or titles unless they are actually mentioned - If no tasks are mentioned, return an empty tasks section @@ -553,7 +616,7 @@ private actor MLXSwiftService { private func generate(prompt: String) async throws -> String { let container = try await loadContainer() let parameters = GenerateParameters( - maxTokens: configuredMaxTokens, + maxTokens: configuredGenerationTokenBudget, maxKVSize: configuredContextTokens, kvBits: 4, kvGroupSize: 64, @@ -563,10 +626,22 @@ private actor MLXSwiftService { repetitionPenalty: configuredRepetitionPenalty, prefillStepSize: 256 ) + let templateContext: [String: any Sendable]? + if isThinkingModeEnabled { + templateContext = ["enable_thinking": true] + AppLog.shared.summarization( + "[MLXSwift] Thinking mode enabled: \(Self.thinkingTokenAllowance)-token hidden reasoning allowance, " + + "\(configuredMaxTokens)-token final-output target" + ) + } else { + templateContext = nil + } + let session = ChatSession( container, instructions: Self.systemInstruction, - generateParameters: parameters + generateParameters: parameters, + additionalContext: templateContext ) let response = try await session.respond(to: prompt) @@ -580,10 +655,10 @@ private actor MLXSwiftService { private static let minimumAvailableMemory: UInt64 = 2_500_000_000 /// Returns the amount of memory the process can safely use before loading. - /// On iOS this is the jetsam-limit headroom; on Mac Catalyst that API returns 0 - /// (no jetsam limits on macOS), so we read host VM stats for actual free RAM. + /// On iOS this is the jetsam-limit headroom; on Mac (Catalyst or native) that + /// API is unavailable/returns 0, so we read host VM stats for actual free RAM. private static func availableMemoryForModelLoad() -> UInt64 { - #if targetEnvironment(macCatalyst) + #if targetEnvironment(macCatalyst) || os(macOS) var stats = vm_statistics64() var count = mach_msg_type_number_t(MemoryLayout.size / MemoryLayout.size) let result = withUnsafeMutablePointer(to: &stats) { ptr -> kern_return_t in @@ -659,6 +734,21 @@ private actor MLXSwiftService { return MLXSwiftSettingsKeys.defaultMaxTokens } + private var configuredGenerationTokenBudget: Int { + let reasoningAllowance = isThinkingModeEnabled ? Self.thinkingTokenAllowance : 0 + return configuredMaxTokens + reasoningAllowance + } + + private var isThinkingModeEnabled: Bool { + #if os(macOS) + let modelId = UserDefaults.standard.string(forKey: MLXSwiftSettingsKeys.modelId) + ?? MLXSwiftSettingsKeys.defaultModelId + return modelId == Self.thinkingModelId + #else + return false + #endif + } + private var configuredContextTokens: Int { if UserDefaults.standard.object(forKey: MLXSwiftSettingsKeys.contextTokens) != nil { return UserDefaults.standard.integer(forKey: MLXSwiftSettingsKeys.contextTokens) @@ -705,7 +795,7 @@ private struct MLXSwiftStructuredResponse { let contentType: ContentType } -private enum MLXSwiftResponseParser { +enum MLXSwiftResponseParser { static func parse( _ rawResponse: String, fallbackText: String @@ -856,12 +946,7 @@ private enum MLXSwiftResponseParser { } static func stripThinking(from text: String) -> String { - text.replacingOccurrences( - of: #"(?is).*?"#, - with: "", - options: .regularExpression - ) - .trimmingCharacters(in: .whitespacesAndNewlines) + MLXSwiftResponseCleaner.stripThinking(from: text) } private static func extractJSONObject(from text: String) -> String { diff --git a/BisonNotes AI/BisonNotes AI/MLXSwiftSettingsView.swift b/BisonNotes AI/BisonNotes AI/MLXSwiftSettingsView.swift index b2a6d8f..06a8656 100644 --- a/BisonNotes AI/BisonNotes AI/MLXSwiftSettingsView.swift +++ b/BisonNotes AI/BisonNotes AI/MLXSwiftSettingsView.swift @@ -20,38 +20,55 @@ struct MLXModelOption: Identifiable { /// Minimum device RAM in GB required to run this model let requiredRAM: Double - static let available: [MLXModelOption] = [ - MLXModelOption( - id: "prism-ml/Ternary-Bonsai-1.7B-mlx-2bit", - displayName: "Ternary Bonsai 1.7B", - description: "Compact model for devices with limited memory.", - downloadSize: "~470 MB", - downloadSizeBytes: 470_000_000, - parameters: "1.7B", - contextWindow: 16_384, - requiredRAM: 4.0 - ), - MLXModelOption( - id: "prism-ml/Ternary-Bonsai-4B-mlx-2bit", - displayName: "Ternary Bonsai 4B", - description: "Fast, memory-efficient model for on-device summaries.", - downloadSize: "~1.1 GB", - downloadSizeBytes: 1_100_000_000, - parameters: "4B", - contextWindow: 16_384, - requiredRAM: 6.0 - ), - MLXModelOption( - id: "prism-ml/Ternary-Bonsai-8B-mlx-2bit", - displayName: "Ternary Bonsai 8B", - description: "Slower but higher quality summaries.", - downloadSize: "~2.3 GB", - downloadSizeBytes: 2_300_000_000, - parameters: "8B", - contextWindow: 16_384, - requiredRAM: 8.0 - ) - ] + static let available: [MLXModelOption] = { + var models = [ + MLXModelOption( + id: "prism-ml/Ternary-Bonsai-1.7B-mlx-2bit", + displayName: "Ternary Bonsai 1.7B", + description: "Compact model for devices with limited memory.", + downloadSize: "~470 MB", + downloadSizeBytes: 470_000_000, + parameters: "1.7B", + contextWindow: 16_384, + requiredRAM: 4.0 + ), + MLXModelOption( + id: "prism-ml/Ternary-Bonsai-4B-mlx-2bit", + displayName: "Ternary Bonsai 4B", + description: "Fast, memory-efficient model for on-device summaries.", + downloadSize: "~1.1 GB", + downloadSizeBytes: 1_100_000_000, + parameters: "4B", + contextWindow: 16_384, + requiredRAM: 6.0 + ), + MLXModelOption( + id: "prism-ml/Ternary-Bonsai-8B-mlx-2bit", + displayName: "Ternary Bonsai 8B", + description: "Slower but higher quality summaries.", + downloadSize: "~2.3 GB", + downloadSizeBytes: 2_300_000_000, + parameters: "8B", + contextWindow: 16_384, + requiredRAM: 8.0 + ) + ] + + #if os(macOS) + models.append(MLXModelOption( + id: "prism-ml/Ternary-Bonsai-27B-mlx-2bit", + displayName: "Ternary Bonsai 27B", + description: "Laptop-class reasoning for high-memory Apple silicon Macs.", + downloadSize: "~8.5 GB", + downloadSizeBytes: 8_520_000_000, + parameters: "27B", + contextWindow: 262_144, + requiredRAM: 16.0 + )) + #endif + + return models + }() /// Identifier for the 1.7B model β€” used by both the device-default selection /// (4-6GB devices) and the experimental-models filter (6GB+ devices). @@ -86,7 +103,11 @@ struct MLXSwiftSettingsView: View { var body: some View { let isSupported = DeviceCapabilities.supportsMLX - return Form { + return Group { + #if os(macOS) + nativeMacContent(isSupported: isSupported) + #else + Form { // Info Section Section { if isSupported { @@ -130,17 +151,21 @@ struct MLXSwiftSettingsView: View { advancedSettingsView } } + } + .scrollContentBackground(.hidden) + .background(Color(.systemGroupedBackground)) + #endif } - .scrollContentBackground(.hidden) - .background(Color(.systemGroupedBackground)) .navigationTitle(AIEngineType.mlxSwift.displayName) .navigationBarTitleDisplayMode(.inline) .toolbar { + #if !os(macOS) ToolbarItem(placement: .topBarTrailing) { Button("Done") { dismiss() } } + #endif } .alert("Delete Model?", isPresented: $showingDeleteConfirmation, presenting: modelToDelete) { model in Button("Delete", role: .destructive) { @@ -161,6 +186,96 @@ struct MLXSwiftSettingsView: View { } } + #if os(macOS) + private func nativeMacContent(isSupported: Bool) -> some View { + ScrollView { + VStack(alignment: .leading, spacing: 22) { + nativeMacHeader + + nativeSettingsCard(title: "Overview", systemImage: "cpu", tint: .indigo) { + Label { + Text(isSupported + ? "Models download from Hugging Face on first use and run locally afterward." + : "MLX Swift requires Apple silicon and at least 4 GB of memory.") + } icon: { + Image(systemName: isSupported ? "lock.shield.fill" : "exclamationmark.triangle.fill") + .foregroundStyle(isSupported ? .green : .orange) + } + .font(.subheadline) + } + + nativeSettingsCard(title: "Models", systemImage: "shippingbox", tint: .blue) { + ForEach(Array(visibleModels.enumerated()), id: \.element.id) { index, model in + if index > 0 { + Divider() + } + modelRow(for: model) + } + } + + if downloadManager.isDownloading { + nativeSettingsCard(title: "Download Progress", systemImage: "arrow.down.circle", tint: .blue) { + downloadProgressView + } + } + + nativeSettingsCard(title: "Model Status", systemImage: "checkmark.seal", tint: .green) { + modelStatusView + } + + nativeSettingsCard(title: "Generation", systemImage: "slider.horizontal.3", tint: .purple) { + temperatureSlider + } + + nativeSettingsCard(title: "Advanced", systemImage: "gearshape.2", tint: .secondary) { + DisclosureGroup("Advanced Generation Settings", isExpanded: $showingAdvancedSettings) { + VStack(alignment: .leading, spacing: 16) { + advancedSettingsView + } + .padding(.top, 14) + } + } + } + .frame(maxWidth: 680) + .frame(maxWidth: .infinity, alignment: .top) + .padding(28) + } + .background(Color(.systemGroupedBackground)) + } + + private var nativeMacHeader: some View { + VStack(alignment: .leading, spacing: 6) { + Text(AIEngineType.mlxSwift.displayName) + .font(.largeTitle.bold()) + Text("Private summarization optimized for Apple silicon.") + .font(.subheadline) + .foregroundStyle(.secondary) + } + } + + private func nativeSettingsCard( + title: String, + systemImage: String, + tint: Color, + @ViewBuilder content: () -> Content + ) -> some View { + VStack(alignment: .leading, spacing: 16) { + Label(title, systemImage: systemImage) + .font(.headline) + .foregroundStyle(tint) + + content() + } + .padding(18) + .frame(maxWidth: .infinity, alignment: .leading) + .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 14)) + .overlay { + RoundedRectangle(cornerRadius: 14) + .stroke(Color.primary.opacity(0.08), lineWidth: 1) + } + } + #endif + // MARK: - Model Visibility /// Models visible for the current device. diff --git a/BisonNotes AI/BisonNotes AI/MistralAISettingsView.swift b/BisonNotes AI/BisonNotes AI/MistralAISettingsView.swift index afbd558..5c4cd92 100644 --- a/BisonNotes AI/BisonNotes AI/MistralAISettingsView.swift +++ b/BisonNotes AI/BisonNotes AI/MistralAISettingsView.swift @@ -33,7 +33,7 @@ struct MistralAISettingsView: View { } var body: some View { - NavigationStack { + PlatformSettingsNavigationStack { Form { if apiKey.isEmpty { Section { @@ -196,6 +196,7 @@ struct MistralAISettingsView: View { .disabled(apiKey.isEmpty || isTestingConnection) } } + .nativeMacSettingsFormStyle() .scrollContentBackground(.hidden) .background(Color(.systemGroupedBackground)) .navigationTitle("Mistral AI") @@ -215,7 +216,7 @@ struct MistralAISettingsView: View { } message: { Text(alertMessage) } - .fullScreenCover(isPresented: $showingOnboarding) { + .platformFullScreenCover(isPresented: $showingOnboarding) { MistralOnboardingView(onSetupComplete: { onConfigurationChanged() }) diff --git a/BisonNotes AI/BisonNotes AI/MistralTranscribeSettingsView.swift b/BisonNotes AI/BisonNotes AI/MistralTranscribeSettingsView.swift index 9bd4cd3..18704db 100644 --- a/BisonNotes AI/BisonNotes AI/MistralTranscribeSettingsView.swift +++ b/BisonNotes AI/BisonNotes AI/MistralTranscribeSettingsView.swift @@ -24,13 +24,17 @@ struct MistralTranscribeSettingsView: View { @Environment(\.dismiss) private var dismiss var body: some View { - NavigationStack { + PlatformSettingsNavigationStack { + #if os(macOS) + nativeMacContent + #else Form { apiConfigurationSection transcriptionSettingsSection connectionTestSection featuresSection } + .nativeMacSettingsFormStyle() .scrollContentBackground(.hidden) .background(Color(.systemGroupedBackground)) .navigationTitle("Mistral Transcription") @@ -40,9 +44,205 @@ struct MistralTranscribeSettingsView: View { Button("Done") { dismiss() } } } + #endif } } + #if os(macOS) + private var nativeMacContent: some View { + ScrollView { + VStack(alignment: .leading, spacing: 20) { + VStack(alignment: .leading, spacing: 6) { + Text("Mistral Transcription") + .font(.largeTitle.bold()) + Text("Configure Voxtral cloud transcription and speaker labeling.") + .font(.subheadline) + .foregroundStyle(.secondary) + } + + nativeSettingsCard( + title: "API Configuration", + systemImage: "key.fill", + tint: .green + ) { + HStack(spacing: 16) { + VStack(alignment: .leading, spacing: 3) { + Text("Mistral API Key") + .fontWeight(.semibold) + Text("Shared with the Mistral AI summarization engine.") + .font(.caption) + .foregroundStyle(.secondary) + } + + Spacer() + + Label( + apiKey.isEmpty ? "Not Configured" : "Configured", + systemImage: apiKey.isEmpty + ? "exclamationmark.circle.fill" + : "checkmark.circle.fill" + ) + .font(.caption.weight(.semibold)) + .foregroundColor(apiKey.isEmpty ? .red : .green) + } + + if apiKey.isEmpty { + Text("Add the key in AI Settings > Mistral AI before testing this connection.") + .font(.caption) + .foregroundStyle(.secondary) + } + } + + nativeSettingsCard( + title: "Transcription Settings", + systemImage: "waveform.badge.mic", + tint: .orange + ) { + VStack(alignment: .leading, spacing: 3) { + Text("Model") + .fontWeight(.semibold) + Text(MistralTranscribeModel.voxtralMiniLatest.displayName) + .foregroundStyle(.secondary) + Text(MistralTranscribeModel.voxtralMiniLatest.description) + .font(.caption) + .foregroundStyle(.secondary) + } + + Divider() + + Toggle(isOn: $enableDiarization) { + VStack(alignment: .leading, spacing: 3) { + Text("Speaker Diarization") + .fontWeight(.semibold) + Text("Identify and label different speakers in the audio.") + .font(.caption) + .foregroundStyle(.secondary) + } + } + .toggleStyle(.switch) + + Divider() + + VStack(alignment: .leading, spacing: 8) { + Text("Language (Optional)") + .fontWeight(.semibold) + TextField("Auto-detect (leave empty)", text: $language) + .textFieldStyle(.roundedBorder) + .autocapitalization(.none) + .disableAutocorrection(true) + Text("Use a language code such as en, fr, or es, or leave this empty for automatic detection.") + .font(.caption) + .foregroundStyle(.secondary) + } + } + + nativeSettingsCard( + title: "Connection", + systemImage: "network", + tint: .blue + ) { + HStack(spacing: 12) { + Button(action: testConnection) { + if isTestingConnection { + ProgressView() + .controlSize(.small) + } else { + Label("Test Connection", systemImage: "network") + } + } + .disabled(apiKey.isEmpty || isTestingConnection) + + if showingConnectionResult { + Label( + connectionTestResult, + systemImage: isConnectionSuccessful + ? "checkmark.circle.fill" + : "xmark.circle.fill" + ) + .font(.caption) + .foregroundColor(isConnectionSuccessful ? .green : .red) + } + } + } + + nativeSettingsCard( + title: "Features & Limits", + systemImage: "list.bullet.rectangle", + tint: .blue + ) { + LazyVGrid( + columns: [ + GridItem(.flexible(), alignment: .topLeading), + GridItem(.flexible(), alignment: .topLeading) + ], + alignment: .leading, + spacing: 16 + ) { + nativeFeature( + icon: "doc.text", + title: "Supported Formats", + description: "MP3, MP4, M4A, WAV, FLAC, OGG, WebM" + ) + nativeFeature( + icon: "person.2", + title: "Speaker Diarization", + description: "Identifies and labels different speakers" + ) + nativeFeature( + icon: "globe", + title: "Language Support", + description: "Automatic detection or a specified language code" + ) + nativeFeature( + icon: "dollarsign.circle", + title: "Pricing", + description: "$0.003 per minute of audio" + ) + } + } + } + .frame(maxWidth: 680) + .frame(maxWidth: .infinity, alignment: .top) + .padding(28) + } + .background(Color(.systemGroupedBackground)) + } + + private func nativeSettingsCard( + title: String, + systemImage: String, + tint: Color, + @ViewBuilder content: () -> Content + ) -> some View { + VStack(alignment: .leading, spacing: 16) { + Label(title, systemImage: systemImage) + .font(.headline) + .foregroundStyle(tint) + + content() + } + .padding(18) + .frame(maxWidth: .infinity, alignment: .leading) + .background(.quaternary.opacity(0.45), in: RoundedRectangle(cornerRadius: 14)) + } + + private func nativeFeature(icon: String, title: String, description: String) -> some View { + HStack(alignment: .top, spacing: 10) { + Image(systemName: icon) + .foregroundStyle(.blue) + .frame(width: 22) + + VStack(alignment: .leading, spacing: 3) { + Text(title) + .font(.subheadline.weight(.semibold)) + Text(description) + .font(.caption) + .foregroundStyle(.secondary) + } + } + } + #endif + // MARK: - Sections private var apiConfigurationSection: some View { diff --git a/BisonNotes AI/BisonNotes AI/Models/DataMigrationManager.swift b/BisonNotes AI/BisonNotes AI/Models/DataMigrationManager.swift index 408c925..895c958 100644 --- a/BisonNotes AI/BisonNotes AI/Models/DataMigrationManager.swift +++ b/BisonNotes AI/BisonNotes AI/Models/DataMigrationManager.swift @@ -8,7 +8,9 @@ import Foundation import CoreData import AVFoundation +#if canImport(UIKit) import UIKit +#endif // MARK: - Data Integrity Structures diff --git a/BisonNotes AI/BisonNotes AI/Models/DeviceCompatibility.swift b/BisonNotes AI/BisonNotes AI/Models/DeviceCompatibility.swift index d8ac94b..2aed8eb 100644 --- a/BisonNotes AI/BisonNotes AI/Models/DeviceCompatibility.swift +++ b/BisonNotes AI/BisonNotes AI/Models/DeviceCompatibility.swift @@ -1,5 +1,7 @@ import Foundation +#if canImport(UIKit) import UIKit +#endif struct DeviceCompatibility { @@ -89,6 +91,7 @@ struct DeviceCompatibility { } } +#if canImport(UIKit) public extension UIDevice { var modelName: String { var systemInfo = utsname() @@ -101,3 +104,4 @@ public extension UIDevice { return identifier } } +#endif diff --git a/BisonNotes AI/BisonNotes AI/Models/RecordingArchiveService.swift b/BisonNotes AI/BisonNotes AI/Models/RecordingArchiveService.swift index 7846116..04f268c 100644 --- a/BisonNotes AI/BisonNotes AI/Models/RecordingArchiveService.swift +++ b/BisonNotes AI/BisonNotes AI/Models/RecordingArchiveService.swift @@ -387,10 +387,10 @@ class RecordingArchiveService: ObservableObject { locationObject.setValue(Self.statusAvailable, forKey: "status") // Persist a security-scoped bookmark so sandbox access survives - // app launches. Mac Catalyst requires the explicit option; on iOS - // the default already retains the picker-granted scope. + // app launches. Both native macOS and Mac Catalyst require the + // explicit option; on iOS the picker-granted scope is retained. let bookmarkOptions: URL.BookmarkCreationOptions = { - #if targetEnvironment(macCatalyst) + #if targetEnvironment(macCatalyst) || os(macOS) return [.withSecurityScope] #else return [] @@ -485,11 +485,10 @@ class RecordingArchiveService: ObservableObject { private func resolvedArchiveURL(from locationObject: NSManagedObject) throws -> URL { if let bookmarkData = locationObject.value(forKey: "bookmarkData") as? Data { var isStale = false - // Mac Catalyst stores security-scoped bookmarks; resolution must - // pass the matching option for startAccessingSecurityScopedResource() - // to grant access on a subsequent launch. + // Mac builds store security-scoped bookmarks; resolution must pass + // the matching option so access can be restored after relaunch. let resolutionOptions: URL.BookmarkResolutionOptions = { - #if targetEnvironment(macCatalyst) + #if targetEnvironment(macCatalyst) || os(macOS) return [.withoutUI, .withSecurityScope] #else return [.withoutUI] diff --git a/BisonNotes AI/BisonNotes AI/OllamaSettingsView.swift b/BisonNotes AI/BisonNotes AI/OllamaSettingsView.swift index 0230b9d..2d69cd1 100644 --- a/BisonNotes AI/BisonNotes AI/OllamaSettingsView.swift +++ b/BisonNotes AI/BisonNotes AI/OllamaSettingsView.swift @@ -53,7 +53,7 @@ struct OllamaSettingsView: View { } var body: some View { - NavigationStack { + PlatformSettingsNavigationStack { Form { headerSection serverConfigurationSection @@ -62,6 +62,7 @@ struct OllamaSettingsView: View { } helpSection } + .nativeMacSettingsFormStyle() .scrollContentBackground(.hidden) .background(Color(.systemGroupedBackground)) .navigationTitle("Ollama Settings") diff --git a/BisonNotes AI/BisonNotes AI/OnDeviceLLM/OnDeviceLLMEngine.swift b/BisonNotes AI/BisonNotes AI/OnDeviceLLM/OnDeviceLLMEngine.swift index a2b7be3..c60851d 100644 --- a/BisonNotes AI/BisonNotes AI/OnDeviceLLM/OnDeviceLLMEngine.swift +++ b/BisonNotes AI/BisonNotes AI/OnDeviceLLM/OnDeviceLLMEngine.swift @@ -8,7 +8,9 @@ import Foundation import os.log +#if canImport(UIKit) import UIKit +#endif // MARK: - On-Device LLM Engine @@ -78,7 +80,7 @@ class OnDeviceLLMEngine: SummarizationEngine, ConnectionTestable { /// a fatal crash in llama.cpp's Metal backend (ggml_abort). private func setupBackgroundObservers() { backgroundObserver = NotificationCenter.default.addObserver( - forName: UIApplication.didEnterBackgroundNotification, + forName: PlatformLifecycle.didEnterBackgroundNotification, object: nil, queue: .main ) { [weak self] _ in @@ -87,7 +89,7 @@ class OnDeviceLLMEngine: SummarizationEngine, ConnectionTestable { } foregroundObserver = NotificationCenter.default.addObserver( - forName: UIApplication.willEnterForegroundNotification, + forName: PlatformLifecycle.willEnterForegroundNotification, object: nil, queue: .main ) { [weak self] _ in @@ -101,7 +103,7 @@ class OnDeviceLLMEngine: SummarizationEngine, ConnectionTestable { // still in flight. Explicitly unloading the model here forces llama_free / // llama_model_free to run before exit(), releasing all Metal resources cleanly. terminateObserver = NotificationCenter.default.addObserver( - forName: UIApplication.willTerminateNotification, + forName: PlatformLifecycle.willTerminateNotification, object: nil, queue: .main ) { [weak self] _ in @@ -348,14 +350,13 @@ class OnDeviceLLMEngine: SummarizationEngine, ConnectionTestable { AppLog.shared.summarization("[OnDeviceLLMEngine] Processing chunk \(index + 1)/\(chunks.count)", level: .debug) // Check if we are running in background and task is about to expire - // Must access UIApplication.shared on MainActor let isBackground = await MainActor.run { - UIApplication.shared.applicationState == .background + PlatformApp.isInBackground } if isBackground { let remaining = await MainActor.run { - UIApplication.shared.backgroundTimeRemaining + PlatformBackgroundTask.remainingTime } if remaining < 10 { // Less than 10 seconds remaining diff --git a/BisonNotes AI/BisonNotes AI/OnDeviceLLM/OnDeviceLLMSettingsView.swift b/BisonNotes AI/BisonNotes AI/OnDeviceLLM/OnDeviceLLMSettingsView.swift index 09d7ccb..56ad8eb 100644 --- a/BisonNotes AI/BisonNotes AI/OnDeviceLLM/OnDeviceLLMSettingsView.swift +++ b/BisonNotes AI/BisonNotes AI/OnDeviceLLM/OnDeviceLLMSettingsView.swift @@ -103,16 +103,19 @@ struct OnDeviceLLMSettingsView: View { connectionTestButton } } + .nativeMacSettingsFormStyle() .scrollContentBackground(.hidden) .background(Color(.systemGroupedBackground)) .navigationTitle(AIEngineType.onDeviceLLM.displayName) .navigationBarTitleDisplayMode(.inline) .toolbar { + #if !os(macOS) ToolbarItem(placement: .topBarTrailing) { Button("Done") { dismiss() } } + #endif } .alert("Delete Model?", isPresented: $showingDeleteConfirmation, presenting: modelToDelete) { model in Button("Delete", role: .destructive) { diff --git a/BisonNotes AI/BisonNotes AI/OpenAISettingsView.swift b/BisonNotes AI/BisonNotes AI/OpenAISettingsView.swift index 5f1c304..2dba5d3 100644 --- a/BisonNotes AI/BisonNotes AI/OpenAISettingsView.swift +++ b/BisonNotes AI/BisonNotes AI/OpenAISettingsView.swift @@ -26,7 +26,7 @@ struct OpenAISettingsView: View { } var body: some View { - NavigationStack { + PlatformSettingsNavigationStack { Form { Section { VStack(alignment: .leading, spacing: 8) { @@ -181,6 +181,7 @@ struct OpenAISettingsView: View { .foregroundColor(.red) } } + .nativeMacSettingsFormStyle() .scrollContentBackground(.hidden) .background(Color(.systemGroupedBackground)) .navigationTitle("OpenAI Settings") diff --git a/BisonNotes AI/BisonNotes AI/OpenAISummarizationSettingsView.swift b/BisonNotes AI/BisonNotes AI/OpenAISummarizationSettingsView.swift index e8752c9..38f5617 100644 --- a/BisonNotes AI/BisonNotes AI/OpenAISummarizationSettingsView.swift +++ b/BisonNotes AI/BisonNotes AI/OpenAISummarizationSettingsView.swift @@ -30,7 +30,7 @@ struct OpenAISummarizationSettingsView: View { } var body: some View { - NavigationStack { + PlatformSettingsNavigationStack { Form { authenticationSection apiConfigurationSection @@ -39,6 +39,7 @@ struct OpenAISummarizationSettingsView: View { responseLimitsSection connectionTestSection } + .nativeMacSettingsFormStyle() .scrollContentBackground(.hidden) .background(Color(.systemGroupedBackground)) .navigationTitle("OpenAI Settings") @@ -412,7 +413,7 @@ struct OpenAICompatibleSettingsView: View { } var body: some View { - NavigationStack { + PlatformSettingsNavigationStack { Form { compatibilityGuideSection authenticationSection @@ -423,6 +424,7 @@ struct OpenAICompatibleSettingsView: View { connectionTestSection featuresSection } + .nativeMacSettingsFormStyle() .scrollContentBackground(.hidden) .background(Color(.systemGroupedBackground)) .navigationTitle("OpenAI Compatible") diff --git a/BisonNotes AI/BisonNotes AI/PerformanceOptimizer.swift b/BisonNotes AI/BisonNotes AI/PerformanceOptimizer.swift index fcf6657..cd7a619 100644 --- a/BisonNotes AI/BisonNotes AI/PerformanceOptimizer.swift +++ b/BisonNotes AI/BisonNotes AI/PerformanceOptimizer.swift @@ -9,24 +9,19 @@ import Foundation import SwiftUI import os.log -extension UIDevice { - /// True when the app is running on a Mac (Mac Catalyst or "Designed for iPad" on Apple Silicon). - /// Battery APIs return unreliable values in both cases β€” `batteryLevel` reports ~0.01 - /// and `batteryState` spams "Error retrieving battery status" to the log. - static var isRunningOnMac: Bool { - #if targetEnvironment(macCatalyst) - return true - #else - return ProcessInfo.processInfo.isiOSAppOnMac - #endif - } -} - // MARK: - Battery Monitor +#if canImport(UIKit) +typealias PlatformBatteryState = UIDevice.BatteryState +#else +enum PlatformBatteryState { + case unknown, unplugged, charging, full +} +#endif + struct BatteryInfo { let level: Float - let state: UIDevice.BatteryState + let state: PlatformBatteryState let isLowPowerMode: Bool var isLowBattery: Bool { @@ -95,7 +90,11 @@ class PerformanceOptimizer: ObservableObject { @Published var isProcessing = false @Published var processingProgress: Double = 0.0 @Published var memoryUsage: MemoryUsage = MemoryUsage() - @Published var batteryInfo: BatteryInfo = BatteryInfo(level: 1.0, state: .unknown, isLowPowerMode: false) + @Published var batteryInfo: BatteryInfo = BatteryInfo( + level: 1.0, + state: PlatformDevice.isRunningOnMac ? .full : .unknown, + isLowPowerMode: false + ) @Published var performanceMetrics: PerformanceMetrics = PerformanceMetrics() @Published var optimizationLevel: OptimizationLevel = .balanced @@ -143,11 +142,18 @@ class PerformanceOptimizer: ObservableObject { // MARK: - Battery Monitoring private func startBatteryMonitoring() { - // No reliable battery API on Mac β€” leave default battery info (treated as full/charged) - // and skip the polling timer to avoid "Error retrieving battery status" logs. - if UIDevice.isRunningOnMac { return } + // No reliable cross-Mac battery API β€” report plugged in/full and + // respect Low Power Mode without starting an iOS battery polling timer. + if PlatformDevice.isRunningOnMac { + Task { @MainActor in + await updateBatteryInfo() + } + return + } + #if canImport(UIKit) UIDevice.current.isBatteryMonitoringEnabled = true + #endif batteryMonitorTimer = Timer.scheduledTimer(withTimeInterval: 30.0, repeats: true) { [weak self] _ in Task { @MainActor in @@ -162,11 +168,12 @@ class PerformanceOptimizer: ObservableObject { } private func updateBatteryInfo() async { - if UIDevice.isRunningOnMac { - // Battery state is not available on Mac; only respect Low Power Mode. + if PlatformDevice.isRunningOnMac { + // Battery state is not available consistently on Mac. Report the + // app as plugged in/full and only respect Low Power Mode. let batteryInfo = BatteryInfo( level: 1.0, - state: .unknown, + state: .full, isLowPowerMode: ProcessInfo.processInfo.isLowPowerModeEnabled ) self.batteryInfo = batteryInfo @@ -174,12 +181,20 @@ class PerformanceOptimizer: ObservableObject { return } + #if canImport(UIKit) let device = UIDevice.current let batteryInfo = BatteryInfo( level: device.batteryLevel, state: device.batteryState, isLowPowerMode: ProcessInfo.processInfo.isLowPowerModeEnabled ) + #else + let batteryInfo = BatteryInfo( + level: 1.0, + state: .unknown, + isLowPowerMode: ProcessInfo.processInfo.isLowPowerModeEnabled + ) + #endif self.batteryInfo = batteryInfo @@ -495,9 +510,11 @@ class PerformanceOptimizer: ObservableObject { batteryMonitorTimer = nil optimizationTimer = nil - if !UIDevice.isRunningOnMac { + #if canImport(UIKit) + if !PlatformDevice.isRunningOnMac { UIDevice.current.isBatteryMonitoringEnabled = false } + #endif } // MARK: - Chunked Processing diff --git a/BisonNotes AI/BisonNotes AI/Persistence.swift b/BisonNotes AI/BisonNotes AI/Persistence.swift index 4cb0b77..d648f1b 100644 --- a/BisonNotes AI/BisonNotes AI/Persistence.swift +++ b/BisonNotes AI/BisonNotes AI/Persistence.swift @@ -38,10 +38,13 @@ struct PersistenceController { persistentContainer.persistentStoreDescriptions.forEach { description in description.setOption(true as NSNumber, forKey: NSMigratePersistentStoresAutomaticallyOption) description.setOption(true as NSNumber, forKey: NSInferMappingModelAutomaticallyOption) + #if os(iOS) + // iOS Data Protection; macOS relies on FileVault for encryption at rest. description.setOption( AppFileProtection.sensitiveFileProtection.rawValue as NSString, forKey: NSPersistentStoreFileProtectionKey ) + #endif } persistentContainer.loadPersistentStores(completionHandler: { (storeDescription, error) in if let error = error as NSError? { diff --git a/BisonNotes AI/BisonNotes AI/Platform/AppCommandFocus.swift b/BisonNotes AI/BisonNotes AI/Platform/AppCommandFocus.swift new file mode 100644 index 0000000..a7cb9e7 --- /dev/null +++ b/BisonNotes AI/BisonNotes AI/Platform/AppCommandFocus.swift @@ -0,0 +1,23 @@ +// +// AppCommandFocus.swift +// BisonNotes AI +// + +import SwiftUI + +/// An action supplied by the currently focused summary scene so app-level +/// commands act on one window instead of broadcasting to every open summary. +struct SummaryExportAction { + let perform: () -> Void +} + +private struct SummaryExportActionKey: FocusedValueKey { + typealias Value = SummaryExportAction +} + +extension FocusedValues { + var summaryExportAction: SummaryExportAction? { + get { self[SummaryExportActionKey.self] } + set { self[SummaryExportActionKey.self] = newValue } + } +} diff --git a/BisonNotes AI/BisonNotes AI/Platform/MacInputDeviceMonitor.swift b/BisonNotes AI/BisonNotes AI/Platform/MacInputDeviceMonitor.swift new file mode 100644 index 0000000..6b80e8c --- /dev/null +++ b/BisonNotes AI/BisonNotes AI/Platform/MacInputDeviceMonitor.swift @@ -0,0 +1,99 @@ +#if os(macOS) + +import CoreAudio +import Foundation + +/// Owns the Core Audio property-listener blocks used to observe microphone +/// connections and system-default input changes. +final class MacInputDeviceMonitor { + private let onChange: () -> Void + private var defaultInputListener: AudioObjectPropertyListenerBlock? + private var deviceListListener: AudioObjectPropertyListenerBlock? + + init(onChange: @escaping () -> Void) { + self.onChange = onChange + } + + deinit { + stop() + } + + func start() { + stop() + addDefaultInputListener() + addDeviceListListener() + } + + func stop() { + let systemObject = AudioObjectID(kAudioObjectSystemObject) + if let defaultInputListener { + var address = Self.defaultInputAddress + AudioObjectRemovePropertyListenerBlock(systemObject, &address, .main, defaultInputListener) + self.defaultInputListener = nil + } + if let deviceListListener { + var address = Self.deviceListAddress + AudioObjectRemovePropertyListenerBlock(systemObject, &address, .main, deviceListListener) + self.deviceListListener = nil + } + } + + private func addDefaultInputListener() { + let listener: AudioObjectPropertyListenerBlock = { [weak self] _, _ in + self?.onChange() + } + var address = Self.defaultInputAddress + let status = AudioObjectAddPropertyListenerBlock( + AudioObjectID(kAudioObjectSystemObject), + &address, + .main, + listener + ) + if status == noErr { + defaultInputListener = listener + } else { + logListenerError("default Mac input", status: status) + } + } + + private func addDeviceListListener() { + let listener: AudioObjectPropertyListenerBlock = { [weak self] _, _ in + self?.onChange() + } + var address = Self.deviceListAddress + let status = AudioObjectAddPropertyListenerBlock( + AudioObjectID(kAudioObjectSystemObject), + &address, + .main, + listener + ) + if status == noErr { + deviceListListener = listener + } else { + logListenerError("Mac audio devices", status: status) + } + } + + private func logListenerError(_ subject: String, status: OSStatus) { + let message = NSError(domain: NSOSStatusErrorDomain, code: Int(status)).localizedDescription + AppLog.shared.audioSession("Could not monitor the \(subject): \(message)", level: .error) + } + + private static var defaultInputAddress: AudioObjectPropertyAddress { + AudioObjectPropertyAddress( + mSelector: kAudioHardwarePropertyDefaultInputDevice, + mScope: kAudioObjectPropertyScopeGlobal, + mElement: kAudioObjectPropertyElementMain + ) + } + + private static var deviceListAddress: AudioObjectPropertyAddress { + AudioObjectPropertyAddress( + mSelector: kAudioHardwarePropertyDevices, + mScope: kAudioObjectPropertyScopeGlobal, + mElement: kAudioObjectPropertyElementMain + ) + } +} + +#endif diff --git a/BisonNotes AI/BisonNotes AI/Platform/NativeWindowRouting.swift b/BisonNotes AI/BisonNotes AI/Platform/NativeWindowRouting.swift new file mode 100644 index 0000000..458b53a --- /dev/null +++ b/BisonNotes AI/BisonNotes AI/Platform/NativeWindowRouting.swift @@ -0,0 +1,222 @@ +// +// NativeWindowRouting.swift +// BisonNotes AI +// + +import SwiftUI + +enum NativeWindowID { + static let summary = "summary-detail" + static let transcript = "transcript-detail" + static let recording = "recording-detail" + static let recordings = "recordings-library" + static let location = "location-detail" + static let backgroundProcessing = "background-processing" + static let processingJob = "processing-job-detail" +} + +/// Settings destinations own their navigation stack on iOS. On native macOS, +/// the Settings scene owns one stack for the entire hierarchy so child panels +/// push in place instead of creating nested navigation containers. +struct PlatformSettingsNavigationStack: View { + private let content: Content + + init(@ViewBuilder content: () -> Content) { + self.content = content() + } + + var body: some View { + #if os(macOS) + content + #else + NavigationStack { content } + #endif + } +} + +extension View { + /// Gives true modal tasks a bounded Mac viewport. The modal's own List, + /// Form, ScrollView, Map, or PDF view remains responsible for scrolling. + @ViewBuilder + func nativeMacModalSizing(width: CGFloat = 700, height: CGFloat = 620) -> some View { + #if os(macOS) + frame(width: width, height: height) + .presentationSizing(.fitted) + #else + self + #endif + } + + /// Preserve the iPhone/iPad navigation shell while allowing settings + /// destinations to participate in the single NavigationStack owned by the + /// native macOS Settings window. + @ViewBuilder + func platformSettingsNavigation() -> some View { + #if os(macOS) + self + #else + NavigationStack { self } + #endif + } + + /// The default macOS Form style uses a two-column preference-grid layout. + /// That works for short label/control pairs, but badly distorts the rich, + /// multi-line provider panels used throughout BisonNotes. Grouped form + /// styling restores a readable full-width hierarchy and native scrolling. + @ViewBuilder + func nativeMacSettingsFormStyle() -> some View { + #if os(macOS) + formStyle(.grouped) + .scrollContentBackground(.hidden) + .background(Color(.systemGroupedBackground)) + #else + self + #endif + } + + /// Navigation-style sheets can lose SwiftUI navigation toolbar items when + /// nested inside another native macOS sheet. Give those destinations a + /// content-level Done button and bind Escape to the same dismissal action. + @ViewBuilder + func nativeMacModalDismissControl(_ title: String = "Done") -> some View { + #if os(macOS) + modifier(NativeMacModalDismissModifier(title: title)) + #else + self + #endif + } + + /// Full-screen covers are appropriate on iPhone but produce trapped, + /// non-window-like experiences on macOS. Keep them as bounded sheets there. + @ViewBuilder + func platformFullScreenCover( + isPresented: Binding, + @ViewBuilder content: @escaping () -> Content + ) -> some View { + #if os(macOS) + sheet(isPresented: isPresented) { + content().nativeMacModalSizing(width: 760, height: 700) + } + #else + fullScreenCover(isPresented: isPresented, content: content) + #endif + } +} + +#if os(macOS) +private struct NativeMacModalDismissModifier: ViewModifier { + @Environment(\.dismiss) private var dismiss + + let title: String + + func body(content: Content) -> some View { + content + .overlay(alignment: .topTrailing) { + Button(title) { + dismiss() + } + .buttonStyle(.bordered) + .keyboardShortcut(.cancelAction) + .padding(.top, 18) + .padding(.trailing, 20) + .accessibilityIdentifier("nativeMacModalDismissButton") + } + } +} + +struct NativeTranscriptWindowView: View { + let recordingID: UUID + + @EnvironmentObject private var recorderVM: AudioRecorderViewModel + @EnvironmentObject private var appCoordinator: AppDataCoordinator + + var body: some View { + Group { + if let recording = appCoordinator.getRecording(id: recordingID) { + if let transcript = appCoordinator.getTranscriptData(for: recordingID) { + EditableTranscriptView( + recording: recording, + transcript: transcript, + transcriptManager: TranscriptManager.shared + ) + } else { + TranscriptDetailView(recording: recording, transcriptText: "") + } + } else { + missingContent("Transcript Not Available", systemImage: "text.bubble") + } + } + .environmentObject(appCoordinator) + .environmentObject(recorderVM) + .frame(minWidth: 680, minHeight: 520) + } +} + +struct NativeRecordingWindowView: View { + let recordingID: UUID + + @EnvironmentObject private var recorderVM: AudioRecorderViewModel + @EnvironmentObject private var appCoordinator: AppDataCoordinator + + var body: some View { + Group { + if let recording = resolvedRecording { + AudioPlayerView(recording: recording) + .environmentObject(recorderVM) + .environmentObject(appCoordinator) + } else { + missingContent("Recording Not Available", systemImage: "waveform") + } + } + .frame(minWidth: 620, minHeight: 520) + } + + private var resolvedRecording: RecordingFile? { + guard let entry = appCoordinator.getRecording(id: recordingID) else { return nil } + let isArchived = entry.isArchived + let url = appCoordinator.getAbsoluteURL(for: entry) + ?? (isArchived ? appCoordinator.getStoredURL(for: entry) : nil) + guard let url else { return nil } + + return RecordingFile( + url: url, + name: entry.recordingName ?? url.deletingPathExtension().lastPathComponent, + date: entry.recordingDate ?? entry.createdAt ?? Date(), + duration: entry.duration, + locationData: appCoordinator.loadLocationData(for: entry), + isArchived: isArchived, + archivedAt: entry.archivedAt, + archiveNote: entry.archiveNote, + recordingId: entry.id, + storedFileSize: entry.fileSize, + isCloudSyncDisabled: entry.isCloudSyncDisabled + ) + } +} + +struct NativeProcessingJobWindowView: View { + let jobID: UUID + + @ObservedObject private var processingManager = BackgroundProcessingManager.shared + + var body: some View { + Group { + if let job = processingManager.activeJobs.first(where: { $0.id == jobID }) { + JobDetailView(job: job) + } else { + missingContent("Job Not Available", systemImage: "gearshape.2") + } + } + .frame(minWidth: 560, minHeight: 440) + } +} + +@ViewBuilder +private func missingContent(_ title: String, systemImage: String) -> some View { + ContentUnavailableView( + title, + systemImage: systemImage, + description: Text("The item may have been deleted or moved.") + ) +} +#endif diff --git a/BisonNotes AI/BisonNotes AI/Platform/PlatformApp.swift b/BisonNotes AI/BisonNotes AI/Platform/PlatformApp.swift new file mode 100644 index 0000000..d048936 --- /dev/null +++ b/BisonNotes AI/BisonNotes AI/Platform/PlatformApp.swift @@ -0,0 +1,331 @@ +// +// PlatformApp.swift +// BisonNotes AI +// +// Cross-platform facade over the UIApplication capabilities the app uses. +// iOS/Catalyst are UIKit-backed today; native macOS implementations arrive in +// Phase 2 of docs/macos-migration-plan.md (NSWorkspace, ProcessInfo activities, +// NSApplication lifecycle notifications). +// +// Views should prefer @Environment(\.openURL) over PlatformApp.open. +// + +import Foundation +#if canImport(UIKit) +import UIKit +#else +import AppKit +#endif + +// MARK: - App-level services + +enum PlatformApp { + /// Open a URL in the default browser/handler. For use from managers; + /// views should use @Environment(\.openURL). + static func open(_ url: URL) { + #if canImport(UIKit) + UIApplication.shared.open(url) + #else + NSWorkspace.shared.open(url) + #endif + } + + static func canOpen(_ url: URL) -> Bool { + #if canImport(UIKit) + return UIApplication.shared.canOpenURL(url) + #else + return true + #endif + } + + static var isActive: Bool { + #if canImport(UIKit) + return UIApplication.shared.applicationState == .active + #else + return true + #endif + } + + static var isInBackground: Bool { + #if canImport(UIKit) + return UIApplication.shared.applicationState == .background + #else + return false + #endif + } + + static var isProtectedDataAvailable: Bool { + #if canImport(UIKit) + return UIApplication.shared.isProtectedDataAvailable + #else + return true + #endif + } +} + +// MARK: - Pasteboard + +enum PlatformPasteboard { + /// The general pasteboard's plain-text contents. + static var string: String? { + get { + #if canImport(UIKit) + return UIPasteboard.general.string + #else + return NSPasteboard.general.string(forType: .string) + #endif + } + set { + #if canImport(UIKit) + UIPasteboard.general.string = newValue + #else + NSPasteboard.general.clearContents() + if let newValue { + NSPasteboard.general.setString(newValue, forType: .string) + } + #endif + } + } +} + +// MARK: - Alerts + +/// Imperatively presents a simple alert from non-SwiftUI contexts (error paths +/// in async tasks). On iOS it presents a UIAlertController from the key window's +/// root controller; on macOS it runs an NSAlert modally. +enum PlatformAlert { + struct Action { + let title: String + let isCancel: Bool + let handler: (() -> Void)? + + init(title: String, isCancel: Bool = false, handler: (() -> Void)? = nil) { + self.title = title + self.isCancel = isCancel + self.handler = handler + } + } + + @MainActor + static func present(title: String, message: String, actions: [Action] = [Action(title: "OK")]) { + #if canImport(UIKit) + let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) + for action in actions { + alert.addAction(UIAlertAction( + title: action.title, + style: action.isCancel ? .cancel : .default + ) { _ in action.handler?() }) + } + if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, + let rootViewController = windowScene.windows.first?.rootViewController { + rootViewController.present(alert, animated: true) + } + #else + let alert = NSAlert() + alert.messageText = title + alert.informativeText = message + for action in actions { + alert.addButton(withTitle: action.title) + } + let response = alert.runModal() + let index = response.rawValue - NSApplication.ModalResponse.alertFirstButtonReturn.rawValue + if index >= 0, index < actions.count { + actions[index].handler?() + } + #endif + } +} + +#if os(macOS) +// MARK: - Native Mac sharing + +/// Owns the AppKit sharing picker for manager-driven and SwiftUI export flows. +/// Retaining the picker here keeps its delegate alive until a service is chosen +/// or the popover is dismissed. AppKit delivers the legacy delegate callback on +/// the main thread, but the protocol lacks actor annotations, so the conformance +/// is explicitly imported with pre-concurrency isolation semantics. +@MainActor +final class PlatformSharingPresenter: NSObject, @preconcurrency NSSharingServicePickerDelegate { + static let shared = PlatformSharingPresenter() + + private var picker: NSSharingServicePicker? + private var subject: String? + private var onDismiss: (() -> Void)? + + @discardableResult + func present( + items: [Any], + subject: String? = nil, + onPresented: () -> Void = {}, + onDismiss: @escaping () -> Void = {} + ) -> Bool { + guard picker == nil, !items.isEmpty, let anchorView = Self.anchorView else { + return false + } + + self.subject = subject + self.onDismiss = onDismiss + let picker = NSSharingServicePicker(items: items) + picker.delegate = self + self.picker = picker + + let anchorRect = NSRect( + x: anchorView.bounds.midX, + y: anchorView.bounds.midY, + width: 1, + height: 1 + ) + picker.show(relativeTo: anchorRect, of: anchorView, preferredEdge: .minY) + onPresented() + return true + } + + func sharingServicePicker( + _ sharingServicePicker: NSSharingServicePicker, + didChoose service: NSSharingService? + ) { + service?.subject = subject + picker = nil + subject = nil + let completion = onDismiss + onDismiss = nil + completion?() + } + + private static var anchorView: NSView? { + NSApp.keyWindow?.contentView + ?? NSApp.mainWindow?.contentView + ?? NSApp.windows.first(where: { $0.isVisible })?.contentView + } +} +#endif + +// MARK: - Device + +enum PlatformDevice { + /// True on any Mac: native macOS, Mac Catalyst, or iOS-app-on-Mac. + /// Battery APIs are unreliable/absent in all three cases. + static var isRunningOnMac: Bool { + #if os(macOS) || targetEnvironment(macCatalyst) + return true + #else + return ProcessInfo.processInfo.isiOSAppOnMac + #endif + } + + /// A stable per-install identifier. On iOS this is identifierForVendor; + /// on macOS (no such API) we persist a generated UUID in UserDefaults. + static var vendorIdentifier: String { + #if canImport(UIKit) + return UIDevice.current.identifierForVendor?.uuidString ?? UUID().uuidString + #else + let key = "PlatformDeviceVendorIdentifier" + if let existing = UserDefaults.standard.string(forKey: key) { + return existing + } + let generated = UUID().uuidString + UserDefaults.standard.set(generated, forKey: key) + return generated + #endif + } +} + +// MARK: - Lifecycle notifications + +/// Platform-neutral names for app lifecycle notifications. +/// Phase 2 maps these to NSApplication.* on native macOS. +enum PlatformLifecycle { + #if canImport(UIKit) + static let didFinishLaunchingNotification = UIApplication.didFinishLaunchingNotification + static let didBecomeActiveNotification = UIApplication.didBecomeActiveNotification + static let willResignActiveNotification = UIApplication.willResignActiveNotification + static let didEnterBackgroundNotification = UIApplication.didEnterBackgroundNotification + static let willEnterForegroundNotification = UIApplication.willEnterForegroundNotification + static let willTerminateNotification = UIApplication.willTerminateNotification + static let didReceiveMemoryWarningNotification = UIApplication.didReceiveMemoryWarningNotification + #else + static let didFinishLaunchingNotification = NSApplication.didFinishLaunchingNotification + static let didBecomeActiveNotification = NSApplication.didBecomeActiveNotification + static let willResignActiveNotification = NSApplication.willResignActiveNotification + // macOS apps are not backgrounded; hide/unhide is the closest user-visible analog. + static let didEnterBackgroundNotification = NSApplication.didHideNotification + static let willEnterForegroundNotification = NSApplication.willUnhideNotification + static let willTerminateNotification = NSApplication.willTerminateNotification + // No macOS analog β€” never posted; observers simply stay idle. + static let didReceiveMemoryWarningNotification = Notification.Name("BisonNotesPlatformMemoryWarning") + #endif +} + +// MARK: - Background task assertions + +/// A platform assertion for user-initiated work that must continue when the app +/// is not frontmost. iOS uses a finite UIKit background task. Mac uses a +/// ProcessInfo activity to prevent App Nap while still allowing idle system sleep. +enum PlatformBackgroundTask { + #if canImport(UIKit) && !targetEnvironment(macCatalyst) + typealias ID = UIBackgroundTaskIdentifier + static let invalidID: ID = .invalid + + static func begin(name: String, expirationHandler: (() -> Void)? = nil) -> ID { + UIApplication.shared.beginBackgroundTask(withName: name, expirationHandler: expirationHandler) + } + + static func end(_ id: ID) { + UIApplication.shared.endBackgroundTask(id) + } + + static var remainingTime: TimeInterval { + UIApplication.shared.backgroundTimeRemaining + } + #else + // Mac apps do not receive iOS expiration time. A ProcessInfo activity keeps + // transcription and summarization responsive when the app is hidden. + struct ID: Equatable { + let rawValue: Int + static let invalid = ID(rawValue: 0) + } + static let invalidID: ID = .invalid + private static let activityRegistry = ActivityRegistry() + + static func begin(name: String, expirationHandler: (() -> Void)? = nil) -> ID { + ID(rawValue: activityRegistry.begin(name: name)) + } + + static func end(_ id: ID) { + guard id != .invalid else { return } + activityRegistry.end(id: id.rawValue) + } + + static var remainingTime: TimeInterval { + .greatestFiniteMagnitude + } + + private final class ActivityRegistry: @unchecked Sendable { + private let lock = NSLock() + private var nextID = 1 + private var activities: [Int: any NSObjectProtocol] = [:] + + func begin(name: String) -> Int { + let activity = ProcessInfo.processInfo.beginActivity( + options: .userInitiatedAllowingIdleSystemSleep, + reason: name + ) + lock.lock() + defer { lock.unlock() } + let id = nextID + nextID += 1 + activities[id] = activity + return id + } + + func end(id: Int) { + lock.lock() + let activity = activities.removeValue(forKey: id) + lock.unlock() + if let activity { + ProcessInfo.processInfo.endActivity(activity) + } + } + } + #endif +} diff --git a/BisonNotes AI/BisonNotes AI/Platform/PlatformColors.swift b/BisonNotes AI/BisonNotes AI/Platform/PlatformColors.swift new file mode 100644 index 0000000..5c3146d --- /dev/null +++ b/BisonNotes AI/BisonNotes AI/Platform/PlatformColors.swift @@ -0,0 +1,46 @@ +// +// PlatformColors.swift +// BisonNotes AI +// +// UIKit system-color names mapped to AppKit dynamic colors so shared SwiftUI +// code can keep writing Color(.systemGroupedBackground) etc. on native macOS. +// The systemGray4-6 values are the UIKit light-mode constants with dark-mode +// variants supplied via dynamic providers. +// + +#if os(macOS) +import SwiftUI +import AppKit + +extension NSColor { + static var systemBackground: NSColor { .windowBackgroundColor } + static var systemGroupedBackground: NSColor { .windowBackgroundColor } + static var secondarySystemGroupedBackground: NSColor { .controlBackgroundColor } + static var tertiarySystemGroupedBackground: NSColor { .underPageBackgroundColor } + static var separator: NSColor { .separatorColor } + + static var systemGray4: NSColor { dynamicGray(light: 0xD1D1D6, dark: 0x3A3A3C) } + static var systemGray5: NSColor { dynamicGray(light: 0xE5E5EA, dark: 0x2C2C2E) } + static var systemGray6: NSColor { dynamicGray(light: 0xF2F2F7, dark: 0x1C1C1E) } + + private static func dynamicGray(light: Int, dark: Int) -> NSColor { + NSColor(name: nil) { appearance in + let rgb = appearance.bestMatch(from: [.darkAqua, .aqua]) == .darkAqua ? dark : light + return NSColor( + srgbRed: CGFloat((rgb >> 16) & 0xFF) / 255.0, + green: CGFloat((rgb >> 8) & 0xFF) / 255.0, + blue: CGFloat(rgb & 0xFF) / 255.0, + alpha: 1.0 + ) + } + } +} + +extension Color { + /// Mirrors UIKit's unlabeled Color(_: UIColor) initializer so shared code + /// using implicit-member color names compiles against NSColor on macOS. + init(_ nsColor: NSColor) { + self.init(nsColor: nsColor) + } +} +#endif diff --git a/BisonNotes AI/BisonNotes AI/Platform/PlatformViewShims.swift b/BisonNotes AI/BisonNotes AI/Platform/PlatformViewShims.swift new file mode 100644 index 0000000..83ba5e6 --- /dev/null +++ b/BisonNotes AI/BisonNotes AI/Platform/PlatformViewShims.swift @@ -0,0 +1,79 @@ +// +// PlatformViewShims.swift +// BisonNotes AI +// +// No-op / remapped implementations of iOS-only SwiftUI API so shared views +// compile unchanged on native macOS. Toolbar placements map to their closest +// macOS equivalents; keyboard- and navigation-bar-specific modifiers are +// meaningless on macOS and become no-ops. +// + +#if os(macOS) +import SwiftUI + +extension ToolbarItemPlacement { + static var navigationBarLeading: ToolbarItemPlacement { .navigation } + static var navigationBarTrailing: ToolbarItemPlacement { .primaryAction } + static var topBarLeading: ToolbarItemPlacement { .navigation } + static var topBarTrailing: ToolbarItemPlacement { .primaryAction } +} + +/// Stand-in for PageTabViewStyle.IndexDisplayMode (iOS-only). macOS has no +/// paged TabView, so `.page(...)` maps to the default style. +struct PlatformPageIndexDisplayMode { + static let automatic = PlatformPageIndexDisplayMode() + static let always = PlatformPageIndexDisplayMode() + static let never = PlatformPageIndexDisplayMode() +} + +extension TabViewStyle where Self == DefaultTabViewStyle { + static func page(indexDisplayMode: PlatformPageIndexDisplayMode = .automatic) -> DefaultTabViewStyle { + .automatic + } +} + +/// WheelDatePickerStyle is iOS-only; map `.wheel` to the macOS default field style. +extension DatePickerStyle where Self == DefaultDatePickerStyle { + static var wheel: DefaultDatePickerStyle { DefaultDatePickerStyle() } +} + +enum PlatformTitleDisplayMode { + case automatic, inline, large +} + +enum PlatformAutocapitalizationType { + case none, words, sentences, allCharacters +} + +enum PlatformKeyboardType { + // swiftlint:disable:next identifier_name + case `default`, URL, numberPad, decimalPad, emailAddress, asciiCapable, numbersAndPunctuation +} + +enum PlatformTextInputAutocapitalization { + case never, words, sentences, characters +} + +extension PickerStyle where Self == MenuPickerStyle { + /// iOS-only picker styles map to a menu picker on macOS. + static var navigationLink: MenuPickerStyle { MenuPickerStyle() } + static var wheel: MenuPickerStyle { MenuPickerStyle() } +} + +extension View { + /// macOS has no full-screen covers; present as a regular sheet. + func fullScreenCover( + isPresented: Binding, + onDismiss: (() -> Void)? = nil, + @ViewBuilder content: @escaping () -> Content + ) -> some View { + sheet(isPresented: isPresented, onDismiss: onDismiss, content: content) + } + + func navigationBarTitleDisplayMode(_ mode: PlatformTitleDisplayMode) -> some View { self } + func autocapitalization(_ type: PlatformAutocapitalizationType) -> some View { self } + func keyboardType(_ type: PlatformKeyboardType) -> some View { self } + func navigationBarHidden(_ hidden: Bool) -> some View { self } + func textInputAutocapitalization(_ autocapitalization: PlatformTextInputAutocapitalization?) -> some View { self } +} +#endif diff --git a/BisonNotes AI/BisonNotes AI/Services/MacSummaryExportRenderer.swift b/BisonNotes AI/BisonNotes AI/Services/MacSummaryExportRenderer.swift new file mode 100644 index 0000000..b214acd --- /dev/null +++ b/BisonNotes AI/BisonNotes AI/Services/MacSummaryExportRenderer.swift @@ -0,0 +1,400 @@ +#if os(macOS) +import AppKit +import CoreText +import Foundation +enum MacSummaryExportRenderer { + enum RenderError: LocalizedError { + case invalidDocument + case documentTooLarge + case pdfContextUnavailable + var errorDescription: String? { + switch self { + case .invalidDocument: + return "The summary did not contain enough information to export." + case .documentTooLarge: + return "The summary is too large to export safely." + case .pdfContextUnavailable: + return "The Mac PDF renderer could not create an output document." + } + } + } + private static let pageRect = CGRect(x: 0, y: 0, width: 612, height: 792) + private static let textRect = CGRect(x: 50, y: 52, width: 512, height: 688) + static func rtfData( + summaryData: EnhancedSummaryData, + locationData: LocationData?, + locationAddress: String? + ) throws -> Data { + let document = try attributedDocument( + summaryData: summaryData, + locationData: locationData, + locationAddress: locationAddress + ) + let data = try document.data( + from: NSRange(location: 0, length: document.length), + documentAttributes: [.documentType: NSAttributedString.DocumentType.rtf] + ) + guard !data.isEmpty else { throw RenderError.invalidDocument } + return data + } + static func pdfData( + summaryData: EnhancedSummaryData, + locationData: LocationData?, + locationAddress: String? + ) throws -> Data { + let document = try attributedDocument( + summaryData: summaryData, + locationData: locationData, + locationAddress: locationAddress + ) + let output = NSMutableData() + guard let consumer = CGDataConsumer(data: output as CFMutableData) else { + throw RenderError.pdfContextUnavailable + } + var mediaBox = pageRect + guard let context = CGContext(consumer: consumer, mediaBox: &mediaBox, nil) else { + throw RenderError.pdfContextUnavailable + } + let framesetter = CTFramesetterCreateWithAttributedString(document as CFAttributedString) + var location = 0 + var pageNumber = 1 + while location < document.length { + context.beginPDFPage(nil) + drawHeader(in: context, generatedAt: summaryData.generatedAt) + drawFooter(in: context, pageNumber: pageNumber) + let path = CGPath(rect: textRect, transform: nil) + let frame = CTFramesetterCreateFrame( + framesetter, + CFRange(location: location, length: 0), + path, + nil + ) + let visibleRange = CTFrameGetVisibleStringRange(frame) + guard visibleRange.length > 0 else { + context.endPDFPage() + context.closePDF() + throw RenderError.invalidDocument + } + CTFrameDraw(frame, context) + context.endPDFPage() + location += visibleRange.length + pageNumber += 1 + } + context.closePDF() + guard output.length > 0 else { throw RenderError.invalidDocument } + return output as Data + } + + private static func attributedDocument( + summaryData: EnhancedSummaryData, + locationData: LocationData?, + locationAddress: String? + ) throws -> NSAttributedString { + let recordingName = summaryData.recordingName.trimmingCharacters(in: .whitespacesAndNewlines) + guard !recordingName.isEmpty else { throw RenderError.invalidDocument } + + let document = NSMutableAttributedString() + appendTitle(recordingName, to: document) + appendMetadata(summaryData, to: document) + appendLocation(locationData, address: locationAddress, to: document) + appendSection("Summary", body: cleanedMarkdown(summaryData.summary), to: document) + + if let notes = summaryData.userNotes?.trimmingCharacters(in: .whitespacesAndNewlines), !notes.isEmpty { + appendSection("User Notes", body: cleanedMarkdown(notes), to: document) + } + appendTasks(summaryData.tasks, to: document) + appendReminders(summaryData.reminders, to: document) + appendTitles(summaryData.titles, to: document) + appendProcessingDetails(summaryData, to: document) + appendFooter(summaryData.generatedAt, to: document) + + guard document.length > 0 else { throw RenderError.invalidDocument } + guard document.length * 100 <= 10_000_000 else { throw RenderError.documentTooLarge } + return document + } +} + +private extension MacSummaryExportRenderer { + private static func appendTitle(_ title: String, to document: NSMutableAttributedString) { + let style = paragraph(alignment: .center, spacing: 14) + append( + title + "\n", + font: .boldSystemFont(ofSize: 26), + color: .black, + paragraphStyle: style, + to: document + ) + } + + private static func appendMetadata(_ summary: EnhancedSummaryData, to document: NSMutableAttributedString) { + let formatter = DateFormatter() + formatter.dateStyle = .full + formatter.timeStyle = .short + let lines = [ + "Recording Date: \(formatter.string(from: summary.recordingDate))", + "AI Provider: \(summary.aiEngine)", + "AI Model: \(summary.aiModel)", + "Content Type: \(summary.contentType.rawValue)", + "Generated: " + DateFormatter.localizedString( + from: summary.generatedAt, + dateStyle: .medium, + timeStyle: .short + ) + ] + append( + lines.joined(separator: "\n") + "\n\n", + font: .systemFont(ofSize: 11), + color: .darkGray, + paragraphStyle: paragraph(spacing: 3), + to: document + ) + } + + private static func appendLocation( + _ location: LocationData?, + address: String?, + to document: NSMutableAttributedString + ) { + guard let location else { return } + appendSectionHeading("Location", to: document) + + var lines: [String] = [] + if let address = address ?? location.address, + !address.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { + lines.append(address) + } + lines.append(String(format: "Coordinates: %.5f, %.5f", location.latitude, location.longitude)) + if let accuracy = location.accuracy { + lines.append(String(format: "Accuracy: Β±%.0f meters", accuracy)) + } + append( + lines.joined(separator: "\n") + "\n\n", + font: .systemFont(ofSize: 11), + color: .black, + paragraphStyle: paragraph(spacing: 3), + to: document + ) + } + + private static func appendSection( + _ title: String, + body: String, + to document: NSMutableAttributedString + ) { + guard !body.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else { return } + appendSectionHeading(title, to: document) + append( + body + "\n\n", + font: .systemFont(ofSize: 12), + color: .black, + paragraphStyle: paragraph(spacing: 4, lineSpacing: 2), + to: document + ) + } + + private static func appendTasks(_ tasks: [TaskItem], to document: NSMutableAttributedString) { + guard !tasks.isEmpty else { return } + appendSectionHeading("Tasks (\(tasks.count))", to: document) + for task in tasks { + append( + "β€’ [\(task.priority.rawValue)] \(task.displayText)\n", + font: .systemFont(ofSize: 11), + color: color(for: task.priority), + paragraphStyle: listParagraph(), + to: document + ) + } + document.append(NSAttributedString(string: "\n")) + } + + private static func appendReminders(_ reminders: [ReminderItem], to document: NSMutableAttributedString) { + guard !reminders.isEmpty else { return } + appendSectionHeading("Reminders (\(reminders.count))", to: document) + for reminder in reminders { + append( + "β€’ [\(reminder.urgency.rawValue)] \(reminder.displayText)\n", + font: .systemFont(ofSize: 11), + color: color(for: reminder.urgency), + paragraphStyle: listParagraph(), + to: document + ) + } + document.append(NSAttributedString(string: "\n")) + } + + private static func appendTitles(_ titles: [TitleItem], to document: NSMutableAttributedString) { + guard !titles.isEmpty else { return } + appendSectionHeading("Suggested Titles", to: document) + let body = titles.enumerated().map { "\($0.offset + 1). \($0.element.text)" }.joined(separator: "\n") + append( + body + "\n\n", + font: .systemFont(ofSize: 11), + color: .black, + paragraphStyle: paragraph(spacing: 3), + to: document + ) + } + + private static func appendProcessingDetails( + _ summary: EnhancedSummaryData, + to document: NSMutableAttributedString + ) { + appendSectionHeading("Processing Details", to: document) + let lines = [ + "Word Count: \(summary.wordCount) words", + "Original Length: \(summary.originalLength) characters", + "Compression Ratio: \(summary.formattedCompressionRatio)", + "Processing Time: \(summary.formattedProcessingTime)" + ] + append( + lines.joined(separator: "\n") + "\n\n", + font: .systemFont(ofSize: 10), + color: .darkGray, + paragraphStyle: paragraph(spacing: 3), + to: document + ) + } + + private static func appendFooter(_ date: Date, to document: NSMutableAttributedString) { + let formatter = DateFormatter() + formatter.dateStyle = .medium + formatter.timeStyle = .short + append( + "Summary export Β· BisonNotes AI\nExported \(formatter.string(from: date))\n", + font: .systemFont(ofSize: 9), + color: .darkGray, + paragraphStyle: paragraph(alignment: .center, spacing: 3), + to: document + ) + } + + private static func appendSectionHeading(_ title: String, to document: NSMutableAttributedString) { + append( + title + "\n", + font: .boldSystemFont(ofSize: 16), + color: .black, + paragraphStyle: paragraph(spacing: 7), + to: document + ) + append( + "β€” β€” β€”\n", + font: .systemFont(ofSize: 9), + color: .darkGray, + paragraphStyle: paragraph(spacing: 5), + to: document + ) + } + + private static func append( + _ text: String, + font: NSFont, + color: NSColor, + paragraphStyle: NSParagraphStyle, + to document: NSMutableAttributedString + ) { + document.append(NSAttributedString( + string: text, + attributes: [ + .font: font, + .foregroundColor: color, + .paragraphStyle: paragraphStyle + ] + )) + } + + private static func paragraph( + alignment: NSTextAlignment = .left, + spacing: CGFloat, + lineSpacing: CGFloat = 0 + ) -> NSParagraphStyle { + let style = NSMutableParagraphStyle() + style.alignment = alignment + style.paragraphSpacing = spacing + style.lineSpacing = lineSpacing + return style + } + + private static func listParagraph() -> NSParagraphStyle { + let style = NSMutableParagraphStyle() + style.firstLineHeadIndent = 0 + style.headIndent = 16 + style.paragraphSpacing = 3 + return style + } + + private static func cleanedMarkdown(_ source: String) -> String { + var text = source + .replacingOccurrences(of: "\\n", with: "\n") + .replacingOccurrences(of: "\\r", with: "\n") + let replacements: [(String, String)] = [ + (#"(?m)^#{1,6}\s+"#, ""), + (#"\[([^\]]+)\]\(([^)]+)\)"#, "$1 ($2)"), + (#"(?m)^[-*+]\s+"#, "β€’ "), + (#"\*\*|__|`"#, "") + ] + for (pattern, replacement) in replacements { + text = text.replacingOccurrences( + of: pattern, + with: replacement, + options: .regularExpression + ) + } + return text.trimmingCharacters(in: .whitespacesAndNewlines) + } + + private static func color(for priority: TaskItem.Priority) -> NSColor { + switch priority { + case .high: return .systemRed + case .medium: return .systemOrange + case .low: return .systemGreen + } + } + + private static func color(for urgency: ReminderItem.Urgency) -> NSColor { + switch urgency { + case .immediate: return .systemRed + case .today: return .systemOrange + case .thisWeek: return .systemBlue + case .later: return .systemGreen + } + } + + private static func drawHeader(in context: CGContext, generatedAt: Date) { + let formatter = DateFormatter() + formatter.dateStyle = .medium + formatter.timeStyle = .short + drawLine( + "BisonNotes AI Β· Summary Export Β· \(formatter.string(from: generatedAt))", + at: CGPoint(x: 50, y: 760), + font: .systemFont(ofSize: 8), + color: .darkGray, + in: context + ) + } + + private static func drawFooter(in context: CGContext, pageNumber: Int) { + drawLine( + "β€” \(pageNumber) β€”", + at: CGPoint(x: 287, y: 28), + font: .systemFont(ofSize: 8), + color: .darkGray, + in: context + ) + } + + private static func drawLine( + _ text: String, + at point: CGPoint, + font: NSFont, + color: NSColor, + in context: CGContext + ) { + let line = CTLineCreateWithAttributedString(NSAttributedString( + string: text, + attributes: [.font: font, .foregroundColor: color] + )) + context.textPosition = point + CTLineDraw(line, context) + } +} +#endif diff --git a/BisonNotes AI/BisonNotes AI/Services/MapSnapshotStorage.swift b/BisonNotes AI/BisonNotes AI/Services/MapSnapshotStorage.swift index 7ef1e81..4605c2c 100644 --- a/BisonNotes AI/BisonNotes AI/Services/MapSnapshotStorage.swift +++ b/BisonNotes AI/BisonNotes AI/Services/MapSnapshotStorage.swift @@ -6,7 +6,9 @@ // import Foundation +#if canImport(UIKit) import UIKit +#endif enum MapSnapshotStorage { private static let directoryName = "SummaryLocationSnapshots" @@ -70,6 +72,7 @@ enum MapSnapshotStorage { } } + #if canImport(UIKit) /// Load a UIImage for a map snapshot /// - Parameters: /// - summaryId: The unique ID of the summary @@ -83,6 +86,7 @@ enum MapSnapshotStorage { return UIImage(data: data, scale: scale) } + #endif /// Save image data to storage /// - Parameters: diff --git a/BisonNotes AI/BisonNotes AI/Services/PDFExportService.swift b/BisonNotes AI/BisonNotes AI/Services/PDFExportService.swift index 640ba95..6b8e658 100644 --- a/BisonNotes AI/BisonNotes AI/Services/PDFExportService.swift +++ b/BisonNotes AI/BisonNotes AI/Services/PDFExportService.swift @@ -6,12 +6,15 @@ // import Foundation +#if canImport(UIKit) import UIKit +#endif import PDFKit import MapKit import CoreLocation import CoreText +#if canImport(UIKit) class PDFExportService { static let shared = PDFExportService() @@ -980,3 +983,24 @@ class PDFExportService { } } } +#else +class PDFExportService { + static let shared = PDFExportService() + + @MainActor + func generatePDF( + summaryData: EnhancedSummaryData, + locationData: LocationData?, + locationAddress: String? + ) async throws -> Data { + AppLog.shared.fileManagement("PDFExportService: Starting native Mac PDF generation") + let data = try MacSummaryExportRenderer.pdfData( + summaryData: summaryData, + locationData: locationData, + locationAddress: locationAddress + ) + AppLog.shared.fileManagement("PDFExportService: Generated native Mac PDF (\(data.count) bytes)") + return data + } +} +#endif diff --git a/BisonNotes AI/BisonNotes AI/Services/RTFExportService.swift b/BisonNotes AI/BisonNotes AI/Services/RTFExportService.swift index 6346614..5fa11c5 100644 --- a/BisonNotes AI/BisonNotes AI/Services/RTFExportService.swift +++ b/BisonNotes AI/BisonNotes AI/Services/RTFExportService.swift @@ -1,5 +1,7 @@ import Foundation +#if canImport(UIKit) import UIKit +#endif import MapKit /// Errors that can occur during RTF document generation @@ -20,6 +22,7 @@ enum RTFExportError: LocalizedError { } } +#if canImport(UIKit) final class RTFExportService { static let shared = RTFExportService() @@ -559,3 +562,43 @@ final class RTFExportService { document.append(list) } } +#else +final class RTFExportService { + static let shared = RTFExportService() + + private init() {} + + @MainActor + func generateDocument( + summaryData: EnhancedSummaryData, + locationData: LocationData?, + locationAddress: String? + ) throws -> Data { + AppLog.shared.fileManagement("RTFExportService: Starting native Mac document generation") + do { + let data = try MacSummaryExportRenderer.rtfData( + summaryData: summaryData, + locationData: locationData, + locationAddress: locationAddress + ) + AppLog.shared.fileManagement("RTFExportService: Generated native Mac RTF (\(data.count) bytes)") + return data + } catch let error as MacSummaryExportRenderer.RenderError { + AppLog.shared.fileManagement( + "RTFExportService: Native Mac export failed: \(error.localizedDescription)", + level: .error + ) + switch error { + case .documentTooLarge: + throw RTFExportError.memoryLimitExceeded + case .invalidDocument: + throw RTFExportError.invalidDocumentData + case .pdfContextUnavailable: + throw RTFExportError.documentGenerationFailed(error.localizedDescription) + } + } catch { + throw RTFExportError.documentGenerationFailed(error.localizedDescription) + } + } +} +#endif diff --git a/BisonNotes AI/BisonNotes AI/Services/SummaryExportFormatter.swift b/BisonNotes AI/BisonNotes AI/Services/SummaryExportFormatter.swift index 56b0764..d972a7f 100644 --- a/BisonNotes AI/BisonNotes AI/Services/SummaryExportFormatter.swift +++ b/BisonNotes AI/BisonNotes AI/Services/SummaryExportFormatter.swift @@ -1,6 +1,9 @@ import Foundation +#if canImport(UIKit) import UIKit +#endif +#if canImport(UIKit) enum SummaryExportFormatter { // MARK: - Cached Regex Patterns @@ -304,3 +307,4 @@ private extension UIFont { return UIFont(descriptor: descriptor, size: pointSize) } } +#endif diff --git a/BisonNotes AI/BisonNotes AI/SummariesView.swift b/BisonNotes AI/BisonNotes AI/SummariesView.swift index 906eeeb..41f8732 100644 --- a/BisonNotes AI/BisonNotes AI/SummariesView.swift +++ b/BisonNotes AI/BisonNotes AI/SummariesView.swift @@ -4,10 +4,20 @@ import Speech import CoreLocation import NaturalLanguage +private struct SummaryWithDate { + let recording: RecordingEntry + let transcript: TranscriptData? + let summary: EnhancedSummaryData? + let date: Date +} + struct SummariesView: View { @EnvironmentObject var recorderVM: AudioRecorderViewModel @EnvironmentObject var appCoordinator: AppDataCoordinator @Environment(\.isEmbeddedInSplitView) private var isEmbeddedInSplitView + #if os(macOS) + @Environment(\.openWindow) private var openWindow + #endif @StateObject private var enhancedTranscriptionManager = EnhancedTranscriptionManager() @StateObject private var enhancedFileManager = EnhancedFileManager.shared @ObservedObject private var iCloudManager = iCloudStorageManager.shared @@ -31,6 +41,8 @@ struct SummariesView: View { @State private var dateFilterEnd: Date = Date() @State private var isDateFilterActive = false @State private var expandedSummaryDateSections: Set = [.today] + @State private var isSummaryCandidatesExpanded = false + @State private var isSummaryArchiveExpanded = false @AppStorage("hasSeeniCloudPrompt") private var hasSeeniCloudPrompt = false @@ -77,7 +89,7 @@ struct SummariesView: View { } } } - .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in + .onReceive(NotificationCenter.default.publisher(for: PlatformLifecycle.willEnterForegroundNotification)) { _ in // Refresh when app comes to foreground loadRecordings() } @@ -221,6 +233,7 @@ struct SummariesView: View { } .sheet(isPresented: $showDateFilter) { dateFilterSheet + .nativeMacModalSizing(width: 520, height: 440) } } // End of body variable @@ -415,9 +428,9 @@ struct SummariesView: View { // MARK: - Recordings List View private func recordingsListView(_ filtered: [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)]) -> some View { - #if targetEnvironment(macCatalyst) - // On Mac Catalyst, the preview-+-NavigationLink-to-More pattern wedges the responder chain - // (destination renders but becomes unresponsive). Render everything inline instead. + #if os(macOS) || targetEnvironment(macCatalyst) + // A NavigationLink to a List with interactive section headers can wedge the + // responder chain on both Mac implementations. Keep the complete archive inline. return summariesSectionedScroll(filtered) #else // iOS / iPadOS: preview cards with "More" navigation to the full list page. @@ -458,19 +471,18 @@ struct SummariesView: View { #endif } - /// Full date-sectioned scroll of summaries (Mac Catalyst inline view) + /// Full date-sectioned scroll used by both Mac implementations. private func summariesSectionedScroll(_ filtered: [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)]) -> some View { - // Filter out recordings with nil dates and create wrapper struct with non-optional dates - struct RecordingWithDate { - let recording: RecordingEntry - let transcript: TranscriptData? - let summary: EnhancedSummaryData? - let date: Date - } - - let recordingsWithDates: [RecordingWithDate] = filtered.compactMap { item in + let availableSummaries = filtered + .filter { $0.summary != nil } + .sorted { ($0.recording.recordingDate ?? .distantPast) > ($1.recording.recordingDate ?? .distantPast) } + let recentSummaries = Array(availableSummaries.prefix(3)) + let archivedSummaries = Array(availableSummaries.dropFirst(recentSummaries.count)) + let summaryCandidates = filtered.filter { $0.summary == nil && $0.transcript != nil } + + let recordingsWithDates: [SummaryWithDate] = archivedSummaries.compactMap { item in guard let date = item.recording.recordingDate else { return nil } - return RecordingWithDate( + return SummaryWithDate( recording: item.recording, transcript: item.transcript, summary: item.summary, @@ -483,21 +495,34 @@ struct SummariesView: View { return ScrollView { LazyVStack(alignment: .leading, spacing: 20) { - ForEach(sectioned, id: \.section) { sectionData in - CollapsibleDateSectionHeader( - title: sectionData.section.title, - count: sectionData.items.count, - isExpanded: isSummaryDateSectionExpanded(sectionData.section), - isAlwaysExpanded: false, - onToggle: { toggleSummaryDateSection(sectionData.section) } - ) + if !recentSummaries.isEmpty { + summarySectionHeader(title: "Recent Summaries", count: availableSummaries.count) - if isSummaryDateSectionExpanded(sectionData.section) { - ForEach(sectionData.items, id: \.recording.objectID) { itemWithDate in - recordingRowView((recording: itemWithDate.recording, transcript: itemWithDate.transcript, summary: itemWithDate.summary)) + ForEach(recentSummaries, id: \.recording.objectID) { item in + recordingRowView(item) + } + } + + if !archivedSummaries.isEmpty { + Button { + withAnimation(.easeInOut(duration: 0.2)) { + isSummaryArchiveExpanded.toggle() } + } label: { + inlineArchiveRow( + title: isSummaryArchiveExpanded ? "Hide older summaries" : "Browse older summaries", + count: archivedSummaries.count, + isExpanded: isSummaryArchiveExpanded + ) + } + .buttonStyle(.plain) + + if isSummaryArchiveExpanded { + summaryArchiveSections(sectioned, candidates: []) } } + + summaryCandidatesSection(summaryCandidates) } .padding(.horizontal, 20) .padding(.top, 18) @@ -513,19 +538,90 @@ struct SummariesView: View { .accessibilityIdentifier(BisonNotesAccessibilityID.summaryList) } + @ViewBuilder + private func summaryArchiveSections( + _ sectioned: [(section: DateSection, items: [SummaryWithDate])], + candidates: [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)] + ) -> some View { + ForEach(sectioned, id: \.section) { sectionData in + CollapsibleDateSectionHeader( + title: sectionData.section.title, + count: sectionData.items.count, + isExpanded: isSummaryDateSectionExpanded(sectionData.section), + isAlwaysExpanded: false, + onToggle: { toggleSummaryDateSection(sectionData.section) } + ) + + if isSummaryDateSectionExpanded(sectionData.section) { + ForEach(sectionData.items, id: \.recording.objectID) { item in + recordingRowView( + (recording: item.recording, transcript: item.transcript, summary: item.summary) + ) + } + } + } + + summaryCandidatesSection(candidates) + } + + @ViewBuilder + private func summaryCandidatesSection( + _ candidates: [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)] + ) -> some View { + if !candidates.isEmpty { + CollapsibleDateSectionHeader( + title: "Ready to Summarize", + count: candidates.count, + isExpanded: isSummaryCandidatesExpanded, + isAlwaysExpanded: false, + onToggle: { isSummaryCandidatesExpanded.toggle() } + ) + + if isSummaryCandidatesExpanded { + ForEach(candidates, id: \.recording.objectID) { item in + recordingRowView(item) + } + } + } + } + + private func inlineArchiveRow(title: String, count: Int, isExpanded: Bool) -> some View { + HStack(spacing: 12) { + Image(systemName: "archivebox") + .font(.title3) + .foregroundColor(.accentColor) + + VStack(alignment: .leading, spacing: 2) { + Text(title) + .font(.subheadline.weight(.semibold)) + Text("\(count) older \(count == 1 ? "summary" : "summaries")") + .font(.caption) + .foregroundColor(.secondary) + } + + Spacer() + + Image(systemName: isExpanded ? "chevron.up" : "chevron.down") + .font(.caption.weight(.semibold)) + .foregroundColor(.secondary) + } + .padding(14) + .background(Color(.secondarySystemGroupedBackground)) + .clipShape(RoundedRectangle(cornerRadius: 15)) + .contentShape(Rectangle()) + .accessibilityElement(children: .combine) + .accessibilityHint(isExpanded ? "Collapses the summary archive." : "Expands the summary archive inline.") + } + /// Full list page reached via the "More" row (matches TranscriptViews' full list pages). /// Respects the same date/search filters as the main page. private var summariesFullListView: some View { - struct RecordingWithDate { - let recording: RecordingEntry - let transcript: TranscriptData? - let summary: EnhancedSummaryData? - let date: Date - } + let availableSummaries = filteredRecordings.filter { $0.summary != nil } + let summaryCandidates = filteredRecordings.filter { $0.summary == nil && $0.transcript != nil } - let recordingsWithDates: [RecordingWithDate] = filteredRecordings.compactMap { item in + let recordingsWithDates: [SummaryWithDate] = availableSummaries.compactMap { item in guard let date = item.recording.recordingDate else { return nil } - return RecordingWithDate( + return SummaryWithDate( recording: item.recording, transcript: item.transcript, summary: item.summary, @@ -561,6 +657,27 @@ struct SummariesView: View { } } } + + if !summaryCandidates.isEmpty { + Section( + header: CollapsibleDateSectionHeader( + title: "Ready to Summarize", + count: summaryCandidates.count, + isExpanded: isSummaryCandidatesExpanded, + isAlwaysExpanded: false, + onToggle: { isSummaryCandidatesExpanded.toggle() } + ) + ) { + if isSummaryCandidatesExpanded { + ForEach(summaryCandidates, id: \.recording.objectID) { item in + recordingRowView(item) + .listRowInsets(EdgeInsets(top: 6, leading: 16, bottom: 6, trailing: 16)) + .listRowSeparator(.hidden) + .listRowBackground(Color.clear) + } + } + } + } } .listStyle(.plain) .scrollContentBackground(.hidden) @@ -676,7 +793,10 @@ struct SummariesView: View { /// dropped entirely (they're section labels, not content), remaining /// markdown syntax is stripped, and whitespace is collapsed. private func summaryPreviewText(_ markdown: String) -> String { - let withoutHeaderLines = markdown + // A preview only renders a few lines. Bound the work so expanding an old + // month never runs markdown cleanup over dozens of complete summaries. + let previewSource = String(markdown.prefix(2_000)) + let withoutHeaderLines = previewSource .components(separatedBy: .newlines) .filter { !$0.trimmingCharacters(in: .whitespaces).hasPrefix("#") } .joined(separator: " ") @@ -716,8 +836,14 @@ struct SummariesView: View { private func summaryActionView(recording: RecordingEntry, summary: EnhancedSummaryData?) -> some View { if summary != nil { Button(action: { + #if os(macOS) + if let recordingID = recording.id { + openWindow(id: NativeWindowID.summary, value: recordingID) + } + #else selectedRecording = recording showSummary = true + #endif }) { Label("View Summary", systemImage: "doc.text.fill") .font(.caption.weight(.semibold)) diff --git a/BisonNotes AI/BisonNotes AI/SummaryDetailView.swift b/BisonNotes AI/BisonNotes AI/SummaryDetailView.swift index 1460d12..63d7bdc 100644 --- a/BisonNotes AI/BisonNotes AI/SummaryDetailView.swift +++ b/BisonNotes AI/BisonNotes AI/SummaryDetailView.swift @@ -2,7 +2,9 @@ import SwiftUI @preconcurrency import MapKit import Contacts @preconcurrency import CoreLocation +#if canImport(UIKit) import UIKit +#endif import LinkPresentation import UniformTypeIdentifiers import PDFKit @@ -28,6 +30,7 @@ private actor SummaryGeocodeCache { private let summaryGeocodeCache = SummaryGeocodeCache() struct SummaryDetailView: View { + @Environment(\.openWindow) private var openWindow let recording: RecordingFile @State private var summaryData: EnhancedSummaryData @Environment(\.dismiss) private var dismiss @@ -107,20 +110,23 @@ struct SummaryDetailView: View { } var body: some View { - // NavigationStack { Form } is the only sheet pattern that scrolls reliably - // on Mac Catalyst. See feedback_mac_catalyst_scrollview.md. NavigationStack { - Form { - Section { locationSection } - Section { headerSection } - Section { summarySection } - Section { tasksSection } - Section { remindersSection } - Section { titlesSection } - Section { attachmentsSection } - Section { dateTimeEditorSection } - Section { metadataSection } - Section { regenerateSection } + Group { + #if os(macOS) + // Native Form can size itself to all rows when hosted in a + // separate window. List supplies an explicit scrolling + // viewport while retaining Section styling and semantics. + List { + summarySections + } + .listStyle(.inset) + #else + // NavigationStack { Form } is the only sheet pattern that + // scrolls reliably on Mac Catalyst. + Form { + summarySections + } + #endif } .scrollContentBackground(.hidden) .background(Color(.systemGroupedBackground)) @@ -157,6 +163,12 @@ struct SummaryDetailView: View { showingAIWarning: $showingAIWarning, onSettingsRequested: {} ) + .focusedSceneValue( + \.summaryExportAction, + SummaryExportAction { + showingExportFormatPicker = true + } + ) .onAppear { // Debug summary data being displayed AppLog.shared.summarization("SummaryDetailView opened: summary=\(summaryData.summary.count) chars, tasks=\(summaryData.tasks.count), reminders=\(summaryData.reminders.count), titles=\(summaryData.titles.count)", level: .debug) @@ -217,6 +229,7 @@ struct SummaryDetailView: View { .sheet(isPresented: $showingLocationDetail) { if let locationData = recording.locationData { LocationDetailView(locationData: locationData) + .nativeMacModalSizing(width: 680, height: 620) } } .sheet(isPresented: $showingLocationPicker) { @@ -225,6 +238,7 @@ struct SummaryDetailView: View { updateRecordingLocation(location) } ) + .nativeMacModalSizing(width: 700, height: 620) } .sheet(isPresented: $showingShareSheet) { Group { @@ -246,6 +260,7 @@ struct SummaryDetailView: View { } } } + .nativeMacModalSizing(width: 560, height: 440) } .alert("Export Error", isPresented: .constant(exportError != nil)) { Button("OK") { @@ -299,6 +314,7 @@ struct SummaryDetailView: View { } } } + .nativeMacModalSizing(width: 760, height: 680) } .sheet(isPresented: $showingPDFAttachment) { if let selectedAttachmentPDFURL { @@ -314,12 +330,14 @@ struct SummaryDetailView: View { } } } + .nativeMacModalSizing(width: 800, height: 700) } } .sheet(isPresented: $showingNoteEditor) { NoteEditorSheet(text: $noteDraft) { saveUserNotes() } + .nativeMacModalSizing(width: 680, height: 600) } .quickLookPreview($selectedAttachmentGenericURL) .alert("Attachment Error", isPresented: .constant(attachmentError != nil)) { @@ -331,6 +349,20 @@ struct SummaryDetailView: View { } } + @ViewBuilder + private var summarySections: some View { + Section { locationSection } + Section { headerSection } + Section { summarySection } + Section { tasksSection } + Section { remindersSection } + Section { titlesSection } + Section { attachmentsSection } + Section { dateTimeEditorSection } + Section { metadataSection } + Section { regenerateSection } + } + // MARK: - Geocoding Helpers @MainActor @@ -478,7 +510,13 @@ struct SummaryDetailView: View { // Button to open full map view Button(action: { + #if os(macOS) + if let locationData = recording.locationData { + openWindow(id: NativeWindowID.location, value: locationData) + } + #else showingLocationDetail = true + #endif }) { Image(systemName: "arrow.up.right.circle.fill") .font(.title3) @@ -843,6 +881,7 @@ struct SummaryDetailView: View { updateRecordingName(to: customTitle) } ) + .nativeMacModalSizing(width: 620, height: 560) } .alert("Edit Title", isPresented: Binding( get: { editingTitle != nil }, @@ -1010,6 +1049,7 @@ struct SummaryDetailView: View { updateRecordingDateTime(to: newDateTime) } ) + .nativeMacModalSizing(width: 560, height: 500) } } @@ -1869,6 +1909,7 @@ struct EnhancedTaskRowView: View { integrationManager.addTaskToGoogleCalendar(task, recordingName: recordingName) } ) + .nativeMacModalSizing(width: 560, height: 500) } .alert("Success", isPresented: $showingSuccessAlert) { Button("OK") { } @@ -2019,6 +2060,7 @@ struct EnhancedReminderRowView: View { integrationManager.addReminderToGoogleCalendar(reminder, recordingName: recordingName) } ) + .nativeMacModalSizing(width: 560, height: 500) } .alert("Success", isPresented: $showingSuccessAlert) { Button("OK") { } @@ -3069,6 +3111,7 @@ struct LocationResultRow: View { // MARK: - Static Location Map View +#if os(iOS) private final class MapSnapshotCache { static let shared = MapSnapshotCache() private let cache = NSCache() @@ -3414,9 +3457,38 @@ private struct StaticLocationMapView: View { } } } +#else +/// Native macOS variant: a live (non-interactive) SwiftUI Map replaces the +/// UIGraphicsImageRenderer-based static snapshot pipeline. +private struct StaticLocationMapView: View { + let summaryId: UUID + let locationData: LocationData + let size: CGSize + + private var coordinate: CLLocationCoordinate2D { + CLLocationCoordinate2D( + latitude: locationData.latitude, + longitude: locationData.longitude + ) + } + + var body: some View { + Map(initialPosition: .region(MKCoordinateRegion( + center: coordinate, + span: MKCoordinateSpan(latitudeDelta: 0.005, longitudeDelta: 0.005) + ))) { + Marker("", coordinate: coordinate) + } + .allowsHitTesting(false) + .frame(width: size.width, height: size.height) + .clipped() + } +} +#endif // MARK: - Attachment Preview +#if os(iOS) private struct SummaryAttachmentPDFView: UIViewRepresentable { let url: URL @@ -3435,9 +3507,30 @@ private struct SummaryAttachmentPDFView: UIViewRepresentable { } } } +#else +private struct SummaryAttachmentPDFView: NSViewRepresentable { + let url: URL + + func makeNSView(context: Context) -> PDFView { + let view = PDFView() + view.autoScales = true + view.displayMode = .singlePageContinuous + view.displayDirection = .vertical + view.document = PDFDocument(url: url) + return view + } + + func updateNSView(_ nsView: PDFView, context: Context) { + if nsView.document?.documentURL != url { + nsView.document = PDFDocument(url: url) + } + } +} +#endif // MARK: - Share Sheet +#if os(iOS) struct ShareSheet: UIViewControllerRepresentable { let activityItems: [Any] let subject: String? @@ -3539,6 +3632,98 @@ private final class ExportActivityItem: NSObject, UIActivityItemSource { } } } +#else +/// macOS twin of the iOS UIActivityItemSource: writes the export payload to a +/// temporary file that can be passed to NSSharingServicePicker. +final class ExportActivityItem { + let fileURL: URL? + + init(data: Data, fileName: String, iconSystemName: String) { + let destination = FileManager.default.temporaryDirectory.appendingPathComponent(fileName) + do { + if FileManager.default.fileExists(atPath: destination.path) { + try FileManager.default.removeItem(at: destination) + } + try data.write(to: destination, options: .atomic) + self.fileURL = destination + } catch { + AppLog.shared.summarization("Failed to write temporary export for sharing: \(error)", level: .error) + self.fileURL = nil + } + } +} + +struct ShareSheet: View { + let activityItems: [Any] + let subject: String? + + @Environment(\.dismiss) private var dismiss + @State private var didRequestSharing = false + @State private var shareUnavailable = false + + init(activityItems: [Any], subject: String? = nil) { + self.activityItems = activityItems + self.subject = subject + } + + private var fileURLs: [URL] { + activityItems.compactMap { item -> URL? in + if let url = item as? URL, url.isFileURL { return url } + if let export = item as? ExportActivityItem { return export.fileURL } + return nil + } + } + + var body: some View { + VStack(spacing: 16) { + Text("Share Export") + .font(.headline) + if fileURLs.isEmpty { + Text("The exported file could not be prepared for sharing.") + .foregroundColor(.secondary) + } else if shareUnavailable { + Text("The sharing picker could not open. You can show the file in Finder instead.") + .foregroundColor(.secondary) + } else { + Text("Choose a Mac sharing service for the exported file.") + .foregroundColor(.secondary) + } + HStack { + Button("Close") { dismiss() } + if !fileURLs.isEmpty { + Button("Share…") { + presentSharingPicker() + } + .keyboardShortcut(.defaultAction) + Button("Show in Finder") { + NSWorkspace.shared.activateFileViewerSelecting(fileURLs) + dismiss() + } + } + } + } + .padding(24) + .frame(minWidth: 380) + .onAppear { + guard !didRequestSharing, !fileURLs.isEmpty else { return } + didRequestSharing = true + DispatchQueue.main.async { + presentSharingPicker() + } + } + } + + @MainActor + private func presentSharingPicker() { + let presented = PlatformSharingPresenter.shared.present( + items: fileURLs, + subject: subject, + onDismiss: { dismiss() } + ) + shareUnavailable = !presented + } +} +#endif // MARK: - Note Editor Sheet diff --git a/BisonNotes AI/BisonNotes AI/SummaryManager.swift b/BisonNotes AI/BisonNotes AI/SummaryManager.swift index aeb1963..166a91c 100644 --- a/BisonNotes AI/BisonNotes AI/SummaryManager.swift +++ b/BisonNotes AI/BisonNotes AI/SummaryManager.swift @@ -1,5 +1,7 @@ import Foundation +#if canImport(UIKit) import UIKit +#endif // MARK: - Engine Availability Status @@ -60,7 +62,7 @@ class SummaryManager: ObservableObject { /// Background task ID for keeping summarization alive when the app is backgrounded. /// Cloud AI calls (OpenAI, Bedrock, Gemini) use network requests that iOS will /// terminate after ~30s without a background task. - private var summaryBackgroundTaskID: UIBackgroundTaskIdentifier = .invalid + private var summaryBackgroundTaskID: PlatformBackgroundTask.ID = .invalid // MARK: - Error Handling Integration @@ -1161,13 +1163,13 @@ class SummaryManager: ObservableObject { private func beginSummaryBackgroundTask() { guard summaryBackgroundTaskID == .invalid else { return } - summaryBackgroundTaskID = UIApplication.shared.beginBackgroundTask(withName: "AISummarization") { [weak self] in + summaryBackgroundTaskID = PlatformBackgroundTask.begin(name: "AISummarization") { [weak self] in // Expiration handler β€” iOS is about to kill us AppLog.shared.summarization("Background task expiring for summarization", level: .default) self?.endSummaryBackgroundTask() } if summaryBackgroundTaskID != .invalid { - let remaining = UIApplication.shared.backgroundTimeRemaining + let remaining = PlatformBackgroundTask.remainingTime if remaining != Double.greatestFiniteMagnitude { AppLog.shared.summarization("Background task started - \(Int(remaining))s remaining", level: .debug) } else { @@ -1179,7 +1181,7 @@ class SummaryManager: ObservableObject { private func endSummaryBackgroundTask() { guard summaryBackgroundTaskID != .invalid else { return } AppLog.shared.summarization("Ending summarization background task", level: .debug) - UIApplication.shared.endBackgroundTask(summaryBackgroundTaskID) + PlatformBackgroundTask.end(summaryBackgroundTaskID) summaryBackgroundTaskID = .invalid } diff --git a/BisonNotes AI/BisonNotes AI/SwiftLintBaseline.json b/BisonNotes AI/BisonNotes AI/SwiftLintBaseline.json index eb1ba1e..85c0af3 100644 --- a/BisonNotes AI/BisonNotes AI/SwiftLintBaseline.json +++ b/BisonNotes AI/BisonNotes AI/SwiftLintBaseline.json @@ -1 +1 @@ -[{"violation":{"ruleDescription":"Type bodies should not span too many lines","ruleName":"Type Body Length","location":{"line":107,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift"},"reason":"Struct body should span 250 lines or less excluding comments and whitespace: currently spans 349 lines","ruleIdentifier":"type_body_length","severity":"warning"},"text":"struct AISettingsView: View {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"line":112,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"},"text":" @AppStorage(SummarizationTimeouts.storageKey) private var summarizationTimeout: Double = SummarizationTimeouts.defaultTimeout"},{"violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift","character":1,"line":139},"reason":"Line should be 120 characters or less; currently it has 122 characters","ruleIdentifier":"line_length"},"text":" let currentEngineName = UserDefaults.standard.string(forKey: \"SelectedAIEngine\") ?? AIEngineType.mlxSwift.rawValue"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift","character":1,"line":150},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 122 characters","ruleName":"Line Length","severity":"warning"},"text":" let currentEngine = UserDefaults.standard.string(forKey: \"SelectedAIEngine\") ?? AIEngineType.mlxSwift.rawValue"},{"violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"line":227,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift"},"reason":"Line should be 120 characters or less; currently it has 141 characters","ruleName":"Line Length","ruleIdentifier":"line_length"},"text":" let modelString = UserDefaults.standard.string(forKey: \"openAISummarizationModel\") ?? OpenAISummarizationModel.gpt41Mini.rawValue"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 125 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift","character":1,"line":232},"severity":"warning"},"text":" let modelName = UserDefaults.standard.string(forKey: \"mistralModel\") ?? MistralAIModel.mistralMedium2508.rawValue"},{"violation":{"ruleName":"Line Length","severity":"warning","location":{"line":235,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift"},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 141 characters"},"text":" let modelName = UserDefaults.standard.string(forKey: AppSettingsKeys.ollamaModelName) ?? AppSettingsKeys.Defaults.ollamaModelName"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"line":241,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift"},"reason":"Line should be 120 characters or less; currently it has 131 characters"},"text":" let storedModelName = UserDefaults.standard.string(forKey: \"awsBedrockModel\") ?? AWSBedrockModel.claude45Haiku.rawValue"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 129 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"line":251,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift"}},"text":" let model = UserDefaults.standard.string(forKey: MLXSwiftSettingsKeys.modelId) ?? MLXSwiftSettingsKeys.defaultModelId"},{"violation":{"reason":"Line should be 200 characters or less; currently it has 210 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"line":282,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift","character":1},"ruleName":"Line Length","severity":"error"},"text":" Text(\"This will regenerate all summaries using the current AI engine. Only summaries with existing transcripts will be processed. This may take some time depending on how many recordings you have.\")"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift","line":384},"reason":"Line should be 120 characters or less; currently it has 191 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."},"text":" AISettingsCard(title: \"Current Engine\", systemImage: currentEngineType.map { iconName(for: $0) } ?? \"sparkles\", tint: currentEngineType.map { engineColor(for: $0) } ?? .accentColor) {"},{"text":" Label(viewModel.regenerationManager.isRegenerating ? \"Processing...\" : \"Regenerate All Summaries\", systemImage: \"arrow.clockwise\")","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","location":{"line":487,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 146 characters"}},{"text":" func openSettings(for engine: AIEngineType) {","violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift","line":726,"character":5},"ruleName":"Cyclomatic Complexity","reason":"Function should have complexity 10 or less; currently complexity is 12","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","reason":"File should contain 400 lines or less: currently contains 890","ruleIdentifier":"file_length","ruleDescription":"Files should not span too many lines.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift","line":890}}},{"text":"class AWSBedrockService: ObservableObject {","violation":{"ruleName":"Type Body Length","ruleDescription":"Type bodies should not span too many lines","severity":"error","reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 533 lines","ruleIdentifier":"type_body_length","location":{"line":14,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","character":1}}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"Failed to initialize AWS Bedrock client: \\(error.localizedDescription)\")","violation":{"ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":64,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift"},"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" AppLog.shared.networking(\"AWS Bedrock Summary: Large text detected (\\(tokenCount) tokens), using chunked processing\")","violation":{"ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":76},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 129 characters","ruleName":"Line Length","ruleIdentifier":"line_length"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 167 characters","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"line":233,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","character":1}}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","ruleName":"Large Tuple","location":{"line":233,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","character":56},"severity":"error","reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.networking(\"AWS Bedrock: Text token count: \\(tokenCount), max allowed: \\(maxTokens)\", level: .debug)","violation":{"location":{"line":241,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift"},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 122 characters","ruleIdentifier":"line_length","severity":"warning"}},{"text":" AppLog.shared.networking(\"AWS Bedrock: Large transcript detected (\\(tokenCount) tokens), using chunked processing\")","violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":244},"reason":"Line should be 120 characters or less; currently it has 127 characters","ruleIdentifier":"line_length"}},{"text":" private func invokeModel(","violation":{"ruleDescription":"Function bodies should not span too many lines","severity":"warning","location":{"line":284,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift"},"ruleIdentifier":"function_body_length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 61 lines","ruleName":"Function Body Length"}},{"text":" AppLog.shared.networking(\"AWS Bedrock API Configuration - Model: \\(config.model.rawValue), Region: \\(config.region)\", level: .debug)","violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":296},"ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 140 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"line":313,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" throw SummarizationError.aiServiceUnavailable(service: \"Failed to encode request: \\(error.localizedDescription)\")"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 153 characters","ruleName":"Line Length","location":{"line":354,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift"},"severity":"warning"},"text":" AppLog.shared.networking(\"AWS Bedrock response rejected: \\(responseData.count) bytes exceeds \\(responseLimit) byte limit\", level: .error)"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 128 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"line":355,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift"}},"text":" throw SummarizationError.aiServiceUnavailable(service: \"AWS Bedrock response exceeded the maximum allowed size\")"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 127 characters","location":{"line":360,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","character":1}},"text":" AppLog.shared.networking(\"AWS Bedrock API Response received, size: \\(responseData.count) bytes\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 145 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"line":367,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift"}},"text":" AppLog.shared.networking(\"AWS Bedrock API Success - Model: \\(config.model.rawValue), response: \\(modelResponse.content.count) chars\")"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 131 characters","severity":"warning","ruleIdentifier":"line_length","location":{"character":1,"line":373,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift"},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."},"text":" throw SummarizationError.aiServiceUnavailable(service: \"AWS Bedrock API request failed: \\(error.localizedDescription)\")"},{"violation":{"reason":"Line should be 200 characters or less; currently it has 211 characters","ruleIdentifier":"line_length","location":{"character":1,"line":396,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift"},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"error"},"text":" private func processCompleteStructured(text: String, contentType: ContentType) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"ruleIdentifier":"large_tuple","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","severity":"error","location":{"line":396,"character":100,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift"},"reason":"Tuples should have at most 2 members","ruleName":"Large Tuple"},"text":" private func processCompleteStructured(text: String, contentType: ContentType) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":412,"character":1},"reason":"Line should be 200 characters or less; currently it has 211 characters"},"text":" private func processCompleteIndividual(text: String, contentType: ContentType) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"ruleName":"Large Tuple","reason":"Tuples should have at most 2 members","severity":"error","ruleIdentifier":"large_tuple","location":{"line":412,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","character":100},"ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead."},"text":" private func processCompleteIndividual(text: String, contentType: ContentType) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"error","reason":"Line should be 200 characters or less; currently it has 224 characters","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":434,"character":1}},"text":" private func processCompleteChunked(text: String, contentType: ContentType, maxTokens: Int) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"ruleIdentifier":"large_tuple","ruleName":"Large Tuple","location":{"character":113,"line":434,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift"},"severity":"error","reason":"Tuples should have at most 2 members","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead."},"text":" private func processCompleteChunked(text: String, contentType: ContentType, maxTokens: Int) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"text":" AppLog.shared.networking(\"AWS Bedrock: Processing chunk \\(index + 1) of \\(chunks.count) (\\(TokenManager.getTokenCount(chunk)) tokens)\", level: .debug)","violation":{"reason":"Line should be 120 characters or less; currently it has 162 characters","ruleDescription":"Lines should not span too many characters.","location":{"line":446,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","character":1},"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning"}},{"text":" AppLog.shared.networking(\"AWS Bedrock: Final summary: \\(combinedSummary.count) chars, tasks: \\(deduplicatedTasks.count), reminders: \\(deduplicatedReminders.count), titles: \\(deduplicatedTitles.count)\", level: .debug)","violation":{"reason":"Line should be 200 characters or less; currently it has 224 characters","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"line":481,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","character":1}}},{"text":" Combine the following summaries into one comprehensive, well-structured summary that captures all key information without redundancy.","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 145 characters","ruleName":"Line Length","location":{"line":505,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift"},"ruleIdentifier":"line_length"}},{"text":" private func parseCompleteResponseFromJSON(_ jsonString: String) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) {","violation":{"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"line":600,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift"},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 165 characters"}},{"text":" private func parseCompleteResponseFromJSON(_ jsonString: String) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) {","violation":{"severity":"error","location":{"character":80,"line":600,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift"},"reason":"Tuples should have at most 2 members","ruleName":"Large Tuple","ruleIdentifier":"large_tuple","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead."}},{"text":"}","violation":{"ruleIdentifier":"file_length","ruleName":"File Length","severity":"warning","location":{"line":729,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","character":1},"reason":"File should contain 400 lines or less: currently contains 729","ruleDescription":"Files should not span too many lines."}},{"text":"struct AWSBedrockSettingsView: View {","violation":{"ruleName":"Type Body Length","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSBedrockSettingsView.swift","line":10,"character":1},"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 456 lines"}},{"text":" Text(\"AWS Bedrock provides access to foundation models from Anthropic, Amazon, Meta, and other providers for high-quality AI summaries and content analysis.\")","violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 174 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSBedrockSettingsView.swift","line":86},"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning"}},{"text":" Text(\"Use an AWS profile configured with the AWS CLI or SDK. The profile should have access to AWS Bedrock in the selected region.\")","violation":{"severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSBedrockSettingsView.swift","line":149,"character":1},"reason":"Line should be 120 characters or less; currently it has 156 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" Text(\"Your AWS credentials are stored securely on your device. Never share these credentials or commit them to version control.\")","violation":{"reason":"Line should be 120 characters or less; currently it has 149 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"line":226,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSBedrockSettingsView.swift","character":1},"ruleName":"Line Length","ruleIdentifier":"line_length"}},{"text":" Text(\"Controls randomness in responses. Lower values (0.1) are more focused and deterministic, higher values (0.9) are more creative and varied.\")","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"line":353,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSBedrockSettingsView.swift","character":1},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 166 characters"}},{"text":" Text(\"Maximum number of tokens in the response. Higher values allow for longer responses but may increase costs.\")","violation":{"ruleDescription":"Lines should not span too many characters.","location":{"line":373,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSBedrockSettingsView.swift","character":1},"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" Link(\"Model Access Setup Guide\", destination: URL(string: \"https:\/\/docs.aws.amazon.com\/bedrock\/latest\/userguide\/model-access.html\")!)","violation":{"ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSBedrockSettingsView.swift","line":445},"severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 145 characters"}},{"text":" Link(\"IAM Permissions Guide\", destination: URL(string: \"https:\/\/docs.aws.amazon.com\/bedrock\/latest\/userguide\/security_iam_service-with-iam.html\")!)","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSBedrockSettingsView.swift","line":446},"reason":"Line should be 120 characters or less; currently it has 159 characters"}},{"text":" testResult = \"βœ… AWS Bedrock connection successful! Model \\(selectedModelEnum.displayName) is ready to use.\"","violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 127 characters","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","location":{"line":510,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSBedrockSettingsView.swift"}}},{"text":"}","violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSBedrockSettingsView.swift","line":539,"character":1},"reason":"File should contain 400 lines or less: currently contains 539","ruleIdentifier":"file_length","ruleDescription":"Files should not span too many lines.","ruleName":"File Length"}},{"text":" Text(\"AWS Transcribe provides high-quality transcription for large audio files with better accuracy than local transcription.\")","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":37,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSSettingsView.swift","character":1},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 151 characters","ruleIdentifier":"line_length"}},{"text":" Text(\"Your AWS credentials are stored securely on your device. Never share these credentials or commit them to version control.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"line":106,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSSettingsView.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 157 characters"}},{"text":" Text(\"This bucket will store your audio files temporarily during transcription. Make sure it exists and your credentials have access to it.\")","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 165 characters","severity":"warning","location":{"character":1,"line":131,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSSettingsView.swift"},"ruleIdentifier":"line_length"}},{"text":" Link(\"AWS Transcribe Documentation\", destination: URL(string: \"https:\/\/docs.aws.amazon.com\/transcribe\/\")!)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 126 characters","severity":"warning","location":{"character":1,"line":195,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSSettingsView.swift"}}},{"text":" Link(\"AWS IAM Setup Guide\", destination: URL(string: \"https:\/\/docs.aws.amazon.com\/IAM\/latest\/UserGuide\/id_credentials_access-keys.html\")!)","violation":{"ruleIdentifier":"line_length","location":{"line":196,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSSettingsView.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 158 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":"class AWSTranscribeService: NSObject, ObservableObject {","violation":{"ruleDescription":"Type bodies should not span too many lines","ruleName":"Type Body Length","location":{"line":66,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSTranscribeService.swift"},"severity":"error","ruleIdentifier":"type_body_length","reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 453 lines"}},{"text":" awsCredentialIdentityResolver: AWSClientCredentialResolver.staticResolver(credentials: sharedCredentials),","violation":{"location":{"line":115,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSTranscribeService.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"}},{"text":" awsCredentialIdentityResolver: AWSClientCredentialResolver.staticResolver(credentials: sharedCredentials),","violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSTranscribeService.swift","character":1,"line":140},"reason":"Line should be 120 characters or less; currently it has 122 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"}},{"text":" func transcribeAudioFileWithChunking(at url: URL, recordingId: UUID? = nil) async throws -> AWSTranscribeResult {","violation":{"location":{"character":5,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSTranscribeService.swift","line":260},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 56 lines","severity":"warning","ruleName":"Function Body Length","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length"}},{"text":" recordingId: recordingId ?? UUID() \/\/ TODO: Get actual recording ID from Core Data","violation":{"ruleDescription":"TODOs and FIXMEs should be resolved.","severity":"warning","ruleName":"Todo","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSTranscribeService.swift","line":304,"character":55},"reason":"TODOs should be resolved (Get actual recording ID from C...)","ruleIdentifier":"todo"}},{"text":" private func processTranscriptionResult(result: TranscribeClientTypes.TranscriptionJob) async throws -> AWSTranscribeResult {","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 129 characters","ruleIdentifier":"line_length","location":{"line":460,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSTranscribeService.swift"},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" AppLog.shared.transcription(\"Failed to download transcript from S3, trying alternative method...\", level: .error)","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 129 characters","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSTranscribeService.swift","line":479,"character":1},"ruleName":"Line Length"}},{"text":" private func parseTranscript(data: Data) throws -> (fullText: String, segments: [TranscriptSegment], confidence: Double) {","violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSTranscribeService.swift","line":556},"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" private func parseTranscript(data: Data) throws -> (fullText: String, segments: [TranscriptSegment], confidence: Double) {","violation":{"severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSTranscribeService.swift","line":556,"character":13},"ruleIdentifier":"function_body_length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 71 lines"}},{"text":" private func parseTranscript(data: Data) throws -> (fullText: String, segments: [TranscriptSegment], confidence: Double) {","violation":{"ruleIdentifier":"large_tuple","ruleName":"Large Tuple","severity":"warning","location":{"character":56,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSTranscribeService.swift","line":556},"reason":"Tuples should have at most 2 members","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead."}},{"text":" let segments_data = speakerLabels[\"segments\"] as? [[String: Any]] {","violation":{"ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSTranscribeService.swift","character":16,"line":592},"severity":"error","reason":"Variable name 'segments_data' should only contain alphanumeric and other allowed characters","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleName":"Identifier Name"}},{"text":"}","violation":{"ruleIdentifier":"file_length","severity":"warning","ruleName":"File Length","ruleDescription":"Files should not span too many lines.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSTranscribeService.swift","line":710,"character":1},"reason":"File should contain 400 lines or less: currently contains 710"}},{"text":" didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {","violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 121 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AppDelegate.swift","line":20}}},{"text":" AppLog.shared.general(\"Received notification action: category=\\(categoryIdentifier), action=\\(actionIdentifier)\")","violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 121 characters","ruleDescription":"Lines should not span too many characters.","location":{"line":100,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AppDelegate.swift","character":1},"severity":"warning","ruleIdentifier":"line_length"}},{"text":" withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AppDelegate.swift","line":140,"character":1},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 129 characters","severity":"warning"}},{"text":" Summarize the following transcript in 4-7 concise bullet points. Keep factual details, decisions, action owners, and deadlines if present. Transcript:\\n\\n\\(chunks[0])","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 178 characters","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AppleNativeEngine.swift","character":1,"line":38}}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AppleNativeEngine.swift","line":125},"reason":"Line should be 120 characters or less; currently it has 167 characters","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AppleNativeEngine.swift","line":125,"character":56},"reason":"Tuples should have at most 2 members","ruleName":"Large Tuple"}},{"text":" throw SummarizationError.processingFailed(reason: \"Apple Foundation Models returned an empty response\")","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AppleNativeEngine.swift","character":1,"line":206},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":"class AudioFileChunkingService: ObservableObject {","violation":{"ruleDescription":"Type bodies should not span too many lines","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","character":1,"line":12},"ruleIdentifier":"type_body_length","ruleName":"Type Body Length","severity":"error","reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 478 lines"}},{"text":" AppLog.shared.chunking(\"shouldChunkFile - Checking: \\(url.lastPathComponent) for engine: \\(engine.rawValue)\", level: .debug)","violation":{"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":30},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" AppLog.shared.chunking(\"shouldChunkFile - File size check: \\(fileInfo.fileSize) bytes > \\(maxBytes) bytes = \\(needsChunking)\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":46,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift"},"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 153 characters"}},{"text":" AppLog.shared.chunking(\"shouldChunkFile - Duration check: \\(fileInfo.duration)s > \\(maxSeconds)s = \\(needsChunking)\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 144 characters","location":{"character":1,"line":49,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift"},"ruleIdentifier":"line_length","severity":"warning"}},{"text":" AppLog.shared.chunking(\"shouldChunkFile - Combined check: size(\\(exceedsSize)) || duration(\\(exceedsDuration)) = \\(needsChunking)\", level: .debug)","violation":{"reason":"Line should be 120 characters or less; currently it has 158 characters","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":54,"character":1},"ruleDescription":"Lines should not span too many characters."}},{"text":" func chunkAudioFile(_ url: URL, for engine: TranscriptionEngine) async throws -> ChunkingResult {","violation":{"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 89 lines","location":{"character":5,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":62},"ruleIdentifier":"function_body_length","ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines"}},{"text":" EnhancedLogger.shared.logChunking(\"Duration: \\(fileInfo.duration)s, Size: \\(fileInfo.fileSize) bytes\", level: .debug)","violation":{"ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","character":1,"line":101},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" AppLog.shared.chunking(\"Creating single chunk for file - Duration: \\(fileInfo.duration)s, Size: \\(fileInfo.fileSize) bytes\", level: .debug)","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","character":1,"line":112},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 155 characters","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length"}},{"violation":{"ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 122 characters","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":123,"character":1},"ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.chunking(\"Single chunk created - ID: \\(singleChunk.id), Duration: \\(singleChunk.duration)s\")"},{"violation":{"severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 124 characters","location":{"line":151,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift"},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."},"text":" chunks = try await chunkByFileSizeWithStreaming(url, maxBytes: maxBytes, config: config, fileInfo: fileInfo)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 128 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":153},"ruleName":"Line Length","ruleIdentifier":"line_length"},"text":" chunks = try await chunkByDurationWithStreaming(url, maxSeconds: maxSeconds, config: config, fileInfo: fileInfo)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 143 characters","severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":155,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift"}},"text":" chunks = try await chunkByCombinedStrategy(url, maxBytes: maxBytes, maxSeconds: maxSeconds, config: config, fileInfo: fileInfo)"},{"violation":{"severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":184,"character":1},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 177 characters","ruleName":"Line Length"},"text":" func reassembleTranscript(from chunks: [TranscriptChunk], originalURL: URL, recordingName: String, recordingDate: Date, recordingId: UUID) async throws -> ReassemblyResult {"},{"violation":{"ruleName":"Line Length","location":{"line":251,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift"},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 140 characters","severity":"warning"},"text":" func createTranscriptChunk(from transcriptText: String, audioChunk: AudioChunk, segments: [TranscriptSegment] = []) -> TranscriptChunk {"},{"violation":{"ruleName":"Prefer For-Where","ruleIdentifier":"for_where","severity":"warning","location":{"line":281,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift"},"reason":"`where` clauses are preferred over a single `if` inside a `for`","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`"},"text":" if chunk.chunkURL != chunk.originalURL {"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","character":1,"line":289},"severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 129 characters"},"text":" AppLog.shared.chunking(\"Failed to delete chunk \\(chunk.chunkURL.lastPathComponent): \\(error)\", level: .error)"},{"violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 122 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":379,"character":1}},"text":" AppLog.shared.chunking(\"Removed duplicate segment at startTime=\\(Int(segment.startTime))s\", level: .debug)"},{"violation":{"severity":"warning","location":{"line":408,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift"},"ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 154 characters","ruleDescription":"Lines should not span too many characters."},"text":" private func chunkByFileSizeWithStreaming(_ url: URL, maxBytes: Int64, config: ChunkingConfig, fileInfo: AudioFileInfo) async throws -> [AudioChunk] {"},{"violation":{"ruleIdentifier":"function_body_length","ruleName":"Function Body Length","ruleDescription":"Function bodies should not span too many lines","location":{"line":408,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","character":13},"severity":"warning","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 53 lines"},"text":" private func chunkByFileSizeWithStreaming(_ url: URL, maxBytes: Int64, config: ChunkingConfig, fileInfo: AudioFileInfo) async throws -> [AudioChunk] {"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","character":1,"line":423},"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 151 characters"},"text":" AppLog.shared.chunking(\"File analysis: \\(bytesPerSecond) bytes\/second, targeting \\(targetBytesPerChunk \/ 1024 \/ 1024)MB chunks\", level: .debug)"},{"violation":{"ruleName":"Line Length","severity":"warning","location":{"character":1,"line":441,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift"},"reason":"Line should be 120 characters or less; currently it has 135 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" try await exportAudioChunkWithStreaming(from: asset, startTime: chunkStartTime, endTime: chunkEndTime, outputURL: chunkURL)"},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":449},"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 134 characters","ruleName":"Line Length"},"text":" AppLog.shared.chunking(\"Chunk \\(sequenceNumber) is too large (\\(chunkSize) bytes > \\(maxBytes) bytes)\", level: .debug)"},{"violation":{"severity":"error","location":{"line":453,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","character":17},"ruleIdentifier":"shorthand_operator","ruleDescription":"Prefer shorthand operators (+=, -=, *=, \/=) over doing the operation and assigning","ruleName":"Shorthand Operator","reason":"Prefer shorthand operators (+=, -=, *=, \/=) over doing the operation and assigning"},"text":" adaptiveDuration = adaptiveDuration * 0.6"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 123 characters","severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"line":454,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift"},"ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.chunking(\"Adjusting chunk duration to \\(adaptiveDuration)s for future chunks\", level: .debug)"},{"violation":{"severity":"error","location":{"character":21,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":458},"ruleDescription":"Prefer shorthand operators (+=, -=, *=, \/=) over doing the operation and assigning","reason":"Prefer shorthand operators (+=, -=, *=, \/=) over doing the operation and assigning","ruleName":"Shorthand Operator","ruleIdentifier":"shorthand_operator"},"text":" adaptiveDuration = adaptiveDuration * 0.3 \/\/ Reduce by 70% for first chunk"},{"violation":{"severity":"warning","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":459},"reason":"Line should be 120 characters or less; currently it has 125 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"},"text":" AppLog.shared.chunking(\"First chunk too large, reducing duration to \\(adaptiveDuration)s\", level: .debug)"},{"violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 129 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":464}},"text":" AppLog.shared.chunking(\"Chunk smaller than expected, increasing duration to \\(adaptiveDuration)s\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","character":1,"line":478},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 148 characters","severity":"warning"},"text":" AppLog.shared.chunking(\"Chunk \\(sequenceNumber) created: \\(chunkSize) bytes, \\(chunkEndTime - chunkStartTime)s duration\", level: .debug)"},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":492},"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 163 characters","ruleDescription":"Lines should not span too many characters."},"text":" private func chunkByDurationWithStreaming(_ url: URL, maxSeconds: TimeInterval, config: ChunkingConfig, fileInfo: AudioFileInfo) async throws -> [AudioChunk] {"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 135 characters","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"line":518,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","character":1},"ruleIdentifier":"line_length"},"text":" try await exportAudioChunkWithStreaming(from: asset, startTime: chunkStartTime, endTime: chunkEndTime, outputURL: chunkURL)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 149 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":536,"character":1},"severity":"warning"},"text":" AppLog.shared.chunking(\"Chunk \\(sequenceNumber) created: \\(chunkSize) bytes, \\(actualEndTime - chunkStartTime)s duration\", level: .debug)"},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":550},"reason":"Line should be 120 characters or less; currently it has 146 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning"},"text":" private func exportAudioChunkWithStreaming(from asset: AVAsset, startTime: TimeInterval, endTime: TimeInterval, outputURL: URL) async throws {"},{"text":" private func chunkByCombinedStrategy(_ url: URL, maxBytes: Int64, maxSeconds: TimeInterval, config: ChunkingConfig, fileInfo: AudioFileInfo) async throws -> [AudioChunk] {","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":596,"character":1},"reason":"Line should be 120 characters or less; currently it has 175 characters"}},{"text":" private func chunkByCombinedStrategy(_ url: URL, maxBytes: Int64, maxSeconds: TimeInterval, config: ChunkingConfig, fileInfo: AudioFileInfo) async throws -> [AudioChunk] {","violation":{"ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":596,"character":13},"severity":"warning","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 59 lines","ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length"}},{"text":" AppLog.shared.chunking(\"Combined strategy: Duration limit \\(maxSeconds)s, Size-based duration limit \\(maxDurationFromSize)s\", level: .debug)","violation":{"severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"line":611,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift"},"reason":"Line should be 120 characters or less; currently it has 148 characters","ruleDescription":"Lines should not span too many characters."}},{"text":" try await exportAudioChunkWithStreaming(from: asset, startTime: chunkStartTime, endTime: chunkEndTime, outputURL: chunkURL)","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":629,"character":1},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 135 characters","ruleIdentifier":"line_length"}},{"text":" AppLog.shared.chunking(\"Chunk \\(sequenceNumber) exceeds size limit (\\(chunkSize) bytes > \\(maxBytes) bytes)\", level: .debug)","violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":638},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" adaptiveDuration = adaptiveDuration * 0.7 \/\/ Reduce by 30%","violation":{"reason":"Prefer shorthand operators (+=, -=, *=, \/=) over doing the operation and assigning","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","character":17,"line":639},"ruleIdentifier":"shorthand_operator","ruleDescription":"Prefer shorthand operators (+=, -=, *=, \/=) over doing the operation and assigning","ruleName":"Shorthand Operator"}},{"text":" AppLog.shared.chunking(\"Chunk \\(sequenceNumber) exceeds duration limit (\\(chunkDuration)s > \\(maxSeconds)s)\", level: .debug)","violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 140 characters","location":{"line":647,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift"},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"}},{"text":" AppLog.shared.chunking(\"Chunk \\(sequenceNumber) created: \\(chunkSize) bytes, \\(chunkDuration)s duration\", level: .debug)","violation":{"reason":"Line should be 120 characters or less; currently it has 132 characters","severity":"warning","location":{"line":668,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift"},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length"}},{"text":"}","violation":{"ruleDescription":"Files should not span too many lines.","location":{"line":690,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","character":1},"reason":"File should contain 400 lines or less: currently contains 690","ruleName":"File Length","ruleIdentifier":"file_length","severity":"warning"}},{"text":" init(type: JobType, recordingURL: URL, recordingName: String, modelName: String? = nil, sourceAudioURL: URL? = nil, chunks: [AudioChunk]? = nil) {","violation":{"location":{"character":1,"line":82,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"},"ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" init(id: UUID, type: JobType, recordingPath: String, recordingName: String, modelName: String? = nil, sourceAudioPath: String? = nil, status: JobProcessingStatus, progress: Double, startTime: Date, processingStartTime: Date? = nil, completionTime: Date?, chunks: [AudioChunk]?, error: String?) {","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":1,"line":135},"reason":"Line should be 200 characters or less; currently it has 299 characters","severity":"error","ruleIdentifier":"line_length"}},{"text":" throw DecodingError.dataCorruptedError(forKey: .engine, in: container, debugDescription: \"Invalid TranscriptionEngine value: \\(engineRawValue)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":204,"character":1},"reason":"Line should be 120 characters or less; currently it has 160 characters","ruleDescription":"Lines should not span too many characters."}},{"text":"class BackgroundProcessingManager: ObservableObject {","violation":{"ruleName":"Type Body Length","ruleIdentifier":"type_body_length","severity":"error","ruleDescription":"Type bodies should not span too many lines","location":{"character":1,"line":307,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 1709 lines"}},{"text":" AppLog.shared.backgroundProcessing(\"Skipping automatic job resume because previous session crashed\", level: .error)","violation":{"severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":375},"reason":"Line should be 120 characters or less; currently it has 131 characters","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"text":" func startTranscriptionJob(recordingURL: URL, recordingName: String, engine: TranscriptionEngine, modelName: String? = nil, sourceAudioURL: URL? = nil, chunks: [AudioChunk]? = nil) async throws {","violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 199 characters","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":436,"character":1}}},{"text":" func startSummarizationJob(recordingURL: URL, recordingName: String, engine: String, modelName: String? = nil, replacingSummaryId: UUID? = nil) async throws -> UUID {","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 170 characters","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":461,"character":1}}},{"text":" AppLog.shared.backgroundProcessing(\"Debug Status: activeJobs=\\(activeJobs.count), currentJob=\\(currentJob != nil), status=\\(processingStatus), bgTaskID=\\(backgroundTaskID.rawValue)\", level: .debug)","violation":{"ruleIdentifier":"line_length","location":{"character":1,"line":543,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"},"reason":"Line should be 200 characters or less; currently it has 205 characters","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" AppLog.shared.backgroundProcessing(\"Job \\(index): status=\\(job.status), progress=\\(job.progress)\", level: .debug)","violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"line":546,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":1},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"trackExternalJob: \\(job.type.displayName) - activeJobs count before: \\(activeJobs.count)\", level: .debug)","violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"line":563,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"},"reason":"Line should be 120 characters or less; currently it has 149 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.backgroundProcessing(\"trackExternalJob done: activeJobs count after: \\(activeJobs.count)\", level: .debug)","violation":{"ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":565,"character":1},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 127 characters","severity":"warning"}},{"text":" AppLog.shared.backgroundProcessing(\"updateExternalJob: status=\\(job.status.displayName), activeJobs count: \\(activeJobs.count)\", level: .debug)","violation":{"reason":"Line should be 120 characters or less; currently it has 151 characters","ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"line":574,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"}}},{"text":" AppLog.shared.backgroundProcessing(\"Job already exists for \\(job.type.displayName). Skipping duplicate. Existing: \\(existingJobs.map { \"\\($0.id) status=\\($0.status.displayName)\" })\")","violation":{"ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":1,"line":605},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 194 characters","ruleIdentifier":"line_length"}},{"text":" AppLog.shared.backgroundProcessing(\"Marked \\(failedCount) unfinished job(s) failed after crash to prevent automatic restart\", level: .error)","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"line":720,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"},"reason":"Line should be 120 characters or less; currently it has 152 characters"}},{"text":" func processNextJob() async {","violation":{"reason":"Function should have complexity 10 or less; currently complexity is 14","location":{"character":5,"line":724,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"},"ruleName":"Cyclomatic Complexity","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","severity":"warning"}},{"text":" func processNextJob() async {","violation":{"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 91 lines","ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length","severity":"warning","location":{"line":724,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":5}}},{"text":" AppLog.shared.backgroundProcessing(\"Starting job: \\(nextJob.type.displayName), engine=\\(nextJob.type.engineName)\\(nextJob.modelName.map { \", model=\\($0)\" } ?? \"\"), fileExists=\\(FileManager.default.fileExists(atPath: nextJob.audioSourceURL.path))\")","violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"line":745,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":1},"severity":"error","reason":"Line should be 200 characters or less; currently it has 255 characters","ruleName":"Line Length"}},{"text":" AppLog.shared.backgroundProcessing(\"Job already terminal (\\(currentStatus.displayName)): \\(nextJob.type.displayName)\")","violation":{"reason":"Line should be 120 characters or less; currently it has 138 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":783,"character":1},"ruleIdentifier":"line_length"}},{"text":" body: \"\\(nextJob.recordingName) β€” \\(nextJob.type.engineName)\\(modelInfo). Open the app to resume.\"","violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":1,"line":798},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 122 characters","ruleName":"Line Length"}},{"text":" AppLog.shared.backgroundProcessing(\"Job already terminal (\\(currentStatus.displayName)): \\(nextJob.type.displayName), error was: \\(error.localizedDescription)\", level: .error)","violation":{"location":{"line":815,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"},"ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 195 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning"}},{"text":" AppLog.shared.backgroundProcessing(\"Job failed: \\(nextJob.type.displayName), error: \\(error.localizedDescription)\", level: .error)","violation":{"reason":"Line should be 120 characters or less; currently it has 150 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","location":{"line":820,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"},"ruleName":"Line Length"}},{"text":" private func processTranscriptionJob(_ job: ProcessingJob, engine: TranscriptionEngine) async throws {","violation":{"ruleIdentifier":"cyclomatic_complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleName":"Cyclomatic Complexity","reason":"Function should have complexity 10 or less; currently complexity is 15","location":{"line":884,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":13}}},{"text":" private func processTranscriptionJob(_ job: ProcessingJob, engine: TranscriptionEngine) async throws {","violation":{"severity":"error","location":{"line":884,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"},"ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 136 lines","ruleName":"Function Body Length"}},{"text":" EnhancedLogger.shared.logBackgroundProcessing(\"File needs chunking for \\(engine.rawValue)\", level: .info)","violation":{"reason":"Line should be 120 characters or less; currently it has 121 characters","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":909},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning"}},{"text":" \"Skipping final FluidAudio chunk under SDK minimum: seq=\\(chunk.sequenceNumber), duration=\\(chunk.duration)s\",","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 130 characters","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":953}}},{"text":" EnhancedLogger.shared.logBackgroundProcessing(\"Chunk \\(index + 1) transcribed: \\(transcriptResult.fullText.count) characters\", level: .debug)","violation":{"severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 153 characters","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":971,"character":1},"ruleIdentifier":"line_length"}},{"text":" EnhancedLogger.shared.logBackgroundProcessing(\"Reassembling transcript from \\(transcriptChunks.count) chunks\", level: .info)","violation":{"reason":"Line should be 120 characters or less; currently it has 136 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":976,"character":1}}},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 122 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":991,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":1}},"text":" AppLog.shared.backgroundProcessing(\"No recording found for reassembly, using new UUID\", level: .error)"},{"violation":{"severity":"warning","ruleDescription":"TODOs and FIXMEs should be resolved.","ruleIdentifier":"todo","reason":"TODOs should be resolved (Get actual recording date)","ruleName":"Todo","location":{"character":43,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1003}},"text":" recordingDate: Date(), \/\/ TODO: Get actual recording date"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1024,"character":1},"ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 124 characters"},"text":" AppLog.shared.backgroundProcessing(\"No recording found for single chunk, using new UUID\", level: .error)"},{"violation":{"ruleIdentifier":"todo","severity":"warning","ruleName":"Todo","reason":"TODOs should be resolved (Get actual recording date)","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1036,"character":43},"ruleDescription":"TODOs and FIXMEs should be resolved."},"text":" recordingDate: Date(), \/\/ TODO: Get actual recording date"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1048,"character":1},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 140 characters"},"text":" AppLog.shared.backgroundProcessing(\"Chunk cleanup failed after transcription: \\(error.localizedDescription)\", level: .error)"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","location":{"line":1053,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 135 characters","ruleDescription":"Lines should not span too many characters."},"text":" let hasTranscriptContent = transcriptChunks.contains { !$0.transcript.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty }"},{"violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":1,"line":1056},"reason":"Line should be 120 characters or less; currently it has 165 characters"},"text":" AppLog.shared.backgroundProcessing(\"Transcription job completed but no transcript content found! Total chunks: \\(transcriptChunks.count)\", level: .error)"},{"violation":{"severity":"warning","location":{"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1082},"reason":"Function should have complexity 10 or less; currently complexity is 16","ruleIdentifier":"cyclomatic_complexity","ruleDescription":"Complexity of function bodies should be limited.","ruleName":"Cyclomatic Complexity"},"text":" private func transcribeChunk(_ chunk: AudioChunk, engine: TranscriptionEngine) async throws -> TranscriptionResult {"},{"violation":{"ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length","severity":"error","location":{"character":13,"line":1082,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 105 lines","ruleIdentifier":"function_body_length"},"text":" private func transcribeChunk(_ chunk: AudioChunk, engine: TranscriptionEngine) async throws -> TranscriptionResult {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1083,"character":1},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 124 characters","ruleName":"Line Length","severity":"warning"},"text":" AppLog.shared.backgroundProcessing(\"Starting transcription of chunk with engine: \\(engine.rawValue)\", level: .debug)"},{"violation":{"reason":"Line should be 200 characters or less; currently it has 214 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"error","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1084,"character":1}},"text":" AppLog.shared.backgroundProcessing(\"Chunk details: seq=\\(chunk.sequenceNumber), duration=\\(chunk.duration)s, size=\\(chunk.fileSize) bytes, isWholeFile=\\(chunk.originalURL == chunk.chunkURL)\", level: .debug)"},{"violation":{"ruleName":"Line Length","location":{"character":1,"line":1096,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"},"reason":"Line should be 120 characters or less; currently it has 121 characters","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.backgroundProcessing(\"Chunk file is empty: \\(chunk.chunkURL.lastPathComponent)\", level: .error)"},{"text":" AppLog.shared.backgroundProcessing(\"Chunk file verified: \\(fileSize) bytes, duration: \\(chunk.duration)s\", level: .debug)","violation":{"location":{"line":1100,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"},"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Recording not found in Core Data for chunk, using fallback UUID\", level: .debug)","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 128 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":1,"line":1111},"ruleDescription":"Lines should not span too many characters.","severity":"warning"}},{"text":" throw BackgroundProcessingError.processingFailed(\"Transcription engine not configured. Please configure a transcription engine in Settings.\")","violation":{"reason":"Line should be 120 characters or less; currently it has 157 characters","location":{"line":1120,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":1},"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"}},{"text":" throw BackgroundProcessingError.processingFailed(\"On-device model not downloaded. Please download the Parakeet model in Settings > Transcription > On Device.\")","violation":{"reason":"Line should be 120 characters or less; currently it has 179 characters","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1155},"severity":"warning","ruleDescription":"Lines should not span too many characters."}},{"text":" throw BackgroundProcessingError.processingFailed(\"OpenAI API Compatible integration not yet implemented\")","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","location":{"line":1174,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"},"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Transcription result is empty. Success: \\(result.success), Segments: \\(result.segments.count)\\(result.error.map { \", error: \\($0.localizedDescription)\" } ?? \"\")\")","violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"error","location":{"line":1182,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":1},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 200 characters or less; currently it has 214 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Audio chunk contains no speech content (silent or background noise)\", level: .debug)","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1184,"character":1},"ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 140 characters","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.backgroundProcessing(\"Empty result may indicate processing error or invalid audio format\", level: .error)","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 139 characters","location":{"line":1186,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"},"severity":"warning","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.backgroundProcessing(\"Transcription successful: \\(result.fullText.count) characters, \\(result.segments.count) segments\")","violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 150 characters","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"character":1,"line":1199,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"}}},{"text":" AppLog.shared.backgroundProcessing(\"Transcription failed after \\(String(format: \"%.1f\", processingTime))s: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 165 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1209}}},{"text":" throw BackgroundProcessingError.processingFailed(\"Transcription failed for \\(engine.rawValue): \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":1,"line":1212},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" let modelString = UserDefaults.standard.string(forKey: \"openAIModel\") ?? OpenAITranscribeModel.gpt4oMiniTranscribe.rawValue","violation":{"reason":"Line should be 120 characters or less; currently it has 131 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":1,"line":1220}}},{"violation":{"reason":"Line should be 120 characters or less; currently it has 141 characters","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1234},"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning"},"text":" let modelString = UserDefaults.standard.string(forKey: \"mistralTranscribeModel\") ?? MistralTranscribeModel.voxtralMiniLatest.rawValue"},{"violation":{"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 128 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1256},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.backgroundProcessing(\"Whisper config: port=\\(port), protocol=\\(selectedProtocol.rawValue)\", level: .debug)"},{"violation":{"ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1323,"character":1},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 124 characters"},"text":" AppLog.shared.backgroundProcessing(\"Error getting audio duration: \\(error.localizedDescription)\", level: .error)"},{"violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":1365,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 165 characters","ruleIdentifier":"line_length"},"text":" AppLog.shared.backgroundProcessing(\"Saved transcript: \\(transcriptData.segments.count) segments, \\(transcriptData.fullText.count) characters\", level: .debug)"},{"violation":{"ruleIdentifier":"function_body_length","ruleName":"Function Body Length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 93 lines","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":13,"line":1378},"ruleDescription":"Function bodies should not span too many lines"},"text":" private func processSummarizationJob(_ job: ProcessingJob, engine: String) async throws {"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 121 characters","ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1390},"severity":"warning"},"text":" throw BackgroundProcessingError.processingFailed(\"Recording not found in Core Data for \\(job.recordingName)\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1396,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"},"text":" throw BackgroundProcessingError.processingFailed(\"No transcript found for \\(job.recordingName). Transcribe the recording first.\")"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 154 characters","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1510}},"text":" private func generateSummary(_ transcriptText: String, engine: String, recordingURL: URL, recordingName: String) async throws -> EnhancedSummaryData {"},{"violation":{"severity":"warning","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 61 lines","ruleName":"Function Body Length","ruleDescription":"Function bodies should not span too many lines","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1510,"character":13},"ruleIdentifier":"function_body_length"},"text":" private func generateSummary(_ transcriptText: String, engine: String, recordingURL: URL, recordingName: String) async throws -> EnhancedSummaryData {"},{"violation":{"location":{"line":1535,"character":16,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"},"ruleDescription":"TODOs and FIXMEs should be resolved.","ruleName":"Todo","ruleIdentifier":"todo","severity":"warning","reason":"TODOs should be resolved (Integrate with Ollama service ...)"},"text":" \/\/ TODO: Integrate with Ollama service when available"},{"violation":{"ruleName":"Todo","ruleIdentifier":"todo","ruleDescription":"TODOs and FIXMEs should be resolved.","location":{"line":1577,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":39},"reason":"TODOs should be resolved (Get actual recording date from...)","severity":"warning"},"text":" recordingDate: Date(), \/\/ TODO: Get actual recording date from file metadata"},{"violation":{"severity":"warning","ruleIdentifier":"line_length","location":{"line":1592,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"},"reason":"Line should be 120 characters or less; currently it has 137 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" let modelString = UserDefaults.standard.string(forKey: \"openAISummarizationModel\") ?? OpenAISummarizationModel.gpt41Mini.rawValue"},{"violation":{"ruleName":"Line Length","location":{"line":1612,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 122 characters"},"text":" if lowercaseText.contains(\"meeting\") || lowercaseText.contains(\"discussion\") || lowercaseText.contains(\"agenda\") {"},{"violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 122 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1614,"character":1}},"text":" } else if lowercaseText.contains(\"technical\") || lowercaseText.contains(\"code\") || lowercaseText.contains(\"api\") {"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"line":1616,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"},"reason":"Line should be 120 characters or less; currently it has 126 characters"},"text":" } else if lowercaseText.contains(\"personal\") || lowercaseText.contains(\"diary\") || lowercaseText.contains(\"journal\") {"},{"violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 136 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1818,"character":1}},"text":" AppLog.shared.backgroundProcessing(\"Failed to schedule background processing: \\(error.localizedDescription)\", level: .error)"},{"violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"line":1831,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"},"reason":"Line should be 120 characters or less; currently it has 140 characters"},"text":" AppLog.shared.backgroundProcessing(\"Skipping automatic foreground job recovery because previous session crashed\", level: .error)"},{"violation":{"ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","severity":"warning","location":{"line":1852,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"},"reason":"Function should have complexity 10 or less; currently complexity is 13","ruleName":"Cyclomatic Complexity"},"text":" private func resumeInterruptedJobs(notify: Bool = true) async {"},{"violation":{"severity":"warning","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","location":{"character":13,"line":1852,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"},"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"},"text":" private func resumeInterruptedJobs(notify: Bool = true) async {"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 129 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":1,"line":1854},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" AppLog.shared.backgroundProcessing(\"Skipping interrupted job resume because previous session crashed\", level: .error)"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1864,"character":1},"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 134 characters"},"text":" return message.contains(\"interrupted\") || message.contains(\"App was terminated\") || message.contains(\"App was closed\")"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 130 characters","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":1,"line":1951}},"text":" private func checkTranscriptionEngineAvailability(_ engine: TranscriptionEngine) async -> (available: Bool, reason: String?) {"},{"violation":{"ruleName":"Line Length","location":{"line":2041,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":1},"ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 145 characters","ruleDescription":"Lines should not span too many characters."},"text":" body: \"\\(job.recordingName) β€” \\(job.type.engineName)\\(modelInfo) was stopped because the app was closed. Open the app to resume.\""},{"violation":{"reason":"Line should be 120 characters or less; currently it has 129 characters","severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"line":2083,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"}},"text":" let engine = TranscriptionEngine(rawValue: jobEntry.engine ?? TranscriptionEngine.fluidAudio.rawValue) ?? .fluidAudio"},{"text":" let buffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: AVAudioFrameCount(frameCount)) else {","violation":{"severity":"warning","location":{"line":2143,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"},"reason":"Line should be 120 characters or less; currently it has 123 characters","ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.backgroundProcessing(\"Failed to start keep-alive audio: \\(error.localizedDescription)\", level: .error)","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":2170,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"},"reason":"Line should be 120 characters or less; currently it has 128 characters","ruleName":"Line Length"}},{"text":" AppLog.shared.backgroundProcessing(\"After audio session config: \\(Int(backgroundTime))s background time\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"line":2204,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters","ruleIdentifier":"line_length"}},{"text":" AppLog.shared.backgroundProcessing(\"After audio session config: Unlimited background time\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2206},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 122 characters","ruleName":"Line Length"}},{"text":" AppLog.shared.backgroundProcessing(\"CRITICAL: Could not configure background audio session: \\(error.localizedDescription). This will severely limit background processing time.\", level: .error)","violation":{"ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2211,"character":1},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"error","reason":"Line should be 200 characters or less; currently it has 204 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Could not deactivate audio session: \\(error.localizedDescription)\", level: .error)","violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 130 characters","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2229,"character":1}}},{"text":" AppLog.shared.backgroundProcessing(\"Background task already running: \\(backgroundTaskID.rawValue)\", level: .debug)","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 126 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2246}}},{"text":" \"AudioProcessing-\\(currentJob.type.displayName.replacingOccurrences(of: \" \", with: \"\"))-\\(currentJob.recordingName.prefix(20))\"","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2252,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.backgroundProcessing(\"Failed to start background task. Check background modes, device resources, or Background App Refresh setting.\", level: .error)","violation":{"ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":1,"line":2265},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 174 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Background time: Unlimited (likely in foreground or audio session active)\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"line":2275,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 142 characters","ruleIdentifier":"line_length"}},{"text":" AppLog.shared.backgroundProcessing(\"CRITICAL: Very limited background time (\\(Int(remainingTime))s). Check Background App Refresh, Low Power Mode.\", level: .error)","violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2281,"character":1},"reason":"Line should be 120 characters or less; currently it has 183 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length"}},{"text":" AppLog.shared.backgroundProcessing(\"Limited background time (\\(Int(remainingTime))s). Audio session may not be properly configured.\", level: .error)","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":1,"line":2283},"reason":"Line should be 120 characters or less; currently it has 168 characters","severity":"warning"}},{"text":" AppLog.shared.backgroundProcessing(\"Background task expiration handled β€” Task catch block will complete cleanup\")","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 121 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2326,"character":1},"severity":"warning"}},{"text":" \/\/ Skip monitoring and refreshing if we have unlimited time (app is likely in foreground or has special privileges\/audio session active)","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2334,"character":1},"reason":"Line should be 120 characters or less; currently it has 144 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"}},{"text":" AppLog.shared.backgroundProcessing(\"Background task age: \\(Int(taskAge))s - refreshing to avoid iOS warning\", level: .debug)","violation":{"reason":"Line should be 120 characters or less; currently it has 140 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2342}}},{"text":" AppLog.shared.backgroundProcessing(\"Background time running low (\\(Int(remainingTime))s remaining)\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":1,"line":2352},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Current job: \\(job.type.displayName) - Progress: \\(Int(job.progress * 100))%\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":1,"line":2356},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 145 characters","severity":"warning"}},{"text":" AppLog.shared.backgroundProcessing(\"Background time critically low (\\(Int(remainingTime))s), will attempt graceful shutdown soon\", level: .error)","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 157 characters","ruleName":"Line Length","location":{"line":2362,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"}}},{"text":" AppLog.shared.backgroundProcessing(\"Background time almost expired (\\(Int(remainingTime))s), initiating graceful shutdown\", level: .error)","violation":{"location":{"line":2368,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":1},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 150 characters","ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.backgroundProcessing(\"Notification permission request failed: \\(error.localizedDescription)\", level: .debug)","violation":{"severity":"warning","ruleIdentifier":"line_length","location":{"character":1,"line":2425,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Failed to send notification: \\(error.localizedDescription)\", level: .error)","violation":{"location":{"line":2455,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"},"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Failed to clear notification badge: \\(error.localizedDescription)\", level: .error)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"line":2496,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift"},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Leaving reconciled jobs stopped because previous session crashed\", level: .error)","violation":{"reason":"Line should be 120 characters or less; currently it has 133 characters","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2557},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"}},{"text":" AppLog.shared.backgroundProcessing(\"Failed to update job in Core Data: \\(error.localizedDescription)\", level: .error)","violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","character":1,"line":2593},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 133 characters","ruleName":"Line Length"}},{"violation":{"reason":"File should contain 1000 lines or less: currently contains 2716","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2716,"character":1},"ruleIdentifier":"file_length","ruleDescription":"Files should not span too many lines.","ruleName":"File Length"},"text":"}"},{"violation":{"ruleIdentifier":"type_body_length","ruleDescription":"Type bodies should not span too many lines","reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 707 lines","ruleName":"Type Body Length","severity":"error","location":{"character":1,"line":20,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift"}},"text":"struct BisonNotesAIApp: App {"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":81},"reason":"Line should be 120 characters or less; currently it has 143 characters"},"text":" NSLog(\"βœ… AI engine migrated from '\\(currentAIEngine ?? \"nil\")' to 'MLX Swift' (model: \\(defaultModelId), RAM: \\(deviceRAM)GB)\")"},{"violation":{"severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 150 characters","location":{"line":94,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","character":1},"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"},"text":" NSLog(\"βœ… Transcription engine migrated from '\\(currentTranscriptionEngine ?? \"nil\")' to '\\(TranscriptionEngine.fluidAudio.rawValue)'\")"},{"violation":{"location":{"line":99,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift"},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 140 characters","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" NSLog(\"βœ… Transcription engine migrated from '\\(currentTranscriptionEngine ?? \"nil\")' to 'Mistral AI' (device has <4GB RAM)\")"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 124 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":141}},"text":" let legacyOnDeviceValues = [\"On Device (WhisperKit)\", \"On Device\", \"WhisperKit\", \"On-Device\", \"Apple Transcription\"]"},{"violation":{"ruleDescription":"Lines should not span too many characters.","location":{"line":158,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","character":1},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 128 characters","ruleName":"Line Length","ruleIdentifier":"line_length"},"text":" let parakeetAlreadyDownloaded = UserDefaults.standard.bool(forKey: FluidAudioModelInfo.SettingsKeys.modelDownloaded)"},{"violation":{"ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","character":1,"line":263},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 134 characters","severity":"warning"},"text":" NSLog(\"βœ… Enabled experimental models because user had '\\(OnDeviceLLMModelInfo.granite4H.id)' selected (now experimental)\")"},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":397},"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 130 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.general(\"Downgraded existing file protection class to completeUntilFirstUserAuthentication (1.11 β†’ 1.11.1)\")"},{"violation":{"location":{"character":13,"line":452,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift"},"ruleName":"Function Body Length","ruleDescription":"Function bodies should not span too many lines","severity":"warning","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 53 lines","ruleIdentifier":"function_body_length"},"text":" private func queueParakeetStartupRepairIfNeeded() {"},{"violation":{"location":{"character":1,"line":501,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift"},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 122 characters","ruleIdentifier":"line_length","severity":"warning"},"text":" \"Parakeet startup repair: selected model is missing or incomplete; starting Wi-Fi background download\""},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 122 characters","location":{"character":1,"line":533,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift"}},"text":" .onReceive(NotificationCenter.default.publisher(for: UIApplication.didFinishLaunchingNotification)) { _ in"},{"text":" .onReceive(NotificationCenter.default.publisher(for: UIApplication.didEnterBackgroundNotification)) { _ in","violation":{"reason":"Line should be 120 characters or less; currently it has 122 characters","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":546}}},{"text":" .onReceive(NotificationCenter.default.publisher(for: Notification.Name(\"ShareExtensionDidSaveFile\"))) { _ in","violation":{"location":{"line":569,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift"},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 124 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"}},{"text":" NotificationCenter.default.post(name: NSNotification.Name(\"NavigateToSection\"), object: \"transcripts\")","violation":{"ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":617},"severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 122 characters","ruleDescription":"Lines should not span too many characters."}},{"text":" \/\/\/ Handles files opened from the share sheet (e.g. Voice Memos, Files). Imports audio as recordings, text as transcripts.","violation":{"reason":"Line should be 120 characters or less; currently it has 126 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","character":1,"line":630},"ruleIdentifier":"line_length","ruleName":"Line Length"}},{"text":" NSLog(\"πŸ“Ž handleOpenURL called (scheme: \\(url.scheme ?? \"nil\"), host: \\(url.host ?? \"nil\"), file: \\(url.isFileURL ? url.lastPathComponent : \"none\"))\")","violation":{"ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 157 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":633},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":" private func scanSharedContainerForImports(trigger: SharedContainerImportTrigger) {","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":695,"character":13},"ruleIdentifier":"cyclomatic_complexity","reason":"Function should have complexity 10 or less; currently complexity is 13","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleName":"Cyclomatic Complexity"}},{"text":" private func scanSharedContainerForImports(trigger: SharedContainerImportTrigger) {","violation":{"ruleIdentifier":"function_body_length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 52 lines","ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length","severity":"warning","location":{"line":695,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","character":13}}},{"text":" private func scanInboxForImportableFiles() {","violation":{"ruleName":"Cyclomatic Complexity","ruleDescription":"Complexity of function bodies should be limited.","reason":"Function should have complexity 10 or less; currently complexity is 13","ruleIdentifier":"cyclomatic_complexity","location":{"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":770},"severity":"warning"}},{"text":" guard let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }","violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 125 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":773}}},{"text":" let remaining = (try? FileManager.default.contentsOfDirectory(at: inboxURL, includingPropertiesForKeys: nil)) ?? []","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":826,"character":1},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" handleBackgroundProcessing(task: task as! BGProcessingTask)","violation":{"ruleIdentifier":"force_cast","severity":"error","reason":"Force casts should be avoided","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":869,"character":51},"ruleDescription":"Force casts should be avoided","ruleName":"Force Cast"}},{"text":" handleAppRefresh(task: task as! BGAppRefreshTask)","violation":{"ruleDescription":"Force casts should be avoided","severity":"error","reason":"Force casts should be avoided","ruleIdentifier":"force_cast","ruleName":"Force Cast","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","character":41,"line":873}}},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":897,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"},"text":" AppLog.shared.general(\"Skipping background job processing because previous session crashed\", level: .error)"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","character":20,"line":980},"reason":"Prefer `!= nil` over `let _ =`","ruleIdentifier":"unused_optional_binding","ruleDescription":"Prefer `!= nil` over `let _ =`","ruleName":"Unused Optional Binding","severity":"warning"},"text":" let _ = try? FileManager.default.contentsOfDirectory(at: plugInsURL, includingPropertiesForKeys: nil) {"},{"violation":{"ruleIdentifier":"file_length","location":{"character":1,"line":1009,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift"},"reason":"File should contain 1000 lines or less: currently contains 1009","ruleName":"File Length","ruleDescription":"Files should not span too many lines.","severity":"error"},"text":"}"},{"violation":{"ruleIdentifier":"type_body_length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleName":"Type Body Length","location":{"line":13,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ContentAnalyzer.swift"},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 428 lines"},"text":"class ContentAnalyzer {"},{"violation":{"severity":"error","ruleName":"Line Length","reason":"Line should be 200 characters or less; currently it has 245 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ContentAnalyzer.swift","line":28},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" AppLogger.shared.verbose(\"Classification scores - Meeting: \\(String(format: \"%.3f\", meetingScore)), Journal: \\(String(format: \"%.3f\", journalScore)), Technical: \\(String(format: \"%.3f\", technicalScore))\", category: \"ContentAnalyzer\")"},{"violation":{"ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ContentAnalyzer.swift","character":1,"line":46},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 157 characters"},"text":" AppLogger.shared.verbose(\"Classified as \\(match.0.rawValue) with confidence \\(String(format: \"%.3f\", match.1))\", category: \"ContentAnalyzer\")"},{"violation":{"ruleIdentifier":"line_length","location":{"line":53,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ContentAnalyzer.swift","character":1},"reason":"Line should be 200 characters or less; currently it has 211 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"error"},"text":" AppLogger.shared.verbose(\"Classified as General (best score: \\(String(format: \"%.3f\", bestMatch?.1 ?? 0.0)) < threshold: \\(String(format: \"%.3f\", confidenceThreshold)))\", category: \"ContentAnalyzer\")"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ContentAnalyzer.swift","line":172,"character":13},"reason":"Variable name 'i' should be between 3 and 40 characters long","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","ruleName":"Identifier Name"},"text":" for i in 0.. [EnhancedRecoveryAction] {"},{"violation":{"severity":"error","reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 146 lines","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedErrorHandlingSystem.swift","line":631,"character":13}},"text":" private func suggestBackgroundProcessingRecovery(_ error: BackgroundProcessingError) -> [EnhancedRecoveryAction] {"},{"violation":{"ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length","reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 107 lines","location":{"line":789,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedErrorHandlingSystem.swift","character":13},"ruleIdentifier":"function_body_length","severity":"error"},"text":" private func suggestChunkingRecovery(_ error: AudioChunkingError) -> [EnhancedRecoveryAction] {"},{"violation":{"severity":"error","ruleDescription":"Function bodies should not span too many lines","location":{"line":928,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedErrorHandlingSystem.swift"},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 122 lines","ruleName":"Function Body Length","ruleIdentifier":"function_body_length"},"text":" private func suggestFileManagementRecovery(_ error: FileManagementError) -> [EnhancedRecoveryAction] {"},{"violation":{"ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length","location":{"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedErrorHandlingSystem.swift","line":1060},"severity":"warning","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 92 lines"},"text":" private func suggestSystemRecovery(_ error: SystemError) -> [EnhancedRecoveryAction] {"},{"violation":{"reason":"File should contain 1000 lines or less: currently contains 1159","ruleName":"File Length","location":{"line":1159,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedErrorHandlingSystem.swift"},"severity":"error","ruleIdentifier":"file_length","ruleDescription":"Files should not span too many lines."},"text":"}"},{"violation":{"severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"line":16,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift"},"reason":"Line should be 120 characters or less; currently it has 163 characters","ruleDescription":"Lines should not span too many characters."},"text":" init(recordingURL: URL?, recordingName: String, recordingDate: Date, transcriptExists: Bool = false, summaryExists: Bool = false, iCloudSynced: Bool = false) {"},{"violation":{"ruleIdentifier":"type_body_length","severity":"error","reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 420 lines","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":113,"character":1},"ruleName":"Type Body Length","ruleDescription":"Type bodies should not span too many lines"},"text":"class EnhancedFileManager: ObservableObject {"},{"violation":{"location":{"line":201,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","character":37},"ruleName":"Todo","ruleIdentifier":"todo","ruleDescription":"TODOs and FIXMEs should be resolved.","severity":"warning","reason":"TODOs should be resolved (Implement actual iCloud sync c...)"},"text":" let iCloudSynced = false \/\/ TODO: Implement actual iCloud sync check"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 125 characters","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":225},"ruleIdentifier":"line_length"},"text":" AppLog.shared.fileManagement(\"Cleaned up non-existent file relationship for: \\(normalizedURL.lastPathComponent)\")"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":229,"character":5},"ruleDescription":"Complexity of function bodies should be limited.","ruleName":"Cyclomatic Complexity","reason":"Function should have complexity 10 or less; currently complexity is 17","ruleIdentifier":"cyclomatic_complexity","severity":"warning"},"text":" func refreshAllRelationships() {"},{"violation":{"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 79 lines","ruleName":"Function Body Length","ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines","severity":"warning","location":{"character":5,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":229}},"text":" func refreshAllRelationships() {"},{"violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 157 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":244}},"text":" let fileURLs = try FileManager.default.contentsOfDirectory(at: documentsURL, includingPropertiesForKeys: [.creationDateKey], options: [])"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 131 characters","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","character":1,"line":247},"ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" return fileExtension == \"m4a\" || fileExtension == \"mp3\" || fileExtension == \"wav\" || fileExtension == \"aac\""},{"violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 181 characters","ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":292,"character":1}},"text":" AppLog.shared.fileManagement(\"Removed \\(removedFiles.count) non-existent file relationships (\\(uniqueRemoved.count) unique files, \\(duplicateCount) duplicates)\")"},{"violation":{"reason":"Function should have complexity 10 or less; currently complexity is 13","ruleIdentifier":"cyclomatic_complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleName":"Cyclomatic Complexity","location":{"character":5,"line":336,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift"}},"text":" func deleteRecording(_ url: URL, preserveSummary: Bool) async throws {"},{"violation":{"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 73 lines","severity":"warning","ruleName":"Function Body Length","location":{"line":336,"character":5,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift"},"ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines"},"text":" func deleteRecording(_ url: URL, preserveSummary: Bool) async throws {"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 147 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":359},"ruleIdentifier":"line_length"},"text":" AppLog.shared.fileManagement(\"Thumbnail generation warning during file deletion: \\(error.localizedDescription)\", level: .debug)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 162 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":375,"character":1},"ruleName":"Line Length","severity":"warning"},"text":" AppLog.shared.fileManagement(\"Thumbnail generation warning during \\(ext) file deletion: \\(error.localizedDescription)\", level: .debug)"},{"violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"line":533,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift"},"reason":"Line should be 120 characters or less; currently it has 128 characters","ruleIdentifier":"line_length"},"text":" AppLog.shared.fileManagement(\"File does not exist, using current date for: \\(url.lastPathComponent)\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":541,"character":1},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 125 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" AppLog.shared.fileManagement(\"Error getting creation date for \\(url.lastPathComponent): \\(error)\", level: .error)"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":605,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift"},"reason":"Line should be 120 characters or less; currently it has 130 characters"},"text":" AppLog.shared.fileManagement(\"Normalized \\(duplicateCount) duplicate URL entries when loading file relationships\")"},{"violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 121 characters","ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","character":1,"line":622}},"text":" let allFiles = try FileManager.default.contentsOfDirectory(at: documentsURL, includingPropertiesForKeys: nil)"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":641,"character":17},"severity":"warning","ruleName":"Prefer For-Where","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","reason":"`where` clauses are preferred over a single `if` inside a `for`"},"text":" if !coreDataURLs.contains(audioFile.path) {"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 144 characters","location":{"line":658,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","character":1},"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" func cleanupOrphanedAudioFiles(coordinator: AppDataCoordinator, dryRun: Bool = true) -> (deleted: Int, totalSize: Int64, errors: [String]) {"},{"violation":{"location":{"character":93,"line":658,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift"},"ruleName":"Large Tuple","severity":"warning","reason":"Tuples should have at most 2 members","ruleIdentifier":"large_tuple","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead."},"text":" func cleanupOrphanedAudioFiles(coordinator: AppDataCoordinator, dryRun: Bool = true) -> (deleted: Int, totalSize: Int64, errors: [String]) {"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 126 characters","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","location":{"line":681,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift"},"ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.fileManagement(\"Would delete: \\(file.lastPathComponent) (\\(fileSize) bytes)\", level: .debug)"},{"text":" let errorMsg = \"Failed to \\(dryRun ? \"analyze\" : \"delete\") \\(file.lastPathComponent): \\(error.localizedDescription)\"","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 132 characters","location":{"line":685,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","character":1},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" AppLog.shared.fileManagement(\"Dry run complete: Found \\(orphanedFiles.count) orphaned files totaling \\(totalSize) bytes\")","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 133 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":692}}},{"text":"}","violation":{"severity":"warning","ruleName":"File Length","location":{"line":733,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","character":1},"reason":"File should contain 400 lines or less: currently contains 733","ruleIdentifier":"file_length","ruleDescription":"Files should not span too many lines."}},{"text":" func logAudioSessionConfiguration(_ category: AVAudioSession.Category, mode: AVAudioSession.Mode, options: AVAudioSession.CategoryOptions) {","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"line":369,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedLoggingSystem.swift"},"reason":"Line should be 120 characters or less; currently it has 144 characters","ruleName":"Line Length","ruleIdentifier":"line_length"}},{"text":" backgroundProcessing(\"Background job failed: \\(job.type.displayName) for \\(job.recordingName) - \\(error.localizedDescription)\", level: .error)","violation":{"severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"line":400,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedLoggingSystem.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters","ruleDescription":"Lines should not span too many characters."}},{"text":" fileManagement(\"File relationship updated for \\(recordingURL.lastPathComponent) - Transcript: \\(transcriptExists), Summary: \\(summaryExists)\", level: .debug)","violation":{"reason":"Line should be 120 characters or less; currently it has 165 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedLoggingSystem.swift","line":418}}},{"text":" errorRecovery(\"Recovery failed for \\(error.localizedDescription): \\(recoveryAction) - \\(failureReason)\", level: .error)","violation":{"reason":"Line should be 120 characters or less; currently it has 127 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"line":430,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedLoggingSystem.swift","character":1}}},{"text":" \"\\(operation) (\\(context)): \\(String(format: \"%.2f\", duration))s, Memory: \\(String(format: \"%.1f\", memoryUsage))MB (\\(String(format: \"%+.1f\", memoryDelta))MB)\"","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedLoggingSystem.swift","character":1,"line":471},"reason":"Line should be 120 characters or less; currently it has 167 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning"}},{"text":"}","violation":{"ruleDescription":"Files should not span too many lines.","severity":"warning","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedLoggingSystem.swift","line":500,"character":1},"reason":"File should contain 400 lines or less: currently contains 500","ruleName":"File Length"}},{"text":"class EnhancedTranscriptionManager: NSObject, ObservableObject {","violation":{"severity":"error","location":{"line":59,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift"},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 1346 lines","ruleIdentifier":"type_body_length","ruleDescription":"Type bodies should not span too many lines","ruleName":"Type Body Length"}},{"text":" let modelString = UserDefaults.standard.string(forKey: \"openAIModel\") ?? OpenAITranscribeModel.gpt4oMiniTranscribe.rawValue","violation":{"reason":"Line should be 120 characters or less; currently it has 131 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":150,"character":1},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning"}},{"text":" let modelString = UserDefaults.standard.string(forKey: \"mistralTranscribeModel\") ?? MistralTranscribeModel.voxtralMiniLatest.rawValue","violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","character":1,"line":172},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" \/\/ Note: Speech authorization will be requested when user actually tries to use native speech recognition transcription","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 131 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":274},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" AppLog.shared.transcription(\"Started background task for Whisper: \\(backgroundTaskID.rawValue)\", level: .debug)","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","character":1,"line":299},"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 123 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.transcription(\"Ending background task for Whisper: \\(backgroundTaskID.rawValue)\", level: .debug)","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 122 characters","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":313,"character":1},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.transcription(\"High app memory usage detected (\\(memoryUsageMB) MB), but continuing transcription\")","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","character":1,"line":382},"reason":"Line should be 120 characters or less; currently it has 125 characters","ruleName":"Line Length"}},{"text":" func transcribeAudioFile(at url: URL, using engine: TranscriptionEngine? = nil) async throws -> TranscriptionResult {","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":414,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters","ruleDescription":"Lines should not span too many characters."}},{"text":" func transcribeAudioFile(at url: URL, using engine: TranscriptionEngine? = nil) async throws -> TranscriptionResult {","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":414,"character":5},"ruleName":"Cyclomatic Complexity","reason":"Function should have complexity 10 or less; currently complexity is 21","ruleIdentifier":"cyclomatic_complexity","ruleDescription":"Complexity of function bodies should be limited.","severity":"error"}},{"text":" func transcribeAudioFile(at url: URL, using engine: TranscriptionEngine? = nil) async throws -> TranscriptionResult {","violation":{"ruleName":"Function Body Length","ruleIdentifier":"function_body_length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","character":5,"line":414},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 84 lines"}},{"text":" AppLog.shared.transcription(\"Audio file is very long (\\(durationMinutes) minutes), this may cause memory issues\")","violation":{"ruleName":"Line Length","severity":"warning","location":{"line":436,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift"},"reason":"Line should be 120 characters or less; currently it has 129 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"}},{"text":" AppLog.shared.transcription(\"File too large for AWS Transcribe: \\(duration\/3600) hours (max: 4 hours)\", level: .error)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 134 characters","severity":"warning","location":{"line":471,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift"}}},{"text":" AppLog.shared.transcription(\"Whisper not properly configured, falling back to native speech recognition\")","violation":{"severity":"warning","location":{"line":482,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift"},"reason":"Line should be 120 characters or less; currently it has 121 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length"}},{"text":" AppLog.shared.transcription(\"Starting native speech recognition for file: \\(url.lastPathComponent), duration: \\(duration)s\")","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":543,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift"},"reason":"Line should be 120 characters or less; currently it has 132 characters","ruleName":"Line Length","ruleIdentifier":"line_length"}},{"text":" statusMessage = \"Speech recognition access denied. Enable in Settings > Privacy & Security > Speech Recognition.\"","violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 129 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","character":1,"line":563},"ruleIdentifier":"line_length"}},{"text":" AppLog.shared.transcription(\"Using single chunk transcription (duration: \\(duration)s <= \\(maxChunkDuration)s)\")","violation":{"location":{"line":590,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","character":1},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 124 characters","ruleName":"Line Length","severity":"warning"}},{"text":" AppLog.shared.transcription(\"Using large file transcription (duration: \\(duration)s > \\(maxChunkDuration)s)\")","violation":{"ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":593,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters","severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length"}},{"text":" AppLog.shared.transcription(\"AWS job failed: \\(jobName) - \\(status.failureReason ?? \"Unknown error\")\", level: .error)","violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 137 characters","severity":"warning","ruleIdentifier":"line_length","location":{"character":1,"line":655,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift"}}},{"text":"private func transcribeSingleChunk(url: URL) async throws -> TranscriptionResult {","violation":{"ruleDescription":"Complexity of function bodies should be limited.","severity":"warning","ruleIdentifier":"cyclomatic_complexity","ruleName":"Cyclomatic Complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":682,"character":9},"reason":"Function should have complexity 10 or less; currently complexity is 12"}},{"text":"private func transcribeSingleChunk(url: URL) async throws -> TranscriptionResult {","violation":{"severity":"warning","ruleName":"Function Body Length","ruleDescription":"Function bodies should not span too many lines","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 89 lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","character":9,"line":682}}},{"text":" try await withCheckedThrowingContinuation { (continuation: CheckedContinuation) in","violation":{"ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","character":1,"line":699},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" AppLog.shared.transcription(\"Transcript contains 'error' text -- may indicate a transcription error was saved as content\")","violation":{"location":{"character":1,"line":757,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift"},"ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 166 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning"}},{"text":"private func transcribeLargeFile(url: URL, duration: TimeInterval) async throws -> TranscriptionResult {","violation":{"reason":"Function should have complexity 10 or less; currently complexity is 17","ruleName":"Cyclomatic Complexity","severity":"warning","ruleIdentifier":"cyclomatic_complexity","ruleDescription":"Complexity of function bodies should be limited.","location":{"character":9,"line":806,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift"}}},{"text":"private func transcribeLargeFile(url: URL, duration: TimeInterval) async throws -> TranscriptionResult {","violation":{"ruleDescription":"Function bodies should not span too many lines","severity":"error","location":{"line":806,"character":9,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift"},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 158 lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length"}},{"text":" AppLog.shared.transcription(\"File duration (\\(duration\/60) minutes) exceeds safe limit (\\(maxSafeDuration\/60) minutes)\", level: .error)","violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 147 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"line":814,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift"},"severity":"warning"}},{"text":" AppLog.shared.transcription(\"File size (\\(fileSizeMB) MB) exceeds safe limit (\\(maxFileSizeMB) MB)\", level: .error)","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":826,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters","ruleName":"Line Length","ruleIdentifier":"line_length"}},{"text":" AppLog.shared.transcription(\"Insufficient disk space (\\(freeSpaceMB) MB), need at least \\(minFreeSpaceMB) MB\", level: .error)","violation":{"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"line":842,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" throw TranscriptionError.recognitionFailed(NSError(domain: \"TranscriptionCancelled\", code: -1, userInfo: [NSLocalizedDescriptionKey: \"Transcription was cancelled by user or system\"]))","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","character":1,"line":881},"reason":"Line should be 200 characters or less; currently it has 203 characters","severity":"error","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" AppLog.shared.transcription(\"Speech recognizer became unavailable during chunk \\(index + 1), locale: \\(recognizer.locale.identifier), authStatus: \\(SFSpeechRecognizer.authorizationStatus().rawValue)\", level: .error)","violation":{"ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":893,"character":1},"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"error","reason":"Line should be 200 characters or less; currently it has 235 characters"}},{"text":" throw TranscriptionError.recognitionFailed(NSError(domain: \"TranscriptionCancelled\", code: -1, userInfo: nil))","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","character":1,"line":981},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" AppLog.shared.transcription(\"No speech detected in any of \\(chunks.count) chunks -- audio may contain only silence or non-speech content\")","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1008,"character":1},"severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 150 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":" private func transcribeChunk(url: URL, startTime: TimeInterval, endTime: TimeInterval) async throws -> TranscriptionResult {","violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 128 characters","location":{"line":1026,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift"},"severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length"}},{"text":" private func transcribeChunkInternal(url: URL, startTime: Date) async throws -> TranscriptionResult {","violation":{"reason":"Function should have complexity 10 or less; currently complexity is 12","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","character":13,"line":1046},"ruleName":"Cyclomatic Complexity"}},{"text":" private func transcribeChunkInternal(url: URL, startTime: Date) async throws -> TranscriptionResult {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","character":13,"line":1046},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 94 lines","ruleDescription":"Function bodies should not span too many lines"}},{"text":" try await withCheckedThrowingContinuation { (continuation: CheckedContinuation) in","violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 126 characters","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1057},"severity":"warning"}},{"text":" AppLog.shared.transcription(\"No speech detected in chunk - returning empty result to continue processing\", level: .debug)","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1087,"character":1},"reason":"Line should be 120 characters or less; currently it has 157 characters"}},{"text":" AppLog.shared.transcription(\"Empty transcript for chunk - returning empty result to continue processing\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"line":1123,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","character":1},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 160 characters","ruleIdentifier":"line_length"}},{"text":" guard let audioTrack = composition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid),","violation":{"ruleName":"Line Length","location":{"character":1,"line":1183,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift"},"reason":"Line should be 120 characters or less; currently it has 130 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"}},{"text":" currentStart = currentStart + minAdvancement","violation":{"ruleName":"Shorthand Operator","severity":"error","reason":"Prefer shorthand operators (+=, -=, *=, \/=) over doing the operation and assigning","ruleIdentifier":"shorthand_operator","ruleDescription":"Prefer shorthand operators (+=, -=, *=, \/=) over doing the operation and assigning","location":{"character":17,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1273}}},{"violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 133 characters","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1338,"character":1}},"text":"private func waitForAndRetrieveTranscription(jobName: String, awsService: AWSTranscribeService) async throws -> TranscriptionResult {"},{"violation":{"reason":"Case statements should vertically aligned with their closing brace","ruleDescription":"Case statements should vertically align with their closing brace, or indented if configured otherwise.","ruleName":"Switch and Case Statement Alignment","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1347,"character":1},"ruleIdentifier":"switch_case_alignment"},"text":"case .completed:"},{"violation":{"ruleDescription":"Case statements should vertically align with their closing brace, or indented if configured otherwise.","severity":"warning","reason":"Case statements should vertically aligned with their closing brace","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1364,"character":1},"ruleIdentifier":"switch_case_alignment","ruleName":"Switch and Case Statement Alignment"},"text":"case .failed:"},{"violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 164 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"line":1367,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift"},"severity":"warning"},"text":" throw TranscriptionError.awsTranscriptionFailed(NSError(domain: \"AWSTranscribe\", code: -1, userInfo: [NSLocalizedDescriptionKey: errorMessage]))"},{"violation":{"ruleName":"Switch and Case Statement Alignment","ruleIdentifier":"switch_case_alignment","severity":"warning","ruleDescription":"Case statements should vertically align with their closing brace, or indented if configured otherwise.","location":{"line":1369,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","character":1},"reason":"Case statements should vertically aligned with their closing brace"},"text":"case .inProgress:"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","character":1,"line":1373},"severity":"warning","reason":"Case statements should vertically aligned with their closing brace","ruleIdentifier":"switch_case_alignment","ruleDescription":"Case statements should vertically align with their closing brace, or indented if configured otherwise.","ruleName":"Switch and Case Statement Alignment"},"text":"default:"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1378,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters","ruleName":"Line Length"},"text":" AppLog.shared.transcription(\"Error checking job status: \\(error), retrying in 30 seconds\", level: .error)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1385,"character":1},"reason":"Line should be 200 characters or less; currently it has 206 characters","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"error"},"text":" throw TranscriptionError.awsTranscriptionFailed(NSError(domain: \"AWSTranscribe\", code: -2, userInfo: [NSLocalizedDescriptionKey: \"Transcription job timed out after \\(Int(maxWaitTime\/60)) minutes\"]))"},{"violation":{"ruleName":"Line Length","location":{"line":1850,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift"},"reason":"Line should be 120 characters or less; currently it has 128 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"},"text":" AppLogger.shared.verbose(\"Whisper transcription configured and ready\", category: \"EnhancedTranscriptionManager\")"},{"violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 131 characters","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1853,"character":1},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" AppLogger.shared.warning(\"Whisper transcription selected but not configured\", category: \"EnhancedTranscriptionManager\")"},{"violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 126 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":1866,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","character":1}},"text":" AppLogger.shared.verbose(\"FluidAudio (Parakeet) transcription selected\", category: \"EnhancedTranscriptionManager\")"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 134 characters","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"line":1874,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift"}},"text":" AppLogger.shared.verbose(\"Updating transcription engine to: \\(engine.rawValue)\", category: \"EnhancedTranscriptionManager\")"},{"violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 143 characters","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1981,"character":1}},"text":" AppLog.shared.transcription(\"Non-critical speech recognition error (safe to ignore): \\(error.localizedDescription)\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"error","reason":"Line should be 200 characters or less; currently it has 238 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":2041},"ruleDescription":"Lines should not span too many characters."},"text":" return \"Speech recognition is not available. This may be due to simulator limitations, missing permissions, or device restrictions. Try running on a physical device or check Settings > Privacy & Security > Speech Recognition.\""},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","character":1,"line":2043},"reason":"Line should be 120 characters or less; currently it has 193 characters","ruleName":"Line Length","severity":"warning"},"text":" return \"Speech recognition permission denied. Please enable Speech Recognition in Settings > Privacy & Security > Speech Recognition to use native speech recognition transcription.\""},{"violation":{"ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":2067,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift"},"reason":"Line should be 120 characters or less; currently it has 134 characters","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length"},"text":" return \"On-device model is not ready. Download and initialize the Parakeet model in Settings > Transcription > On Device.\""},{"violation":{"ruleIdentifier":"file_length","ruleDescription":"Files should not span too many lines.","ruleName":"File Length","reason":"File should contain 1000 lines or less: currently contains 2078","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":2078},"severity":"error"},"text":"}"},{"violation":{"ruleIdentifier":"type_body_length","severity":"warning","location":{"line":14,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ErrorHandlingSystem.swift"},"reason":"Class body should span 250 lines or less excluding comments and whitespace: currently spans 274 lines","ruleDescription":"Type bodies should not span too many lines","ruleName":"Type Body Length"},"text":"class ErrorHandler: ObservableObject {"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 122 characters","severity":"warning","location":{"line":20,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ErrorHandlingSystem.swift","character":1}},"text":" private let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? \"com.bisonnotes.app\", category: \"ErrorHandler\")"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"line":63,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ErrorHandlingSystem.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"},"text":" AppLog.shared.errorRecovery(\"Validating transcript for summarization, length: \\(text.count) characters\", level: .debug)"},{"violation":{"reason":"File should contain 400 lines or less: currently contains 864","ruleDescription":"Files should not span too many lines.","severity":"warning","ruleName":"File Length","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ErrorHandlingSystem.swift","line":864,"character":1}},"text":"}"},{"violation":{"ruleIdentifier":"type_body_length","ruleName":"Type Body Length","location":{"line":17,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FileImportManager.swift"},"ruleDescription":"Type bodies should not span too many lines","reason":"Class body should span 250 lines or less excluding comments and whitespace: currently spans 306 lines","severity":"warning"},"text":"class FileImportManager: NSObject, ObservableObject {"},{"violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 122 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FileImportManager.swift","line":125,"character":1},"ruleName":"Line Length"},"text":" AppLog.shared.fileManagement(\"Thumbnail generation warning: \\(error.localizedDescription)\", level: .debug)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 138 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FileImportManager.swift","character":1,"line":184},"severity":"warning"},"text":" AppLog.shared.fileManagement(\"Archive restore: \\(matches.count) UUID-prefix matches for token \\(parsed.token)\", level: .debug)"},{"text":" AppLog.shared.fileManagement(\"Cleared archive flags for \\(recording.recordingName ?? \"unknown\") (local audio still present)\")","violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 137 characters","location":{"line":219,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FileImportManager.swift","character":1},"ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.fileManagement(\"Thumbnail generation warning: \\(error.localizedDescription)\", level: .debug)","violation":{"severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FileImportManager.swift","character":1,"line":235},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" AppLog.shared.fileManagement(\"Restored archived recording \\(recording.recordingName ?? \"unknown\") from import \\(sourceURL.lastPathComponent)\")","violation":{"location":{"character":1,"line":246,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FileImportManager.swift"},"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 154 characters","ruleIdentifier":"line_length"}},{"text":" let resourceValues = try fileURL.resourceValues(forKeys: [.creationDateKey, .contentModificationDateKey, .fileSizeKey])","violation":{"ruleName":"Line Length","location":{"line":390,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FileImportManager.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning"}},{"text":" return \"Unsupported format: \\(format). Supported audio: m4a, mp3, wav, caf, aiff. Supported video: mp4, mov, m4v\"","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FileImportManager.swift","line":471,"character":1},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":"}","violation":{"reason":"File should contain 400 lines or less: currently contains 509","location":{"line":509,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FileImportManager.swift"},"ruleName":"File Length","ruleIdentifier":"file_length","severity":"warning","ruleDescription":"Files should not span too many lines."}},{"text":"final class FluidAudioManager: ObservableObject {","violation":{"ruleName":"Type Body Length","reason":"Class body should span 250 lines or less excluding comments and whitespace: currently spans 330 lines","ruleDescription":"Type bodies should not span too many lines","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift","line":10,"character":7},"ruleIdentifier":"type_body_length"}},{"text":" UserDefaults.standard.set(selectedVersion, forKey: FluidAudioModelInfo.SettingsKeys.downloadedModelVersion)","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 123 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift","line":37},"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length"}},{"text":" let downloadedVersion = UserDefaults.standard.string(forKey: FluidAudioModelInfo.SettingsKeys.downloadedModelVersion)","violation":{"location":{"line":43,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"}},{"text":" if let dv = downloadedVersion {","violation":{"severity":"warning","ruleIdentifier":"identifier_name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleName":"Identifier Name","location":{"line":46,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift","character":16},"reason":"Variable name 'dv' should be between 3 and 40 characters long"}},{"text":" UserDefaults.standard.set(availableVersion.rawValue, forKey: FluidAudioModelInfo.SettingsKeys.selectedModelVersion)","violation":{"reason":"Line should be 120 characters or less; currently it has 127 characters","severity":"warning","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift","line":64},"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"}},{"text":" UserDefaults.standard.set(availableVersion.rawValue, forKey: FluidAudioModelInfo.SettingsKeys.downloadedModelVersion)","violation":{"reason":"Line should be 120 characters or less; currently it has 129 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","location":{"line":65,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift"}}},{"violation":{"severity":"warning","location":{"character":1,"line":75,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift"},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 124 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."},"text":" guard let appSupport = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first else {"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 124 characters","location":{"character":1,"line":164,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift"},"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length"},"text":" \/\/\/ Whether the FluidAudio SDK is linked in this build. Compile-time constant, safe to access from any isolation domain."},{"violation":{"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 51 lines","ruleDescription":"Function bodies should not span too many lines","location":{"line":210,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift","character":5},"ruleIdentifier":"function_body_length","ruleName":"Function Body Length","severity":"warning"},"text":" func downloadAndPrepareModel() async throws {"},{"violation":{"severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift","character":1,"line":268},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 124 characters","ruleDescription":"Lines should not span too many characters."},"text":" UserDefaults.standard.set(selectedVersion.rawValue, forKey: FluidAudioModelInfo.SettingsKeys.downloadedModelVersion)"},{"violation":{"severity":"warning","ruleName":"Function Body Length","location":{"line":313,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift","character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 60 lines","ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines"},"text":" func transcribe(audioURL: URL) async throws -> TranscriptionResult {"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 127 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","location":{"line":394,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift","character":1}},"text":" AppLog.shared.transcription(\"Could not read Parakeet input duration: \\(error.localizedDescription)\", level: .debug)"},{"violation":{"ruleName":"Line Length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift","line":404},"reason":"Line should be 120 characters or less; currently it has 163 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"},"text":" let message = \"Parakeet SDK transcription failed for \\(originalURL.lastPathComponent): \\(nsError.domain) \\(nsError.code) - \\(nsError.localizedDescription)\""},{"violation":{"ruleIdentifier":"file_length","ruleDescription":"Files should not span too many lines.","severity":"warning","ruleName":"File Length","reason":"File should contain 400 lines or less: currently contains 415","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift","line":415,"character":1}},"text":"}"},{"violation":{"location":{"line":5,"character":14,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioModelInfo.swift"},"ruleName":"Identifier Name","reason":"Enum element name 'v2' should be between 3 and 40 characters long","ruleIdentifier":"identifier_name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","severity":"warning"},"text":" case v2"},{"violation":{"reason":"Enum element name 'v3' should be between 3 and 40 characters long","ruleName":"Identifier Name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","severity":"warning","ruleIdentifier":"identifier_name","location":{"character":14,"line":6,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioModelInfo.swift"}},"text":" case v3"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"line":5,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioSettingsView.swift"},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 150 characters"},"text":" @AppStorage(FluidAudioModelInfo.SettingsKeys.selectedModelVersion) private var selectedModelVersion = FluidAudioModelInfo.ModelVersion.v2.rawValue"},{"violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 196 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioSettingsView.swift","character":1,"line":76},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" Text(\"FluidAudio runs NVIDIA Parakeet models fully on-device using CoreML\/ANE acceleration. This option keeps audio local and does not remove your existing transcription engines.\")"},{"violation":{"location":{"line":14,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift"},"ruleDescription":"Type bodies should not span too many lines","reason":"Class body should span 250 lines or less excluding comments and whitespace: currently spans 301 lines","severity":"warning","ruleIdentifier":"type_body_length","ruleName":"Type Body Length"},"text":"class AWSBedrockEngine: SummarizationEngine, ConnectionTestable {"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"line":20,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift"},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 129 characters"},"text":" let storedModelString = UserDefaults.standard.string(forKey: \"awsBedrockModel\") ?? AWSBedrockModel.claude45Haiku.rawValue"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":35,"character":1},"reason":"Line should be 120 characters or less; currently it has 151 characters"},"text":" AppLogger.shared.verbose(\"Checking enableAWSBedrock setting - Value: \\(isEnabled), Key exists: \\(keyExists)\", category: \"AWSBedrockEngine\")"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":63},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 127 characters","ruleName":"Line Length"},"text":" AppLogger.shared.verbose(\"AWS credentials not configured in unified manager\", category: \"AWSBedrockEngine\")"},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":168},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 167 characters","severity":"warning","ruleIdentifier":"line_length"},"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"ruleName":"Large Tuple","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","severity":"error","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":168,"character":56},"reason":"Tuples should have at most 2 members"},"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"location":{"line":185,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 151 characters","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.networking(\"AWSBedrockEngine: Large transcript detected (\\(tokenCount) tokens), using chunked processing\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":188,"character":1},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 123 characters","severity":"warning"},"text":" AppLog.shared.networking(\"AWSBedrockEngine: Processing single chunk (\\(tokenCount) tokens)\", level: .debug)"},{"violation":{"severity":"warning","ruleName":"Line Length","location":{"line":203,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift"},"reason":"Line should be 120 characters or less; currently it has 129 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"},"text":" let storedModelString = UserDefaults.standard.string(forKey: \"awsBedrockModel\") ?? AWSBedrockModel.claude45Haiku.rawValue"},{"violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":230},"reason":"Line should be 120 characters or less; currently it has 151 characters","ruleIdentifier":"line_length"},"text":" AppLogger.shared.verbose(\"Updating configuration - Model: \\(modelString), Region: \\(credentials.region)\", category: \"AWSBedrockEngine\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":245,"character":1},"severity":"error","ruleIdentifier":"line_length","reason":"Line should be 200 characters or less; currently it has 208 characters"},"text":" private func processChunkedText(_ text: String, service: AWSBedrockService) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"location":{"line":245,"character":97,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift"},"ruleName":"Large Tuple","reason":"Tuples should have at most 2 members","ruleIdentifier":"large_tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead."},"text":" private func processChunkedText(_ text: String, service: AWSBedrockService) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","character":1,"line":265},"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 167 characters"},"text":" AppLog.shared.networking(\"AWSBedrockEngine: Processing chunk \\(index + 1) of \\(chunks.count) (\\(TokenManager.getTokenCount(chunk)) tokens)\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":285},"reason":"Line should be 120 characters or less; currently it has 123 characters"},"text":" AppLog.shared.networking(\"AWSBedrockEngine: Failed to process chunk \\(index + 1): \\(error)\", level: .error)"},{"violation":{"ruleName":"Line Length","location":{"line":303,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","character":1},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 128 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" AppLog.shared.networking(\"AWSBedrockEngine: Chunked processing completed in \\(String(format: \"%.2f\", processingTime))s\")"},{"violation":{"ruleIdentifier":"line_length","severity":"error","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":304},"reason":"Line should be 200 characters or less; currently it has 221 characters","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.networking(\"AWSBedrockEngine: Final results - summary: \\(combinedSummary.count) chars, tasks: \\(uniqueTasks.count), reminders: \\(uniqueReminders.count), titles: \\(uniqueTitles.count)\", level: .debug)"},{"violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 144 characters","location":{"line":412,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","character":1},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length"},"text":" return SummarizationError.aiServiceUnavailable(service: \"AWS Bedrock access denied. Please check your credentials and permissions.\")"},{"violation":{"location":{"line":414,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift"},"reason":"Line should be 120 characters or less; currently it has 127 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length"},"text":" return SummarizationError.aiServiceUnavailable(service: \"AWS Bedrock rate limit exceeded. Please try again later.\")"},{"violation":{"severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":416},"reason":"Line should be 120 characters or less; currently it has 142 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" return SummarizationError.aiServiceUnavailable(service: \"AWS Bedrock model not available. Please check your model configuration.\")"},{"violation":{"ruleName":"Type Body Length","location":{"line":427,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift"},"ruleDescription":"Type bodies should not span too many lines","severity":"error","reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 466 lines","ruleIdentifier":"type_body_length"},"text":"class LocalLLMEngine: SummarizationEngine, ConnectionTestable {"},{"violation":{"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 145 characters","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":443}},"text":" AppLogger.shared.verbose(\"Checking enableOllama setting - Value: \\(isEnabled), Key exists: \\(keyExists)\", category: \"LocalLLMEngine\")"},{"violation":{"ruleName":"Line Length","location":{"line":469,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift"},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 121 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"},"text":" AppLogger.shared.verbose(\"Ollama not explicitly configured (using defaults)\", category: \"LocalLLMEngine\")"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":537},"reason":"Line should be 120 characters or less; currently it has 150 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" throw SummarizationError.aiServiceUnavailable(service: \"Cannot connect to Ollama server. Please check your server URL and port settings.\")"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 150 characters","severity":"warning","location":{"line":569,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","character":1},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" throw SummarizationError.aiServiceUnavailable(service: \"Cannot connect to Ollama server. Please check your server URL and port settings.\")"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 150 characters","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","character":1,"line":600},"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning"},"text":" throw SummarizationError.aiServiceUnavailable(service: \"Cannot connect to Ollama server. Please check your server URL and port settings.\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":631},"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 150 characters"},"text":" throw SummarizationError.aiServiceUnavailable(service: \"Cannot connect to Ollama server. Please check your server URL and port settings.\")"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","character":1,"line":653},"reason":"Line should be 120 characters or less; currently it has 154 characters"},"text":" return SummarizationError.aiServiceUnavailable(service: \"Ollama server is not connected. Please check your server URL and port settings.\")"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 158 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":659}},"text":" return SummarizationError.aiServiceUnavailable(service: \"Ollama model '\\(model)' not found on server. Please check your model configuration.\")"},{"violation":{"ruleName":"Line Length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":682},"reason":"Line should be 120 characters or less; currently it has 167 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"reason":"Tuples should have at most 2 members","ruleIdentifier":"large_tuple","ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","location":{"line":682,"character":56,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift"}},"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"severity":"warning","location":{"character":1,"line":699,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift"},"reason":"Line should be 120 characters or less; currently it has 150 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" throw SummarizationError.aiServiceUnavailable(service: \"Cannot connect to Ollama server. Please check your server URL and port settings.\")"},{"violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 145 characters","ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":708}},"text":" AppLog.shared.networking(\"LocalLLMEngine: Large transcript detected (\\(tokenCount) tokens), using chunked processing\", level: .debug)"},{"violation":{"severity":"warning","location":{"line":718,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" AppLog.shared.networking(\"LocalLLMEngine: Context window exceeded, retrying with chunked processing\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","severity":"error","reason":"Line should be 200 characters or less; currently it has 204 characters","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":733,"character":1},"ruleDescription":"Lines should not span too many characters."},"text":" private func processSingleChunk(_ text: String, service: OllamaService) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"reason":"Tuples should have at most 2 members","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleName":"Large Tuple","severity":"error","ruleIdentifier":"large_tuple","location":{"line":733,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","character":93}},"text":" private func processSingleChunk(_ text: String, service: OllamaService) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":734,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters","ruleName":"Line Length"},"text":" AppLog.shared.networking(\"LocalLLMEngine: Processing single chunk with Ollama using complete processing\", level: .debug)"},{"text":" AppLog.shared.networking(\"LocalLLMEngine: Result - summary: \\(result.summary.count) chars, tasks: \\(result.tasks.count), reminders: \\(result.reminders.count), titles: \\(result.titles.count)\", level: .debug)","violation":{"severity":"error","location":{"line":740,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","character":1},"reason":"Line should be 200 characters or less; currently it has 218 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length"}},{"text":" AppLog.shared.networking(\"LocalLLMEngine: Complete processing failed, falling back to individual calls: \\(error)\", level: .error)","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"line":745,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" private func processSingleChunkFallback(_ text: String, service: OllamaService) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":752,"character":1},"reason":"Line should be 200 characters or less; currently it has 212 characters"}},{"text":" private func processSingleChunkFallback(_ text: String, service: OllamaService) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","reason":"Tuples should have at most 2 members","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","severity":"error","location":{"line":752,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","character":101}}},{"text":" AppLog.shared.networking(\"LocalLLMEngine: Failed to extract tasks\/reminders, continuing with empty arrays: \\(error)\", level: .error)","violation":{"location":{"character":1,"line":772,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift"},"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 144 characters"}},{"text":" AppLog.shared.networking(\"LocalLLMEngine: Failed to extract titles, continuing with empty array: \\(error)\", level: .error)","violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":786},"reason":"Line should be 120 characters or less; currently it has 134 characters","ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning"}},{"text":" AppLog.shared.networking(\"LocalLLMEngine: Result - summary: \\(summary.count) chars, tasks: \\(tasks.count), reminders: \\(reminders.count), titles: \\(titles.count)\", level: .debug)","violation":{"ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":793},"reason":"Line should be 120 characters or less; currently it has 186 characters","ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters."}},{"text":" private func processChunkedText(_ text: String, service: OllamaService, maxTokens: Int) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":798},"reason":"Line should be 200 characters or less; currently it has 220 characters","ruleDescription":"Lines should not span too many characters.","severity":"error","ruleIdentifier":"line_length"}},{"text":" private func processChunkedText(_ text: String, service: OllamaService, maxTokens: Int) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"reason":"Tuples should have at most 2 members","ruleIdentifier":"large_tuple","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":798,"character":109},"ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleName":"Large Tuple"}},{"text":" AppLog.shared.networking(\"LocalLLMEngine: Processing chunk \\(index + 1) of \\(chunks.count) (\\(TokenManager.getTokenCount(chunk)) tokens)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"character":1,"line":813,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift"},"reason":"Line should be 120 characters or less; currently it has 165 characters"}},{"text":" AppLog.shared.networking(\"LocalLLMEngine: Failed to process chunk \\(index + 1): \\(error)\", level: .error)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 121 characters","ruleIdentifier":"line_length","location":{"line":833,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift"},"severity":"warning"}},{"text":" AppLog.shared.networking(\"LocalLLMEngine: Chunked processing completed in \\(String(format: \"%.2f\", processingTime))s\")","violation":{"location":{"line":851,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning"}},{"violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 200 characters or less; currently it has 219 characters","ruleIdentifier":"line_length","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","character":1,"line":852}},"text":" AppLog.shared.networking(\"LocalLLMEngine: Final results - summary: \\(combinedSummary.count) chars, tasks: \\(uniqueTasks.count), reminders: \\(uniqueReminders.count), titles: \\(uniqueTitles.count)\", level: .debug)"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":928,"character":1},"ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 148 characters"},"text":" AppLog.shared.networking(\"LocalLLMEngine: Updating configuration - Server: \\(serverURL), Port: \\(port), Model: \\(modelName)\", level: .debug)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 136 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":953,"character":1},"severity":"warning","ruleIdentifier":"line_length"},"text":" throw SummarizationError.aiServiceUnavailable(service: \"Cannot connect to Ollama server at \\(config?.baseURL ?? \"unknown\")\")"},{"violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 140 characters","ruleIdentifier":"line_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":960,"character":1},"ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.networking(\"LocalLLMEngine: Configured model '\\(config?.modelName ?? \"unknown\")' is not available\", level: .error)"},{"violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"line":964,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift"},"severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 128 characters"},"text":" AppLog.shared.networking(\"LocalLLMEngine: Switching to available model '\\(firstAvailableModel)'\", level: .debug)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":982},"reason":"Line should be 120 characters or less; currently it has 133 characters","ruleName":"Line Length","ruleIdentifier":"line_length"},"text":" AppLog.shared.networking(\"LocalLLMEngine: Updated saved model preference to '\\(firstAvailableModel)'\", level: .debug)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 167 characters","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"line":985,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","character":1}},"text":" throw SummarizationError.aiServiceUnavailable(service: \"No models available on Ollama server. Please install a model using 'ollama pull '\")"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 180 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1041}},"text":" let testText = \"I need to call John tomorrow and buy groceries. Don't forget the meeting at 3pm. We discussed the quarterly budget and decided to increase marketing spend.\""},{"violation":{"ruleName":"Line Length","severity":"error","location":{"line":1045,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift"},"ruleIdentifier":"line_length","reason":"Line should be 200 characters or less; currently it has 234 characters","ruleDescription":"Lines should not span too many characters."},"text":" let summary = \"Successfully processed: Summary (\\(result.summary.count) chars), \\(result.tasks.count) tasks, \\(result.reminders.count) reminders, \\(result.titles.count) titles, content type: \\(result.contentType.rawValue)\""},{"violation":{"ruleIdentifier":"type_body_length","ruleName":"Type Body Length","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1098,"character":1},"ruleDescription":"Type bodies should not span too many lines","reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 427 lines"},"text":"class GoogleAIStudioEngine: SummarizationEngine {"},{"violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 130 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","location":{"character":1,"line":1109,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift"}},"text":" private let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? \"com.bisonnotes.app\", category: \"GoogleAIStudioEngine\")"},{"violation":{"ruleName":"Line Length","location":{"line":1167,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","character":1},"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 167 characters"},"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","severity":"error","ruleName":"Large Tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1167,"character":56},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.networking(\"GoogleAI: Large transcript detected (\\(tokenCount) tokens), using chunked processing\", level: .debug)","violation":{"reason":"Line should be 120 characters or less; currently it has 143 characters","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1179},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"}},{"text":" AppLog.shared.networking(\"GoogleAI: Context limit reached, falling back to chunked processing\", level: .error)","violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1189,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters","ruleName":"Line Length","ruleIdentifier":"line_length"}},{"text":" private func processSingleChunk(_ text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1196},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 180 characters"}},{"text":" private func processSingleChunk(_ text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleIdentifier":"large_tuple","reason":"Tuples should have at most 2 members","ruleName":"Large Tuple","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","character":69,"line":1196}}},{"text":" private func processChunkedText(_ text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1217},"reason":"Line should be 120 characters or less; currently it has 180 characters","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"text":" private func processChunkedText(_ text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleIdentifier":"function_body_length","location":{"line":1217,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift"},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 55 lines","ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length","severity":"warning"}},{"text":" private func processChunkedText(_ text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"reason":"Tuples should have at most 2 members","ruleName":"Large Tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1217,"character":69},"ruleIdentifier":"large_tuple","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","severity":"error"}},{"text":" AppLog.shared.networking(\"GoogleAI: Processing chunk \\(index + 1) of \\(chunks.count) (\\(TokenManager.getTokenCount(chunk)) tokens)\", level: .debug)","violation":{"ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1233,"character":1},"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 159 characters"}},{"text":" let deduplicatedTasks = Array(Set(allTasks.map { $0.text })).prefix(15).map { TaskItem(text: $0, priority: .medium, confidence: 0.8) }","violation":{"location":{"line":1279,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 142 characters","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" let deduplicatedReminders = Array(Set(allReminders.map { $0.text })).prefix(15).map { ReminderItem(text: $0, timeReference: ReminderItem.TimeReference.fromReminderText($0), urgency: .later, confidence: 0.8) }","violation":{"reason":"Line should be 200 characters or less; currently it has 216 characters","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"error","location":{"line":1280,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","character":1}}},{"text":" let deduplicatedTitles = Array(Set(allTitles.map { $0.text })).prefix(5).map { TitleItem(text: $0, confidence: 0.8) }","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 125 characters","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","character":1,"line":1281}}},{"text":" AppLog.shared.networking(\"GoogleAI: Final results - tasks: \\(deduplicatedTasks.count), reminders: \\(deduplicatedReminders.count), titles: \\(deduplicatedTitles.count)\", level: .debug)","violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 190 characters","location":{"line":1288,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift"},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"}},{"text":" Focus on the key points and main ideas. Keep the summary clear, informative, and well-structured with proper markdown formatting.","violation":{"reason":"Line should be 120 characters or less; currently it has 137 characters","ruleIdentifier":"line_length","location":{"line":1328,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","character":1},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"}},{"text":" - Examples of tasks to AVOID: \"Follow the news about elections\", \"Check updates on celebrity gossip\", \"Monitor world events\"","violation":{"severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"line":1344,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift"},"reason":"Line should be 120 characters or less; currently it has 132 characters","ruleDescription":"Lines should not span too many characters."}},{"text":" - Examples of GOOD reminders: \"Dentist appointment on Friday\", \"Submit report by Monday\", \"Pick up dry cleaning tomorrow\"","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"character":1,"line":1361,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift"},"reason":"Line should be 120 characters or less; currently it has 129 characters","ruleDescription":"Lines should not span too many characters."}},{"text":" - Examples of reminders to AVOID: \"Election day is coming\", \"Check the weather forecast\", \"Follow news about world events\"","violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1362},"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" let taskText = RecordingNameGenerator.cleanAIOutput(trimmed.dropFirst().trimmingCharacters(in: .whitespacesAndNewlines))","violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1402},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 136 characters","ruleDescription":"Lines should not span too many characters."}},{"text":" let reminderText = RecordingNameGenerator.cleanAIOutput(trimmed.dropFirst().trimmingCharacters(in: .whitespacesAndNewlines))","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"line":1419,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift"},"ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" reminders.append(ReminderItem(text: reminderText, timeReference: timeRef, urgency: .later, confidence: 0.8))","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 128 characters","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"line":1422,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift"}}},{"text":" let titleText = RecordingNameGenerator.cleanStandardizedTitleResponse(trimmed.dropFirst().trimmingCharacters(in: .whitespacesAndNewlines))","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","character":1,"line":1437},"reason":"Line should be 120 characters or less; currently it has 154 characters"}},{"text":" private func parseStructuredResponse(_ response: String) -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"reason":"Line should be 120 characters or less; currently it has 176 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1509,"character":1},"ruleIdentifier":"line_length"}},{"text":" private func parseStructuredResponse(_ response: String) -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleDescription":"Complexity of function bodies should be limited.","ruleName":"Cyclomatic Complexity","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1509,"character":13},"ruleIdentifier":"cyclomatic_complexity","reason":"Function should have complexity 10 or less; currently complexity is 22"}},{"text":" private func parseStructuredResponse(_ response: String) -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1509,"character":13},"ruleName":"Function Body Length","ruleDescription":"Function bodies should not span too many lines","severity":"warning","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 90 lines","ruleIdentifier":"function_body_length"}},{"violation":{"location":{"character":65,"line":1509,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift"},"reason":"Tuples should have at most 2 members","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","severity":"error","ruleName":"Large Tuple","ruleIdentifier":"large_tuple"},"text":" private func parseStructuredResponse(_ response: String) -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1524,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"},"text":" let tasks = summaryResponse.tasks.map { TaskItem(text: RecordingNameGenerator.cleanAIOutput($0), priority: .medium, confidence: 0.8) }"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 157 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1527},"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters."},"text":" return ReminderItem(text: cleaned, timeReference: ReminderItem.TimeReference.fromReminderText(cleaned), urgency: .later, confidence: 0.8)"},{"violation":{"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","character":1,"line":1529},"reason":"Line should be 120 characters or less; currently it has 151 characters"},"text":" let titles = summaryResponse.titles.map { TitleItem(text: RecordingNameGenerator.cleanStandardizedTitleResponse($0), confidence: 0.8) }"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","location":{"character":1,"line":1541,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift"},"reason":"Line should be 120 characters or less; currently it has 146 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" logger.error(\"GoogleAIStudioEngine: Response length: \\(response.count) chars, starts with valid JSON: \\(response.hasPrefix(\"{\"))\")"},{"violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 140 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1582},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" let taskText = RecordingNameGenerator.cleanAIOutput(trimmed.dropFirst().trimmingCharacters(in: .whitespacesAndNewlines))"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1589,"character":1},"reason":"Line should be 120 characters or less; currently it has 144 characters"},"text":" let reminderText = RecordingNameGenerator.cleanAIOutput(trimmed.dropFirst().trimmingCharacters(in: .whitespacesAndNewlines))"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 136 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1592,"character":1}},"text":" reminders.append(ReminderItem(text: reminderText, timeReference: timeRef, urgency: .later, confidence: 0.8))"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"line":1597,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift"},"reason":"Line should be 120 characters or less; currently it has 158 characters"},"text":" let titleText = RecordingNameGenerator.cleanStandardizedTitleResponse(trimmed.dropFirst().trimmingCharacters(in: .whitespacesAndNewlines))"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","character":1,"line":1713},"reason":"Line should be 120 characters or less; currently it has 132 characters"},"text":" case .localLLM, .openAI, .openAICompatible, .googleAIStudio, .mistralAI, .awsBedrock, .onDeviceLLM, .mlxSwift, .appleNative:"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1740,"character":1},"reason":"File should contain 1000 lines or less: currently contains 1740","ruleIdentifier":"file_length","ruleDescription":"Files should not span too many lines.","ruleName":"File Length","severity":"error"},"text":"}"},{"violation":{"ruleDescription":"Type bodies should not span too many lines","reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 483 lines","ruleName":"Type Body Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","character":1,"line":14},"ruleIdentifier":"type_body_length","severity":"error"},"text":"class GoogleAIStudioService: ObservableObject {"},{"text":" private let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? \"com.bisonnotes.app\", category: \"GoogleAIStudio\")","violation":{"location":{"line":15,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift"},"ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 124 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" throw SummarizationError.networkError(underlying: NSError(domain: \"GoogleAIStudio\", code: -1, userInfo: [NSLocalizedDescriptionKey: \"Invalid response\"]))","violation":{"reason":"Line should be 120 characters or less; currently it has 165 characters","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","line":163,"character":1}}},{"text":" throw SummarizationError.networkError(underlying: NSError(domain: \"GoogleAIStudio\", code: httpResponse.statusCode, userInfo: [NSLocalizedDescriptionKey: \"HTTP \\(httpResponse.statusCode): \\(errorMessage)\"]))","violation":{"reason":"Line should be 200 characters or less; currently it has 218 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","character":1,"line":169},"ruleName":"Line Length"}},{"text":" private func createStructuredRequest(prompt: String) throws -> Data {","violation":{"severity":"warning","location":{"line":181,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift"},"ruleIdentifier":"function_body_length","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 57 lines"}},{"text":" private func createStructuredPrompt(_ text: String) -> String {","violation":{"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 54 lines","ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length","severity":"warning","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","line":264,"character":13}}},{"text":" logger.warning(\"GoogleAIStudioService: Raw response length: \\(textPart.text.count) chars, starts with valid JSON: \\(textPart.text.hasPrefix(\"{\"))\")","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","line":341,"character":1},"reason":"Line should be 120 characters or less; currently it has 163 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length"}},{"text":" if let remindersMatch = truncatedJSON.range(of: \"\\\"reminders\\\":\\\\s*\\\\[([^\\\\]]*)\\\\]\", options: .regularExpression) {","violation":{"reason":"Line should be 120 characters or less; currently it has 123 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","character":1,"line":434},"severity":"warning","ruleName":"Line Length"}},{"text":" if let contentTypeMatch = truncatedJSON.range(of: \"\\\"contentType\\\":\\\\s*\\\"([^\\\"]*)\\\"\", options: .regularExpression) {","violation":{"reason":"Line should be 120 characters or less; currently it has 124 characters","ruleIdentifier":"line_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","character":1,"line":446},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" let contentTypeStart = truncatedJSON.index(contentTypeMatch.lowerBound, offsetBy: 14) \/\/ Skip \"contentType\":\"","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","line":447,"character":1},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" logger.info(\"GoogleAIStudioService: Extracted partial response - Summary: \\(summary.count) chars, Tasks: \\(tasks.count), Reminders: \\(reminders.count), Titles: \\(titles.count)\")","violation":{"location":{"line":456,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift"},"reason":"Line should be 120 characters or less; currently it has 189 characters","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters."}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"Google AI Studio title extraction failed: \\(error.localizedDescription)\")","violation":{"severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 141 characters","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","line":529,"character":1}}},{"text":" let category = TitleItem.TitleCategory(rawValue: titleResponse.category?.lowercased() ?? \"general\") ?? .general","violation":{"ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 127 characters","location":{"line":554,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","character":1},"ruleDescription":"Lines should not span too many characters."}},{"text":" let category = TitleItem.TitleCategory(rawValue: titleResponse.category?.lowercased() ?? \"general\") ?? .general","violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 131 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","character":1,"line":566},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"Failed to parse titles JSON: \\(error.localizedDescription)\")","violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","line":574},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":"}","violation":{"reason":"File should contain 400 lines or less: currently contains 611","ruleDescription":"Files should not span too many lines.","severity":"warning","location":{"character":1,"line":611,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift"},"ruleIdentifier":"file_length","ruleName":"File Length"}},{"text":" private let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? \"com.bisonnotes.app\", category: \"GoogleAIStudioSettings\")","violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"line":23,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioSettingsView.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" alertMessage = isConnected ? \"Connection successful!\" : \"Connection failed. Please check your API key and internet connection.\"","violation":{"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 143 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"line":160,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioSettingsView.swift"}}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","severity":"warning","location":{"character":24,"line":50,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/IntegrationSelectionView.swift"},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/IntegrationSelectionView.swift","line":84,"character":24},"ruleIdentifier":"multiple_closures_with_trailing_closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/IntegrationSelectionView.swift","line":119,"character":28},"ruleIdentifier":"multiple_closures_with_trailing_closure","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" let recognizer = SFSpeechRecognizer(locale: Locale.current) ?? SFSpeechRecognizer(locale: Locale(identifier: \"en-US\"))","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"character":1,"line":60,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LiveTranscriptionService.swift"},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" Marker(\"Recording Location\", coordinate: CLLocationCoordinate2D(latitude: locationData.latitude, longitude: locationData.longitude))","violation":{"reason":"Line should be 120 characters or less; currently it has 152 characters","severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LocationDetailView.swift","character":1,"line":30}}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleDescription":"Lines should not span too many characters.","location":{"line":60,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LocationDetailView.swift"},"severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LocationDetailView.swift","character":32,"line":66},"reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure"}},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","location":{"line":77,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LocationDetailView.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters","ruleName":"Line Length"},"text":" .background(Color.accentColor, in: RoundedRectangle(cornerRadius: 12, style: .continuous))"},{"violation":{"reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","ruleIdentifier":"multiple_closures_with_trailing_closure","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LocationDetailView.swift","line":82,"character":32}},"text":" }) {"},{"violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 136 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"line":93,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LocationDetailView.swift","character":1},"ruleName":"Line Length"},"text":" .background(Color.accentColor.opacity(0.12), in: RoundedRectangle(cornerRadius: 12, style: .continuous))"},{"violation":{"ruleIdentifier":"type_body_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LocationManager.swift","line":12,"character":1},"ruleDescription":"Type bodies should not span too many lines","ruleName":"Type Body Length","reason":"Class body should span 250 lines or less excluding comments and whitespace: currently spans 269 lines"},"text":"class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {"},{"violation":{"ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","severity":"warning","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 64 lines","location":{"line":26,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LogExporter.swift","character":12},"ruleName":"Function Body Length"},"text":" static func exportLogs() async throws -> URL {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LogExporter.swift","line":64},"reason":"Line should be 120 characters or less; currently it has 130 characters"},"text":" logLines.append(\"[\\(formatter.string(from: entry.date))] [\\(level)] [\\(entry.category)] \\(entry.composedMessage)\")"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"line":68,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LogExporter.swift"},"reason":"Line should be 120 characters or less; currently it has 126 characters"},"text":" sections.append(\"\\n\" + sectionHeader(\"CURRENT SESSION LOGS\") + \"\\nFailed to fetch: \\(error.localizedDescription)\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LogExporter.swift","line":75,"character":1},"reason":"Line should be 120 characters or less; currently it has 151 characters","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length"},"text":" sections.append(\"\\n\" + sectionHeader(\"PERSISTENT BREADCRUMBS (\\(breadcrumbLines.count) entries, survives crashes)\") + \"\\n\" + breadcrumbLog)"},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LogExporter.swift","line":82},"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 139 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" sections.append(\"\\n\" + sectionHeader(\"PERSISTENT ERROR LOG (\\(errorLines.count) entries, survives crashes)\") + \"\\n\" + errorLog)"},{"violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LogExporter.swift","character":1,"line":94},"reason":"Line should be 120 characters or less; currently it has 190 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"},"text":" sections.append(\"\\n\" + sectionHeader(\"METRICKIT CRASH\/HANG DIAGNOSTICS\") + \"\\nNo MetricKit diagnostics available yet. iOS may deliver crash and hang payloads on a later launch.\")"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LogExporter.swift","line":163,"character":1},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 123 characters"},"text":" \"Hi,\\n\\nAttached is a diagnostic log from BisonNotes AI.\\n\\nPlease describe what happened (optional):\\n\\n\","},{"violation":{"reason":"Line should be 120 characters or less; currently it has 133 characters","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"line":188,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LogExporter.swift"}},"text":" func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {"},{"text":" var vc = root","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LogExporter.swift","character":13,"line":203},"reason":"Variable name 'vc' should be between 3 and 40 characters long","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","ruleName":"Identifier Name","severity":"warning"}},{"text":" AppLog.shared.summarization(\"[MLXSwift] Download failed: \\(error.localizedDescription)\", level: .error)","violation":{"reason":"Line should be 120 characters or less; currently it has 123 characters","ruleIdentifier":"line_length","severity":"warning","location":{"character":1,"line":86,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift"},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" func processComplete(text: String) async throws -> (","violation":{"severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","reason":"Tuples should have at most 2 members","ruleIdentifier":"large_tuple","ruleName":"Large Tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":177,"character":56}}},{"text":"private actor MLXSwiftService {","violation":{"ruleIdentifier":"type_body_length","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","character":9,"line":267},"ruleDescription":"Type bodies should not span too many lines","ruleName":"Type Body Length","reason":"Actor body should span 350 lines or less excluding comments and whitespace: currently spans 359 lines"}},{"text":" + \"\\((before.activeMemory + before.cacheMemory - after.activeMemory - after.cacheMemory) \/ (1024*1024))MB \"","violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":319,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" message: \"The device is running low on memory. Close other apps and try again, or use a cloud AI engine for large transcripts.\"","violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 143 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":331,"character":1}}},{"text":" func processComplete(text: String) async throws -> (","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","character":56,"line":336},"ruleIdentifier":"large_tuple","reason":"Tuples should have at most 2 members","ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead."}},{"text":" AppLog.shared.summarization(\"[MLXSwift] Transcript: \\(tokenCount) tokens, input limit: \\(inputLimit) tokens\/chunk\")","violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","character":1,"line":352},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 123 characters","ruleIdentifier":"line_length"}},{"text":" let result: (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)","violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","character":1,"line":354},"reason":"Line should be 120 characters or less; currently it has 130 characters","ruleIdentifier":"line_length","ruleName":"Line Length"}},{"text":" let result: (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)","violation":{"ruleName":"Large Tuple","reason":"Tuples should have at most 2 members","ruleIdentifier":"large_tuple","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","character":21,"line":354}}},{"text":" AppLog.shared.summarization(\"[MLXSwift] Chunking transcript into ~\\(inputLimit)-token pieces\", level: .debug)","violation":{"location":{"line":356,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","character":1},"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" private func processChunked(text: String, maxTokens: Int) async throws -> (","violation":{"ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","severity":"error","reason":"Tuples should have at most 2 members","location":{"line":368,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","character":79},"ruleIdentifier":"large_tuple","ruleName":"Large Tuple"}},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":398},"severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 124 characters"},"text":" return try await consolidate(chunkResults: chunkResults, originalContentType: ContentAnalyzer.classifyContent(text))"},{"violation":{"ruleIdentifier":"function_body_length","location":{"character":13,"line":401,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift"},"severity":"warning","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 51 lines","ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length"},"text":" private func runCompletePrompt(transcript: String, contentHint: ContentType) async throws -> ("},{"violation":{"ruleIdentifier":"large_tuple","ruleName":"Large Tuple","location":{"line":401,"character":98,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift"},"ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","reason":"Tuples should have at most 2 members","severity":"error"},"text":" private func runCompletePrompt(transcript: String, contentHint: ContentType) async throws -> ("},{"violation":{"ruleName":"Function Body Length","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":463,"character":13},"ruleDescription":"Function bodies should not span too many lines","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 54 lines","severity":"warning"},"text":" private func consolidate("},{"violation":{"severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","character":23,"line":466},"reason":"Tuples should have at most 2 members","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","ruleName":"Large Tuple"},"text":" ) async throws -> ("},{"violation":{"ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":626,"character":1},"reason":"Line should be 120 characters or less; currently it has 144 characters","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning"},"text":" AppLog.shared.summarization(\"[MLXSwift] Insufficient memory: \\(availableMB) MB available, \\(requiredMB) MB required\", level: .error)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 159 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","location":{"line":628,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","character":1}},"text":" message: \"Not enough free memory to load the MLX model. Close other apps and try again. (\\(availableMB) MB available, \\(requiredMB) MB needed)\""},{"violation":{"ruleIdentifier":"large_tuple","reason":"Tuples should have at most 2 members","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleName":"Large Tuple","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":712,"character":10}},"text":" ) -> ("},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 127 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":725},"severity":"warning","ruleIdentifier":"line_length"},"text":" AppLog.shared.summarization(\"[MLXSwift] Could not parse structured JSON, using raw response as summary\", level: .error)"},{"violation":{"reason":"Tuples should have at most 2 members","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleName":"Large Tuple","location":{"line":741,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","character":10},"ruleIdentifier":"large_tuple"},"text":" ) -> ("},{"violation":{"reason":"Line should be 120 characters or less; currently it has 131 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":869}},"text":" cleaned = cleaned.replacingOccurrences(of: #\"^```(?:json)?\\s*\"#, with: \"\", options: [.regularExpression, .caseInsensitive])"},{"violation":{"ruleName":"Large Tuple","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","location":{"character":51,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":889},"reason":"Tuples should have at most 2 members","severity":"error","ruleIdentifier":"large_tuple"},"text":" func toSummaryResult(fallbackText: String) -> ("},{"violation":{"ruleIdentifier":"file_length","severity":"error","ruleDescription":"Files should not span too many lines.","reason":"File should contain 1000 lines or less: currently contains 1002","ruleName":"File Length","location":{"line":1002,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","character":1}},"text":"}"},{"violation":{"ruleIdentifier":"type_body_length","severity":"warning","ruleDescription":"Type bodies should not span too many lines","reason":"Struct body should span 250 lines or less excluding comments and whitespace: currently spans 311 lines","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftSettingsView.swift","line":63},"ruleName":"Type Body Length"},"text":"struct MLXSwiftSettingsView: View {"},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftSettingsView.swift","line":75},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 133 characters","ruleName":"Line Length"},"text":" @AppStorage(MLXSwiftSettingsKeys.repetitionPenalty) private var repetitionPenalty = MLXSwiftSettingsKeys.defaultRepetitionPenalty"},{"violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftSettingsView.swift","character":1,"line":93},"reason":"Line should be 120 characters or less; currently it has 180 characters","ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."},"text":" Text(\"Process transcripts locally using Apple's MLX framework. Models download from Hugging Face on first use. No internet connection required after download.\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":97,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftSettingsView.swift"},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 132 characters","ruleIdentifier":"line_length"},"text":" Text(\"MLX Swift requires a device with 4GB+ RAM and Apple Silicon. Your device does not meet this requirement.\")"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 129 characters","ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"line":157,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftSettingsView.swift"}},"text":" Text(\"This will delete \\(model.displayName) (\\(model.downloadSize)) from your device. You can re-download it later.\")"},{"violation":{"severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftSettingsView.swift","character":1,"line":389},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 200 characters or less; currently it has 221 characters","ruleName":"Line Length","ruleIdentifier":"line_length"},"text":" Text(\"Automatically set based on device RAM: \\(DeviceCapabilities.onDeviceLLMContextSize == 8192 ? \"8k\" : \"16k\") for devices with \\(DeviceCapabilities.onDeviceLLMContextSize == 8192 ? \"<8GB\" : \"\\u{2265}8GB\") RAM\")"},{"violation":{"ruleDescription":"Files should not span too many lines.","ruleName":"File Length","severity":"warning","reason":"File should contain 400 lines or less: currently contains 459","location":{"line":459,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftSettingsView.swift","character":1},"ruleIdentifier":"file_length"},"text":"}"},{"violation":{"ruleName":"Type Body Length","ruleDescription":"Type bodies should not span too many lines","severity":"error","reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 353 lines","location":{"line":11,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","character":1},"ruleIdentifier":"type_body_length"},"text":"class MistralAIEngine: SummarizationEngine, ConnectionTestable {"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"line":23,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" private let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? \"com.bisonnotes.app\", category: \"MistralAIEngine\")"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 149 characters","location":{"character":1,"line":61,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift"},"severity":"warning"},"text":" AppLogger.shared.verbose(\"Checking enableMistralAI setting - Value: \\(isEnabled), Key exists: \\(keyExists)\", category: \"MistralAIEngine\")"},{"violation":{"ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 121 characters","location":{"line":108,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift"}},"text":" \/\/\/ This method calls `processComplete()` internally, which extracts ALL content (summary, tasks, reminders, titles)."},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":134,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift"},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 121 characters","ruleIdentifier":"line_length"},"text":" \/\/\/ This method calls `processComplete()` internally, which extracts ALL content (summary, tasks, reminders, titles)."},{"violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 121 characters","location":{"line":160,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","character":1},"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."},"text":" \/\/\/ This method calls `processComplete()` internally, which extracts ALL content (summary, tasks, reminders, titles)."},{"violation":{"reason":"Line should be 120 characters or less; currently it has 124 characters","ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":197,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","character":1}},"text":" \/\/\/ - Returns: A tuple containing summary, tasks (max 15), reminders (max 15), titles (max 5), and detected content type"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 167 characters","location":{"line":204,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift"},"severity":"warning"},"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":204,"character":56},"ruleIdentifier":"large_tuple","ruleName":"Large Tuple","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","severity":"error","reason":"Tuples should have at most 2 members"},"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"location":{"character":1,"line":233,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift"},"severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 127 characters","ruleDescription":"Lines should not span too many characters."},"text":" logger.info(\"Mistral AI test connection \\(success ? \"successful\" : \"failed\") - Response length: \\(response.count)\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","location":{"line":267,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift"},"reason":"Line should be 120 characters or less; currently it has 188 characters","ruleName":"Line Length"},"text":" AppLogger.shared.verbose(\"Mistral AI JSON format: user override (\\(userSetting)) differs from auto-detection (\\(autoDetectedJsonSupport))\", category: \"MistralAIEngine\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","character":1,"line":270},"reason":"Line should be 120 characters or less; currently it has 159 characters","ruleName":"Line Length","severity":"warning"},"text":" AppLogger.shared.verbose(\"Mistral AI JSON format: using auto-detection (\\(autoDetectedJsonSupport)) based on URL\", category: \"MistralAIEngine\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","location":{"line":292,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","character":1},"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 190 characters"},"text":" AppLogger.shared.verbose(\"Updated Mistral AI configuration - Model: \\(modelId), BaseURL: \\(baseURL), JSON Format: \\(supportsJsonResponseFormat)\", category: \"MistralAIEngine\")"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":319,"character":1},"severity":"error","reason":"Line should be 200 characters or less; currently it has 240 characters","ruleDescription":"Lines should not span too many characters."},"text":" private func processChunkedText(_ text: String, service: MistralAISummarizationService, contextWindow: Int) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","character":13,"line":319},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 56 lines","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length"},"text":" private func processChunkedText(_ text: String, service: MistralAISummarizationService, contextWindow: Int) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"severity":"error","ruleName":"Large Tuple","reason":"Tuples should have at most 2 members","ruleIdentifier":"large_tuple","location":{"character":129,"line":319,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift"},"ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead."},"text":" private func processChunkedText(_ text: String, service: MistralAISummarizationService, contextWindow: Int) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":358,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift"},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 157 characters"},"text":" logger.warning(\"Failed to process Mistral chunk \\(index + 1), retrying (\\(retryCount)\/\\(maxRetries)): \\(error.localizedDescription)\")"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 153 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"line":362,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift"},"ruleName":"Line Length","ruleIdentifier":"line_length"},"text":" logger.error(\"Failed to process Mistral chunk \\(index + 1) after \\(maxRetries) retries, skipping: \\(error.localizedDescription)\")"},{"violation":{"severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":377},"reason":"Line should be 120 characters or less; currently it has 128 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" logger.warning(\"Completed chunked processing with \\(successfulChunks) successful and \\(failedChunks) failed chunks\")"},{"violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":508},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 129 characters","severity":"warning"},"text":" let metaSummary = try await generateMetaSummary(from: combinedText, contentType: contentType, service: service, depth: 0)"},{"violation":{"severity":"warning","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","character":1,"line":531},"reason":"Line should be 120 characters or less; currently it has 139 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" throw SummarizationError.aiServiceUnavailable(service: \"Mistral AI - Summary processing too complex (recursion limit reached)\")"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":558,"character":1},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 125 characters","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning"},"text":" return try await generateMetaSummary(from: reducedText, contentType: contentType, service: service, depth: depth + 1)"},{"violation":{"ruleName":"File Length","location":{"line":578,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","character":1},"ruleDescription":"Files should not span too many lines.","severity":"warning","reason":"File should contain 400 lines or less: currently contains 578","ruleIdentifier":"file_length"},"text":"}"},{"violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 127 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"line":27,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISettingsView.swift","character":1}},"text":" private let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? \"com.bisonnotes.app\", category: \"MistralAISettings\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISettingsView.swift","line":49},"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 173 characters"},"text":" Text(\"Mistral AI offers a free tier with all models -- no credit card required. Use the guided setup to create an account and get your API key.\")"},{"violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"character":74,"line":53,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISettingsView.swift"},"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","reason":"Trailing closure syntax should not be used when passing more than one closure argument"},"text":" Button(action: { showingOnboarding = true }) {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 130 characters","ruleIdentifier":"line_length","location":{"line":79,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISettingsView.swift"},"ruleName":"Line Length","severity":"warning"},"text":" Text(\"Mistral uses OpenAI-compatible chat endpoints. Keep the default base URL unless you use a gateway.\")"},{"violation":{"location":{"line":88,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISettingsView.swift"},"reason":"Line should be 120 characters or less; currently it has 197 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"},"text":" Text(\"Enable strict JSON mode for structured outputs. Official Mistral API supports this. Disable if using a custom gateway that doesn't support response_format parameter.\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"line":150,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISettingsView.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"},"text":" Text(\"Context window: \\(selectedModelEnum.contextWindow\/1000)K tokens β€’ \\(selectedModelEnum.costTier) pricing\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 129 characters","severity":"warning","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISettingsView.swift","line":235,"character":1},"ruleIdentifier":"line_length"},"text":" alertMessage = success ? \"Connection successful!\" : \"Connection failed. Please verify your API key and base URL.\""},{"violation":{"ruleName":"Line Length","location":{"line":29,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISummarizationService.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" private let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? \"com.bisonnotes.app\", category: \"MistralAISummarizationService\")"},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISummarizationService.swift","line":136},"severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 167 characters"},"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"location":{"character":56,"line":136,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISummarizationService.swift"},"reason":"Tuples should have at most 2 members","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleName":"Large Tuple","severity":"error","ruleIdentifier":"large_tuple"},"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 150 characters","ruleIdentifier":"line_length","location":{"line":156,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISummarizationService.swift","character":1},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"},"text":" logger.debug(\"Using response_format: \\(self.config.supportsJsonResponseFormat ? \"json_object\" : \"none (flexible parsing)\", privacy: .public)\")"},{"violation":{"severity":"warning","ruleName":"Cyclomatic Complexity","ruleIdentifier":"cyclomatic_complexity","reason":"Function should have complexity 10 or less; currently complexity is 12","ruleDescription":"Complexity of function bodies should be limited.","location":{"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISummarizationService.swift","line":170}},"text":" private func makeAPICall(request: MistralChatCompletionRequest) async throws -> OpenAIChatCompletionResponse {"},{"violation":{"ruleName":"Function Body Length","ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 62 lines","location":{"line":170,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISummarizationService.swift"},"severity":"warning"},"text":" private func makeAPICall(request: MistralChatCompletionRequest) async throws -> OpenAIChatCompletionResponse {"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISummarizationService.swift","character":1,"line":176},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 160 characters","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters."},"text":" logger.debug(\"Mistral AI API Configuration - Model: \\(self.config.model.rawValue, privacy: .public), BaseURL: \\(self.config.baseURL, privacy: .public)\")"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 125 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISummarizationService.swift","line":197,"character":1}},"text":" throw SummarizationError.aiServiceUnavailable(service: \"Failed to encode request: \\(error.localizedDescription)\")"},{"violation":{"severity":"warning","location":{"line":216,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISummarizationService.swift"},"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 156 characters"},"text":" logger.warning(\"Mistral API rate limit exceeded - Retry-After: \\(retryAfter, privacy: .public), Reset: \\(rateLimitReset, privacy: .public)\")"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 127 characters","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISummarizationService.swift","character":1,"line":232},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"},"text":" throw SummarizationError.aiServiceUnavailable(service: \"Mistral API Error: \\(errorResponse.error.message)\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISummarizationService.swift","line":234},"reason":"Line should be 120 characters or less; currently it has 158 characters"},"text":" logger.error(\"Mistral API Error: HTTP \\(httpResponse.statusCode, privacy: .public), response size: \\(data.count, privacy: .public) bytes\")"},{"violation":{"ruleIdentifier":"line_length","location":{"line":235,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISummarizationService.swift"},"severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 128 characters","ruleDescription":"Lines should not span too many characters."},"text":" throw SummarizationError.aiServiceUnavailable(service: \"Mistral API Error: HTTP \\(httpResponse.statusCode)\")"},{"violation":{"severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 190 characters","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISummarizationService.swift","line":243,"character":1}},"text":" logger.info(\"Usage - Prompt: \\(usage.promptTokens, privacy: .public), Completion: \\(usage.completionTokens, privacy: .public), Total: \\(usage.totalTokens, privacy: .public)\")"},{"violation":{"ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines","location":{"line":156,"character":5,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift"},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 76 lines","severity":"warning","ruleName":"Function Body Length"},"text":" func transcribeAudioFile(at url: URL, recordingId: UUID? = nil) async throws -> MistralTranscribeResult {"},{"violation":{"ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","character":1,"line":186},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 134 characters"},"text":" let result = try await performTranscription(audioData: audioData, fileName: audioChunk.chunkURL.lastPathComponent)"},{"violation":{"severity":"error","ruleIdentifier":"function_body_length","reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 105 lines","location":{"line":249,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift"},"ruleName":"Function Body Length","ruleDescription":"Function bodies should not span too many lines"},"text":" private func performTranscription(audioData: Data, fileName: String) async throws -> MistralTranscribeResult {"},{"violation":{"ruleIdentifier":"non_optional_string_data_conversion","severity":"warning","ruleName":"Non-optional String -> Data Conversion","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","location":{"character":21,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":266}},"text":" body.append(\"--\\(boundary)\\r\\n\".data(using: .utf8)!)"},{"violation":{"location":{"character":21,"line":267,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift"},"severity":"warning","ruleName":"Non-optional String -> Data Conversion","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"},"text":" body.append(\"Content-Disposition: form-data; name=\\\"file\\\"; filename=\\\"\\(fileName)\\\"\\r\\n\".data(using: .utf8)!)"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","character":21,"line":268},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","severity":"warning","ruleName":"Non-optional String -> Data Conversion"},"text":" body.append(\"Content-Type: \\(getContentType(for: fileName))\\r\\n\\r\\n\".data(using: .utf8)!)"},{"violation":{"ruleIdentifier":"non_optional_string_data_conversion","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleName":"Non-optional String -> Data Conversion","location":{"line":270,"character":21,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift"},"severity":"warning"},"text":" body.append(\"\\r\\n\".data(using: .utf8)!)"},{"violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","location":{"line":273,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","character":21},"ruleIdentifier":"non_optional_string_data_conversion"},"text":" body.append(\"--\\(boundary)\\r\\n\".data(using: .utf8)!)"},{"violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":274,"character":21},"ruleIdentifier":"non_optional_string_data_conversion","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleName":"Non-optional String -> Data Conversion"},"text":" body.append(\"Content-Disposition: form-data; name=\\\"model\\\"\\r\\n\\r\\n\".data(using: .utf8)!)"},{"text":" body.append(\"\\r\\n\".data(using: .utf8)!)","violation":{"ruleIdentifier":"non_optional_string_data_conversion","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleName":"Non-optional String -> Data Conversion","location":{"character":21,"line":276,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift"},"severity":"warning","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"--\\(boundary)\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","severity":"warning","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","character":21,"line":279},"ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"Content-Disposition: form-data; name=\\\"response_format\\\"\\r\\n\\r\\n\".data(using: .utf8)!)","violation":{"severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","location":{"character":21,"line":280,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift"},"ruleName":"Non-optional String -> Data Conversion","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion"}},{"text":" body.append(\"verbose_json\".data(using: .utf8)!)","violation":{"ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleName":"Non-optional String -> Data Conversion","ruleIdentifier":"non_optional_string_data_conversion","severity":"warning","location":{"character":21,"line":281,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift"},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"\\r\\n\".data(using: .utf8)!)","violation":{"ruleIdentifier":"non_optional_string_data_conversion","ruleName":"Non-optional String -> Data Conversion","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","severity":"warning","location":{"character":21,"line":282,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift"}}},{"text":" body.append(\"--\\(boundary)\\r\\n\".data(using: .utf8)!)","violation":{"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleName":"Non-optional String -> Data Conversion","severity":"warning","location":{"character":21,"line":285,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift"}}},{"text":" body.append(\"Content-Disposition: form-data; name=\\\"timestamp_granularities[]\\\"\\r\\n\\r\\n\".data(using: .utf8)!)","violation":{"ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","ruleName":"Non-optional String -> Data Conversion","location":{"line":286,"character":21,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift"},"severity":"warning"}},{"text":" body.append(\"segment\".data(using: .utf8)!)","violation":{"severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","location":{"line":287,"character":21,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift"},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","ruleName":"Non-optional String -> Data Conversion"}},{"text":" body.append(\"\\r\\n\".data(using: .utf8)!)","violation":{"ruleIdentifier":"non_optional_string_data_conversion","ruleName":"Non-optional String -> Data Conversion","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","severity":"warning","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","location":{"line":288,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","character":21}}},{"text":" body.append(\"--\\(boundary)\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":292,"character":25},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"Content-Disposition: form-data; name=\\\"diarize\\\"\\r\\n\\r\\n\".data(using: .utf8)!)","violation":{"ruleIdentifier":"non_optional_string_data_conversion","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleName":"Non-optional String -> Data Conversion","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","character":25,"line":293},"severity":"warning"}},{"text":" body.append(\"true\".data(using: .utf8)!)","violation":{"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","severity":"warning","ruleIdentifier":"non_optional_string_data_conversion","ruleName":"Non-optional String -> Data Conversion","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","location":{"character":25,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":294}}},{"text":" body.append(\"\\r\\n\".data(using: .utf8)!)","violation":{"ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":295,"character":25},"ruleIdentifier":"non_optional_string_data_conversion","ruleName":"Non-optional String -> Data Conversion","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","severity":"warning"}},{"text":" body.append(\"--\\(boundary)\\r\\n\".data(using: .utf8)!)","violation":{"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"character":25,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":300},"ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleName":"Non-optional String -> Data Conversion","severity":"warning"}},{"text":" body.append(\"Content-Disposition: form-data; name=\\\"language\\\"\\r\\n\\r\\n\".data(using: .utf8)!)","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":301,"character":25},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","severity":"warning","ruleName":"Non-optional String -> Data Conversion"}},{"text":" body.append(\"\\r\\n\".data(using: .utf8)!)","violation":{"severity":"warning","location":{"character":25,"line":303,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift"},"ruleIdentifier":"non_optional_string_data_conversion","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleName":"Non-optional String -> Data Conversion"}},{"text":" body.append(\"--\\(boundary)--\\r\\n\".data(using: .utf8)!)","violation":{"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleName":"Non-optional String -> Data Conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":307,"character":21},"severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion"}},{"text":" AppLog.shared.transcription(\"Mistral transcription: model=\\(config.model.rawValue), diarize=\\(config.diarize), size=\\(body.count) bytes\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","location":{"line":311,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift"},"reason":"Line should be 120 characters or less; currently it has 160 characters","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning"}},{"text":" AppLog.shared.transcription(\"Parsed \\(mistralSegments.count) segments with \\(speakerCount) unique speakers\", level: .debug)","violation":{"location":{"character":1,"line":355,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift"},"reason":"Line should be 120 characters or less; currently it has 135 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length"}},{"text":" AppLog.shared.transcription(\"Mistral transcription complete: \\(transcriptText.count) chars, \\(segments.count) segments, \\(String(format: \"%.1f\", processingTime))s\")","violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":379},"severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 172 characters"}},{"text":"}","violation":{"location":{"character":1,"line":452,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift"},"ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","severity":"warning","reason":"File should contain 400 lines or less: currently contains 452","ruleName":"File Length"}},{"text":" Text(\"Specify a language code (e.g., 'en', 'fr', 'es') for better accuracy, or leave empty for auto-detection.\")","violation":{"ruleDescription":"Lines should not span too many characters.","location":{"line":105,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeSettingsView.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning"}},{"text":" func addRecording(url: URL, name: String, date: Date, fileSize: Int64, duration: TimeInterval, quality: AudioQuality, locationData: LocationData? = nil) -> UUID {","violation":{"location":{"line":38,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift","character":1},"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 166 characters","ruleIdentifier":"line_length","ruleName":"Line Length"}},{"text":" func addRecording(url: URL, name: String, date: Date, fileSize: Int64, duration: TimeInterval, quality: AudioQuality, locationData: LocationData? = nil) -> UUID {","violation":{"ruleIdentifier":"function_parameter_count","severity":"warning","reason":"Function should have 5 parameters or less: it currently has 6","ruleDescription":"Number of function parameters should be low.","ruleName":"Function Parameter Count","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift","line":38,"character":5}}},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"line":52,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 171 characters"},"text":" func addWatchRecording(url: URL, name: String, date: Date, fileSize: Int64, duration: TimeInterval, quality: AudioQuality, locationData: LocationData? = nil) -> UUID {"},{"violation":{"ruleIdentifier":"function_parameter_count","ruleDescription":"Number of function parameters should be low.","ruleName":"Function Parameter Count","severity":"warning","location":{"character":5,"line":52,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift"},"reason":"Function should have 5 parameters or less: it currently has 6"},"text":" func addWatchRecording(url: URL, name: String, date: Date, fileSize: Int64, duration: TimeInterval, quality: AudioQuality, locationData: LocationData? = nil) -> UUID {"},{"violation":{"reason":"Line should be 200 characters or less; currently it has 224 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift","character":1,"line":66},"ruleIdentifier":"line_length"},"text":" func addTranscript(for recordingId: UUID, segments: [TranscriptSegment], speakerMappings: [String: String] = [:], engine: TranscriptionEngine? = nil, processingTime: TimeInterval = 0, confidence: Double = 0.5) -> UUID? {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"error","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift","line":81},"reason":"Line should be 200 characters or less; currently it has 311 characters"},"text":" func addSummary(for recordingId: UUID, transcriptId: UUID, summary: String, tasks: [TaskItem] = [], reminders: [ReminderItem] = [], titles: [TitleItem] = [], contentType: ContentType = .general, aiEngine: String = \"Unknown\", aiModel: String, originalLength: Int, processingTime: TimeInterval = 0) -> UUID? {"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 137 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift","line":144},"ruleName":"Line Length"},"text":" func getCompleteRecordingData(id: UUID) -> (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)? {"},{"violation":{"severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","reason":"Tuples should have at most 2 members","ruleName":"Large Tuple","location":{"character":48,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift","line":144}},"text":" func getCompleteRecordingData(id: UUID) -> (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)? {"},{"violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 130 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift","line":148,"character":1},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" func getAllRecordingsWithData() -> [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)] {"},{"violation":{"reason":"Tuples should have at most 2 members","ruleIdentifier":"large_tuple","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleName":"Large Tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift","line":148,"character":41},"severity":"warning"},"text":" func getAllRecordingsWithData() -> [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)] {"},{"violation":{"ruleIdentifier":"line_length","location":{"line":152,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift"},"reason":"Line should be 120 characters or less; currently it has 134 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"},"text":" func getRecordingsWithTranscripts() -> [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)] {"},{"violation":{"ruleName":"Large Tuple","reason":"Tuples should have at most 2 members","ruleIdentifier":"large_tuple","location":{"line":152,"character":45,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift"},"severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead."},"text":" func getRecordingsWithTranscripts() -> [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)] {"},{"violation":{"location":{"character":1,"line":171,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift"},"severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 134 characters","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.coreData(\"Deleted local recording and queued iCloud deletion marker for retry: \\(error)\", level: .error)"},{"violation":{"ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","location":{"line":193,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift"},"reason":"Line should be 120 characters or less; currently it has 128 characters","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.coreData(\"Deleted local summary but failed to remove iCloud summary records: \\(error)\", level: .error)"},{"violation":{"ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift","character":1,"line":220},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 130 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"},"text":" AppLog.shared.coreData(\"Marked recording local-only and queued iCloud removal for retry: \\(error)\", level: .error)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AudioChunkingModels.swift","line":24,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters","ruleName":"Line Length"},"text":" init(originalURL: URL, chunkURL: URL, sequenceNumber: Int, startTime: TimeInterval, endTime: TimeInterval, fileSize: Int64) {"},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AudioChunkingModels.swift","line":49},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 182 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length"},"text":" init(chunkId: UUID, sequenceNumber: Int, transcript: String, segments: [TranscriptSegment], startTime: TimeInterval, endTime: TimeInterval, processingTime: TimeInterval? = nil) {"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AudioChunkingModels.swift","line":69,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters","severity":"warning"},"text":" static let openAI = ChunkingStrategy.combined(maxBytes: 24 * 1024 * 1024, maxSeconds: 1300) \/\/ 24MB and 1300 seconds (21.67 minutes)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 123 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AudioChunkingModels.swift","character":1,"line":73}},"text":" static let mistralAI = ChunkingStrategy.combined(maxBytes: 24 * 1024 * 1024, maxSeconds: 1300) \/\/ 24MB and 1300 seconds"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 122 characters","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"line":100,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AudioChunkingModels.swift","character":1},"severity":"warning","ruleDescription":"Lines should not span too many characters."},"text":" self.tempDirectory = tempDirectory ?? FileManager.default.temporaryDirectory.appendingPathComponent(\"AudioChunks\")"},{"violation":{"location":{"line":160,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AudioChunkingModels.swift","character":12},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 52 lines","ruleIdentifier":"function_body_length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length"},"text":" static func create(from url: URL) async throws -> AudioFileInfo {"},{"violation":{"location":{"line":163,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AudioChunkingModels.swift","character":1},"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 136 characters"},"text":" AppLog.shared.chunking(\"AudioFileInfo.create - File exists: \\(FileManager.default.fileExists(atPath: url.path))\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AudioChunkingModels.swift","line":167},"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 126 characters"},"text":" AppLog.shared.chunking(\"AudioFileInfo.create - Loaded duration: \\(duration)s (\\(duration\/60) minutes)\", level: .debug)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 127 characters","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AudioChunkingModels.swift","character":1,"line":171},"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length"},"text":" AppLog.shared.chunking(\"AudioFileInfo.create - File size: \\(fileSize) bytes (\\(fileSize\/1024\/1024) MB)\", level: .debug)"},{"violation":{"severity":"error","ruleName":"Line Length","reason":"Line should be 200 characters or less; currently it has 275 characters","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AudioChunkingModels.swift","line":223,"character":1},"ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.chunking(\"AudioFileInfo.create - Successfully created: duration=\\(audioFileInfo.duration)s, size=\\(audioFileInfo.fileSize) bytes, format=\\(audioFileInfo.format), sampleRate=\\(audioFileInfo.sampleRate), channels=\\(audioFileInfo.channels)\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AudioModels.swift","line":111},"reason":"Line should be 120 characters or less; currently it has 149 characters"},"text":" return \"High-quality on-device transcription powered by NVIDIA Parakeet. Your audio never leaves your device, ensuring complete privacy.\""},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":115,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AudioModels.swift"},"reason":"Line should be 120 characters or less; currently it has 128 characters","ruleName":"Line Length","ruleIdentifier":"line_length"},"text":" return \"High-quality transcription using OpenAI's Whisper model on your local server (REST API or Wyoming protocol)\""},{"violation":{"reason":"Line should be 120 characters or less; currently it has 121 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"line":155,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AudioModels.swift"},"ruleName":"Line Length","severity":"warning"},"text":" let protocolString = UserDefaults.standard.string(forKey: \"whisperProtocol\") ?? WhisperProtocol.rest.rawValue"},{"violation":{"severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/ConfigurationWarningHelper.swift","line":40},"reason":"Line should be 120 characters or less; currently it has 127 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length"},"text":" message: \"No transcription engine has been configured. Please go to Settings to configure a transcription engine.\","},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 127 characters","location":{"character":1,"line":69,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/ConfigurationWarningHelper.swift"}},"text":" Text(\"No transcription engine has been configured. Please go to Settings to configure a transcription engine.\")"},{"violation":{"ruleName":"Type Body Length","reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 904 lines","ruleDescription":"Type bodies should not span too many lines","severity":"error","location":{"line":15,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift"},"ruleIdentifier":"type_body_length"},"text":"class CoreDataManager: ObservableObject {"},{"violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 127 characters","ruleDescription":"Lines should not span too many characters.","location":{"line":184,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift"},"ruleIdentifier":"line_length","ruleName":"Line Length"},"text":" AppLog.shared.coreData(\"File not found anywhere for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)"},{"violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 131 characters","ruleIdentifier":"line_length","location":{"line":369,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift"},"severity":"warning","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.coreData(\"Repairing orphaned summary \\(index): ID \\(summary.id?.uuidString ?? \"nil\")\", level: .debug)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":389},"reason":"Line should be 120 characters or less; currently it has 150 characters","severity":"warning","ruleIdentifier":"line_length"},"text":" AppLog.shared.coreData(\"Created recording \\(newRecordingId.uuidString) for summary \\(summary.id?.uuidString ?? \"nil\")\", level: .debug)"},{"violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"line":404,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift"},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 132 characters","ruleIdentifier":"line_length"},"text":" AppLog.shared.coreData(\"After repair: \\(newRecordingCount) recordings, \\(newSummaryCount) summaries\", level: .debug)"},{"violation":{"severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","location":{"line":420,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","character":5},"reason":"Function should have complexity 10 or less; currently complexity is 16","ruleName":"Cyclomatic Complexity","ruleIdentifier":"cyclomatic_complexity"},"text":" func cleanupDuplicates() -> (summaries: Int, transcripts: Int) {"},{"violation":{"ruleName":"Function Body Length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 77 lines","ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines","location":{"line":420,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","character":5},"severity":"warning"},"text":" func cleanupDuplicates() -> (summaries: Int, transcripts: Int) {"},{"violation":{"severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 124 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":439,"character":1}},"text":" AppLog.shared.coreData(\"Found \\(summaries.count) summaries for recording ID: \\(recordingId)\", level: .debug)"},{"text":" AppLog.shared.coreData(\"Deleting duplicate summary ID: \\(summary.id?.uuidString ?? \"nil\") (length: \\(summaryLength) chars)\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","character":1,"line":444},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 163 characters","ruleIdentifier":"line_length"}},{"text":" AppLog.shared.coreData(\"Keeping most recent summary ID: \\(summary.id?.uuidString ?? \"nil\") (length: \\(summaryLength) chars)\", level: .debug)","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","character":1,"line":449},"reason":"Line should be 120 characters or less; currently it has 164 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning"}},{"text":" AppLog.shared.coreData(\"Found \\(transcripts.count) transcripts for recording ID: \\(recordingId)\", level: .debug)","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 128 characters","ruleName":"Line Length","severity":"warning","location":{"line":460,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","character":1}}},{"text":" AppLog.shared.coreData(\"Deleting duplicate transcript ID: \\(transcript.id?.uuidString ?? \"nil\") (segments: \\(segmentsLength) chars)\", level: .debug)","violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 172 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":465,"character":1}}},{"text":" AppLog.shared.coreData(\"Keeping most recent transcript ID: \\(transcript.id?.uuidString ?? \"nil\") (segments: \\(segmentsLength) chars)\", level: .debug)","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":470,"character":1},"reason":"Line should be 120 characters or less; currently it has 173 characters"}},{"text":" AppLog.shared.coreData(\"Deleting orphaned summary (no recording): ID \\(summary.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"line":482,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift"},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" AppLog.shared.coreData(\"Deleting orphaned transcript (no recording): ID \\(transcript.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 146 characters","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":495,"character":1}}},{"text":" AppLog.shared.coreData(\"Cleanup complete: deleted \\(summariesDeleted) duplicate\/orphaned summaries, \\(transcriptsDeleted) duplicate\/orphaned transcripts\")","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"line":505,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift"},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 170 characters","severity":"warning"}},{"text":" AppLog.shared.coreData(\"Found \\(summaries.count) summaries for recording \\(recordingId) β€” auto-cleaning duplicates\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 147 characters","severity":"warning","ruleName":"Line Length","location":{"line":529,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","character":1},"ruleIdentifier":"line_length"}},{"text":" AppLog.shared.coreData(\"Auto-deleting duplicate summary ID=\\(summary.id?.uuidString ?? \"nil\"), length=\\(summary.summary?.count ?? 0)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","location":{"character":1,"line":532,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift"},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 169 characters"}},{"text":" AppLog.shared.coreData(\"Deleting \\(summaries.count) summary\/summaries for recording: \\(recordingId)\", level: .debug)","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 128 characters","ruleName":"Line Length","location":{"line":628,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift"},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"text":" func getCompleteRecordingData(id: UUID) -> (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)? {","violation":{"severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":645},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 137 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"}},{"violation":{"severity":"warning","ruleIdentifier":"large_tuple","reason":"Tuples should have at most 2 members","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","location":{"character":48,"line":645,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift"},"ruleName":"Large Tuple"},"text":" func getCompleteRecordingData(id: UUID) -> (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)? {"},{"violation":{"severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":656,"character":1},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 130 characters","ruleDescription":"Lines should not span too many characters."},"text":" func getAllRecordingsWithData() -> [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)] {"},{"violation":{"ruleIdentifier":"large_tuple","location":{"character":41,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":656},"ruleName":"Large Tuple","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","reason":"Tuples should have at most 2 members","severity":"warning"},"text":" func getAllRecordingsWithData() -> [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)] {"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 134 characters","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":666,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift"},"severity":"warning"},"text":" func getRecordingsWithTranscripts() -> [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)] {"},{"violation":{"ruleName":"Large Tuple","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","severity":"warning","ruleIdentifier":"large_tuple","reason":"Tuples should have at most 2 members","location":{"line":666,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","character":45}},"text":" func getRecordingsWithTranscripts() -> [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)] {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":700,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","character":1},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 127 characters","ruleIdentifier":"line_length"},"text":" private func convertToTranscriptData(transcriptEntry: TranscriptEntry, recordingEntry: RecordingEntry) -> TranscriptData? {"},{"violation":{"ruleName":"Unused Optional Binding","ruleIdentifier":"unused_optional_binding","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":701,"character":19},"reason":"Prefer `!= nil` over `let _ =`","ruleDescription":"Prefer `!= nil` over `let _ =`"},"text":" guard let _ = transcriptEntry.id,"},{"violation":{"location":{"line":703,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift"},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 131 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" AppLog.shared.coreData(\"Transcript missing id for recording: \\(recordingEntry.id?.uuidString ?? \"nil\")\", level: .error)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 123 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","location":{"line":709,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift"}},"text":" let url = getAbsoluteURL(for: recordingEntry) ?? preservedContentURL(for: recordingEntry, recordingId: recordingId)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":744,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length"},"text":" private func convertToEnhancedSummaryData(summaryEntry: SummaryEntry, recordingEntry: RecordingEntry) -> EnhancedSummaryData? {"},{"violation":{"location":{"line":745,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","character":19},"reason":"Prefer `!= nil` over `let _ =`","ruleIdentifier":"unused_optional_binding","ruleName":"Unused Optional Binding","ruleDescription":"Prefer `!= nil` over `let _ =`","severity":"warning"},"text":" guard let _ = summaryEntry.id,"},{"violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 123 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":752,"character":1},"severity":"warning"},"text":" let url = getAbsoluteURL(for: recordingEntry) ?? preservedContentURL(for: recordingEntry, recordingId: recordingId)"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","location":{"line":920,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift"},"reason":"Line should be 120 characters or less; currently it has 128 characters","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.coreData(\"Cleaning up orphaned recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)"},{"violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":991,"character":1},"ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 126 characters"},"text":" AppLog.shared.coreData(\"Cleaning up recording with missing file: \\(url.lastPathComponent)\", level: .debug)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":1003,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift"},"reason":"Line should be 120 characters or less; currently it has 123 characters","ruleName":"Line Length","ruleIdentifier":"line_length"},"text":" AppLog.shared.coreData(\"Preserving recording with transcript\/summary, clearing URL\", level: .debug)"},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":1010},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 130 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length"},"text":" AppLog.shared.coreData(\"Recording with unresolvable URL, ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)"},{"violation":{"reason":"Line should be 200 characters or less; currently it has 312 characters","severity":"error","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":1047},"ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.coreData(\"Recording ID: \\(recording.id?.uuidString ?? \"nil\") | transcript: \\(hasTranscript) | summary: \\(hasSummary) | transcriptionStatus: \\(recording.transcriptionStatus ?? \"unknown\") | summaryStatus: \\(recording.summaryStatus ?? \"unknown\") | location: \\(hasLocation)\", level: .debug)"},{"violation":{"reason":"Function should have complexity 10 or less; currently complexity is 18","ruleIdentifier":"cyclomatic_complexity","ruleName":"Cyclomatic Complexity","location":{"character":5,"line":1054,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift"},"ruleDescription":"Complexity of function bodies should be limited.","severity":"warning"},"text":" func syncRecordingURLs() {"},{"violation":{"ruleIdentifier":"function_body_length","ruleName":"Function Body Length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 71 lines","location":{"line":1054,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","character":5},"severity":"warning","ruleDescription":"Function bodies should not span too many lines"},"text":" func syncRecordingURLs() {"},{"violation":{"severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 143 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":1094},"ruleDescription":"Lines should not span too many characters."},"text":" let fileURLs = try FileManager.default.contentsOfDirectory(at: documentsPath, includingPropertiesForKeys: nil, options: [])"},{"violation":{"ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 194 characters","location":{"character":1,"line":1105,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift"},"ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.coreData(\"Updated URL for recording ID \\(recording.id?.uuidString ?? \"nil\"): \\(oldURL.lastPathComponent) -> \\(newURL.lastPathComponent)\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length","location":{"line":1107,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift"},"reason":"Line should be 120 characters or less; currently it has 162 characters","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.coreData(\"Fixed path for recording ID \\(recording.id?.uuidString ?? \"nil\"): \\(newURL.lastPathComponent)\", level: .debug)"},{"violation":{"reason":"Line should be 200 characters or less; currently it has 212 characters","ruleName":"Line Length","severity":"error","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","character":1,"line":1125}},"text":" AppLog.shared.coreData(\"Updated URL by name match for recording ID \\(recording.id?.uuidString ?? \"nil\"): \\(oldURL.lastPathComponent) -> \\(newURL.lastPathComponent)\", level: .debug)"},{"violation":{"severity":"error","location":{"character":1,"line":1127,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift"},"ruleIdentifier":"line_length","reason":"Line should be 200 characters or less; currently it has 214 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.coreData(\"Could not find file for recording ID \\(recording.id?.uuidString ?? \"nil\"), expected filename: \\(filename), available files: \\(fileURLs.count)\", level: .error)"},{"text":" AppLog.shared.coreData(\"Could not find file for recording ID \\(recording.id?.uuidString ?? \"nil\")\", level: .error)","violation":{"reason":"Line should be 120 characters or less; currently it has 142 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","character":1,"line":1130}}},{"text":" AppLog.shared.coreData(\"Updated recording URL for ID \\(recording.id?.uuidString ?? \"nil\"): \\(newURL.lastPathComponent)\")","violation":{"reason":"Line should be 120 characters or less; currently it has 132 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","character":1,"line":1160},"severity":"warning"}},{"text":" throw NSError(domain: \"CoreDataManager\", code: 404, userInfo: [NSLocalizedDescriptionKey: \"Recording not found with ID: \\(recordingId)\"])","violation":{"severity":"warning","location":{"line":1168,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 149 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length"}},{"text":" throw NSError(domain: \"CoreDataManager\", code: 404, userInfo: [NSLocalizedDescriptionKey: \"Recording not found with ID: \\(recordingId)\"])","violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 149 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","character":1,"line":1188}}},{"text":"}","violation":{"ruleIdentifier":"file_length","ruleName":"File Length","location":{"line":1226,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","character":1},"reason":"File should contain 1000 lines or less: currently contains 1226","severity":"error","ruleDescription":"Files should not span too many lines."}},{"text":"class DataMigrationManager: ObservableObject {","violation":{"severity":"error","reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 1614 lines","location":{"line":92,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":1},"ruleIdentifier":"type_body_length","ruleDescription":"Type bodies should not span too many lines","ruleName":"Type Body Length"}},{"text":" await createCoreDataEntries(audioFiles: audioFiles, transcriptFiles: transcriptFiles, summaryFiles: summaryFiles)","violation":{"reason":"Line should be 120 characters or less; currently it has 125 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"line":137,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift"},"ruleIdentifier":"line_length"}},{"text":" let fileURLs = try FileManager.default.contentsOfDirectory(at: documentsPath, includingPropertiesForKeys: nil, options: [])","violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":182,"character":1},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" let fileURLs = try FileManager.default.contentsOfDirectory(at: documentsPath, includingPropertiesForKeys: nil, options: [])","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":1,"line":198},"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 135 characters","ruleName":"Line Length"}},{"text":" await createRecordingEntry(audioFile: audioFile, transcriptFiles: transcriptFiles, summaryFiles: summaryFiles)","violation":{"ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":1,"line":212},"reason":"Line should be 120 characters or less; currently it has 122 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"text":" private func createRecordingEntry(audioFile: URL, transcriptFiles: [URL], summaryFiles: [URL]) async {","violation":{"ruleName":"Function Body Length","severity":"warning","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 64 lines","ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines","location":{"character":13,"line":216,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift"}}},{"text":" AppLog.shared.dataMigration(\"Created transcript entry for recording ID: \\(recordingEntry.id?.uuidString ?? \"nil\")\")","violation":{"ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 127 characters","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":1,"line":337},"ruleName":"Line Length"}},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 124 characters","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":1,"line":386},"ruleIdentifier":"line_length"},"text":" AppLog.shared.dataMigration(\"Created summary entry for recording ID: \\(recordingEntry.id?.uuidString ?? \"nil\")\")"},{"violation":{"ruleName":"Function Body Length","ruleDescription":"Function bodies should not span too many lines","severity":"warning","location":{"line":405,"character":5,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift"},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 65 lines","ruleIdentifier":"function_body_length"},"text":" func recoverDataFromiCloud() async -> (transcripts: Int, summaries: Int, errors: [String]) {"},{"violation":{"severity":"warning","ruleName":"Large Tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":43,"line":405},"ruleIdentifier":"large_tuple","reason":"Tuples should have at most 2 members","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead."},"text":" func recoverDataFromiCloud() async -> (transcripts: Int, summaries: Int, errors: [String]) {"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 121 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":423,"character":1},"ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.dataMigration(\"Found \\(summaries.count) summaries in legacy iCloud\", level: .debug)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 137 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":1,"line":454},"ruleName":"Line Length","ruleIdentifier":"line_length"},"text":" summaryEntry.aiMethod = SummaryMetadataCodec.encode(aiEngine: summary.aiEngine, aiModel: summary.aiModel)"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 142 characters","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":461,"character":1},"severity":"warning"},"text":" AppLog.shared.dataMigration(\"Recovered summary for recording ID: \\(summary.recordingId?.uuidString ?? \"nil\")\")"},{"violation":{"ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":463},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 162 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.dataMigration(\"Summary already exists for recording ID: \\(summary.recordingId?.uuidString ?? \"nil\")\", level: .debug)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 124 characters","ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length","location":{"character":1,"line":487,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift"},"ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.dataMigration(\"Recovery results: \\(transcriptCount) transcripts, \\(summaryCount) summaries recovered\")"},{"violation":{"ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":1,"line":523},"reason":"Line should be 200 characters or less; currently it has 203 characters","severity":"error","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.dataMigration(\" Recording ID: \\(recording.id?.uuidString ?? \"nil\") - hasTranscript: \\(recording.transcript != nil), hasSummary: \\(recording.summary != nil)\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":701},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 135 characters","severity":"warning"},"text":" let fileURLs = try FileManager.default.contentsOfDirectory(at: documentsPath, includingPropertiesForKeys: nil, options: [])"},{"violation":{"ruleIdentifier":"for_where","severity":"warning","ruleName":"Prefer For-Where","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","location":{"character":17,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":757},"reason":"`where` clauses are preferred over a single `if` inside a `for`"},"text":" if transcript.recording == nil {"},{"violation":{"ruleName":"Prefer For-Where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":775,"character":17},"ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","severity":"warning","reason":"`where` clauses are preferred over a single `if` inside a `for`"},"text":" if summary.recording == nil {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"line":814,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 142 characters","ruleIdentifier":"line_length"},"text":" AppLog.shared.dataMigration(\"Could not resolve URL for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .error)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":928},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 139 characters"},"text":" let fileURLs = try FileManager.default.contentsOfDirectory(at: documentsPath, includingPropertiesForKeys: nil, options: [])"},{"violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 139 characters","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":934}},"text":" if let matchingAudio = audioFiles.first(where: { $0.deletingPathExtension().lastPathComponent == orphanedFile.baseName }) {"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":1,"line":936},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 200 characters or less; currently it has 228 characters","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"error"},"text":" await createRecordingEntry(audioFile: matchingAudio, transcriptFiles: orphanedFile.type == .transcript ? [orphanedFile.fileURL] : [], summaryFiles: orphanedFile.type == .summary ? [orphanedFile.fileURL] : [])"},{"violation":{"ruleDescription":"Complexity of function bodies should be limited.","severity":"warning","ruleName":"Cyclomatic Complexity","ruleIdentifier":"cyclomatic_complexity","location":{"line":948,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":13},"reason":"Function should have complexity 10 or less; currently complexity is 11"},"text":" private func repairBrokenRelationships(_ broken: [BrokenRelationship]) async -> Int {"},{"violation":{"ruleName":"Function Body Length","ruleIdentifier":"function_body_length","severity":"warning","location":{"character":13,"line":948,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift"},"ruleDescription":"Function bodies should not span too many lines","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 56 lines"},"text":" private func repairBrokenRelationships(_ broken: [BrokenRelationship]) async -> Int {"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":1085,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift"},"reason":"Line should be 120 characters or less; currently it has 181 characters","ruleName":"Line Length","severity":"warning"},"text":" AppLog.shared.dataMigration(\"Repair summary - relationships: \\(relationshipFixes), names: \\(nameFixes), URLs: \\(urlFixes), duplicates: \\(duplicateFixes)\", level: .debug)"},{"violation":{"ruleDescription":"Complexity of function bodies should be limited.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1096,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 13","ruleIdentifier":"cyclomatic_complexity","ruleName":"Cyclomatic Complexity","severity":"warning"},"text":" private func fixRelationshipInconsistencies() async -> Int {"},{"violation":{"severity":"warning","location":{"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1096},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 56 lines","ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length"},"text":" private func fixRelationshipInconsistencies() async -> Int {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1118},"reason":"Line should be 120 characters or less; currently it has 158 characters"},"text":" AppLog.shared.dataMigration(\"Fixed transcript relationship for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","location":{"line":1124,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 145 characters","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.dataMigration(\"Synced transcript ID for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 148 characters","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":1130,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":1}},"text":" AppLog.shared.dataMigration(\"Added missing transcript ID for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)"},{"text":" AppLog.shared.dataMigration(\"Fixed summary relationship for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 155 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1144},"ruleIdentifier":"line_length"}},{"text":" AppLog.shared.dataMigration(\"Synced summary ID for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"severity":"warning","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 142 characters","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":1,"line":1150}}},{"text":" AppLog.shared.dataMigration(\"Added missing summary ID for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"reason":"Line should be 120 characters or less; currently it has 145 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":1156,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift"},"ruleName":"Line Length"}},{"text":" private func syncRecordingNamesWithTitles() async -> Int {","violation":{"ruleName":"Cyclomatic Complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1173,"character":13},"ruleDescription":"Complexity of function bodies should be limited.","reason":"Function should have complexity 10 or less; currently complexity is 11","ruleIdentifier":"cyclomatic_complexity","severity":"warning"}},{"text":" private func syncRecordingNamesWithTitles() async -> Int {","violation":{"ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length","severity":"warning","location":{"line":1173,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 66 lines"}},{"text":" AppLog.shared.dataMigration(\"Skipping standardized name for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 147 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"character":1,"line":1187,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift"}}},{"text":" (currentName.count > 15 && (currentName.contains(\"1754\") || currentName.contains(\"2025\")))","violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 125 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":1,"line":1199}}},{"text":" AppLog.shared.dataMigration(\"Skipping non-generic name for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"location":{"line":1202,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift"},"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 146 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"}},{"text":" AppLog.shared.dataMigration(\"Found summary title for recording ID: \\(recording.id?.uuidString ?? \"nil\") (confidence: \\(bestTitleItem.confidence))\", level: .debug)","violation":{"ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1217},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 186 characters","severity":"warning"}},{"text":" AppLog.shared.dataMigration(\"Generated title from transcript for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1239},"reason":"Line should be 120 characters or less; currently it has 160 characters","ruleIdentifier":"line_length"}},{"text":" let validatedTitle = RecordingNameGenerator.validateAndFixRecordingName(newTitle, originalName: currentName)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1246,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.dataMigration(\"Converted URL to relative path for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1279,"character":1},"reason":"Line should be 120 characters or less; currently it has 155 characters","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"}},{"violation":{"reason":"Line should be 120 characters or less; currently it has 135 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"line":1327,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":1},"severity":"warning"},"text":" AppLog.shared.dataMigration(\"Removing duplicate recording ID: \\(duplicate.id?.uuidString ?? \"nil\")\", level: .debug)"},{"violation":{"reason":"Function should have complexity 10 or less; currently complexity is 19","location":{"line":1345,"character":5,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift"},"ruleIdentifier":"cyclomatic_complexity","ruleDescription":"Complexity of function bodies should be limited.","ruleName":"Cyclomatic Complexity","severity":"warning"},"text":" func resolveFilenameTitleDuplicates() async -> Int {"},{"violation":{"ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":5,"line":1345},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 94 lines","severity":"warning","ruleName":"Function Body Length","ruleDescription":"Function bodies should not span too many lines"},"text":" func resolveFilenameTitleDuplicates() async -> Int {"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 149 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1376,"character":1},"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" \/\/ Check if the other recording has a nice title and content (exclude standardized names from being considered \"nice titles\")"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":1,"line":1377},"reason":"Line should be 120 characters or less; currently it has 126 characters"},"text":" let isOtherStandardized = otherName.hasPrefix(\"apprecording-\") || otherName.hasPrefix(\"importedfile-\")"},{"violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 147 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":1,"line":1387}},"text":" let timeDifference = abs((recording.recordingDate ?? Date()).timeIntervalSince(otherRecording.recordingDate ?? Date()))"},{"violation":{"ruleName":"Line Length","reason":"Line should be 200 characters or less; currently it has 279 characters","severity":"error","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1395},"ruleIdentifier":"line_length"},"text":" AppLog.shared.dataMigration(\"Potential duplicate pair found - generic ID: \\(recording.id?.uuidString ?? \"nil\"), titled ID: \\(otherRecording.id?.uuidString ?? \"nil\"), timeDiff: \\(Int(timeDifference))s, sameLocation: \\(sameLocation)\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1408},"reason":"Line should be 120 characters or less; currently it has 176 characters","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.dataMigration(\"Merging duplicate generic ID: \\(generic.id?.uuidString ?? \"nil\") into titled ID: \\(titled.id?.uuidString ?? \"nil\")\", level: .debug)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":1467,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift"},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 122 characters","ruleIdentifier":"line_length"},"text":" AppLog.shared.dataMigration(\"Merged and deleted generic recording ID: \\(generic.id?.uuidString ?? \"nil\")\")"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1500,"character":17},"ruleIdentifier":"for_where","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleName":"Prefer For-Where","severity":"warning","reason":"`where` clauses are preferred over a single `if` inside a `for`"},"text":" if transcript.recording == nil {"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 136 characters","location":{"line":1501,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift"},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"},"text":" AppLog.shared.dataMigration(\"Removing orphaned transcript ID: \\(transcript.id?.uuidString ?? \"nil\")\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 130 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":1,"line":1520},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" AppLog.shared.dataMigration(\"Removing orphaned summary ID: \\(summary.id?.uuidString ?? \"nil\")\", level: .debug)"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"line":1525,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 159 characters","severity":"warning"},"text":" AppLog.shared.dataMigration(\"Keeping preserved summary (anchor recordingId present) ID: \\(summary.id?.uuidString ?? \"nil\")\", level: .debug)"},{"violation":{"severity":"error","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1585,"character":1},"ruleIdentifier":"line_length","reason":"Line should be 200 characters or less; currently it has 295 characters"},"text":" AppLog.shared.dataMigration(\"Recording #\\(index + 1): ID=\\(id), hasTranscript=\\(hasTranscript), hasTranscriptId=\\(hasTranscriptId), hasSummary=\\(hasSummary), hasSummaryId=\\(hasSummaryId), transcriptionStatus=\\(transcriptionStatus), summaryStatus=\\(summaryStatus)\", level: .debug)"},{"violation":{"severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"line":1599,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.dataMigration(\"Recording #\\(index + 1) has generic name pattern, ID: \\(id)\", level: .debug)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 186 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":1614,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":1},"ruleName":"Line Length"},"text":" AppLog.shared.dataMigration(\" Orphaned transcript ID: \\(transcript.id?.uuidString ?? \"nil\"), recordingId: \\(transcript.recordingId?.uuidString ?? \"nil\")\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":1619,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 177 characters","ruleName":"Line Length"},"text":" AppLog.shared.dataMigration(\" Orphaned summary ID: \\(summary.id?.uuidString ?? \"nil\"), recordingId: \\(summary.recordingId?.uuidString ?? \"nil\")\", level: .debug)"},{"violation":{"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 54 lines","ruleIdentifier":"function_body_length","location":{"character":5,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1628},"severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length"},"text":" func findAndImportOrphanedAudioFiles() async -> Int {"},{"violation":{"severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 150 characters","ruleIdentifier":"line_length","location":{"character":1,"line":1641,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift"},"ruleDescription":"Lines should not span too many characters."},"text":" let allFiles = try FileManager.default.contentsOfDirectory(at: documentsURL, includingPropertiesForKeys: [.isRegularFileKey], options: [])"},{"violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 173 characters","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":1,"line":1686}},"text":" AppLog.shared.dataMigration(\"Import summary - total files: \\(audioFiles.count), already in DB: \\(existingURLs.count), imported: \\(importedCount)\", level: .debug)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"character":1,"line":1749,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift"},"reason":"Line should be 120 characters or less; currently it has 126 characters","ruleName":"Line Length","severity":"warning"},"text":" AppLog.shared.dataMigration(\"Imported orphaned audio file as recording ID: \\(recordingEntry.id?.uuidString ?? \"nil\")\")"},{"violation":{"ruleIdentifier":"cyclomatic_complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleName":"Cyclomatic Complexity","reason":"Function should have complexity 10 or less; currently complexity is 13","location":{"line":1753,"character":5,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift"}},"text":" func forceNameSynchronization() async -> Int {"},{"violation":{"location":{"character":5,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1753},"ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 78 lines","ruleName":"Function Body Length","severity":"warning"},"text":" func forceNameSynchronization() async -> Int {"},{"violation":{"severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 125 characters","location":{"line":1772,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift"},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" (currentName.count > 15 && (currentName.contains(\"1754\") || currentName.contains(\"2025\")))"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","location":{"line":1775,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":1},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 146 characters"},"text":" AppLog.shared.dataMigration(\"Skipping non-generic name for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 140 characters","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1779,"character":1}},"text":" AppLog.shared.dataMigration(\"Processing generic name for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 186 characters","severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1791,"character":1},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" AppLog.shared.dataMigration(\"Found summary title for recording ID: \\(recording.id?.uuidString ?? \"nil\") (confidence: \\(bestTitleItem.confidence))\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"line":1799,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift"},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 139 characters"},"text":" AppLog.shared.dataMigration(\"Using summary recording name for ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1820,"character":1},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 160 characters","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning"},"text":" AppLog.shared.dataMigration(\"Generated title from transcript for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":1,"line":1827},"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 128 characters","severity":"warning"},"text":" let validatedTitle = RecordingNameGenerator.validateAndFixRecordingName(newTitle, originalName: currentName)"},{"violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 144 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","location":{"line":1835,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift"}},"text":" AppLog.shared.dataMigration(\"No suitable title found for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)"},{"violation":{"severity":"warning","ruleName":"Cyclomatic Complexity","ruleIdentifier":"cyclomatic_complexity","location":{"character":5,"line":1919,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift"},"ruleDescription":"Complexity of function bodies should be limited.","reason":"Function should have complexity 10 or less; currently complexity is 13"},"text":" func fixInvalidURLs() async -> Int {"},{"violation":{"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 63 lines","ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length","severity":"warning","ruleIdentifier":"function_body_length","location":{"line":1919,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":5}},"text":" func fixInvalidURLs() async -> Int {"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 128 characters","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1930},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" let allFiles = try FileManager.default.contentsOfDirectory(at: documentsURL, includingPropertiesForKeys: [.nameKey])"},{"violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1961},"reason":"Line should be 120 characters or less; currently it has 133 characters","ruleIdentifier":"line_length"},"text":" AppLog.shared.dataMigration(\"Recording has invalid URL, ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":1,"line":1981},"reason":"Line should be 120 characters or less; currently it has 127 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning"},"text":" AppLog.shared.dataMigration(\"Fixed URL for recording ID: \\(recording.id?.uuidString ?? \"nil\")\")"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 157 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1987,"character":1},"severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.dataMigration(\"Could not find matching file for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .error)"},{"violation":{"ruleDescription":"Function bodies should not span too many lines","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2008,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 60 lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","severity":"warning"},"text":" func cleanupMissingAudioReferences() async -> Int {"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2020},"reason":"Line should be 120 characters or less; currently it has 128 characters","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.dataMigration(\"Recording has no URL, ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)"},{"violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 165 characters","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2024,"character":1},"ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.dataMigration(\"Cleaning up orphaned transcript for URL-less recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 121 characters","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"line":2033,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift"}},"text":" AppLog.shared.dataMigration(\"Checking recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"line":2057,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift"},"reason":"Line should be 120 characters or less; currently it has 143 characters"},"text":" AppLog.shared.dataMigration(\"Invalid URL format for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)"},{"violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2061,"character":1},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 176 characters"},"text":" AppLog.shared.dataMigration(\"Cleanup decision for recording ID \\(recording.id?.uuidString ?? \"nil\"): shouldCleanup=\\(shouldCleanup) (\\(reason))\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 138 characters","location":{"character":1,"line":2065,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift"}},"text":" AppLog.shared.dataMigration(\"Cleaning missing audio reference for recording ID: \\(recording.id?.uuidString ?? \"nil\")\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 164 characters","severity":"warning","location":{"character":1,"line":2073,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift"},"ruleIdentifier":"line_length","ruleName":"Line Length"},"text":" AppLog.shared.dataMigration(\"Deleting transcript for recording with no audio file, ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"error","location":{"character":1,"line":2119,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift"},"reason":"Line should be 200 characters or less; currently it has 224 characters","ruleName":"Line Length","ruleIdentifier":"line_length"},"text":" AppLog.shared.dataMigration(\"Comprehensive fix completed - orphans: \\(cleanedOrphans), incomplete: \\(fixedIncomplete), URLs: \\(urlFixes), renames: \\(renames), validations: \\(validations), specific: \\(specificFixes)\")"},{"violation":{"ruleDescription":"Complexity of function bodies should be limited.","ruleName":"Cyclomatic Complexity","ruleIdentifier":"cyclomatic_complexity","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2125,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 11"},"text":" private func fixGenericNamedRecordingsIssue() async -> Int {"},{"violation":{"severity":"warning","location":{"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2125},"ruleIdentifier":"function_body_length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 55 lines","ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length"},"text":" private func fixGenericNamedRecordingsIssue() async -> Int {"},{"text":" (currentName.count > 15 && (currentName.contains(\"1754\") || currentName.contains(\"2025\")))","violation":{"severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2142},"reason":"Line should be 120 characters or less; currently it has 125 characters","ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.dataMigration(\"Found generic recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2145},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 130 characters","ruleName":"Line Length"}},{"text":" AppLog.shared.dataMigration(\"Fixed recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"location":{"character":1,"line":2184,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift"},"reason":"Line should be 120 characters or less; currently it has 126 characters","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"text":" private func linkOrphanedContentToRecording(_ recording: RecordingEntry) async {","violation":{"ruleName":"Function Body Length","ruleDescription":"Function bodies should not span too many lines","location":{"line":2202,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift"},"severity":"warning","ruleIdentifier":"function_body_length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 56 lines"}},{"text":" transcriptFetch.predicate = NSPredicate(format: \"recording == nil AND recordingId == %@\", recordingId as CVarArg)","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 121 characters","location":{"line":2207,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift"},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" AppLog.shared.dataMigration(\"Linking orphaned transcript to recording ID: \\(recordingId)\", level: .debug)","violation":{"ruleName":"Line Length","location":{"line":2212,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":1},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 121 characters","ruleIdentifier":"line_length","severity":"warning"}},{"text":" AppLog.shared.dataMigration(\"Updated recording name from transcript for ID: \\(recordingId)\", level: .debug)","violation":{"reason":"Line should be 120 characters or less; currently it has 135 characters","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2234},"severity":"warning"}},{"text":" let cleanedTitle = RecordingNameGenerator.validateAndFixRecordingName(bestTitle.text, originalName: recording.recordingName ?? \"\")","violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2261,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters","ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.dataMigration(\"Updated recording name from summary for ID: \\(recordingId)\", level: .debug)","violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2264,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":"}","violation":{"severity":"error","ruleName":"File Length","ruleIdentifier":"file_length","location":{"line":2309,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","character":1},"ruleDescription":"Files should not span too many lines.","reason":"File should contain 1000 lines or less: currently contains 2309"}},{"text":" AppLog.shared.performance(\"DeviceCompatibility: Simulator detected - enabling native speech transcription support\")","violation":{"ruleIdentifier":"line_length","location":{"line":15,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DeviceCompatibility.swift"},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 123 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.performance(\"DeviceCompatibility: Native speech transcription supported (RAM: \\(String(format: \"%.1f\", totalMemoryGB))GB)\")","violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"character":1,"line":24,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DeviceCompatibility.swift"},"reason":"Line should be 120 characters or less; currently it has 149 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"violation":{"ruleIdentifier":"line_length","location":{"line":27,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DeviceCompatibility.swift","character":1},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 163 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" AppLog.shared.performance(\"DeviceCompatibility: Native speech transcription requires 3GB+ RAM (Device has \\(String(format: \"%.1f\", totalMemoryGB))GB)\")"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 136 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DeviceCompatibility.swift","character":1,"line":80},"severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length"},"text":" AppLog.shared.performance(\"DeviceCompatibility: FluidAudio supported (RAM: \\(String(format: \"%.1f\", totalMemoryGB))GB)\")"},{"violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DeviceCompatibility.swift","character":1,"line":82},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 150 characters"},"text":" AppLog.shared.performance(\"DeviceCompatibility: FluidAudio requires 4GB+ RAM (Device has \\(String(format: \"%.1f\", totalMemoryGB))GB)\")"},{"violation":{"severity":"warning","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift","line":35},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 145 characters"},"text":" init(text: String, priority: Priority = .medium, timeReference: String? = nil, category: TaskCategory = .general, confidence: Double = 0.5) {"},{"violation":{"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 54 lines","location":{"line":130,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift","character":16},"ruleDescription":"Function bodies should not span too many lines","severity":"warning","ruleIdentifier":"function_body_length","ruleName":"Function Body Length"},"text":" static func fromReminderText(_ text: String) -> TimeReference {"},{"violation":{"severity":"warning","ruleIdentifier":"for_where","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","reason":"`where` clauses are preferred over a single `if` inside a `for`","location":{"line":164,"character":17,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift"},"ruleName":"Prefer For-Where"},"text":" if lowercased.contains(pattern) {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","location":{"line":356,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift"},"severity":"error","ruleName":"Line Length","reason":"Line should be 200 characters or less; currently it has 376 characters","ruleIdentifier":"line_length"},"text":" init(recordingURL: URL, recordingName: String, recordingDate: Date, summary: String, tasks: [TaskItem] = [], reminders: [ReminderItem] = [], titles: [TitleItem] = [], attachments: [SummaryAttachment] = [], userNotes: String? = nil, contentType: ContentType = .general, aiEngine: String = \"Unknown\", aiModel: String, originalLength: Int, processingTime: TimeInterval = 0) {"},{"violation":{"ruleIdentifier":"line_length","location":{"line":381,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"},"text":" let reminderConfidence = reminders.isEmpty ? 0.5 : reminders.map { $0.confidence }.reduce(0, +) \/ Double(reminders.count)"},{"violation":{"reason":"Line should be 200 characters or less; currently it has 422 characters","location":{"character":1,"line":387,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift"},"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"error"},"text":" init(recordingId: UUID, transcriptId: UUID? = nil, recordingURL: URL, recordingName: String, recordingDate: Date, summary: String, tasks: [TaskItem] = [], reminders: [ReminderItem] = [], titles: [TitleItem] = [], attachments: [SummaryAttachment] = [], userNotes: String? = nil, contentType: ContentType = .general, aiEngine: String = \"Unknown\", aiModel: String, originalLength: Int, processingTime: TimeInterval = 0) {"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift","line":412,"character":1},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 129 characters","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" let reminderConfidence = reminders.isEmpty ? 0.5 : reminders.map { $0.confidence }.reduce(0, +) \/ Double(reminders.count)"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"error","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift","line":418},"reason":"Line should be 200 characters or less; currently it has 560 characters"},"text":" init(id: UUID, recordingId: UUID?, transcriptId: UUID? = nil, recordingURL: URL, recordingName: String, recordingDate: Date, summary: String, tasks: [TaskItem] = [], reminders: [ReminderItem] = [], titles: [TitleItem] = [], attachments: [SummaryAttachment] = [], userNotes: String? = nil, contentType: ContentType = .general, aiEngine: String = \"Unknown\", aiModel: String, originalLength: Int, processingTime: TimeInterval = 0, generatedAt: Date? = nil, version: Int = 1, wordCount: Int? = nil, compressionRatio: Double? = nil, confidence: Double? = nil) {"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift","line":436},"reason":"Line should be 120 characters or less; currently it has 123 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" self.wordCount = wordCount ?? summary.components(separatedBy: .whitespacesAndNewlines).filter { !$0.isEmpty }.count"},{"text":" self.compressionRatio = compressionRatio ?? (originalLength > 0 ? Double(self.wordCount) \/ Double(originalLength) : 0.0)","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 128 characters","location":{"line":438,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift","character":1}}},{"text":" let reminderConfidence = reminders.isEmpty ? 0.5 : reminders.map { $0.confidence }.reduce(0, +) \/ Double(reminders.count)","violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 133 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"line":442,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift"}}},{"text":" let titleConfidence = titles.isEmpty ? 0.5 : titles.map { $0.confidence }.reduce(0, +) \/ Double(titles.count)","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 121 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift","character":1,"line":443}}},{"text":" let c = try decoder.container(keyedBy: CodingKeys.self)","violation":{"reason":"Variable name 'c' should be between 3 and 40 characters long","ruleIdentifier":"identifier_name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleName":"Identifier Name","severity":"error","location":{"line":467,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift","character":13}}},{"text":"}","violation":{"severity":"warning","ruleIdentifier":"file_length","ruleName":"File Length","location":{"line":511,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift"},"ruleDescription":"Files should not span too many lines.","reason":"File should contain 400 lines or less: currently contains 511"}},{"text":"class RecordingArchiveService: ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 690 lines","location":{"line":62,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","character":1},"ruleIdentifier":"type_body_length"}},{"text":" AppLog.shared.recording(\"Archive: not marking \\(recording.recordingName ?? \"unknown\") archived because no destination URL was saved\", level: .error)","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 164 characters","location":{"line":99,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift"},"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.recording(\"Archived: failed to remove local audio: \\(error.localizedDescription)\", level: .error)","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","character":1,"line":123},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 135 characters","ruleIdentifier":"line_length","severity":"warning"}},{"text":" AppLog.shared.recording(\"Archived \\(archivedCount) of \\(recordings.count) recording(s), removeLocal=\\(removeLocal)\")","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"line":136,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.recording(\"Failed to query recordings older than \\(days) days: \\(error.localizedDescription)\", level: .error)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 135 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":162},"ruleIdentifier":"line_length"}},{"text":" AppLog.shared.recording(\"Cleared archive flags (local audio intact): \\(recording.recordingName ?? \"unknown\")\")","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"line":213,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift"},"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" AppLog.shared.recording(\"Archive: failed to fetch archive locations: \\(error.localizedDescription)\", level: .error)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","character":1,"line":231},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" func restoreArchivedRecording(_ recording: RecordingEntry, from locationId: UUID? = nil) throws -> URL {","violation":{"ruleName":"Cyclomatic Complexity","ruleIdentifier":"cyclomatic_complexity","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":241,"character":5},"reason":"Function should have complexity 10 or less; currently complexity is 11","ruleDescription":"Complexity of function bodies should be limited."}},{"text":" func restoreArchivedRecording(_ recording: RecordingEntry, from locationId: UUID? = nil) throws -> URL {","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":241,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 66 lines","ruleName":"Function Body Length","ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines","severity":"warning"}},{"text":" coordinator.coordinate(writingItemAt: sourceURL, options: .forDeleting, error: &coordinatorError) { coordinatedURL in","violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"line":323,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" private func recordArchiveLocations(for recordings: [RecordingEntry], exportedURLs: [URL], exportedAt: Date) -> [RecordingArchiveLocationInfo] {","violation":{"location":{"line":343,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","character":1},"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 148 characters"}},{"text":" private func recordArchiveLocations(for recordings: [RecordingEntry], exportedURLs: [URL], exportedAt: Date) -> [RecordingArchiveLocationInfo] {","violation":{"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","severity":"warning","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","location":{"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":343}}},{"text":" AppLog.shared.recording(\"Archive: exported URL did not match a staged recording: \\(url.lastPathComponent)\", level: .debug)","violation":{"location":{"line":359,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" AppLog.shared.recording(\"Archive: skipped untrackable destination URL \\(url.lastPathComponent)\", level: .error)","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":409},"reason":"Line should be 120 characters or less; currently it has 127 characters","ruleIdentifier":"line_length"}},{"text":" AppLog.shared.recording(\"Archive: failed to resolve bookmark: \\(error.localizedDescription)\", level: .error)","violation":{"severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":512},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" displayName: object.value(forKey: \"displayName\") as? String ?? object.value(forKey: \"exportedFilename\") as? String ?? \"Archived audio\",","violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":575,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift"},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 147 characters"}},{"text":" AppLog.shared.recording(\"Audio export: failed to create staging dir: \\(error.localizedDescription)\", level: .error)","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":639},"reason":"Line should be 120 characters or less; currently it has 127 characters","ruleName":"Line Length","ruleIdentifier":"line_length"}},{"text":" AppLog.shared.recording(\"Audio export: failed to create staging dir: \\(error.localizedDescription)\", level: .error)","violation":{"ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"line":669,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift"},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" AppLog.shared.recording(\"Audio export: failed to stage \\(sourceURL.lastPathComponent): \\(error.localizedDescription)\", level: .error)","violation":{"reason":"Line should be 120 characters or less; currently it has 145 characters","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":708},"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning"}},{"violation":{"ruleName":"Line Length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":731},"reason":"Line should be 120 characters or less; currently it has 122 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.recording(\"Archive: failed to create staging dir: \\(error.localizedDescription)\", level: .error)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 144 characters","ruleName":"Line Length","severity":"warning","location":{"line":751,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift"},"ruleIdentifier":"line_length"},"text":" AppLog.shared.recording(\"Archive: failed to stage \\(sourceURL.lastPathComponent): \\(error.localizedDescription)\", level: .error)"},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":925},"reason":"File should contain 400 lines or less: currently contains 925","ruleIdentifier":"file_length","ruleDescription":"Files should not span too many lines.","ruleName":"File Length","severity":"warning"},"text":"}"},{"violation":{"ruleDescription":"Type bodies should not span too many lines","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":5},"ruleName":"Type Body Length","severity":"error","ruleIdentifier":"type_body_length","reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 511 lines"},"text":"class RecordingNameGenerator {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":9},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 178 characters","ruleIdentifier":"line_length","ruleName":"Line Length"},"text":" static func generateRecordingNameFromTranscript(_ transcript: String, contentType: ContentType, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) -> String {"},{"violation":{"reason":"Function should have complexity 10 or less; currently complexity is 15","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","character":5,"line":9},"ruleIdentifier":"cyclomatic_complexity","ruleDescription":"Complexity of function bodies should be limited.","ruleName":"Cyclomatic Complexity","severity":"warning"},"text":" static func generateRecordingNameFromTranscript(_ transcript: String, contentType: ContentType, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) -> String {"},{"violation":{"ruleIdentifier":"function_body_length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 60 lines","ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","character":12,"line":9}},"text":" static func generateRecordingNameFromTranscript(_ transcript: String, contentType: ContentType, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) -> String {"},{"violation":{"location":{"line":14,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift"},"reason":"Line should be 120 characters or less; currently it has 126 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length"},"text":" AppLog.shared.recording(\"RecordingNameGenerator: Starting name generation with \\(titles.count) titles\", level: .debug)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 128 characters","severity":"warning","ruleIdentifier":"line_length","location":{"character":1,"line":16,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift"},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.recording(\"RecordingNameGenerator: Title \\(index + 1): confidence \\(title.confidence)\", level: .debug)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 148 characters","location":{"line":34,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","character":1},"ruleName":"Line Length","ruleIdentifier":"line_length"},"text":" AppLog.shared.recording(\"RecordingNameGenerator: Processing high-confidence title (confidence: \\(bestTitle.confidence))\", level: .debug)"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","character":1,"line":46},"reason":"Line should be 120 characters or less; currently it has 135 characters","ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" AppLog.shared.recording(\"RecordingNameGenerator: Processing any title (confidence: \\(anyTitle.confidence))\", level: .debug)"},{"violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 123 characters","ruleIdentifier":"line_length","location":{"character":1,"line":89,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift"},"ruleName":"Line Length"},"text":" return generateNameFromTranscript(transcript, contentType: contentType, minLength: minLength, maxLength: maxLength)"},{"text":" static func generateRecordingName(from summary: String, contentType: ContentType, tasks: [TaskItem], reminders: [ReminderItem]) -> String {","violation":{"reason":"Line should be 120 characters or less; currently it has 143 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length","location":{"character":1,"line":92,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift"}}},{"text":" let summaryName = generateNameFromSummary(summary, contentType: contentType, minLength: minLength, maxLength: maxLength)","violation":{"reason":"Line should be 120 characters or less; currently it has 128 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"line":114,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift"}}},{"text":" let genericNames = [\"the\", \"a\", \"an\", \"this\", \"that\", \"it\", \"and\", \"or\", \"but\", \"in\", \"on\", \"at\", \"to\", \"for\", \"of\", \"with\", \"by\"]","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"line":127,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift"},"ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" if cleanedName.lowercased().hasSuffix(ext) {","violation":{"ruleName":"Prefer For-Where","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","severity":"warning","location":{"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":156},"ruleIdentifier":"for_where","reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" 9. Never end with weak words like \"with\", \"to\", \"for\", \"of\", \"in\", \"on\", \"at\", \"by\", \"from\", \"about\", \"regarding\", \"concerning\", \"pertaining\", \"related\", \"involving\", \"including\", \"containing\", \"featuring\", \"about\", \"regarding\", \"concerning\", \"pertaining\", \"related\", \"involving\", \"including\", \"containing\", \"featuring\"","violation":{"severity":"error","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"line":177,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","character":1},"ruleName":"Line Length","reason":"Line should be 200 characters or less; currently it has 327 characters"}},{"text":" **IMPORTANT: Return ONLY the title, nothing else. No quotes, no explanation, no markdown formatting, no extra text, no punctuation at the end.**","violation":{"reason":"Line should be 120 characters or less; currently it has 152 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"line":193,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","character":1},"ruleIdentifier":"line_length"}},{"text":" static func cleanStandardizedTitleResponse(_ response: String) -> String {","violation":{"severity":"warning","location":{"line":202,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","character":5},"ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","ruleName":"Cyclomatic Complexity","reason":"Function should have complexity 10 or less; currently complexity is 11"}},{"text":" static func cleanStandardizedTitleResponse(_ response: String) -> String {","violation":{"location":{"line":202,"character":12,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift"},"ruleName":"Function Body Length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 54 lines","ruleIdentifier":"function_body_length","severity":"warning","ruleDescription":"Function bodies should not span too many lines"}},{"text":" if cleanedTitle.lowercased().hasSuffix(roleSuffix) {","violation":{"ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleName":"Prefer For-Where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","character":13,"line":226},"ruleIdentifier":"for_where","reason":"`where` clauses are preferred over a single `if` inside a `for`","severity":"warning"}},{"text":" cleanedTitle = String(cleanedTitle.dropLast(roleSuffix.count)).trimmingCharacters(in: .whitespacesAndNewlines)","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":227},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 126 characters","severity":"warning"}},{"text":" let genericTitles = [\"title\", \"conversation\", \"meeting\", \"discussion\", \"talk\", \"chat\", \"recording\", \"audio\", \"transcript\"]","violation":{"reason":"Line should be 120 characters or less; currently it has 130 characters","location":{"line":277,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift"},"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning"}},{"text":" if genericTitles.contains(lowerTitle) || genericTitles.contains(where: { lowerTitle.contains($0) && words.count <= 2 }) {","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":279,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters","severity":"warning"}},{"text":" if cleaned.lowercased().hasPrefix(prefix.lowercased()) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","location":{"character":13,"line":314,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift"},"reason":"`where` clauses are preferred over a single `if` inside a `for`","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where"}},{"text":" private static func generateNameFromTask(_ task: TaskItem, minLength: Int, maxLength: Int) -> String {","violation":{"ruleName":"Cyclomatic Complexity","ruleDescription":"Complexity of function bodies should be limited.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":392,"character":13},"ruleIdentifier":"cyclomatic_complexity","reason":"Function should have complexity 10 or less; currently complexity is 11","severity":"warning"}},{"text":" let actionKeywords = [\"call\", \"email\", \"meet\", \"buy\", \"get\", \"do\", \"make\", \"see\", \"visit\", \"go\", \"come\", \"take\", \"bring\", \"send\", \"schedule\", \"book\", \"order\", \"pick up\", \"drop off\", \"return\", \"check\", \"review\", \"update\", \"prepare\", \"create\", \"develop\", \"implement\", \"analyze\", \"research\", \"present\", \"discuss\", \"plan\", \"organize\"]","violation":{"ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":396,"character":1},"reason":"Line should be 200 characters or less; currently it has 338 characters","ruleDescription":"Lines should not span too many characters.","severity":"error","ruleName":"Line Length"}},{"text":" if taskText.contains(action) {","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":399,"character":13},"ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","reason":"`where` clauses are preferred over a single `if` inside a `for`","ruleName":"Prefer For-Where","severity":"warning"}},{"text":" let eventKeywords = [\"appointment\", \"meeting\", \"deadline\", \"call\", \"email\", \"visit\", \"check\", \"review\", \"presentation\", \"interview\", \"consultation\", \"follow-up\", \"check-in\"]","violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 181 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"line":443,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift"}}},{"text":" if reminderText.contains(event) {","violation":{"ruleName":"Prefer For-Where","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"character":13,"line":446,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift"},"severity":"warning","reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" private static func generateNameFromTranscript(_ transcript: String, contentType: ContentType, minLength: Int, maxLength: Int) -> String {","violation":{"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 142 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":483,"character":1}}},{"text":" private static func generateNameFromTranscript(_ transcript: String, contentType: ContentType, minLength: Int, maxLength: Int) -> String {","violation":{"ruleName":"Cyclomatic Complexity","ruleIdentifier":"cyclomatic_complexity","severity":"warning","reason":"Function should have complexity 10 or less; currently complexity is 16","location":{"character":13,"line":483,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift"},"ruleDescription":"Complexity of function bodies should be limited."}},{"text":" private static func generateNameFromTranscript(_ transcript: String, contentType: ContentType, minLength: Int, maxLength: Int) -> String {","violation":{"ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 56 lines","ruleName":"Function Body Length","severity":"warning","location":{"line":483,"character":20,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift"}}},{"text":" let titleKeywords = [\"meeting about\", \"discussion on\", \"call about\", \"talk about\", \"conversation about\", \"presentation on\", \"review of\", \"planning for\", \"discussion of\", \"interview with\", \"consultation about\", \"briefing on\", \"update on\", \"report on\"]","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"error","location":{"line":492,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift"},"reason":"Line should be 200 characters or less; currently it has 258 characters","ruleIdentifier":"line_length"}},{"text":" private static func generateNameFromSummary(_ summary: String, contentType: ContentType, minLength: Int, maxLength: Int) -> String {","violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":555,"character":1},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" AppLog.shared.recording(\"RecordingNameGenerator: Processing title with \\(words.count) words, constraints: min=\\(minLength), max=\\(maxLength)\", level: .debug)","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 165 characters","location":{"character":1,"line":603,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift"},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length"}},{"text":" AppLog.shared.recording(\"RecordingNameGenerator: Name too long, trying shorter (length: \\(shortName.count))\", level: .debug)","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 140 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":625,"character":1},"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.recording(\"RecordingNameGenerator: Trying longer name (length: \\(longerName.count))\", level: .debug)","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":635,"character":1},"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" AppLog.shared.recording(\"RecordingNameGenerator: Using original title (length: \\(title.text.count))\", level: .debug)","violation":{"reason":"Line should be 120 characters or less; currently it has 136 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":644,"character":1},"ruleName":"Line Length"}},{"text":"}","violation":{"ruleIdentifier":"file_length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":711},"reason":"File should contain 400 lines or less: currently contains 711","ruleDescription":"Files should not span too many lines.","ruleName":"File Length"}},{"text":"class RecordingWorkflowManager: ObservableObject {","violation":{"ruleIdentifier":"type_body_length","ruleDescription":"Type bodies should not span too many lines","ruleName":"Type Body Length","location":{"line":15,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift"},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 369 lines","severity":"error"}},{"text":" func createRecording(url: URL, name: String, date: Date, fileSize: Int64, duration: TimeInterval, quality: AudioQuality, locationData: LocationData? = nil) -> UUID {","violation":{"ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"line":33,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 169 characters","ruleName":"Line Length"}},{"text":" func createRecording(url: URL, name: String, date: Date, fileSize: Int64, duration: TimeInterval, quality: AudioQuality, locationData: LocationData? = nil) -> UUID {","violation":{"severity":"warning","location":{"character":5,"line":33,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift"},"ruleDescription":"Number of function parameters should be low.","reason":"Function should have 5 parameters or less: it currently has 6","ruleIdentifier":"function_parameter_count","ruleName":"Function Parameter Count"}},{"text":" AppLog.shared.backgroundProcessing(\"Saving location data - lat: \\(locationData.latitude), lon: \\(locationData.longitude)\")","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 134 characters","ruleIdentifier":"line_length","location":{"line":55,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift"},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" func createTranscript(for recordingId: UUID, segments: [TranscriptSegment], speakerMappings: [String: String] = [:], engine: TranscriptionEngine? = nil, processingTime: TimeInterval = 0, confidence: Double = 0.5) -> UUID? {","violation":{"location":{"line":79,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","character":1},"severity":"error","ruleIdentifier":"line_length","reason":"Line should be 200 characters or less; currently it has 227 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":" func createTranscript(for recordingId: UUID, segments: [TranscriptSegment], speakerMappings: [String: String] = [:], engine: TranscriptionEngine? = nil, processingTime: TimeInterval = 0, confidence: Double = 0.5) -> UUID? {","violation":{"severity":"warning","ruleName":"Function Body Length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 51 lines","ruleDescription":"Function bodies should not span too many lines","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":79,"character":5},"ruleIdentifier":"function_body_length"}},{"text":" AppLog.shared.backgroundProcessing(\"Creating transcript for recording: \\(recordingEntry.recordingName ?? \"unknown\")\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","character":1,"line":88},"reason":"Line should be 120 characters or less; currently it has 125 characters","ruleIdentifier":"line_length"}},{"text":" return replaceTranscript(existingTranscript, with: segments, speakerMappings: speakerMappings, engine: engine, processingTime: processingTime, confidence: confidence)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 178 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","character":1,"line":93}}},{"violation":{"reason":"Line should be 200 characters or less; currently it has 257 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":153},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"error"},"text":" private func replaceTranscript(_ existingTranscript: TranscriptEntry, with segments: [TranscriptSegment], speakerMappings: [String: String] = [:], engine: TranscriptionEngine? = nil, processingTime: TimeInterval = 0, confidence: Double = 0.5) -> UUID? {"},{"violation":{"ruleName":"Line Length","location":{"character":1,"line":155,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift"},"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 134 characters"},"text":" AppLog.shared.backgroundProcessing(\"Replacing existing transcript with ID: \\(existingTranscript.id?.uuidString ?? \"unknown\")\")"},{"violation":{"location":{"line":184,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift"},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 141 characters"},"text":" AppLog.shared.backgroundProcessing(\"Transcript replaced successfully with ID: \\(existingTranscript.id?.uuidString ?? \"unknown\")\")"},{"violation":{"reason":"Line should be 200 characters or less; currently it has 314 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"line":195,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","character":1},"ruleName":"Line Length","severity":"error"},"text":" func createSummary(for recordingId: UUID, transcriptId: UUID, summary: String, tasks: [TaskItem] = [], reminders: [ReminderItem] = [], titles: [TitleItem] = [], contentType: ContentType = .general, aiEngine: String = \"Unknown\", aiModel: String, originalLength: Int, processingTime: TimeInterval = 0) -> UUID? {"},{"violation":{"severity":"warning","ruleIdentifier":"cyclomatic_complexity","ruleDescription":"Complexity of function bodies should be limited.","ruleName":"Cyclomatic Complexity","location":{"character":5,"line":195,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift"},"reason":"Function should have complexity 10 or less; currently complexity is 14"},"text":" func createSummary(for recordingId: UUID, transcriptId: UUID, summary: String, tasks: [TaskItem] = [], reminders: [ReminderItem] = [], titles: [TitleItem] = [], contentType: ContentType = .general, aiEngine: String = \"Unknown\", aiModel: String, originalLength: Int, processingTime: TimeInterval = 0) -> UUID? {"},{"violation":{"ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","character":5,"line":195},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 111 lines"},"text":" func createSummary(for recordingId: UUID, transcriptId: UUID, summary: String, tasks: [TaskItem] = [], reminders: [ReminderItem] = [], titles: [TitleItem] = [], contentType: ContentType = .general, aiEngine: String = \"Unknown\", aiModel: String, originalLength: Int, processingTime: TimeInterval = 0) -> UUID? {"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"line":212,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 149 characters"},"text":" AppLog.shared.backgroundProcessing(\"Summary too short (\\(summaryTrimmed.count) chars) -- skipping save to avoid storing a failed result\")"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":217,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"},"text":" AppLog.shared.backgroundProcessing(\"Creating summary for recording: \\(recordingEntry.recordingName ?? \"unknown\")\")"},{"violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 125 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"line":218,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","character":1},"ruleIdentifier":"line_length"},"text":" AppLog.shared.backgroundProcessing(\"Recording UUID: \\(recordingId), Transcript UUID: \\(transcriptId)\", level: .debug)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","location":{"line":230,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","character":1},"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 142 characters"},"text":" AppLog.shared.backgroundProcessing(\"Found \\(existingSummaries.count) existing summary(ies) to clean up after save\", level: .debug)"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","character":1,"line":235},"reason":"Line should be 120 characters or less; currently it has 122 characters","severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" let recordingURL = appCoordinator?.coreDataManager.getAbsoluteURL(for: recordingEntry) ?? URL(fileURLWithPath: \"\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"character":1,"line":306,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift"},"reason":"Line should be 120 characters or less; currently it has 138 characters","severity":"warning"},"text":" AppLog.shared.backgroundProcessing(\"Migrated supplemental data from \\(oldId) to \\(summaryData.id)\", level: .debug)"},{"text":" AppLog.shared.backgroundProcessing(\"Failed to migrate supplemental data from \\(oldId): \\(error)\", level: .error)","violation":{"ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":308,"character":1},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 136 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"}},{"text":" AppLog.shared.backgroundProcessing(\"Cleaned up \\(deletedCount) old summary(ies) for recording \\(recordingId)\", level: .debug)","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":325,"character":1},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 145 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning"}},{"text":" AppLog.shared.backgroundProcessing(\"No valid URL found for recording: \\(recordingEntry.recordingName ?? \"unknown\")\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 143 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","character":1,"line":410},"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"}},{"text":" AppLog.shared.backgroundProcessing(\"Audio file renamed: \\(oldURL.lastPathComponent) -> \\(newURL.lastPathComponent)\")","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","character":1,"line":422},"reason":"Line should be 120 characters or less; currently it has 132 characters","ruleIdentifier":"line_length","ruleName":"Line Length"}},{"text":" AppLog.shared.backgroundProcessing(\"Audio file not found at expected location, checking new name\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 129 characters","severity":"warning","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":428,"character":1},"ruleIdentifier":"line_length"}},{"text":" AppLog.shared.backgroundProcessing(\"Updated Core Data URL to match existing file: \\(newURL.lastPathComponent)\")","violation":{"severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":434},"reason":"Line should be 120 characters or less; currently it has 131 characters","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.backgroundProcessing(\"Thumbnail generation warning during file rename (can be ignored)\", level: .debug)","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 133 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","character":1,"line":446}}},{"text":" AppLog.shared.backgroundProcessing(\"Failed to save Core Data after file rename: \\(error)\", level: .error)","violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":458},"reason":"Line should be 120 characters or less; currently it has 125 characters","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.backgroundProcessing(\"Failed to rename audio file: \\(error.localizedDescription)\", level: .error)","violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 127 characters","severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"line":461,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","character":1}}},{"text":"}","violation":{"reason":"File should contain 400 lines or less: currently contains 538","severity":"warning","ruleIdentifier":"file_length","ruleDescription":"Files should not span too many lines.","location":{"line":538,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift"},"ruleName":"File Length"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)","violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"line":29,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/SummarizationEngine.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 165 characters","ruleIdentifier":"line_length"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)","violation":{"ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","location":{"character":56,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/SummarizationEngine.swift","line":29},"ruleIdentifier":"large_tuple","reason":"Tuples should have at most 2 members","ruleName":"Large Tuple","severity":"error"}},{"text":" return \"Try with a shorter recording, check your connection, or increase the AI timeout in Settings > AI Processing.\"","violation":{"severity":"warning","ruleIdentifier":"line_length","location":{"line":54,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/SummarizationErrors.swift"},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 129 characters","ruleName":"Line Length"}},{"text":" return \"This transcript triggered safety filters on this AI engine. Try a different AI engine in Settings (e.g., OpenAI, Claude, or Gemini).\"","violation":{"severity":"warning","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/SummarizationErrors.swift","line":68,"character":1},"reason":"Line should be 120 characters or less; currently it has 153 characters"}},{"text":" let documents = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first ?? fileManager.temporaryDirectory","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"character":1,"line":125,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/SummaryAttachmentStore.swift"},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" AppLog.shared.summarization(\"SummaryMetadataCodec: Failed to encode metadata, falling back to plain model string\", level: .error)","violation":{"reason":"Line should be 120 characters or less; currently it has 141 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/SummaryMetadataCodec.swift","line":28,"character":1},"ruleIdentifier":"line_length"}},{"text":" init(recordingURL: URL, recordingName: String, recordingDate: Date, segments: [TranscriptSegment], speakerMappings: [String: String] = [:]) {","violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptData.swift","line":36,"character":1},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 145 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" init(recordingId: UUID, recordingURL: URL, recordingName: String, recordingDate: Date, segments: [TranscriptSegment], speakerMappings: [String: String] = [:], engine: TranscriptionEngine? = nil, processingTime: TimeInterval = 0, confidence: Double = 0.5) {","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptData.swift","character":1,"line":52},"ruleIdentifier":"line_length","reason":"Line should be 200 characters or less; currently it has 260 characters"}},{"text":" init(id: UUID, recordingId: UUID, recordingURL: URL, recordingName: String, recordingDate: Date, segments: [TranscriptSegment], speakerMappings: [String: String] = [:], engine: TranscriptionEngine? = nil, processingTime: TimeInterval = 0, confidence: Double = 0.5, createdAt: Date? = nil, lastModified: Date? = nil) {","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"error","location":{"line":68,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptData.swift"},"reason":"Line should be 200 characters or less; currently it has 321 characters"}},{"text":" private func convertCoreDataToTranscriptData(transcriptEntry: TranscriptEntry, recordingEntry: RecordingEntry) -> TranscriptData? {","violation":{"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 135 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"character":1,"line":68,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptManager.swift"}}},{"text":" AppLog.shared.transcription(\"Could not resolve URL for recording: \\(recordingEntry.recordingName ?? \"unknown\")\", level: .error)","violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"character":1,"line":76,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptManager.swift"},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" func activeTranscriptionJobStatus(for recording: RecordingEntry, appCoordinator: AppDataCoordinator) -> JobProcessingStatus? {","violation":{"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"line":52,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptionStarter.swift"},"reason":"Line should be 120 characters or less; currently it has 130 characters","ruleName":"Line Length"}},{"text":" AppLog.shared.transcription(\"Cleaned audio created at temp location: \\(tempCleanedURL.lastPathComponent)\", level: .debug)","violation":{"reason":"Line should be 120 characters or less; currently it has 137 characters","ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":110,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptionStarter.swift","character":1}}},{"text":" guard let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {","violation":{"reason":"Line should be 120 characters or less; currently it has 124 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"line":113,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptionStarter.swift"},"ruleIdentifier":"line_length"}},{"violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 123 characters","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptionStarter.swift","line":114,"character":1}},"text":" AppLog.shared.transcription(\"Could not access Documents directory, using original file\", level: .error)"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"line":126,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptionStarter.swift"},"reason":"Line should be 120 characters or less; currently it has 129 characters","severity":"warning"},"text":" performEnhancedTranscription(for: recording, sourceAudioURL: documentsCleanedURL, appCoordinator: appCoordinator)"},{"violation":{"severity":"warning","ruleDescription":"Function bodies should not span too many lines","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 68 lines","ruleName":"Function Body Length","ruleIdentifier":"function_body_length","location":{"line":136,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptionStarter.swift"}},"text":" private func performEnhancedTranscription(for recording: RecordingEntry,"},{"violation":{"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 136 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptionStarter.swift","line":141}},"text":" rawValue: UserDefaults.standard.string(forKey: \"selectedTranscriptionEngine\") ?? TranscriptionEngine.fluidAudio.rawValue"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"character":1,"line":171,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptionStarter.swift"},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 136 characters"},"text":" let result = try await enhancedTranscriptionManager.transcribeAudioFile(at: transcriptionURL, using: selectedEngine)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 150 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"line":172,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptionStarter.swift"},"ruleIdentifier":"line_length"},"text":" AppLog.shared.transcription(\"Transcription result: success=\\(result.success), textLength=\\(result.fullText.count)\", level: .debug)"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptionStarter.swift","character":1,"line":213},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 142 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" AppLog.shared.transcription(\"Cleaned up source audio file after fallback: \\(cleanupURL.lastPathComponent)\", level: .debug)"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/UserPreferences.swift","line":85,"character":1},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 126 characters","ruleIdentifier":"line_length"},"text":" formatter.setLocalizedDateFormatFromTemplate(timeFormat == .twentyFourHour ? \"M\/d\/yy HH:mm\" : \"M\/d\/yy h:mm a\")"},{"violation":{"ruleName":"Line Length","location":{"line":88,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/UserPreferences.swift"},"reason":"Line should be 120 characters or less; currently it has 136 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" formatter.setLocalizedDateFormatFromTemplate(timeFormat == .twentyFourHour ? \"MMM d, yyyy HH:mm\" : \"MMM d, yyyy h:mm a\")"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/UserPreferences.swift","line":91,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"},"text":" formatter.setLocalizedDateFormatFromTemplate(timeFormat == .twentyFourHour ? \"MMMM d, yyyy HH:mm\" : \"MMMM d, yyyy h:mm a\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/UserPreferences.swift","line":94,"character":1},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 150 characters"},"text":" formatter.setLocalizedDateFormatFromTemplate(timeFormat == .twentyFourHour ? \"EEEE, MMMM d, yyyy HH:mm\" : \"EEEE, MMMM d, yyyy h:mm a\")"},{"violation":{"ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":9,"line":45},"reason":"Variable name 'modified_at' should only contain alphanumeric and other allowed characters","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleName":"Identifier Name","severity":"error"},"text":" let modified_at: String"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","location":{"line":124,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1},"ruleDescription":"Lines should not span too many characters.","severity":"error","reason":"Line should be 200 characters or less; currently it has 449 characters"},"text":" \"description\": \"The main comprehensive summary of the entire transcript (15-20% of original length). CRITICAL: This should be a LONG, detailed summary with complete overview, all key points, insights, takeaways, main themes and conclusions. Use markdown formatting with ## headers, **bold**, β€’ bullets. This is the primary content field and must be substantial (minimum 500 characters for short transcripts, 2000+ for longer ones).\","},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1,"line":133},"reason":"Line should be 120 characters or less; currently it has 197 characters"},"text":" \"text\": [\"type\": \"string\", \"description\": \"Concise, specific, UNIQUE task description (one clear action item, not a long explanation). Must be different from other tasks.\"],"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 148 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":135,"character":1},"ruleName":"Line Length"},"text":" \"category\": [\"type\": \"string\", \"enum\": [\"Call\", \"Email\", \"Meeting\", \"Purchase\", \"Research\", \"Travel\", \"Health\", \"General\"]],"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":149},"reason":"Line should be 120 characters or less; currently it has 124 characters","ruleIdentifier":"line_length"},"text":" \"timeReference\": [\"type\": [\"string\", \"null\"], \"description\": \"Specific time\/date mentioned or null\"]"},{"violation":{"ruleIdentifier":"line_length","location":{"line":156,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 180 characters","severity":"warning"},"text":" \"description\": \"Array of 3-5 diverse, descriptive titles. Each title should capture a different aspect or topic. REQUIRED field - must generate at least 3 titles.\","},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":162},"reason":"Line should be 200 characters or less; currently it has 224 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"error","ruleName":"Line Length"},"text":" \"text\": [\"type\": \"string\", \"description\": \"Descriptive, unique title (40-60 characters). Each title must be different and capture a distinct aspect of the content.\", \"minLength\": 10, \"maxLength\": 80],"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":187,"character":1},"reason":"Line should be 120 characters or less; currently it has 148 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" \"category\": [\"type\": \"string\", \"enum\": [\"Call\", \"Email\", \"Meeting\", \"Purchase\", \"Research\", \"Travel\", \"Health\", \"General\"]],"},{"violation":{"severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 124 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1,"line":200}},"text":" \"timeReference\": [\"type\": [\"string\", \"null\"], \"description\": \"Specific time\/date mentioned or null\"]"},{"violation":{"severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":256},"ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 147 characters","ruleDescription":"Lines should not span too many characters."},"text":" init(type: String, description: String, items: OllamaProperty? = nil, properties: [String: OllamaProperty]? = nil, required: [String]? = nil) {"},{"violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 146 characters","severity":"warning","location":{"line":273,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1}},"text":" static func object(_ type: String, _ description: String, properties: [String: OllamaProperty], required: [String]? = nil) -> OllamaProperty {"},{"violation":{"reason":"Variable name 'num_predict' should only contain alphanumeric and other allowed characters","ruleIdentifier":"identifier_name","location":{"character":9,"line":279,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short."},"text":" let num_predict: Int"},{"violation":{"ruleName":"Identifier Name","severity":"error","ruleIdentifier":"identifier_name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","reason":"Variable name 'top_p' should only contain alphanumeric and other allowed characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":281,"character":9}},"text":" let top_p: Double"},{"text":" let top_k: Int","violation":{"ruleName":"Identifier Name","severity":"error","reason":"Variable name 'top_k' should only contain alphanumeric and other allowed characters","location":{"line":282,"character":9,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name"}},{"text":" let created_at: String","violation":{"ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","ruleName":"Identifier Name","severity":"error","reason":"Variable name 'created_at' should only contain alphanumeric and other allowed characters","location":{"character":9,"line":287,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"}}},{"text":" let done_reason: String?","violation":{"ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleName":"Identifier Name","severity":"error","reason":"Variable name 'done_reason' should only contain alphanumeric and other allowed characters","location":{"line":290,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":9},"ruleIdentifier":"identifier_name"}},{"text":" let total_duration: Int64?","violation":{"ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","reason":"Variable name 'total_duration' should only contain alphanumeric and other allowed characters","ruleName":"Identifier Name","severity":"error","location":{"character":9,"line":292,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"}}},{"text":" let load_duration: Int64?","violation":{"location":{"character":9,"line":293,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"ruleName":"Identifier Name","reason":"Variable name 'load_duration' should only contain alphanumeric and other allowed characters","ruleIdentifier":"identifier_name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","severity":"error"}},{"text":" let prompt_eval_count: Int?","violation":{"ruleIdentifier":"identifier_name","location":{"line":294,"character":9,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"severity":"error","reason":"Variable name 'prompt_eval_count' should only contain alphanumeric and other allowed characters","ruleName":"Identifier Name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short."}},{"text":" let prompt_eval_duration: Int64?","violation":{"ruleName":"Identifier Name","ruleIdentifier":"identifier_name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","severity":"error","reason":"Variable name 'prompt_eval_duration' should only contain alphanumeric and other allowed characters","location":{"character":9,"line":295,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"}}},{"text":" let eval_count: Int?","violation":{"ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":9,"line":296},"ruleName":"Identifier Name","reason":"Variable name 'eval_count' should only contain alphanumeric and other allowed characters","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","severity":"error"}},{"text":" let eval_duration: Int64?","violation":{"ruleName":"Identifier Name","severity":"error","reason":"Variable name 'eval_duration' should only contain alphanumeric and other allowed characters","ruleIdentifier":"identifier_name","location":{"line":297,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":9},"ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short."}},{"text":" let tool_calls: [OllamaToolCall]?","violation":{"ruleIdentifier":"identifier_name","ruleName":"Identifier Name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":9,"line":298},"ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","severity":"error","reason":"Variable name 'tool_calls' should only contain alphanumeric and other allowed characters"}},{"text":"class OllamaService: ObservableObject {","violation":{"ruleDescription":"Type bodies should not span too many lines","ruleName":"Type Body Length","ruleIdentifier":"type_body_length","severity":"error","location":{"character":1,"line":312,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 2057 lines"}},{"text":" AppLog.shared.networking(\"OllamaService: Connection test response: \\(httpResponse.statusCode)\", level: .debug)","violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"line":352,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 134 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":358},"severity":"warning","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.networking(\"OllamaService: Connection failed with status \\(httpResponse.statusCode)\", level: .error)"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 123 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":360}},"text":" AppLog.shared.networking(\"OllamaService: Error response received (\\(data.count) bytes)\", level: .error)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 123 characters","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"character":1,"line":378,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"}},"text":" AppLog.shared.networking(\"OllamaService: Connection test failed: \\(error.localizedDescription)\", level: .error)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 135 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":415,"character":1}},"text":" AppLog.shared.networking(\"OllamaService: Failed to check model availability: \\(error.localizedDescription)\", level: .error)"},{"violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":425,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters","ruleName":"Line Length","ruleIdentifier":"line_length"},"text":" AppLog.shared.networking(\"OllamaService: Failed to get available models: \\(error.localizedDescription)\", level: .error)"},{"violation":{"ruleDescription":"Function bodies should not span too many lines","severity":"warning","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","location":{"character":13,"line":474,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 52 lines"},"text":" private func extractJSONFromResponse(_ response: String) -> String {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 123 characters","severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":530}},"text":" AppLog.shared.networking(\"OllamaService: Successfully converted wrong schema to correct format\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":539,"character":1},"reason":"Line should be 120 characters or less; currently it has 163 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length"},"text":" if response.contains(\"\\\"summary\\\"\") || response.contains(\"\\\"contentType\\\"\") || response.contains(\"\\\"transcript\\\"\") || response.contains(\"\\\"key_points\\\"\") {"},{"violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"line":541,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"reason":"Line should be 120 characters or less; currently it has 137 characters","ruleIdentifier":"line_length"},"text":" AppLog.shared.networking(\"OllamaService: Detected complete processing context but invalid schema, returning empty structure\")"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":603,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"reason":"Line should be 120 characters or less; currently it has 131 characters","severity":"warning"},"text":" AppLog.shared.networking(\"OllamaService: Failed to convert wrong schema: \\(error.localizedDescription)\", level: .error)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 172 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1,"line":666}},"text":" func processComplete(from text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"location":{"line":666,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":5},"ruleIdentifier":"cyclomatic_complexity","reason":"Function should have complexity 10 or less; currently complexity is 11","ruleDescription":"Complexity of function bodies should be limited.","ruleName":"Cyclomatic Complexity","severity":"warning"},"text":" func processComplete(from text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"text":" func processComplete(from text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"severity":"error","reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 121 lines","location":{"character":5,"line":666,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length"}},{"text":" func processComplete(from text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"reason":"Tuples should have at most 2 members","ruleName":"Large Tuple","ruleIdentifier":"large_tuple","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","severity":"error","location":{"line":666,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":61}}},{"text":" AppLog.shared.networking(\"OllamaService: Structured outputs failed, falling back to traditional prompting: \\(error.localizedDescription)\")","violation":{"reason":"Line should be 120 characters or less; currently it has 150 characters","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":691},"ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.networking(\"OllamaService: Raw response for complete processing, length: \\(response.count) characters\", level: .debug)","violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"line":701,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 144 characters","ruleName":"Line Length"}},{"text":" AppLog.shared.networking(\"OllamaService: Summary: \\(rawResult.summary.count) chars, Tasks: \\(tasks.count), Reminders: \\(reminders.count), Titles: \\(titles.count)\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":760,"character":1},"reason":"Line should be 120 characters or less; currently it has 190 characters","ruleIdentifier":"line_length","ruleName":"Line Length"}},{"text":" AppLog.shared.networking(\"OllamaService: JSON parsing failed for complete processing: \\(error.localizedDescription)\", level: .error)","violation":{"severity":"warning","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"line":765,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"reason":"Line should be 120 characters or less; currently it has 144 characters","ruleIdentifier":"line_length"}},{"text":" AppLog.shared.networking(\"OllamaService: Attempting to parse cleaned JSON for complete processing\", level: .debug)","violation":{"severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":771,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.networking(\"OllamaService: Cleaned JSON parsing also failed: \\(error.localizedDescription)\", level: .error)","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 141 characters","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1,"line":821},"ruleDescription":"Lines should not span too many characters."}},{"text":" throw OllamaError.parsingError(\"Failed to parse JSON response after cleaning: \\(error.localizedDescription)\")","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1,"line":822},"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 129 characters","ruleName":"Line Length"}},{"text":" AppLog.shared.networking(\"OllamaService: Summary generation failed with parsing error: \\(message)\", level: .error)","violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 126 characters","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":842,"character":1},"ruleName":"Line Length","severity":"warning"}},{"text":" AppLog.shared.networking(\"OllamaService: Summary generation failed: \\(error.localizedDescription)\", level: .error)","violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"character":1,"line":845,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"reason":"Line should be 120 characters or less; currently it has 126 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":" let prompt = \"Please analyze the following transcript and create a comprehensive summary using the create_summary function:\\n\\n\\(text)\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"line":862,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","location":{"line":875,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"},"text":" AppLog.shared.networking(\"OllamaService: Successfully generated summary using standard tool calling\")"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"line":885,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 153 characters","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.networking(\"OllamaService: Standard tool calling failed, falling back to traditional prompting: \\(error.localizedDescription)\")"},{"violation":{"reason":"Line should be 200 characters or less; currently it has 232 characters","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"error","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":903}},"text":" \"A comprehensive markdown-formatted summary (approximately 10% of original transcript length) with ## headers, **bold** text, β€’ bullet points, and proper structure. Aim for substantive, detailed content.\""},{"violation":{"location":{"line":912,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"ruleName":"Function Body Length","ruleIdentifier":"function_body_length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 64 lines","severity":"warning","ruleDescription":"Function bodies should not span too many lines"},"text":" private func createCompleteAnalysisTool() -> OllamaTool {"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 162 characters","severity":"warning","location":{"line":934,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1},"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length"},"text":" \"category\": OllamaProperty.simple(\"string\", \"Category: Call, Email, Meeting, Purchase, Research, Travel, Health, or General\"),"},{"violation":{"ruleName":"Line Length","location":{"line":948,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 129 characters","ruleIdentifier":"line_length"},"text":" \"urgency\": OllamaProperty.simple(\"string\", \"Urgency: Immediate, Today, This Week, or Later\"),"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"line":949,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 124 characters"},"text":" \"timeReference\": OllamaProperty.simple(\"string\", \"Specific time\/date mentioned or null\")"},{"violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 134 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":962,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"ruleName":"Line Length"},"text":" \"category\": OllamaProperty.simple(\"string\", \"Category: Meeting, Personal, Technical, or General\"),"},{"violation":{"ruleName":"Line Length","location":{"line":997,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"reason":"Line should be 120 characters or less; currently it has 162 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length"},"text":" \"category\": OllamaProperty.simple(\"string\", \"Category: Call, Email, Meeting, Purchase, Research, Travel, Health, or General\"),"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 129 characters","location":{"line":1011,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"severity":"warning","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"},"text":" \"urgency\": OllamaProperty.simple(\"string\", \"Urgency: Immediate, Today, This Week, or Later\"),"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 134 characters","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"line":1041,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"}},"text":" \"category\": OllamaProperty.simple(\"string\", \"Category: Meeting, Personal, Technical, or General\"),"},{"violation":{"ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":13,"line":1056},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 58 lines","severity":"warning"},"text":" private func createRobustSummaryPrompt(from text: String) -> String {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"error","ruleName":"Line Length","reason":"Line should be 200 characters or less; currently it has 230 characters","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1073,"character":1}},"text":" You are a professional AI assistant specialized in analyzing and summarizing conversations, meetings, and transcripts. Your goal is to create comprehensive, well-structured summaries that capture the essential information."},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1124,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 55 lines","ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length","severity":"warning","ruleIdentifier":"function_body_length"},"text":" private func createRobustCompleteProcessingPrompt(from text: String) -> String {"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1127},"reason":"Line should be 120 characters or less; currently it has 143 characters"},"text":" You MUST return ONLY valid JSON in the EXACT format specified below. Do not include any other text, explanations, or additional fields."},{"violation":{"ruleIdentifier":"function_body_length","location":{"line":1193,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":5},"ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length","severity":"error","reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 122 lines"},"text":" func extractTasksAndReminders(from text: String) async throws -> (tasks: [TaskItem], reminders: [ReminderItem]) {"},{"violation":{"severity":"warning","location":{"line":1217,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 145 characters"},"text":" AppLog.shared.networking(\"OllamaService: Structured outputs failed for tasks\/reminders, falling back: \\(error.localizedDescription)\")"},{"violation":{"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"line":1249,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"reason":"Line should be 120 characters or less; currently it has 140 characters"},"text":" AppLog.shared.networking(\"OllamaService: Raw response for tasks\/reminders, length: \\(response.count) characters\", level: .debug)"},{"violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 126 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1,"line":1260},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" AppLog.shared.networking(\"OllamaService: Failed to convert tasks\/reminders response to UTF-8 data\", level: .error)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":1289,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"reason":"Line should be 120 characters or less; currently it has 128 characters","ruleName":"Line Length","ruleIdentifier":"line_length"},"text":" AppLog.shared.networking(\"OllamaService: Successfully parsed \\(tasks.count) tasks and \\(reminders.count) reminders\")"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 140 characters","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1292,"character":1},"ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.networking(\"OllamaService: JSON parsing failed for tasks\/reminders: \\(error.localizedDescription)\", level: .error)"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1298},"reason":"Line should be 120 characters or less; currently it has 126 characters"},"text":" AppLog.shared.networking(\"OllamaService: Attempting to parse cleaned JSON for tasks\/reminders\", level: .debug)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 154 characters","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1,"line":1334}},"text":" AppLog.shared.networking(\"OllamaService: Successfully parsed cleaned JSON with \\(tasks.count) tasks and \\(reminders.count) reminders\")"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 161 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"line":1337,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"ruleIdentifier":"line_length","severity":"warning"},"text":" AppLog.shared.networking(\"OllamaService: Cleaned JSON parsing also failed for tasks\/reminders: \\(error.localizedDescription)\", level: .error)"},{"violation":{"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 68 lines","ruleDescription":"Function bodies should not span too many lines","severity":"warning","ruleIdentifier":"function_body_length","location":{"line":1347,"character":5,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"ruleName":"Function Body Length"},"text":" func extractTitles(from text: String) async throws -> [TitleItem] {"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 131 characters","ruleIdentifier":"line_length","location":{"line":1368,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"},"text":" AppLog.shared.networking(\"OllamaService: Raw response for titles, length: \\(response.count) characters\", level: .debug)"},{"violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 131 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"character":1,"line":1400,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"}},"text":" AppLog.shared.networking(\"OllamaService: JSON parsing failed for titles: \\(error.localizedDescription)\", level: .error)"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 127 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1409,"character":1}},"text":" AppLog.shared.networking(\"OllamaService: Failed to convert cleaned titles response to data\", level: .error)"},{"violation":{"location":{"line":1424,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"reason":"Line should be 120 characters or less; currently it has 123 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"},"text":" AppLog.shared.networking(\"OllamaService: Successfully parsed cleaned JSON with \\(titles.count) titles\")"},{"violation":{"severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1427},"reason":"Line should be 120 characters or less; currently it has 152 characters","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.networking(\"OllamaService: Cleaned JSON parsing also failed for titles: \\(error.localizedDescription)\", level: .error)"},{"violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 190 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1,"line":1437}},"text":" private func processCompleteWithTools(from text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)? {"},{"violation":{"ruleName":"Large Tuple","ruleIdentifier":"large_tuple","severity":"error","location":{"line":1437,"character":78,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"reason":"Tuples should have at most 2 members","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead."},"text":" private func processCompleteWithTools(from text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)? {"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 143 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"line":1449,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1}},"text":" let prompt = \"Please analyze the following transcript and provide a complete analysis using the complete_analysis function:\\n\\n\\(text)\""},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1469,"character":1},"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 138 characters","ruleIdentifier":"line_length"},"text":" AppLog.shared.networking(\"OllamaService: Standard tool calling failed for complete processing: \\(error.localizedDescription)\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"line":1474,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 179 characters"},"text":" private func parseCompleteAnalysisResult(data: Data) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"ruleName":"Large Tuple","severity":"error","location":{"character":68,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1474},"ruleIdentifier":"large_tuple","reason":"Tuples should have at most 2 members","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead."},"text":" private func parseCompleteAnalysisResult(data: Data) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"line":1520,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1},"severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 136 characters"},"text":" AppLog.shared.networking(\"OllamaService: Failed to parse tool calling result: \\(error.localizedDescription)\", level: .error)"},{"violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 124 characters","location":{"line":1574,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"severity":"warning"},"text":" AppLog.shared.networking(\"OllamaService: Qwen tool calling failed, falling back: \\(error.localizedDescription)\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 194 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1579,"character":1},"ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length"},"text":" private func processCompleteWithQwenTools(from text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)? {"},{"violation":{"severity":"error","ruleName":"Large Tuple","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"character":82,"line":1579,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"reason":"Tuples should have at most 2 members"},"text":" private func processCompleteWithQwenTools(from text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)? {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","location":{"line":1597,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning"},"text":" AppLog.shared.networking(\"OllamaService: Found create_summary with \\(summary.count) characters\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 122 characters","location":{"character":1,"line":1601,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.networking(\"OllamaService: Using high-quality Qwen summary for complete processing\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 133 characters","location":{"line":1609,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"ruleIdentifier":"line_length"},"text":" AppLog.shared.networking(\"OllamaService: Successfully created complete result from high-quality summary\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 200 characters or less; currently it has 210 characters","ruleIdentifier":"line_length","severity":"error","location":{"line":1610,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1},"ruleName":"Line Length"},"text":" AppLog.shared.networking(\"OllamaService: Final result: Summary: \\(summary.count) chars, Tasks: \\(tasks.count), Reminders: \\(reminders.count), Titles: \\(titles.count)\", level: .debug)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 158 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"line":1613,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1}},"text":" AppLog.shared.networking(\"OllamaService: Failed to extract tasks\/reminders from excellent summary: \\(error.localizedDescription)\")"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 123 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1618,"character":1}},"text":" AppLog.shared.networking(\"OllamaService: Summary too short (\\(summary.count) chars), falling back\")"},{"violation":{"ruleName":"Line Length","severity":"warning","location":{"line":1623,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"},"text":" AppLog.shared.networking(\"OllamaService: No valid Qwen tool calls in complete processing response, falling back\")"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 134 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1,"line":1627},"severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length"},"text":" AppLog.shared.networking(\"OllamaService: Qwen tool calling failed for complete processing: \\(error.localizedDescription)\")"},{"violation":{"ruleIdentifier":"function_body_length","ruleName":"Function Body Length","reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 126 lines","location":{"line":1632,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"severity":"error","ruleDescription":"Function bodies should not span too many lines"},"text":" private func createQwenToolPrompt(for type: String, text: String) -> String {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","location":{"line":1651,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 181 characters","severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length"},"text":" \"description\": \"A comprehensive markdown-formatted summary (15-20% of original length) with ## headers, **bold** text, β€’ bullet points, and proper structure\""},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1,"line":1685},"reason":"Line should be 120 characters or less; currently it has 124 characters","ruleIdentifier":"line_length"},"text":" \"description\": \"Perform complete analysis extracting summary, tasks, reminders, titles, and content type\","},{"violation":{"reason":"Line should be 120 characters or less; currently it has 123 characters","severity":"warning","ruleIdentifier":"line_length","location":{"line":1691,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" \"description\": \"Comprehensive markdown-formatted summary with ## headers, **bold** text, β€’ bullets\""},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 156 characters","ruleName":"Line Length","severity":"warning","location":{"line":1701,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1}},"text":" \"category\": {\"type\": \"string\", \"description\": \"Category: Call, Email, Meeting, Purchase, Research, Travel, Health, or General\"},"},{"violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":1714,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"reason":"Line should be 120 characters or less; currently it has 123 characters","ruleIdentifier":"line_length"},"text":" \"urgency\": {\"type\": \"string\", \"description\": \"Urgency: Immediate, Today, This Week, or Later\"},"},{"violation":{"ruleIdentifier":"line_length","location":{"line":1727,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1},"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 128 characters","ruleName":"Line Length"},"text":" \"category\": {\"type\": \"string\", \"description\": \"Category: Meeting, Personal, Technical, or General\"},"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 149 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":1747,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"ruleIdentifier":"line_length","severity":"warning"},"text":" {\"name\": \"complete_analysis\", \"arguments\": {\"summary\": \"...\", \"tasks\": [...], \"reminders\": [...], \"titles\": [...], \"contentType\": \"...\"}}"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 144 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1,"line":1785},"ruleName":"Line Length","severity":"warning"},"text":" AppLog.shared.networking(\"OllamaService: Failed to parse Qwen tool call JSON: \\(error.localizedDescription)\", level: .error)"},{"violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 126 characters","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1792},"ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.networking(\"OllamaService: Found structured Qwen content, using as fallback summary\", level: .debug)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 133 characters","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1804,"character":1},"ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.networking(\"OllamaService: Summary content length: \\(cleanedResponse.count) characters\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1,"line":1813},"reason":"Line should be 120 characters or less; currently it has 197 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" private func parseQwenCompleteAnalysisResult(arguments: [String: Any]) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"ruleName":"Large Tuple","reason":"Tuples should have at most 2 members","severity":"error","ruleIdentifier":"large_tuple","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","location":{"line":1813,"character":86,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"}},"text":" private func parseQwenCompleteAnalysisResult(arguments: [String: Any]) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 127 characters","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1959,"character":1}},"text":" AppLog.shared.networking(\"OllamaService: GPT-OSS tool calling failed, falling back: \\(error.localizedDescription)\")"},{"violation":{"location":{"line":1964,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1},"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 196 characters","severity":"warning"},"text":" private func processCompleteWithGPTOSSTools(from text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)? {"},{"violation":{"severity":"error","ruleName":"Large Tuple","ruleIdentifier":"large_tuple","reason":"Tuples should have at most 2 members","location":{"character":84,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1964},"ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead."},"text":" private func processCompleteWithGPTOSSTools(from text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)? {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"line":1978,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"},"text":" AppLog.shared.networking(\"OllamaService: No valid GPT-OSS tool calls in complete processing response, falling back\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 137 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1982,"character":1},"ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length"},"text":" AppLog.shared.networking(\"OllamaService: GPT-OSS tool calling failed for complete processing: \\(error.localizedDescription)\")"},{"violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 172 characters","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1996,"character":1},"ruleIdentifier":"line_length"},"text":" - summary (string): A comprehensive markdown-formatted summary (15-20% of original length) with ## headers, **bold** text, β€’ bullet points, and proper structure"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1998,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters","ruleIdentifier":"line_length","ruleName":"Line Length"},"text":" Please analyze the following transcript and use the create_summary function to generate a well-structured summary:"},{"violation":{"severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":2013,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"reason":"Line should be 120 characters or less; currently it has 174 characters"},"text":" - tasks (array): Array of task objects with text, priority (High\/Medium\/Low), category (Call\/Email\/Meeting\/Purchase\/Research\/Travel\/Health\/General), timeReference"},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2014},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 126 characters","ruleName":"Line Length"},"text":" - reminders (array): Array of reminder objects with text, urgency (Immediate\/Today\/This Week\/Later), timeReference"},{"violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 145 characters","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2015,"character":1},"ruleName":"Line Length","severity":"warning"},"text":" - titles (array): Array of title objects with text (40-60 chars), category (Meeting\/Personal\/Technical\/General), confidence (0.0-1.0)"},{"violation":{"severity":"warning","location":{"character":1,"line":2018,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"reason":"Line should be 120 characters or less; currently it has 125 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" Please analyze the following transcript and use the complete_analysis function to provide comprehensive analysis:"},{"text":" AppLog.shared.networking(\"OllamaService: Parsing GPT-OSS response, length: \\(response.count) characters\", level: .debug)","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 128 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1,"line":2032}}},{"text":" AppLog.shared.networking(\"OllamaService: Successfully parsed GPT-OSS function call: \\(functionName)\")","violation":{"reason":"Line should be 120 characters or less; currently it has 125 characters","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2048,"character":1}}},{"text":" AppLog.shared.networking(\"OllamaService: Failed to parse GPT-OSS function call JSON: \\(error.localizedDescription)\", level: .error)","violation":{"severity":"warning","ruleIdentifier":"line_length","location":{"character":1,"line":2052,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"reason":"Line should be 120 characters or less; currently it has 151 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.networking(\"OllamaService: Attempting to parse extracted JSON from GPT-OSS response\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2060},"reason":"Line should be 120 characters or less; currently it has 126 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.networking(\"OllamaService: Successfully parsed extracted GPT-OSS JSON: \\(functionName)\")","violation":{"location":{"character":1,"line":2065,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 122 characters","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.networking(\"OllamaService: Failed to parse extracted GPT-OSS JSON: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 143 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"line":2069,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1},"severity":"warning"}},{"text":" private func parseGPTOSSCompleteAnalysisResult(arguments: [String: Any]) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"severity":"warning","location":{"character":1,"line":2077,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"reason":"Line should be 120 characters or less; currently it has 199 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length"}},{"text":" private func parseGPTOSSCompleteAnalysisResult(arguments: [String: Any]) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"severity":"error","reason":"Tuples should have at most 2 members","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleName":"Large Tuple","ruleIdentifier":"large_tuple","location":{"character":88,"line":2077,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"}}},{"text":" AppLog.shared.networking(\"OllamaService: Successfully generated summary using Magistral tool calling\")","violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 122 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1,"line":2153}}},{"text":" AppLog.shared.networking(\"OllamaService: Magistral tool calling failed, falling back: \\(error.localizedDescription)\")","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2162},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" private func processCompleteWithMagistralTools(from text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)? {","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2167,"character":1},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 199 characters"}},{"text":" private func processCompleteWithMagistralTools(from text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)? {","violation":{"ruleIdentifier":"large_tuple","ruleName":"Large Tuple","location":{"character":87,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2167},"severity":"error","reason":"Tuples should have at most 2 members","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead."}},{"text":" AppLog.shared.networking(\"OllamaService: No valid Magistral tool calls in complete processing response, falling back\")","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2181,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length"}},{"text":" AppLog.shared.networking(\"OllamaService: Magistral tool calling failed for complete processing: \\(error.localizedDescription)\")","violation":{"location":{"line":2185,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 139 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" private func createMagistralToolPrompt(for type: String, text: String) -> String {","violation":{"severity":"error","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","location":{"line":2190,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":13},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 106 lines"}},{"text":" \"description\": \"A comprehensive markdown-formatted summary (15-20% of original length) with ## headers, **bold** text, β€’ bullet points, and proper structure\"","violation":{"reason":"Line should be 120 characters or less; currently it has 179 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2207,"character":1}}},{"text":" [INST]Please analyze the following transcript and use the create_summary tool to generate a well-structured summary:","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2215,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" I need to analyze this transcript and create a comprehensive summary using the create_summary tool. Let me process the content and structure it properly.","violation":{"ruleDescription":"Lines should not span too many characters.","location":{"line":2220,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 165 characters","ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length"}},{"text":" \"description\": \"Perform complete analysis extracting summary, tasks, reminders, titles, and content type\",","violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 122 characters","location":{"line":2234,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning"}},{"text":" \"description\": \"Comprehensive markdown-formatted summary with ## headers, **bold** text, β€’ bullets\"","violation":{"ruleName":"Line Length","location":{"character":1,"line":2240,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 121 characters","ruleDescription":"Lines should not span too many characters."}},{"text":" \"category\": {\"type\": \"string\", \"description\": \"Category: Call, Email, Meeting, Purchase, Research, Travel, Health, or General\"},","violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2249,"character":1},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 154 characters"}},{"text":" \"urgency\": {\"type\": \"string\", \"description\": \"Urgency: Immediate, Today, This Week, or Later\"},","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 121 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1,"line":2260},"ruleName":"Line Length","severity":"warning"}},{"text":" \"category\": {\"type\": \"string\", \"description\": \"Category: Meeting, Personal, Technical, or General\"},","violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"line":2271,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"reason":"Line should be 120 characters or less; currently it has 126 characters","ruleIdentifier":"line_length"}},{"text":" [INST]Please analyze the following transcript and use the complete_analysis tool to provide comprehensive analysis:","violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2286,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"violation":{"location":{"line":2291,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"reason":"Line should be 200 characters or less; currently it has 201 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"error","ruleIdentifier":"line_length"},"text":" I need to perform a complete analysis of this transcript, extracting summary, tasks, reminders, titles, and content type. Let me use the complete_analysis tool with all required parameters."},{"violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 131 characters","ruleDescription":"Lines should not span too many characters.","location":{"line":2327,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1},"ruleIdentifier":"line_length","ruleName":"Line Length"},"text":" AppLog.shared.networking(\"OllamaService: Successfully parsed Magistral tool call: \\(functionName)\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1,"line":2331},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 157 characters"},"text":" AppLog.shared.networking(\"OllamaService: Failed to parse Magistral arguments JSON: \\(error.localizedDescription)\", level: .error)"},{"violation":{"location":{"character":1,"line":2356,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 200 characters or less; currently it has 202 characters","severity":"error","ruleName":"Line Length"},"text":" private func parseMagistralCompleteAnalysisResult(arguments: [String: Any]) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","location":{"character":91,"line":2356,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"ruleIdentifier":"large_tuple","reason":"Tuples should have at most 2 members"},"text":" private func parseMagistralCompleteAnalysisResult(arguments: [String: Any]) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"ruleName":"Line Length","location":{"line":2421,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 135 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" private func generateResponseWithTools(prompt: String, model: String, tools: [OllamaTool]) async throws -> OllamaGenerateResponse {"},{"violation":{"ruleName":"Function Body Length","ruleDescription":"Function bodies should not span too many lines","location":{"line":2421,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 59 lines","severity":"warning","ruleIdentifier":"function_body_length"},"text":" private func generateResponseWithTools(prompt: String, model: String, tools: [OllamaTool]) async throws -> OllamaGenerateResponse {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 136 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1,"line":2457},"ruleIdentifier":"line_length"},"text":" AppLog.shared.networking(\"OllamaService: Tool calling network request failed: \\(error.localizedDescription)\", level: .error)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 134 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2467,"character":1},"ruleIdentifier":"line_length"},"text":" AppLog.shared.networking(\"OllamaService: HTTP error for tool calling - Status: \\(httpResponse.statusCode)\", level: .error)"},{"violation":{"location":{"line":2477,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 124 characters","severity":"warning"},"text":" AppLog.shared.networking(\"OllamaService: Received tool calling response data of \\(data.count) bytes\", level: .debug)"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1,"line":2491},"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 133 characters"},"text":" AppLog.shared.networking(\"OllamaService: Tool calling JSON parsing failed: \\(error.localizedDescription)\", level: .error)"},{"violation":{"ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length","severity":"warning","ruleIdentifier":"function_body_length","location":{"character":13,"line":2498,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 65 lines"},"text":" private func generateResponse(prompt: String, model: String, cleanForJSON: Bool = true) async throws -> String {"},{"violation":{"severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"character":1,"line":2535,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"reason":"Line should be 120 characters or less; currently it has 123 characters","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.networking(\"OllamaService: Network request failed: \\(error.localizedDescription)\", level: .error)"},{"violation":{"ruleName":"Line Length","location":{"character":1,"line":2562,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"reason":"Line should be 120 characters or less; currently it has 148 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" AppLog.shared.networking(\"OllamaService: Raw response content length: \\(generateResponse.response.count) characters\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2567,"character":1},"reason":"Line should be 120 characters or less; currently it has 145 characters"},"text":" let cleanedResponse = cleanForJSON ? cleanOllamaResponse(generateResponse.response) : cleanSummaryResponse(generateResponse.response)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 130 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1,"line":2569}},"text":" AppLog.shared.networking(\"OllamaService: Cleaned response length: \\(cleanedResponse.count) characters\", level: .debug)"},{"violation":{"ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 144 characters","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1,"line":2584}},"text":" throw OllamaError.parsingError(\"Failed to parse JSON response: \\(error.localizedDescription). Response length: \\(data.count) bytes\")"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2590},"reason":"Line should be 120 characters or less; currently it has 122 characters","ruleDescription":"Lines should not span too many characters."},"text":" private func generateStructuredResponse(prompt: String, model: String, schema: [String: Any]) async throws -> String {"},{"violation":{"ruleIdentifier":"function_body_length","severity":"warning","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 55 lines","ruleName":"Function Body Length","location":{"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2590},"ruleDescription":"Function bodies should not span too many lines"},"text":" private func generateStructuredResponse(prompt: String, model: String, schema: [String: Any]) async throws -> String {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 141 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2625,"character":1}},"text":" AppLog.shared.networking(\"OllamaService: Structured output network request failed: \\(error.localizedDescription)\", level: .error)"},{"violation":{"location":{"character":1,"line":2635,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"reason":"Line should be 120 characters or less; currently it has 139 characters","ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" AppLog.shared.networking(\"OllamaService: HTTP error for structured output - Status: \\(httpResponse.statusCode)\", level: .error)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 122 characters","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","location":{"line":2644,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"}},"text":" AppLog.shared.networking(\"OllamaService: Received structured response data of \\(data.count) bytes\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 153 characters","location":{"line":2650,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1},"ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.networking(\"OllamaService: Structured response received, length: \\(generateResponse.response.count) characters\", level: .debug)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 138 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1,"line":2657},"severity":"warning"},"text":" AppLog.shared.networking(\"OllamaService: Structured output JSON parsing failed: \\(error.localizedDescription)\", level: .error)"},{"text":" private func createStructuredCompleteProcessingPrompt(from text: String) -> String {","violation":{"severity":"warning","ruleDescription":"Function bodies should not span too many lines","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 57 lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2666,"character":13}}},{"text":" You are analyzing a transcript. Extract and summarize the ACTUAL CONTENT discussed, not a description of what type of document it is.","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2669,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters","ruleDescription":"Lines should not span too many characters."}},{"text":" \"tasks\": [{\"text\": \"Specific action item\", \"priority\": \"High|Medium|Low\", \"category\": \"Call|Email|Meeting|Purchase|Research|Travel|Health|General\", \"timeReference\": null}],","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2675},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 182 characters","ruleIdentifier":"line_length"}},{"text":" \"reminders\": [{\"text\": \"Time-sensitive item\", \"urgency\": \"Immediate|Today|This Week|Later\", \"timeReference\": null}],","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2676,"character":1},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 126 characters","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning"}},{"text":" \"titles\": [{\"text\": \"Descriptive title\", \"category\": \"Meeting|Personal|Technical|General\", \"confidence\": 0.8}],","violation":{"severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":2677,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" private func parseStructuredCompleteResponse(_ response: String) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2726},"reason":"Line should be 120 characters or less; currently it has 191 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning"}},{"text":" private func parseStructuredCompleteResponse(_ response: String) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2726},"severity":"warning","reason":"Function should have complexity 10 or less; currently complexity is 11","ruleName":"Cyclomatic Complexity"}},{"text":" private func parseStructuredCompleteResponse(_ response: String) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Function Body Length","ruleDescription":"Function bodies should not span too many lines","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2726,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 90 lines","ruleIdentifier":"function_body_length","severity":"warning"}},{"text":" private func parseStructuredCompleteResponse(_ response: String) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleIdentifier":"large_tuple","severity":"error","location":{"line":2726,"character":80,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"ruleName":"Large Tuple","reason":"Tuples should have at most 2 members","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead."}},{"text":" AppLog.shared.networking(\"OllamaService: Validating structured response - Summary: \\(summaryLength) chars, Titles: \\(rawResult.titles.count), Tasks: \\(rawResult.tasks.count)\", level: .debug)","violation":{"ruleIdentifier":"line_length","reason":"Line should be 200 characters or less; currently it has 202 characters","ruleDescription":"Lines should not span too many characters.","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2738,"character":1},"ruleName":"Line Length"}},{"text":" AppLog.shared.networking(\"OllamaService: Summary is very short (\\(summaryLength) chars), may need enhancement\")","violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"line":2742,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift"},"reason":"Line should be 120 characters or less; currently it has 127 characters","severity":"warning","ruleName":"Line Length"}},{"text":" AppLog.shared.networking(\"OllamaService: Skipping invalid task (question format detected)\", level: .debug)","violation":{"location":{"line":2756,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning"}},{"violation":{"ruleIdentifier":"line_length","location":{"line":2797,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" AppLog.shared.networking(\"OllamaService: Skipping invalid reminder (statement format detected)\", level: .debug)"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1,"line":2842},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 197 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" AppLog.shared.networking(\"OllamaService: Final: Summary: \\(rawResult.summary.count) chars, Tasks: \\(tasks.count), Reminders: \\(reminders.count), Titles: \\(titles.count)\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":2847,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters","ruleName":"Line Length"},"text":" AppLog.shared.networking(\"OllamaService: Structured JSON parsing failed: \\(error.localizedDescription)\", level: .error)"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"line":2852,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"},"text":" private func parseStructuredTasksReminders(_ response: String) throws -> (tasks: [TaskItem], reminders: [ReminderItem]) {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2891},"reason":"Line should be 120 characters or less; currently it has 142 characters","ruleIdentifier":"line_length"},"text":" AppLog.shared.networking(\"OllamaService: Structured tasks\/reminders parsing failed: \\(error.localizedDescription)\", level: .error)"},{"violation":{"ruleDescription":"Files should not span too many lines.","ruleName":"File Length","reason":"File should contain 1000 lines or less: currently contains 2955","severity":"error","ruleIdentifier":"file_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2955}},"text":"}"},{"violation":{"severity":"error","ruleName":"Type Body Length","ruleIdentifier":"type_body_length","location":{"character":1,"line":10,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaSettingsView.swift"},"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 364 lines","ruleDescription":"Type bodies should not span too many lines"},"text":"struct OllamaSettingsView: View {"},{"violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 126 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaSettingsView.swift","line":18,"character":1}},"text":" @AppStorage(EndpointSecurityPolicy.allowInsecurePublicEndpointsKey) private var allowInsecurePublicEndpoints: Bool = false"},{"violation":{"severity":"warning","ruleName":"File Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaSettingsView.swift","line":447,"character":1},"ruleIdentifier":"file_length","ruleDescription":"Files should not span too many lines.","reason":"File should contain 400 lines or less: currently contains 447"},"text":"}"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"line":60,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceAIDownloadMonitor.swift"},"reason":"Line should be 120 characters or less; currently it has 142 characters"},"text":" completionMessage = \"Both models have been downloaded successfully! You can now use on-device AI for transcription and summaries.\""},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceAIDownloadMonitor.swift","line":66,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters","severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" body: \"On-device AI models have finished downloading. You can now use on-device transcription and summaries.\""},{"violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 159 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceAIDownloadMonitor.swift","line":87,"character":1},"severity":"warning","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.summarization(\"[OnDeviceAIDownloadMonitor] Notification permission request failed: \\(error.localizedDescription)\", level: .debug)"},{"text":" AppLog.shared.summarization(\"[OnDeviceAIDownloadMonitor] Failed to send notification: \\(error)\", level: .error)","violation":{"reason":"Line should be 120 characters or less; currently it has 123 characters","ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"line":110,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceAIDownloadMonitor.swift"},"ruleName":"Line Length"}},{"text":"open class OnDeviceLLM: ObservableObject {","violation":{"ruleDescription":"Type bodies should not span too many lines","ruleName":"Type Body Length","severity":"error","location":{"line":17,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","character":6},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 508 lines","ruleIdentifier":"type_body_length"}},{"text":" public var preprocess: (_ input: String, _ history: [LLMChat], _ llmInstance: OnDeviceLLM) -> String = { input, _, _ in return input }","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 138 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":44,"character":1}}},{"text":" let logCallback: @convention(c) (ggml_log_level, UnsafePointer?, UnsafeMutableRawPointer?) -> Void = { level, text, _ in","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"line":130,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift"},"reason":"Line should be 120 characters or less; currently it has 135 characters","severity":"warning","ruleIdentifier":"line_length"}},{"text":" public init(","violation":{"ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","severity":"warning","location":{"character":12,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":164},"reason":"Initializer body should span 50 lines or less excluding comments and whitespace: currently spans 81 lines"}},{"text":" let modelParams_n = llama_model_n_params(model)","violation":{"ruleName":"Identifier Name","reason":"Variable name 'modelParams_n' should only contain alphanumeric and other allowed characters","ruleIdentifier":"identifier_name","location":{"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":202},"ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","severity":"error"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLM] Model loaded - size: \\(modelSize \/ 1_000_000)MB, params: \\(modelParams_n \/ 1_000_000)M\")","violation":{"ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"line":203,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" let n_batch: UInt32","violation":{"severity":"error","location":{"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":217},"ruleName":"Identifier Name","reason":"Variable name 'n_batch' should only contain alphanumeric and other allowed characters","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLM] Context: n_ctx=\\(self.maxTokenCount), n_batch=\\(n_batch), model_train_ctx=\\(modelTrainCtx), threads=\\(processorCount)\", level: .debug)","violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"line":228,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","character":1},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 185 characters","ruleName":"Line Length"}},{"text":" if let s = stopSequence, !sequences.contains(s) {","violation":{"ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","location":{"line":241,"character":16,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift"},"ruleIdentifier":"identifier_name","severity":"error","reason":"Variable name 's' should be between 3 and 40 characters long","ruleName":"Identifier Name"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLM] App is backgrounded, stopping token generation to avoid Metal crash\", level: .error)","violation":{"severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":412,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLM] Decode failed during token prediction, ending generation\", level: .error)","violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","location":{"line":426,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift"},"reason":"Line should be 120 characters or less; currently it has 128 characters","ruleDescription":"Lines should not span too many characters."}},{"violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleIdentifier":"cyclomatic_complexity","reason":"Function should have complexity 10 or less; currently complexity is 11","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":433,"character":13},"ruleDescription":"Complexity of function bodies should be limited."},"text":" private func tokenizeAndBatchInput(message input: borrowing String) -> Bool {"},{"violation":{"severity":"warning","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 52 lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","ruleDescription":"Function bodies should not span too many lines","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":433,"character":13}},"text":" private func tokenizeAndBatchInput(message input: borrowing String) -> Bool {"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 184 characters","location":{"character":1,"line":445,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift"}},"text":" AppLog.shared.summarization(\"[OnDeviceLLM] Input too long (\\(tokens.count) tokens), truncating to \\(maxInputTokens) (reserving \\(outputReserve) for output)\", level: .error)"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","character":1,"line":462},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 133 characters","ruleIdentifier":"line_length"},"text":" AppLog.shared.summarization(\"[OnDeviceLLM] Processing \\(totalTokens) input tokens in batches of \\(batchSize)\", level: .debug)"},{"violation":{"ruleIdentifier":"identifier_name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","location":{"line":471,"character":17,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift"},"ruleName":"Identifier Name","severity":"error","reason":"Variable name 'i' should be between 3 and 40 characters long"},"text":" for i in 0...Continuation) -> Bool {"},{"violation":{"severity":"warning","location":{"line":513,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift"},"ruleName":"Function Body Length","ruleDescription":"Function bodies should not span too many lines","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 56 lines","ruleIdentifier":"function_body_length"},"text":" private func emitDecoded(token: Token, to output: borrowing AsyncStream.Continuation) -> Bool {"},{"violation":{"ruleIdentifier":"type_name","severity":"error","location":{"character":16,"line":514,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift"},"reason":"Type name 'saved' should start with an uppercase character","ruleDescription":"Type name should only contain alphanumeric characters, start with an uppercase character and span between 3 and 40 characters in length.\nPrivate types may start with an underscore.","ruleName":"Type Name"},"text":" struct saved {"},{"violation":{"severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":606},"reason":"Line should be 120 characters or less; currently it has 141 characters","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.summarization(\"[OnDeviceLLM] Max output tokens (\\(self.maxOutputTokens)) reached, stopping generation\")"},{"violation":{"severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":628,"character":13},"reason":"Variable name 'seq_id' should only contain alphanumeric and other allowed characters","ruleName":"Identifier Name","ruleIdentifier":"identifier_name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short."},"text":" let seq_id: Int32 = 0"},{"violation":{"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":639,"character":1},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 141 characters"},"text":" AppLog.shared.summarization(\"[OnDeviceLLM] KV cache trimmed: kv_cache(\\(kvCacheTokenCount)) nPast(\\(self.nPast))\", level: .debug)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 128 characters","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":644,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift"}},"text":" public func performInference(to input: String, with makeOutputFrom: @escaping (AsyncStream) async -> String) async {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":684,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift"},"reason":"Line should be 120 characters or less; currently it has 129 characters","ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length"},"text":" AppLog.shared.summarization(\"[OnDeviceLLM] Cannot rollback - context is nil (likely already cleared)\", level: .debug)"},{"violation":{"reason":"Variable name 'seq_id' should only contain alphanumeric and other allowed characters","ruleIdentifier":"identifier_name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleName":"Identifier Name","severity":"error","location":{"character":17,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":689}},"text":" let seq_id = Int32(0)"},{"violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"character":1,"line":719,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift"},"reason":"Line should be 120 characters or less; currently it has 131 characters","ruleName":"Line Length"},"text":" let bytesWritten = llama_state_get_data(contextPointer, baseAddress.assumingMemoryBound(to: UInt8.self), stateSize)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 134 characters","ruleName":"Line Length","location":{"line":735,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift"}},"text":" let bytesRead = llama_state_set_data(contextPointer, baseAddress.assumingMemoryBound(to: UInt8.self), stateData.count)"},{"violation":{"location":{"line":745,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","character":1},"ruleName":"File Length","reason":"File should contain 400 lines or less: currently contains 745","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length"},"text":"}"},{"violation":{"location":{"line":31,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift","character":1},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 134 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length"},"text":" @Published public var selectedModel: OnDeviceLLMModelInfo = OnDeviceLLMModelInfo.granite4Micro \/\/ Default, will be updated in init"},{"violation":{"location":{"line":127,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift"},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 136 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length"},"text":" AppLog.shared.summarization(\"[OnDeviceLLMDownloadManager] Starting download from host: \\(url.host ?? \"unknown\")\", level: .debug)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":244,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift"},"reason":"Line should be 120 characters or less; currently it has 122 characters","ruleIdentifier":"line_length","ruleName":"Line Length"},"text":" AppLog.shared.summarization(\"[OnDeviceLLMDownloadManager] Error checking disk space: \\(error)\", level: .error)"},{"violation":{"severity":"warning","location":{"character":1,"line":264,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift"},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 139 characters","ruleIdentifier":"line_length"},"text":" public nonisolated func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {"},{"violation":{"ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift","character":24,"line":264},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 52 lines"},"text":" public nonisolated func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {"},{"violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 135 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift","line":283,"character":1}},"text":" let model = OnDeviceLLMModelInfo.allModels.first(where: { $0.id == modelId }) ?? OnDeviceLLMModelInfo.defaultSummarizationModel"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift","line":314,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" AppLog.shared.summarization(\"[OnDeviceLLMDownloadManager] File saved successfully. Size: \\(formatSize(fileSize))\")"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 121 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift","line":341,"character":1}},"text":" public nonisolated func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift","character":1,"line":343},"reason":"Line should be 120 characters or less; currently it has 135 characters"},"text":" AppLog.shared.summarization(\"[OnDeviceLLMDownloadManager] Task completed. Error: \\(error?.localizedDescription ?? \"none\")\")"},{"violation":{"ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift","character":1,"line":346},"reason":"Line should be 120 characters or less; currently it has 130 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" AppLog.shared.summarization(\"[OnDeviceLLMDownloadManager] HTTP Status: \\(httpResponse.statusCode)\", level: .debug)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 195 characters","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift","line":367,"character":1},"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" public nonisolated func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {"},{"violation":{"ruleName":"Line Length","reason":"Line should be 200 characters or less; currently it has 223 characters","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift","line":401,"character":1},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" public nonisolated func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) {"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 134 characters","location":{"character":1,"line":402,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift"}},"text":" AppLog.shared.summarization(\"[OnDeviceLLMDownloadManager] Redirect to host: \\(request.url?.host ?? \"unknown\")\", level: .debug)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"error","location":{"line":406,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift","character":1},"reason":"Line should be 200 characters or less; currently it has 227 characters","ruleIdentifier":"line_length","ruleName":"Line Length"},"text":" public nonisolated func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {"},{"violation":{"ruleIdentifier":"file_length","ruleDescription":"Files should not span too many lines.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift","line":443},"reason":"File should contain 400 lines or less: currently contains 443","severity":"warning","ruleName":"File Length"},"text":"}"},{"violation":{"severity":"error","ruleIdentifier":"type_body_length","reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 468 lines","ruleDescription":"Type bodies should not span too many lines","ruleName":"Type Body Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":16,"character":1}},"text":"class OnDeviceLLMEngine: SummarizationEngine, ConnectionTestable {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"line":22,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift"},"reason":"Line should be 120 characters or less; currently it has 136 characters","ruleName":"Line Length","ruleIdentifier":"line_length"},"text":" var description: String { \"Private, local summarization using models like Llama, Phi, or Mistral running entirely on your device.\" }"},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Model not downloaded: \\(selectedModel.displayName)\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","location":{"line":40,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" private let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? \"com.bisonnotes.app\", category: \"OnDeviceLLMEngine\")","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 127 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","character":1,"line":56},"ruleName":"Line Length"}},{"text":" logger.info(\"Configuration updated - Model: \\(newConfig.modelInfo.displayName), Temp: \\(newConfig.temperature)\")","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":128,"character":1},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" func processComplete(text: String) async throws -> (","violation":{"ruleName":"Large Tuple","reason":"Tuples should have at most 2 members","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","character":56,"line":216},"ruleIdentifier":"large_tuple","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead."}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Using accurate tokenization: \\(tokenCount) tokens\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 127 characters","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":249},"ruleIdentifier":"line_length"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Using token estimation: \\(tokenCount) tokens\", level: .debug)","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":253,"character":1},"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Text token count: \\(tokenCount), max context: \\(maxContextTokens), output reserve: \\(outputReserve), effective input limit: \\(effectiveInputLimit)\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":256},"ruleIdentifier":"line_length","severity":"error","reason":"Line should be 200 characters or less; currently it has 220 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Large text detected, using chunked processing with overlap\")","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":260,"character":1},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 125 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Inference interrupted by app backgrounding (GPU not available)\", level: .error)","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","character":1,"line":268},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 148 characters","severity":"warning"}},{"text":" throw OnDeviceLLMError.inferenceFailed(\"On-device AI needs the app to stay open. Please return to the app and try again.\")","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 142 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","character":1,"line":269},"severity":"warning","ruleName":"Line Length"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Inference completed at \\(String(format: \"%.1f\", metrics.inferenceTokensPerSecond)) tokens\/sec\")","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":273,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 164 characters","ruleIdentifier":"line_length","ruleName":"Line Length"}},{"text":" private func processChunkedText(","violation":{"severity":"warning","ruleIdentifier":"cyclomatic_complexity","location":{"line":286,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift"},"reason":"Function should have complexity 10 or less; currently complexity is 13","ruleDescription":"Complexity of function bodies should be limited.","ruleName":"Cyclomatic Complexity"}},{"text":" private func processChunkedText(","violation":{"location":{"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":286},"ruleName":"Function Body Length","ruleIdentifier":"function_body_length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 92 lines","ruleDescription":"Function bodies should not span too many lines","severity":"warning"}},{"text":" ) async throws -> (","violation":{"ruleName":"Large Tuple","ruleIdentifier":"large_tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","location":{"line":290,"character":23,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift"},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Could not use accurate tokenizer, falling back to estimation: \\(error)\", level: .error)","violation":{"ruleIdentifier":"line_length","location":{"line":310,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift"},"reason":"Line should be 120 characters or less; currently it has 152 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Split into \\(chunks.count) chunks with \\(overlapTokens) token overlap\")","violation":{"severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","character":1,"line":321},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 128 characters","ruleName":"Line Length"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Chunk \\(index + 1) token count (\\(chunkTokenCount)) exceeds limit (\\(maxTokens)). May be truncated by OnDeviceLLM.\", level: .error)","violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"line":328,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift"},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 200 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Chunk \\(index + 1): \\(chunkTokenCount) tokens (within limit)\", level: .debug)","violation":{"severity":"warning","location":{"line":330,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift"},"reason":"Line should be 120 characters or less; currently it has 146 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Chunk \\(index + 1) estimated token count (\\(chunkTokenEstimate)) exceeds limit (\\(maxTokens)). May be truncated by OnDeviceLLM.\", level: .error)","violation":{"location":{"line":336,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift"},"reason":"Line should be 200 characters or less; currently it has 213 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"error","ruleName":"Line Length"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Processing chunk \\(index + 1)\/\\(chunks.count)\", level: .debug)","violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 123 characters","ruleDescription":"Lines should not span too many characters.","location":{"line":348,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift"}}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Background time critical (\\(remaining)s), aborting to prevent crash\", level: .error)","violation":{"severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 153 characters","location":{"line":362,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift"},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"text":" throw OnDeviceLLMError.inferenceFailed(\"On-device AI needs the app to stay open. Please return to the app and try again.\")","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":363,"character":1},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 142 characters","ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Chunk \\(index + 1) interrupted by app backgrounding\", level: .error)","violation":{"reason":"Line should be 120 characters or less; currently it has 137 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":372,"character":1},"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning"}},{"text":" throw OnDeviceLLMError.inferenceFailed(\"On-device AI needs the app to stay open. Please return to the app and try again.\")","violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 142 characters","severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":373,"character":1},"ruleName":"Line Length"}},{"violation":{"ruleName":"Line Length","location":{"line":398,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift"},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 129 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Combining \\(allSummaries.count) chunk summaries into final summary\")"},{"violation":{"severity":"warning","ruleName":"Line Length","location":{"line":417,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift"},"reason":"Line should be 120 characters or less; currently it has 133 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Chunked processing completed in \\(String(format: \"%.1f\", processingTime))s\")"},{"violation":{"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 59 lines","ruleDescription":"Function bodies should not span too many lines","severity":"warning","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":463,"character":13}},"text":" private func combineChunkSummaries("},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 134 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":478}},"text":" You are consolidating summaries from different parts of a single recording into ONE unified, comprehensive Structured Outline."},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":524},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 173 characters"},"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Meta-summary: \\(metaPromptTokenCount) tokens, max: \\(maxInputForMeta), target: \\(targetWords) words\", level: .debug)"},{"violation":{"severity":"warning","ruleIdentifier":"function_parameter_count","reason":"Function should have 5 parameters or less: it currently has 8","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","character":13,"line":546},"ruleDescription":"Number of function parameters should be low.","ruleName":"Function Parameter Count"},"text":" private func combineSummariesRecursive("},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":579},"reason":"Line should be 120 characters or less; currently it has 149 characters"},"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Splitting \\(summaries.count) summaries into groups of ~\\(summariesPerGroup)\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","character":1,"line":644},"reason":"Line should be 120 characters or less; currently it has 142 characters","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters."},"text":" return SummarizationError.configurationRequired(message: \"On-Device AI model not ready. Please download a model in Settings.\")"},{"violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 129 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":650,"character":1},"ruleName":"Line Length"},"text":" return SummarizationError.processingFailed(reason: \"Insufficient disk space. Need \\(formatSize(required)) free.\")"},{"violation":{"ruleDescription":"Files should not span too many lines.","severity":"warning","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":665,"character":1},"ruleName":"File Length","reason":"File should contain 400 lines or less: currently contains 665"},"text":"}"},{"violation":{"severity":"error","ruleIdentifier":"identifier_name","ruleName":"Identifier Name","reason":"Variable name 'i' should be between 3 and 40 characters long","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","location":{"line":87,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMExtensions.swift","character":13}},"text":" let i = Int(self.n_tokens)"},{"violation":{"ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleName":"Identifier Name","reason":"Variable name 'seq_id' should only contain alphanumeric and other allowed characters","ruleIdentifier":"identifier_name","severity":"error","location":{"character":16,"line":91,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMExtensions.swift"}},"text":" if let seq_id = self.seq_id[i] {"},{"violation":{"severity":"error","location":{"character":18,"line":92,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMExtensions.swift"},"reason":"Variable name 'j' should be between 3 and 40 characters long","ruleIdentifier":"identifier_name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleName":"Identifier Name"},"text":" for (j, id) in ids.enumerated() {"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 130 characters","location":{"line":162,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMModels.swift","character":1},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"},"text":" downloadURL: \"https:\/\/huggingface.co\/unsloth\/gemma-3n-E4B-it-GGUF\/resolve\/main\/gemma-3n-E4B-it-Q4_K_M.gguf?download=true\","},{"violation":{"severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":186,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMModels.swift"},"reason":"Line should be 120 characters or less; currently it has 130 characters"},"text":" downloadURL: \"https:\/\/huggingface.co\/unsloth\/gemma-3n-E2B-it-GGUF\/resolve\/main\/gemma-3n-E2B-it-Q4_K_M.gguf?download=true\","},{"violation":{"severity":"warning","location":{"line":212,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMModels.swift"},"reason":"Line should be 120 characters or less; currently it has 156 characters","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" downloadURL: \"https:\/\/huggingface.co\/unsloth\/Ministral-3-3B-Instruct-2512-GGUF\/resolve\/main\/Ministral-3-3B-Instruct-2512-Q4_K_M.gguf?download=true\","},{"violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"line":237,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMModels.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters","ruleIdentifier":"line_length","severity":"warning"},"text":" downloadURL: \"https:\/\/huggingface.co\/unsloth\/granite-4.0-h-tiny-GGUF\/resolve\/main\/granite-4.0-h-tiny-Q4_K_M.gguf?download=true\","},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMModels.swift","line":258,"character":23},"reason":"Variable name 'qwen3_5_2B' should only contain alphanumeric and other allowed characters","ruleIdentifier":"identifier_name","ruleName":"Identifier Name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","severity":"error"},"text":" public static let qwen3_5_2B = OnDeviceLLMModelInfo("},{"violation":{"severity":"warning","location":{"line":263,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMModels.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" downloadURL: \"https:\/\/huggingface.co\/unsloth\/Qwen3.5-2B-GGUF\/resolve\/main\/Qwen3.5-2B-UD-Q4_K_XL.gguf?download=true\","},{"violation":{"ruleIdentifier":"identifier_name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","reason":"Variable name 'qwen3_5_4B' should only contain alphanumeric and other allowed characters","location":{"character":23,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMModels.swift","line":289},"ruleName":"Identifier Name","severity":"error"},"text":" public static let qwen3_5_4B = OnDeviceLLMModelInfo("},{"violation":{"severity":"warning","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMModels.swift","line":324,"character":1},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 134 characters","ruleIdentifier":"line_length"},"text":" downloadURL: \"https:\/\/huggingface.co\/unsloth\/granite-4.0-micro-GGUF\/resolve\/main\/granite-4.0-micro-Q4_K_M.gguf?download=true\","},{"violation":{"reason":"Line should be 120 characters or less; currently it has 140 characters","ruleName":"Line Length","severity":"warning","location":{"character":1,"line":477,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMModels.swift"},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.summarization(\"[OnDeviceLLMModelInfo] Selected model '\\(modelId)' is not available, migrating to default\")"},{"violation":{"ruleName":"File Length","location":{"line":540,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMModels.swift","character":1},"reason":"File should contain 400 lines or less: currently contains 540","severity":"warning","ruleIdentifier":"file_length","ruleDescription":"Files should not span too many lines."},"text":"}"},{"violation":{"ruleIdentifier":"type_body_length","severity":"error","ruleName":"Type Body Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","character":8,"line":50},"ruleDescription":"Type bodies should not span too many lines","reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 685 lines"},"text":"public class OnDeviceLLMService: ObservableObject {"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":104,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"},"text":" AppLog.shared.summarization(\"[OnDeviceLLMService] Model loaded: \\(config.modelInfo.displayName) (backgrounded: \\(_isAppBackgrounded))\")"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 128 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":162,"character":1},"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length"},"text":" AppLog.shared.summarization(\"[OnDeviceLLMService] generateSummary raw output: \\(result.count) chars\", level: .debug)"},{"violation":{"severity":"error","location":{"line":164,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift"},"ruleName":"Line Length","reason":"Line should be 200 characters or less; currently it has 203 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"},"text":" AppLog.shared.summarization(\"[OnDeviceLLMService] Metrics: \\(metrics.inferenceTokenCount) output tokens, \\(String(format: \"%.1f\", metrics.inferenceTokensPerSecond)) tok\/s\", level: .debug)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 134 characters","location":{"character":1,"line":171,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift"},"ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.summarization(\"[OnDeviceLLMService] Model generated empty or minimal response after cleanup\", level: .error)"},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":172},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 142 characters","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length"},"text":" return \"Summary generation encountered an issue. The model produced an empty response. Please try again or use a different model.\""},{"violation":{"severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleName":"Large Tuple","ruleIdentifier":"large_tuple","reason":"Tuples should have at most 2 members","location":{"line":238,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","character":56}},"text":" func processComplete(text: String) async throws -> ("},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 128 characters","severity":"warning","location":{"line":266,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift"}},"text":" AppLog.shared.summarization(\"[OnDeviceLLMService] processComplete raw output: \\(result.count) chars\", level: .debug)"},{"violation":{"location":{"line":268,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift"},"ruleName":"Line Length","reason":"Line should be 200 characters or less; currently it has 203 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"error"},"text":" AppLog.shared.summarization(\"[OnDeviceLLMService] Metrics: \\(metrics.inferenceTokenCount) output tokens, \\(String(format: \"%.1f\", metrics.inferenceTokensPerSecond)) tok\/s\", level: .debug)"},{"violation":{"ruleName":"Function Body Length","location":{"line":299,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","character":13},"severity":"warning","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 80 lines","ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines"},"text":" private func cleanupResponse(_ response: String) -> String {"},{"violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 141 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":305,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","character":1}},"text":" if let thinkRegex = try? NSRegularExpression(pattern: \".*?<\/think>\", options: [.dotMatchesLineSeparators, .caseInsensitive]) {"},{"violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 128 characters","severity":"warning","location":{"line":340,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","character":1}},"text":" if let trailingRole = try? NSRegularExpression(pattern: #\"\\n?(assistant|user|system)\\s*$\"#, options: .caseInsensitive) {"},{"violation":{"ruleName":"Prefer For-Where","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","reason":"`where` clauses are preferred over a single `if` inside a `for`","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","character":13,"line":371}},"text":" if cleaned.lowercased().hasPrefix(phrase.lowercased()) {"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":378,"character":1},"reason":"Line should be 200 characters or less; currently it has 244 characters","ruleIdentifier":"line_length","severity":"error","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."},"text":" if let reasoningPattern = try? NSRegularExpression(pattern: #\"(?i)^(okay, let me try|let me try to|the user wants|i need to make sure|let me check).*?(?=\\n\\n##|## Summary|$)\"#, options: [.dotMatchesLineSeparators, .anchorsMatchLines]) {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":380},"reason":"Line should be 120 characters or less; currently it has 121 characters","severity":"warning","ruleIdentifier":"line_length"},"text":" cleaned = reasoningPattern.stringByReplacingMatches(in: cleaned, options: [], range: range, withTemplate: \"\")"},{"violation":{"severity":"error","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"character":1,"line":386,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift"},"reason":"Line should be 200 characters or less; currently it has 255 characters","ruleDescription":"Lines should not span too many characters."},"text":" if let thinkingPattern = try? NSRegularExpression(pattern: #\"^(Alright, |Let me |I should |I need to |Now, putting it together: |Putting it together: ).*?(?=\\n\\n##|## Summary|## Title|$)\"#, options: [.dotMatchesLineSeparators, .caseInsensitive]) {"},{"violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":452,"character":1},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 132 characters"},"text":" Extract all actionable tasks from the following transcript. Focus only on personal, actionable items that require follow-up."},{"violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"line":454,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 152 characters","ruleName":"Line Length"},"text":" IMPORTANT: Return each task on a new line, starting with \"- \" followed directly by the task text. Do NOT use prefixes like [Task 1] or [Task 2]."},{"violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 136 characters","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"line":465,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","character":1}},"text":" Extract all time-sensitive reminders and deadlines from the following transcript. Include dates, times, and deadlines mentioned."},{"violation":{"ruleIdentifier":"line_length","location":{"line":467,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift"},"reason":"Line should be 120 characters or less; currently it has 168 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length"},"text":" IMPORTANT: Return each reminder on a new line, starting with \"- \" followed directly by the reminder text. Do NOT use prefixes like [Reminder 1] or [Reminder 2]."},{"violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 128 characters","severity":"warning","ruleName":"Line Length","location":{"line":478,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift"},"ruleIdentifier":"line_length"},"text":" Suggest 3-5 concise, descriptive titles for the following transcript. Each title should capture the main topic or theme."},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":480},"reason":"Line should be 120 characters or less; currently it has 156 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"},"text":" IMPORTANT: Return each title on a new line, starting with \"- \" followed directly by the title text. Do NOT use prefixes like [Title 1] or [Title 2]."},{"violation":{"ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":489,"character":13},"severity":"warning","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 51 lines"},"text":" private func createCompleteProcessingPrompt(text: String) -> String {"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 155 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"line":496,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","character":1}},"text":" Analyze the following transcript and extract the actual content discussed. Base your response ONLY on what is actually mentioned in the transcript."},{"violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":620,"character":1},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 127 characters"},"text":" reminders.append(ReminderItem(text: cleaned, timeReference: timeRef, urgency: .later, confidence: 0.8))"},{"text":" private func parseCompleteResponse(_ response: String) -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) {","violation":{"severity":"warning","ruleIdentifier":"line_length","location":{"line":658,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","character":1},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 148 characters"}},{"text":" private func parseCompleteResponse(_ response: String) -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) {","violation":{"ruleName":"Cyclomatic Complexity","ruleDescription":"Complexity of function bodies should be limited.","reason":"Function should have complexity 10 or less; currently complexity is 51","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":658,"character":13},"ruleIdentifier":"cyclomatic_complexity"}},{"text":" private func parseCompleteResponse(_ response: String) -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) {","violation":{"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 245 lines","ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines","severity":"error","ruleName":"Function Body Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":658,"character":13}}},{"text":" private func parseCompleteResponse(_ response: String) -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) {","violation":{"severity":"error","reason":"Tuples should have at most 2 members","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleName":"Large Tuple","ruleIdentifier":"large_tuple","location":{"line":658,"character":63,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift"}}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMService] Thinking content detected (\\(thinkingContent.count) chars)\", level: .debug)","violation":{"reason":"Line should be 120 characters or less; currently it has 141 characters","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","location":{"line":685,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","character":1},"ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMService] Content after thinking (\\(contentAfterThinking.count) chars)\", level: .debug)","violation":{"ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":686,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMService] Model generated thinking content (\\(thinkingContent.count) chars) but no actual response after thinking block (length: \\(cleanedTest.count))\", level: .error)","violation":{"ruleName":"Line Length","reason":"Line should be 200 characters or less; currently it has 223 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":703,"character":1},"severity":"error"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMService] This may indicate the model hit the output token limit during thinking\", level: .error)","violation":{"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"line":704,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift"},"reason":"Line should be 120 characters or less; currently it has 153 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMService] Response contains only stop tokens or minimal content (length: \\(cleanedTest.count)), returning empty result\", level: .error)","violation":{"reason":"Line should be 120 characters or less; currently it has 191 characters","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":706,"character":1}}},{"text":" sanitizedResponse = sanitizedResponse.replacingOccurrences(of: token.lowercased(), with: \"\", options: .caseInsensitive)","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":722,"character":1},"ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 131 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning"}},{"text":" sanitizedResponse = regex.stringByReplacingMatches(in: sanitizedResponse, options: [], range: range, withTemplate: \"\")","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 130 characters","severity":"warning","location":{"line":728,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","character":1}}},{"text":" if let thinkRegex = try? NSRegularExpression(pattern: \".*?<\/think>\", options: [.dotMatchesLineSeparators, .caseInsensitive]) {","violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 141 characters","severity":"warning","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","character":1,"line":732}}},{"text":" sanitizedResponse = thinkRegex.stringByReplacingMatches(in: sanitizedResponse, options: [], range: range, withTemplate: \"\")","violation":{"reason":"Line should be 120 characters or less; currently it has 135 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","character":1,"line":734},"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning"}},{"text":" if sanitizedResponse.lowercased().hasPrefix(phrase.lowercased()) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","location":{"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":758},"reason":"`where` clauses are preferred over a single `if` inside a `for`","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where"}},{"text":" sanitizedResponse = String(sanitizedResponse.dropFirst(phrase.count)).trimmingCharacters(in: .whitespacesAndNewlines)","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","character":1,"line":759},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" if let thinkingPattern = try? NSRegularExpression(pattern: #\"(?i)^(Alright, |Let me |I should |I need to |Okay, let me try|Let me try to|The user wants|I need to make sure|Let me check).*?(?=\\n\\n|##|$)\"#, options: [.dotMatchesLineSeparators, .anchorsMatchLines]) {","violation":{"location":{"line":766,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift"},"ruleName":"Line Length","reason":"Line should be 200 characters or less; currently it has 272 characters","ruleDescription":"Lines should not span too many characters.","severity":"error","ruleIdentifier":"line_length"}},{"text":" sanitizedResponse = thinkingPattern.stringByReplacingMatches(in: sanitizedResponse, options: [], range: range, withTemplate: \"\")","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":768,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","character":1},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 140 characters","ruleName":"Line Length"}},{"text":" (lowercased.contains(\"reminder\") && (lowercased.contains(\"##\") || lowercased.hasPrefix(\"reminder\"))) {","violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 124 characters","location":{"line":794,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift"},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning"}},{"text":" var text = parts.dropFirst().joined(separator: \".\").trimmingCharacters(in: .whitespacesAndNewlines)","violation":{"ruleName":"Line Length","location":{"character":1,"line":829,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift"},"ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 123 characters","ruleDescription":"Lines should not span too many characters."}},{"text":" reminders.append(ReminderItem(text: cleaned, timeReference: timeRef, urgency: .later, confidence: 0.8))","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 131 characters","location":{"line":852,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift"}}},{"text":" var text = parts.dropFirst().joined(separator: \".\").trimmingCharacters(in: .whitespacesAndNewlines)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"character":1,"line":859,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift"},"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" reminders.append(ReminderItem(text: cleaned, timeReference: timeRef, urgency: .later, confidence: 0.8))","violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":867,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" let cleaned = RecordingNameGenerator.cleanStandardizedTitleResponse(String(text).sanitizedForTitle())","violation":{"severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 121 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":878},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":" var text = parts.dropFirst().joined(separator: \".\").trimmingCharacters(in: .whitespacesAndNewlines)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":890,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters","ruleName":"Line Length","severity":"warning"}},{"text":"}","violation":{"ruleName":"File Length","ruleDescription":"Files should not span too many lines.","severity":"warning","reason":"File should contain 400 lines or less: currently contains 983","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","character":1,"line":983},"ruleIdentifier":"file_length"}},{"text":"struct OnDeviceLLMSettingsView: View {","violation":{"severity":"error","reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 394 lines","ruleName":"Type Body Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMSettingsView.swift","line":12,"character":1},"ruleIdentifier":"type_body_length","ruleDescription":"Type bodies should not span too many lines"}},{"text":" Text(\"Process transcripts locally on your device using a downloaded AI model. No internet connection required after model download.\")","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"line":42,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMSettingsView.swift"},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 153 characters"}},{"text":" Text(\"Models available for your device (4-6GB RAM) are experimental. They generate summaries and one title only (no tasks or reminders) and may produce lower quality results.\")","violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMSettingsView.swift","character":1,"line":58},"ruleIdentifier":"line_length","reason":"Line should be 200 characters or less; currently it has 208 characters"}},{"text":" Text(\"This will delete \\(model.displayName) (\\(model.downloadSize)) from your device. You can re-download it later.\")","violation":{"location":{"line":123,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMSettingsView.swift"},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 129 characters","ruleName":"Line Length","severity":"warning"}},{"text":" private func modelRow(for model: OnDeviceLLMModelInfo) -> some View {","violation":{"ruleName":"Function Body Length","severity":"warning","location":{"character":13,"line":137,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMSettingsView.swift"},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 62 lines","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length"}},{"text":" Text(\"⚠️ Requires \\(String(format: \"%.0f\", model.requiredRAM))GB RAM (Device: \\(String(format: \"%.1f\", DeviceCapabilities.totalRAMInGB))GB)\")","violation":{"ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMSettingsView.swift","line":178,"character":1},"reason":"Line should be 120 characters or less; currently it has 168 characters","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"text":" Text(\"Automatically set based on device RAM: \\(DeviceCapabilities.onDeviceLLMContextSize == 8192 ? \"8k\" : \"16k\") for devices with \\(DeviceCapabilities.onDeviceLLMContextSize == 8192 ? \"<8GB\" : \"β‰₯8GB\") RAM\")","violation":{"location":{"character":1,"line":378,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMSettingsView.swift"},"severity":"error","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 200 characters or less; currently it has 214 characters"}},{"text":"}","violation":{"ruleIdentifier":"file_length","reason":"File should contain 400 lines or less: currently contains 502","ruleDescription":"Files should not span too many lines.","ruleName":"File Length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMSettingsView.swift","line":502}}},{"text":"You are an AI assistant specialized in processing audio transcripts. Analyze the ACTUAL CONTENT of the transcript and extract only what is explicitly mentioned.","violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMTemplate.swift","line":300,"character":1},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 160 characters"}},{"text":"Be thorough but concise. Focus on information that is personally relevant to the speaker and actually appears in the transcript.","violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 128 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMTemplate.swift","line":316}}},{"text":" init(model: String, messages: [ChatMessage], temperature: Double? = nil, maxCompletionTokens: Int? = nil, topP: Double? = nil, frequencyPenalty: Double? = nil, presencePenalty: Double? = nil, responseFormat: ResponseFormat? = nil, reasoningEffort: String? = nil) {","violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIModels.swift","character":1,"line":118},"reason":"Line should be 200 characters or less; currently it has 268 characters"}},{"text":" if isHostMatch(lowercasedHost, provider: provider) {","violation":{"ruleName":"Prefer For-Where","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","severity":"warning","ruleIdentifier":"for_where","location":{"line":356,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIModels.swift","character":13},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" if isHostMatch(lowercasedHost, provider: provider) {","violation":{"severity":"warning","ruleName":"Prefer For-Where","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIModels.swift","line":364,"character":13},"reason":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where"}},{"text":" if matchesProviderDomain(lowercasedHost, provider: provider) {","violation":{"severity":"warning","reason":"`where` clauses are preferred over a single `if` inside a `for`","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleName":"Prefer For-Where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIModels.swift","line":431,"character":13},"ruleIdentifier":"for_where"}},{"text":" if matchesProviderDomain(lowercasedHost, provider: provider) {","violation":{"ruleIdentifier":"for_where","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleName":"Prefer For-Where","severity":"warning","location":{"character":13,"line":438,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIModels.swift"},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: encoder.codingPath, debugDescription: \"Invalid type for AnyCodable\"))","violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 155 characters","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIModels.swift","line":617}}},{"text":" throw DecodingError.typeMismatch(AnyCodable.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: \"Could not decode AnyCodable\"))","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":635,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIModels.swift","character":1},"ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 165 characters"}},{"text":" \"category\": [\"type\": \"string\", \"enum\": [\"call\", \"meeting\", \"purchase\", \"research\", \"email\", \"travel\", \"health\", \"general\"]],","violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIModels.swift","character":1,"line":658},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 152 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"text":"\/\/ OpenAIErrorResponse and OpenAIError are defined in OpenAITranscribeService.swift","violation":{"ruleName":"File Length","ruleIdentifier":"file_length","severity":"warning","location":{"line":726,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIModels.swift","character":1},"ruleDescription":"Files should not span too many lines.","reason":"File should contain 400 lines or less: currently contains 726"}},{"text":" case off = \"off\"","violation":{"reason":"String enum values can be omitted when they are equal to the enumcase name","ruleDescription":"String enum values can be omitted when they are equal to the enumcase name","ruleIdentifier":"redundant_string_enum_value","severity":"warning","ruleName":"Redundant String Enum Value","location":{"character":16,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","line":13}}},{"text":" case snarky = \"snarky\"","violation":{"ruleName":"Redundant String Enum Value","severity":"warning","ruleDescription":"String enum values can be omitted when they are equal to the enumcase name","location":{"line":14,"character":19,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift"},"reason":"String enum values can be omitted when they are equal to the enumcase name","ruleIdentifier":"redundant_string_enum_value"}},{"text":" case funny = \"funny\"","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","line":15,"character":18},"reason":"String enum values can be omitted when they are equal to the enumcase name","severity":"warning","ruleDescription":"String enum values can be omitted when they are equal to the enumcase name","ruleIdentifier":"redundant_string_enum_value","ruleName":"Redundant String Enum Value"}},{"text":" - Be ruthlessly sarcastic β€” drip with condescension, mock bad ideas, question obvious statements, and add biting commentary after nearly every point","violation":{"reason":"Line should be 120 characters or less; currently it has 160 characters","ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"line":42,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift"},"ruleName":"Line Length"}},{"text":" - Use heavy sarcasm tags like \"oh how groundbreaking\", \"truly shocking\", \"what a revelation\", \"nobody saw that coming\"","violation":{"ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":43,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift"},"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 130 characters","ruleIdentifier":"line_length"}},{"text":" - Editorialize constantly β€” if something is boring, say it's boring. If something is obvious, mock it for being obvious. If a decision is questionable, tear it apart","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 177 characters","ruleName":"Line Length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","line":44}}},{"text":" - Add parenthetical asides that break the fourth wall and commiserate with the reader about having to sit through this","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"character":1,"line":45,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift"},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" - Channel the energy of a comedian who was forced to attend this meeting\/conversation and is NOT happy about it","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","line":46,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters","severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"text":" - Keep it PG and family-friendly β€” no profanity or crude humor, but absolutely DO NOT hold back on the snark, sarcasm, and roasting","violation":{"location":{"line":47,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift"},"reason":"Line should be 120 characters or less; currently it has 143 characters","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters."}},{"text":" - Every paragraph should have at least one zinger. If you're not making the reader smirk, you're not being snarky enough","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"line":48,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","character":1},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":"class OpenAIPromptGenerator {","violation":{"ruleIdentifier":"type_body_length","severity":"warning","ruleDescription":"Type bodies should not span too many lines","ruleName":"Type Body Length","location":{"character":1,"line":70,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift"},"reason":"Class body should span 250 lines or less excluding comments and whitespace: currently spans 296 lines"}},{"text":" You are an AI assistant specialized in analyzing and summarizing audio transcripts and conversations. Your role is to provide clear, actionable insights from the content provided.","violation":{"ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","line":86,"character":1},"reason":"Line should be 120 characters or less; currently it has 187 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"}},{"text":" Extract personal, actionable tasks from the following content. Focus only on tasks that are personal to the speaker or require their direct action. Avoid tasks related to national news, public figures, or general world events.","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","line":274,"character":1},"ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 200 characters or less; currently it has 234 characters","ruleDescription":"Lines should not span too many characters.","severity":"error"}},{"text":" Extract personal, time-sensitive reminders from the following content. Focus only on personal appointments, deadlines, or commitments that directly affect the speaker. Avoid reminders about national news, public events, or general world happenings.","violation":{"reason":"Line should be 200 characters or less; currently it has 256 characters","ruleIdentifier":"line_length","location":{"character":1,"line":296,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift"},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"error"}},{"text":" Please analyze the following content and provide a comprehensive response in VALID JSON format only. Do not include any text before or after the JSON. The response must be a single, well-formed JSON object with this exact structure:","violation":{"severity":"error","ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 200 characters or less; currently it has 240 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","line":348},"ruleDescription":"Lines should not span too many characters."}},{"text":" \"summary\": \"A detailed summary using Markdown formatting with **bold**, *italic*, ## headers, β€’ bullet points, 1. numbered lists, > blockquotes, etc. (aim for 15-20% of the original transcript length)\",","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","character":1,"line":351},"ruleIdentifier":"line_length","reason":"Line should be 200 characters or less; currently it has 214 characters"}},{"text":" - Tasks must be PERSONAL and ACTIONABLE to the speaker β€” do NOT include tasks about news, public figures, or world events","violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 129 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","line":381},"ruleName":"Line Length"}},{"text":" - Reminders must be PERSONAL and TIME-SENSITIVE to the speaker β€” do NOT include reminders about news events or public happenings","violation":{"location":{"line":382,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift"},"reason":"Line should be 120 characters or less; currently it has 136 characters","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":"class OpenAIResponseParser {","violation":{"ruleName":"Type Body Length","ruleIdentifier":"type_body_length","reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 358 lines","location":{"character":1,"line":12,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift"},"severity":"error","ruleDescription":"Type bodies should not span too many lines"}},{"text":" static func parseCompleteResponseFromJSON(_ jsonString: String) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) {","violation":{"ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":16,"character":1},"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 164 characters"}},{"text":" static func parseCompleteResponseFromJSON(_ jsonString: String) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) {","violation":{"ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":16,"character":12},"ruleName":"Function Body Length","ruleDescription":"Function bodies should not span too many lines","severity":"warning","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 94 lines"}},{"text":" static func parseCompleteResponseFromJSON(_ jsonString: String) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) {","violation":{"ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","ruleName":"Large Tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","character":79,"line":16},"reason":"Tuples should have at most 2 members","severity":"error"}},{"text":" struct TaskResponse: Codable {","violation":{"severity":"warning","ruleIdentifier":"nesting","location":{"line":29,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift"},"ruleDescription":"Types should be nested at most 1 level deep, and functions should be nested at most 2 levels deep.","ruleName":"Nesting","reason":"Types should be nested at most 1 level deep"}},{"text":" struct ReminderResponse: Codable {","violation":{"ruleDescription":"Types should be nested at most 1 level deep, and functions should be nested at most 2 levels deep.","severity":"warning","ruleName":"Nesting","ruleIdentifier":"nesting","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","character":13,"line":37},"reason":"Types should be nested at most 1 level deep"}},{"text":" struct TitleResponse: Codable {","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":44,"character":13},"ruleIdentifier":"nesting","ruleDescription":"Types should be nested at most 1 level deep, and functions should be nested at most 2 levels deep.","reason":"Types should be nested at most 1 level deep","ruleName":"Nesting","severity":"warning"}},{"text":" category: TaskItem.TaskCategory(rawValue: taskResponse.category?.lowercased() ?? \"general\") ?? .general,","violation":{"ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":79,"character":1},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 124 characters","ruleName":"Line Length","ruleIdentifier":"line_length"}},{"text":" let urgency = ReminderItem.Urgency(rawValue: reminderResponse.urgency?.lowercased() ?? \"later\") ?? .later","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 121 characters","severity":"warning","location":{"line":85,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","character":1},"ruleDescription":"Lines should not span too many characters."}},{"text":" if let aiTimeRef = reminderResponse.timeReference, !aiTimeRef.isEmpty && aiTimeRef != \"No time specified\" {","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":90,"character":1},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 123 characters","ruleIdentifier":"line_length","severity":"warning"}},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":105,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift"},"reason":"Line should be 120 characters or less; currently it has 127 characters"},"text":" let category = TitleItem.TitleCategory(rawValue: titleResponse.category?.lowercased() ?? \"general\") ?? .general"},{"violation":{"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 132 characters","ruleIdentifier":"line_length","location":{"line":126,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","character":1},"ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.networking(\"OpenAI returned empty JSON object - check API key and model configuration\", level: .error)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":127,"character":1},"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 140 characters","ruleIdentifier":"line_length"},"text":" throw SummarizationError.aiServiceUnavailable(service: \"OpenAI returned empty JSON - check API key and model configuration\")"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":158,"character":1},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 127 characters"},"text":" let category = TitleItem.TitleCategory(rawValue: titleResponse.category?.lowercased() ?? \"general\") ?? .general"},{"violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":168},"reason":"Line should be 120 characters or less; currently it has 128 characters","ruleIdentifier":"line_length"},"text":" throw SummarizationError.aiServiceUnavailable(service: \"Failed to parse titles JSON: \\(error.localizedDescription)\")"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 124 characters","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":194,"character":1}},"text":" category: TaskItem.TaskCategory(rawValue: taskResponse.category?.lowercased() ?? \"general\") ?? .general,"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":199},"reason":"Line should be 120 characters or less; currently it has 127 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" throw SummarizationError.aiServiceUnavailable(service: \"Failed to parse tasks JSON: \\(error.localizedDescription)\")"},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":220},"severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 121 characters","ruleDescription":"Lines should not span too many characters."},"text":" let urgency = ReminderItem.Urgency(rawValue: reminderResponse.urgency?.lowercased() ?? \"later\") ?? .later"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 123 characters","location":{"line":225,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift"},"ruleName":"Line Length","ruleIdentifier":"line_length"},"text":" if let aiTimeRef = reminderResponse.timeReference, !aiTimeRef.isEmpty && aiTimeRef != \"No time specified\" {"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 131 characters","ruleDescription":"Lines should not span too many characters.","location":{"line":239,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift"},"ruleName":"Line Length"},"text":" throw SummarizationError.aiServiceUnavailable(service: \"Failed to parse reminders JSON: \\(error.localizedDescription)\")"},{"violation":{"reason":"Function should have complexity 10 or less; currently complexity is 14","ruleDescription":"Complexity of function bodies should be limited.","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":389,"character":13},"ruleName":"Cyclomatic Complexity","ruleIdentifier":"cyclomatic_complexity"},"text":" private static func extractJSONFromResponse(_ response: String) -> String {"},{"violation":{"reason":"File should contain 400 lines or less: currently contains 483","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":483},"ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","ruleName":"File Length","severity":"warning"},"text":"}"},{"text":"class OpenAISummarizationService: ObservableObject {","violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift","line":12},"severity":"warning","ruleIdentifier":"type_body_length","ruleDescription":"Type bodies should not span too many lines","ruleName":"Type Body Length","reason":"Class body should span 250 lines or less excluding comments and whitespace: currently spans 259 lines"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 167 characters","location":{"character":1,"line":136,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift"},"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","reason":"Tuples should have at most 2 members","ruleIdentifier":"large_tuple","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift","character":56,"line":136}}},{"text":" AppLog.shared.networking(\"Provider: \\(config.baseURL), format: \\(cachedMessageFormat.displayName), response_format: \\(cachedShouldUseResponseFormat ? \"json_object\" : \"none\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 198 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"line":168,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift","character":1}}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"Failed to parse models response: \\(error.localizedDescription)\")","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift","line":290},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" private func makeAPICall(request: OpenAIChatCompletionRequest) async throws -> OpenAIChatCompletionResponse {","violation":{"severity":"warning","ruleIdentifier":"function_body_length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 56 lines","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift","line":331,"character":13},"ruleName":"Function Body Length","ruleDescription":"Function bodies should not span too many lines"}},{"text":" AppLog.shared.networking(\"OpenAI API Configuration - Model: \\(config.effectiveModelId), BaseURL: \\(config.baseURL)\", level: .debug)","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","location":{"line":351,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift","character":1},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 139 characters","severity":"warning"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"Failed to encode request: \\(error.localizedDescription)\")","violation":{"ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 125 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift","character":1,"line":369}}},{"text":" AppLog.shared.networking(\"OpenAI API Response - Status: \\(httpResponse.statusCode), size: \\(data.count) bytes\", level: .debug)","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 142 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift","line":381}}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"OpenAI API Error: \\(errorResponse.error.message)\")","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":388,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift"},"reason":"Line should be 120 characters or less; currently it has 126 characters","severity":"warning"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"OpenAI API Error: HTTP \\(httpResponse.statusCode)\")","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 127 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift","character":1,"line":391}}},{"text":" AppLog.shared.networking(\"OpenAI API Success - Model: \\(apiResponse.model), Tokens: \\(tokenCount), response: \\(apiResponse.choices.first?.message.content.count ?? 0) chars\", level: .debug)","violation":{"reason":"Line should be 120 characters or less; currently it has 200 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length","location":{"character":1,"line":401,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift"}}},{"violation":{"severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift","line":407},"reason":"Line should be 120 characters or less; currently it has 126 characters","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" throw SummarizationError.aiServiceUnavailable(service: \"OpenAI API request failed: \\(error.localizedDescription)\")"},{"violation":{"ruleDescription":"Files should not span too many lines.","severity":"warning","ruleName":"File Length","ruleIdentifier":"file_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift","line":410},"reason":"File should contain 400 lines or less: currently contains 410"},"text":"}"},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISettingsView.swift","line":14},"reason":"Line should be 120 characters or less; currently it has 126 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length"},"text":" @AppStorage(EndpointSecurityPolicy.allowInsecurePublicEndpointsKey) private var allowInsecurePublicEndpoints: Bool = false"},{"violation":{"reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISettingsView.swift","line":36,"character":74}},"text":" Button(action: { showingAPIKeyInfo = true }) {"},{"violation":{"severity":"warning","location":{"line":94,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISettingsView.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 144 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"},"text":" Text(\"GPT-4o Mini is the cheapest and fastest option. GPT-4o Transcribe is the most robust. Whisper-1 is the legacy model.\")"},{"violation":{"location":{"line":198,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISettingsView.swift"},"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"error","reason":"Line should be 200 characters or less; currently it has 204 characters","ruleDescription":"Lines should not span too many characters."},"text":" Text(\"You can get your OpenAI API key from platform.openai.com. Go to API Keys section and create a new secret key. Make sure your account has sufficient credits for transcription usage.\")"},{"violation":{"severity":"warning","reason":"Class body should span 250 lines or less excluding comments and whitespace: currently spans 280 lines","ruleIdentifier":"type_body_length","ruleName":"Type Body Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","character":1,"line":10},"ruleDescription":"Type bodies should not span too many lines"},"text":"class OpenAISummarizationEngine: SummarizationEngine, ConnectionTestable {"},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":40},"reason":"Line should be 120 characters or less; currently it has 156 characters","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" AppLogger.shared.verbose(\"Checking enableOpenAI setting - Value: \\(isEnabled), Key exists: \\(keyExists)\", category: \"OpenAISummarizationEngine\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 121 characters","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":117},"ruleIdentifier":"line_length"},"text":" AppLog.shared.summarization(\"OpenAISummarizationEngine: Reminder extraction failed: \\(error)\", level: .error)"},{"violation":{"location":{"character":1,"line":151,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift"},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 124 characters","severity":"warning"},"text":" AppLog.shared.summarization(\"OpenAISummarizationEngine: Content classification failed: \\(error)\", level: .error)"},{"violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 167 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":156},"ruleIdentifier":"line_length"},"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"reason":"Tuples should have at most 2 members","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","location":{"character":56,"line":156,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift"},"ruleName":"Large Tuple","ruleIdentifier":"large_tuple"},"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":172,"character":1},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 121 characters"},"text":" AppLog.shared.summarization(\"Large transcript detected (\\(tokenCount) tokens), using chunked processing\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","character":1,"line":179},"reason":"Line should be 120 characters or less; currently it has 121 characters","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning"},"text":" AppLog.shared.summarization(\"OpenAISummarizationEngine: Complete processing failed: \\(error)\", level: .error)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":188},"reason":"Line should be 120 characters or less; currently it has 137 characters","ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length"},"text":" let modelString = UserDefaults.standard.string(forKey: \"openAISummarizationModel\") ?? OpenAISummarizationModel.gpt41Mini.rawValue"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 150 characters","location":{"line":216,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","character":1}},"text":" AppLogger.shared.verbose(\"Updating configuration - Model: \\(modelString), BaseURL: \\(baseURL)\", category: \"OpenAISummarizationEngine\")"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 200 characters or less; currently it has 217 characters","severity":"error","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":231,"character":1}},"text":" private func processChunkedText(_ text: String, service: OpenAISummarizationService) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"ruleIdentifier":"large_tuple","location":{"line":231,"character":106,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift"},"severity":"error","reason":"Tuples should have at most 2 members","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleName":"Large Tuple"},"text":" private func processChunkedText(_ text: String, service: OpenAISummarizationService) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":250,"character":1},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 152 characters"},"text":" AppLog.shared.summarization(\"Processing chunk \\(index + 1) of \\(chunks.count) (\\(TokenManager.getTokenCount(chunk)) tokens)\", level: .debug)"},{"violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"character":1,"line":284,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift"},"severity":"error","reason":"Line should be 200 characters or less; currently it has 206 characters"},"text":" AppLog.shared.summarization(\"Final results - summary: \\(combinedSummary.count) chars, tasks: \\(uniqueTasks.count), reminders: \\(uniqueReminders.count), titles: \\(uniqueTitles.count)\", level: .debug)"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","character":1,"line":358},"ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 121 characters","severity":"warning","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.summarization(\"OpenAISummarizationEngine: Service is nil - configuration issue\", level: .error)"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":383,"character":1},"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 131 characters"},"text":" return SummarizationError.aiServiceUnavailable(service: \"OpenAI API quota exceeded. Please check your billing status.\")"},{"violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 126 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":385,"character":1},"severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" return SummarizationError.aiServiceUnavailable(service: \"OpenAI API rate limit exceeded. Please try again later.\")"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 127 characters","severity":"warning","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":387,"character":1}},"text":" return SummarizationError.aiServiceUnavailable(service: \"Invalid OpenAI API key. Please check your configuration.\")"},{"text":" AppLogger.shared.verbose(\"Checking enableOpenAICompatible setting - Value: \\(isEnabled), Key exists: \\(keyExists)\", category: \"OpenAICompatibleEngine\")","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":427,"character":1},"reason":"Line should be 120 characters or less; currently it has 163 characters","severity":"warning","ruleIdentifier":"line_length"}},{"text":" AppLogger.shared.verbose(\"OpenAI Compatible is not enabled in settings\", category: \"OpenAICompatibleEngine\")","violation":{"ruleName":"Line Length","location":{"line":433,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift"},"reason":"Line should be 120 characters or less; currently it has 124 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":527,"character":1},"reason":"Line should be 120 characters or less; currently it has 167 characters"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","reason":"Tuples should have at most 2 members","location":{"character":56,"line":527,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift"},"ruleName":"Large Tuple","severity":"error"}},{"text":" AppLogger.shared.verbose(\"Updating configuration - Model: \\(modelId), BaseURL: \\(baseURL)\", category: \"OpenAICompatibleEngine\")","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 143 characters","location":{"line":583,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","character":1},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":"}","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","character":1,"line":603},"reason":"File should contain 400 lines or less: currently contains 603","ruleName":"File Length","ruleIdentifier":"file_length","ruleDescription":"Files should not span too many lines.","severity":"warning"}},{"text":" @AppStorage(\"openAISummarizationModel\") private var selectedModel: String = OpenAISummarizationModel.gpt41Mini.rawValue","violation":{"ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","character":1,"line":12},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 123 characters","ruleIdentifier":"line_length"}},{"text":" @AppStorage(EndpointSecurityPolicy.allowInsecurePublicEndpointsKey) private var allowInsecurePublicEndpoints: Bool = false","violation":{"reason":"Line should be 120 characters or less; currently it has 126 characters","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","character":1,"line":17},"ruleDescription":"Lines should not span too many characters."}},{"text":" Button(action: { showingAPIKeyInfo = true }) {","violation":{"ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"line":81,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","character":66},"severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":"struct OpenAICompatibleSettingsView: View {","violation":{"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 703 lines","ruleIdentifier":"type_body_length","ruleName":"Type Body Length","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":266,"character":1},"ruleDescription":"Type bodies should not span too many lines"}},{"text":" @AppStorage(EndpointSecurityPolicy.allowInsecurePublicEndpointsKey) private var allowInsecurePublicEndpoints: Bool = false","violation":{"reason":"Line should be 120 characters or less; currently it has 126 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","location":{"line":275,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift"},"ruleName":"Line Length"}},{"text":" AppLog.shared.general(\"OpenAICompatibleSettingsView: Initialized enableOpenAICompatible to \\(isSelectedEngine)\")","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":309,"character":1},"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 124 characters","ruleName":"Line Length","ruleIdentifier":"line_length"}},{"violation":{"location":{"character":1,"line":335,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift"},"reason":"Line should be 120 characters or less; currently it has 123 characters","ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."},"text":" let modelIds = try await OpenAISummarizationService.fetchCompatibleModels(apiKey: apiKey, baseURL: baseURL)"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":351,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift"},"reason":"Line should be 120 characters or less; currently it has 151 characters"},"text":" AppLog.shared.general(\"Models: \\(modelIds.prefix(5).joined(separator: \", \"))\\(modelIds.count > 5 ? \"...\" : \"\")\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"line":449,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift"},"ruleName":"Line Length","reason":"Line should be 200 characters or less; currently it has 307 characters","severity":"error"},"text":" Text(\"Get your API key from your provider:\\n\\nβ€’ OpenRouter: openrouter.ai\\nβ€’ Together AI: api.together.xyz\\nβ€’ Groq: console.groq.com\\nβ€’ Replicate: replicate.com\\nβ€’ Fireworks AI: fireworks.ai\\nβ€’ Local services (LiteLLM, vLLM, LocalAI): May not require a real key, use any value like 'local'\")"},{"violation":{"severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":497,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."},"text":" Text(\"This engine is currently active and will be used for AI processing. It has been automatically enabled.\")"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":599,"character":1},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 196 characters"},"text":" Text(\"This engine supports many providers through LiteLLM, OpenRouter, and similar services. JSON output quality varies by model. Larger, more recent models generally perform better.\")"},{"violation":{"reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":609,"character":66},"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","severity":"warning"},"text":" Button(action: { showingAPIKeyInfo = true }) {"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","location":{"line":641,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","character":1},"ruleDescription":"Lines should not span too many characters.","severity":"error","reason":"Line should be 200 characters or less; currently it has 227 characters"},"text":" Text(\"Your API key is stored securely on your device and only used for AI summarization. Some providers (like LocalAI or local LiteLLM) may not require an API key - in that case, you can use any placeholder value.\")"},{"violation":{"ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":678},"reason":"Line should be 200 characters or less; currently it has 273 characters","severity":"error","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" Text(\"Enter the base URL for your OpenAI-compatible API. Examples:\\nβ€’ LiteLLM: http:\/\/localhost:4000\\nβ€’ vLLM: http:\/\/localhost:8000\/v1\\nβ€’ LocalAI: http:\/\/localhost:8080\/v1\\nβ€’ OpenRouter: https:\/\/openrouter.ai\/api\/v1\\nβ€’ Together AI: https:\/\/api.together.xyz\/v1\")"},{"violation":{"location":{"character":1,"line":700,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift"},"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 200 characters","ruleDescription":"Lines should not span too many characters."},"text":" Text(\"Enable to discover models from your API endpoint automatically. If your provider supports the \/models endpoint (like LiteLLM, vLLM, LocalAI), it will list all available models.\")"},{"violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 161 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":702,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift"},"ruleName":"Line Length"},"text":" Text(\"Enter the model ID manually. Common examples: gpt-4o, claude-sonnet-4-5-20250929, llama-4-maverick, gemini-2.5-flash, deepseek-chat, etc.\")"},{"violation":{"severity":"warning","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","location":{"line":728,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","character":36}},"text":" }) {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":810,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"},"text":" Text(\"Fine-tune the AI's behavior. Lower temperature for consistent results, higher for more creative summaries.\")"},{"text":" Text(\"Block-based format: {\\\"content\\\": [{\\\"type\\\": \\\"text\\\", \\\"text\\\": \\\"...\\\"}]}\")","violation":{"location":{"line":915,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift"},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 124 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"}},{"text":" Text(\"Format is automatically detected from your base URL. Enable override only if auto-detection fails.\")","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"line":939,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift"},"reason":"Line should be 120 characters or less; currently it has 122 characters","severity":"warning"}},{"text":" Text(\"Test your API connection. A successful test means the provider is reachable, but individual model performance may vary. If your model produces poor results, try a different model or adjust generation parameters.\")","violation":{"ruleName":"Line Length","severity":"error","ruleIdentifier":"line_length","reason":"Line should be 200 characters or less; currently it has 231 characters","ruleDescription":"Lines should not span too many characters.","location":{"line":951,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","character":1}}},{"text":"}","violation":{"ruleName":"File Length","severity":"error","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":1074},"ruleIdentifier":"file_length","reason":"File should contain 1000 lines or less: currently contains 1074","ruleDescription":"Files should not span too many lines."}},{"text":" func transcribeAudioFile(at url: URL, recordingId: UUID? = nil) async throws -> OpenAITranscribeResult {","violation":{"ruleIdentifier":"function_body_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","character":5,"line":200},"ruleName":"Function Body Length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 84 lines","ruleDescription":"Function bodies should not span too many lines"}},{"text":" let result = try await performTranscription(audioData: audioData, fileName: audioChunk.chunkURL.lastPathComponent)","violation":{"ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":231,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"text":" recordingId: recordingId ?? UUID() \/\/ TODO: Get actual recording ID from Core Data","violation":{"severity":"warning","ruleName":"Todo","reason":"TODOs should be resolved (Get actual recording ID from C...)","ruleIdentifier":"todo","ruleDescription":"TODOs and FIXMEs should be resolved.","location":{"character":59,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":254}}},{"text":" private func performTranscription(audioData: Data, fileName: String) async throws -> OpenAITranscribeResult {","violation":{"ruleIdentifier":"function_body_length","ruleName":"Function Body Length","ruleDescription":"Function bodies should not span too many lines","severity":"warning","location":{"line":308,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift"},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 75 lines"}},{"text":" body.append(\"--\\(boundary)\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","character":21,"line":327},"ruleIdentifier":"non_optional_string_data_conversion"}},{"text":" body.append(\"Content-Disposition: form-data; name=\\\"file\\\"; filename=\\\"\\(fileName)\\\"\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"line":328,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","character":21},"ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"Content-Type: \\(getContentType(for: fileName))\\r\\n\\r\\n\".data(using: .utf8)!)","violation":{"location":{"line":329,"character":21,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift"},"ruleIdentifier":"non_optional_string_data_conversion","severity":"warning","ruleName":"Non-optional String -> Data Conversion","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"\\r\\n\".data(using: .utf8)!)","violation":{"severity":"warning","location":{"line":331,"character":21,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift"},"ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","ruleName":"Non-optional String -> Data Conversion","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"violation":{"ruleName":"Non-optional String -> Data Conversion","ruleIdentifier":"non_optional_string_data_conversion","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","location":{"line":334,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","character":21},"severity":"warning"},"text":" body.append(\"--\\(boundary)\\r\\n\".data(using: .utf8)!)"},{"violation":{"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","ruleName":"Non-optional String -> Data Conversion","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","location":{"line":335,"character":21,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift"},"severity":"warning"},"text":" body.append(\"Content-Disposition: form-data; name=\\\"model\\\"\\r\\n\\r\\n\".data(using: .utf8)!)"},{"violation":{"ruleIdentifier":"non_optional_string_data_conversion","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","severity":"warning","ruleName":"Non-optional String -> Data Conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","character":21,"line":337},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"},"text":" body.append(\"\\r\\n\".data(using: .utf8)!)"},{"violation":{"ruleName":"Non-optional String -> Data Conversion","location":{"line":340,"character":21,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift"},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","severity":"warning"},"text":" body.append(\"--\\(boundary)\\r\\n\".data(using: .utf8)!)"},{"violation":{"ruleIdentifier":"non_optional_string_data_conversion","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleName":"Non-optional String -> Data Conversion","severity":"warning","location":{"character":21,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":341}},"text":" body.append(\"Content-Disposition: form-data; name=\\\"response_format\\\"\\r\\n\\r\\n\".data(using: .utf8)!)"},{"violation":{"ruleIdentifier":"non_optional_string_data_conversion","ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":342,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"},"text":" body.append(\"json\".data(using: .utf8)!)"},{"violation":{"location":{"line":343,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","character":21},"ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleIdentifier":"non_optional_string_data_conversion","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"},"text":" body.append(\"\\r\\n\".data(using: .utf8)!)"},{"violation":{"ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleName":"Non-optional String -> Data Conversion","location":{"line":349,"character":21,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift"},"ruleIdentifier":"non_optional_string_data_conversion","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","severity":"warning"},"text":" body.append(\"--\\(boundary)\\r\\n\".data(using: .utf8)!)"},{"violation":{"ruleIdentifier":"non_optional_string_data_conversion","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleName":"Non-optional String -> Data Conversion","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":350,"character":21}},"text":" body.append(\"Content-Disposition: form-data; name=\\\"temperature\\\"\\r\\n\\r\\n\".data(using: .utf8)!)"},{"violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","location":{"character":21,"line":351,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift"},"ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"},"text":" body.append(\"0\".data(using: .utf8)!)"},{"violation":{"ruleIdentifier":"non_optional_string_data_conversion","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleName":"Non-optional String -> Data Conversion","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":352,"character":21}},"text":" body.append(\"\\r\\n\".data(using: .utf8)!)"},{"violation":{"ruleName":"Non-optional String -> Data Conversion","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","character":21,"line":355},"ruleIdentifier":"non_optional_string_data_conversion","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"},"text":" body.append(\"--\\(boundary)--\\r\\n\".data(using: .utf8)!)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":359},"reason":"Line should be 120 characters or less; currently it has 129 characters","ruleName":"Line Length","ruleIdentifier":"line_length"},"text":" AppLog.shared.transcription(\"Using model: \\(config.model.displayName), request size: \\(body.count) bytes\", level: .debug)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 143 characters","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","character":1,"line":373},"ruleIdentifier":"line_length"},"text":" AppLog.shared.transcription(\"OpenAI API error: HTTP \\(httpResponse.statusCode), response size: \\(data.count) bytes\", level: .error)"},{"violation":{"location":{"character":1,"line":399,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift"},"reason":"Line should be 120 characters or less; currently it has 157 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length"},"text":" AppLog.shared.transcription(\"Transcript length: \\(transcribeResponse.text.count) chars, processing time: \\(String(format: \"%.1f\", processingTime))s\")"},{"violation":{"location":{"line":402,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 174 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning"},"text":" AppLog.shared.transcription(\"Token usage - Input: \\(usage.inputTokens ?? 0), Output: \\(usage.outputTokens ?? 0), Total: \\(usage.totalTokens ?? 0)\", level: .debug)"},{"violation":{"ruleName":"File Length","location":{"line":474,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift"},"ruleIdentifier":"file_length","ruleDescription":"Files should not span too many lines.","severity":"warning","reason":"File should contain 400 lines or less: currently contains 474"},"text":"}"},{"violation":{"ruleIdentifier":"type_body_length","ruleDescription":"Type bodies should not span too many lines","severity":"error","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","line":92},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 519 lines","ruleName":"Type Body Length"},"text":"class PerformanceOptimizer: ObservableObject {"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"line":102,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters","severity":"warning","ruleName":"Line Length"},"text":" private let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? \"com.bisonnotes.app\", category: \"Performance\")"},{"violation":{"reason":"Line should be 200 characters or less; currently it has 224 characters","ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":372,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift"},"ruleIdentifier":"line_length"},"text":" func processLargeTranscriptWithStreaming(_ text: String, using engine: SummarizationEngine) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"ruleIdentifier":"large_tuple","reason":"Tuples should have at most 2 members","ruleName":"Large Tuple","severity":"error","location":{"character":113,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","line":372},"ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead."},"text":" func processLargeTranscriptWithStreaming(_ text: String, using engine: SummarizationEngine) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 142 characters","ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","character":1,"line":446}},"text":" let result = (summary: finalSummary, tasks: finalTasks, reminders: finalReminders, titles: finalTitles, contentType: finalContentType)"},{"violation":{"ruleIdentifier":"line_length","reason":"Line should be 200 characters or less; currently it has 211 characters","location":{"line":505,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift"},"severity":"error","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" func processLargeTranscript(_ text: String, using engine: SummarizationEngine) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"ruleDescription":"Function bodies should not span too many lines","severity":"warning","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 59 lines","location":{"character":5,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","line":505},"ruleIdentifier":"function_body_length","ruleName":"Function Body Length"},"text":" func processLargeTranscript(_ text: String, using engine: SummarizationEngine) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"severity":"error","reason":"Tuples should have at most 2 members","ruleIdentifier":"large_tuple","location":{"character":100,"line":505,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift"},"ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleName":"Large Tuple"},"text":" func processLargeTranscript(_ text: String, using engine: SummarizationEngine) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","character":1,"line":590},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 142 characters"},"text":" let result = (summary: finalSummary, tasks: finalTasks, reminders: finalReminders, titles: finalTitles, contentType: finalContentType)"},{"violation":{"reason":"Line should be 200 characters or less; currently it has 236 characters","severity":"error","ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":629,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift"}},"text":" private func processChunkWithRetry(_ chunk: String, using engine: SummarizationEngine, retryCount: Int) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"location":{"line":629,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","character":125},"ruleIdentifier":"large_tuple","ruleName":"Large Tuple","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","severity":"error","reason":"Tuples should have at most 2 members"},"text":" private func processChunkWithRetry(_ chunk: String, using engine: SummarizationEngine, retryCount: Int) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {"},{"violation":{"location":{"line":753,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift"},"reason":"Line should be 120 characters or less; currently it has 162 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length"},"text":" private func getCachedResult(key: String) -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)? {"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","line":753,"character":50},"reason":"Tuples should have at most 2 members","severity":"error","ruleIdentifier":"large_tuple","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleName":"Large Tuple"},"text":" private func getCachedResult(key: String) -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)? {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 174 characters","severity":"warning","location":{"line":757,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","character":1},"ruleName":"Line Length"},"text":" private func cacheResult(key: String, result: (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType), cost: Int) {"},{"violation":{"ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleName":"Large Tuple","ruleIdentifier":"large_tuple","severity":"error","location":{"character":51,"line":757,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift"},"reason":"Tuples should have at most 2 members"},"text":" private func cacheResult(key: String, result: (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType), cost: Int) {"},{"violation":{"ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","line":899},"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 143 characters"},"text":" init(averageProcessingTime: TimeInterval = 0.0, wordsPerSecond: Double = 0.0, cacheHitRate: Double = 0.0, memoryEfficiency: Double = 1.0) {"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","character":1,"line":924},"reason":"Line should be 120 characters or less; currently it has 126 characters","ruleName":"Line Length","severity":"warning"},"text":" let result: (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)"},{"violation":{"ruleIdentifier":"large_tuple","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","location":{"line":924,"character":17,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift"},"ruleName":"Large Tuple","severity":"error","reason":"Tuples should have at most 2 members"},"text":" let result: (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","character":1,"line":927},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 147 characters","ruleName":"Line Length","ruleIdentifier":"line_length"},"text":" init(result: (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType), timestamp: Date) {"},{"violation":{"ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleName":"Large Tuple","ruleIdentifier":"large_tuple","location":{"line":927,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","character":18},"severity":"error","reason":"Tuples should have at most 2 members"},"text":" init(result: (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType), timestamp: Date) {"},{"violation":{"location":{"line":1113,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift"},"ruleDescription":"Files should not span too many lines.","reason":"File should contain 1000 lines or less: currently contains 1113","severity":"error","ruleIdentifier":"file_length","ruleName":"File Length"},"text":"}"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Persistence.swift","character":1,"line":80},"reason":"Line should be 120 characters or less; currently it has 172 characters","ruleName":"Line Length","severity":"warning"},"text":" \"Loaded temporary in-memory Core Data fallback after persistent store failure. Existing recordings may be unavailable until the app restarts successfully.\","},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"line":85,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Persistence.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"},"text":" \"Failed to load in-memory Core Data fallback after persistent store failure: \\(error.localizedDescription)\","},{"violation":{"ruleName":"Type Body Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":13,"character":1},"ruleIdentifier":"type_body_length","ruleDescription":"Type bodies should not span too many lines","severity":"error","reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 486 lines"},"text":"class ReminderExtractor {"},{"violation":{"ruleName":"Prefer For-Where","severity":"warning","reason":"`where` clauses are preferred over a single `if` inside a `for`","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":106,"character":13}},"text":" if lowercased.contains(pattern) {"},{"violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 139 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":110,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift"}},"text":" let confidence = calculateExplicitReminderConfidence(sentence: sentence, pattern: pattern, baseConfidence: confidenceBoost)"},{"violation":{"ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleName":"Prefer For-Where","ruleIdentifier":"for_where","location":{"character":13,"line":148,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift"},"reason":"`where` clauses are preferred over a single `if` inside a `for`","severity":"warning"},"text":" if lowercased.contains(pattern) {"},{"violation":{"severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 121 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":154,"character":1}},"text":" let urgency = determineUrgencyFromTimeReference(timeReference, sentence: sentence, hint: urgencyHint)"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","character":1,"line":155},"reason":"Line should be 120 characters or less; currently it has 141 characters","severity":"warning","ruleName":"Line Length"},"text":" let confidence = calculateTimeBasedReminderConfidence(sentence: sentence, pattern: pattern, timeReference: timeReference)"},{"violation":{"ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleName":"Prefer For-Where","ruleIdentifier":"for_where","reason":"`where` clauses are preferred over a single `if` inside a `for`","severity":"warning","location":{"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":198}},"text":" if lowercased.contains(pattern) {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 137 characters","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":205,"character":1}},"text":" let confidence = calculateEventReminderConfidence(sentence: sentence, pattern: pattern, timeReference: timeReference)"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":237,"character":13},"ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","reason":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","ruleName":"Prefer For-Where","severity":"warning"},"text":" if lowercased.contains(pattern) {"},{"violation":{"reason":"Tuples should have at most 2 members","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","character":68,"line":316},"ruleName":"Large Tuple","ruleIdentifier":"large_tuple"},"text":" private func parseRelativeTimeReference(_ sentence: String) -> (original: String, date: Date?, relative: String)? {"},{"violation":{"ruleName":"Large Tuple","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","character":32,"line":321},"ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","reason":"Tuples should have at most 2 members","ruleIdentifier":"large_tuple"},"text":" let relativePatterns: [(pattern: String, dateCalculation: (Date, Calendar) -> Date?, relative: String)] = ["},{"violation":{"location":{"line":335,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift"},"severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","ruleName":"Prefer For-Where","reason":"`where` clauses are preferred over a single `if` inside a `for`"},"text":" if lowercased.contains(pattern) {"},{"violation":{"reason":"Tuples should have at most 2 members","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","severity":"warning","ruleIdentifier":"large_tuple","ruleName":"Large Tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":344,"character":65}},"text":" private func parseDayOfWeekReference(_ sentence: String) -> (original: String, date: Date?, relative: String)? {"},{"violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":355,"character":13},"ruleIdentifier":"for_where","reason":"`where` clauses are preferred over a single `if` inside a `for`","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleName":"Prefer For-Where"},"text":" if lowercased.contains(dayName) {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","location":{"line":356,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift"},"reason":"Line should be 120 characters or less; currently it has 136 characters","severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length"},"text":" if let nextDate = calendar.nextDate(after: now, matching: DateComponents(weekday: weekday), matchingPolicy: .nextTime) {"},{"violation":{"ruleIdentifier":"for_where","ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","location":{"character":13,"line":378,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift"},"reason":"`where` clauses are preferred over a single `if` inside a `for`"},"text":" if lowercased.contains(pattern) {"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"line":393,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift"},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 126 characters"},"text":" if let match = regex?.firstMatch(in: sentence, options: [], range: NSRange(location: 0, length: sentence.count)) {"},{"violation":{"severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","ruleName":"Prefer For-Where","location":{"character":13,"line":411,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift"},"reason":"`where` clauses are preferred over a single `if` inside a `for`"},"text":" if lowercased.contains(pattern) {"},{"violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"line":444,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 174 characters","ruleIdentifier":"line_length"},"text":" private func determineUrgencyFromTimeReference(_ timeReference: ReminderItem.TimeReference, sentence: String, hint: ReminderItem.Urgency? = nil) -> ReminderItem.Urgency {"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 147 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"line":448,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift"}},"text":" if lowercased.contains(\"urgent\") || lowercased.contains(\"asap\") || lowercased.contains(\"immediately\") || lowercased.contains(\"right now\") {"},{"text":" if cleaned.lowercased().hasPrefix(prefix) {","violation":{"reason":"`where` clauses are preferred over a single `if` inside a `for`","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","severity":"warning","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":502,"character":13},"ruleName":"Prefer For-Where"}},{"text":" private func calculateExplicitReminderConfidence(sentence: String, pattern: String, baseConfidence: Double) -> Double {","violation":{"ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 123 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","character":1,"line":546}}},{"text":" private func calculateTimeBasedReminderConfidence(sentence: String, pattern: String, timeReference: ReminderItem.TimeReference) -> Double {","violation":{"ruleIdentifier":"line_length","location":{"line":562,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift"},"reason":"Line should be 120 characters or less; currently it has 143 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length"}},{"text":" private func calculateEventReminderConfidence(sentence: String, pattern: String, timeReference: ReminderItem.TimeReference) -> Double {","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 139 characters","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":579,"character":1},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"text":" for i in 0.. [Float] {"},{"violation":{"ruleName":"Function Body Length","severity":"warning","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 69 lines","ruleDescription":"Function bodies should not span too many lines","location":{"character":13,"line":287,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/AudioCleanupService.swift"},"ruleIdentifier":"function_body_length"},"text":" private func applyNoiseReduction(samples: [Float], noiseProfile: NoiseProfile, strength: Float, sampleRate: Float) -> [Float] {"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 121 characters","ruleIdentifier":"line_length","location":{"line":305,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/AudioCleanupService.swift"},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"},"text":" let paddedInput = [Float](repeating: 0, count: fftSize \/ 2) + samples + [Float](repeating: 0, count: fftSize \/ 2)"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/AudioCleanupService.swift","line":322},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 125 characters"},"text":" segmentPtr.baseAddress!.withMemoryRebound(to: DSPComplex.self, capacity: fftSize \/ 2) { complexPtr in"},{"violation":{"location":{"character":17,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/AudioCleanupService.swift","line":334},"reason":"Variable name 'i' should be between 3 and 40 characters long","ruleIdentifier":"identifier_name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleName":"Identifier Name","severity":"error"},"text":" for i in 0..<(fftSize \/ 2) {"},{"violation":{"ruleIdentifier":"identifier_name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleName":"Identifier Name","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/AudioCleanupService.swift","line":342,"character":17},"reason":"Variable name 'i' should be between 3 and 40 characters long"},"text":" for i in 0.. CGFloat {"},{"violation":{"severity":"error","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","character":48,"line":215},"reason":"Variable name 'y' should be between 3 and 40 characters long","ruleName":"Identifier Name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short."},"text":" private func drawTitle(_ title: String, at y: CGFloat, contentWidth: CGFloat, margins: UIEdgeInsets, context: UIGraphicsPDFRendererContext) -> CGFloat {"},{"violation":{"location":{"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":233},"severity":"error","reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 122 lines","ruleName":"Function Body Length","ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines"},"text":" private func drawHeaderWithMap("},{"violation":{"ruleDescription":"Number of function parameters should be low.","ruleName":"Function Parameter Count","location":{"line":233,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift"},"ruleIdentifier":"function_parameter_count","severity":"warning","reason":"Function should have 5 parameters or less: it currently has 8"},"text":" private func drawHeaderWithMap("},{"violation":{"ruleIdentifier":"identifier_name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","location":{"character":12,"line":238,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift"},"severity":"error","reason":"Variable name 'y' should be between 3 and 40 characters long","ruleName":"Identifier Name"},"text":" at y: CGFloat,"},{"violation":{"location":{"line":382,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift"},"ruleIdentifier":"function_parameter_count","ruleName":"Function Parameter Count","reason":"Function should have 5 parameters or less: it currently has 9","severity":"error","ruleDescription":"Number of function parameters should be low."},"text":" private func drawSummarySection("},{"violation":{"severity":"error","reason":"Variable name 'y' should be between 3 and 40 characters long","ruleIdentifier":"identifier_name","ruleName":"Identifier Name","location":{"character":12,"line":384,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift"},"ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short."},"text":" at y: CGFloat,"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length","location":{"line":407,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift"},"reason":"Line should be 120 characters or less; currently it has 124 characters","ruleDescription":"Lines should not span too many characters."},"text":" currentY = drawSectionTitle(\"Summary\", at: currentY, contentWidth: contentWidth, margins: margins, context: context)"},{"violation":{"severity":"error","location":{"character":13,"line":429,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift"},"reason":"Function should have 5 parameters or less: it currently has 9","ruleName":"Function Parameter Count","ruleIdentifier":"function_parameter_count","ruleDescription":"Number of function parameters should be low."},"text":" private func drawAttributedSummary("},{"violation":{"location":{"character":12,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":431},"severity":"error","ruleName":"Identifier Name","ruleIdentifier":"identifier_name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","reason":"Variable name 'y' should be between 3 and 40 characters long"},"text":" at y: CGFloat,"},{"violation":{"ruleIdentifier":"function_parameter_count","reason":"Function should have 5 parameters or less: it currently has 9","severity":"error","location":{"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":479},"ruleDescription":"Number of function parameters should be low.","ruleName":"Function Parameter Count"},"text":" private func drawTasksSection("},{"violation":{"ruleIdentifier":"identifier_name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","location":{"line":481,"character":12,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift"},"ruleName":"Identifier Name","reason":"Variable name 'y' should be between 3 and 40 characters long","severity":"error"},"text":" at y: CGFloat,"},{"violation":{"ruleName":"Line Length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":502},"reason":"Line should be 120 characters or less; currently it has 139 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"},"text":" currentY = drawSectionTitle(\"Tasks (\\(tasks.count))\", at: currentY, contentWidth: contentWidth, margins: margins, context: context)"},{"violation":{"ruleIdentifier":"function_parameter_count","reason":"Function should have 5 parameters or less: it currently has 9","ruleName":"Function Parameter Count","severity":"error","ruleDescription":"Number of function parameters should be low.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","character":13,"line":533}},"text":" private func drawUserNotesSection("},{"violation":{"location":{"line":535,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","character":12},"ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","severity":"error","ruleName":"Identifier Name","reason":"Variable name 'y' should be between 3 and 40 characters long"},"text":" at y: CGFloat,"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 127 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":557,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift"}},"text":" currentY = drawSectionTitle(\"User Notes\", at: currentY, contentWidth: contentWidth, margins: margins, context: context)"},{"violation":{"ruleIdentifier":"function_parameter_count","severity":"error","location":{"character":13,"line":580,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift"},"reason":"Function should have 5 parameters or less: it currently has 9","ruleName":"Function Parameter Count","ruleDescription":"Number of function parameters should be low."},"text":" private func drawRemindersSection("},{"violation":{"ruleIdentifier":"identifier_name","reason":"Variable name 'y' should be between 3 and 40 characters long","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":582,"character":12},"ruleName":"Identifier Name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","severity":"error"},"text":" at y: CGFloat,"},{"violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 147 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":603},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"},"text":" currentY = drawSectionTitle(\"Reminders (\\(reminders.count))\", at: currentY, contentWidth: contentWidth, margins: margins, context: context)"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 128 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","character":1,"line":639},"severity":"warning"},"text":" private func buildHeaderMapImages(summaryData: EnhancedSummaryData, locationData: LocationData?) async -> HeaderMapImages? {"},{"violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":662,"character":13},"ruleIdentifier":"function_body_length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 54 lines","ruleName":"Function Body Length","ruleDescription":"Function bodies should not span too many lines"},"text":" private func createZoomedOutMapImage("},{"violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","character":1,"line":724},"reason":"Line should be 120 characters or less; currently it has 138 characters"},"text":" AppLog.shared.fileManagement(\"PDFExportService: Regional map generation failed: \\(error.localizedDescription)\", level: .error)"},{"violation":{"reason":"Function should have 5 parameters or less: it currently has 7","severity":"warning","ruleIdentifier":"function_parameter_count","ruleDescription":"Number of function parameters should be low.","ruleName":"Function Parameter Count","location":{"line":742,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift"}},"text":" private func drawMetadataCompactRow("},{"violation":{"ruleName":"Identifier Name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","severity":"error","location":{"line":745,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","character":9},"reason":"Variable name 'x' should be between 3 and 40 characters long","ruleIdentifier":"identifier_name"},"text":" x: CGFloat,"},{"violation":{"ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":746,"character":9},"reason":"Variable name 'y' should be between 3 and 40 characters long","ruleName":"Identifier Name","severity":"error"},"text":" y: inout CGFloat,"},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":830},"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 163 characters","severity":"warning","ruleName":"Line Length"},"text":" private func drawSectionTitle(_ title: String, at y: CGFloat, contentWidth: CGFloat, margins: UIEdgeInsets, context: UIGraphicsPDFRendererContext) -> CGFloat {"},{"violation":{"ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","reason":"Variable name 'y' should be between 3 and 40 characters long","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","character":55,"line":830},"ruleIdentifier":"identifier_name","ruleName":"Identifier Name"},"text":" private func drawSectionTitle(_ title: String, at y: CGFloat, contentWidth: CGFloat, margins: UIEdgeInsets, context: UIGraphicsPDFRendererContext) -> CGFloat {"},{"violation":{"severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 193 characters","ruleDescription":"Lines should not span too many characters.","location":{"line":844,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift"},"ruleName":"Line Length"},"text":" private func drawBulletPoint(_ text: String, at y: CGFloat, contentWidth: CGFloat, margins: UIEdgeInsets, context: UIGraphicsPDFRendererContext, color: UIColor = UIColor.black) -> CGFloat {"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","character":53,"line":844},"reason":"Variable name 'y' should be between 3 and 40 characters long","ruleName":"Identifier Name","ruleIdentifier":"identifier_name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","severity":"error"},"text":" private func drawBulletPoint(_ text: String, at y: CGFloat, contentWidth: CGFloat, margins: UIEdgeInsets, context: UIGraphicsPDFRendererContext, color: UIColor = UIColor.black) -> CGFloat {"},{"violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","character":13,"line":857},"ruleDescription":"Number of function parameters should be low.","ruleIdentifier":"function_parameter_count","ruleName":"Function Parameter Count","reason":"Function should have 5 parameters or less: it currently has 8"},"text":" private func checkAndStartNewPageWithBranding("},{"violation":{"severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 162 characters","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":877,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift"},"ruleName":"Line Length"},"text":" private func drawLine(from start: CGPoint, to end: CGPoint, context: UIGraphicsPDFRendererContext, color: UIColor = UIColor.lightGray, width: CGFloat = 1.0) {"},{"violation":{"ruleDescription":"Function bodies should not span too many lines","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":885,"character":13},"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":"warning"},"text":" private func createSmallFallbackMapImage(for locationData: LocationData, size: CGSize) -> UIImage? {"},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":895},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 128 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning"},"text":" let gradient = CGGradient(colorsSpace: CGColorSpaceCreateDeviceRGB(), colors: colors as CFArray, locations: [0.0, 1.0])!"},{"text":" context.drawLinearGradient(gradient, start: CGPoint(x: 0, y: 0), end: CGPoint(x: size.width, y: size.height), options: [])","violation":{"severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 130 characters","ruleDescription":"Lines should not span too many characters.","location":{"line":896,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","character":1},"ruleIdentifier":"line_length"}},{"text":" context.setShadow(offset: CGSize(width: 1, height: 1), blur: 2, color: UIColor.black.withAlphaComponent(0.3).cgColor)","violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 125 characters","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":910},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":" let coordText = \"\\(String(format: \"%.4f\", locationData.latitude)), \\(String(format: \"%.4f\", locationData.longitude))\"","violation":{"location":{"character":1,"line":930,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift"},"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 125 characters","ruleDescription":"Lines should not span too many characters."}},{"text":" let titleSize = titleText.boundingRect(with: size, options: [.usesLineFragmentOrigin], attributes: titleAttributes, context: nil)","violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":939,"character":1},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" let coordSize = coordText.boundingRect(with: size, options: [.usesLineFragmentOrigin], attributes: coordAttributes, context: nil)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"line":954,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift"},"reason":"Line should be 120 characters or less; currently it has 137 characters","severity":"warning","ruleIdentifier":"line_length"}},{"text":"}","violation":{"reason":"File should contain 400 lines or less: currently contains 982","ruleName":"File Length","ruleIdentifier":"file_length","ruleDescription":"Files should not span too many lines.","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":982}}},{"text":"final class RTFExportService {","violation":{"ruleName":"Type Body Length","reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 427 lines","severity":"error","ruleIdentifier":"type_body_length","ruleDescription":"Type bodies should not span too many lines","location":{"character":7,"line":23,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RTFExportService.swift"}}},{"text":" func generateDocument(","violation":{"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 57 lines","ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length","ruleIdentifier":"function_body_length","severity":"warning","location":{"line":29,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RTFExportService.swift","character":5}}},{"text":" AppLog.shared.fileManagement(\"RTFExportService: Invalid summary data - recording name is empty\", level: .error)","violation":{"location":{"line":38,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RTFExportService.swift"},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 123 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"}},{"text":" AppLog.shared.fileManagement(\"RTFExportService: Document too large, estimated memory usage: \\(estimatedMemoryUsage) bytes\", level: .error)","violation":{"severity":"warning","location":{"line":89,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RTFExportService.swift"},"reason":"Line should be 120 characters or less; currently it has 154 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" AppLog.shared.fileManagement(\"RTFExportService: Converting attributed string to RTF document data\", level: .debug)","violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 126 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RTFExportService.swift","line":97,"character":1}}},{"text":" let data = try document.data(from: NSRange(location: 0, length: documentLength), documentAttributes: documentAttributes)","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","location":{"line":98,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RTFExportService.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning"}},{"violation":{"location":{"line":111,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RTFExportService.swift"},"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 134 characters"},"text":" AppLog.shared.fileManagement(\"RTFExportService: Document generation failed: \\(error.localizedDescription)\", level: .error)"},{"violation":{"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 64 lines","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RTFExportService.swift","line":134,"character":13},"ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","severity":"warning","ruleName":"Function Body Length"},"text":" private func appendMetadata(for summaryData: EnhancedSummaryData, to document: NSMutableAttributedString) {"},{"violation":{"severity":"warning","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":190,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RTFExportService.swift"},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 128 characters"},"text":" (\"Generated: \", DateFormatter.localizedString(from: summaryData.generatedAt, dateStyle: .medium, timeStyle: .short))"},{"violation":{"ruleDescription":"Function bodies should not span too many lines","location":{"line":220,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RTFExportService.swift","character":13},"ruleIdentifier":"function_body_length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 66 lines","severity":"warning","ruleName":"Function Body Length"},"text":" private func appendLocationSection("},{"violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 124 characters","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"line":271,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RTFExportService.swift"},"ruleDescription":"Lines should not span too many characters."},"text":" string: \"\\(String(format: \"%.5f\", locationData.latitude)), \\(String(format: \"%.5f\", locationData.longitude))\\n\","},{"violation":{"reason":"Line should be 120 characters or less; currently it has 124 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RTFExportService.swift","line":529,"character":1},"ruleName":"Line Length","severity":"warning"},"text":" private func appendBulletedList(_ lines: [String], to document: NSMutableAttributedString, includeBullet: Bool = true) {"},{"violation":{"ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","ruleName":"File Length","severity":"warning","reason":"File should contain 400 lines or less: currently contains 561","location":{"line":561,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RTFExportService.swift"}},"text":"}"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 127 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"line":14,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RecordingCombiner.swift"}},"text":" private let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? \"com.bisonnotes.app\", category: \"RecordingCombiner\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 122 characters","ruleIdentifier":"line_length","location":{"line":65,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RecordingCombiner.swift","character":1},"ruleName":"Line Length"},"text":" guard let exportSession = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetAppleM4A) else {"},{"violation":{"location":{"character":42,"line":7,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift"},"ruleName":"Force Try","severity":"error","reason":"Force tries should be avoided","ruleIdentifier":"force_try","ruleDescription":"Force tries should be avoided"},"text":" private static let jsonPrefixRegex = try! NSRegularExpression(pattern: \"^\\\"summary\\\"\\\\s*:\\\\s*\\\"\", options: [])"},{"violation":{"location":{"character":43,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":8},"ruleIdentifier":"force_try","ruleDescription":"Force tries should be avoided","severity":"error","reason":"Force tries should be avoided","ruleName":"Force Try"},"text":" private static let jsonContentRegex = try! NSRegularExpression(pattern: \"^\\\"content\\\"\\\\s*:\\\\s*\\\"\", options: [])"},{"violation":{"location":{"line":9,"character":40,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift"},"reason":"Force tries should be avoided","ruleIdentifier":"force_try","ruleDescription":"Force tries should be avoided","ruleName":"Force Try","severity":"error"},"text":" private static let jsonTextRegex = try! NSRegularExpression(pattern: \"^\\\"text\\\"\\\\s*:\\\\s*\\\"\", options: [])"},{"violation":{"ruleName":"Force Try","ruleIdentifier":"force_try","severity":"error","reason":"Force tries should be avoided","ruleDescription":"Force tries should be avoided","location":{"line":10,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","character":42}},"text":" private static let jsonSuffixRegex = try! NSRegularExpression(pattern: \"\\\"\\\\s*$\", options: [])"},{"violation":{"ruleIdentifier":"force_try","reason":"Force tries should be avoided","ruleDescription":"Force tries should be avoided","severity":"error","location":{"line":11,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","character":48},"ruleName":"Force Try"},"text":" private static let multipleNewlinesRegex = try! NSRegularExpression(pattern: \"\\n{3,}\", options: [])"},{"violation":{"reason":"Force tries should be avoided","ruleIdentifier":"force_try","ruleName":"Force Try","location":{"line":12,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","character":38},"ruleDescription":"Force tries should be avoided","severity":"error"},"text":" private static let headerRegex = try! NSRegularExpression(pattern: \"^#{1,6}\\\\s+\", options: [])"},{"violation":{"reason":"Force tries should be avoided","ruleIdentifier":"force_try","severity":"error","ruleName":"Force Try","ruleDescription":"Force tries should be avoided","location":{"line":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","character":38}},"text":" private static let bulletRegex = try! NSRegularExpression(pattern: \"^[-*+]\\\\s+\", options: [])"},{"violation":{"ruleDescription":"Force tries should be avoided","severity":"error","ruleName":"Force Try","location":{"line":14,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","character":43},"reason":"Force tries should be avoided","ruleIdentifier":"force_try"},"text":" private static let orderedListRegex = try! NSRegularExpression(pattern: \"^\\\\d+\\\\.\\\\s+\", options: [])"},{"violation":{"severity":"error","ruleDescription":"Force tries should be avoided","ruleName":"Force Try","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","character":48,"line":15},"ruleIdentifier":"force_try","reason":"Force tries should be avoided"},"text":" private static let orderedListSpaceRegex = try! NSRegularExpression(pattern: \"\\\\s+\", options: [])"},{"violation":{"ruleDescription":"Force tries should be avoided","severity":"error","ruleIdentifier":"force_try","location":{"character":44,"line":16,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift"},"ruleName":"Force Try","reason":"Force tries should be avoided"},"text":" private static let markdownLinkRegex = try! NSRegularExpression(pattern: #\"\\[([^\\]]+)\\]\\(([^)]+)\\)\"#, options: [])"},{"violation":{"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 161 characters","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":27,"character":1}},"text":" cleaned = jsonContentRegex.stringByReplacingMatches(in: cleaned, options: [], range: NSRange(location: 0, length: cleaned.utf16.count), withTemplate: \"\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 158 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":28,"character":1}},"text":" cleaned = jsonTextRegex.stringByReplacingMatches(in: cleaned, options: [], range: NSRange(location: 0, length: cleaned.utf16.count), withTemplate: \"\")"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","character":1,"line":29},"severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 160 characters","ruleDescription":"Lines should not span too many characters."},"text":" cleaned = jsonSuffixRegex.stringByReplacingMatches(in: cleaned, options: [], range: NSRange(location: 0, length: cleaned.utf16.count), withTemplate: \"\")"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":32},"reason":"Line should be 120 characters or less; currently it has 170 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" cleaned = multipleNewlinesRegex.stringByReplacingMatches(in: cleaned, options: [], range: NSRange(location: 0, length: cleaned.utf16.count), withTemplate: \"\\n\\n\")"},{"violation":{"location":{"character":12,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":37},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 56 lines","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","severity":"warning"},"text":" static func flattenMarkdown(_ text: String) -> String {"},{"text":" let headerMatches = headerRegex.matches(in: line, options: [], range: NSRange(location: 0, length: line.utf16.count))","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":57,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters","severity":"warning"}},{"text":" let bulletMatches = bulletRegex.matches(in: line, options: [], range: NSRange(location: 0, length: line.utf16.count))","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"line":75,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift"},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" let orderedMatches = orderedListRegex.matches(in: line, options: [], range: NSRange(location: 0, length: line.utf16.count))","violation":{"reason":"Line should be 120 characters or less; currently it has 135 characters","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"line":82,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift"}}},{"text":" let normalizedPrefix = orderedListSpaceRegex.stringByReplacingMatches(in: prefix, options: [], range: NSRange(location: 0, length: prefix.utf16.count), withTemplate: \" \")","violation":{"reason":"Line should be 120 characters or less; currently it has 186 characters","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"line":86,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift"}}},{"text":" let matches = markdownLinkRegex.matches(in: line, options: [], range: NSRange(location: 0, length: line.utf16.count))","violation":{"ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":114,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" static func attributedSummary(","violation":{"ruleDescription":"Function bodies should not span too many lines","location":{"character":12,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":143},"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":"warning"}},{"text":" for (_, rawLine) in lines.enumerated() {","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","character":14,"line":160},"ruleName":"Unused Enumerated","ruleDescription":"When the index or the item is not used, `.enumerated()` can be removed.","ruleIdentifier":"unused_enumerated","reason":"When the index is not used, `.enumerated()` can be removed","severity":"warning"}},{"text":" result.append(NSAttributedString(string: \"\\n\", attributes: [.font: baseFont, .foregroundColor: textColor]))","violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":164},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 127 characters","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"text":" let headerMatches = headerRegex.matches(in: trimmed, options: [], range: NSRange(location: 0, length: trimmed.utf16.count))","violation":{"location":{"line":173,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift"},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 135 characters","ruleIdentifier":"line_length","severity":"warning"}},{"text":" let headerText = (trimmed as NSString).substring(from: headerMatch.range.length).trimmingCharacters(in: .whitespaces)","violation":{"reason":"Line should be 120 characters or less; currently it has 133 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"character":1,"line":177,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift"}}},{"text":" let bulletMatches = bulletRegex.matches(in: line, options: [], range: NSRange(location: 0, length: line.utf16.count))","violation":{"ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 129 characters","location":{"line":197,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift"},"ruleDescription":"Lines should not span too many characters."}},{"text":" let orderedMatches = orderedListRegex.matches(in: line, options: [], range: NSRange(location: 0, length: line.utf16.count))","violation":{"ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":204,"character":1},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" let normalized = orderedListSpaceRegex.stringByReplacingMatches(in: prefix, options: [], range: NSRange(location: 0, length: prefix.utf16.count), withTemplate: \" \")","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":207},"reason":"Line should be 120 characters or less; currently it has 180 characters"}},{"text":" private static func parseInlineStyles(","violation":{"ruleIdentifier":"function_body_length","ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 55 lines","location":{"line":232,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","character":20}}},{"text":" private static func parseInlineStyles(","violation":{"ruleName":"Function Parameter Count","ruleDescription":"Number of function parameters should be low.","severity":"warning","reason":"Function should have 5 parameters or less: it currently has 6","location":{"line":232,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","character":20},"ruleIdentifier":"function_parameter_count"}},{"text":" var i = line.startIndex","violation":{"ruleName":"Identifier Name","ruleIdentifier":"identifier_name","severity":"error","reason":"Variable name 'i' should be between 3 and 40 characters long","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","character":13,"line":241},"ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short."}},{"text":" let s = String(line[runStart.. some View {","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 153 characters","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":417},"ruleName":"Line Length","ruleIdentifier":"line_length"}},{"text":" private func recordingsListView(_ filtered: [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)]) -> some View {","violation":{"ruleName":"Large Tuple","severity":"warning","reason":"Tuples should have at most 2 members","ruleIdentifier":"large_tuple","location":{"character":50,"line":417,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift"},"ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead."}},{"text":" private func summariesSectionedScroll(_ filtered: [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)]) -> some View {","violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"line":462,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 159 characters"}},{"text":" private func summariesSectionedScroll(_ filtered: [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)]) -> some View {","violation":{"ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":462,"character":56},"reason":"Tuples should have at most 2 members","severity":"warning","ruleName":"Large Tuple","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead."}},{"text":" recordingRowView((recording: itemWithDate.recording, transcript: itemWithDate.transcript, summary: itemWithDate.summary))","violation":{"ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","character":1,"line":497},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 149 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"text":" recordingRowView((recording: itemWithDate.recording, transcript: itemWithDate.transcript, summary: itemWithDate.summary))","violation":{"severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","character":1,"line":556},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 153 characters"}},{"text":" Button(action: { showDateFilter = true }) {","violation":{"reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","location":{"character":59,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":572},"severity":"warning"}},{"violation":{"reason":"Line should be 120 characters or less; currently it has 138 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","character":1,"line":573}},"text":" Image(systemName: isDateFilterActive ? \"line.3.horizontal.decrease.circle.fill\" : \"line.3.horizontal.decrease.circle\")"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 154 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"line":603,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","character":1},"ruleIdentifier":"line_length"},"text":" private func recordingRowView(_ recordingData: (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)) -> some View {"},{"violation":{"ruleName":"Function Body Length","location":{"line":603,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift"},"ruleIdentifier":"function_body_length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 60 lines","severity":"warning","ruleDescription":"Function bodies should not span too many lines"},"text":" private func recordingRowView(_ recordingData: (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)) -> some View {"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":603,"character":52},"severity":"warning","reason":"Tuples should have at most 2 members","ruleName":"Large Tuple","ruleIdentifier":"large_tuple","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead."},"text":" private func recordingRowView(_ recordingData: (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)) -> some View {"},{"violation":{"ruleIdentifier":"multiple_closures_with_trailing_closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","character":16,"line":721},"severity":"warning","reason":"Trailing closure syntax should not be used when passing more than one closure argument"},"text":" }) {"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 156 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":732},"ruleIdentifier":"line_length","severity":"warning"},"text":" } else if recording.summaryStatus == ProcessingStatus.processing.rawValue || (isGeneratingSummary && generatingSummaryRecordingId == recording.id) {"},{"violation":{"location":{"line":752,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","character":16},"reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","severity":"warning"},"text":" }) {"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 127 characters","ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"line":914,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","character":1},"ruleName":"Line Length"},"text":" private var filteredRecordings: [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)] {"},{"violation":{"reason":"Tuples should have at most 2 members","ruleIdentifier":"large_tuple","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":914,"character":38},"ruleName":"Large Tuple"},"text":" private var filteredRecordings: [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)] {"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":920,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"},"text":" let endOfDay = Calendar.current.date(bySettingHour: 23, minute: 59, second: 59, of: dateFilterEnd) ?? dateFilterEnd"},{"violation":{"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","character":1,"line":940},"reason":"Line should be 120 characters or less; currently it has 167 characters"},"text":" private func matchesSearch(_ recordingData: (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?), searchTerms: String) -> Bool {"},{"violation":{"ruleIdentifier":"large_tuple","reason":"Tuples should have at most 2 members","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":940,"character":49},"ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleName":"Large Tuple","severity":"warning"},"text":" private func matchesSearch(_ recordingData: (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?), searchTerms: String) -> Bool {"},{"violation":{"ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 123 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":988,"character":1},"ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.summarization(\"Schema-safe fetch failed, trying standard fetch: \\(error)\", level: .error)"},{"violation":{"severity":"error","location":{"character":1,"line":1063,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift"},"reason":"File should contain 1000 lines or less: currently contains 1063","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","ruleName":"File Length"},"text":"}"},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":30},"ruleDescription":"Type bodies should not span too many lines","reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 1470 lines","ruleIdentifier":"type_body_length","severity":"error","ruleName":"Type Body Length"},"text":"struct SummaryDetailView: View {"},{"violation":{"ruleName":"Line Length","location":{"character":1,"line":162,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift"},"severity":"error","reason":"Line should be 200 characters or less; currently it has 238 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"},"text":" AppLog.shared.summarization(\"SummaryDetailView opened: summary=\\(summaryData.summary.count) chars, tasks=\\(summaryData.tasks.count), reminders=\\(summaryData.reminders.count), titles=\\(summaryData.titles.count)\", level: .debug)"},{"violation":{"ruleName":"Line Length","location":{"line":167,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift"},"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 125 characters","ruleIdentifier":"line_length"},"text":" AppLog.shared.summarization(\"SummaryDetailView: hasLocationData=\\(recording.locationData != nil)\", level: .debug)"},{"violation":{"ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":215,"character":1},"reason":"Line should be 120 characters or less; currently it has 199 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning"},"text":" Text(\"Are you sure you want to delete this summary? Any notes and attached files will also be deleted. This action cannot be undone. The audio file and transcript will remain unchanged.\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":234,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters","ruleIdentifier":"line_length"},"text":" activityItems: [ExportActivityItem(data: exportData, fileName: fileName, iconSystemName: exportIconSystemName)],"},{"violation":{"severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 121 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":259},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."},"text":" .confirmationDialog(\"Choose Export Format\", isPresented: $showingExportFormatPicker, titleVisibility: .visible) {"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":386},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 123 characters","ruleName":"Line Length"},"text":" let safeLongitude = locationData.longitude.isFinite && !locationData.longitude.isNaN ? locationData.longitude : 0.0"},{"violation":{"severity":"warning","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"character":28,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":471},"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","reason":"Trailing closure syntax should not be used when passing more than one closure argument"},"text":" }) {"},{"violation":{"ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"line":482,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","character":28},"severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","reason":"Trailing closure syntax should not be used when passing more than one closure argument"},"text":" }) {"},{"violation":{"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"line":517,"character":24,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift"},"reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","severity":"warning"},"text":" }) {"},{"violation":{"location":{"line":633,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","character":1},"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 129 characters"},"text":" metadataRow(title: \"Generation Time\", value: formatDate(summaryData.generatedAt), icon: \"clock.arrow.circlepath\")"},{"violation":{"location":{"line":636,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift"},"ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 125 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" metadataRow(title: \"Compression Ratio\", value: summaryData.formattedCompressionRatio, icon: \"chart.bar.fill\")"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","character":1,"line":638},"reason":"Line should be 120 characters or less; currently it has 128 characters","ruleDescription":"Lines should not span too many characters."},"text":" metadataRow(title: \"Processing Time\", value: formattedProcessingTime(summaryData.processingTime), icon: \"timer\")"},{"violation":{"location":{"line":677,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift"},"reason":"Line should be 120 characters or less; currently it has 138 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning"},"text":" AITextView(text: summaryData.summary, aiService: AIService.from(aiEngine: summaryData.aiEngine, aiModel: summaryData.aiModel))"},{"violation":{"ruleIdentifier":"multiple_closures_with_trailing_closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":769,"character":20},"ruleName":"Multiple Closures with Trailing Closure","reason":"Trailing closure syntax should not be used when passing more than one closure argument"},"text":" }) {"},{"violation":{"ruleIdentifier":"multiple_closures_with_trailing_closure","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","severity":"warning","location":{"line":984,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","character":20}},"text":" }) {"},{"violation":{"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","severity":"warning","location":{"line":1041,"character":20,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift"},"ruleIdentifier":"multiple_closures_with_trailing_closure"},"text":" }) {"},{"violation":{"ruleIdentifier":"multiple_closures_with_trailing_closure","severity":"warning","location":{"character":28,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":1111},"reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure"},"text":" }) {"},{"violation":{"reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"line":1143,"character":28,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift"},"severity":"warning","ruleName":"Multiple Closures with Trailing Closure"},"text":" }) {"},{"violation":{"severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"line":1189,"character":20,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift"},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"},"text":" }) {"},{"violation":{"severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"line":1235,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift"},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 129 characters"},"text":" AppLog.shared.summarization(\"Deleted empty anchor recording entry after summary deletion\", level: .debug)"},{"violation":{"location":{"character":1,"line":1246,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift"},"reason":"Line should be 120 characters or less; currently it has 139 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length"},"text":" AppLog.shared.summarization(\"Recording no longer exists (orphaned summary) - skipping recording update\", level: .debug)"},{"text":" AppLog.shared.summarization(\"Refreshing summary from Core Data, new length: \\(latestSummary.summary.count) chars, new model: \\(latestSummary.aiModel)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 178 characters","location":{"line":1279,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift"},"ruleIdentifier":"line_length"}},{"text":" \/\/ TODO: Implement custom date detection once Core Data field is added","violation":{"ruleDescription":"TODOs and FIXMEs should be resolved.","severity":"warning","reason":"TODOs should be resolved (Implement custom date detectio...)","ruleName":"Todo","ruleIdentifier":"todo","location":{"line":1357,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","character":8}}},{"text":" private func updateRecordingName(to newName: String) {","violation":{"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 56 lines","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","location":{"line":1365,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift"}}},{"text":" private func updateRecordingDateTime(to newDateTime: Date) {","violation":{"ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length","severity":"warning","location":{"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":1435},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 52 lines"}},{"text":" throw NSError(domain: \"CoreDataManager\", code: 404, userInfo: [NSLocalizedDescriptionKey: \"Recording not found\"])","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 125 characters","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"line":1502,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift"},"ruleDescription":"Lines should not span too many characters."}},{"text":" throw NSError(domain: \"CoreDataManager\", code: 404, userInfo: [NSLocalizedDescriptionKey: \"Recording not found\"])","violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":1553,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"text":" let normalizedNotes = userNotes?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == true ? nil : userNotes","violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"character":1,"line":1670,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift"},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" AppLog.shared.summarization(\"\\(format.displayName) generated successfully, size: \\(exportData.count) bytes\")","violation":{"reason":"Line should be 120 characters or less; currently it has 124 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"line":1730,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift"},"ruleIdentifier":"line_length","severity":"warning"}},{"text":" exportFileName = sanitizeFileName(\"\\(summaryData.recordingName)_Summary\", fileExtension: format.fileExtension)","violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 126 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":1733,"character":1},"severity":"warning"}},{"text":" }) {","violation":{"ruleIdentifier":"multiple_closures_with_trailing_closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","character":24,"line":1814},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":1964,"character":24},"ruleIdentifier":"multiple_closures_with_trailing_closure","severity":"warning","reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" let success = await integrationManager.addReminderToReminders(reminder, recordingName: recordingName)","violation":{"ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":1996,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"violation":{"ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2008,"character":1},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 124 characters","ruleIdentifier":"line_length","severity":"warning"},"text":" let success = await integrationManager.addReminderToCalendar(reminder, recordingName: recordingName)"},{"violation":{"severity":"warning","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","ruleName":"Multiple Closures with Trailing Closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","character":16,"line":2063}},"text":" }) {"},{"violation":{"reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","severity":"warning","ruleName":"Multiple Closures with Trailing Closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","character":16,"line":2108}},"text":" }) {"},{"violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 129 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2172},"ruleName":"Line Length"},"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))"},{"violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 141 characters","ruleName":"Line Length","severity":"warning","location":{"character":1,"line":2202,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift"},"ruleIdentifier":"line_length"},"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))"},{"violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2234,"character":1},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 122 characters","ruleIdentifier":"line_length","ruleName":"Line Length"},"text":" .disabled(customTitleText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty)"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2241,"character":36},"ruleName":"Multiple Closures with Trailing Closure","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument"},"text":" }) {"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 137 characters","location":{"line":2253,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift"},"ruleDescription":"Lines should not span too many characters."},"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 129 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2370}},"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))"},{"violation":{"location":{"line":2396,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift"},"reason":"Line should be 120 characters or less; currently it has 137 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning"},"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","character":1,"line":2418},"reason":"Line should be 120 characters or less; currently it has 137 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"},"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))"},{"violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2439},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 137 characters","ruleName":"Line Length"},"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))"},{"text":" }) {","violation":{"severity":"warning","ruleIdentifier":"multiple_closures_with_trailing_closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","location":{"character":32,"line":2446,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift"},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","ruleIdentifier":"multiple_closures_with_trailing_closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","location":{"line":2464,"character":32,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift"},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":"struct LocationPickerView: View {","violation":{"ruleIdentifier":"type_body_length","reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 427 lines","ruleName":"Type Body Length","ruleDescription":"Type bodies should not span too many lines","severity":"error","location":{"line":2518,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift"}}},{"text":" }) {","violation":{"ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","character":32,"line":2564},"reason":"Trailing closure syntax should not be used when passing more than one closure argument","severity":"warning","ruleName":"Multiple Closures with Trailing Closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 137 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2586},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"line":2659,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift"},"reason":"Line should be 120 characters or less; currently it has 137 characters","ruleDescription":"Lines should not span too many characters."}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","ruleIdentifier":"multiple_closures_with_trailing_closure","reason":"Trailing closure syntax should not be used when passing more than one closure argument","location":{"character":36,"line":2713,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift"},"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","severity":"warning"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"reason":"Line should be 120 characters or less; currently it has 137 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","location":{"line":2725,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift"}}},{"text":" }) {","violation":{"reason":"Trailing closure syntax should not be used when passing more than one closure argument","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","character":12,"line":3037},"ruleIdentifier":"multiple_closures_with_trailing_closure"}},{"text":" let snapshot: MKMapSnapshotter.Snapshot = try await withCheckedThrowingContinuation { (continuation: CheckedContinuation) in","violation":{"ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 166 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":3119,"character":1},"ruleDescription":"Lines should not span too many characters."}},{"text":" private func loadSnapshot(for key: String) async {","violation":{"ruleIdentifier":"function_body_length","ruleName":"Function Body Length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 71 lines","severity":"warning","ruleDescription":"Function bodies should not span too many lines","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":3306,"character":13}}},{"text":" func activityViewController(_ controller: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {","violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":3498,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift"},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 146 characters","ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":3505,"character":1}},"text":" func activityViewController(_ controller: UIActivityViewController, subjectForActivityType activityType: UIActivity.ActivityType?) -> String {"},{"violation":{"severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":3558},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 133 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))"},{"violation":{"ruleName":"File Length","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":3593,"character":1},"reason":"File should contain 1000 lines or less: currently contains 3593"},"text":"}"},{"violation":{"ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","ruleName":"Type Body Length","reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 1494 lines","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":41,"character":1}},"text":"class SummaryManager: ObservableObject {"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 125 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"line":89,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":1},"severity":"warning"},"text":" AppLog.shared.summarization(\"Loaded \\(legacySummaries.count) legacy summaries from UserDefaults during init\")"},{"violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":1,"line":99},"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 139 characters","ruleName":"Line Length"},"text":" @available(*, deprecated, message: \"Use AppDataCoordinator.addSummary() for Core Data persistence. This method only updates UI state.\")"},{"violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":114,"character":1},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 134 characters"},"text":" AppLog.shared.summarization(\"Enhanced summary saved. Total summaries: \\(self.enhancedSummaries.count)\", level: .debug)"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":133},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 129 characters","severity":"warning"},"text":" AppLog.shared.summarization(\"Can find summary: \\(self.hasSummary(for: summary.recordingURL))\", level: .debug)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 131 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":157,"character":1}},"text":" AppLog.shared.summarization(\"Looking for enhanced summary with file: \\(recordingURL.lastPathComponent)\", level: .debug)"},{"violation":{"ruleName":"Line Length","location":{"line":216,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift"},"severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 126 characters","ruleIdentifier":"line_length"},"text":" AppLog.shared.summarization(\"hasEnhancedSummary for \\(recordingURL.lastPathComponent) = \\(result)\", level: .debug)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 169 characters","severity":"warning","ruleName":"Line Length","location":{"character":1,"line":272,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift"},"ruleIdentifier":"line_length"},"text":" let error = AppError.system(.configurationError(message: \"The selected AI engine is not supported on this device. Please select another AI engine in Settings.\"))"},{"violation":{"ruleName":"Cyclomatic Complexity","reason":"Function should have complexity 10 or less; currently complexity is 14","severity":"warning","location":{"line":278,"character":5,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift"},"ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity"},"text":" func initializeEngines() {"},{"text":" func initializeEngines() {","violation":{"severity":"warning","location":{"character":5,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":278},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 61 lines","ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length"}},{"text":" AppLog.shared.summarization(\"Successfully initialized \\(engine.name) (Available: \\(engine.isAvailable))\", level: .debug)","violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 136 characters","ruleName":"Line Length","location":{"line":305,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":1},"severity":"warning","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.summarization(\"Engine initialization complete - \\(successfullyInitialized)\/\\(allEngineTypes.count) engines initialized\")","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":313,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift"},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 142 characters","ruleName":"Line Length"}},{"text":" AppLog.shared.summarization(\"Saved engine '\\(savedEngineName)' not available, using '\\(availableEngine.name)' temporarily\", level: .default)","violation":{"ruleName":"Line Length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":337},"reason":"Line should be 120 characters or less; currently it has 156 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"}},{"text":" if let anyAvailableEngine = availableEngines.values.first(where: { $0.isAvailable && $0.name != \"None\" }) {","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 123 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":347}}},{"text":" AppLog.shared.summarization(\"On-Device AI not available, using '\\(anyAvailableEngine.name)' as default\")","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":350},"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" AppLog.shared.summarization(\"No available engines found, attempting to find any available engine\", level: .default)","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":362,"character":1},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 131 characters","severity":"warning","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.summarization(\"Engine details: \\(engine.description) (Available: \\(engine.isAvailable))\", level: .debug)","violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":433,"character":1},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 134 characters","ruleIdentifier":"line_length"}},{"text":" AppLog.shared.summarization(\"Engine configuration updated for '\\(engineName)' (Available: \\(updatedEngine.isAvailable))\")","violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":1,"line":457},"reason":"Line should be 120 characters or less; currently it has 129 characters","ruleIdentifier":"line_length"}},{"text":" func validateEngineAvailability(_ engineName: String) -> (isValid: Bool, isAvailable: Bool, errorMessage: String?) {","violation":{"ruleName":"Large Tuple","severity":"warning","ruleIdentifier":"large_tuple","reason":"Tuples should have at most 2 members","location":{"line":466,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":62},"ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead."}},{"text":" func getEngineTypeInfo(for engineType: AIEngineType) -> (description: String, requirements: [String], isComingSoon: Bool) {","violation":{"severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":547},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" func getEngineTypeInfo(for engineType: AIEngineType) -> (description: String, requirements: [String], isComingSoon: Bool) {","violation":{"severity":"warning","reason":"Tuples should have at most 2 members","ruleName":"Large Tuple","ruleIdentifier":"large_tuple","location":{"line":547,"character":61,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift"},"ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead."}},{"violation":{"ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"line":569,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift"},"reason":"Line should be 120 characters or less; currently it has 139 characters"},"text":" \/\/ Don't overwrite the user's saved preference - they may want to use their selected engine when it becomes available again"},{"violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":578},"reason":"Line should be 120 characters or less; currently it has 123 characters","ruleName":"Line Length"},"text":" let selectedEngineName = UserDefaults.standard.string(forKey: \"SelectedAIEngine\") ?? AIEngineType.mlxSwift.rawValue"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"character":1,"line":584,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift"},"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 124 characters"},"text":" AppLog.shared.summarization(\"Synced current engine to '\\(selectedEngineName)' from settings\", level: .debug)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 141 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":586,"character":1}},"text":" AppLog.shared.summarization(\"Selected engine '\\(selectedEngineName)' not available, keeping current engine\", level: .default)"},{"violation":{"ruleName":"Large Tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":51,"line":591},"ruleIdentifier":"large_tuple","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","severity":"warning","reason":"Tuples should have at most 2 members"},"text":" func getEngineInfo(for engineName: String) -> (description: String, isAvailable: Bool, version: String)? {"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":1,"line":752},"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 125 characters","ruleName":"Line Length","ruleIdentifier":"line_length"},"text":" AppLog.shared.summarization(\"Current engine '\\(currentEngine.name)' is no longer available\", level: .default)"},{"violation":{"severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 121 characters","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":866},"ruleIdentifier":"line_length"},"text":" AppLog.shared.summarization(\"Current engine '\\(currentEngine.name)' is no longer available\", level: .default)"},{"violation":{"location":{"line":941,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":1},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 149 characters"},"text":" AppLog.shared.summarization(\"Available: \\(availableCount), Unavailable: \\(unavailableCount), Coming Soon: \\(comingSoonCount)\", level: .debug)"},{"violation":{"location":{"line":948,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift"},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"error","ruleIdentifier":"line_length","reason":"Line should be 200 characters or less; currently it has 223 characters"},"text":" func generateEnhancedSummary(from text: String, for recordingURL: URL, recordingName: String, recordingDate: Date, coordinator: AppDataCoordinator? = nil, engineName: String? = nil) async throws -> EnhancedSummaryData {"},{"violation":{"ruleDescription":"Complexity of function bodies should be limited.","severity":"error","location":{"line":948,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":5},"ruleName":"Cyclomatic Complexity","ruleIdentifier":"cyclomatic_complexity","reason":"Function should have complexity 10 or less; currently complexity is 21"},"text":" func generateEnhancedSummary(from text: String, for recordingURL: URL, recordingName: String, recordingDate: Date, coordinator: AppDataCoordinator? = nil, engineName: String? = nil) async throws -> EnhancedSummaryData {"},{"violation":{"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 155 lines","ruleIdentifier":"function_body_length","severity":"error","ruleDescription":"Function bodies should not span too many lines","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":948,"character":5},"ruleName":"Function Body Length"},"text":" func generateEnhancedSummary(from text: String, for recordingURL: URL, recordingName: String, recordingDate: Date, coordinator: AppDataCoordinator? = nil, engineName: String? = nil) async throws -> EnhancedSummaryData {"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":1,"line":961},"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 126 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"},"text":" AppLog.shared.summarization(\"Transcript has 50 words or less (\\(words.count) words) - returning transcript as-is\")"},{"text":" if let index = self.enhancedSummaries.firstIndex(where: { $0.recordingURL == shortTranscriptSummary.recordingURL }) {","violation":{"ruleDescription":"Lines should not span too many characters.","location":{"line":981,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift"},"reason":"Line should be 120 characters or less; currently it has 133 characters","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length"}},{"text":" return try await generateBasicSummary(from: text, for: recordingURL, recordingName: recordingName, recordingDate: recordingDate, coordinator: coordinator)","violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 166 characters","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"line":1021,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":1}}},{"text":" var result: (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)","violation":{"ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1026,"character":1},"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" var result: (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)","violation":{"location":{"line":1026,"character":21,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift"},"ruleName":"Large Tuple","reason":"Tuples should have at most 2 members","ruleIdentifier":"large_tuple","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","severity":"error"}},{"text":" throw SummarizationError.processingFailed(reason: \"Ollama returned text that couldn't be parsed. Please check your Ollama model configuration or try a different model.\")","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"line":1068,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift"},"reason":"Line should be 120 characters or less; currently it has 193 characters"}},{"text":" } else if error.localizedDescription.contains(\"connection\") || error.localizedDescription.contains(\"server\") {","violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 130 characters","location":{"line":1069,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":1},"severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length"}},{"text":" let finalRecordingName = intelligentName.isEmpty || intelligentName == \"Recording\" ? recordingName : intelligentName","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 124 characters","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1098,"character":1}}},{"text":" handleError(SummarizationError.processingFailed(reason: \"Summary quality below threshold\"), context: \"Summary Quality\", recordingName: recordingName)","violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"line":1119,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":1},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 161 characters","ruleName":"Line Length"}},{"text":" if let index = self.enhancedSummaries.firstIndex(where: { $0.recordingURL == enhancedSummary.recordingURL }) {","violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 122 characters","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"character":1,"line":1125,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift"},"severity":"warning"}},{"text":" AppLog.shared.summarization(\"Background task started - unlimited time (foreground or audio session active)\", level: .debug)","violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 139 characters","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1174},"ruleDescription":"Lines should not span too many characters."}},{"text":" private func generateBasicSummary(from text: String, for recordingURL: URL, recordingName: String, recordingDate: Date, coordinator: AppDataCoordinator?) async throws -> EnhancedSummaryData {","violation":{"severity":"warning","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1188},"reason":"Line should be 120 characters or less; currently it has 195 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":" private func generateBasicSummary(from text: String, for recordingURL: URL, recordingName: String, recordingDate: Date, coordinator: AppDataCoordinator?) async throws -> EnhancedSummaryData {","violation":{"ruleName":"Function Body Length","ruleIdentifier":"function_body_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":13,"line":1188},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 97 lines","ruleDescription":"Function bodies should not span too many lines"}},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 126 characters","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1199,"character":1}},"text":" AppLog.shared.summarization(\"Transcript has 50 words or less (\\(words.count) words) - returning transcript as-is\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 133 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1219,"character":1},"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning"},"text":" if let index = self.enhancedSummaries.firstIndex(where: { $0.recordingURL == shortTranscriptSummary.recordingURL }) {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1260,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters","ruleIdentifier":"line_length","severity":"warning"},"text":" let finalRecordingName = intelligentName.isEmpty || intelligentName == \"Recording\" ? recordingName : intelligentName"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":1,"line":1280},"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 173 characters","ruleDescription":"Lines should not span too many characters."},"text":" handleError(SummarizationError.processingFailed(reason: \"Basic summary quality below threshold\"), context: \"Basic Summary Quality\", recordingName: recordingName)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 122 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":1,"line":1286},"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters."},"text":" if let index = self.enhancedSummaries.firstIndex(where: { $0.recordingURL == enhancedSummary.recordingURL }) {"},{"violation":{"ruleDescription":"Complexity of function bodies should be limited.","ruleName":"Cyclomatic Complexity","reason":"Function should have complexity 10 or less; currently complexity is 16","ruleIdentifier":"cyclomatic_complexity","location":{"line":1319,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":13},"severity":"warning"},"text":" private func createBasicSummary(from text: String, contentType: ContentType) -> String {"},{"violation":{"ruleIdentifier":"function_body_length","ruleName":"Function Body Length","ruleDescription":"Function bodies should not span too many lines","location":{"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1319},"severity":"warning","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 55 lines"},"text":" private func createBasicSummary(from text: String, contentType: ContentType) -> String {"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1320,"character":1},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 122 characters"},"text":" AppLog.shared.summarization(\"Creating content-type optimized summary for: \\(contentType.rawValue)\", level: .debug)"},{"violation":{"severity":"warning","ruleIdentifier":"unused_enumerated","ruleName":"Unused Enumerated","location":{"character":60,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1330},"reason":"When the index is not used, `.enumerated()` can be removed","ruleDescription":"When the index or the item is not used, `.enumerated()` can be removed."},"text":" let scoredSentences = sentences.enumerated().map { _, sentence in"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 138 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1337},"severity":"warning"},"text":" let meetingKeywords = [\"decision\", \"action item\", \"follow up\", \"next step\", \"agreed\", \"consensus\", \"deadline\", \"schedule\"]"},{"violation":{"severity":"warning","reason":"`where` clauses are preferred over a single `if` inside a `for`","location":{"line":1339,"character":21,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift"},"ruleIdentifier":"for_where","ruleName":"Prefer For-Where","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`"},"text":" if sentence.lowercased().contains(keyword) {"},{"violation":{"ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1344,"character":1},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 135 characters","severity":"warning","ruleDescription":"Lines should not span too many characters."},"text":" let reflectionKeywords = [\"i feel\", \"i think\", \"i learned\", \"i realized\", \"i discovered\", \"my experience\", \"i believe\"]"},{"text":" if sentence.lowercased().contains(keyword) {","violation":{"ruleName":"Prefer For-Where","ruleIdentifier":"for_where","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1346,"character":21},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" let technicalKeywords = [\"algorithm\", \"function\", \"method\", \"solution\", \"implementation\", \"architecture\", \"system\", \"code\"]","violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1351,"character":1},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" if sentence.lowercased().contains(keyword) {","violation":{"ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","reason":"`where` clauses are preferred over a single `if` inside a `for`","location":{"line":1353,"character":21,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift"},"severity":"warning","ruleIdentifier":"for_where","ruleName":"Prefer For-Where"}},{"text":" AppLog.shared.summarization(\"Content-type optimized summary created: \\(summary.count) characters\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 121 characters","ruleName":"Line Length","location":{"character":1,"line":1391,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift"},"ruleIdentifier":"line_length"}},{"text":" AppLog.shared.summarization(\"AI engine task extraction failed, using fallback extractor\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1416},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" AppLog.shared.summarization(\"AI engine reminder extraction failed, using fallback extractor\", level: .debug)","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1449},"severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" func extractTasksAndRemindersFromText(_ text: String) async throws -> (tasks: [TaskItem], reminders: [ReminderItem]) {","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 122 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1484,"character":1},"ruleDescription":"Lines should not span too many characters.","severity":"warning"}},{"text":" AppLog.shared.summarization(\"Extracted \\(taskResults.count) tasks and \\(reminderResults.count) reminders\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 129 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1492,"character":1}}},{"text":" func extractTasksRemindersAndTitlesFromText(_ text: String) async throws -> (tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) {","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","location":{"line":1496,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift"},"reason":"Line should be 120 characters or less; currently it has 149 characters"}},{"text":" func extractTasksRemindersAndTitlesFromText(_ text: String) async throws -> (tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) {","violation":{"ruleName":"Large Tuple","location":{"line":1496,"character":81,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift"},"reason":"Tuples should have at most 2 members","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","severity":"warning"}},{"text":" AppLog.shared.summarization(\"Extracted \\(taskResults.count) tasks, \\(reminderResults.count) reminders, and \\(titleResults.count) titles\", level: .debug)","violation":{"severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"line":1505,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 160 characters"}},{"text":" AppLog.shared.summarization(\"Generating content-type optimized summary for \\(contentType.rawValue)\", level: .debug)","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":1512,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift"},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" let scoredSentences = sentences.enumerated().map { _, sentence in","violation":{"ruleName":"Unused Enumerated","severity":"warning","reason":"When the index is not used, `.enumerated()` can be removed","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":60,"line":1532},"ruleDescription":"When the index or the item is not used, `.enumerated()` can be removed.","ruleIdentifier":"unused_enumerated"}},{"text":" let meetingKeywords = [\"decision\", \"action item\", \"follow up\", \"next step\", \"agreed\", \"consensus\", \"deadline\", \"schedule\"]","violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1536},"severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 134 characters","ruleName":"Line Length"}},{"text":" if sentence.lowercased().contains(keyword) {","violation":{"reason":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","ruleName":"Prefer For-Where","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","severity":"warning","location":{"line":1540,"character":17,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift"}}},{"text":" let scoredSentences = sentences.enumerated().map { _, sentence in","violation":{"severity":"warning","ruleDescription":"When the index or the item is not used, `.enumerated()` can be removed.","reason":"When the index is not used, `.enumerated()` can be removed","ruleName":"Unused Enumerated","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1566,"character":60},"ruleIdentifier":"unused_enumerated"}},{"text":" let reflectionKeywords = [\"i feel\", \"i think\", \"i learned\", \"i realized\", \"i discovered\", \"my experience\", \"i believe\"]","violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1570},"reason":"Line should be 120 characters or less; currently it has 131 characters","ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning"}},{"text":" if sentence.lowercased().contains(keyword) {","violation":{"ruleIdentifier":"for_where","location":{"character":17,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1574},"severity":"warning","reason":"`where` clauses are preferred over a single `if` inside a `for`","ruleName":"Prefer For-Where","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" let scoredSentences = sentences.enumerated().map { _, sentence in","violation":{"reason":"When the index is not used, `.enumerated()` can be removed","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":60,"line":1600},"ruleDescription":"When the index or the item is not used, `.enumerated()` can be removed.","ruleIdentifier":"unused_enumerated","ruleName":"Unused Enumerated","severity":"warning"}},{"text":" let technicalKeywords = [\"algorithm\", \"function\", \"method\", \"solution\", \"implementation\", \"architecture\", \"system\", \"code\", \"debug\", \"test\"]","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":1,"line":1604},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 152 characters","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters."}},{"text":" if sentence.lowercased().contains(keyword) {","violation":{"ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":17,"line":1608},"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" let scoredSentences = sentences.enumerated().map { _, sentence in","violation":{"ruleName":"Unused Enumerated","ruleIdentifier":"unused_enumerated","severity":"warning","location":{"line":1634,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":60},"reason":"When the index is not used, `.enumerated()` can be removed","ruleDescription":"When the index or the item is not used, `.enumerated()` can be removed."}},{"text":" _ = try await generateEnhancedSummary(from: transcriptText, for: url, recordingName: name, recordingDate: date)","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"line":1661,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":1},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" AppLog.shared.summarization(\"Chunk \\(index + 1) failed: \\(error.localizedDescription)\", level: .error)","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":1802,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters","ruleIdentifier":"line_length","ruleName":"Line Length"}},{"violation":{"location":{"line":1819,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":1},"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 130 characters"},"text":" originalLength: transcript.fullText.components(separatedBy: .whitespacesAndNewlines).filter { !$0.isEmpty }.count,"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"character":1,"line":1824,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift"},"reason":"Line should be 120 characters or less; currently it has 125 characters"},"text":" if let index = enhancedSummaries.firstIndex(where: { $0.recordingURL == combinedEnhancedSummary.recordingURL }) {"},{"violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 164 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1854,"character":1}},"text":" SummarizationError.networkError(underlying: NSError(domain: \"NetworkError\", code: 0, userInfo: [NSLocalizedDescriptionKey: \"Network unavailable\"])),"},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1886},"reason":"Line should be 200 characters or less; currently it has 326 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"error","ruleName":"Line Length"},"text":" summary: \"## Manual Summary Required\\n\\nThis recording requires manual summarization due to processing errors.\\n\\n**Recording:** \\(recordingName)\\n**Date:** \\(DateFormatter.localizedString(from: Date(), dateStyle: .medium, timeStyle: .short))\\n\\nPlease create a summary manually using the app's editing features.\","},{"violation":{"ruleName":"Line Length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1922},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 165 characters","ruleDescription":"Lines should not span too many characters."},"text":" func generateIntelligentRecordingName(from text: String, contentType: ContentType, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) -> String {"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"line":1941,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift"},"reason":"Line should be 200 characters or less; currently it has 237 characters","severity":"error"},"text":" func updateRecordingNameWithAI(from oldName: String, recordingURL: URL, transcript: String, contentType: ContentType, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], coordinator: AppDataCoordinator?) async throws {"},{"violation":{"reason":"Function should have 5 parameters or less: it currently has 8","ruleIdentifier":"function_parameter_count","location":{"line":1941,"character":5,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift"},"ruleDescription":"Number of function parameters should be low.","ruleName":"Function Parameter Count","severity":"warning"},"text":" func updateRecordingNameWithAI(from oldName: String, recordingURL: URL, transcript: String, contentType: ContentType, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], coordinator: AppDataCoordinator?) async throws {"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1945,"character":1},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 150 characters"},"text":" let newName = generateIntelligentRecordingName(from: transcript, contentType: contentType, tasks: tasks, reminders: reminders, titles: titles)"},{"violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 127 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":1,"line":1951},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"},"text":" try await updateRecordingName(from: oldName, to: newName, recordingURL: recordingURL, coordinator: coordinator)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 126 characters","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1980,"character":1},"ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length"},"text":" AppLog.shared.summarization(\"Keeping original name '\\(oldName)' (no meaningful improvement found)\", level: .debug)"},{"violation":{"severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1984},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 145 characters"},"text":" private func updateRecordingName(from oldName: String, to newName: String, recordingURL: URL, coordinator: AppDataCoordinator) async throws {"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1990,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"},"text":" AppLog.shared.summarization(\"Could not find recording in Core Data for file: \\(recordingURL.lastPathComponent)\", level: .error)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 143 characters","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":2084,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift"}},"text":" let averageConfidence = enhancedSummaries.isEmpty ? 0.0 : enhancedSummaries.map { $0.confidence }.reduce(0, +) \/ Double(totalSummaries)"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":2085,"character":1},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 155 characters"},"text":" let averageCompressionRatio = enhancedSummaries.isEmpty ? 0.0 : enhancedSummaries.map { $0.compressionRatio }.reduce(0, +) \/ Double(totalSummaries)"},{"violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 136 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":2109,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","character":1}},"text":" AppLog.shared.summarization(\"saveEnhancedSummariesToDisk() called - this is deprecated, use Core Data instead\", level: .default)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 157 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":2122,"character":1}},"text":" AppLog.shared.summarization(\"Found \\(legacySummaries.count) legacy summaries in UserDefaults - consider migrating to Core Data\", level: .default)"},{"violation":{"reason":"File should contain 1000 lines or less: currently contains 2127","severity":"error","ruleIdentifier":"file_length","ruleDescription":"Files should not span too many lines.","ruleName":"File Length","location":{"character":1,"line":2127,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift"}},"text":"}"},{"violation":{"severity":"warning","location":{"line":38,"character":5,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryRegenerationManager.swift"},"ruleName":"Function Body Length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 76 lines","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length"},"text":" func regenerateAllSummaries() async {"},{"violation":{"severity":"warning","location":{"line":84,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryRegenerationManager.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 164 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length"},"text":" AppLog.shared.summarization(\"Bulk regeneration name check: nameChanged=\\(newEnhancedSummary.recordingName != summary.recordingName)\", level: .debug)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 155 characters","ruleIdentifier":"line_length","location":{"character":1,"line":167,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryRegenerationManager.swift"}},"text":" AppLog.shared.summarization(\"Regeneration name check: nameChanged=\\(newEnhancedSummary.recordingName != summary.recordingName)\", level: .debug)"},{"violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryRegenerationManager.swift","line":205,"character":1},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 146 characters","ruleIdentifier":"line_length","ruleName":"Line Length"},"text":" AppLog.shared.summarization(\"Failed to regenerate summary for recording \\(recordingId): \\(error.localizedDescription)\", level: .error)"},{"violation":{"severity":"warning","ruleIdentifier":"type_body_length","ruleDescription":"Type bodies should not span too many lines","ruleName":"Type Body Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SystemIntegrationManager.swift","line":16,"character":1},"reason":"Class body should span 250 lines or less excluding comments and whitespace: currently spans 292 lines"},"text":"class SystemIntegrationManager: NSObject, ObservableObject {"},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SystemIntegrationManager.swift","line":98},"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 126 characters","severity":"warning"},"text":" reminder.dueDateComponents = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute], from: dueDate)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 128 characters","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SystemIntegrationManager.swift","line":194,"character":1}},"text":" ekReminder.dueDateComponents = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute], from: dueDate)"},{"violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","location":{"line":198,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SystemIntegrationManager.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"},"text":" ekReminder.dueDateComponents = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute], from: relativeDate)"},{"violation":{"ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SystemIntegrationManager.swift","character":5,"line":223},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 53 lines","ruleName":"Function Body Length"},"text":" func addReminderToCalendar(_ reminder: ReminderItem, recordingName: String) async -> Bool {"},{"violation":{"severity":"warning","ruleIdentifier":"file_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SystemIntegrationManager.swift","line":428},"reason":"File should contain 400 lines or less: currently contains 428","ruleDescription":"Files should not span too many lines.","ruleName":"File Length"},"text":"}"},{"violation":{"ruleDescription":"Type bodies should not span too many lines","reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 414 lines","ruleIdentifier":"type_body_length","severity":"error","location":{"line":13,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/TaskExtractor.swift"},"ruleName":"Type Body Length"},"text":"class TaskExtractor {"},{"violation":{"ruleDescription":"Function bodies should not span too many lines","severity":"warning","location":{"line":79,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/TaskExtractor.swift"},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 62 lines","ruleName":"Function Body Length","ruleIdentifier":"function_body_length"},"text":" private func extractTaskUsingPatterns(_ sentence: String) -> TaskItem? {"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":83,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/TaskExtractor.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"},"text":" let taskPatterns: [(pattern: String, category: TaskItem.TaskCategory, basePriority: TaskItem.Priority, confidenceBoost: Double)] = ["},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/TaskExtractor.swift","character":28,"line":83},"ruleIdentifier":"large_tuple","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","reason":"Tuples should have at most 2 members","severity":"error","ruleName":"Large Tuple"},"text":" let taskPatterns: [(pattern: String, category: TaskItem.TaskCategory, basePriority: TaskItem.Priority, confidenceBoost: Double)] = ["},{"violation":{"severity":"warning","ruleName":"Prefer For-Where","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","location":{"character":13,"line":143,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/TaskExtractor.swift"},"ruleIdentifier":"for_where","reason":"`where` clauses are preferred over a single `if` inside a `for`"},"text":" if lowercased.contains(pattern) {"},{"violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"line":147,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/TaskExtractor.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters","ruleIdentifier":"line_length","ruleName":"Line Length"},"text":" let confidence = calculatePatternConfidence(sentence: sentence, pattern: pattern, baseConfidence: confidenceBoost)"},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/TaskExtractor.swift","line":178},"severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 142 characters"},"text":" tagger.enumerateTags(in: range, unit: .word, scheme: .lexicalClass, options: [.omitWhitespace, .omitPunctuation]) { tag, tokenRange in"},{"violation":{"ruleName":"Prefer For-Where","ruleIdentifier":"for_where","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/TaskExtractor.swift","line":225,"character":13},"reason":"`where` clauses are preferred over a single `if` inside a `for`"},"text":" if lowercased.hasPrefix(starter) {"},{"violation":{"ruleName":"Identifier Name","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/TaskExtractor.swift","line":283,"character":13},"reason":"Variable name 'i' should be between 3 and 40 characters long","ruleIdentifier":"identifier_name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short."},"text":" for i in 0..= \\(SHORT_CALL_THRESHOLD)s threshold) - asking user whether to resume\")","violation":{"reason":"Line should be 120 characters or less; currently it has 150 characters","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Interruptions.swift","character":1,"line":61}}},{"text":"\tfunc attemptResumeAfterUnexpectedStop() async {","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Interruptions.swift","character":2,"line":115},"ruleDescription":"Function bodies should not span too many lines","severity":"warning","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 63 lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length"}},{"text":"\t\t\tAppLog.shared.audioSession(\"Resume already in progress, skipping duplicate attemptResumeAfterUnexpectedStop\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 127 characters","location":{"character":1,"line":117,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Interruptions.swift"}}},{"text":"\t\t\t\tAppLog.shared.audioSession(\"Failed to resume recording - recorder not active, treating as real interruption\", level: .error)","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Interruptions.swift","character":1,"line":199},"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 128 characters","ruleIdentifier":"line_length"}},{"text":"\t\t\tAppLog.shared.audioSession(\"Failed to resume recording: \\(error.localizedDescription), treating as real interruption\", level: .error)","violation":{"ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Interruptions.swift","line":203,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters."}},{"text":"\tfunc resumeRecordingAfterInterruption(url: URL?) async {","violation":{"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 79 lines","ruleName":"Function Body Length","severity":"warning","ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines","location":{"character":2,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Interruptions.swift","line":209}}},{"text":"\t\t\tAppLog.shared.audioSession(\"Resume already in progress, skipping duplicate resumeRecordingAfterInterruption\", level: .debug)","violation":{"location":{"character":1,"line":222,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Interruptions.swift"},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 127 characters","severity":"warning","ruleName":"Line Length"}},{"violation":{"reason":"Line should be 120 characters or less; currently it has 123 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"line":483,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Interruptions.swift","character":1},"severity":"warning","ruleIdentifier":"line_length"},"text":"\t\t\tAppLog.shared.audioSession(\"Recording already being processed, skipping duplicate interruption handling\", level: .debug)"},{"violation":{"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 63 lines","ruleName":"Function Body Length","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","severity":"warning","location":{"line":520,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Interruptions.swift","character":2}},"text":"\tfunc recoverInterruptedRecording(url: URL, reason: String) async {"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 165 characters","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":618,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Interruptions.swift"},"ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length"},"text":"\t\tAppLog.shared.audioSession(\"checkForUnprocessedRecording called - recordingBeingProcessed: \\(recordingBeingProcessed), isRecording: \\(isRecording)\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Interruptions.swift","line":849,"character":1},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 137 characters"},"text":"\t\tlet body = \"Your recording was interrupted when the app went to background. Don't worry - it will be saved when you return to the app!\""},{"violation":{"ruleIdentifier":"file_length","ruleName":"File Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Interruptions.swift","line":888},"ruleDescription":"Files should not span too many lines.","reason":"File should contain 400 lines or less: currently contains 888","severity":"warning"},"text":"}"},{"violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Playback.swift","line":15,"character":2},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 54 lines","ruleName":"Function Body Length","ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines"},"text":"\tfunc playRecording(url: URL) {"},{"violation":{"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 75 lines","ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length","severity":"warning","location":{"line":27,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Segments.swift","character":2}},"text":"\tfunc mergeRecordingSegments() async {"},{"violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Segments.swift","character":1,"line":70},"reason":"Line should be 120 characters or less; currently it has 131 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length"},"text":"\t\t\t\tAppLog.shared.recording(\"Added segment \\(index + 1) at \\(currentTime.seconds)s, duration: \\(duration.seconds)s\", level: .debug)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 152 characters","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Segments.swift","character":1,"line":240},"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length"},"text":"\t\t\tAppLog.shared.recording(\"Checkpoint: Forced buffer flush at \\(Int(recordingTime))s (no silence for \\(Int(timeSinceLastCheckpoint))s)\", level: .debug)"},{"violation":{"ruleIdentifier":"function_body_length","location":{"character":14,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Utilities.swift","line":30},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 59 lines","ruleName":"Function Body Length","ruleDescription":"Function bodies should not span too many lines","severity":"warning"},"text":"\tnonisolated func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Utilities.swift","line":35,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters","severity":"warning"},"text":"\t\t\t\tAppLog.shared.recording(\"Recorder finished but still in recording mode - ignoring (interruption will be handled)\", level: .debug)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Utilities.swift","line":42},"reason":"Line should be 120 characters or less; currently it has 125 characters"},"text":"\t\t\t\tAppLog.shared.recording(\"Recording already processed by interruption handler, skipping normal completion\", level: .debug)"},{"text":"\t\t\t\t\tAppLog.shared.recording(\"Failed to set preferred input, falling back to default: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 132 characters","severity":"warning","ruleIdentifier":"line_length","location":{"line":213,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Utilities.swift"}}},{"text":"\t\t\t\tAppLog.shared.recording(\"Could not clear preferred input, iOS will use default: \\(error.localizedDescription)\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Utilities.swift","line":237,"character":1},"severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":"\t\t\tlet d = player.duration","violation":{"ruleName":"Identifier Name","ruleIdentifier":"identifier_name","reason":"Variable name 'd' should be between 3 and 40 characters long","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","location":{"line":262,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Utilities.swift","character":8}}},{"text":"\tfunc checkRecordingLimitsAndWarnings() async {","violation":{"ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 62 lines","severity":"warning","ruleName":"Function Body Length","location":{"character":2,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Warnings.swift","line":45}}},{"text":"\t\t\t\t\tthrow NSError(domain: \"AudioRecorderViewModel\", code: -2, userInfo: [NSLocalizedDescriptionKey: \"Could not access Documents directory\"])","violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+WatchIntegration.swift","line":68},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":"\t\t\t\t\tthrow NSError(domain: \"AudioRecorderViewModel\", code: -1, userInfo: [NSLocalizedDescriptionKey: \"App coordinator not available\"])","violation":{"severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 134 characters","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+WatchIntegration.swift","line":81,"character":1},"ruleDescription":"Lines should not span too many characters."}},{"text":"\t\t\t\t\tAppLog.shared.watchConnectivity(\"Calling onWatchRecordingSyncCompleted - callback is nil: \\(watchManager.onWatchRecordingSyncCompleted == nil)\", level: .debug)","violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+WatchIntegration.swift","line":108,"character":1},"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 164 characters"}},{"text":"\t\t\t\t\tAppLog.shared.watchConnectivity(\"Called completion callback for successful watch recording: \\(syncRequest.recordingId)\")","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 125 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+WatchIntegration.swift","character":1,"line":110},"ruleDescription":"Lines should not span too many characters."}},{"text":"\t\t\t\t\tAppLog.shared.watchConnectivity(\"Called completion callback for failed watch recording: \\(syncRequest.recordingId)\", level: .error)","violation":{"severity":"warning","location":{"line":120,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+WatchIntegration.swift"},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 136 characters","ruleIdentifier":"line_length"}},{"text":"class AudioRecorderViewModel: NSObject, ObservableObject {","violation":{"ruleIdentifier":"type_body_length","ruleDescription":"Type bodies should not span too many lines","severity":"error","ruleName":"Type Body Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","character":1,"line":18},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 727 lines"}},{"text":"\tlet SHORT_CALL_THRESHOLD: TimeInterval = 180 \/\/ 3 minutes","violation":{"ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","reason":"Variable name 'SHORT_CALL_THRESHOLD' should only contain alphanumeric and other allowed characters","ruleName":"Identifier Name","severity":"error","ruleIdentifier":"identifier_name","location":{"character":6,"line":119,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift"}}},{"text":"\tlet MICROPHONE_RECONNECTION_TIMEOUT: TimeInterval = 300 \/\/ 5 minutes","violation":{"reason":"Variable name 'MICROPHONE_RECONNECTION_TIMEOUT' should only contain alphanumeric and other allowed characters","ruleName":"Identifier Name","severity":"error","location":{"character":6,"line":123,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift"},"ruleIdentifier":"identifier_name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short."}},{"violation":{"location":{"character":6,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","line":129},"reason":"Variable name 'MAX_RECORDING_DURATION' should only contain alphanumeric and other allowed characters","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleName":"Identifier Name","severity":"error","ruleIdentifier":"identifier_name"},"text":"\tlet MAX_RECORDING_DURATION: TimeInterval = 10800 \/\/ 3 hours"},{"violation":{"severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleName":"Identifier Name","reason":"Variable name 'DURATION_WARNING_THRESHOLD' should only contain alphanumeric and other allowed characters","ruleIdentifier":"identifier_name","location":{"character":6,"line":130,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift"}},"text":"\tlet DURATION_WARNING_THRESHOLD: TimeInterval = 9900 \/\/ 2h 45m (15 min warning)"},{"violation":{"ruleIdentifier":"identifier_name","severity":"error","reason":"Variable name 'MIN_STORAGE_REQUIRED_MB' should only contain alphanumeric and other allowed characters","ruleName":"Identifier Name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","character":6,"line":131},"ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short."},"text":"\tlet MIN_STORAGE_REQUIRED_MB: Int64 = 100 \/\/ Stop recording at 100 MB free"},{"violation":{"severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","character":6,"line":132},"ruleIdentifier":"identifier_name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","reason":"Variable name 'STORAGE_WARNING_THRESHOLD_MB' should only contain alphanumeric and other allowed characters","ruleName":"Identifier Name"},"text":"\tlet STORAGE_WARNING_THRESHOLD_MB: Int64 = 200 \/\/ Warn at 200 MB free"},{"violation":{"severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleName":"Identifier Name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","line":133,"character":6},"ruleIdentifier":"identifier_name","reason":"Variable name 'MIN_BATTERY_LEVEL' should only contain alphanumeric and other allowed characters"},"text":"\tlet MIN_BATTERY_LEVEL: Float = 0.05 \/\/ Stop at 5%"},{"violation":{"ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleName":"Identifier Name","severity":"error","ruleIdentifier":"identifier_name","reason":"Variable name 'BATTERY_WARNING_THRESHOLD' should only contain alphanumeric and other allowed characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","line":134,"character":6}},"text":"\tlet BATTERY_WARNING_THRESHOLD: Float = 0.15 \/\/ Warn at 15%"},{"violation":{"ruleName":"Cyclomatic Complexity","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","severity":"warning","reason":"Function should have complexity 10 or less; currently complexity is 18","location":{"line":262,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","character":2}},"text":"\tfunc setupNotificationObservers() {"},{"violation":{"ruleIdentifier":"function_body_length","ruleName":"Function Body Length","severity":"error","ruleDescription":"Function bodies should not span too many lines","reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 115 lines","location":{"character":2,"line":262,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift"}},"text":"\tfunc setupNotificationObservers() {"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","character":1,"line":284},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 126 characters"},"text":"\t\t\t\tlet newNotification = Notification(name: AVAudioSession.interruptionNotification, object: nil, userInfo: capturedUserInfo)"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 121 characters","ruleName":"Line Length","location":{"character":1,"line":302,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift"}},"text":"\t\t\t\t\tlet newNotification = Notification(name: AVAudioSession.routeChangeNotification, object: nil, userInfo: newUserInfo)"},{"violation":{"ruleIdentifier":"line_length","location":{"line":346,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift"},"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 123 characters","ruleName":"Line Length"},"text":"\t\t\t\t\tAppLog.shared.recording(\"Resume already in progress from another handler, skipping foreground restore\", level: .debug)"},{"violation":{"location":{"character":1,"line":352,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift"},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 121 characters","ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters."},"text":"\t\t\t\t\tAppLog.shared.recording(\"App foregrounded without active recording - leaving audio session inactive\", level: .debug)"},{"text":"\t\t\t\t\t\tif let r = self.audioRecorder, r.isRecording {","violation":{"ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","character":14,"line":371},"reason":"Variable name 'r' should be between 3 and 40 characters long","ruleIdentifier":"identifier_name","ruleName":"Identifier Name"}},{"text":"\t\t\terrorMessage = \"Microphone access is denied. Open System Settings β†’ Privacy & Security β†’ Microphone and enable BisonNotes AI, then try again.\"","violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"line":510,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift"},"reason":"Line should be 120 characters or less; currently it has 145 characters","severity":"warning"}},{"text":"\t\t\terrorMessage = \"Recording failed on simulator. Enable Device β†’ Microphone β†’ Internal Microphone in simulator menu, or test on a physical device.\"","violation":{"severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","character":1,"line":636},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 148 characters","ruleDescription":"Lines should not span too many characters."}},{"text":"\tfunc stopRecording() {","violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","character":2,"line":724},"ruleIdentifier":"function_body_length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 58 lines","ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length"}},{"text":"\t\t\t\t\t\t\tAppLog.shared.recording(\"Detected recorder stopped - waiting for interruption notification (grace period: 5s)\", level: .debug)","violation":{"ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","line":921},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 133 characters","severity":"warning"}},{"text":"}","violation":{"ruleIdentifier":"file_length","severity":"error","ruleDescription":"Files should not span too many lines.","ruleName":"File Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","line":1002,"character":1},"reason":"File should contain 1000 lines or less: currently contains 1002"}},{"text":"\tfunc start() async throws {","violation":{"ruleName":"Function Body Length","severity":"warning","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 55 lines","ruleDescription":"Function bodies should not span too many lines","location":{"line":37,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/CatalystSystemAudioCapture.swift","character":2},"ruleIdentifier":"function_body_length"}},{"text":"\t\t\tAppLog.shared.recording(\"Catalyst system audio capture produced no audio; continuing with microphone recording only\", level: .debug)","violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/CatalystSystemAudioCapture.swift","line":143},"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":"\tfunc stream(_ stream: SCStream, didOutputSampleBuffer sampleBuffer: CMSampleBuffer, of type: SCStreamOutputType) {","violation":{"ruleDescription":"Complexity of function bodies should be limited.","severity":"warning","location":{"line":151,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/CatalystSystemAudioCapture.swift","character":2},"reason":"Function should have complexity 10 or less; currently complexity is 16","ruleName":"Cyclomatic Complexity","ruleIdentifier":"cyclomatic_complexity"}},{"text":"\t\tAppLog.shared.recording(\"Catalyst system audio stream stopped with error: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 122 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/CatalystSystemAudioCapture.swift","line":206},"ruleIdentifier":"line_length"}},{"text":" } else if engineLower.contains(\"device\") || engineLower.contains(\"apple\") || engineLower.contains(\"mlx\") || modelLower.contains(\"intelligence\") || modelLower.contains(\"gemma\") || modelLower.contains(\"phi\") || modelLower.contains(\"qwen\") || modelLower.contains(\"llama\") || modelLower.contains(\"mistral\") || modelLower.contains(\"olmo\") || modelLower.contains(\"alpaca\") || modelLower.contains(\"bonsai\") || modelLower.contains(\"ternary\") {","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"error","location":{"line":44,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AITextView.swift","character":1},"reason":"Line should be 200 characters or less; currently it has 443 characters","ruleIdentifier":"line_length"}},{"text":" let _ = {","violation":{"reason":"Prefer `_ = foo()` over `let _ = foo()` when discarding a result from a function","severity":"warning","ruleName":"Redundant Discardable Let","location":{"character":9,"line":67,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AITextView.swift"},"ruleIdentifier":"redundant_discardable_let","ruleDescription":"Prefer `_ = foo()` over `let _ = foo()` when discarding a result from a function"}},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AITextView.swift","character":1,"line":71},"reason":"Line should be 120 characters or less; currently it has 130 characters"},"text":" AppLog.shared.summarization(\"AITextView text was cleaned to empty, original length: \\(text.count)\", level: .error)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 123 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AITextView.swift","line":106,"character":1},"ruleIdentifier":"line_length","severity":"warning"},"text":" AppLog.shared.summarization(\"AITextView cleaning: original=\\(text.count), cleaned=\\(cleaned.count)\", level: .debug)"},{"violation":{"ruleName":"Line Length","reason":"Line should be 200 characters or less; currently it has 263 characters","location":{"line":125,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AITextView.swift","character":1},"ruleDescription":"Lines should not span too many characters.","severity":"error","ruleIdentifier":"line_length"},"text":" AITextView(text: \"### Summary with Emoji\\n\\n:checkmark: Task completed successfully\\n:warning: Important note to review\\n:info: Additional information\\n:rocket: Quick start guide\\n:lightbulb: Helpful tips\\n:star: Key highlights\", aiService: .googleAI)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AITextView.swift","line":132,"character":1},"reason":"Line should be 200 characters or less; currently it has 218 characters"},"text":" AITextView(text: \"### Product Overview\\n\\nThe company offers an AI-powered tutoring platform.\\n\\n#### Key Features\\n\\nβ€’ Personalized tutoring for students\\nβ€’ Concurrent seating model\", aiService: .googleAI)"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","location":{"line":139,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AITextView.swift","character":1},"reason":"Line should be 200 characters or less; currently it has 299 characters","severity":"error","ruleDescription":"Lines should not span too many characters."},"text":" AITextView(text: \"### Primary Action Items\\n\\nβ€’ Tim to provide list of suspended accounts\\nβ€’ Confirm deletion with Jack\\nβ€’ Review MOU language for data deletion\\n\\n1. Create sample account for testing\\n2. Review storage quotas\\n3. Implement notification processes\", aiService: .googleAI)"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AITextView.swift","character":1,"line":146},"reason":"Line should be 200 characters or less; currently it has 679 characters","ruleDescription":"Lines should not span too many characters."},"text":" AITextView(text: \"## Market and Political Dynamics\\n\\nβ€’ Federal Reserve Chair **Jerome Powell** discussed potential interest rate cuts\\nβ€’ Stock market surged with Dow rising over 800 points\\nβ€’ Political tensions emerged around Federal Reserve governance\\n\\n### Key Economic Insights\\n\\nβ€’ Investors looking for positive economic signals\\nβ€’ Concerns about political interference in independent institutions\\nβ€’ Discussions about inflation, employment, and market confidence\\n\\n### Notable Political Developments\\n\\nβ€’ President Trump threatening to fire Federal Reserve Governor **Lisa Cook**\\nβ€’ Debates about immigrant labor's economic importance\", aiService: .googleAI)"},{"violation":{"reason":"Line should be 200 characters or less; currently it has 299 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AITextView.swift","character":1,"line":153},"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"error"},"text":" AITextView(text: \"\\\"summary\\\": \\\"**Storage and Account Management Highlights**\\n\\nβ€’ Retirees will retain **5GB storage**\\nβ€’ Data deletion and account management for alumni\\nβ€’ Google storage quotas and notification processes\\nβ€’ Suspended account cleanup strategy\\\"\", aiService: .googleAI)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 188 characters","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","character":1,"line":59},"severity":"warning","ruleDescription":"Lines should not span too many characters."},"text":" Text(\"These are brought in through AWS SDK and other direct dependencies. All dependencies are MIT or Apache 2.0 licensed. See each project repository for full terms.\")"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","character":1,"line":116},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 140 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning"},"text":" description: \"Apple Silicon ML framework and language-model utilities used for on-device summarization with Ternary Bonsai models.\","},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","location":{"line":152,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 144 characters","severity":"warning","ruleDescription":"Lines should not span too many characters."},"text":" TransitiveProject(name: \"Swift NIO Transport Services\", url: URL(string: \"https:\/\/github.com\/apple\/swift-nio-transport-services\")!),"},{"violation":{"ruleIdentifier":"line_length","location":{"character":1,"line":155,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift"},"severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 122 characters"},"text":" TransitiveProject(name: \"Swift Collections\", url: URL(string: \"https:\/\/github.com\/apple\/swift-collections\")!),"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 132 characters","ruleIdentifier":"line_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","character":1,"line":161}},"text":" TransitiveProject(name: \"Swift Async Algorithms\", url: URL(string: \"https:\/\/github.com\/apple\/swift-async-algorithms\")!),"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 130 characters","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"line":162,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","character":1},"ruleName":"Line Length"},"text":" TransitiveProject(name: \"Swift Argument Parser\", url: URL(string: \"https:\/\/github.com\/apple\/swift-argument-parser\")!),"},{"violation":{"severity":"warning","location":{"line":164,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift"},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 124 characters","ruleName":"Line Length","ruleIdentifier":"line_length"},"text":" TransitiveProject(name: \"Swift Certificates\", url: URL(string: \"https:\/\/github.com\/apple\/swift-certificates\")!),"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 146 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","line":167},"ruleName":"Line Length"},"text":" TransitiveProject(name: \"Swift HTTP Structured Headers\", url: URL(string: \"https:\/\/github.com\/apple\/swift-http-structured-headers\")!),"},{"violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 138 characters","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","character":1,"line":168},"severity":"warning"},"text":" TransitiveProject(name: \"Swift Distributed Tracing\", url: URL(string: \"https:\/\/github.com\/apple\/swift-distributed-tracing\")!),"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","line":169,"character":1},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 130 characters"},"text":" TransitiveProject(name: \"Swift Service Context\", url: URL(string: \"https:\/\/github.com\/apple\/swift-service-context\")!),"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 125 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"line":170,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","character":1},"severity":"warning"},"text":" TransitiveProject(name: \"Swift Configuration\", url: URL(string: \"https:\/\/github.com\/apple\/swift-configuration\")!)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 129 characters","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","character":1,"line":176}},"text":" TransitiveProject(name: \"Async HTTP Client\", url: URL(string: \"https:\/\/github.com\/swift-server\/async-http-client\")!),"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"line":177,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift"},"reason":"Line should be 120 characters or less; currently it has 141 characters","severity":"warning"},"text":" TransitiveProject(name: \"Swift Service Lifecycle\", url: URL(string: \"https:\/\/github.com\/swift-server\/swift-service-lifecycle\")!),"},{"violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","character":1,"line":179},"reason":"Line should be 120 characters or less; currently it has 135 characters","ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."},"text":" TransitiveProject(name: \"OpenTelemetry Swift\", url: URL(string: \"https:\/\/github.com\/open-telemetry\/opentelemetry-swift\")!),"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 128 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","line":183,"character":1}},"text":" TransitiveProject(name: \"Swift HuggingFace\", url: URL(string: \"https:\/\/github.com\/huggingface\/swift-huggingface\")!),"},{"violation":{"ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","line":187,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" TransitiveProject(name: \"Swift Concurrency Extras\", url: URL(string: \"https:\/\/github.com\/pointfreeco\/swift-concurrency-extras\")!)"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AdaptiveNavigationView.swift","line":111},"reason":"Line should be 120 characters or less; currently it has 121 characters","ruleDescription":"Lines should not span too many characters."},"text":" .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(\"NavigateToSection\"))) { notification in"},{"text":" Text(\"Archive copies are currently limited to iCloud Drive so the app can reliably track, restore, and clean them up.\")","violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 143 characters","ruleName":"Line Length","severity":"warning","location":{"line":36,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/ArchiveConfirmationView.swift","character":1}}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 137 characters","severity":"warning","location":{"line":65,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/ArchiveConfirmationView.swift","character":1},"ruleName":"Line Length"}},{"text":" .background(Color.accentColor.opacity(0.12), in: RoundedRectangle(cornerRadius: 10, style: .continuous))","violation":{"ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/ArchiveConfirmationView.swift","line":74,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters","ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters."}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/ArchiveConfirmationView.swift","character":1,"line":87},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 133 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"text":"struct AudioPlayerView: View {","violation":{"ruleName":"Type Body Length","ruleDescription":"Type bodies should not span too many lines","reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 478 lines","severity":"error","ruleIdentifier":"type_body_length","location":{"line":11,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioPlayerView.swift"}}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioPlayerView.swift","line":97},"reason":"Line should be 120 characters or less; currently it has 133 characters","ruleIdentifier":"line_length","ruleName":"Line Length"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioPlayerView.swift","character":1,"line":174},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" }) {","violation":{"reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioPlayerView.swift","line":201,"character":12}}},{"text":" EditableTranscriptView(recording: entry, transcript: transcript, transcriptManager: TranscriptManager.shared)","violation":{"ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioPlayerView.swift","line":209},"reason":"Line should be 120 characters or less; currently it has 125 characters","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning"}},{"text":" transcriptionStarter.startTranscription(for: pending, cleanFirst: true, appCoordinator: appCoordinator)","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioPlayerView.swift","character":1,"line":224},"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" transcriptionStarter.startTranscription(for: pending, cleanFirst: false, appCoordinator: appCoordinator)","violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"line":230,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioPlayerView.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters","severity":"warning","ruleIdentifier":"line_length"}},{"text":" Text(\"Cleaning reduces static and normalizes volume, which can improve transcription accuracy. The original audio file is not changed.\")","violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 148 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioPlayerView.swift","line":237},"ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length"}},{"text":" .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(\"RecordingCloudSyncPreferenceChanged\"))) { _ in","violation":{"ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioPlayerView.swift","character":1,"line":281},"reason":"Line should be 120 characters or less; currently it has 128 characters","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning"}},{"text":" .background((isCloudSyncDisabled ? Color.indigo : Color.blue).opacity(0.12), in: RoundedRectangle(cornerRadius: 10, style: .continuous))","violation":{"reason":"Line should be 120 characters or less; currently it has 152 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioPlayerView.swift","line":303,"character":1}}},{"text":" .accessibilityHint(\"Excludes this recording, transcript, and summary from BisonNotes iCloud sync and backup.\")","violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioPlayerView.swift","line":325},"reason":"Line should be 120 characters or less; currently it has 122 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning"}},{"text":" }) {","violation":{"severity":"warning","ruleName":"Multiple Closures with Trailing Closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioPlayerView.swift","character":16,"line":349},"reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure"}},{"text":"}","violation":{"ruleIdentifier":"file_length","ruleName":"File Length","reason":"File should contain 400 lines or less: currently contains 587","ruleDescription":"Files should not span too many lines.","location":{"character":1,"line":587,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioPlayerView.swift"},"severity":"warning"}},{"text":" x: min(max(isDragging ? 10 : 8, (geometry.size.width * progress)), geometry.size.width - (isDragging ? 10 : 8)),","violation":{"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 140 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"line":75,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioScrubber.swift","character":1}}},{"text":" let _ = AppLog.shared.backgroundProcessing(\"BackgroundProcessingView body: activeJobs.count = \\(processingManager.activeJobs.count)\", level: .debug)","violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/BackgroundProcessingView.swift","line":16},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 156 characters","ruleDescription":"Lines should not span too many characters."}},{"text":" let _ = AppLog.shared.backgroundProcessing(\"BackgroundProcessingView body: activeJobs.count = \\(processingManager.activeJobs.count)\", level: .debug)","violation":{"ruleIdentifier":"redundant_discardable_let","location":{"line":16,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/BackgroundProcessingView.swift","character":9},"severity":"warning","ruleName":"Redundant Discardable Let","ruleDescription":"Prefer `_ = foo()` over `let _ = foo()` when discarding a result from a function","reason":"Prefer `_ = foo()` over `let _ = foo()` when discarding a result from a function"}},{"text":" value: \"\\(processingManager.activeJobs.filter { $0.status.isError || $0.status.isCancelled }.count)\",","violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 121 characters","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"line":135,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/BackgroundProcessingView.swift"}}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 133 characters","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"line":464,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/BackgroundProcessingView.swift"}}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/BackgroundProcessingView.swift","line":492,"character":1},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 133 characters","ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/BackgroundProcessingView.swift","line":538,"character":1},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 133 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/BackgroundProcessingView.swift","character":1,"line":563},"reason":"Line should be 120 characters or less; currently it has 133 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"},"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/BackgroundProcessingView.swift","line":576,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"},"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))"},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/BackgroundProcessingView.swift","line":595},"reason":"Line should be 120 characters or less; currently it has 137 characters","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 137 characters","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/BackgroundProcessingView.swift","line":614,"character":1}},"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))"},{"violation":{"severity":"warning","location":{"line":694,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/BackgroundProcessingView.swift"},"ruleDescription":"Files should not span too many lines.","reason":"File should contain 400 lines or less: currently contains 694","ruleIdentifier":"file_length","ruleName":"File Length"},"text":"}"},{"violation":{"ruleName":"Type Body Length","reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 467 lines","ruleDescription":"Type bodies should not span too many lines","severity":"error","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/CombineRecordingsView.swift","character":1,"line":10}},"text":"struct CombineRecordingsView: View {"},{"violation":{"ruleName":"Line Length","location":{"character":1,"line":35,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/CombineRecordingsView.swift"},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 121 characters","severity":"warning"},"text":" init(firstRecording: AudioRecordingFile, secondRecording: AudioRecordingFile, recommendedFirst: AudioRecordingFile) {"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 140 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"line":104,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/CombineRecordingsView.swift","character":1}},"text":" Text(\"Select which recording should be first in the combined file. The recordings will be merged in the order you specify.\")"},{"violation":{"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","severity":"warning","location":{"character":20,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/CombineRecordingsView.swift","line":176},"reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","ruleName":"Multiple Closures with Trailing Closure"},"text":" }) {"},{"violation":{"ruleDescription":"Function bodies should not span too many lines","severity":"warning","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/CombineRecordingsView.swift","character":13,"line":205},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 51 lines"},"text":" private func recordingOrderCard(recording: AudioRecordingFile, position: String, isRecommended: Bool) -> some View {"},{"violation":{"ruleName":"Multiple Closures with Trailing Closure","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","severity":"warning","location":{"character":12,"line":312,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/CombineRecordingsView.swift"},"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument"},"text":" }) {"},{"violation":{"location":{"line":381,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/CombineRecordingsView.swift","character":13},"ruleIdentifier":"cyclomatic_complexity","ruleDescription":"Complexity of function bodies should be limited.","severity":"warning","reason":"Function should have complexity 10 or less; currently complexity is 15","ruleName":"Cyclomatic Complexity"},"text":" private func combineRecordings() async {"},{"text":" private func combineRecordings() async {","violation":{"ruleName":"Function Body Length","ruleDescription":"Function bodies should not span too many lines","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/CombineRecordingsView.swift","character":13,"line":381},"severity":"error","ruleIdentifier":"function_body_length","reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 125 lines"}},{"text":" errorMessage = \"Cannot combine recordings with existing transcripts or summaries. Please delete them first.\"","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 124 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/CombineRecordingsView.swift","line":386,"character":1},"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length"}},{"text":" AppLog.shared.recording(\"Combine: hasLocation=\\(combinedLocation != nil) for addRecording\", level: .debug)","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"line":518,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/CombineRecordingsView.swift"},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":"}","violation":{"ruleIdentifier":"file_length","ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","reason":"File should contain 400 lines or less: currently contains 577","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/CombineRecordingsView.swift","line":577,"character":1}}},{"text":"struct DataMigrationView: View {","violation":{"severity":"error","location":{"line":16,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","character":1},"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 1017 lines","ruleDescription":"Type bodies should not span too many lines","ruleName":"Type Body Length","ruleIdentifier":"type_body_length"}},{"text":" @State private var orphanedFilesResults: (deleted: Int, totalSize: Int64, errors: [String])?","violation":{"location":{"line":42,"character":46,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift"},"reason":"Tuples should have at most 2 members","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleName":"Large Tuple","ruleIdentifier":"large_tuple","severity":"warning"}},{"text":" Text(\"🚨🚨🚨 EXTREME WARNING 🚨🚨🚨\\n\\nYou are about to PERMANENTLY DELETE ALL DATABASE DATA:\\n\\n❌ ALL TRANSCRIPTS will be DELETED FOREVER\\n❌ ALL SUMMARIES will be DELETED FOREVER\\n❌ ALL RECORDING METADATA will be DELETED FOREVER\\n\\nβœ… Audio files will remain on disk (but without any metadata)\\n\\n⚠️ THIS ACTION CANNOT BE UNDONE\\n⚠️ NO RECOVERY IS POSSIBLE\\n⚠️ ALL PROCESSED DATA WILL BE LOST\\n\\nThis is an extreme troubleshooting measure. DO NOT proceed unless you:\\n\\n1. Have a backup of your data\\n2. Understand you will lose ALL transcripts and summaries\\n3. Are prepared to re-transcribe and re-summarize everything\\n\\nOnly tap 'DELETE EVERYTHING' if you absolutely understand the consequences.\")","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"error","location":{"line":109,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","character":1},"reason":"Line should be 200 characters or less; currently it has 708 characters","ruleIdentifier":"line_length"}},{"text":" Text(\"This will remove summaries and transcripts for recordings that no longer exist. This action cannot be undone.\")","violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":122,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift"},"ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" Text(\"This will scan for duplicate summaries and transcripts for the same recording and keep only the most recent one.\\n\\nThis is useful after failed summarization runs that may have created multiple entries.\\n\\nThis action cannot be undone.\")","violation":{"ruleName":"Line Length","reason":"Line should be 200 characters or less; currently it has 259 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"error","location":{"line":131,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","character":1}}},{"text":" Text(\"This will upload ALL local summaries to iCloud. This is useful for:\\n\\nβ€’ Initial setup on a new device\\nβ€’ After restoring from backup\\nβ€’ Manual full synchronization\\n\\nThis may take several minutes depending on the number of summaries.\")","violation":{"location":{"line":146,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift"},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 200 characters or less; currently it has 259 characters","ruleIdentifier":"line_length","severity":"error"}},{"text":" let result = try await legacyiCloudManager.performFullCloudKitResetAndSync(appCoordinator: appCoordinator)","violation":{"reason":"Line should be 120 characters or less; currently it has 134 characters","ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"line":153,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift"}}},{"text":" AppLog.shared.dataMigration(\"CloudKit reset complete: deleted \\(result.deleted), uploaded \\(result.uploaded)\")","violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 138 characters","ruleIdentifier":"line_length","severity":"warning","location":{"line":154,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift"},"ruleDescription":"Lines should not span too many characters."}},{"text":" Text(\"🚨 DESTRUCTIVE ACTION 🚨\\n\\nThis will:\\n\\n1️⃣ DELETE ALL summaries from iCloud\\n2️⃣ Upload fresh copies of all your current summaries\\n\\nThis is the nuclear option for fixing CloudKit sync issues. Use this when:\\n\\nβ€’ CloudKit has orphaned or duplicate data\\nβ€’ Sync is completely broken\\nβ€’ You want a clean slate\\n\\n⚠️ This cannot be undone and may take several minutes.\")","violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":161},"severity":"error","reason":"Line should be 200 characters or less; currently it has 386 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 18, style: .continuous))","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","character":1,"line":185},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 14, style: .continuous))","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"line":195,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 121 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":225},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":" }) {","violation":{"reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","location":{"character":20,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":234}}},{"text":" }) {","violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":250,"character":20},"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","ruleName":"Multiple Closures with Trailing Closure"}},{"text":" }) {","violation":{"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","character":20,"line":271},"severity":"warning","ruleIdentifier":"multiple_closures_with_trailing_closure"}},{"text":" }) {","violation":{"ruleIdentifier":"multiple_closures_with_trailing_closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","location":{"line":292,"character":20,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift"},"reason":"Trailing closure syntax should not be used when passing more than one closure argument","severity":"warning"}},{"text":" }) {","violation":{"ruleIdentifier":"multiple_closures_with_trailing_closure","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":317,"character":20}}},{"text":" }) {","violation":{"location":{"character":20,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":388},"ruleName":"Multiple Closures with Trailing Closure","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","severity":"warning"}},{"text":" }) {","violation":{"location":{"character":20,"line":405,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift"},"reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","severity":"warning","ruleIdentifier":"multiple_closures_with_trailing_closure","ruleName":"Multiple Closures with Trailing Closure"}},{"text":" }) {","violation":{"ruleIdentifier":"multiple_closures_with_trailing_closure","ruleName":"Multiple Closures with Trailing Closure","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","severity":"warning","location":{"character":20,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":446}}},{"violation":{"reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","severity":"warning","location":{"line":464,"character":20,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift"}},"text":" }) {"},{"violation":{"ruleIdentifier":"multiple_closures_with_trailing_closure","ruleName":"Multiple Closures with Trailing Closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","location":{"line":494,"character":24,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift"},"severity":"warning","reason":"Trailing closure syntax should not be used when passing more than one closure argument"},"text":" }) {"},{"violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","location":{"line":551,"character":16,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift"},"reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure"},"text":" }) {"},{"violation":{"severity":"warning","location":{"line":571,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","character":16},"ruleIdentifier":"multiple_closures_with_trailing_closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure"},"text":" }) {"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","character":1,"line":589},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 121 characters","severity":"warning","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."},"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 18, style: .continuous))"},{"violation":{"ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":600,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift"},"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 151 characters"},"text":" Text(\"This will fetch summaries from iCloud and add any missing entries to your database. It will not overwrite existing local summaries.\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"error","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":610,"character":1},"reason":"Line should be 200 characters or less; currently it has 247 characters"},"text":" Text(\"This will permanently delete \\(orphanedAudioFiles.count) orphaned audio files (\\(formatFileSize(totalOrphanedSize))). This action cannot be undone.\\n\\nThese files exist on disk but are not referenced in your Core Data database.\")"},{"violation":{"location":{"line":621,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","character":1},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 131 characters","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning"},"text":" Text(\"Successfully deleted \\(results.deleted) files, freeing \\(formatFileSize(results.totalSize)) of storage.\")"},{"violation":{"severity":"warning","location":{"character":1,"line":623,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift"},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 171 characters","ruleIdentifier":"line_length"},"text":" Text(\"Deleted \\(results.deleted) files, freeing \\(formatFileSize(results.totalSize)) of storage.\\n\\nErrors: \\(results.errors.joined(separator: \", \"))\")"},{"violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 150 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":648,"character":1}},"text":" \\(result.unsyncedLocalCount > 0 ? \"⚠️ \\(result.unsyncedLocalCount) local summaries not in iCloud\" : \"βœ… All local summaries are synced\")"},{"violation":{"severity":"warning","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"line":663,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","character":16},"ruleName":"Multiple Closures with Trailing Closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument"},"text":" }) {"},{"violation":{"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"line":680,"character":16,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift"},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"},"text":" }) {"},{"violation":{"location":{"line":698,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift"},"reason":"Line should be 120 characters or less; currently it has 121 characters","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 18, style: .continuous))"},{"violation":{"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","severity":"warning","reason":"Trailing closure syntax should not be used when passing more than one closure argument","location":{"character":20,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":708},"ruleIdentifier":"multiple_closures_with_trailing_closure"},"text":" }) {"},{"violation":{"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","character":16,"line":726},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"},"text":" }) {"},{"violation":{"ruleName":"Line Length","location":{"line":744,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift"},"reason":"Line should be 120 characters or less; currently it has 121 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"},"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 18, style: .continuous))"},{"violation":{"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","ruleName":"Multiple Closures with Trailing Closure","reason":"Trailing closure syntax should not be used when passing more than one closure argument","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":794,"character":28}},"text":" }) {"},{"violation":{"ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":810},"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 129 characters"},"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))"},{"violation":{"ruleName":"Line Length","location":{"line":853,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift"},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 129 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"},"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))"},{"violation":{"severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":894,"character":1},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 132 characters","ruleName":"Line Length"},"text":" return \"Check for missing transcripts and summaries, import legacy files, view database information, or clear all data.\""},{"violation":{"ruleName":"Line Length","severity":"warning","location":{"line":898,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","character":1},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 135 characters"},"text":" return \"Automatically repair the data integrity issues found during the scan to restore missing transcripts and summaries.\""},{"violation":{"ruleIdentifier":"cyclomatic_complexity","ruleDescription":"Complexity of function bodies should be limited.","ruleName":"Cyclomatic Complexity","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":962,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 15"},"text":" private func cleanupOrphanedData() async throws -> CleanupResults {"},{"violation":{"ruleIdentifier":"function_body_length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 93 lines","ruleName":"Function Body Length","location":{"character":13,"line":962,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift"},"ruleDescription":"Function bodies should not span too many lines","severity":"warning"},"text":" private func cleanupOrphanedData() async throws -> CleanupResults {"},{"violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","character":1,"line":973},"reason":"Line should be 120 characters or less; currently it has 145 characters","ruleIdentifier":"line_length","severity":"warning"},"text":" AppLog.shared.dataMigration(\"Found \\(allSummaries.count) stored summaries and \\(allTranscripts.count) stored transcripts\", level: .debug)"},{"text":" AppLog.shared.dataMigration(\"Found orphaned summary for recording ID: \\(recordingId?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":993},"reason":"Line should be 120 characters or less; currently it has 138 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.dataMigration(\"Found orphaned transcript for recording ID: \\(recordingId?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":1020,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift"},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 141 characters","ruleName":"Line Length"}},{"text":" AppLog.shared.dataMigration(\"Found valid transcript for recording ID: \\(recordingId?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleIdentifier":"line_length","location":{"line":1031,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift"},"severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 138 characters","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.dataMigration(\"Found transcript for non-existent recording file: \\(recordingURL.lastPathComponent)\", level: .debug)","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","character":1,"line":1052},"reason":"Line should be 120 characters or less; currently it has 145 characters"}},{"text":" AppLog.shared.dataMigration(\"File not found on disk but recording exists in Core Data: \\(recordingURL.lastPathComponent)\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":1063},"reason":"Line should be 120 characters or less; currently it has 153 characters","ruleName":"Line Length","ruleIdentifier":"line_length"}},{"text":" guard let _ = recording.recordingURL,","violation":{"ruleDescription":"Prefer `!= nil` over `let _ =`","ruleName":"Unused Optional Binding","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":1070,"character":23},"reason":"Prefer `!= nil` over `let _ =`","ruleIdentifier":"unused_optional_binding"}},{"text":" AppLog.shared.dataMigration(\"Found orphaned recording (no file, no transcript, no summary)\", level: .debug)","violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 127 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"line":1086,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift"},"ruleIdentifier":"line_length"}},{"text":" AppLog.shared.dataMigration(\"Keeping recording with missing file (has transcript: \\(hasTranscript), has summary: \\(hasSummary))\", level: .debug)","violation":{"reason":"Line should be 120 characters or less; currently it has 164 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":1096,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","character":1},"ruleName":"Line Length"}},{"text":" AppLog.shared.dataMigration(\"Cleanup complete: removed \\(orphanedSummaries) summaries, \\(orphanedTranscripts) transcripts, \\(orphanedRecordings) recordings, freed \\(String(format: \"%.1f\", freedSpaceMB)) MB\")","violation":{"reason":"Line should be 200 characters or less; currently it has 215 characters","ruleName":"Line Length","location":{"line":1103,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift"},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"error"}},{"text":" AppLog.shared.dataMigration(\"Sync verification complete: local=\\(result.localCount), cloud=\\(result.cloudCount), synced=\\(result.syncedCount), unsynced=\\(result.unsyncedLocalCount), cloudOnly=\\(result.cloudOnlyCount)\")","violation":{"ruleName":"Line Length","severity":"error","reason":"Line should be 200 characters or less; currently it has 230 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","character":1,"line":1143},"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"}},{"text":"}","violation":{"ruleIdentifier":"file_length","reason":"File should contain 1000 lines or less: currently contains 1230","ruleDescription":"Files should not span too many lines.","ruleName":"File Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":1230,"character":1},"severity":"error"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 133 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/EnhancedDeleteDialog.swift","line":69,"character":1}}},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 137 characters","location":{"character":1,"line":98,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/EnhancedDeleteDialog.swift"},"severity":"warning"},"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))"},{"violation":{"severity":"warning","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 129 characters","location":{"line":105,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/EnhancedDeleteDialog.swift","character":1},"ruleIdentifier":"line_length"},"text":" Text(\"The summary will be preserved and can be accessed later, even without the original recording.\")"},{"violation":{"ruleName":"Line Length","severity":"warning","location":{"line":132,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/EnhancedDeleteDialog.swift","character":1},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 145 characters","ruleIdentifier":"line_length"},"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 12, style: .continuous))"},{"violation":{"reason":"Line should be 200 characters or less; currently it has 261 characters","location":{"line":152,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/EnhancedDeleteDialog.swift"},"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"error"},"text":" AppLog.shared.fileManagement(\"EnhancedDeleteDialog rendering: hasRecording=\\(relationships.hasRecording), hasTranscript=\\(relationships.transcriptExists), hasSummary=\\(relationships.summaryExists), preserveSummary=\\(preserveSummary)\", level: .debug)"},{"violation":{"severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleName":"Type Body Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","character":1,"line":13},"ruleIdentifier":"type_body_length","reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 492 lines"},"text":"struct MistralOnboardingView: View {"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":88,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift"},"reason":"Line should be 120 characters or less; currently it has 134 characters"},"text":" .fill(step == currentStep ? Color.orange : (step < currentStep ? Color.orange.opacity(0.5) : Color(.systemGray4)))"},{"violation":{"ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","line":118,"character":1},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 127 characters","severity":"warning","ruleDescription":"Lines should not span too many characters."},"text":" benefitRow(icon: \"waveform\", title: \"Audio Transcription\", detail: \"Voxtral Mini with speaker diarization\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":119,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift"},"ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 124 characters"},"text":" benefitRow(icon: \"doc.text\", title: \"AI Summaries\", detail: \"Automatic summaries, tasks, and reminders\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 128 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","line":120,"character":1}},"text":" benefitRow(icon: \"gift\", title: \"Free Tier Included\", detail: \"No credit card, all models, 500K tokens\/min\")"},{"violation":{"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","ruleName":"Multiple Closures with Trailing Closure","severity":"warning","reason":"Trailing closure syntax should not be used when passing more than one closure argument","location":{"character":71,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","line":141}},"text":" Button(action: { withAnimation { currentStep = 1 } }) {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","location":{"line":165,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift"},"reason":"Line should be 120 characters or less; currently it has 122 characters","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning"},"text":" Text(\"Create a free Mistral AI account on their console. You'll just need an email and phone number.\")"},{"violation":{"location":{"line":189,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","character":20},"ruleIdentifier":"multiple_closures_with_trailing_closure","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","severity":"warning"},"text":" }) {"},{"text":" Button(action: { withAnimation { currentStep = 0 } }) {","violation":{"reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","location":{"character":75,"line":202,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift"},"ruleIdentifier":"multiple_closures_with_trailing_closure","severity":"warning","ruleName":"Multiple Closures with Trailing Closure"}},{"text":" }) {","violation":{"ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"character":24,"line":210,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift"},"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","severity":"warning","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure"}},{"text":" }) {","violation":{"severity":"warning","reason":"Trailing closure syntax should not be used when passing more than one closure argument","location":{"character":20,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","line":272},"ruleIdentifier":"multiple_closures_with_trailing_closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure"}},{"text":" Button(action: { withAnimation { currentStep = 1 } }) {","violation":{"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","line":285,"character":75},"ruleName":"Multiple Closures with Trailing Closure","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","severity":"warning"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","line":293,"character":24},"severity":"warning","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" Button(action: { withAnimation { currentStep = 2 } }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","reason":"Trailing closure syntax should not be used when passing more than one closure argument","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","line":400,"character":75},"ruleIdentifier":"multiple_closures_with_trailing_closure"}},{"text":" }) {","violation":{"severity":"warning","reason":"Trailing closure syntax should not be used when passing more than one closure argument","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","line":409,"character":28},"ruleIdentifier":"multiple_closures_with_trailing_closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure"}},{"text":" }) {","violation":{"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","severity":"warning","ruleName":"Multiple Closures with Trailing Closure","reason":"Trailing closure syntax should not be used when passing more than one closure argument","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","character":20,"line":471},"ruleIdentifier":"multiple_closures_with_trailing_closure"}},{"text":"}","violation":{"reason":"File should contain 400 lines or less: currently contains 592","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","ruleName":"File Length","location":{"line":592,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift"}}},{"text":" private let mlxModel: MLXModelOption = MLXModelOption.available.first { $0.id == MLXSwiftSettingsKeys.defaultModelId }","violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"line":20,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/OnDeviceAIDownloadView.swift"},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" Text(\"To use on-device AI, we need to download two models to your device. Downloads will continue in the background.\")","violation":{"ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/OnDeviceAIDownloadView.swift","line":65},"reason":"Line should be 120 characters or less; currently it has 134 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length"}},{"text":" Text(\"You can close this screen and use the app. You'll receive a notification when both models are ready.\")","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 128 characters","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/OnDeviceAIDownloadView.swift","line":117,"character":1}}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/OnDeviceAIDownloadView.swift","line":147,"character":20},"reason":"Trailing closure syntax should not be used when passing more than one closure argument","severity":"warning","ruleIdentifier":"multiple_closures_with_trailing_closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" AppLog.shared.summarization(\"OnDeviceAIDownload: Starting MLX \\(mlxModel.displayName) download...\", level: .debug)","violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/OnDeviceAIDownloadView.swift","line":215},"severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 126 characters","ruleIdentifier":"line_length","ruleName":"Line Length"}},{"text":" }) {","violation":{"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","location":{"character":24,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/PreferencesView.swift","line":91},"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/PreferencesView.swift","line":115,"character":12}}},{"text":" .background(userPreferences.timeFormat == format ? Color.blue.opacity(0.12) : Color(.tertiarySystemGroupedBackground))","violation":{"ruleName":"Line Length","severity":"warning","location":{"character":1,"line":146,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/PreferencesView.swift"},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 130 characters","ruleIdentifier":"line_length"}},{"text":"struct RecordingsListView: View {","violation":{"ruleIdentifier":"type_body_length","severity":"error","reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 1369 lines","location":{"character":1,"line":19,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift"},"ruleName":"Type Body Length","ruleDescription":"Type bodies should not span too many lines"}},{"text":" await deleteRecordingWithRelationships(recording, preserveSummary: preserveSummaryOnDelete)","violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 123 characters","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":109},"severity":"warning"}},{"text":" let recommendedRecording = recommended == recordings.first.url ? recordings.first : recordings.second","violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","character":1,"line":164},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" archiveExportURLs = RecordingArchiveService.shared.prepareArchiveExportURLs(for: recordingsToArchive)","violation":{"severity":"warning","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":182,"character":1},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" archiveRestoreError = \"The export completed, but the selected destination was not iCloud Drive or was not trackable. The audio was left local so you can archive it again to iCloud Drive.\"","violation":{"severity":"error","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 200 characters or less; currently it has 215 characters","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":206}}},{"text":" let skippedText = audioExportSkippedCount == 1 ? \"1 selected recording was\" : \"\\(audioExportSkippedCount) selected recordings were\"","violation":{"reason":"Line should be 120 characters or less; currently it has 159 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":222}}},{"text":" archiveRestoreError = \"\\(skippedText) not exported because the audio is not stored locally. Restore archived audio before exporting it.\"","violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 164 characters","location":{"line":223,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift"},"ruleIdentifier":"line_length"}},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 127 characters","ruleName":"Line Length","location":{"character":1,"line":246,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift"},"ruleIdentifier":"line_length"},"text":" let locationText = location.map { \"\\nSaved location: \\($0.providerDisplayName) \/ \\($0.displayName)\" } ?? \"\""},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"error","ruleName":"Line Length","location":{"character":1,"line":247,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift"},"reason":"Line should be 200 characters or less; currently it has 231 characters","ruleIdentifier":"line_length"},"text":" Text(\"\\(note)\\(dateStr.isEmpty ? \"\" : \" on \\(dateStr)\")\\(locationText)\\n\\nThe audio file is no longer stored locally. Use the download button to restore it, or use \\\"Import Audio Files\\\" if the file was moved.\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 129 characters","severity":"warning","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":261}},"text":" EditableTranscriptView(recording: entry, transcript: transcript, transcriptManager: TranscriptManager.shared)"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"line":276,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift"},"reason":"Line should be 120 characters or less; currently it has 129 characters","ruleName":"Line Length","severity":"warning"},"text":" transcriptionStarter.startTranscription(for: recording, cleanFirst: true, appCoordinator: appCoordinator)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":282},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 130 characters"},"text":" transcriptionStarter.startTranscription(for: recording, cleanFirst: false, appCoordinator: appCoordinator)"},{"violation":{"ruleName":"Line Length","location":{"line":289,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift"},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 152 characters"},"text":" Text(\"Cleaning reduces static and normalizes volume, which can improve transcription accuracy. The original audio file is not changed.\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","character":1,"line":313},"reason":"Line should be 120 characters or less; currently it has 128 characters"},"text":" .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(\"RecordingCloudSyncPreferenceChanged\"))) { _ in"},{"violation":{"ruleIdentifier":"multiple_closures_with_trailing_closure","reason":"Trailing closure syntax should not be used when passing more than one closure argument","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","character":55,"line":406},"ruleName":"Multiple Closures with Trailing Closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","severity":"warning"},"text":" Button(action: { showDateFilter = true }) {"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 134 characters","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","character":1,"line":407},"ruleDescription":"Lines should not span too many characters."},"text":" Image(systemName: isDateFilterActive ? \"line.3.horizontal.decrease.circle.fill\" : \"line.3.horizontal.decrease.circle\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 133 characters","ruleIdentifier":"line_length","location":{"line":410,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","character":1},"severity":"warning","ruleName":"Line Length"},"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 10, style: .continuous))"},{"violation":{"location":{"line":421,"character":24,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift"},"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument"},"text":" }) {"},{"violation":{"severity":"warning","ruleIdentifier":"multiple_closures_with_trailing_closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","location":{"line":431,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","character":20},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"},"text":" }) {"},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","ruleIdentifier":"multiple_closures_with_trailing_closure","severity":"warning","reason":"Trailing closure syntax should not be used when passing more than one closure argument","location":{"line":440,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","character":20},"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","location":{"character":20,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":446},"ruleIdentifier":"multiple_closures_with_trailing_closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 10, style: .continuous))","violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":453},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" }) {","violation":{"ruleIdentifier":"multiple_closures_with_trailing_closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","severity":"warning","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","location":{"line":459,"character":16,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift"}}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 10, style: .continuous))","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 133 characters","ruleDescription":"Lines should not span too many characters.","location":{"line":463,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","character":1}}},{"text":" return \"No recordings found between \\(dateFilterStart.formatted(date: .abbreviated, time: .omitted)) and \\(dateFilterEnd.formatted(date: .abbreviated, time: .omitted)).\"","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 181 characters","location":{"line":545,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","character":1},"ruleIdentifier":"line_length"}},{"text":" Text(\"\\(dateFilterStart, format: .dateTime.month().day()) - \\(dateFilterEnd, format: .dateTime.month().day())\")","violation":{"location":{"line":555,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift"},"reason":"Line should be 120 characters or less; currently it has 123 characters","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":" }) {","violation":{"ruleIdentifier":"multiple_closures_with_trailing_closure","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","character":16,"line":561}}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 12, style: .continuous))","violation":{"reason":"Line should be 120 characters or less; currently it has 121 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":567}}},{"text":" DatePicker(\"To\", selection: $dateFilterEnd, in: dateFilterStart...Date(), displayedComponents: .date)","violation":{"severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","character":1,"line":579},"reason":"Line should be 120 characters or less; currently it has 125 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 14, style: .continuous))","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 133 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"line":582,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift"}}},{"text":" private func recordingRow(for recording: AudioRecordingFile) -> some View {","violation":{"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 83 lines","ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","character":13,"line":648},"severity":"warning"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"character":1,"line":742,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift"},"reason":"Line should be 120 characters or less; currently it has 121 characters","ruleIdentifier":"line_length"}},{"text":" Label(\"\\(location.providerDisplayName) \/ \\(location.displayName)\", systemImage: \"externaldrive.badge.checkmark\")","violation":{"severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 132 characters","location":{"line":832,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift"},"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"}},{"text":" private func recordingActionButtons(for recording: AudioRecordingFile) -> some View {","violation":{"ruleName":"Function Body Length","ruleIdentifier":"function_body_length","location":{"line":848,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 65 lines","severity":"warning","ruleDescription":"Function bodies should not span too many lines"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","location":{"character":16,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":863},"ruleIdentifier":"multiple_closures_with_trailing_closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","reason":"Trailing closure syntax should not be used when passing more than one closure argument","severity":"warning"}},{"text":" .background(Color.accentColor.opacity(0.12), in: RoundedRectangle(cornerRadius: 10, style: .continuous))","violation":{"reason":"Line should be 120 characters or less; currently it has 128 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","character":1,"line":871}}},{"text":" private func transcriptActionButton(for recording: AudioRecordingFile) -> some View {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 51 lines","ruleIdentifier":"function_body_length","location":{"line":958,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift"}}},{"text":" let jobStatus = transcriptionStarter.activeTranscriptionJobStatus(for: entry, appCoordinator: appCoordinator)","violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":965},"reason":"Line should be 120 characters or less; currently it has 121 characters","ruleIdentifier":"line_length","ruleName":"Line Length"}},{"text":" }) {","violation":{"reason":"Trailing closure syntax should not be used when passing more than one closure argument","location":{"character":16,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":982},"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure"}},{"text":" let endOfDay = Calendar.current.date(bySettingHour: 23, minute: 59, second: 59, of: dateFilterEnd) ?? dateFilterEnd","violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"line":1044,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift"},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 127 characters","ruleIdentifier":"line_length"}},{"text":" private func loadRecordings() {","violation":{"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 70 lines","ruleDescription":"Function bodies should not span too many lines","severity":"warning","ruleIdentifier":"function_body_length","ruleName":"Function Body Length","location":{"line":1063,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift"}}},{"text":" var bestByFilename: [String: (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)] = [:]","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":1068,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length"}},{"text":" var bestByFilename: [String: (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)] = [:]","violation":{"severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleName":"Large Tuple","location":{"line":1068,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","character":38},"reason":"Tuples should have at most 2 members","ruleIdentifier":"large_tuple"}},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 121 characters","location":{"line":1070,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","character":1},"ruleName":"Line Length"},"text":" func score(_ e: (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)) -> Int {"},{"violation":{"ruleName":"Identifier Name","reason":"Variable name 'e' should be between 3 and 40 characters long","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","severity":"error","location":{"character":22,"line":1070,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift"}},"text":" func score(_ e: (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)) -> Int {"},{"violation":{"reason":"Tuples should have at most 2 members","location":{"character":25,"line":1070,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift"},"ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","ruleName":"Large Tuple","severity":"warning"},"text":" func score(_ e: (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)) -> Int {"},{"violation":{"reason":"Variable name 's' should be between 3 and 40 characters long","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","ruleName":"Identifier Name","severity":"error","location":{"line":1071,"character":17,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift"}},"text":" var s = 0"},{"violation":{"ruleIdentifier":"unused_optional_binding","ruleDescription":"Prefer `!= nil` over `let _ =`","ruleName":"Unused Optional Binding","severity":"warning","location":{"line":1214,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","character":23},"reason":"Prefer `!= nil` over `let _ =`"},"text":" guard let _ = recording.locationData else { return false }"},{"violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 121 characters","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":1346,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift"},"severity":"warning","ruleIdentifier":"line_length"},"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 12, style: .continuous))"},{"violation":{"ruleName":"Line Length","severity":"error","reason":"Line should be 200 characters or less; currently it has 203 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"line":1408,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift"}},"text":" message: \"These recordings cannot be combined because:\\n\\n\\(issues.joined(separator: \"\\n\"))\\n\\nPlease delete the transcripts and\/or summaries from both recordings before combining them.\","},{"violation":{"reason":"Line should be 120 characters or less; currently it has 125 characters","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"line":1495,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift"}},"text":" archiveRestoreError = \"No local audio files are available to export. Restore archived audio before exporting it.\""},{"violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","character":20,"line":1554},"reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument"},"text":" }) {"},{"violation":{"location":{"line":1578,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","character":1},"severity":"error","reason":"File should contain 1000 lines or less: currently contains 1578","ruleIdentifier":"file_length","ruleDescription":"Files should not span too many lines.","ruleName":"File Length"},"text":"}"},{"violation":{"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 572 lines","ruleIdentifier":"type_body_length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleName":"Type Body Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsView.swift","line":13,"character":1}},"text":"struct RecordingsView: View {"},{"violation":{"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","location":{"character":57,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsView.swift","line":118},"reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","severity":"warning"},"text":" Button(action: { recorderVM.startRecording() }) {"},{"violation":{"ruleIdentifier":"multiple_closures_with_trailing_closure","ruleName":"Multiple Closures with Trailing Closure","location":{"character":28,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsView.swift","line":192},"severity":"warning","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument"},"text":" }) {"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"character":1,"line":315,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsView.swift"},"reason":"Line should be 120 characters or less; currently it has 132 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" AudioDocumentPicker(isPresented: $documentPickerCoordinator.isShowingPicker, coordinator: documentPickerCoordinator)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"line":318,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsView.swift"},"reason":"Line should be 120 characters or less; currently it has 139 characters","severity":"warning","ruleName":"Line Length"},"text":" TextDocumentPicker(isPresented: $textDocumentPickerCoordinator.isShowingPicker, coordinator: textDocumentPickerCoordinator)"},{"violation":{"severity":"warning","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"character":1,"line":377,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsView.swift"},"reason":"Line should be 120 characters or less; currently it has 121 characters"},"text":" .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(\"ImportTranscriptFromMenu\"))) { _ in"},{"violation":{"ruleIdentifier":"multiple_closures_with_trailing_closure","severity":"warning","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","location":{"character":12,"line":510,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsView.swift"},"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument"},"text":" }) {"},{"violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsView.swift","line":617,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters","ruleIdentifier":"line_length"},"text":" return \"Call ended (\\(Int(duration\/60))m \\(Int(duration.truncatingRemainder(dividingBy: 60)))s) - Choose action\""},{"violation":{"ruleDescription":"Files should not span too many lines.","severity":"warning","ruleIdentifier":"file_length","reason":"File should contain 400 lines or less: currently contains 662","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsView.swift","character":1,"line":662},"ruleName":"File Length"},"text":"\/\/ SafariView is now in Views\/SafariView.swift"},{"violation":{"ruleDescription":"Type bodies should not span too many lines","severity":"error","location":{"line":15,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift"},"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 1322 lines","ruleIdentifier":"type_body_length","ruleName":"Type Body Length"},"text":"struct SettingsView: View {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 200 characters or less; currently it has 351 characters","ruleName":"Line Length","severity":"error","ruleIdentifier":"line_length","location":{"character":1,"line":85,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift"}},"text":" Text(\"BisonNotes AI and uploads to iCloud are not HIPAA-compliant. When iCloud Sync is enabled, eligible recordings, transcripts, summaries, and selected settings may be uploaded to your private iCloud account. To exclude an item from BisonNotes iCloud sync and backup, mark it Keep on This Device from its recording row or audio player.\")"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"line":92,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift"},"reason":"Line should be 200 characters or less; currently it has 215 characters","severity":"error"},"text":" message: Text(\"BisonNotes needs macOS Screen Recording permission to capture audio playing from other Mac apps during a recording. BisonNotes records audio only and does not save screen video.\"),"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"error","location":{"line":103,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","character":1},"ruleIdentifier":"line_length","reason":"Line should be 200 characters or less; currently it has 324 characters","ruleName":"Line Length"},"text":" message: Text(\"macOS did not grant Screen Recording permission, so BisonNotes will keep recording microphone audio only. Enable BisonNotes in System Settings > Privacy & Security > Screen & System Audio Recording, then return to BisonNotes. You may need to restart the app after changing this setting.\"),"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 126 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":138,"character":1}},"text":" let currentModelId = UserDefaults.standard.string(forKey: OnDeviceLLMModelInfo.SettingsKeys.selectedModelId) ?? \"\""},{"text":" ModernStatusPill(text: iCloudManager.isEnabled ? \"Enabled\" : \"Disabled\", tint: iCloudManager.isEnabled ? .green : .secondary)","violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"line":370,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters","ruleIdentifier":"line_length"}},{"text":" ) {","violation":{"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","severity":"warning","location":{"line":372,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","character":11},"ruleIdentifier":"multiple_closures_with_trailing_closure"}},{"text":" Text(\"API keys and AWS credentials stay in Keychain and are never included in iCloud settings backups. Leave sensitive settings off unless you explicitly want eligible future sensitive preferences copied to iCloud.\")","violation":{"reason":"Line should be 200 characters or less; currently it has 232 characters","location":{"line":389,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift"},"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"error"}},{"text":" Text(\"Exposes experimental on-device models. Experimental models are less reliable and may produce empty summaries.\")","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":521,"character":1},"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 129 characters","ruleName":"Line Length"}},{"text":" Image(systemName: recorderVM.selectedInput?.uid == input.uid ? \"largecircle.fill.circle\" : \"circle\")","violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 128 characters","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":662},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"text":" Text(\"API keys and AWS credentials stay in Keychain and are never included in iCloud settings backups. Leave sensitive settings off unless you explicitly want eligible future sensitive preferences copied to iCloud.\")","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","character":1,"line":782},"severity":"error","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 200 characters or less; currently it has 232 characters"}},{"text":" message: \"We found \\(cloudOnlySummaries.count) summaries in your iCloud that aren't on this device. Would you like to download them?\",","violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 174 characters","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"line":884,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","character":1}}},{"text":" let count = try await iCloudManager.downloadSummariesFromCloud(appCoordinator: appCoordinator, forRecovery: true)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 161 characters","ruleIdentifier":"line_length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":891}}},{"text":" AppLog.shared.log(\"Downloaded \\(count) summaries from iCloud\", category: .general)","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"line":892,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","character":1},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" AppLog.shared.log(\"Failed to download summaries: \\(error)\", level: .error, category: .general)","violation":{"location":{"line":894,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 142 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length"}},{"text":" AppLog.shared.log(\"Failed to check for iCloud data: \\(error)\", level: .error, category: .general)","violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":918},"reason":"Line should be 120 characters or less; currently it has 125 characters","ruleIdentifier":"line_length","severity":"warning"}},{"text":" Text(\"Make AI summaries entertaining with a comedic twist. All information is preserved β€” just delivered with flair.\")","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 130 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"line":977,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","character":1},"ruleIdentifier":"line_length"}},{"violation":{"reason":"Line should be 200 characters or less; currently it has 224 characters","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","character":1,"line":985},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"error"},"text":" Text(\"Exposes experimental models in the On Device AI (Legacy) engine and the smaller Ternary Bonsai 1.7B model in the On Device AI engine. Experimental models are less reliable and may produce empty summaries.\")"},{"violation":{"location":{"character":31,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":1039},"ruleIdentifier":"multiple_closures_with_trailing_closure","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","severity":"warning"},"text":" ) {"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":1221},"reason":"Line should be 120 characters or less; currently it has 123 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" guard let url = URL(string: \"x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture\") else {"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 200 characters or less; currently it has 244 characters","severity":"error","location":{"line":1285,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift"}},"text":" \"Backup complete: \\(result.recordingsBackedUp) recordings, \\(result.transcriptsBackedUp) transcripts, \\(result.summariesBackedUp) summaries, \\(result.audioFilesBackedUp) audio uploaded\\(unchangedAudioText), \\(settingsText).\""},{"violation":{"severity":"error","reason":"Line should be 200 characters or less; currently it has 234 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":1325},"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."},"text":" \"Restore complete: \\(result.recordingsRestored) recordings, \\(result.transcriptsRestored) transcripts, \\(result.summariesRestored) summaries, \\(result.audioFilesRestored) audio files, \\(settingsText)\\(reviewText).\""},{"violation":{"ruleIdentifier":"function_body_length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","character":13,"line":1338},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 59 lines","ruleName":"Function Body Length"},"text":" private func checkForiCloudData() {"},{"violation":{"severity":"warning","location":{"line":1351,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift"},"reason":"Line should be 120 characters or less; currently it has 162 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" message: \"We found \\(cloudOnlySummaries.count) summaries in your iCloud that aren't on this device. Would you like to download them?\","},{"violation":{"ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":1358,"character":1},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 149 characters","ruleIdentifier":"line_length"},"text":" let count = try await iCloudManager.downloadSummariesFromCloud(appCoordinator: appCoordinator, forRecovery: true)"},{"violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 130 characters","location":{"line":1361,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift"},"ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.log(\"Failed to download summaries: \\(error)\", level: .error, category: .general)"},{"violation":{"reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","ruleIdentifier":"multiple_closures_with_trailing_closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":1418,"character":23}},"text":" ) {"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","location":{"line":1593,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift"},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 158 characters"},"text":" Text(\"This removes app-created iCloud sync records for the selected item. It does not delete anything already stored locally on this device.\")"},{"violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 165 characters","location":{"line":1620,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","character":1}},"text":" actionMessage = \"Restored \\(result.recordingsRestored) recordings, \\(result.transcriptsRestored) transcripts, \\(result.summariesRestored) summaries.\""},{"text":"}","violation":{"ruleIdentifier":"file_length","ruleDescription":"Files should not span too many lines.","severity":"error","reason":"File should contain 1000 lines or less: currently contains 1949","ruleName":"File Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","character":1,"line":1949}}},{"text":"struct SimpleSettingsView: View {","violation":{"ruleDescription":"Type bodies should not span too many lines","severity":"error","ruleIdentifier":"type_body_length","ruleName":"Type Body Length","location":{"line":73,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift"},"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 500 lines"}},{"text":" if isShowing, let url = URL(string: \"https:\/\/www.bisonnetworking.com\/bisonnotes-ai\/#simple-vs-advanced-settings\") {","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 127 characters","severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":171,"character":1}}},{"text":" NotificationCenter.default.post(name: NSNotification.Name(\"RequestLocationPermission\"), object: nil)","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 124 characters","severity":"warning","location":{"character":1,"line":193,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift"}}},{"text":" }) {","violation":{"severity":"warning","ruleName":"Multiple Closures with Trailing Closure","location":{"character":16,"line":227,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift"},"reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure"}},{"text":" Text(\"On-Device AI requires 6GB+ RAM. Your device has \\(String(format: \"%.1f\", DeviceCapabilities.totalRAMInGB))GB RAM.\")","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","character":1,"line":313},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" subtitle: \"Free cloud AI with transcription and summaries. No credit card required -- just create an account.\",","violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":351},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 127 characters","ruleIdentifier":"line_length"}},{"text":" subtitle: \"Configure providers manually from app settings. Existing provider configuration is preserved.\",","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 122 characters","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","character":1,"line":380},"ruleDescription":"Lines should not span too many characters."}},{"text":" }) {","violation":{"location":{"line":397,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","character":16},"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","severity":"warning","reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure"}},{"text":" let transcriptionEngine = UserDefaults.standard.string(forKey: \"selectedTranscriptionEngine\") ?? \"Not Configured\"","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":503,"character":1},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 121 characters","ruleIdentifier":"line_length"}},{"text":" else if transcriptionEngine == TranscriptionEngine.fluidAudio.rawValue && aiEngine == AIEngineType.onDeviceLLM.rawValue {","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":515},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" else if transcriptionEngine == TranscriptionEngine.fluidAudio.rawValue && aiEngine == AIEngineType.appleNative.rawValue {","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 129 characters","location":{"line":519,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","character":1}}},{"violation":{"ruleIdentifier":"cyclomatic_complexity","ruleDescription":"Complexity of function bodies should be limited.","ruleName":"Cyclomatic Complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":528,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 14","severity":"warning"},"text":" private func saveConfiguration() {"},{"violation":{"ruleDescription":"Function bodies should not span too many lines","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":528,"character":13},"ruleIdentifier":"function_body_length","reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 105 lines","ruleName":"Function Body Length"},"text":" private func saveConfiguration() {"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 125 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":588},"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters."},"text":" UserDefaults.standard.set(TranscriptionEngine.fluidAudio.rawValue, forKey: \"selectedTranscriptionEngine\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":610,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters","severity":"warning"},"text":" UserDefaults.standard.set(MLXSwiftSettingsKeys.defaultModelId, forKey: MLXSwiftSettingsKeys.modelId)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 126 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":638,"character":1}},"text":" NotificationCenter.default.post(name: NSNotification.Name(\"FirstSetupCompleted\"), object: nil)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":641},"ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 136 characters"},"text":" NotificationCenter.default.post(name: NSNotification.Name(\"RequestLocationPermission\"), object: nil)"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","location":{"line":654,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","character":1},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 122 characters","severity":"warning"},"text":" NotificationCenter.default.post(name: NSNotification.Name(\"FirstSetupCompleted\"), object: nil)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 132 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":657,"character":1}},"text":" NotificationCenter.default.post(name: NSNotification.Name(\"RequestLocationPermission\"), object: nil)"},{"violation":{"ruleName":"File Length","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","severity":"warning","reason":"File should contain 400 lines or less: currently contains 829","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":829}},"text":"}"},{"violation":{"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 1139 lines","ruleIdentifier":"type_body_length","severity":"error","ruleName":"Type Body Length","ruleDescription":"Type bodies should not span too many lines","location":{"character":1,"line":25,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift"}},"text":"struct TranscriptsView: View {"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 129 characters","ruleIdentifier":"line_length","severity":"warning","location":{"line":61,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","character":1},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" EditableTranscriptView(recording: recording, transcript: transcript, transcriptManager: TranscriptManager.shared)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","location":{"line":81,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift"},"reason":"Line should be 120 characters or less; currently it has 125 characters"},"text":" transcriptionStarter.startTranscription(for: recording, cleanFirst: true, appCoordinator: appCoordinator)"},{"text":" transcriptionStarter.startTranscription(for: recording, cleanFirst: false, appCoordinator: appCoordinator)","violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 126 characters","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":87}}},{"text":" Text(\"Cleaning reduces static and normalizes volume, which can improve transcription accuracy. The original audio file is not changed.\")","violation":{"reason":"Line should be 120 characters or less; currently it has 148 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","character":1,"line":94}}},{"text":" Text(completedTranscriptionText.isEmpty ? \"A background transcription has completed. The transcript is now available for editing.\" : completedTranscriptionText)","violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 172 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":102,"character":1},"ruleIdentifier":"line_length"}},{"text":" Button(action: { showDateFilter = true }) {","violation":{"ruleIdentifier":"multiple_closures_with_trailing_closure","severity":"warning","location":{"line":130,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","character":59},"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" Image(systemName: isDateFilterActive ? \"line.3.horizontal.decrease.circle.fill\" : \"line.3.horizontal.decrease.circle\")","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":131},"reason":"Line should be 120 characters or less; currently it has 138 characters","ruleName":"Line Length"}},{"text":" return \"No transcripts found between \\(dateFilterStart.formatted(date: .abbreviated, time: .omitted)) and \\(dateFilterEnd.formatted(date: .abbreviated, time: .omitted)).\"","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"line":236,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift"},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 182 characters"}},{"text":" Text(\"\\(dateFilterStart, format: .dateTime.month().day()) - \\(dateFilterEnd, format: .dateTime.month().day())\")","violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":246},"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" }) {","violation":{"ruleIdentifier":"multiple_closures_with_trailing_closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","location":{"line":252,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","character":16},"severity":"warning","ruleName":"Multiple Closures with Trailing Closure","reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" DatePicker(\"To\", selection: $dateFilterEnd, in: dateFilterStart...Date(), displayedComponents: .date)","violation":{"reason":"Line should be 120 characters or less; currently it has 121 characters","location":{"line":267,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","character":1},"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" private func transcriptsListView(_ filtered: [(recording: RecordingEntry, transcript: TranscriptData?)], _ filteredImported: [(recording: RecordingEntry, transcript: TranscriptData?)]) -> some View {","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"error","reason":"Line should be 200 characters or less; currently it has 203 characters","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","character":1,"line":305}}},{"text":" private func transcriptsListView(_ filtered: [(recording: RecordingEntry, transcript: TranscriptData?)], _ filteredImported: [(recording: RecordingEntry, transcript: TranscriptData?)]) -> some View {","violation":{"ruleDescription":"Function bodies should not span too many lines","location":{"character":13,"line":305,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift"},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 80 lines","ruleIdentifier":"function_body_length","severity":"warning","ruleName":"Function Body Length"}},{"text":" transcriptItemsWithDates(filtered, source: .audio) + transcriptItemsWithDates(filteredImported, source: .imported),","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":310,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"}},{"text":" recordingRowView((recording: itemWithDate.recording, transcript: itemWithDate.transcript))","violation":{"reason":"Line should be 120 characters or less; currently it has 122 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"line":431,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","character":1},"ruleIdentifier":"line_length","severity":"warning"}},{"text":" Button(action: { showDateFilter = true }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","location":{"line":447,"character":59,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift"},"reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","severity":"warning"}},{"text":" Image(systemName: isDateFilterActive ? \"line.3.horizontal.decrease.circle.fill\" : \"line.3.horizontal.decrease.circle\")","violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":448,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" importedTranscriptRowView((recording: itemWithDate.recording, transcript: itemWithDate.transcript))","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","character":1,"line":488},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" Button(action: { showDateFilter = true }) {","violation":{"severity":"warning","ruleIdentifier":"multiple_closures_with_trailing_closure","ruleName":"Multiple Closures with Trailing Closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","location":{"character":59,"line":511,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift"},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" Image(systemName: isDateFilterActive ? \"line.3.horizontal.decrease.circle.fill\" : \"line.3.horizontal.decrease.circle\")","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":512,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters","severity":"warning"}},{"text":" private func recordingRowView(_ recordingData: (recording: RecordingEntry, transcript: TranscriptData?)) -> some View {","violation":{"ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":623},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" private func importedTranscriptRowView(","violation":{"ruleName":"Function Body Length","severity":"warning","ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 57 lines","location":{"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":652}}},{"text":" }) {","violation":{"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","reason":"Trailing closure syntax should not be used when passing more than one closure argument","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":659,"character":16},"ruleIdentifier":"multiple_closures_with_trailing_closure"}},{"text":" private func recordingInfoView(_ recordingData: (recording: RecordingEntry, transcript: TranscriptData?)) -> some View {","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":755,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift"},"reason":"Line should be 120 characters or less; currently it has 124 characters","ruleName":"Line Length","ruleIdentifier":"line_length"}},{"text":" }) {","violation":{"location":{"line":794,"character":12,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift"},"reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleName":"Multiple Closures with Trailing Closure","severity":"warning"}},{"text":" private func transcriptButtonView(_ recordingData: (recording: RecordingEntry, transcript: TranscriptData?)) -> some View {","violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 127 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","location":{"line":808,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","character":1}}},{"violation":{"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"line":810,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift"},"reason":"Line should be 120 characters or less; currently it has 135 characters","ruleName":"Line Length"},"text":" let hasActiveJob = transcriptionStarter.hasActiveTranscriptionJob(for: recordingData.recording, appCoordinator: appCoordinator)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 135 characters","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"character":1,"line":814,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift"}},"text":" let jobStatus = transcriptionStarter.activeTranscriptionJobStatus(for: recordingData.recording, appCoordinator: appCoordinator)"},{"violation":{"location":{"line":827,"character":12,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift"},"reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument"},"text":" }) {"},{"violation":{"ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","character":1,"line":833},"ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 133 characters","ruleDescription":"Lines should not span too many characters."},"text":" Text(processingButtonLabel(isCleaning: isCleaning, isQueuedForCleanup: isQueuedForCleanup, jobStatus: jobStatus))"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 156 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"character":1,"line":855,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift"}},"text":" .id(\"\\(recordingData.recording.id?.uuidString ?? \"unknown\")-\\(hasTranscript)-\\(hasActiveJob)-\\(isCleaning)-\\(isQueuedForCleanup)-\\(refreshTrigger)\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 127 characters","ruleName":"Line Length","location":{"character":1,"line":859,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift"}},"text":" private func processingButtonLabel(isCleaning: Bool, isQueuedForCleanup: Bool, jobStatus: JobProcessingStatus?) -> String {"},{"violation":{"severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":886,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters","ruleDescription":"Lines should not span too many characters."},"text":" private func summaryButtonView(_ recordingData: (recording: RecordingEntry, transcript: TranscriptData?)) -> some View {"},{"violation":{"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":901,"character":16},"reason":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","severity":"warning","ruleName":"Multiple Closures with Trailing Closure"},"text":" }) {"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"line":983,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"},"text":" AppLog.shared.summarization(\"Failed to queue summary job from TranscriptsView row: \\(error)\", level: .error)"},{"violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 163 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1001}},"text":" private func applyFilters(to items: [(recording: RecordingEntry, transcript: TranscriptData?)]) -> [(recording: RecordingEntry, transcript: TranscriptData?)] {"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1007,"character":1},"severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 127 characters","ruleDescription":"Lines should not span too many characters."},"text":" let endOfDay = Calendar.current.date(bySettingHour: 23, minute: 59, second: 59, of: dateFilterEnd) ?? dateFilterEnd"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","character":1,"line":1027},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 136 characters","ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length"},"text":" private func matchesSearch(_ recordingData: (recording: RecordingEntry, transcript: TranscriptData?), searchTerms: String) -> Bool {"},{"text":"\t\t\tvar s = 0","violation":{"location":{"character":8,"line":1061,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift"},"ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","severity":"error","reason":"Variable name 's' should be between 3 and 40 characters long","ruleIdentifier":"identifier_name","ruleName":"Identifier Name"}},{"text":"\t\tfor rd in recordingsWithData {","violation":{"ruleIdentifier":"identifier_name","ruleName":"Identifier Name","severity":"warning","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","location":{"line":1069,"character":7,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift"},"reason":"Variable name 'rd' should be between 3 and 40 characters long"}},{"text":"\t\tlet (imported, regular) = deduped.reduce(into: (imported: [(RecordingEntry, TranscriptData?)](), regular: [(RecordingEntry, TranscriptData?)]())) { result, item in","violation":{"ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","character":1,"line":1090},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 165 characters","ruleDescription":"Lines should not span too many characters."}},{"text":" let _ = appCoordinator.loadLocationData(for: recording) else { return false }","violation":{"reason":"Prefer `!= nil` over `let _ =`","ruleIdentifier":"unused_optional_binding","ruleDescription":"Prefer `!= nil` over `let _ =`","ruleName":"Unused Optional Binding","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1186,"character":23}}},{"text":" guard !transcriptionStarter.hasActiveTranscriptionJob(for: recording, appCoordinator: appCoordinator) else { return }","violation":{"ruleName":"Line Length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1232},"reason":"Line should be 120 characters or less; currently it has 125 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"}},{"text":" private func setupTranscriptionCompletionCallback() {","violation":{"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 89 lines","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1239,"character":13},"ruleIdentifier":"function_body_length"}},{"text":" AppLog.shared.transcription(\"Background transcript already saved by BackgroundProcessingManager\", level: .debug)","violation":{"ruleName":"Line Length","location":{"line":1277,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift"},"reason":"Line should be 120 characters or less; currently it has 132 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning"}},{"text":" self.completedTranscriptionText = \"Transcription completed for: \\(recording.recording.recordingName ?? \"Unknown Recording\")\"","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1289,"character":1},"reason":"Line should be 120 characters or less; currently it has 148 characters","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.transcription(\"Background transcription completed, available recordings: \\(recordings.count)\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","character":1,"line":1301},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" AppLog.shared.transcription(\"Background transcript saved to Core Data with ID: \\(transcriptId!)\")","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","location":{"character":1,"line":1338,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift"},"reason":"Line should be 120 characters or less; currently it has 121 characters","ruleName":"Line Length"}},{"text":" self.completedTranscriptionText = \"Transcription completed for: \\(recording.recording.recordingName ?? \"Unknown Recording\")\"","violation":{"reason":"Line should be 120 characters or less; currently it has 148 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"character":1,"line":1351,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift"}}},{"text":"struct EditableTranscriptView: View {","violation":{"ruleIdentifier":"type_body_length","ruleName":"Type Body Length","ruleDescription":"Type bodies should not span too many lines","severity":"error","location":{"line":1362,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","character":1},"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 511 lines"}},{"violation":{"ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","severity":"error","ruleName":"Identifier Name","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","character":17,"line":1391},"reason":"Variable name 's' should be between 3 and 40 characters long"},"text":" let s = seg.speaker"},{"violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1517},"reason":"Line should be 120 characters or less; currently it has 169 characters","ruleIdentifier":"line_length"},"text":" Text(\"This will replace the current transcript with a new transcription using the currently configured transcription service. This action cannot be undone.\")"},{"violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","character":1,"line":1568},"ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 131 characters"},"text":" .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(\"TranscriptionRerunCompleted\"))) { notification in"},{"violation":{"location":{"character":1,"line":1579,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift"},"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 121 characters","ruleIdentifier":"line_length","ruleName":"Line Length"},"text":" NotificationCenter.default.post(name: NSNotification.Name(\"TranscriptReplacementCompleted\"), object: nil)"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 127 characters","location":{"line":1698,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift"}},"text":" AppLog.shared.summarization(\"Failed to queue summary job from EditableTranscriptView: \\(error)\", level: .error)"},{"violation":{"ruleName":"Line Length","severity":"warning","location":{"line":1771,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.transcription(\"Failed to update recording title from transcript editor: \\(error)\", level: .error)"},{"violation":{"ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","character":13,"line":1776},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 52 lines","ruleIdentifier":"function_body_length"},"text":" private func rerunTranscription() {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","location":{"character":1,"line":1784,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift"},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 193 characters"},"text":" let selectedEngine = TranscriptionEngine(rawValue: UserDefaults.standard.string(forKey: \"selectedTranscriptionEngine\") ?? TranscriptionEngine.fluidAudio.rawValue) ?? .fluidAudio"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 129 characters","severity":"warning","location":{"line":1797,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift"},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" AppLog.shared.transcription(\"Rerunning transcription for file: \\(recordingURL.lastPathComponent)\", level: .debug)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 124 characters","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","character":1,"line":1818}},"text":" AppLog.shared.transcription(\"Invalid recording URL for fallback transcription rerun\", level: .error)"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 197 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1826}},"text":" let selectedEngine = TranscriptionEngine(rawValue: UserDefaults.standard.string(forKey: \"selectedTranscriptionEngine\") ?? TranscriptionEngine.fluidAudio.rawValue) ?? .fluidAudio"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1828,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"},"text":" let result = try await enhancedTranscriptionManager.transcribeAudioFile(at: recordingURL, using: selectedEngine)"},{"text":" AppLog.shared.transcription(\"Transcription rerun result: success=\\(result.success), textLength=\\(result.fullText.count)\", level: .debug)","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 156 characters","location":{"line":1830,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift"},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" NotificationCenter.default.post(name: NSNotification.Name(\"TranscriptReplacementCompleted\"), object: nil)","violation":{"reason":"Line should be 120 characters or less; currently it has 133 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"line":1840,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift"},"severity":"warning"}},{"text":" AppLog.shared.transcription(\"Transcription rerun failed or returned empty result\", level: .error)","violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 121 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"line":1843,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","character":1}}},{"text":" let engineString = UserDefaults.standard.string(forKey: \"selectedTranscriptionEngine\") ?? TranscriptionEngine.fluidAudio.rawValue","violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 141 characters","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1912,"character":1},"severity":"warning","ruleName":"Line Length"}},{"text":" AppLog.shared.transcription(\"Could not find recording entry in Core Data for transcript save\", level: .error)","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","character":1,"line":1937},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" let hasValidContent = updatedTranscript.segments.contains { !$0.text.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines).isEmpty }","violation":{"ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1955,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning"}},{"text":" let s = segment.speaker","violation":{"reason":"Variable name 's' should be between 3 and 40 characters long","ruleName":"Identifier Name","ruleIdentifier":"identifier_name","severity":"error","location":{"line":1976,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift"},"ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short."}},{"text":" let s = segment.speaker","violation":{"reason":"Variable name 's' should be between 3 and 40 characters long","ruleIdentifier":"identifier_name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleName":"Identifier Name","severity":"error","location":{"line":1985,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","character":13}}},{"text":" set: { segment = TranscriptSegment(speaker: segment.speaker, text: $0, startTime: segment.startTime, endTime: segment.endTime) }","violation":{"ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":2029,"character":1},"reason":"Line should be 120 characters or less; currently it has 144 characters","ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 121 characters","location":{"line":2046,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","character":1},"ruleName":"Line Length","severity":"warning"}},{"text":" Section(header: Text(\"Rename Speakers\"), footer: Text(\"Enter a name for each speaker. Changes apply to the entire transcript and are used in AI summaries.\")) {","violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":2120,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift"},"reason":"Line should be 120 characters or less; currently it has 171 characters","ruleIdentifier":"line_length"}},{"text":" }) {","violation":{"ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","ruleName":"Multiple Closures with Trailing Closure","location":{"line":2301,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","character":24},"reason":"Trailing closure syntax should not be used when passing more than one closure argument","severity":"warning"}},{"text":" }) {","violation":{"reason":"Trailing closure syntax should not be used when passing more than one closure argument","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":2370,"character":24},"ruleIdentifier":"multiple_closures_with_trailing_closure","ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":"}","violation":{"ruleName":"File Length","location":{"character":1,"line":2402,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift"},"reason":"File should contain 1000 lines or less: currently contains 2402","severity":"error","ruleIdentifier":"file_length","ruleDescription":"Files should not span too many lines."}},{"text":" private func handleWatchRecordingReceived(fileURL: URL, metadata: [String: Any]) {","violation":{"ruleDescription":"Function bodies should not span too many lines","severity":"warning","location":{"line":119,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift"},"ruleIdentifier":"function_body_length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 71 lines","ruleName":"Function Body Length"}},{"text":" AppLog.shared.watchConnectivity(\"Recording \\(recordingId) already imported - re-acking instead of re-importing\", level: .debug)","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift","line":129,"character":1},"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" AppLog.shared.watchConnectivity(\"Recording \\(recordingId) import already in flight - ignoring duplicate\", level: .debug)","violation":{"ruleName":"Line Length","location":{"line":139,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift","character":1},"severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 132 characters","ruleDescription":"Lines should not span too many characters."}},{"text":" let backgroundTaskID = UIApplication.shared.beginBackgroundTask(withName: \"WatchFileProcessing\") { [weak self] in","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 121 characters","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift","line":156,"character":1}}},{"text":" AppLog.shared.watchConnectivity(\"onWatchSyncRecordingReceived callback is nil - file will not be processed\", level: .error)","violation":{"ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift","character":1,"line":205},"ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" AppLog.shared.watchConnectivity(\"Failed to read received file: \\(error.localizedDescription)\", level: .error)","violation":{"location":{"character":1,"line":210,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift"},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 121 characters","severity":"warning"}},{"text":" AppLog.shared.watchConnectivity(\"Cannot send command - watch not reachable or session not activated\", level: .error)","violation":{"reason":"Line should be 120 characters or less; currently it has 128 characters","location":{"character":1,"line":307,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift"},"severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.watchConnectivity(\"Unknown or missing message type from watch: \\(message[\"messageType\"] ?? \"nil\")\", level: .error)","violation":{"reason":"Line should be 120 characters or less; currently it has 140 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"line":350,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift"}}},{"text":" nonisolated func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 136 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift","line":381,"character":1}}},{"text":" AppLog.shared.watchConnectivity(\"WCSession activation failed: \\(error.localizedDescription)\", level: .error)","violation":{"severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 124 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift","line":384,"character":1},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"text":" nonisolated func session(_ session: WCSession, didReceiveMessage message: [String: Any], replyHandler: @escaping ([String: Any]) -> Void) {","violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 143 characters","ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift","character":1,"line":436}}},{"text":" nonisolated func session(_ session: WCSession, didFinish userInfoTransfer: WCSessionUserInfoTransfer, error: Error?) {","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift","character":1,"line":464},"reason":"Line should be 120 characters or less; currently it has 122 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning"}},{"text":" let stagingDir = fileManager.temporaryDirectory.appendingPathComponent(\"WatchTransferStaging\", isDirectory: true)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"line":489,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift"},"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" AppLog.shared.watchConnectivity(\"Failed to stage received watch file: \\(error.localizedDescription)\", level: .error)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift","line":496,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":"}","violation":{"ruleIdentifier":"file_length","reason":"File should contain 400 lines or less: currently contains 517","ruleDescription":"Files should not span too many lines.","ruleName":"File Length","severity":"warning","location":{"line":517,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift","character":1}}},{"text":" let avg_logprob: Double?","violation":{"ruleIdentifier":"identifier_name","ruleName":"Identifier Name","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":102,"character":9},"ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","reason":"Variable name 'avg_logprob' should only contain alphanumeric and other allowed characters"}},{"text":" let compression_ratio: Double?","violation":{"severity":"error","location":{"line":103,"character":9,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift"},"reason":"Variable name 'compression_ratio' should only contain alphanumeric and other allowed characters","ruleIdentifier":"identifier_name","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleName":"Identifier Name"}},{"text":" let no_speech_prob: Double?","violation":{"ruleIdentifier":"identifier_name","reason":"Variable name 'no_speech_prob' should only contain alphanumeric and other allowed characters","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","severity":"error","ruleName":"Identifier Name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":104,"character":9}}},{"text":" let detected_language: String","violation":{"ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","ruleName":"Identifier Name","reason":"Variable name 'detected_language' should only contain alphanumeric and other allowed characters","severity":"error","location":{"character":9,"line":109,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift"}}},{"text":" let language_code: String","violation":{"reason":"Variable name 'language_code' should only contain alphanumeric and other allowed characters","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleName":"Identifier Name","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","character":9,"line":110},"severity":"error"}},{"text":"class WhisperService: ObservableObject {","violation":{"ruleIdentifier":"type_body_length","ruleDescription":"Type bodies should not span too many lines","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","character":1,"line":117},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 539 lines","ruleName":"Type Body Length"}},{"text":" AppLog.shared.transcription(\"WhisperService init - Config: URL='\\(config.serverURL)', Port=\\(config.port), Protocol=\\(config.whisperProtocol.rawValue)\", level: .debug)","violation":{"reason":"Line should be 120 characters or less; currently it has 175 characters","severity":"warning","location":{"line":132,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift"},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" AppLog.shared.transcription(\"REST connection test HTTP status: \\(httpResponse.statusCode)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","character":1,"line":201},"reason":"Line should be 120 characters or less; currently it has 122 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"text":" private func performRESTTranscription(url: URL) async throws -> TranscriptionResult {","violation":{"ruleDescription":"Complexity of function bodies should be limited.","ruleName":"Cyclomatic Complexity","severity":"error","location":{"line":354,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","character":13},"ruleIdentifier":"cyclomatic_complexity","reason":"Function should have complexity 10 or less; currently complexity is 25"}},{"text":" private func performRESTTranscription(url: URL) async throws -> TranscriptionResult {","violation":{"ruleName":"Function Body Length","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":354},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 241 lines","severity":"error"}},{"text":" AppLog.shared.transcription(\"Audio duration: \\(String(format: \"%.1f\", duration))s (\\(String(format: \"%.1f\", duration\/60)) minutes)\", level: .debug)","violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":364},"severity":"warning","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 159 characters","ruleIdentifier":"line_length"}},{"text":" AppLog.shared.transcription(\"Processing \\(String(format: \"%.1f\", duration\/60)) minute file - expected processing time: ~\\(Int(duration\/60)) minutes\")","violation":{"location":{"character":1,"line":367,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift"},"ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 165 characters","severity":"warning","ruleDescription":"Lines should not span too many characters."}},{"text":" let audioStreamBasicDescription = CMAudioFormatDescriptionGetStreamBasicDescription(formatDescription)","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 122 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","character":1,"line":390},"severity":"warning"}},{"text":" AppLog.shared.transcription(\"Audio format - FormatID: \\(asbd.mFormatID), SampleRate: \\(asbd.mSampleRate)Hz, Channels: \\(asbd.mChannelsPerFrame), BitsPerChannel: \\(asbd.mBitsPerChannel), BytesPerFrame: \\(asbd.mBytesPerFrame), BytesPerPacket: \\(asbd.mBytesPerPacket)\", level: .debug)","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","character":1,"line":392},"severity":"error","reason":"Line should be 200 characters or less; currently it has 305 characters","ruleName":"Line Length"}},{"text":" AppLog.shared.transcription(\"Low sample rate: \\(asbd.mSampleRate)Hz - Whisper works best with 16kHz+\")","violation":{"ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","character":1,"line":395},"severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 130 characters","ruleName":"Line Length"}},{"text":" AppLog.shared.transcription(\"Uncommon audio format ID: \\(asbd.mFormatID) - Whisper prefers AAC or PCM\")","violation":{"ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":399,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" AppLog.shared.transcription(\"File metadata - Creation: \\((fileAttributes[FileAttributeKey.creationDate] as? Date).map { \"\\($0)\" } ?? \"unknown\"), Modified: \\((fileAttributes[FileAttributeKey.modificationDate] as? Date).map { \"\\($0)\" } ?? \"unknown\")\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"error","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":414,"character":1},"reason":"Line should be 200 characters or less; currently it has 276 characters"}},{"text":" body.append(\"--\\(boundary)\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","ruleIdentifier":"non_optional_string_data_conversion","location":{"line":530,"character":21,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift"},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"Content-Disposition: form-data; name=\\\"audio_file\\\"; filename=\\\"\\(url.lastPathComponent)\\\"\\r\\n\".data(using: .utf8)!)","violation":{"reason":"Line should be 120 characters or less; currently it has 137 characters","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":531,"character":1},"ruleDescription":"Lines should not span too many characters."}},{"violation":{"ruleIdentifier":"non_optional_string_data_conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","location":{"line":531,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","character":21},"ruleName":"Non-optional String -> Data Conversion"},"text":" body.append(\"Content-Disposition: form-data; name=\\\"audio_file\\\"; filename=\\\"\\(url.lastPathComponent)\\\"\\r\\n\".data(using: .utf8)!)"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","character":21,"line":532},"ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","severity":"warning","ruleName":"Non-optional String -> Data Conversion"},"text":" body.append(\"Content-Type: application\/octet-stream\\r\\n\\r\\n\".data(using: .utf8)!)"},{"violation":{"severity":"warning","location":{"character":21,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":534},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleName":"Non-optional String -> Data Conversion","ruleIdentifier":"non_optional_string_data_conversion","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"},"text":" body.append(\"\\r\\n\".data(using: .utf8)!)"},{"violation":{"ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":535,"character":21},"severity":"warning","ruleIdentifier":"non_optional_string_data_conversion","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleName":"Non-optional String -> Data Conversion"},"text":" body.append(\"--\\(boundary)--\\r\\n\".data(using: .utf8)!)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 190 characters","location":{"line":557,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","character":1},"ruleIdentifier":"line_length","severity":"warning"},"text":" AppLog.shared.transcription(\"Request completed suspiciously fast - expected ~\\(Int(duration\/60)) minutes, actual: \\(String(format: \"%.1f\", requestDuration))s\", level: .error)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"error","ruleName":"Line Length","location":{"character":1,"line":603,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift"},"reason":"Line should be 200 characters or less; currently it has 208 characters","ruleIdentifier":"line_length"},"text":" AppLog.shared.transcription(\"Parsed response - text length: \\(whisperResponse.text.count) chars, segments: \\(whisperResponse.segments?.count ?? 0), language: \\(whisperResponse.language ?? \"unknown\")\")"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","character":1,"line":607},"reason":"Line should be 120 characters or less; currently it has 180 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" AppLog.shared.transcription(\"Whisper returned empty transcript - segments: \\(whisperResponse.segments?.count ?? 0), language: \\(whisperResponse.language ?? \"unknown\")\")"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":683},"reason":"Line should be 120 characters or less; currently it has 142 characters","ruleName":"Line Length"},"text":" func transcribeAudioInChunks(url: URL, chunkDuration: TimeInterval = 3600, recordingId: UUID? = nil) async throws -> TranscriptionResult {"},{"violation":{"location":{"line":683,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","character":5},"severity":"warning","ruleIdentifier":"function_body_length","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 56 lines"},"text":" func transcribeAudioInChunks(url: URL, chunkDuration: TimeInterval = 3600, recordingId: UUID? = nil) async throws -> TranscriptionResult {"},{"violation":{"severity":"warning","reason":"TODOs should be resolved (Get actual recording ID from C...)","ruleDescription":"TODOs and FIXMEs should be resolved.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":723,"character":55},"ruleName":"Todo","ruleIdentifier":"todo"},"text":" recordingId: recordingId ?? UUID() \/\/ TODO: Get actual recording ID from Core Data"},{"violation":{"severity":"warning","ruleIdentifier":"non_optional_string_data_conversion","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleName":"Non-optional String -> Data Conversion","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":777,"character":21}},"text":" body.append(\"--\\(boundary)\\r\\n\".data(using: .utf8)!)"},{"violation":{"location":{"character":1,"line":778,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift"},"reason":"Line should be 120 characters or less; currently it has 137 characters","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" body.append(\"Content-Disposition: form-data; name=\\\"audio_file\\\"; filename=\\\"\\(url.lastPathComponent)\\\"\\r\\n\".data(using: .utf8)!)"},{"text":" body.append(\"Content-Disposition: form-data; name=\\\"audio_file\\\"; filename=\\\"\\(url.lastPathComponent)\\\"\\r\\n\".data(using: .utf8)!)","violation":{"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleName":"Non-optional String -> Data Conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":778,"character":21},"ruleIdentifier":"non_optional_string_data_conversion","severity":"warning"}},{"text":" body.append(\"Content-Type: application\/octet-stream\\r\\n\\r\\n\".data(using: .utf8)!)","violation":{"severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleName":"Non-optional String -> Data Conversion","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","character":21,"line":779}}},{"text":" body.append(\"\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","ruleIdentifier":"non_optional_string_data_conversion","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","location":{"line":781,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","character":21}}},{"text":" body.append(\"--\\(boundary)--\\r\\n\".data(using: .utf8)!)","violation":{"ruleIdentifier":"non_optional_string_data_conversion","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleName":"Non-optional String -> Data Conversion","location":{"character":21,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":782},"severity":"warning","reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" throw WhisperError.invalidResponse(\"Failed to parse language detection response: \\(error.localizedDescription)\")","violation":{"location":{"line":808,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","character":1},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 124 characters","ruleIdentifier":"line_length"}},{"text":" AppLog.shared.transcription(\"Language detection completed: \\(languageResponse.detected_language) (\\(languageResponse.language_code)) - confidence: \\(languageResponse.confidence)\")","violation":{"ruleIdentifier":"line_length","location":{"character":1,"line":811,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift"},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 187 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":"}","violation":{"severity":"warning","location":{"line":816,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift"},"ruleIdentifier":"file_length","reason":"File should contain 400 lines or less: currently contains 816","ruleName":"File Length","ruleDescription":"Files should not span too many lines."}},{"text":"struct WhisperSettingsView: View {","violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperSettingsView.swift","character":1,"line":10},"reason":"Struct body should span 250 lines or less excluding comments and whitespace: currently spans 343 lines","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","ruleName":"Type Body Length"}},{"text":" @AppStorage(EndpointSecurityPolicy.allowInsecurePublicEndpointsKey) private var allowInsecurePublicEndpoints: Bool = false","violation":{"reason":"Line should be 120 characters or less; currently it has 126 characters","ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"line":15,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperSettingsView.swift","character":1}}},{"text":" _whisperService = State(initialValue: WhisperService(config: config, chunkingService: AudioFileChunkingService()))","violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 122 characters","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperSettingsView.swift","line":49,"character":1},"ruleIdentifier":"line_length","ruleName":"Line Length"}},{"text":" Text(\"Whisper provides high-quality transcription using OpenAI's Whisper model via REST API. This service runs on your local server for privacy and performance.\")","violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 186 characters","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"line":57,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperSettingsView.swift"}}},{"text":" TextField(selectedProtocol == .wyoming ? \"10300\" : \"9000\", value: $port, format: .number.grouping(.never))","violation":{"reason":"Line should be 120 characters or less; currently it has 138 characters","ruleIdentifier":"line_length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperSettingsView.swift","line":188},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":" .fill(testResult.hasPrefix(\"βœ…\") ? Color.green.opacity(0.1) : Color.red.opacity(0.1))","violation":{"ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 128 characters","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperSettingsView.swift","line":259,"character":1}}},{"text":" Link(\"Wyoming Protocol Documentation\", destination: URL(string: \"https:\/\/github.com\/rhasspy\/wyoming-whisper\")!)","violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 135 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":322,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperSettingsView.swift","character":1}}},{"text":" Link(\"Wyoming Protocol Specification\", destination: URL(string: \"https:\/\/github.com\/rhasspy\/wyoming\")!)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 127 characters","severity":"warning","location":{"line":323,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperSettingsView.swift"},"ruleIdentifier":"line_length"}},{"text":" Link(\"Whisper REST API Documentation\", destination: URL(string: \"https:\/\/github.com\/guillaumekln\/faster-whisper\")!)","violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 139 characters","severity":"warning","ruleIdentifier":"line_length","location":{"line":325,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperSettingsView.swift"}}},{"text":" if serverURL.hasPrefix(\"ws:\/\/\") || serverURL.hasPrefix(\"wss:\/\/\") || serverURL.hasPrefix(\"http:\/\/\") || serverURL.hasPrefix(\"https:\/\/\") {","violation":{"location":{"line":362,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperSettingsView.swift"},"severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 143 characters","ruleName":"Line Length","ruleIdentifier":"line_length"}},{"text":"}","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperSettingsView.swift","line":446,"character":1},"ruleIdentifier":"file_length","reason":"File should contain 400 lines or less: currently contains 446","ruleDescription":"Files should not span too many lines.","severity":"warning","ruleName":"File Length"}},{"text":" init(type: WyomingMessageType, data: (any WyomingMessageData)? = nil, payload: Data? = nil, includeTimestamp: Bool = false) {","violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"line":43,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingProtocol.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: [], debugDescription: \"Cannot encode value\"))","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingProtocol.swift","line":123,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters","ruleName":"Line Length","severity":"warning"}},{"text":" let supports_transcript_streaming: Bool?","violation":{"ruleIdentifier":"identifier_name","ruleName":"Identifier Name","severity":"error","reason":"Variable name 'supports_transcript_streaming' should only contain alphanumeric and other allowed characters","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","location":{"line":154,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingProtocol.swift","character":9}}},{"text":" init(rate: Int = WyomingConstants.audioSampleRate, width: Int = WyomingConstants.audioBitDepth, channels: Int = WyomingConstants.audioChannels) {","violation":{"ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingProtocol.swift","character":1,"line":228},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 149 characters"}},{"text":" static func createAudioChunkMessage(audioData: Data, rate: Int = WyomingConstants.audioSampleRate, width: Int = WyomingConstants.audioBitDepth, channels: Int = WyomingConstants.audioChannels) -> WyomingMessage {","violation":{"ruleIdentifier":"line_length","location":{"line":267,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingProtocol.swift"},"reason":"Line should be 200 characters or less; currently it has 215 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"error"}},{"text":"class WyomingTCPClient: ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"warning","reason":"Class body should span 250 lines or less excluding comments and whitespace: currently spans 291 lines","ruleDescription":"Type bodies should not span too many lines","location":{"character":1,"line":51,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingTCPClient.swift"},"ruleIdentifier":"type_body_length"}},{"text":" AppLog.shared.transcription(\"Too many consecutive errors (\\(consecutiveErrors)), aborting batch send\", level: .error)","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingTCPClient.swift","line":293},"reason":"Line should be 120 characters or less; currently it has 141 characters","severity":"warning","ruleDescription":"Lines should not span too many characters."}},{"text":" throw WyomingError.serverError(\"Network streaming failed after \\(consecutiveErrors) consecutive errors\")","violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingTCPClient.swift","line":294,"character":1},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.transcription(\"Chunk \\(index + 1) failed after \\(maxRetries) retries\", level: .error)","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"character":1,"line":302,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingTCPClient.swift"},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" connection.receive(minimumIncompleteLength: 1, maximumLength: 65536) { [weak self] data, _, isComplete, error in","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 124 characters","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"character":1,"line":325,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingTCPClient.swift"}}},{"text":" let message = WyomingMessageFactory.createAudioChunkMessage(audioData: audioData, rate: rate, width: width, channels: channels)","violation":{"reason":"Line should be 120 characters or less; currently it has 135 characters","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingTCPClient.swift","line":435}}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","reason":"File should contain 400 lines or less: currently contains 462","ruleIdentifier":"file_length","ruleDescription":"Files should not span too many lines.","location":{"line":462,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingTCPClient.swift","character":1}}},{"text":" func connect() async throws {","violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWebSocketClient.swift","line":48,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 53 lines","ruleName":"Function Body Length","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length"}},{"text":" AppLog.shared.transcription(\"No handler registered for message type: \\(wyomingMessage.type)\", level: .debug)","violation":{"location":{"line":191,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWebSocketClient.swift","character":1},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 124 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning"}},{"text":"class WyomingWhisperClient: ObservableObject {","violation":{"ruleName":"Type Body Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":13,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 666 lines","ruleIdentifier":"type_body_length","severity":"error","ruleDescription":"Type bodies should not span too many lines"}},{"text":" AppLog.shared.transcription(\"ASR: \\(asrInfo.name), version: \\(asrInfo.version ?? \"unknown\"), models: \\(asrInfo.models?.count ?? 0)\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","location":{"line":112,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift"},"reason":"Line should be 120 characters or less; currently it has 159 characters","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length"}},{"text":" AppLog.shared.transcription(\"Audio duration (\\(Int(duration))s) exceeds \\(Int(maxChunkDuration))s, using chunked transcription\")","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"line":257,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","character":1},"severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" return try await transcribeAudioWithChunking(url: url, recordingId: recordingId, maxChunkDuration: maxChunkDuration)","violation":{"severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","character":1,"line":258},"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 128 characters","ruleName":"Line Length"}},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"line":260,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters","ruleIdentifier":"line_length"},"text":" AppLog.shared.transcription(\"Audio duration (\\(Int(duration))s) is within limits, using standard transcription\")"},{"violation":{"ruleDescription":"Complexity of function bodies should be limited.","ruleName":"Cyclomatic Complexity","location":{"character":13,"line":265,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift"},"severity":"warning","ruleIdentifier":"cyclomatic_complexity","reason":"Function should have complexity 10 or less; currently complexity is 13"},"text":" private func transcribeAudioStandard(url: URL, recordingId: UUID? = nil) async throws -> TranscriptionResult {"},{"violation":{"severity":"warning","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 74 lines","ruleName":"Function Body Length","ruleIdentifier":"function_body_length","location":{"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":265},"ruleDescription":"Function bodies should not span too many lines"},"text":" private func transcribeAudioStandard(url: URL, recordingId: UUID? = nil) async throws -> TranscriptionResult {"},{"violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"line":276,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift"},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 146 characters"},"text":" AppLog.shared.transcription(\"Wyoming client background task management disabled - parent is handling background tasks\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 146 characters","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":304}},"text":" AppLog.shared.transcription(\"File size: \\(fileSize) bytes (\\(String(format: \"%.1f\", Double(fileSize) \/ (1024 * 1024)))MB)\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":323,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","character":1},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 128 characters"},"text":" AppLog.shared.transcription(\"Setting Wyoming timeout: \\(timeoutSeconds)s (\\(timeoutSeconds\/60) minutes)\", level: .debug)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 121 characters","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":347},"ruleIdentifier":"line_length"},"text":" AppLog.shared.transcription(\"Disconnecting after transcription error\", level: .debug)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 157 characters","location":{"line":444,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","character":1},"ruleIdentifier":"line_length","ruleName":"Line Length"},"text":" AppLog.shared.transcription(\"Streaming audio (\\(String(format: \"%.1f\", Double(audioData.count)\/1024\/1024))MB, \\(totalChunks) chunks)\", level: .debug)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"line":510,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift"},"reason":"Line should be 120 characters or less; currently it has 129 characters","ruleIdentifier":"line_length"},"text":" CMBlockBufferCopyDataBytes(blockBuffer, atOffset: 0, dataLength: length, destination: bytes.baseAddress!)"},{"violation":{"ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","character":1,"line":514},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 122 characters","ruleName":"Line Length","severity":"warning"},"text":" AppLog.shared.transcription(\"CMBlockBufferCopyDataBytes returned error: \\(result)\", level: .error)"},{"violation":{"severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 144 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":543}},"text":" private func transcribeAudioWithChunking(url: URL, recordingId: UUID?, maxChunkDuration: TimeInterval) async throws -> TranscriptionResult {"},{"violation":{"severity":"warning","location":{"line":543,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","character":13},"reason":"Function should have complexity 10 or less; currently complexity is 16","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","ruleName":"Cyclomatic Complexity"},"text":" private func transcribeAudioWithChunking(url: URL, recordingId: UUID?, maxChunkDuration: TimeInterval) async throws -> TranscriptionResult {"},{"text":" private func transcribeAudioWithChunking(url: URL, recordingId: UUID?, maxChunkDuration: TimeInterval) async throws -> TranscriptionResult {","violation":{"severity":"error","ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines","location":{"character":13,"line":543,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift"},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 137 lines","ruleName":"Function Body Length"}},{"text":" AppLog.shared.transcription(\"Wyoming client managing its own background task for chunked transcription\", level: .debug)","violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"line":549,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift"},"reason":"Line should be 120 characters or less; currently it has 131 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.transcription(\"Wyoming client background task management disabled - parent is handling chunked transcription\", level: .debug)","violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 151 characters","ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","character":1,"line":551}}},{"text":" AppLog.shared.transcription(\"Audio duration: \\(Int(totalDuration))s, splitting into \\(numberOfChunks) chunks of \\(Int(maxChunkDuration))s each\")","violation":{"reason":"Line should be 120 characters or less; currently it has 152 characters","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":571,"character":1},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" AppLog.shared.transcription(\"Processing chunk \\(chunkIndex + 1)\/\\(numberOfChunks): \\(Int(chunkStartTime))s - \\(Int(chunkEndTime))s (\\(Int(chunkDuration))s)\", level: .debug)","violation":{"ruleName":"Line Length","location":{"line":592,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift"},"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 184 characters"}},{"text":" try await createAudioChunk(sourceURL: url, outputURL: chunkURL, startTime: chunkStartTime, duration: chunkDuration)","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":600},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" AppLog.shared.transcription(\"Disconnecting and reconnecting for chunk \\(chunkIndex + 1)\", level: .debug)","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","character":1,"line":607},"ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 124 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning"}},{"text":" AppLog.shared.transcription(\"Failed to establish fresh connection for chunk \\(chunkIndex + 1)\", level: .error)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 134 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":617,"character":1},"ruleName":"Line Length","severity":"warning"}},{"text":" AppLog.shared.transcription(\"Fresh connection established for chunk \\(chunkIndex + 1)\", level: .debug)","violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":620},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 122 characters","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.transcription(\"Connection error detected for chunk \\(chunkIndex + 1), establishing fresh connection\")","violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 135 characters","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"line":660,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","character":1}}},{"text":" AppLog.shared.transcription(\"Chunk \\(chunkIndex + 1) completed on retry: \\(adjustedSegments.count) segments\")","violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"character":1,"line":687,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift"},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" AppLog.shared.transcription(\"Retry also failed for chunk \\(chunkIndex + 1): \\(error)\", level: .error)","violation":{"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":689,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" AppLog.shared.transcription(\"Could not reconnect for chunk \\(chunkIndex + 1) retry\", level: .error)","violation":{"ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":694},"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 123 characters","ruleName":"Line Length"}},{"text":" AppLog.shared.transcription(\"Non-connection error for chunk \\(chunkIndex + 1), skipping retry: \\(error)\", level: .error)","violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 140 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":698,"character":1}}},{"text":" AppLog.shared.transcription(\"Wyoming client not ending background task - parent is managing it\", level: .debug)","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 123 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":710,"character":1}}},{"text":" AppLog.shared.transcription(\"Chunked transcription completed: \\(mergedSegments.count) segments, \\(fullText.count) chars, \\(Int(finalProcessingTime))s\")","violation":{"location":{"line":722,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","character":1},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 159 characters","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning"}},{"text":" private func createAudioChunk(sourceURL: URL, outputURL: URL, startTime: TimeInterval, duration: TimeInterval) async throws {","violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"line":739,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift"},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 129 characters","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.transcription(\"Creating audio chunk: \\(Int(startTime))s - \\(Int(startTime + duration))s\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 126 characters","severity":"warning","location":{"line":740,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift"},"ruleIdentifier":"line_length"}},{"text":" if timeDifference < 2.0 && isSameSpeaker && !currentSegment.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {","violation":{"location":{"line":800,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","character":1},"ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" AppLog.shared.transcription(\"Merged \\(segments.count) segments into \\(mergedSegments.count) segments\", level: .debug)","violation":{"ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 125 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":815},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" AppLog.shared.transcription(\"Started Wyoming background task with \\(String(format: \"%.0f\", remainingTime))s remaining\", level: .debug)","violation":{"ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 150 characters","ruleName":"Line Length","location":{"character":1,"line":848,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift"}}},{"text":" AppLog.shared.transcription(\"Started Wyoming background task with unlimited time remaining\", level: .debug)","violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 123 characters","severity":"warning","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":850,"character":1},"ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.transcription(\"Disconnecting after streaming timeout (no active transcription)\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 121 characters","location":{"line":949,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift"}}},{"text":"}","violation":{"ruleIdentifier":"file_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":957,"character":1},"ruleDescription":"Files should not span too many lines.","ruleName":"File Length","reason":"File should contain 400 lines or less: currently contains 957"}},{"text":"class iCloudStorageManager: ObservableObject {","violation":{"ruleIdentifier":"type_body_length","reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 1652 lines","ruleName":"Type Body Length","severity":"error","location":{"line":140,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"ruleDescription":"Type bodies should not span too many lines"}},{"text":"class iCloudStorageManager: ObservableObject {","violation":{"ruleName":"Type Name","ruleDescription":"Type name should only contain alphanumeric characters, start with an uppercase character and span between 3 and 40 characters in length.\nPrivate types may start with an underscore.","ruleIdentifier":"type_name","severity":"error","location":{"character":7,"line":140,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"reason":"Type name 'iCloudStorageManager' should start with an uppercase character"}},{"text":" case disabled = \"disabled\"","violation":{"severity":"warning","ruleDescription":"String enum values can be omitted when they are equal to the enumcase name","ruleName":"Redundant String Enum Value","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":200,"character":25},"reason":"String enum values can be omitted when they are equal to the enumcase name","ruleIdentifier":"redundant_string_enum_value"}},{"text":" case changesOnly = \"changesOnly\" \/\/ Only sync when summaries are modified (default)","violation":{"ruleDescription":"String enum values can be omitted when they are equal to the enumcase name","reason":"String enum values can be omitted when they are equal to the enumcase name","location":{"character":28,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":201},"ruleIdentifier":"redundant_string_enum_value","ruleName":"Redundant String Enum Value","severity":"warning"}},{"text":" case periodic = \"periodic\" \/\/ Sync all summaries periodically (legacy behavior)","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":202,"character":25},"ruleIdentifier":"redundant_string_enum_value","reason":"String enum values can be omitted when they are equal to the enumcase name","ruleDescription":"String enum values can be omitted when they are equal to the enumcase name","severity":"warning","ruleName":"Redundant String Enum Value"}},{"text":" let error = NSError(domain: \"iCloudStorageManager\", code: 1, userInfo: [NSLocalizedDescriptionKey: \"Failed to initialize CloudKit components\"])","violation":{"ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 155 characters","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":352}}},{"text":" let error = NSError(domain: \"iCloudStorageManager\", code: 2, userInfo: [NSLocalizedDescriptionKey: \"CloudKit not initialized\"])","violation":{"reason":"Line should be 120 characters or less; currently it has 139 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":382,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"ruleIdentifier":"line_length"}},{"text":" let error = NSError(domain: \"iCloudStorageManager\", code: 3, userInfo: [NSLocalizedDescriptionKey: \"iCloud account not available\"])","violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","location":{"line":393,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1},"ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 147 characters"}},{"text":" \/\/ Note: userDiscoverability permission is deprecated in iOS 17.0 and not needed for private database operations","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1,"line":400},"reason":"Line should be 120 characters or less; currently it has 124 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning"}},{"text":" AppLog.shared.iCloudSync(\"Performing initial full sync (first install: \\(isFirstInstall), requested: \\(shouldPerformFullSyncOnStartup))\")","violation":{"reason":"Line should be 120 characters or less; currently it has 153 characters","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":411,"character":1}}},{"text":" AppLog.shared.iCloudSync(\"Summary belongs to a recording marked Keep on This Device, skipping iCloud sync\", level: .debug)","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":452},"reason":"Line should be 120 characters or less; currently it has 134 characters","severity":"warning","ruleName":"Line Length"}},{"text":" AppLog.shared.iCloudSync(\"Batch sync completed with errors: \\(syncedCount) synced, \\(failedCount) failed\", level: .error)","violation":{"location":{"line":541,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"}},{"text":" private func performIndividualSync(_ summary: EnhancedSummaryData) async throws {","violation":{"location":{"line":555,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":13},"severity":"warning","ruleIdentifier":"cyclomatic_complexity","ruleDescription":"Complexity of function bodies should be limited.","ruleName":"Cyclomatic Complexity","reason":"Function should have complexity 10 or less; currently complexity is 13"}},{"text":" private func performIndividualSync(_ summary: EnhancedSummaryData) async throws {","violation":{"ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":555,"character":13},"severity":"warning","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 52 lines","ruleIdentifier":"function_body_length"}},{"text":" throw NSError(domain: \"iCloudStorageManager\", code: 1, userInfo: [NSLocalizedDescriptionKey: \"CloudKit not initialized\"])","violation":{"reason":"Line should be 120 characters or less; currently it has 133 characters","ruleIdentifier":"line_length","location":{"line":562,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1},"severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" throw NSError(domain: \"iCloudStorageManager\", code: 2, userInfo: [NSLocalizedDescriptionKey: \"Network unavailable\"])","violation":{"reason":"Line should be 120 characters or less; currently it has 128 characters","ruleIdentifier":"line_length","location":{"line":566,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length"}},{"text":" AppLog.shared.iCloudSync(\"Server record changed, refetching and retrying (attempt \\(retryCount)\/\\(maxRetryAttempts))\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 157 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1,"line":594}}},{"text":" AppLog.shared.iCloudSync(\"Network error, retrying in \\(retryDelay)s (attempt \\(retryCount)\/\\(maxRetryAttempts))\", level: .error)","violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 156 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","location":{"line":599,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"}}},{"text":" AppLog.shared.iCloudSync(\"Unknown record type, setting up schema and retrying\", level: .error)","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1,"line":606},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 122 characters","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length"}},{"text":" AppLog.shared.iCloudSync(\"Retryable CloudKit error, attempt \\(retryCount)\/\\(maxRetryAttempts): \\(ckError.localizedDescription)\", level: .error)","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 171 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1,"line":612},"ruleName":"Line Length","severity":"warning"}},{"text":" AppLog.shared.iCloudSync(\"Failed to sync summary after \\(retryCount) attempts: \\(error.localizedDescription)\", level: .error)","violation":{"reason":"Line should be 120 characters or less; currently it has 141 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1,"line":619}}},{"text":" private func handleConflictResolution(for recordID: CKRecord.ID, with summary: EnhancedSummaryData) async throws -> CKRecord {","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"line":626,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" throw NSError(domain: \"iCloudStorageManager\", code: 1, userInfo: [NSLocalizedDescriptionKey: \"Database not available\"])","violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1,"line":628},"reason":"Line should be 120 characters or less; currently it has 131 characters","severity":"warning"}},{"text":" AppLog.shared.iCloudSync(\"Schema issue detected, ensuring schema and creating record\", level: .error)","violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"line":646,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"reason":"Line should be 120 characters or less; currently it has 121 characters","ruleDescription":"Lines should not span too many characters."}},{"violation":{"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"line":709,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 133 characters"},"text":" AppLog.shared.iCloudSync(\"Batch sync completed with errors: \\(syncedCount) synced, \\(failedCount) failed\", level: .error)"},{"violation":{"ruleIdentifier":"cyclomatic_complexity","ruleDescription":"Complexity of function bodies should be limited.","location":{"line":747,"character":5,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"ruleName":"Cyclomatic Complexity","reason":"Function should have complexity 10 or less; currently complexity is 13","severity":"warning"},"text":" func fetchSummariesFromiCloud(forRecovery: Bool = false) async throws -> [EnhancedSummaryData] {"},{"violation":{"ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":747,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 54 lines"},"text":" func fetchSummariesFromiCloud(forRecovery: Bool = false) async throws -> [EnhancedSummaryData] {"},{"violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 133 characters","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"line":759,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"}},"text":" throw NSError(domain: \"iCloudStorageManager\", code: 1, userInfo: [NSLocalizedDescriptionKey: \"CloudKit not initialized\"])"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 128 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"character":1,"line":764,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"ruleIdentifier":"line_length","ruleName":"Line Length"},"text":" throw NSError(domain: \"iCloudStorageManager\", code: 2, userInfo: [NSLocalizedDescriptionKey: \"Network unavailable\"])"},{"violation":{"ruleIdentifier":"line_length","location":{"character":1,"line":788,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"reason":"Line should be 120 characters or less; currently it has 122 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning"},"text":" AppLog.shared.iCloudSync(\"Failed to process record: \\(error.localizedDescription)\", level: .error)"},{"violation":{"severity":"warning","location":{"line":803,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 179 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"},"text":" AppLog.shared.iCloudSync(\"Retryable error fetching from iCloud, attempt \\(retryCount)\/\\(maxRetryAttempts): \\(ckError.localizedDescription)\", level: .error)"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"line":807,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"reason":"Line should be 120 characters or less; currently it has 164 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" AppLog.shared.iCloudSync(\"Failed to fetch summaries from iCloud after \\(retryCount) attempts: \\(error.localizedDescription)\", level: .error)"},{"violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":811},"reason":"Line should be 120 characters or less; currently it has 160 characters"},"text":" AppLog.shared.iCloudSync(\"Failed to fetch summaries from iCloud after \\(retryCount) attempts: \\(error.localizedDescription)\", level: .error)"},{"violation":{"severity":"warning","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":818},"reason":"Line should be 120 characters or less; currently it has 132 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" throw NSError(domain: \"iCloudStorageManager\", code: 3, userInfo: [NSLocalizedDescriptionKey: \"Max retry attempts exceeded\"])"},{"violation":{"location":{"line":823,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"reason":"Line should be 120 characters or less; currently it has 122 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning"},"text":" AppLog.shared.iCloudSync(\"Cannot perform bidirectional sync - disabled or network unavailable\", level: .error)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 159 characters","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"line":849,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1}},"text":" if let resolved = try await handleSyncConflict(localSummary: localSummary, cloudRecord: try createCloudKitRecord(from: cloudSummary)) {"},{"violation":{"severity":"warning","location":{"character":17,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":865},"ruleIdentifier":"for_where","reason":"`where` clauses are preferred over a single `if` inside a `for`","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleName":"Prefer For-Where"},"text":" if localLookup[cloudSummary.id] == nil {"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":877,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"reason":"Line should be 120 characters or less; currently it has 153 characters","ruleName":"Line Length"},"text":" AppLog.shared.iCloudSync(\"Bidirectional sync completed with conflicts: \\(syncedCount) synced, \\(conflictCount) conflicts\", level: .error)"},{"violation":{"ruleIdentifier":"unused_optional_binding","ruleDescription":"Prefer `!= nil` over `let _ =`","location":{"character":45,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":894},"severity":"warning","ruleName":"Unused Optional Binding","reason":"Prefer `!= nil` over `let _ =`"},"text":" guard forRecovery || isEnabled, let _ = database else {"},{"violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 160 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":895},"ruleName":"Line Length"},"text":" throw NSError(domain: \"iCloudStorageManager\", code: 1, userInfo: [NSLocalizedDescriptionKey: \"iCloud sync not enabled or CloudKit not initialized\"])"},{"violation":{"severity":"warning","location":{"line":931,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 144 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"},"text":" AppLog.shared.iCloudSync(\"Failed to create Core Data entry for cloud summary: \\(error.localizedDescription)\", level: .error)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 124 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1,"line":985},"ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" AppLog.shared.iCloudSync(\"Failed to decode cloud summary: \\(error.localizedDescription)\", level: .error)"},{"violation":{"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 126 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":988},"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"},"text":" AppLog.shared.iCloudSync(\"Failed to fetch cloud summary record: \\(error.localizedDescription)\", level: .error)"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1004,"character":1},"severity":"warning","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 129 characters","ruleIdentifier":"line_length"},"text":" func fetchAllSummariesUsingRecordOperation(appCoordinator: AppDataCoordinator? = nil) async throws -> [EnhancedSummaryData] {"},{"violation":{"ruleName":"Cyclomatic Complexity","ruleIdentifier":"cyclomatic_complexity","ruleDescription":"Complexity of function bodies should be limited.","severity":"warning","location":{"character":5,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1004},"reason":"Function should have complexity 10 or less; currently complexity is 12"},"text":" func fetchAllSummariesUsingRecordOperation(appCoordinator: AppDataCoordinator? = nil) async throws -> [EnhancedSummaryData] {"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1004,"character":5},"severity":"warning","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 74 lines","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","ruleName":"Function Body Length"},"text":" func fetchAllSummariesUsingRecordOperation(appCoordinator: AppDataCoordinator? = nil) async throws -> [EnhancedSummaryData] {"},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1019,"character":1},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 125 characters"},"text":" AppLog.shared.iCloudSync(\"UUID scanning + change tracking found \\(summaries.count) summaries\", level: .debug)"},{"violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 128 characters","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1021},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" AppLog.shared.iCloudSync(\"UUID scanning + change tracking failed: \\(error.localizedDescription)\", level: .error)"},{"text":" AppLog.shared.iCloudSync(\"Brute force scanning found \\(scannedSummaries.count) summaries\", level: .debug)","violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1033},"reason":"Line should be 120 characters or less; currently it has 121 characters","ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"}},{"text":" AppLog.shared.iCloudSync(\"Failed to fetch from zone using changes: \\(error.localizedDescription)\", level: .error)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1081},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 137 characters","severity":"warning"}},{"text":" AppLog.shared.iCloudSync(\"Database changes + zone scanning found \\(allSummaries.count) summaries\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 129 characters","location":{"line":1085,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning"}},{"text":" AppLog.shared.iCloudSync(\"Database changes + zone scanning failed: \\(error.localizedDescription)\", level: .error)","violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","location":{"character":1,"line":1088,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"reason":"Line should be 120 characters or less; currently it has 129 characters","ruleName":"Line Length"}},{"text":" AppLog.shared.iCloudSync(\"Total unique summaries found: \\(uniqueSummaries.count) (removed \\(allSummaries.count - uniqueSummaries.count) duplicates)\", level: .debug)","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1098,"character":1},"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 172 characters","ruleName":"Line Length"}},{"text":" private func fetchSummariesByUUIDScanning(appCoordinator: AppDataCoordinator) async throws -> [EnhancedSummaryData] {","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1105},"severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" private func fetchSummariesByUUIDScanning(appCoordinator: AppDataCoordinator) async throws -> [EnhancedSummaryData] {","violation":{"ruleIdentifier":"cyclomatic_complexity","severity":"warning","reason":"Function should have complexity 10 or less; currently complexity is 11","location":{"line":1105,"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"ruleName":"Cyclomatic Complexity","ruleDescription":"Complexity of function bodies should be limited."}},{"text":" private func fetchSummariesByUUIDScanning(appCoordinator: AppDataCoordinator) async throws -> [EnhancedSummaryData] {","violation":{"ruleIdentifier":"function_body_length","ruleName":"Function Body Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":13,"line":1105},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 70 lines","ruleDescription":"Function bodies should not span too many lines"}},{"text":" AppLog.shared.iCloudSync(\"No CloudKit record found for local summary: \\(error.localizedDescription)\", level: .debug)","violation":{"ruleName":"Line Length","location":{"line":1148,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 132 characters","severity":"warning"}},{"text":" AppLog.shared.iCloudSync(\"Failed to fetch cloud-only record: \\(error.localizedDescription)\", level: .error)","violation":{"severity":"warning","location":{"line":1174,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"reason":"Line should be 120 characters or less; currently it has 127 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length"}},{"text":" AppLog.shared.iCloudSync(\"Failed to convert cloud-only record: \\(error.localizedDescription)\", level: .error)","violation":{"reason":"Line should be 120 characters or less; currently it has 129 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":1192,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"severity":"warning","ruleName":"Line Length"}},{"text":" AppLog.shared.iCloudSync(\"Change tracking found \\(cloudOnlyRecords.count) cloud-only records\", level: .debug)","violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 121 characters","location":{"line":1196,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1},"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.iCloudSync(\"UUID scanning + change tracking found \\(foundSummaries.count) total summaries\", level: .debug)","violation":{"reason":"Line should be 120 characters or less; currently it has 128 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1,"line":1202},"severity":"warning"}},{"text":" AppLog.shared.iCloudSync(\"Failed to fetch record with configuration: \\(error.localizedDescription)\", level: .error)","violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1263},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 131 characters","severity":"warning"}},{"text":" AppLog.shared.iCloudSync(\"Failed to convert configured record: \\(error.localizedDescription)\", level: .error)","violation":{"severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 125 characters","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1,"line":1281},"ruleName":"Line Length"}},{"text":" private func fetchRecordsFromZoneByScanning(_ zoneID: CKRecordZone.ID) async throws -> [EnhancedSummaryData] {","violation":{"severity":"warning","ruleIdentifier":"cyclomatic_complexity","ruleDescription":"Complexity of function bodies should be limited.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1384,"character":13},"ruleName":"Cyclomatic Complexity","reason":"Function should have complexity 10 or less; currently complexity is 12"}},{"text":" let (matchResults, _) = try await database.records(matching: query, inZoneWith: zoneID, desiredKeys: nil, resultsLimit: 1)","violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1,"line":1400},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" let (matchResults, _) = try await database.records(matching: query, inZoneWith: zoneID, desiredKeys: nil, resultsLimit: 1000)","violation":{"location":{"character":1,"line":1419,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 141 characters","severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length"}},{"text":" private func createCoreDataSummary(from cloudSummary: EnhancedSummaryData, appCoordinator: AppDataCoordinator) async throws -> Bool {","violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 137 characters","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1455}}},{"text":" AppLog.shared.iCloudSync(\"Creating orphaned Core Data summary entry (no local recording\/transcript)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 128 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1493,"character":1},"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"}},{"text":" private func createOrphanedSummaryEntry(_ cloudSummary: EnhancedSummaryData, appCoordinator: AppDataCoordinator) async throws {","violation":{"ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1,"line":1509},"severity":"warning","reason":"Line should be 120 characters or less; currently it has 131 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters."}},{"text":" private func handleSyncConflict(localSummary: EnhancedSummaryData, cloudRecord: CKRecord) async throws -> EnhancedSummaryData? {","violation":{"location":{"line":1583,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 132 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length"}},{"text":" AppLog.shared.iCloudSync(\"Auto-backup complete: \\(result.recordingsBackedUp) recordings, \\(result.transcriptsBackedUp) transcripts, \\(result.summariesBackedUp) summaries\")","violation":{"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 187 characters","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"line":1734,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"ruleIdentifier":"line_length"}},{"text":" AppLog.shared.iCloudSync(\"Auto-backup failed (will retry on next data change): \\(error.localizedDescription)\", level: .error)","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 137 characters","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1740,"character":1}}},{"violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"line":1801,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1},"ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 123 characters"},"text":" AppLog.shared.iCloudSync(\"Skipping full periodic sync - only syncing changes as they occur\", level: .debug)"},{"violation":{"location":{"line":1996,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length"},"text":" AppLog.shared.iCloudSync(\"Failed to encode complex objects during update: \\(error.localizedDescription)\", level: .error)"},{"violation":{"ruleName":"Function Body Length","ruleIdentifier":"function_body_length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 61 lines","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":13,"line":2000},"severity":"warning","ruleDescription":"Function bodies should not span too many lines"},"text":" private func createEnhancedSummaryData(from record: CKRecord) throws -> EnhancedSummaryData {"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"line":2011,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"reason":"Line should be 120 characters or less; currently it has 151 characters"},"text":" throw NSError(domain: \"iCloudStorageManager\", code: 1, userInfo: [NSLocalizedDescriptionKey: \"Missing required fields in CloudKit record\"])"},{"violation":{"severity":"warning","location":{"character":5,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2113},"reason":"Function should have complexity 10 or less; currently complexity is 12","ruleIdentifier":"cyclomatic_complexity","ruleDescription":"Complexity of function bodies should be limited.","ruleName":"Cyclomatic Complexity"},"text":" func testCloudKitConnectivity() async -> String {"},{"violation":{"ruleName":"Function Body Length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 71 lines","severity":"warning","location":{"character":5,"line":2113,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines"},"text":" func testCloudKitConnectivity() async -> String {"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 157 characters","severity":"warning","location":{"line":2158,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"},"text":" let (matchResults, _) = try await database.records(matching: query, inZoneWith: CKRecordZone.default().zoneID, desiredKeys: nil, resultsLimit: 1)"},{"violation":{"severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2260},"ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 124 characters","ruleDescription":"Lines should not span too many characters."},"text":" func performFullCloudKitResetAndSync(appCoordinator: AppDataCoordinator) async throws -> (deleted: Int, uploaded: Int) {"},{"violation":{"location":{"line":2262,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1},"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 160 characters","ruleName":"Line Length"},"text":" throw NSError(domain: \"iCloudStorageManager\", code: 1, userInfo: [NSLocalizedDescriptionKey: \"iCloud sync not enabled or CloudKit not initialized\"])"},{"violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 126 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"line":2284,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1}},"text":" if let enhancedSummary = try? convertCoreDataToEnhancedSummary(localSummary, appCoordinator: appCoordinator) {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2290,"character":1},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 122 characters"},"text":" AppLog.shared.iCloudSync(\"Failed to upload summary: \\(error.localizedDescription)\", level: .error)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 124 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2296},"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length"},"text":" AppLog.shared.iCloudSync(\"CloudKit reset and sync complete: deleted \\(deletedCount), uploaded \\(uploadedCount)\")"},{"violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 125 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2330},"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning"},"text":" AppLog.shared.iCloudSync(\"Failed to fetch record for deletion: \\(error.localizedDescription)\", level: .error)"},{"violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 147 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1,"line":2364}},"text":" private func convertCoreDataToEnhancedSummary(_ summaryEntry: SummaryEntry, appCoordinator: AppDataCoordinator) throws -> EnhancedSummaryData {"},{"violation":{"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 57 lines","ruleIdentifier":"function_body_length","ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length","severity":"warning","location":{"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2364}},"text":" private func convertCoreDataToEnhancedSummary(_ summaryEntry: SummaryEntry, appCoordinator: AppDataCoordinator) throws -> EnhancedSummaryData {"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 140 characters","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2368}},"text":" throw NSError(domain: \"iCloudStorageManager\", code: 1, userInfo: [NSLocalizedDescriptionKey: \"Missing required summary fields\"])"},{"violation":{"ruleDescription":"Complexity of function bodies should be limited.","severity":"error","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":5,"line":2740},"reason":"Function should have complexity 10 or less; currently complexity is 27","ruleName":"Cyclomatic Complexity","ruleIdentifier":"cyclomatic_complexity"},"text":" func backupAllDataToiCloud("},{"violation":{"ruleName":"Function Body Length","ruleIdentifier":"function_body_length","location":{"line":2740,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":5},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 410 lines","ruleDescription":"Function bodies should not span too many lines","severity":"error"},"text":" func backupAllDataToiCloud("},{"violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 134 characters","ruleName":"Line Length","location":{"character":1,"line":2760,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"severity":"warning","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.iCloudSync(\"Backup context - bundle: \\(bundleIdentifier), container: \\(containerIdentifier)\", level: .debug)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 130 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2851,"character":1}},"text":" excludedRecordingIds.contains(recordingId) || !isActiveBackupRecord(record) ? nil : record.recordID.recordName"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2873,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters","severity":"warning"},"text":" updateStringField(Self.fieldRecordingName, value: recording.recordingName, on: record, changed: &shouldSave)"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 122 characters","ruleDescription":"Lines should not span too many characters.","location":{"line":2874,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"}},"text":" updateDateField(Self.fieldRecordingDate, value: recording.recordingDate, on: record, changed: &shouldSave)"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1,"line":2875},"reason":"Line should be 120 characters or less; currently it has 122 characters","ruleName":"Line Length"},"text":" updateStringField(Self.fieldRecordingURL, value: recording.recordingURL, on: record, changed: &shouldSave)"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2880},"reason":"Line should be 120 characters or less; currently it has 122 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" updateStringField(Self.fieldAudioQuality, value: recording.audioQuality, on: record, changed: &shouldSave)"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2881,"character":1},"ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 136 characters"},"text":" updateStringField(Self.fieldTranscriptionStatus, value: recording.transcriptionStatus, on: record, changed: &shouldSave)"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 124 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1,"line":2882}},"text":" updateStringField(Self.fieldSummaryStatus, value: recording.summaryStatus, on: record, changed: &shouldSave)"},{"violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 134 characters","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2883,"character":1},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" updateStringField(Self.fieldTranscriptId, value: recording.transcriptId?.uuidString, on: record, changed: &shouldSave)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":2884,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters","ruleName":"Line Length","ruleIdentifier":"line_length"},"text":" updateStringField(Self.fieldSummaryId, value: recording.summaryId?.uuidString, on: record, changed: &shouldSave)"},{"violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2885},"reason":"Line should be 120 characters or less; currently it has 130 characters"},"text":" updateDoubleField(Self.fieldLocationLatitude, value: recording.locationLatitude, on: record, changed: &shouldSave)"},{"violation":{"location":{"character":1,"line":2886,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 132 characters"},"text":" updateDoubleField(Self.fieldLocationLongitude, value: recording.locationLongitude, on: record, changed: &shouldSave)"},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2887},"reason":"Line should be 120 characters or less; currently it has 130 characters","ruleName":"Line Length","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" updateDoubleField(Self.fieldLocationAccuracy, value: recording.locationAccuracy, on: record, changed: &shouldSave)"},{"violation":{"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 130 characters","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1,"line":2888},"ruleIdentifier":"line_length"},"text":" updateDateField(Self.fieldLocationTimestamp, value: recording.locationTimestamp, on: record, changed: &shouldSave)"},{"violation":{"ruleIdentifier":"line_length","severity":"warning","location":{"character":1,"line":2889,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"reason":"Line should be 120 characters or less; currently it has 128 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" updateStringField(Self.fieldLocationAddress, value: recording.locationAddress, on: record, changed: &shouldSave)"},{"violation":{"location":{"character":1,"line":2900,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 139 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length"},"text":" updateStringField(Self.fieldAudioFileName, value: localURL.lastPathComponent, on: record, changed: &shouldSave)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 121 characters","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"line":2903,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"}},"text":" updateInt64Field(Self.fieldAudioByteCount, value: size, on: record, changed: &shouldSave)"},{"violation":{"severity":"warning","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2905},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 123 characters"},"text":" updateStringField(Self.fieldAudioSignature, value: signature, on: record, changed: &shouldSave)"},{"text":" updateStringField(Self.fieldRecordingId, value: transcript.recordingId?.uuidString, on: record, changed: &shouldSave)","violation":{"ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2966,"character":1},"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" updateDoubleField(Self.fieldProcessingTime, value: transcript.processingTime, on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 127 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1,"line":2970},"ruleDescription":"Lines should not span too many characters."}},{"text":" updateStringField(Self.fieldSpeakerMappings, value: transcript.speakerMappings, on: record, changed: &shouldSave)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2973},"reason":"Line should be 120 characters or less; currently it has 129 characters","severity":"warning","ruleIdentifier":"line_length"}},{"text":" AppLog.shared.iCloudSync(\"Removed \\(transcriptResolution.loserRecordIDs.count) older transcript backup records\", level: .debug)","violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"character":1,"line":3022,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"reason":"Line should be 120 characters or less; currently it has 143 characters","ruleName":"Line Length"}},{"text":" updateStringField(Self.fieldRecordingId, value: summary.recordingId?.uuidString, on: record, changed: &shouldSave)","violation":{"severity":"warning","location":{"character":1,"line":3069,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 130 characters","ruleName":"Line Length"}},{"text":" updateStringField(Self.fieldTranscriptId, value: summary.transcriptId?.uuidString, on: record, changed: &shouldSave)","violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 132 characters","ruleIdentifier":"line_length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3070},"ruleName":"Line Length"}},{"text":" updateIntField(Self.fieldOriginalLength, value: Int(summary.originalLength), on: record, changed: &shouldSave)","violation":{"severity":"warning","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3080,"character":1},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" updateDoubleField(Self.fieldCompressionRatio, value: summary.compressionRatio, on: record, changed: &shouldSave)","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"line":3081,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" updateDoubleField(Self.fieldProcessingTime, value: summary.processingTime, on: record, changed: &shouldSave)","violation":{"severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3083,"character":1},"ruleIdentifier":"line_length","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" updateStringField(Self.fieldRecordingName, value: summary.recording?.recordingName, on: record, changed: &shouldSave)","violation":{"ruleDescription":"Lines should not span too many characters.","location":{"line":3087,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1},"ruleName":"Line Length","ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 133 characters","severity":"warning"}},{"text":" updateDateField(Self.fieldRecordingDate, value: summary.recording?.recordingDate, on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3088,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters","ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters."}},{"text":" AppLog.shared.iCloudSync(\"Removed \\(summaryResolution.loserRecordIDs.count) older summary backup records\", level: .debug)","violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3136},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" self.lastMaintenanceMessage = \"\\(items.count) older iCloud item\\(items.count == 1 ? \"\" : \"s\") held for review.\"","violation":{"ruleName":"Line Length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1,"line":3233},"reason":"Line should be 120 characters or less; currently it has 127 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"text":" private func scanCloudOnlyReviewItems(","violation":{"location":{"line":3239,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":13},"ruleIdentifier":"cyclomatic_complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","reason":"Function should have complexity 10 or less; currently complexity is 15","ruleName":"Cyclomatic Complexity"}},{"text":" private func scanCloudOnlyReviewItems(","violation":{"ruleName":"Function Body Length","reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 109 lines","ruleIdentifier":"function_body_length","location":{"character":13,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3239},"severity":"error","ruleDescription":"Function bodies should not span too many lines"}},{"text":" let recordingRecords = try await fetchBackupRecords(recordType: Self.backupRecordingRecordType, database: database)","violation":{"reason":"Line should be 120 characters or less; currently it has 123 characters","ruleIdentifier":"line_length","ruleName":"Line Length","location":{"line":3255,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1},"ruleDescription":"Lines should not span too many characters.","severity":"warning"}},{"text":" let transcriptRecords = try await fetchBackupRecords(recordType: Self.backupTranscriptRecordType, database: database)","violation":{"severity":"warning","ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3256},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" recordingId.map({ !locallyExcludedRecordingIds.contains($0) && !deletedRecordingIds.contains($0) }) ?? true,","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 126 characters","location":{"line":3293,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"severity":"warning"}},{"text":" recordingId.map({ !locallyExcludedRecordingIds.contains($0) && !deletedRecordingIds.contains($0) }) ?? true,","violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3316,"character":1},"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 126 characters","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning"}},{"text":" let recordingId = (record[CloudKitSummaryRecord.recordingIdField] as? String).flatMap { UUID(uuidString: $0) }","violation":{"severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3337},"reason":"Line should be 120 characters or less; currently it has 122 characters","ruleName":"Line Length"}},{"text":" recordingId.map({ !locallyExcludedRecordingIds.contains($0) && !deletedRecordingIds.contains($0) }) ?? true else {","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"character":1,"line":3339,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" let deletedCount = try await deleteExistingCloudRecords(legacySchemaBootstrapRecordIDs, database: database)","violation":{"ruleIdentifier":"line_length","location":{"line":3354,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" AppLog.shared.iCloudSync(\"Could not clean up legacy schema bootstrap records: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","location":{"line":3359,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" builder.sourceDeviceIdentifier = builder.sourceDeviceIdentifier ?? (record[Self.fieldDeviceIdentifier] as? String)","violation":{"ruleDescription":"Lines should not span too many characters.","location":{"line":3384,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 122 characters","ruleIdentifier":"line_length","severity":"warning"}},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3398},"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 129 characters"},"text":" builder.date = builder.date ?? (record[Self.fieldGeneratedAt] as? Date) ?? (record[Self.fieldRecordingDate] as? Date)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3415,"character":1},"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 159 characters"},"text":" builder.date = builder.date ?? (record[CloudKitSummaryRecord.generatedAtField] as? Date) ?? (record[CloudKitSummaryRecord.recordingDateField] as? Date)"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"line":3416,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 139 characters"},"text":" builder.sourceDeviceIdentifier = builder.sourceDeviceIdentifier ?? (record[CloudKitSummaryRecord.deviceIdentifierField] as? String)"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":5,"line":3438},"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 62 lines"},"text":" func restoreCloudReviewItem("},{"violation":{"ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3487,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning"},"text":" recordingRecordNames: Array(trustedManifest.recordings.union(recordingRecords.map { $0.recordID.recordName })).sorted(),"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","location":{"line":3488,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"reason":"Line should be 120 characters or less; currently it has 135 characters"},"text":" transcriptRecordNames: Array(trustedManifest.transcripts.union(transcriptRecords.map { $0.recordID.recordName })).sorted(),"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 126 characters","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3489},"ruleIdentifier":"line_length"},"text":" summaryRecordNames: Array(trustedManifest.summaries.union(summaryRecords.map { $0.recordID.recordName })).sorted()"},{"violation":{"location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3550,"character":5},"reason":"Function should have complexity 10 or less; currently complexity is 41","ruleName":"Cyclomatic Complexity","ruleDescription":"Complexity of function bodies should be limited.","severity":"error","ruleIdentifier":"cyclomatic_complexity"},"text":" func restoreAllDataFromiCloud("},{"violation":{"ruleName":"Function Body Length","ruleDescription":"Function bodies should not span too many lines","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3550,"character":5},"ruleIdentifier":"function_body_length","severity":"error","reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 339 lines"},"text":" func restoreAllDataFromiCloud("},{"violation":{"ruleIdentifier":"line_length","reason":"Line should be 120 characters or less; currently it has 135 characters","location":{"line":3571,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleName":"Line Length"},"text":" AppLog.shared.iCloudSync(\"Restore context - bundle: \\(bundleIdentifier), container: \\(containerIdentifier)\", level: .debug)"},{"violation":{"ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1,"line":3613},"reason":"Line should be 120 characters or less; currently it has 125 characters","severity":"warning","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" let locallyExcludedRecordingIds = Set(appCoordinator.coreDataManager.getAllRecordings().compactMap { recording in"},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3747},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 143 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" let fileExtension = (backupFileName as NSString).pathExtension.isEmpty ? \"m4a\" : (backupFileName as NSString).pathExtension"},{"text":" entry.recordingURL = appCoordinator.coreDataManager.urlToRelativePath(destinationURL) ?? uniqueFileName","violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","location":{"line":3757,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"reason":"Line should be 120 characters or less; currently it has 123 characters","ruleName":"Line Length","severity":"warning"}},{"text":" let reviewItems = (try? await scanCloudOnlyReviewItems(appCoordinator: appCoordinator, database: database)) ?? []","violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1,"line":3898},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" \" Run Backup Now on the source device and ensure both devices use the same app build channel (both Debug or both TestFlight\/App Store).\"","violation":{"severity":"warning","location":{"line":3918,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"reason":"Line should be 120 characters or less; currently it has 164 characters","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length"}},{"text":" AppLog.shared.iCloudSync(\"Query threw error (\\(error.localizedDescription)), trying schema-safe record discovery\", level: .error)","violation":{"reason":"Line should be 120 characters or less; currently it has 141 characters","ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","location":{"line":3958,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"}}},{"text":" func reconcileAllDataWithiCloud(","violation":{"ruleIdentifier":"function_body_length","ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","location":{"line":4034,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 54 lines"}},{"text":" let recordID = CKRecord.ID(recordName: makeBackupRecordName(prefix: Self.backupDeletionRecordPrefix, id: recordingId))","violation":{"ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 126 characters","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":4116,"character":1},"ruleName":"Line Length","severity":"warning"}},{"text":" AppLog.shared.iCloudSync(\"Recorded iCloud deletion marker for \\(recordingId.uuidString); removed \\(deletedCloudRecords) cloud content records\", level: .debug)","violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","location":{"character":1,"line":4138,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"reason":"Line should be 120 characters or less; currently it has 166 characters"}},{"text":" AppLog.shared.iCloudSync(\"Removed \\(deletedCloudRecords) iCloud records for local-only recording \\(recordingId.uuidString)\", level: .debug)","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 147 characters","ruleDescription":"Lines should not span too many characters.","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1,"line":4186},"ruleName":"Line Length","ruleIdentifier":"line_length"}},{"text":" get { Self.decodePendingCloudMutations(PendingLocalOnlyCloudRemoval.self, key: Self.pendingLocalOnlyRemovalsKey) }","violation":{"severity":"warning","reason":"Line should be 120 characters or less; currently it has 122 characters","location":{"line":4214,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1},"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length"}},{"text":" lastMaintenanceMessage = \"Existing iCloud copies for local-only recordings will be removed when iCloud sync is available.\"","violation":{"reason":"Line should be 120 characters or less; currently it has 130 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1,"line":4268},"ruleName":"Line Length"}},{"text":" lastMaintenanceMessage = \"Deleted summaries will be removed from iCloud sync records when iCloud sync is available.\"","violation":{"ruleName":"Line Length","severity":"warning","location":{"line":4278,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"reason":"Line should be 120 characters or less; currently it has 124 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."}},{"text":" func flushPendingiCloudMutations(appCoordinator: AppDataCoordinator) async throws -> (deletions: Int, localOnlyRemovals: Int, summaryRemovals: Int) {","violation":{"ruleName":"Line Length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":4298,"character":1},"reason":"Line should be 120 characters or less; currently it has 153 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning"}},{"violation":{"reason":"Tuples should have at most 2 members","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","severity":"warning","ruleName":"Large Tuple","location":{"character":90,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":4298}},"text":" func flushPendingiCloudMutations(appCoordinator: AppDataCoordinator) async throws -> (deletions: Int, localOnlyRemovals: Int, summaryRemovals: Int) {"},{"violation":{"ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 179 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":4347},"ruleIdentifier":"line_length"},"text":" \"Flushed pending iCloud mutations - deletions: \\(flushedDeletions), local-only removals: \\(flushedLocalOnlyRemovals), summary removals: \\(flushedSummaryRemovals)\","},{"violation":{"reason":"Line should be 120 characters or less; currently it has 122 characters","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","severity":"warning","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1,"line":4375}},"text":" private func applyiCloudDeletionMarkers(appCoordinator: AppDataCoordinator) async throws -> (local: Int, cloud: Int) {"},{"violation":{"ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","reason":"Line should be 120 characters or less; currently it has 122 characters","location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":4390}},"text":" ?? decodeBackupRecordUUID(recordName: record.recordID.recordName, prefix: Self.backupDeletionRecordPrefix)"},{"violation":{"ruleDescription":"Lines should not span too many characters.","severity":"error","ruleName":"Line Length","ruleIdentifier":"line_length","location":{"character":1,"line":4415,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"reason":"Line should be 200 characters or less; currently it has 226 characters"},"text":" self.lastMaintenanceMessage = \"Applied \\(deletedLocalCount) iCloud deletion\\(deletedLocalCount == 1 ? \"\" : \"s\") to this device and cleaned \\(deletedCloudCount) cloud record\\(deletedCloudCount == 1 ? \"\" : \"s\").\""},{"violation":{"ruleIdentifier":"line_length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","location":{"line":4429,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"reason":"Line should be 120 characters or less; currently it has 122 characters"},"text":" ?? decodeBackupRecordUUID(recordName: record.recordID.recordName, prefix: Self.backupDeletionRecordPrefix)"},{"violation":{"ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning","reason":"Line should be 120 characters or less; currently it has 134 characters","location":{"line":4458,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1},"ruleName":"Line Length"},"text":" let transcriptRecords = (try? await fetchBackupRecords(recordType: Self.backupTranscriptRecordType, database: database)) ?? []"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 128 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1,"line":4459},"ruleDescription":"Lines should not span too many characters.","ruleName":"Line Length","severity":"warning","ruleIdentifier":"line_length"},"text":" let summaryRecords = (try? await fetchBackupRecords(recordType: Self.backupSummaryRecordType, database: database)) ?? []"},{"violation":{"ruleName":"Line Length","severity":"warning","location":{"line":4553,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"reason":"Line should be 120 characters or less; currently it has 149 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.iCloudSync(\"Could not scan legacy summary sync records for deletion cleanup: \\(error.localizedDescription)\", level: .error)"},{"violation":{"ruleName":"Line Length","ruleIdentifier":"line_length","severity":"warning","location":{"line":4576,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters","ruleDescription":"Lines should not span too many characters."},"text":" AppLog.shared.iCloudSync(\"Could not scan legacy summary sync records: \\(error.localizedDescription)\", level: .error)"},{"violation":{"ruleIdentifier":"function_body_length","severity":"warning","reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 79 lines","location":{"character":13,"line":4607,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"ruleDescription":"Function bodies should not span too many lines","ruleName":"Function Body Length"},"text":" private func computeBackupStateSignature("},{"violation":{"ruleIdentifier":"line_length","ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","reason":"Line should be 120 characters or less; currently it has 123 characters","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":4849,"character":1}},"text":" updateIntField(Self.fieldSyncSchemaVersion, value: Self.activeManifestSchemaVersion, on: record, changed: &changed)"},{"violation":{"reason":"Line should be 120 characters or less; currently it has 137 characters","ruleIdentifier":"line_length","ruleName":"Line Length","ruleDescription":"Lines should not span too many characters.","severity":"warning","location":{"line":5479,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","character":1}},"text":" \"Deploy the development CloudKit schema for \\(Self.sharedContainerIdentifier) to production, then try syncing again.\""},{"violation":{"location":{"line":5568,"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift"},"ruleName":"Line Length","reason":"Line should be 120 characters or less; currently it has 136 characters","ruleIdentifier":"line_length","ruleDescription":"Lines should not span too many characters.","severity":"warning"},"text":" private func collectSettingsForBackup(includeSensitiveSettings: Bool) -> (values: [String: Data], includedSensitiveSettings: Bool) {"},{"violation":{"location":{"character":1,"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":5753},"reason":"File should contain 1000 lines or less: currently contains 5753","ruleDescription":"Files should not span too many lines.","ruleName":"File Length","ruleIdentifier":"file_length","severity":"error"},"text":"}"}] \ No newline at end of file +[{"text":"struct AISettingsView: View {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift","line":107,"character":1},"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 389 lines"}},{"text":" @AppStorage(SummarizationTimeouts.storageKey) private var summarizationTimeout: Double = SummarizationTimeouts.defaultTimeout","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift","line":112,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" let currentEngineName = UserDefaults.standard.string(forKey: \"SelectedAIEngine\") ?? AIEngineType.mlxSwift.rawValue","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift","line":139,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" let currentEngine = UserDefaults.standard.string(forKey: \"SelectedAIEngine\") ?? AIEngineType.mlxSwift.rawValue","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift","line":150,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" let modelString = UserDefaults.standard.string(forKey: \"openAISummarizationModel\") ?? OpenAISummarizationModel.gpt41Mini.rawValue","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift","line":227,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" let modelName = UserDefaults.standard.string(forKey: \"mistralModel\") ?? MistralAIModel.mistralMedium2508.rawValue","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift","line":232,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" let modelName = UserDefaults.standard.string(forKey: AppSettingsKeys.ollamaModelName) ?? AppSettingsKeys.Defaults.ollamaModelName","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift","line":235,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" let storedModelName = UserDefaults.standard.string(forKey: \"awsBedrockModel\") ?? AWSBedrockModel.claude45Haiku.rawValue","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift","line":241,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" let model = UserDefaults.standard.string(forKey: MLXSwiftSettingsKeys.modelId) ?? MLXSwiftSettingsKeys.defaultModelId","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift","line":251,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" Text(\"This will regenerate all summaries using the current AI engine. Only summaries with existing transcripts will be processed. This may take some time depending on how many recordings you have.\")","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift","line":285,"character":1},"reason":"Line should be 200 characters or less; currently it has 210 characters"}},{"text":" AISettingsCard(title: \"Current Engine\", systemImage: currentEngineType.map { iconName(for: $0) } ?? \"sparkles\", tint: currentEngineType.map { engineColor(for: $0) } ?? .accentColor) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift","line":424,"character":1},"reason":"Line should be 120 characters or less; currently it has 191 characters"}},{"text":" Label(viewModel.regenerationManager.isRegenerating ? \"Processing...\" : \"Regenerate All Summaries\", systemImage: \"arrow.clockwise\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift","line":527,"character":1},"reason":"Line should be 120 characters or less; currently it has 146 characters"}},{"text":" func openSettings(for engine: AIEngineType) {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift","line":766,"character":5},"reason":"Function should have complexity 10 or less; currently complexity is 12"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AISettingsView.swift","line":930,"character":1},"reason":"File should contain 400 lines or less: currently contains 930"}},{"text":"class AWSBedrockService: ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":14,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 533 lines"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"Failed to initialize AWS Bedrock client: \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":64,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" AppLog.shared.networking(\"AWS Bedrock Summary: Large text detected (\\(tokenCount) tokens), using chunked processing\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":76,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":233,"character":1},"reason":"Line should be 120 characters or less; currently it has 167 characters"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":233,"character":56},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.networking(\"AWS Bedrock: Text token count: \\(tokenCount), max allowed: \\(maxTokens)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":241,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" AppLog.shared.networking(\"AWS Bedrock: Large transcript detected (\\(tokenCount) tokens), using chunked processing\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":244,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" private func invokeModel(","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":284,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 61 lines"}},{"text":" AppLog.shared.networking(\"AWS Bedrock API Configuration - Model: \\(config.model.rawValue), Region: \\(config.region)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":296,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"Failed to encode request: \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":313,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" AppLog.shared.networking(\"AWS Bedrock response rejected: \\(responseData.count) bytes exceeds \\(responseLimit) byte limit\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":354,"character":1},"reason":"Line should be 120 characters or less; currently it has 153 characters"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"AWS Bedrock response exceeded the maximum allowed size\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":355,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.networking(\"AWS Bedrock API Response received, size: \\(responseData.count) bytes\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":360,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" AppLog.shared.networking(\"AWS Bedrock API Success - Model: \\(config.model.rawValue), response: \\(modelResponse.content.count) chars\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":367,"character":1},"reason":"Line should be 120 characters or less; currently it has 145 characters"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"AWS Bedrock API request failed: \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":373,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" private func processCompleteStructured(text: String, contentType: ContentType) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":396,"character":1},"reason":"Line should be 200 characters or less; currently it has 211 characters"}},{"text":" private func processCompleteStructured(text: String, contentType: ContentType) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":396,"character":100},"reason":"Tuples should have at most 2 members"}},{"text":" private func processCompleteIndividual(text: String, contentType: ContentType) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":412,"character":1},"reason":"Line should be 200 characters or less; currently it has 211 characters"}},{"text":" private func processCompleteIndividual(text: String, contentType: ContentType) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":412,"character":100},"reason":"Tuples should have at most 2 members"}},{"text":" private func processCompleteChunked(text: String, contentType: ContentType, maxTokens: Int) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":434,"character":1},"reason":"Line should be 200 characters or less; currently it has 224 characters"}},{"text":" private func processCompleteChunked(text: String, contentType: ContentType, maxTokens: Int) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":434,"character":113},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.networking(\"AWS Bedrock: Processing chunk \\(index + 1) of \\(chunks.count) (\\(TokenManager.getTokenCount(chunk)) tokens)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":446,"character":1},"reason":"Line should be 120 characters or less; currently it has 162 characters"}},{"text":" AppLog.shared.networking(\"AWS Bedrock: Final summary: \\(combinedSummary.count) chars, tasks: \\(deduplicatedTasks.count), reminders: \\(deduplicatedReminders.count), titles: \\(deduplicatedTitles.count)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":481,"character":1},"reason":"Line should be 200 characters or less; currently it has 224 characters"}},{"text":" Combine the following summaries into one comprehensive, well-structured summary that captures all key information without redundancy.","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":505,"character":1},"reason":"Line should be 120 characters or less; currently it has 145 characters"}},{"text":" private func parseCompleteResponseFromJSON(_ jsonString: String) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":600,"character":1},"reason":"Line should be 120 characters or less; currently it has 165 characters"}},{"text":" private func parseCompleteResponseFromJSON(_ jsonString: String) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":600,"character":80},"reason":"Tuples should have at most 2 members"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWS\/AWSBedrockService.swift","line":729,"character":1},"reason":"File should contain 400 lines or less: currently contains 729"}},{"text":"struct AWSBedrockSettingsView: View {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSBedrockSettingsView.swift","line":10,"character":1},"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 457 lines"}},{"text":" Text(\"AWS Bedrock provides access to foundation models from Anthropic, Amazon, Meta, and other providers for high-quality AI summaries and content analysis.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSBedrockSettingsView.swift","line":87,"character":1},"reason":"Line should be 120 characters or less; currently it has 174 characters"}},{"text":" Text(\"Use an AWS profile configured with the AWS CLI or SDK. The profile should have access to AWS Bedrock in the selected region.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSBedrockSettingsView.swift","line":150,"character":1},"reason":"Line should be 120 characters or less; currently it has 156 characters"}},{"text":" Text(\"Your AWS credentials are stored securely on your device. Never share these credentials or commit them to version control.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSBedrockSettingsView.swift","line":227,"character":1},"reason":"Line should be 120 characters or less; currently it has 149 characters"}},{"text":" Text(\"Controls randomness in responses. Lower values (0.1) are more focused and deterministic, higher values (0.9) are more creative and varied.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSBedrockSettingsView.swift","line":354,"character":1},"reason":"Line should be 120 characters or less; currently it has 166 characters"}},{"text":" Text(\"Maximum number of tokens in the response. Higher values allow for longer responses but may increase costs.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSBedrockSettingsView.swift","line":374,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" Link(\"Model Access Setup Guide\", destination: URL(string: \"https:\/\/docs.aws.amazon.com\/bedrock\/latest\/userguide\/model-access.html\")!)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSBedrockSettingsView.swift","line":446,"character":1},"reason":"Line should be 120 characters or less; currently it has 145 characters"}},{"text":" Link(\"IAM Permissions Guide\", destination: URL(string: \"https:\/\/docs.aws.amazon.com\/bedrock\/latest\/userguide\/security_iam_service-with-iam.html\")!)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSBedrockSettingsView.swift","line":447,"character":1},"reason":"Line should be 120 characters or less; currently it has 159 characters"}},{"text":" testResult = \"βœ… AWS Bedrock connection successful! Model \\(selectedModelEnum.displayName) is ready to use.\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSBedrockSettingsView.swift","line":511,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSBedrockSettingsView.swift","line":540,"character":1},"reason":"File should contain 400 lines or less: currently contains 540"}},{"text":" Text(\"AWS Transcribe provides high-quality transcription for large audio files with better accuracy than local transcription.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSSettingsView.swift","line":37,"character":1},"reason":"Line should be 120 characters or less; currently it has 151 characters"}},{"text":" Text(\"Your AWS credentials are stored securely on your device. Never share these credentials or commit them to version control.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSSettingsView.swift","line":106,"character":1},"reason":"Line should be 120 characters or less; currently it has 157 characters"}},{"text":" Text(\"This bucket will store your audio files temporarily during transcription. Make sure it exists and your credentials have access to it.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSSettingsView.swift","line":131,"character":1},"reason":"Line should be 120 characters or less; currently it has 165 characters"}},{"text":" Link(\"AWS Transcribe Documentation\", destination: URL(string: \"https:\/\/docs.aws.amazon.com\/transcribe\/\")!)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSSettingsView.swift","line":195,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" Link(\"AWS IAM Setup Guide\", destination: URL(string: \"https:\/\/docs.aws.amazon.com\/IAM\/latest\/UserGuide\/id_credentials_access-keys.html\")!)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSSettingsView.swift","line":196,"character":1},"reason":"Line should be 120 characters or less; currently it has 158 characters"}},{"text":"class AWSTranscribeService: NSObject, ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSTranscribeService.swift","line":66,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 453 lines"}},{"text":" awsCredentialIdentityResolver: AWSClientCredentialResolver.staticResolver(credentials: sharedCredentials),","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSTranscribeService.swift","line":115,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" awsCredentialIdentityResolver: AWSClientCredentialResolver.staticResolver(credentials: sharedCredentials),","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSTranscribeService.swift","line":140,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" func transcribeAudioFileWithChunking(at url: URL, recordingId: UUID? = nil) async throws -> AWSTranscribeResult {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSTranscribeService.swift","line":260,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 56 lines"}},{"text":" recordingId: recordingId ?? UUID() \/\/ TODO: Get actual recording ID from Core Data","violation":{"ruleName":"Todo","severity":"warning","ruleDescription":"TODOs and FIXMEs should be resolved.","ruleIdentifier":"todo","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSTranscribeService.swift","line":304,"character":55},"reason":"TODOs should be resolved (Get actual recording ID from C...)"}},{"text":" private func processTranscriptionResult(result: TranscribeClientTypes.TranscriptionJob) async throws -> AWSTranscribeResult {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSTranscribeService.swift","line":460,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" AppLog.shared.transcription(\"Failed to download transcript from S3, trying alternative method...\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSTranscribeService.swift","line":479,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" private func parseTranscript(data: Data) throws -> (fullText: String, segments: [TranscriptSegment], confidence: Double) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSTranscribeService.swift","line":556,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" private func parseTranscript(data: Data) throws -> (fullText: String, segments: [TranscriptSegment], confidence: Double) {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSTranscribeService.swift","line":556,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 71 lines"}},{"text":" private func parseTranscript(data: Data) throws -> (fullText: String, segments: [TranscriptSegment], confidence: Double) {","violation":{"ruleName":"Large Tuple","severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSTranscribeService.swift","line":556,"character":56},"reason":"Tuples should have at most 2 members"}},{"text":" let segments_data = speakerLabels[\"segments\"] as? [[String: Any]] {","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSTranscribeService.swift","line":592,"character":16},"reason":"Variable name 'segments_data' should only contain alphanumeric and other allowed characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AWSTranscribeService.swift","line":710,"character":1},"reason":"File should contain 400 lines or less: currently contains 710"}},{"text":" AppLog.shared.general(\"Received notification action: category=\\(categoryIdentifier), action=\\(actionIdentifier)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AppDelegate.swift","line":104,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AppDelegate.swift","line":144,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AppDelegate.swift","line":154,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" Summarize the following transcript in 4-7 concise bullet points. Keep factual details, decisions, action owners, and deadlines if present. Transcript:\\n\\n\\(chunks[0])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AppleNativeEngine.swift","line":38,"character":1},"reason":"Line should be 120 characters or less; currently it has 178 characters"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AppleNativeEngine.swift","line":125,"character":1},"reason":"Line should be 120 characters or less; currently it has 167 characters"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AppleNativeEngine.swift","line":125,"character":56},"reason":"Tuples should have at most 2 members"}},{"text":" throw SummarizationError.processingFailed(reason: \"Apple Foundation Models returned an empty response\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AppleNativeEngine.swift","line":206,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":"class AudioFileChunkingService: ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":12,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 478 lines"}},{"text":" AppLog.shared.chunking(\"shouldChunkFile - Checking: \\(url.lastPathComponent) for engine: \\(engine.rawValue)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":30,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" AppLog.shared.chunking(\"shouldChunkFile - File size check: \\(fileInfo.fileSize) bytes > \\(maxBytes) bytes = \\(needsChunking)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":46,"character":1},"reason":"Line should be 120 characters or less; currently it has 153 characters"}},{"text":" AppLog.shared.chunking(\"shouldChunkFile - Duration check: \\(fileInfo.duration)s > \\(maxSeconds)s = \\(needsChunking)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":49,"character":1},"reason":"Line should be 120 characters or less; currently it has 144 characters"}},{"text":" AppLog.shared.chunking(\"shouldChunkFile - Combined check: size(\\(exceedsSize)) || duration(\\(exceedsDuration)) = \\(needsChunking)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":54,"character":1},"reason":"Line should be 120 characters or less; currently it has 158 characters"}},{"text":" func chunkAudioFile(_ url: URL, for engine: TranscriptionEngine) async throws -> ChunkingResult {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":62,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 89 lines"}},{"text":" EnhancedLogger.shared.logChunking(\"Duration: \\(fileInfo.duration)s, Size: \\(fileInfo.fileSize) bytes\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":101,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" AppLog.shared.chunking(\"Creating single chunk for file - Duration: \\(fileInfo.duration)s, Size: \\(fileInfo.fileSize) bytes\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":112,"character":1},"reason":"Line should be 120 characters or less; currently it has 155 characters"}},{"text":" AppLog.shared.chunking(\"Single chunk created - ID: \\(singleChunk.id), Duration: \\(singleChunk.duration)s\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":123,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" chunks = try await chunkByFileSizeWithStreaming(url, maxBytes: maxBytes, config: config, fileInfo: fileInfo)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":151,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" chunks = try await chunkByDurationWithStreaming(url, maxSeconds: maxSeconds, config: config, fileInfo: fileInfo)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":153,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" chunks = try await chunkByCombinedStrategy(url, maxBytes: maxBytes, maxSeconds: maxSeconds, config: config, fileInfo: fileInfo)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":155,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"text":" func reassembleTranscript(from chunks: [TranscriptChunk], originalURL: URL, recordingName: String, recordingDate: Date, recordingId: UUID) async throws -> ReassemblyResult {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":184,"character":1},"reason":"Line should be 120 characters or less; currently it has 177 characters"}},{"text":" func createTranscriptChunk(from transcriptText: String, audioChunk: AudioChunk, segments: [TranscriptSegment] = []) -> TranscriptChunk {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":251,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" if chunk.chunkURL != chunk.originalURL {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":281,"character":13},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" AppLog.shared.chunking(\"Failed to delete chunk \\(chunk.chunkURL.lastPathComponent): \\(error)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":289,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" AppLog.shared.chunking(\"Removed duplicate segment at startTime=\\(Int(segment.startTime))s\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":379,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" private func chunkByFileSizeWithStreaming(_ url: URL, maxBytes: Int64, config: ChunkingConfig, fileInfo: AudioFileInfo) async throws -> [AudioChunk] {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":408,"character":1},"reason":"Line should be 120 characters or less; currently it has 154 characters"}},{"text":" private func chunkByFileSizeWithStreaming(_ url: URL, maxBytes: Int64, config: ChunkingConfig, fileInfo: AudioFileInfo) async throws -> [AudioChunk] {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":408,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 53 lines"}},{"text":" AppLog.shared.chunking(\"File analysis: \\(bytesPerSecond) bytes\/second, targeting \\(targetBytesPerChunk \/ 1024 \/ 1024)MB chunks\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":423,"character":1},"reason":"Line should be 120 characters or less; currently it has 151 characters"}},{"text":" try await exportAudioChunkWithStreaming(from: asset, startTime: chunkStartTime, endTime: chunkEndTime, outputURL: chunkURL)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":441,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" AppLog.shared.chunking(\"Chunk \\(sequenceNumber) is too large (\\(chunkSize) bytes > \\(maxBytes) bytes)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":449,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" adaptiveDuration = adaptiveDuration * 0.6","violation":{"ruleName":"Shorthand Operator","severity":"error","ruleDescription":"Prefer shorthand operators (+=, -=, *=, \/=) over doing the operation and assigning","ruleIdentifier":"shorthand_operator","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":453,"character":17},"reason":"Prefer shorthand operators (+=, -=, *=, \/=) over doing the operation and assigning"}},{"text":" AppLog.shared.chunking(\"Adjusting chunk duration to \\(adaptiveDuration)s for future chunks\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":454,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" adaptiveDuration = adaptiveDuration * 0.3 \/\/ Reduce by 70% for first chunk","violation":{"ruleName":"Shorthand Operator","severity":"error","ruleDescription":"Prefer shorthand operators (+=, -=, *=, \/=) over doing the operation and assigning","ruleIdentifier":"shorthand_operator","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":458,"character":21},"reason":"Prefer shorthand operators (+=, -=, *=, \/=) over doing the operation and assigning"}},{"text":" AppLog.shared.chunking(\"First chunk too large, reducing duration to \\(adaptiveDuration)s\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":459,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" AppLog.shared.chunking(\"Chunk smaller than expected, increasing duration to \\(adaptiveDuration)s\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":464,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" AppLog.shared.chunking(\"Chunk \\(sequenceNumber) created: \\(chunkSize) bytes, \\(chunkEndTime - chunkStartTime)s duration\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":478,"character":1},"reason":"Line should be 120 characters or less; currently it has 148 characters"}},{"text":" private func chunkByDurationWithStreaming(_ url: URL, maxSeconds: TimeInterval, config: ChunkingConfig, fileInfo: AudioFileInfo) async throws -> [AudioChunk] {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":492,"character":1},"reason":"Line should be 120 characters or less; currently it has 163 characters"}},{"text":" try await exportAudioChunkWithStreaming(from: asset, startTime: chunkStartTime, endTime: chunkEndTime, outputURL: chunkURL)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":518,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" AppLog.shared.chunking(\"Chunk \\(sequenceNumber) created: \\(chunkSize) bytes, \\(actualEndTime - chunkStartTime)s duration\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":536,"character":1},"reason":"Line should be 120 characters or less; currently it has 149 characters"}},{"text":" private func exportAudioChunkWithStreaming(from asset: AVAsset, startTime: TimeInterval, endTime: TimeInterval, outputURL: URL) async throws {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":550,"character":1},"reason":"Line should be 120 characters or less; currently it has 146 characters"}},{"text":" private func chunkByCombinedStrategy(_ url: URL, maxBytes: Int64, maxSeconds: TimeInterval, config: ChunkingConfig, fileInfo: AudioFileInfo) async throws -> [AudioChunk] {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":596,"character":1},"reason":"Line should be 120 characters or less; currently it has 175 characters"}},{"text":" private func chunkByCombinedStrategy(_ url: URL, maxBytes: Int64, maxSeconds: TimeInterval, config: ChunkingConfig, fileInfo: AudioFileInfo) async throws -> [AudioChunk] {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":596,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 59 lines"}},{"text":" AppLog.shared.chunking(\"Combined strategy: Duration limit \\(maxSeconds)s, Size-based duration limit \\(maxDurationFromSize)s\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":611,"character":1},"reason":"Line should be 120 characters or less; currently it has 148 characters"}},{"text":" try await exportAudioChunkWithStreaming(from: asset, startTime: chunkStartTime, endTime: chunkEndTime, outputURL: chunkURL)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":629,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" AppLog.shared.chunking(\"Chunk \\(sequenceNumber) exceeds size limit (\\(chunkSize) bytes > \\(maxBytes) bytes)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":638,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" adaptiveDuration = adaptiveDuration * 0.7 \/\/ Reduce by 30%","violation":{"ruleName":"Shorthand Operator","severity":"error","ruleDescription":"Prefer shorthand operators (+=, -=, *=, \/=) over doing the operation and assigning","ruleIdentifier":"shorthand_operator","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":639,"character":17},"reason":"Prefer shorthand operators (+=, -=, *=, \/=) over doing the operation and assigning"}},{"text":" AppLog.shared.chunking(\"Chunk \\(sequenceNumber) exceeds duration limit (\\(chunkDuration)s > \\(maxSeconds)s)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":647,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" AppLog.shared.chunking(\"Chunk \\(sequenceNumber) created: \\(chunkSize) bytes, \\(chunkDuration)s duration\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":668,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/AudioFileChunkingService.swift","line":690,"character":1},"reason":"File should contain 400 lines or less: currently contains 690"}},{"text":" init(type: JobType, recordingURL: URL, recordingName: String, modelName: String? = nil, sourceAudioURL: URL? = nil, chunks: [AudioChunk]? = nil) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":86,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" init(id: UUID, type: JobType, recordingPath: String, recordingName: String, modelName: String? = nil, sourceAudioPath: String? = nil, status: JobProcessingStatus, progress: Double, startTime: Date, processingStartTime: Date? = nil, completionTime: Date?, chunks: [AudioChunk]?, error: String?) {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":139,"character":1},"reason":"Line should be 200 characters or less; currently it has 299 characters"}},{"text":" throw DecodingError.dataCorruptedError(forKey: .engine, in: container, debugDescription: \"Invalid TranscriptionEngine value: \\(engineRawValue)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":208,"character":1},"reason":"Line should be 120 characters or less; currently it has 160 characters"}},{"text":"class BackgroundProcessingManager: ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":311,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 1758 lines"}},{"text":" AppLog.shared.backgroundProcessing(\"Skipping automatic job resume because previous session crashed\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":387,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" func startTranscriptionJob(recordingURL: URL, recordingName: String, engine: TranscriptionEngine, modelName: String? = nil, sourceAudioURL: URL? = nil, chunks: [AudioChunk]? = nil) async throws {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":448,"character":1},"reason":"Line should be 120 characters or less; currently it has 199 characters"}},{"text":" func startSummarizationJob(recordingURL: URL, recordingName: String, engine: String, modelName: String? = nil, replacingSummaryId: UUID? = nil) async throws -> UUID {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":473,"character":1},"reason":"Line should be 120 characters or less; currently it has 170 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Debug Status: activeJobs=\\(activeJobs.count), currentJob=\\(currentJob != nil), status=\\(processingStatus), bgTaskID=\\(backgroundTaskID.rawValue)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":555,"character":1},"reason":"Line should be 200 characters or less; currently it has 205 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Job \\(index): status=\\(job.status), progress=\\(job.progress)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":558,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"trackExternalJob: \\(job.type.displayName) - activeJobs count before: \\(activeJobs.count)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":575,"character":1},"reason":"Line should be 120 characters or less; currently it has 149 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"trackExternalJob done: activeJobs count after: \\(activeJobs.count)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":577,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"updateExternalJob: status=\\(job.status.displayName), activeJobs count: \\(activeJobs.count)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":586,"character":1},"reason":"Line should be 120 characters or less; currently it has 151 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Job already exists for \\(job.type.displayName). Skipping duplicate. Existing: \\(existingJobs.map { \"\\($0.id) status=\\($0.status.displayName)\" })\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":617,"character":1},"reason":"Line should be 120 characters or less; currently it has 194 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Marked \\(failedCount) unfinished job(s) failed after crash to prevent automatic restart\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":732,"character":1},"reason":"Line should be 120 characters or less; currently it has 152 characters"}},{"text":" func processNextJob() async {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":736,"character":5},"reason":"Function should have complexity 10 or less; currently complexity is 14"}},{"text":" func processNextJob() async {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":736,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 91 lines"}},{"text":" AppLog.shared.backgroundProcessing(\"Starting job: \\(nextJob.type.displayName), engine=\\(nextJob.type.engineName)\\(nextJob.modelName.map { \", model=\\($0)\" } ?? \"\"), fileExists=\\(FileManager.default.fileExists(atPath: nextJob.audioSourceURL.path))\")","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":757,"character":1},"reason":"Line should be 200 characters or less; currently it has 255 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Job already terminal (\\(currentStatus.displayName)): \\(nextJob.type.displayName)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":795,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" body: \"\\(nextJob.recordingName) β€” \\(nextJob.type.engineName)\\(modelInfo). Open the app to resume.\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":810,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Job already terminal (\\(currentStatus.displayName)): \\(nextJob.type.displayName), error was: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":827,"character":1},"reason":"Line should be 120 characters or less; currently it has 195 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Job failed: \\(nextJob.type.displayName), error: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":832,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" private func processTranscriptionJob(_ job: ProcessingJob, engine: TranscriptionEngine) async throws {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":896,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 15"}},{"text":" private func processTranscriptionJob(_ job: ProcessingJob, engine: TranscriptionEngine) async throws {","violation":{"ruleName":"Function Body Length","severity":"error","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":896,"character":13},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 136 lines"}},{"text":" EnhancedLogger.shared.logBackgroundProcessing(\"File needs chunking for \\(engine.rawValue)\", level: .info)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":921,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" \"Skipping final FluidAudio chunk under SDK minimum: seq=\\(chunk.sequenceNumber), duration=\\(chunk.duration)s\",","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":965,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" EnhancedLogger.shared.logBackgroundProcessing(\"Chunk \\(index + 1) transcribed: \\(transcriptResult.fullText.count) characters\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":983,"character":1},"reason":"Line should be 120 characters or less; currently it has 153 characters"}},{"text":" EnhancedLogger.shared.logBackgroundProcessing(\"Reassembling transcript from \\(transcriptChunks.count) chunks\", level: .info)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":988,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"No recording found for reassembly, using new UUID\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1003,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" recordingDate: Date(), \/\/ TODO: Get actual recording date","violation":{"ruleName":"Todo","severity":"warning","ruleDescription":"TODOs and FIXMEs should be resolved.","ruleIdentifier":"todo","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1015,"character":43},"reason":"TODOs should be resolved (Get actual recording date)"}},{"text":" AppLog.shared.backgroundProcessing(\"No recording found for single chunk, using new UUID\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1036,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" recordingDate: Date(), \/\/ TODO: Get actual recording date","violation":{"ruleName":"Todo","severity":"warning","ruleDescription":"TODOs and FIXMEs should be resolved.","ruleIdentifier":"todo","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1048,"character":43},"reason":"TODOs should be resolved (Get actual recording date)"}},{"text":" AppLog.shared.backgroundProcessing(\"Chunk cleanup failed after transcription: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1060,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" let hasTranscriptContent = transcriptChunks.contains { !$0.transcript.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty }","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1065,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Transcription job completed but no transcript content found! Total chunks: \\(transcriptChunks.count)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1068,"character":1},"reason":"Line should be 120 characters or less; currently it has 165 characters"}},{"text":" private func transcribeChunk(_ chunk: AudioChunk, engine: TranscriptionEngine) async throws -> TranscriptionResult {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1094,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 16"}},{"text":" private func transcribeChunk(_ chunk: AudioChunk, engine: TranscriptionEngine) async throws -> TranscriptionResult {","violation":{"ruleName":"Function Body Length","severity":"error","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1094,"character":13},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 105 lines"}},{"text":" AppLog.shared.backgroundProcessing(\"Starting transcription of chunk with engine: \\(engine.rawValue)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1095,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Chunk details: seq=\\(chunk.sequenceNumber), duration=\\(chunk.duration)s, size=\\(chunk.fileSize) bytes, isWholeFile=\\(chunk.originalURL == chunk.chunkURL)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1096,"character":1},"reason":"Line should be 200 characters or less; currently it has 214 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Chunk file is empty: \\(chunk.chunkURL.lastPathComponent)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1108,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Chunk file verified: \\(fileSize) bytes, duration: \\(chunk.duration)s\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1112,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Recording not found in Core Data for chunk, using fallback UUID\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1123,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" throw BackgroundProcessingError.processingFailed(\"Transcription engine not configured. Please configure a transcription engine in Settings.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1132,"character":1},"reason":"Line should be 120 characters or less; currently it has 157 characters"}},{"text":" throw BackgroundProcessingError.processingFailed(\"On-device model not downloaded. Please download the Parakeet model in Settings > Transcription > On Device.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1167,"character":1},"reason":"Line should be 120 characters or less; currently it has 179 characters"}},{"text":" throw BackgroundProcessingError.processingFailed(\"OpenAI API Compatible integration not yet implemented\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1186,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Transcription result is empty. Success: \\(result.success), Segments: \\(result.segments.count)\\(result.error.map { \", error: \\($0.localizedDescription)\" } ?? \"\")\")","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1194,"character":1},"reason":"Line should be 200 characters or less; currently it has 214 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Audio chunk contains no speech content (silent or background noise)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1196,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Empty result may indicate processing error or invalid audio format\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1198,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Transcription successful: \\(result.fullText.count) characters, \\(result.segments.count) segments\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1211,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Transcription failed after \\(String(format: \"%.1f\", processingTime))s: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1221,"character":1},"reason":"Line should be 120 characters or less; currently it has 165 characters"}},{"text":" throw BackgroundProcessingError.processingFailed(\"Transcription failed for \\(engine.rawValue): \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1224,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" let modelString = UserDefaults.standard.string(forKey: \"openAIModel\") ?? OpenAITranscribeModel.gpt4oMiniTranscribe.rawValue","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1232,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" let modelString = UserDefaults.standard.string(forKey: \"mistralTranscribeModel\") ?? MistralTranscribeModel.voxtralMiniLatest.rawValue","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1246,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Whisper config: port=\\(port), protocol=\\(selectedProtocol.rawValue)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1268,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Error getting audio duration: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1335,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Saved transcript: \\(transcriptData.segments.count) segments, \\(transcriptData.fullText.count) characters\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1377,"character":1},"reason":"Line should be 120 characters or less; currently it has 165 characters"}},{"text":" private func processSummarizationJob(_ job: ProcessingJob, engine: String) async throws {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1390,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 93 lines"}},{"text":" throw BackgroundProcessingError.processingFailed(\"Recording not found in Core Data for \\(job.recordingName)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1402,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" throw BackgroundProcessingError.processingFailed(\"No transcript found for \\(job.recordingName). Transcribe the recording first.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1408,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" private func generateSummary(_ transcriptText: String, engine: String, recordingURL: URL, recordingName: String) async throws -> EnhancedSummaryData {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1522,"character":1},"reason":"Line should be 120 characters or less; currently it has 154 characters"}},{"text":" private func generateSummary(_ transcriptText: String, engine: String, recordingURL: URL, recordingName: String) async throws -> EnhancedSummaryData {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1522,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 61 lines"}},{"text":" \/\/ TODO: Integrate with Ollama service when available","violation":{"ruleName":"Todo","severity":"warning","ruleDescription":"TODOs and FIXMEs should be resolved.","ruleIdentifier":"todo","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1547,"character":16},"reason":"TODOs should be resolved (Integrate with Ollama service ...)"}},{"text":" recordingDate: Date(), \/\/ TODO: Get actual recording date from file metadata","violation":{"ruleName":"Todo","severity":"warning","ruleDescription":"TODOs and FIXMEs should be resolved.","ruleIdentifier":"todo","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1589,"character":39},"reason":"TODOs should be resolved (Get actual recording date from...)"}},{"text":" let modelString = UserDefaults.standard.string(forKey: \"openAISummarizationModel\") ?? OpenAISummarizationModel.gpt41Mini.rawValue","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1604,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" if lowercaseText.contains(\"meeting\") || lowercaseText.contains(\"discussion\") || lowercaseText.contains(\"agenda\") {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1624,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" } else if lowercaseText.contains(\"technical\") || lowercaseText.contains(\"code\") || lowercaseText.contains(\"api\") {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1626,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" } else if lowercaseText.contains(\"personal\") || lowercaseText.contains(\"diary\") || lowercaseText.contains(\"journal\") {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1628,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Failed to schedule background processing: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1831,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Skipping automatic foreground job recovery because previous session crashed\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1846,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" private func resumeInterruptedJobs(notify: Bool = true) async {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1867,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 13"}},{"text":" private func resumeInterruptedJobs(notify: Bool = true) async {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1867,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 66 lines"}},{"text":" AppLog.shared.backgroundProcessing(\"Skipping interrupted job resume because previous session crashed\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1869,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" return message.contains(\"interrupted\") || message.contains(\"App was terminated\") || message.contains(\"App was closed\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1879,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" private func checkTranscriptionEngineAvailability(_ engine: TranscriptionEngine) async -> (available: Bool, reason: String?) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":1966,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" body: \"\\(job.recordingName) β€” \\(job.type.engineName)\\(modelInfo) was stopped because the app was closed. Open the app to resume.\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2056,"character":1},"reason":"Line should be 120 characters or less; currently it has 145 characters"}},{"text":" let engine = TranscriptionEngine(rawValue: jobEntry.engine ?? TranscriptionEngine.fluidAudio.rawValue) ?? .fluidAudio","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2098,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" let buffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: AVAudioFrameCount(frameCount)) else {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2158,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Failed to start keep-alive audio: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2185,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"After audio session config: \\(Int(backgroundTime))s background time\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2219,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"After audio session config: Unlimited background time\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2221,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"CRITICAL: Could not configure background audio session: \\(error.localizedDescription). This will severely limit background processing time.\", level: .error)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2226,"character":1},"reason":"Line should be 200 characters or less; currently it has 204 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Could not deactivate audio session: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2244,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Background task already running: \\(backgroundTaskID.rawValue)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2263,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Failed to start background task. Check background modes, device resources, or Background App Refresh setting.\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2283,"character":1},"reason":"Line should be 120 characters or less; currently it has 174 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Background time: Unlimited (likely in foreground or audio session active)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2293,"character":1},"reason":"Line should be 120 characters or less; currently it has 142 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"CRITICAL: Very limited background time (\\(Int(remainingTime))s). Check Background App Refresh, Low Power Mode.\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2299,"character":1},"reason":"Line should be 120 characters or less; currently it has 183 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Limited background time (\\(Int(remainingTime))s). Audio session may not be properly configured.\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2301,"character":1},"reason":"Line should be 120 characters or less; currently it has 168 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Background task expiration handled β€” Task catch block will complete cleanup\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2378,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" \/\/ Skip monitoring and refreshing if we have unlimited time (app is likely in foreground or has special privileges\/audio session active)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2386,"character":1},"reason":"Line should be 120 characters or less; currently it has 144 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Background task age: \\(Int(taskAge))s - refreshing to avoid iOS warning\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2394,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Background time running low (\\(Int(remainingTime))s remaining)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2404,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Current job: \\(job.type.displayName) - Progress: \\(Int(job.progress * 100))%\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2408,"character":1},"reason":"Line should be 120 characters or less; currently it has 145 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Background time critically low (\\(Int(remainingTime))s), will attempt graceful shutdown soon\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2414,"character":1},"reason":"Line should be 120 characters or less; currently it has 157 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Background time almost expired (\\(Int(remainingTime))s), initiating graceful shutdown\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2420,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Notification permission request failed: \\(error.localizedDescription)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2482,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Failed to send notification: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2512,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Failed to clear notification badge: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2553,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Leaving reconciled jobs stopped because previous session crashed\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2614,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Failed to update job in Core Data: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2650,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"error","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BackgroundProcessingManager.swift","line":2773,"character":1},"reason":"File should contain 1000 lines or less: currently contains 2773"}},{"text":"struct BisonNotesAIApp: App {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":24,"character":1},"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 814 lines"}},{"text":" NSLog(\"βœ… AI engine migrated from '\\(currentAIEngine ?? \"nil\")' to 'MLX Swift' (model: \\(defaultModelId), RAM: \\(deviceRAM)GB)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":91,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"text":" NSLog(\"βœ… Transcription engine migrated from '\\(currentTranscriptionEngine ?? \"nil\")' to '\\(TranscriptionEngine.fluidAudio.rawValue)'\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":104,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" NSLog(\"βœ… Transcription engine migrated from '\\(currentTranscriptionEngine ?? \"nil\")' to 'Mistral AI' (device has <4GB RAM)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":109,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" let legacyOnDeviceValues = [\"On Device (WhisperKit)\", \"On Device\", \"WhisperKit\", \"On-Device\", \"Apple Transcription\"]","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":151,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" let parakeetAlreadyDownloaded = UserDefaults.standard.bool(forKey: FluidAudioModelInfo.SettingsKeys.modelDownloaded)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":168,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" NSLog(\"βœ… Enabled experimental models because user had '\\(OnDeviceLLMModelInfo.granite4H.id)' selected (now experimental)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":273,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" AppLog.shared.general(\"Downgraded existing file protection class to completeUntilFirstUserAuthentication (1.11 β†’ 1.11.1)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":407,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" private func queueParakeetStartupRepairIfNeeded() {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":462,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 53 lines"}},{"text":" \"Parakeet startup repair: selected model is missing or incomplete; starting Wi-Fi background download\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":511,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" .onReceive(NotificationCenter.default.publisher(for: PlatformLifecycle.didFinishLaunchingNotification)) { _ in","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":544,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" .onReceive(NotificationCenter.default.publisher(for: PlatformLifecycle.didEnterBackgroundNotification)) { _ in","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":557,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" .onReceive(NotificationCenter.default.publisher(for: PlatformLifecycle.willTerminateNotification)) { _ in","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":560,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" .onReceive(NotificationCenter.default.publisher(for: PlatformLifecycle.didBecomeActiveNotification)) { _ in","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":563,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" .onReceive(NotificationCenter.default.publisher(for: Notification.Name(\"ShareExtensionDidSaveFile\"))) { _ in","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":580,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" NotificationCenter.default.post(name: NSNotification.Name(\"NavigateToSection\"), object: \"transcripts\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":639,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" \/\/\/ Handles files opened from the share sheet (e.g. Voice Memos, Files). Imports audio as recordings, text as transcripts.","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":746,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" NSLog(\"πŸ“Ž handleOpenURL called (scheme: \\(url.scheme ?? \"nil\"), host: \\(url.host ?? \"nil\"), file: \\(url.isFileURL ? url.lastPathComponent : \"none\"))\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":749,"character":1},"reason":"Line should be 120 characters or less; currently it has 157 characters"}},{"text":" private func scanSharedContainerForImports(trigger: SharedContainerImportTrigger) {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":811,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 13"}},{"text":" private func scanSharedContainerForImports(trigger: SharedContainerImportTrigger) {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":811,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 52 lines"}},{"text":" private func scanInboxForImportableFiles() {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":886,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 13"}},{"text":" guard let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":889,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" let remaining = (try? FileManager.default.contentsOfDirectory(at: inboxURL, includingPropertiesForKeys: nil)) ?? []","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":942,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" handleBackgroundProcessing(task: task as! BGProcessingTask)","violation":{"ruleName":"Force Cast","severity":"error","ruleDescription":"Force casts should be avoided","ruleIdentifier":"force_cast","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":986,"character":51},"reason":"Force casts should be avoided"}},{"text":" handleAppRefresh(task: task as! BGAppRefreshTask)","violation":{"ruleName":"Force Cast","severity":"error","ruleDescription":"Force casts should be avoided","ruleIdentifier":"force_cast","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":990,"character":41},"reason":"Force casts should be avoided"}},{"text":" AppLog.shared.general(\"Skipping background job processing because previous session crashed\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":1021,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" let _ = try? FileManager.default.contentsOfDirectory(at: plugInsURL, includingPropertiesForKeys: nil) {","violation":{"ruleName":"Unused Optional Binding","severity":"warning","ruleDescription":"Prefer `!= nil` over `let _ =`","ruleIdentifier":"unused_optional_binding","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":1105,"character":20},"reason":"Prefer `!= nil` over `let _ =`"}},{"text":"}","violation":{"ruleName":"File Length","severity":"error","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/BisonNotesAIApp.swift","line":1145,"character":1},"reason":"File should contain 1000 lines or less: currently contains 1145"}},{"text":"class ContentAnalyzer {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ContentAnalyzer.swift","line":13,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 428 lines"}},{"text":" AppLogger.shared.verbose(\"Classification scores - Meeting: \\(String(format: \"%.3f\", meetingScore)), Journal: \\(String(format: \"%.3f\", journalScore)), Technical: \\(String(format: \"%.3f\", technicalScore))\", category: \"ContentAnalyzer\")","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ContentAnalyzer.swift","line":28,"character":1},"reason":"Line should be 200 characters or less; currently it has 245 characters"}},{"text":" AppLogger.shared.verbose(\"Classified as \\(match.0.rawValue) with confidence \\(String(format: \"%.3f\", match.1))\", category: \"ContentAnalyzer\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ContentAnalyzer.swift","line":46,"character":1},"reason":"Line should be 120 characters or less; currently it has 157 characters"}},{"text":" AppLogger.shared.verbose(\"Classified as General (best score: \\(String(format: \"%.3f\", bestMatch?.1 ?? 0.0)) < threshold: \\(String(format: \"%.3f\", confidenceThreshold)))\", category: \"ContentAnalyzer\")","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ContentAnalyzer.swift","line":53,"character":1},"reason":"Line should be 200 characters or less; currently it has 211 characters"}},{"text":" for i in 0.. [EnhancedRecoveryAction] {","violation":{"ruleName":"Function Body Length","severity":"error","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedErrorHandlingSystem.swift","line":473,"character":13},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 152 lines"}},{"text":" private func suggestBackgroundProcessingRecovery(_ error: BackgroundProcessingError) -> [EnhancedRecoveryAction] {","violation":{"ruleName":"Function Body Length","severity":"error","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedErrorHandlingSystem.swift","line":637,"character":13},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 146 lines"}},{"text":" private func suggestChunkingRecovery(_ error: AudioChunkingError) -> [EnhancedRecoveryAction] {","violation":{"ruleName":"Function Body Length","severity":"error","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedErrorHandlingSystem.swift","line":795,"character":13},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 107 lines"}},{"text":" private func suggestFileManagementRecovery(_ error: FileManagementError) -> [EnhancedRecoveryAction] {","violation":{"ruleName":"Function Body Length","severity":"error","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedErrorHandlingSystem.swift","line":934,"character":13},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 122 lines"}},{"text":" private func suggestSystemRecovery(_ error: SystemError) -> [EnhancedRecoveryAction] {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedErrorHandlingSystem.swift","line":1066,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 92 lines"}},{"text":"}","violation":{"ruleName":"File Length","severity":"error","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedErrorHandlingSystem.swift","line":1165,"character":1},"reason":"File should contain 1000 lines or less: currently contains 1165"}},{"text":" init(recordingURL: URL?, recordingName: String, recordingDate: Date, transcriptExists: Bool = false, summaryExists: Bool = false, iCloudSynced: Bool = false) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":16,"character":1},"reason":"Line should be 120 characters or less; currently it has 163 characters"}},{"text":"class EnhancedFileManager: ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":113,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 420 lines"}},{"text":" let iCloudSynced = false \/\/ TODO: Implement actual iCloud sync check","violation":{"ruleName":"Todo","severity":"warning","ruleDescription":"TODOs and FIXMEs should be resolved.","ruleIdentifier":"todo","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":201,"character":37},"reason":"TODOs should be resolved (Implement actual iCloud sync c...)"}},{"text":" AppLog.shared.fileManagement(\"Cleaned up non-existent file relationship for: \\(normalizedURL.lastPathComponent)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":225,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" func refreshAllRelationships() {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":229,"character":5},"reason":"Function should have complexity 10 or less; currently complexity is 17"}},{"text":" func refreshAllRelationships() {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":229,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 79 lines"}},{"text":" let fileURLs = try FileManager.default.contentsOfDirectory(at: documentsURL, includingPropertiesForKeys: [.creationDateKey], options: [])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":244,"character":1},"reason":"Line should be 120 characters or less; currently it has 157 characters"}},{"text":" return fileExtension == \"m4a\" || fileExtension == \"mp3\" || fileExtension == \"wav\" || fileExtension == \"aac\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":247,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" AppLog.shared.fileManagement(\"Removed \\(removedFiles.count) non-existent file relationships (\\(uniqueRemoved.count) unique files, \\(duplicateCount) duplicates)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":292,"character":1},"reason":"Line should be 120 characters or less; currently it has 181 characters"}},{"text":" func deleteRecording(_ url: URL, preserveSummary: Bool) async throws {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":336,"character":5},"reason":"Function should have complexity 10 or less; currently complexity is 13"}},{"text":" func deleteRecording(_ url: URL, preserveSummary: Bool) async throws {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":336,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 73 lines"}},{"text":" AppLog.shared.fileManagement(\"Thumbnail generation warning during file deletion: \\(error.localizedDescription)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":359,"character":1},"reason":"Line should be 120 characters or less; currently it has 147 characters"}},{"text":" AppLog.shared.fileManagement(\"Thumbnail generation warning during \\(ext) file deletion: \\(error.localizedDescription)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":375,"character":1},"reason":"Line should be 120 characters or less; currently it has 162 characters"}},{"text":" AppLog.shared.fileManagement(\"File does not exist, using current date for: \\(url.lastPathComponent)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":533,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.fileManagement(\"Error getting creation date for \\(url.lastPathComponent): \\(error)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":541,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" AppLog.shared.fileManagement(\"Normalized \\(duplicateCount) duplicate URL entries when loading file relationships\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":605,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" let allFiles = try FileManager.default.contentsOfDirectory(at: documentsURL, includingPropertiesForKeys: nil)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":622,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" if !coreDataURLs.contains(audioFile.path) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":641,"character":17},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" func cleanupOrphanedAudioFiles(coordinator: AppDataCoordinator, dryRun: Bool = true) -> (deleted: Int, totalSize: Int64, errors: [String]) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":658,"character":1},"reason":"Line should be 120 characters or less; currently it has 144 characters"}},{"text":" func cleanupOrphanedAudioFiles(coordinator: AppDataCoordinator, dryRun: Bool = true) -> (deleted: Int, totalSize: Int64, errors: [String]) {","violation":{"ruleName":"Large Tuple","severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":658,"character":93},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.fileManagement(\"Would delete: \\(file.lastPathComponent) (\\(fileSize) bytes)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":681,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" let errorMsg = \"Failed to \\(dryRun ? \"analyze\" : \"delete\") \\(file.lastPathComponent): \\(error.localizedDescription)\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":685,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" AppLog.shared.fileManagement(\"Dry run complete: Found \\(orphanedFiles.count) orphaned files totaling \\(totalSize) bytes\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":692,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedFileManager.swift","line":733,"character":1},"reason":"File should contain 400 lines or less: currently contains 733"}},{"text":" func logAudioSessionConfiguration(_ category: AVAudioSession.Category, mode: AVAudioSession.Mode, options: AVAudioSession.CategoryOptions) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedLoggingSystem.swift","line":378,"character":1},"reason":"Line should be 120 characters or less; currently it has 144 characters"}},{"text":" backgroundProcessing(\"Background job failed: \\(job.type.displayName) for \\(job.recordingName) - \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedLoggingSystem.swift","line":410,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" fileManagement(\"File relationship updated for \\(recordingURL.lastPathComponent) - Transcript: \\(transcriptExists), Summary: \\(summaryExists)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedLoggingSystem.swift","line":428,"character":1},"reason":"Line should be 120 characters or less; currently it has 165 characters"}},{"text":" errorRecovery(\"Recovery failed for \\(error.localizedDescription): \\(recoveryAction) - \\(failureReason)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedLoggingSystem.swift","line":440,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" \"\\(operation) (\\(context)): \\(String(format: \"%.2f\", duration))s, Memory: \\(String(format: \"%.1f\", memoryUsage))MB (\\(String(format: \"%+.1f\", memoryDelta))MB)\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedLoggingSystem.swift","line":481,"character":1},"reason":"Line should be 120 characters or less; currently it has 167 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedLoggingSystem.swift","line":510,"character":1},"reason":"File should contain 400 lines or less: currently contains 510"}},{"text":"class EnhancedTranscriptionManager: NSObject, ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":61,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 1348 lines"}},{"text":" let modelString = UserDefaults.standard.string(forKey: \"openAIModel\") ?? OpenAITranscribeModel.gpt4oMiniTranscribe.rawValue","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":152,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" let modelString = UserDefaults.standard.string(forKey: \"mistralTranscribeModel\") ?? MistralTranscribeModel.voxtralMiniLatest.rawValue","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":174,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" \/\/ Note: Speech authorization will be requested when user actually tries to use native speech recognition transcription","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":276,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" AppLog.shared.transcription(\"Started background task for Whisper: \\(backgroundTaskID.rawValue)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":301,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" AppLog.shared.transcription(\"Ending background task for Whisper: \\(backgroundTaskID.rawValue)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":317,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" AppLog.shared.transcription(\"High app memory usage detected (\\(memoryUsageMB) MB), but continuing transcription\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":386,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" func transcribeAudioFile(at url: URL, using engine: TranscriptionEngine? = nil) async throws -> TranscriptionResult {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":418,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" func transcribeAudioFile(at url: URL, using engine: TranscriptionEngine? = nil) async throws -> TranscriptionResult {","violation":{"ruleName":"Cyclomatic Complexity","severity":"error","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":418,"character":5},"reason":"Function should have complexity 10 or less; currently complexity is 21"}},{"text":" func transcribeAudioFile(at url: URL, using engine: TranscriptionEngine? = nil) async throws -> TranscriptionResult {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":418,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 84 lines"}},{"text":" AppLog.shared.transcription(\"Audio file is very long (\\(durationMinutes) minutes), this may cause memory issues\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":440,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" AppLog.shared.transcription(\"File too large for AWS Transcribe: \\(duration\/3600) hours (max: 4 hours)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":475,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" AppLog.shared.transcription(\"Whisper not properly configured, falling back to native speech recognition\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":486,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" AppLog.shared.transcription(\"Starting native speech recognition for file: \\(url.lastPathComponent), duration: \\(duration)s\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":547,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" statusMessage = \"Speech recognition access denied. Enable in Settings > Privacy & Security > Speech Recognition.\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":567,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" AppLog.shared.transcription(\"Using single chunk transcription (duration: \\(duration)s <= \\(maxChunkDuration)s)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":594,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" AppLog.shared.transcription(\"Using large file transcription (duration: \\(duration)s > \\(maxChunkDuration)s)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":597,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" AppLog.shared.transcription(\"AWS job failed: \\(jobName) - \\(status.failureReason ?? \"Unknown error\")\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":659,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":"private func transcribeSingleChunk(url: URL) async throws -> TranscriptionResult {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":686,"character":9},"reason":"Function should have complexity 10 or less; currently complexity is 12"}},{"text":"private func transcribeSingleChunk(url: URL) async throws -> TranscriptionResult {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":686,"character":9},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 89 lines"}},{"text":" try await withCheckedThrowingContinuation { (continuation: CheckedContinuation) in","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":703,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" AppLog.shared.transcription(\"Transcript contains 'error' text -- may indicate a transcription error was saved as content\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":761,"character":1},"reason":"Line should be 120 characters or less; currently it has 166 characters"}},{"text":"private func transcribeLargeFile(url: URL, duration: TimeInterval) async throws -> TranscriptionResult {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":810,"character":9},"reason":"Function should have complexity 10 or less; currently complexity is 17"}},{"text":"private func transcribeLargeFile(url: URL, duration: TimeInterval) async throws -> TranscriptionResult {","violation":{"ruleName":"Function Body Length","severity":"error","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":810,"character":9},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 158 lines"}},{"text":" AppLog.shared.transcription(\"File duration (\\(duration\/60) minutes) exceeds safe limit (\\(maxSafeDuration\/60) minutes)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":818,"character":1},"reason":"Line should be 120 characters or less; currently it has 147 characters"}},{"text":" AppLog.shared.transcription(\"File size (\\(fileSizeMB) MB) exceeds safe limit (\\(maxFileSizeMB) MB)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":830,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" AppLog.shared.transcription(\"Insufficient disk space (\\(freeSpaceMB) MB), need at least \\(minFreeSpaceMB) MB\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":846,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" throw TranscriptionError.recognitionFailed(NSError(domain: \"TranscriptionCancelled\", code: -1, userInfo: [NSLocalizedDescriptionKey: \"Transcription was cancelled by user or system\"]))","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":885,"character":1},"reason":"Line should be 200 characters or less; currently it has 203 characters"}},{"text":" AppLog.shared.transcription(\"Speech recognizer became unavailable during chunk \\(index + 1), locale: \\(recognizer.locale.identifier), authStatus: \\(SFSpeechRecognizer.authorizationStatus().rawValue)\", level: .error)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":897,"character":1},"reason":"Line should be 200 characters or less; currently it has 235 characters"}},{"text":" throw TranscriptionError.recognitionFailed(NSError(domain: \"TranscriptionCancelled\", code: -1, userInfo: nil))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":985,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" AppLog.shared.transcription(\"No speech detected in any of \\(chunks.count) chunks -- audio may contain only silence or non-speech content\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1012,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" private func transcribeChunk(url: URL, startTime: TimeInterval, endTime: TimeInterval) async throws -> TranscriptionResult {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1030,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" private func transcribeChunkInternal(url: URL, startTime: Date) async throws -> TranscriptionResult {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1050,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 12"}},{"text":" private func transcribeChunkInternal(url: URL, startTime: Date) async throws -> TranscriptionResult {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1050,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 94 lines"}},{"text":" try await withCheckedThrowingContinuation { (continuation: CheckedContinuation) in","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1061,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" AppLog.shared.transcription(\"No speech detected in chunk - returning empty result to continue processing\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1091,"character":1},"reason":"Line should be 120 characters or less; currently it has 157 characters"}},{"text":" AppLog.shared.transcription(\"Empty transcript for chunk - returning empty result to continue processing\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1127,"character":1},"reason":"Line should be 120 characters or less; currently it has 160 characters"}},{"text":" guard let audioTrack = composition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid),","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1187,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" currentStart = currentStart + minAdvancement","violation":{"ruleName":"Shorthand Operator","severity":"error","ruleDescription":"Prefer shorthand operators (+=, -=, *=, \/=) over doing the operation and assigning","ruleIdentifier":"shorthand_operator","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1277,"character":17},"reason":"Prefer shorthand operators (+=, -=, *=, \/=) over doing the operation and assigning"}},{"text":"private func waitForAndRetrieveTranscription(jobName: String, awsService: AWSTranscribeService) async throws -> TranscriptionResult {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1342,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":"case .completed:","violation":{"ruleName":"Switch and Case Statement Alignment","severity":"warning","ruleDescription":"Case statements should vertically align with their closing brace, or indented if configured otherwise.","ruleIdentifier":"switch_case_alignment","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1351,"character":1},"reason":"Case statements should vertically aligned with their closing brace"}},{"text":"case .failed:","violation":{"ruleName":"Switch and Case Statement Alignment","severity":"warning","ruleDescription":"Case statements should vertically align with their closing brace, or indented if configured otherwise.","ruleIdentifier":"switch_case_alignment","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1368,"character":1},"reason":"Case statements should vertically aligned with their closing brace"}},{"text":" throw TranscriptionError.awsTranscriptionFailed(NSError(domain: \"AWSTranscribe\", code: -1, userInfo: [NSLocalizedDescriptionKey: errorMessage]))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1371,"character":1},"reason":"Line should be 120 characters or less; currently it has 164 characters"}},{"text":"case .inProgress:","violation":{"ruleName":"Switch and Case Statement Alignment","severity":"warning","ruleDescription":"Case statements should vertically align with their closing brace, or indented if configured otherwise.","ruleIdentifier":"switch_case_alignment","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1373,"character":1},"reason":"Case statements should vertically aligned with their closing brace"}},{"text":"default:","violation":{"ruleName":"Switch and Case Statement Alignment","severity":"warning","ruleDescription":"Case statements should vertically align with their closing brace, or indented if configured otherwise.","ruleIdentifier":"switch_case_alignment","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1377,"character":1},"reason":"Case statements should vertically aligned with their closing brace"}},{"text":" AppLog.shared.transcription(\"Error checking job status: \\(error), retrying in 30 seconds\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1382,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" throw TranscriptionError.awsTranscriptionFailed(NSError(domain: \"AWSTranscribe\", code: -2, userInfo: [NSLocalizedDescriptionKey: \"Transcription job timed out after \\(Int(maxWaitTime\/60)) minutes\"]))","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1389,"character":1},"reason":"Line should be 200 characters or less; currently it has 206 characters"}},{"text":" AppLogger.shared.verbose(\"Whisper transcription configured and ready\", category: \"EnhancedTranscriptionManager\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1854,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLogger.shared.warning(\"Whisper transcription selected but not configured\", category: \"EnhancedTranscriptionManager\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1857,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" AppLogger.shared.verbose(\"FluidAudio (Parakeet) transcription selected\", category: \"EnhancedTranscriptionManager\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1870,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" AppLogger.shared.verbose(\"Updating transcription engine to: \\(engine.rawValue)\", category: \"EnhancedTranscriptionManager\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1878,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" AppLog.shared.transcription(\"Non-critical speech recognition error (safe to ignore): \\(error.localizedDescription)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":1985,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"text":" return \"Speech recognition is not available. This may be due to simulator limitations, missing permissions, or device restrictions. Try running on a physical device or check Settings > Privacy & Security > Speech Recognition.\"","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":2045,"character":1},"reason":"Line should be 200 characters or less; currently it has 238 characters"}},{"text":" return \"Speech recognition permission denied. Please enable Speech Recognition in Settings > Privacy & Security > Speech Recognition to use native speech recognition transcription.\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":2047,"character":1},"reason":"Line should be 120 characters or less; currently it has 193 characters"}},{"text":" return \"On-device model is not ready. Download and initialize the Parakeet model in Settings > Transcription > On Device.\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":2071,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"error","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/EnhancedTranscriptionManager.swift","line":2082,"character":1},"reason":"File should contain 1000 lines or less: currently contains 2082"}},{"text":"class ErrorHandler: ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"warning","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ErrorHandlingSystem.swift","line":14,"character":1},"reason":"Class body should span 250 lines or less excluding comments and whitespace: currently spans 274 lines"}},{"text":" private let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? \"com.bisonnotes.app\", category: \"ErrorHandler\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ErrorHandlingSystem.swift","line":20,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" AppLog.shared.errorRecovery(\"Validating transcript for summarization, length: \\(text.count) characters\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ErrorHandlingSystem.swift","line":63,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ErrorHandlingSystem.swift","line":864,"character":1},"reason":"File should contain 400 lines or less: currently contains 864"}},{"text":"class FileImportManager: NSObject, ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"warning","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FileImportManager.swift","line":19,"character":1},"reason":"Class body should span 250 lines or less excluding comments and whitespace: currently spans 336 lines"}},{"text":" AppLog.shared.fileManagement(\"Thumbnail generation warning: \\(error.localizedDescription)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FileImportManager.swift","line":140,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" AppLog.shared.fileManagement(\"Archive restore: \\(matches.count) UUID-prefix matches for token \\(parsed.token)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FileImportManager.swift","line":200,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" AppLog.shared.fileManagement(\"Cleared archive flags for \\(recording.recordingName ?? \"unknown\") (local audio still present)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FileImportManager.swift","line":235,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" AppLog.shared.fileManagement(\"Thumbnail generation warning: \\(error.localizedDescription)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FileImportManager.swift","line":258,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" AppLog.shared.fileManagement(\"Restored archived recording \\(recording.recordingName ?? \"unknown\") from import \\(sourceURL.lastPathComponent)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FileImportManager.swift","line":270,"character":1},"reason":"Line should be 120 characters or less; currently it has 154 characters"}},{"text":" let resourceValues = try fileURL.resourceValues(forKeys: [.creationDateKey, .contentModificationDateKey, .fileSizeKey])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FileImportManager.swift","line":426,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" return \"Unsupported format: \\(format). Supported audio: m4a, mp3, wav, caf, aiff. Supported video: mp4, mov, m4v\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FileImportManager.swift","line":508,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FileImportManager.swift","line":546,"character":1},"reason":"File should contain 400 lines or less: currently contains 546"}},{"text":"final class FluidAudioManager: ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"warning","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift","line":10,"character":7},"reason":"Class body should span 250 lines or less excluding comments and whitespace: currently spans 330 lines"}},{"text":" UserDefaults.standard.set(selectedVersion, forKey: FluidAudioModelInfo.SettingsKeys.downloadedModelVersion)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift","line":37,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" let downloadedVersion = UserDefaults.standard.string(forKey: FluidAudioModelInfo.SettingsKeys.downloadedModelVersion)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift","line":43,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" if let dv = downloadedVersion {","violation":{"ruleName":"Identifier Name","severity":"warning","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift","line":46,"character":16},"reason":"Variable name 'dv' should be between 3 and 40 characters long"}},{"text":" UserDefaults.standard.set(availableVersion.rawValue, forKey: FluidAudioModelInfo.SettingsKeys.selectedModelVersion)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift","line":64,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" UserDefaults.standard.set(availableVersion.rawValue, forKey: FluidAudioModelInfo.SettingsKeys.downloadedModelVersion)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift","line":65,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" guard let appSupport = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first else {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift","line":75,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" \/\/\/ Whether the FluidAudio SDK is linked in this build. Compile-time constant, safe to access from any isolation domain.","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift","line":164,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" func downloadAndPrepareModel() async throws {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift","line":210,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 51 lines"}},{"text":" UserDefaults.standard.set(selectedVersion.rawValue, forKey: FluidAudioModelInfo.SettingsKeys.downloadedModelVersion)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift","line":268,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" func transcribe(audioURL: URL) async throws -> TranscriptionResult {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift","line":313,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 60 lines"}},{"text":" AppLog.shared.transcription(\"Could not read Parakeet input duration: \\(error.localizedDescription)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift","line":394,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" let message = \"Parakeet SDK transcription failed for \\(originalURL.lastPathComponent): \\(nsError.domain) \\(nsError.code) - \\(nsError.localizedDescription)\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift","line":404,"character":1},"reason":"Line should be 120 characters or less; currently it has 163 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioManager.swift","line":415,"character":1},"reason":"File should contain 400 lines or less: currently contains 415"}},{"text":" case v2","violation":{"ruleName":"Identifier Name","severity":"warning","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioModelInfo.swift","line":5,"character":14},"reason":"Enum element name 'v2' should be between 3 and 40 characters long"}},{"text":" case v3","violation":{"ruleName":"Identifier Name","severity":"warning","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioModelInfo.swift","line":6,"character":14},"reason":"Enum element name 'v3' should be between 3 and 40 characters long"}},{"text":" @AppStorage(FluidAudioModelInfo.SettingsKeys.selectedModelVersion) private var selectedModelVersion = FluidAudioModelInfo.ModelVersion.v2.rawValue","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioSettingsView.swift","line":5,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" Text(\"FluidAudio runs NVIDIA Parakeet models fully on-device using CoreML\/ANE acceleration. This option keeps audio local and does not remove your existing transcription engines.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FluidAudio\/FluidAudioSettingsView.swift","line":235,"character":1},"reason":"Line should be 120 characters or less; currently it has 196 characters"}},{"text":"class AWSBedrockEngine: SummarizationEngine, ConnectionTestable {","violation":{"ruleName":"Type Body Length","severity":"warning","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":14,"character":1},"reason":"Class body should span 250 lines or less excluding comments and whitespace: currently spans 301 lines"}},{"text":" let storedModelString = UserDefaults.standard.string(forKey: \"awsBedrockModel\") ?? AWSBedrockModel.claude45Haiku.rawValue","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":20,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" AppLogger.shared.verbose(\"Checking enableAWSBedrock setting - Value: \\(isEnabled), Key exists: \\(keyExists)\", category: \"AWSBedrockEngine\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":35,"character":1},"reason":"Line should be 120 characters or less; currently it has 151 characters"}},{"text":" AppLogger.shared.verbose(\"AWS credentials not configured in unified manager\", category: \"AWSBedrockEngine\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":63,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":168,"character":1},"reason":"Line should be 120 characters or less; currently it has 167 characters"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":168,"character":56},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.networking(\"AWSBedrockEngine: Large transcript detected (\\(tokenCount) tokens), using chunked processing\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":185,"character":1},"reason":"Line should be 120 characters or less; currently it has 151 characters"}},{"text":" AppLog.shared.networking(\"AWSBedrockEngine: Processing single chunk (\\(tokenCount) tokens)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":188,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" let storedModelString = UserDefaults.standard.string(forKey: \"awsBedrockModel\") ?? AWSBedrockModel.claude45Haiku.rawValue","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":203,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" AppLogger.shared.verbose(\"Updating configuration - Model: \\(modelString), Region: \\(credentials.region)\", category: \"AWSBedrockEngine\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":230,"character":1},"reason":"Line should be 120 characters or less; currently it has 151 characters"}},{"text":" private func processChunkedText(_ text: String, service: AWSBedrockService) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":245,"character":1},"reason":"Line should be 200 characters or less; currently it has 208 characters"}},{"text":" private func processChunkedText(_ text: String, service: AWSBedrockService) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":245,"character":97},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.networking(\"AWSBedrockEngine: Processing chunk \\(index + 1) of \\(chunks.count) (\\(TokenManager.getTokenCount(chunk)) tokens)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":265,"character":1},"reason":"Line should be 120 characters or less; currently it has 167 characters"}},{"text":" AppLog.shared.networking(\"AWSBedrockEngine: Failed to process chunk \\(index + 1): \\(error)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":285,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" AppLog.shared.networking(\"AWSBedrockEngine: Chunked processing completed in \\(String(format: \"%.2f\", processingTime))s\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":303,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.networking(\"AWSBedrockEngine: Final results - summary: \\(combinedSummary.count) chars, tasks: \\(uniqueTasks.count), reminders: \\(uniqueReminders.count), titles: \\(uniqueTitles.count)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":304,"character":1},"reason":"Line should be 200 characters or less; currently it has 221 characters"}},{"text":" return SummarizationError.aiServiceUnavailable(service: \"AWS Bedrock access denied. Please check your credentials and permissions.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":412,"character":1},"reason":"Line should be 120 characters or less; currently it has 144 characters"}},{"text":" return SummarizationError.aiServiceUnavailable(service: \"AWS Bedrock rate limit exceeded. Please try again later.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":414,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" return SummarizationError.aiServiceUnavailable(service: \"AWS Bedrock model not available. Please check your model configuration.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":416,"character":1},"reason":"Line should be 120 characters or less; currently it has 142 characters"}},{"text":"class LocalLLMEngine: SummarizationEngine, ConnectionTestable {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":427,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 466 lines"}},{"text":" AppLogger.shared.verbose(\"Checking enableOllama setting - Value: \\(isEnabled), Key exists: \\(keyExists)\", category: \"LocalLLMEngine\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":443,"character":1},"reason":"Line should be 120 characters or less; currently it has 145 characters"}},{"text":" AppLogger.shared.verbose(\"Ollama not explicitly configured (using defaults)\", category: \"LocalLLMEngine\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":469,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"Cannot connect to Ollama server. Please check your server URL and port settings.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":537,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"Cannot connect to Ollama server. Please check your server URL and port settings.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":569,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"Cannot connect to Ollama server. Please check your server URL and port settings.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":600,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"Cannot connect to Ollama server. Please check your server URL and port settings.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":631,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" return SummarizationError.aiServiceUnavailable(service: \"Ollama server is not connected. Please check your server URL and port settings.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":653,"character":1},"reason":"Line should be 120 characters or less; currently it has 154 characters"}},{"text":" return SummarizationError.aiServiceUnavailable(service: \"Ollama model '\\(model)' not found on server. Please check your model configuration.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":659,"character":1},"reason":"Line should be 120 characters or less; currently it has 158 characters"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":682,"character":1},"reason":"Line should be 120 characters or less; currently it has 167 characters"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":682,"character":56},"reason":"Tuples should have at most 2 members"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"Cannot connect to Ollama server. Please check your server URL and port settings.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":699,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" AppLog.shared.networking(\"LocalLLMEngine: Large transcript detected (\\(tokenCount) tokens), using chunked processing\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":708,"character":1},"reason":"Line should be 120 characters or less; currently it has 145 characters"}},{"text":" AppLog.shared.networking(\"LocalLLMEngine: Context window exceeded, retrying with chunked processing\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":718,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" private func processSingleChunk(_ text: String, service: OllamaService) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":733,"character":1},"reason":"Line should be 200 characters or less; currently it has 204 characters"}},{"text":" private func processSingleChunk(_ text: String, service: OllamaService) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":733,"character":93},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.networking(\"LocalLLMEngine: Processing single chunk with Ollama using complete processing\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":734,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.networking(\"LocalLLMEngine: Result - summary: \\(result.summary.count) chars, tasks: \\(result.tasks.count), reminders: \\(result.reminders.count), titles: \\(result.titles.count)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":740,"character":1},"reason":"Line should be 200 characters or less; currently it has 218 characters"}},{"text":" AppLog.shared.networking(\"LocalLLMEngine: Complete processing failed, falling back to individual calls: \\(error)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":745,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" private func processSingleChunkFallback(_ text: String, service: OllamaService) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":752,"character":1},"reason":"Line should be 200 characters or less; currently it has 212 characters"}},{"text":" private func processSingleChunkFallback(_ text: String, service: OllamaService) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":752,"character":101},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.networking(\"LocalLLMEngine: Failed to extract tasks\/reminders, continuing with empty arrays: \\(error)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":772,"character":1},"reason":"Line should be 120 characters or less; currently it has 144 characters"}},{"text":" AppLog.shared.networking(\"LocalLLMEngine: Failed to extract titles, continuing with empty array: \\(error)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":786,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" AppLog.shared.networking(\"LocalLLMEngine: Result - summary: \\(summary.count) chars, tasks: \\(tasks.count), reminders: \\(reminders.count), titles: \\(titles.count)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":793,"character":1},"reason":"Line should be 120 characters or less; currently it has 186 characters"}},{"text":" private func processChunkedText(_ text: String, service: OllamaService, maxTokens: Int) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":798,"character":1},"reason":"Line should be 200 characters or less; currently it has 220 characters"}},{"text":" private func processChunkedText(_ text: String, service: OllamaService, maxTokens: Int) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":798,"character":109},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.networking(\"LocalLLMEngine: Processing chunk \\(index + 1) of \\(chunks.count) (\\(TokenManager.getTokenCount(chunk)) tokens)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":813,"character":1},"reason":"Line should be 120 characters or less; currently it has 165 characters"}},{"text":" AppLog.shared.networking(\"LocalLLMEngine: Failed to process chunk \\(index + 1): \\(error)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":833,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" AppLog.shared.networking(\"LocalLLMEngine: Chunked processing completed in \\(String(format: \"%.2f\", processingTime))s\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":851,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" AppLog.shared.networking(\"LocalLLMEngine: Final results - summary: \\(combinedSummary.count) chars, tasks: \\(uniqueTasks.count), reminders: \\(uniqueReminders.count), titles: \\(uniqueTitles.count)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":852,"character":1},"reason":"Line should be 200 characters or less; currently it has 219 characters"}},{"text":" AppLog.shared.networking(\"LocalLLMEngine: Updating configuration - Server: \\(serverURL), Port: \\(port), Model: \\(modelName)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":928,"character":1},"reason":"Line should be 120 characters or less; currently it has 148 characters"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"Cannot connect to Ollama server at \\(config?.baseURL ?? \"unknown\")\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":953,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" AppLog.shared.networking(\"LocalLLMEngine: Configured model '\\(config?.modelName ?? \"unknown\")' is not available\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":960,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" AppLog.shared.networking(\"LocalLLMEngine: Switching to available model '\\(firstAvailableModel)'\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":964,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.networking(\"LocalLLMEngine: Updated saved model preference to '\\(firstAvailableModel)'\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":982,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"No models available on Ollama server. Please install a model using 'ollama pull '\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":985,"character":1},"reason":"Line should be 120 characters or less; currently it has 167 characters"}},{"text":" let testText = \"I need to call John tomorrow and buy groceries. Don't forget the meeting at 3pm. We discussed the quarterly budget and decided to increase marketing spend.\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1041,"character":1},"reason":"Line should be 120 characters or less; currently it has 180 characters"}},{"text":" let summary = \"Successfully processed: Summary (\\(result.summary.count) chars), \\(result.tasks.count) tasks, \\(result.reminders.count) reminders, \\(result.titles.count) titles, content type: \\(result.contentType.rawValue)\"","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1045,"character":1},"reason":"Line should be 200 characters or less; currently it has 234 characters"}},{"text":"class GoogleAIStudioEngine: SummarizationEngine {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1098,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 427 lines"}},{"text":" private let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? \"com.bisonnotes.app\", category: \"GoogleAIStudioEngine\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1109,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1167,"character":1},"reason":"Line should be 120 characters or less; currently it has 167 characters"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1167,"character":56},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.networking(\"GoogleAI: Large transcript detected (\\(tokenCount) tokens), using chunked processing\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1179,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"text":" AppLog.shared.networking(\"GoogleAI: Context limit reached, falling back to chunked processing\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1189,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" private func processSingleChunk(_ text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1196,"character":1},"reason":"Line should be 120 characters or less; currently it has 180 characters"}},{"text":" private func processSingleChunk(_ text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1196,"character":69},"reason":"Tuples should have at most 2 members"}},{"text":" private func processChunkedText(_ text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1217,"character":1},"reason":"Line should be 120 characters or less; currently it has 180 characters"}},{"text":" private func processChunkedText(_ text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1217,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 55 lines"}},{"text":" private func processChunkedText(_ text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1217,"character":69},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.networking(\"GoogleAI: Processing chunk \\(index + 1) of \\(chunks.count) (\\(TokenManager.getTokenCount(chunk)) tokens)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1233,"character":1},"reason":"Line should be 120 characters or less; currently it has 159 characters"}},{"text":" let deduplicatedTasks = Array(Set(allTasks.map { $0.text })).prefix(15).map { TaskItem(text: $0, priority: .medium, confidence: 0.8) }","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1279,"character":1},"reason":"Line should be 120 characters or less; currently it has 142 characters"}},{"text":" let deduplicatedReminders = Array(Set(allReminders.map { $0.text })).prefix(15).map { ReminderItem(text: $0, timeReference: ReminderItem.TimeReference.fromReminderText($0), urgency: .later, confidence: 0.8) }","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1280,"character":1},"reason":"Line should be 200 characters or less; currently it has 216 characters"}},{"text":" let deduplicatedTitles = Array(Set(allTitles.map { $0.text })).prefix(5).map { TitleItem(text: $0, confidence: 0.8) }","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1281,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" AppLog.shared.networking(\"GoogleAI: Final results - tasks: \\(deduplicatedTasks.count), reminders: \\(deduplicatedReminders.count), titles: \\(deduplicatedTitles.count)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1288,"character":1},"reason":"Line should be 120 characters or less; currently it has 190 characters"}},{"text":" Focus on the key points and main ideas. Keep the summary clear, informative, and well-structured with proper markdown formatting.","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1328,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" - Examples of tasks to AVOID: \"Follow the news about elections\", \"Check updates on celebrity gossip\", \"Monitor world events\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1344,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" - Examples of GOOD reminders: \"Dentist appointment on Friday\", \"Submit report by Monday\", \"Pick up dry cleaning tomorrow\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1361,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" - Examples of reminders to AVOID: \"Election day is coming\", \"Check the weather forecast\", \"Follow news about world events\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1362,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" let taskText = RecordingNameGenerator.cleanAIOutput(trimmed.dropFirst().trimmingCharacters(in: .whitespacesAndNewlines))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1402,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" let reminderText = RecordingNameGenerator.cleanAIOutput(trimmed.dropFirst().trimmingCharacters(in: .whitespacesAndNewlines))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1419,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" reminders.append(ReminderItem(text: reminderText, timeReference: timeRef, urgency: .later, confidence: 0.8))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1422,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" let titleText = RecordingNameGenerator.cleanStandardizedTitleResponse(trimmed.dropFirst().trimmingCharacters(in: .whitespacesAndNewlines))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1437,"character":1},"reason":"Line should be 120 characters or less; currently it has 154 characters"}},{"text":" private func parseStructuredResponse(_ response: String) -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1509,"character":1},"reason":"Line should be 120 characters or less; currently it has 176 characters"}},{"text":" private func parseStructuredResponse(_ response: String) -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Cyclomatic Complexity","severity":"error","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1509,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 22"}},{"text":" private func parseStructuredResponse(_ response: String) -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1509,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 90 lines"}},{"text":" private func parseStructuredResponse(_ response: String) -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1509,"character":65},"reason":"Tuples should have at most 2 members"}},{"text":" let tasks = summaryResponse.tasks.map { TaskItem(text: RecordingNameGenerator.cleanAIOutput($0), priority: .medium, confidence: 0.8) }","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1524,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" return ReminderItem(text: cleaned, timeReference: ReminderItem.TimeReference.fromReminderText(cleaned), urgency: .later, confidence: 0.8)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1527,"character":1},"reason":"Line should be 120 characters or less; currently it has 157 characters"}},{"text":" let titles = summaryResponse.titles.map { TitleItem(text: RecordingNameGenerator.cleanStandardizedTitleResponse($0), confidence: 0.8) }","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1529,"character":1},"reason":"Line should be 120 characters or less; currently it has 151 characters"}},{"text":" logger.error(\"GoogleAIStudioEngine: Response length: \\(response.count) chars, starts with valid JSON: \\(response.hasPrefix(\"{\"))\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1541,"character":1},"reason":"Line should be 120 characters or less; currently it has 146 characters"}},{"text":" let taskText = RecordingNameGenerator.cleanAIOutput(trimmed.dropFirst().trimmingCharacters(in: .whitespacesAndNewlines))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1582,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" let reminderText = RecordingNameGenerator.cleanAIOutput(trimmed.dropFirst().trimmingCharacters(in: .whitespacesAndNewlines))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1589,"character":1},"reason":"Line should be 120 characters or less; currently it has 144 characters"}},{"text":" reminders.append(ReminderItem(text: reminderText, timeReference: timeRef, urgency: .later, confidence: 0.8))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1592,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" let titleText = RecordingNameGenerator.cleanStandardizedTitleResponse(trimmed.dropFirst().trimmingCharacters(in: .whitespacesAndNewlines))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1597,"character":1},"reason":"Line should be 120 characters or less; currently it has 158 characters"}},{"text":" case .localLLM, .openAI, .openAICompatible, .googleAIStudio, .mistralAI, .awsBedrock, .onDeviceLLM, .mlxSwift, .appleNative:","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1713,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"error","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/FutureAIEngines.swift","line":1740,"character":1},"reason":"File should contain 1000 lines or less: currently contains 1740"}},{"text":"class GoogleAIStudioService: ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","line":14,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 483 lines"}},{"text":" private let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? \"com.bisonnotes.app\", category: \"GoogleAIStudio\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","line":15,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" throw SummarizationError.networkError(underlying: NSError(domain: \"GoogleAIStudio\", code: -1, userInfo: [NSLocalizedDescriptionKey: \"Invalid response\"]))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","line":163,"character":1},"reason":"Line should be 120 characters or less; currently it has 165 characters"}},{"text":" throw SummarizationError.networkError(underlying: NSError(domain: \"GoogleAIStudio\", code: httpResponse.statusCode, userInfo: [NSLocalizedDescriptionKey: \"HTTP \\(httpResponse.statusCode): \\(errorMessage)\"]))","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","line":169,"character":1},"reason":"Line should be 200 characters or less; currently it has 218 characters"}},{"text":" private func createStructuredRequest(prompt: String) throws -> Data {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","line":181,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 57 lines"}},{"text":" private func createStructuredPrompt(_ text: String) -> String {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","line":264,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 54 lines"}},{"text":" logger.warning(\"GoogleAIStudioService: Raw response length: \\(textPart.text.count) chars, starts with valid JSON: \\(textPart.text.hasPrefix(\"{\"))\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","line":341,"character":1},"reason":"Line should be 120 characters or less; currently it has 163 characters"}},{"text":" if let remindersMatch = truncatedJSON.range(of: \"\\\"reminders\\\":\\\\s*\\\\[([^\\\\]]*)\\\\]\", options: .regularExpression) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","line":434,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" if let contentTypeMatch = truncatedJSON.range(of: \"\\\"contentType\\\":\\\\s*\\\"([^\\\"]*)\\\"\", options: .regularExpression) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","line":446,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" let contentTypeStart = truncatedJSON.index(contentTypeMatch.lowerBound, offsetBy: 14) \/\/ Skip \"contentType\":\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","line":447,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" logger.info(\"GoogleAIStudioService: Extracted partial response - Summary: \\(summary.count) chars, Tasks: \\(tasks.count), Reminders: \\(reminders.count), Titles: \\(titles.count)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","line":456,"character":1},"reason":"Line should be 120 characters or less; currently it has 189 characters"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"Google AI Studio title extraction failed: \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","line":529,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" let category = TitleItem.TitleCategory(rawValue: titleResponse.category?.lowercased() ?? \"general\") ?? .general","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","line":554,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" let category = TitleItem.TitleCategory(rawValue: titleResponse.category?.lowercased() ?? \"general\") ?? .general","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","line":566,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"Failed to parse titles JSON: \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","line":574,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioService.swift","line":611,"character":1},"reason":"File should contain 400 lines or less: currently contains 611"}},{"text":" private let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? \"com.bisonnotes.app\", category: \"GoogleAIStudioSettings\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioSettingsView.swift","line":23,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" alertMessage = isConnected ? \"Connection successful!\" : \"Connection failed. Please check your API key and internet connection.\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/GoogleAIStudioSettingsView.swift","line":161,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/IntegrationSelectionView.swift","line":50,"character":24},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/IntegrationSelectionView.swift","line":84,"character":24},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/IntegrationSelectionView.swift","line":119,"character":28},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" let recognizer = SFSpeechRecognizer(locale: Locale.current) ?? SFSpeechRecognizer(locale: Locale(identifier: \"en-US\"))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LiveTranscriptionService.swift","line":60,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" Marker(\"Recording Location\", coordinate: CLLocationCoordinate2D(latitude: locationData.latitude, longitude: locationData.longitude))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LocationDetailView.swift","line":30,"character":1},"reason":"Line should be 120 characters or less; currently it has 152 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LocationDetailView.swift","line":60,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LocationDetailView.swift","line":66,"character":32},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" .background(Color.accentColor, in: RoundedRectangle(cornerRadius: 12, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LocationDetailView.swift","line":77,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LocationDetailView.swift","line":82,"character":32},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" .background(Color.accentColor.opacity(0.12), in: RoundedRectangle(cornerRadius: 12, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LocationDetailView.swift","line":93,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":"class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {","violation":{"ruleName":"Type Body Length","severity":"warning","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LocationManager.swift","line":12,"character":1},"reason":"Class body should span 250 lines or less excluding comments and whitespace: currently spans 269 lines"}},{"text":" static func exportLogs() async throws -> URL {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LogExporter.swift","line":32,"character":12},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 71 lines"}},{"text":" logLines.append(\"[\\(formatter.string(from: entry.date))] [\\(level)] [\\(entry.category)] \\(entry.composedMessage)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LogExporter.swift","line":77,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" sections.append(\"\\n\" + sectionHeader(\"CURRENT SESSION LOGS\") + \"\\nFailed to fetch: \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LogExporter.swift","line":81,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" sections.append(\"\\n\" + sectionHeader(\"PERSISTENT BREADCRUMBS (\\(breadcrumbLines.count) entries, survives crashes)\") + \"\\n\" + breadcrumbLog)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LogExporter.swift","line":88,"character":1},"reason":"Line should be 120 characters or less; currently it has 151 characters"}},{"text":" sections.append(\"\\n\" + sectionHeader(\"PERSISTENT ERROR LOG (\\(errorLines.count) entries, survives crashes)\") + \"\\n\" + errorLog)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LogExporter.swift","line":95,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" sections.append(\"\\n\" + sectionHeader(\"METRICKIT CRASH\/HANG DIAGNOSTICS\") + \"\\nNo MetricKit diagnostics available yet. iOS may deliver crash and hang payloads on a later launch.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LogExporter.swift","line":107,"character":1},"reason":"Line should be 120 characters or less; currently it has 190 characters"}},{"text":" \"Hi,\\n\\nAttached is a diagnostic log from BisonNotes AI.\\n\\nPlease describe what happened (optional):\\n\\n\",","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LogExporter.swift","line":177,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LogExporter.swift","line":202,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" var vc = root","violation":{"ruleName":"Identifier Name","severity":"warning","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/LogExporter.swift","line":217,"character":13},"reason":"Variable name 'vc' should be between 3 and 40 characters long"}},{"text":" AppLog.shared.summarization(\"[MLXSwift] Download failed: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":86,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" func processComplete(text: String) async throws -> (","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":177,"character":56},"reason":"Tuples should have at most 2 members"}},{"text":"private actor MLXSwiftService {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":320,"character":9},"reason":"Actor body should span 350 lines or less excluding comments and whitespace: currently spans 392 lines"}},{"text":" + \"\\((before.activeMemory + before.cacheMemory - after.activeMemory - after.cacheMemory) \/ (1024*1024))MB \"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":377,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" message: \"The device is running low on memory. Close other apps and try again, or use a cloud AI engine for large transcripts.\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":389,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"text":" func processComplete(text: String) async throws -> (","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":394,"character":56},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.summarization(\"[MLXSwift] Transcript: \\(tokenCount) tokens, input limit: \\(inputLimit) tokens\/chunk\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":413,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" let result: (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":415,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" let result: (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":415,"character":21},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.summarization(\"[MLXSwift] Chunking transcript into ~\\(inputLimit)-token pieces\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":417,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" private func processChunked(text: String, maxTokens: Int) async throws -> (","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":429,"character":79},"reason":"Tuples should have at most 2 members"}},{"text":" return try await consolidate(chunkResults: chunkResults, originalContentType: ContentAnalyzer.classifyContent(text))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":459,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" private func runCompletePrompt(transcript: String, contentHint: ContentType) async throws -> (","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":462,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 51 lines"}},{"text":" private func runCompletePrompt(transcript: String, contentHint: ContentType) async throws -> (","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":462,"character":98},"reason":"Tuples should have at most 2 members"}},{"text":" private func consolidate(","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":524,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 54 lines"}},{"text":" ) async throws -> (","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":527,"character":23},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.summarization(\"[MLXSwift] Insufficient memory: \\(availableMB) MB available, \\(requiredMB) MB required\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":701,"character":1},"reason":"Line should be 120 characters or less; currently it has 144 characters"}},{"text":" message: \"Not enough free memory to load the MLX model. Close other apps and try again. (\\(availableMB) MB available, \\(requiredMB) MB needed)\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":703,"character":1},"reason":"Line should be 120 characters or less; currently it has 159 characters"}},{"text":" ) -> (","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":802,"character":10},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.summarization(\"[MLXSwift] Could not parse structured JSON, using raw response as summary\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":815,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" ) -> (","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":831,"character":10},"reason":"Tuples should have at most 2 members"}},{"text":" cleaned = cleaned.replacingOccurrences(of: #\"^```(?:json)?\\s*\"#, with: \"\", options: [.regularExpression, .caseInsensitive])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":954,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" func toSummaryResult(fallbackText: String) -> (","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":974,"character":51},"reason":"Tuples should have at most 2 members"}},{"text":"}","violation":{"ruleName":"File Length","severity":"error","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftEngine.swift","line":1087,"character":1},"reason":"File should contain 1000 lines or less: currently contains 1087"}},{"text":"struct MLXSwiftSettingsView: View {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftSettingsView.swift","line":80,"character":1},"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 399 lines"}},{"text":" @AppStorage(MLXSwiftSettingsKeys.repetitionPenalty) private var repetitionPenalty = MLXSwiftSettingsKeys.defaultRepetitionPenalty","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftSettingsView.swift","line":92,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" Text(\"Process transcripts locally using Apple's MLX framework. Models download from Hugging Face on first use. No internet connection required after download.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftSettingsView.swift","line":114,"character":1},"reason":"Line should be 120 characters or less; currently it has 180 characters"}},{"text":" Text(\"MLX Swift requires a device with 4GB+ RAM and Apple Silicon. Your device does not meet this requirement.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftSettingsView.swift","line":118,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" Text(\"This will delete \\(model.displayName) (\\(model.downloadSize)) from your device. You can re-download it later.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftSettingsView.swift","line":182,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" Text(\"Automatically set based on device RAM: \\(DeviceCapabilities.onDeviceLLMContextSize == 8192 ? \"8k\" : \"16k\") for devices with \\(DeviceCapabilities.onDeviceLLMContextSize == 8192 ? \"<8GB\" : \"\\u{2265}8GB\") RAM\")","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftSettingsView.swift","line":504,"character":1},"reason":"Line should be 200 characters or less; currently it has 221 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MLXSwiftSettingsView.swift","line":574,"character":1},"reason":"File should contain 400 lines or less: currently contains 574"}},{"text":"class MistralAIEngine: SummarizationEngine, ConnectionTestable {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":11,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 353 lines"}},{"text":" private let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? \"com.bisonnotes.app\", category: \"MistralAIEngine\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":23,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" AppLogger.shared.verbose(\"Checking enableMistralAI setting - Value: \\(isEnabled), Key exists: \\(keyExists)\", category: \"MistralAIEngine\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":61,"character":1},"reason":"Line should be 120 characters or less; currently it has 149 characters"}},{"text":" \/\/\/ This method calls `processComplete()` internally, which extracts ALL content (summary, tasks, reminders, titles).","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":108,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" \/\/\/ This method calls `processComplete()` internally, which extracts ALL content (summary, tasks, reminders, titles).","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":134,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" \/\/\/ This method calls `processComplete()` internally, which extracts ALL content (summary, tasks, reminders, titles).","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":160,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" \/\/\/ - Returns: A tuple containing summary, tasks (max 15), reminders (max 15), titles (max 5), and detected content type","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":197,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":204,"character":1},"reason":"Line should be 120 characters or less; currently it has 167 characters"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":204,"character":56},"reason":"Tuples should have at most 2 members"}},{"text":" logger.info(\"Mistral AI test connection \\(success ? \"successful\" : \"failed\") - Response length: \\(response.count)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":233,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" AppLogger.shared.verbose(\"Mistral AI JSON format: user override (\\(userSetting)) differs from auto-detection (\\(autoDetectedJsonSupport))\", category: \"MistralAIEngine\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":267,"character":1},"reason":"Line should be 120 characters or less; currently it has 188 characters"}},{"text":" AppLogger.shared.verbose(\"Mistral AI JSON format: using auto-detection (\\(autoDetectedJsonSupport)) based on URL\", category: \"MistralAIEngine\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":270,"character":1},"reason":"Line should be 120 characters or less; currently it has 159 characters"}},{"text":" AppLogger.shared.verbose(\"Updated Mistral AI configuration - Model: \\(modelId), BaseURL: \\(baseURL), JSON Format: \\(supportsJsonResponseFormat)\", category: \"MistralAIEngine\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":292,"character":1},"reason":"Line should be 120 characters or less; currently it has 190 characters"}},{"text":" private func processChunkedText(_ text: String, service: MistralAISummarizationService, contextWindow: Int) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":319,"character":1},"reason":"Line should be 200 characters or less; currently it has 240 characters"}},{"text":" private func processChunkedText(_ text: String, service: MistralAISummarizationService, contextWindow: Int) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":319,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 56 lines"}},{"text":" private func processChunkedText(_ text: String, service: MistralAISummarizationService, contextWindow: Int) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":319,"character":129},"reason":"Tuples should have at most 2 members"}},{"text":" logger.warning(\"Failed to process Mistral chunk \\(index + 1), retrying (\\(retryCount)\/\\(maxRetries)): \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":358,"character":1},"reason":"Line should be 120 characters or less; currently it has 157 characters"}},{"text":" logger.error(\"Failed to process Mistral chunk \\(index + 1) after \\(maxRetries) retries, skipping: \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":362,"character":1},"reason":"Line should be 120 characters or less; currently it has 153 characters"}},{"text":" logger.warning(\"Completed chunked processing with \\(successfulChunks) successful and \\(failedChunks) failed chunks\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":377,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" let metaSummary = try await generateMetaSummary(from: combinedText, contentType: contentType, service: service, depth: 0)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":508,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"Mistral AI - Summary processing too complex (recursion limit reached)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":531,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" return try await generateMetaSummary(from: reducedText, contentType: contentType, service: service, depth: depth + 1)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":558,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAIEngine.swift","line":578,"character":1},"reason":"File should contain 400 lines or less: currently contains 578"}},{"text":" private let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? \"com.bisonnotes.app\", category: \"MistralAISettings\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISettingsView.swift","line":27,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" Text(\"Mistral AI offers a free tier with all models -- no credit card required. Use the guided setup to create an account and get your API key.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISettingsView.swift","line":49,"character":1},"reason":"Line should be 120 characters or less; currently it has 173 characters"}},{"text":" Button(action: { showingOnboarding = true }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISettingsView.swift","line":53,"character":74},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" Text(\"Mistral uses OpenAI-compatible chat endpoints. Keep the default base URL unless you use a gateway.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISettingsView.swift","line":79,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" Text(\"Enable strict JSON mode for structured outputs. Official Mistral API supports this. Disable if using a custom gateway that doesn't support response_format parameter.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISettingsView.swift","line":88,"character":1},"reason":"Line should be 120 characters or less; currently it has 197 characters"}},{"text":" Text(\"Context window: \\(selectedModelEnum.contextWindow\/1000)K tokens β€’ \\(selectedModelEnum.costTier) pricing\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISettingsView.swift","line":150,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" alertMessage = success ? \"Connection successful!\" : \"Connection failed. Please verify your API key and base URL.\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISettingsView.swift","line":236,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" private let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? \"com.bisonnotes.app\", category: \"MistralAISummarizationService\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISummarizationService.swift","line":29,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISummarizationService.swift","line":136,"character":1},"reason":"Line should be 120 characters or less; currently it has 167 characters"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISummarizationService.swift","line":136,"character":56},"reason":"Tuples should have at most 2 members"}},{"text":" logger.debug(\"Using response_format: \\(self.config.supportsJsonResponseFormat ? \"json_object\" : \"none (flexible parsing)\", privacy: .public)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISummarizationService.swift","line":156,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" private func makeAPICall(request: MistralChatCompletionRequest) async throws -> OpenAIChatCompletionResponse {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISummarizationService.swift","line":170,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 12"}},{"text":" private func makeAPICall(request: MistralChatCompletionRequest) async throws -> OpenAIChatCompletionResponse {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISummarizationService.swift","line":170,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 62 lines"}},{"text":" logger.debug(\"Mistral AI API Configuration - Model: \\(self.config.model.rawValue, privacy: .public), BaseURL: \\(self.config.baseURL, privacy: .public)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISummarizationService.swift","line":176,"character":1},"reason":"Line should be 120 characters or less; currently it has 160 characters"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"Failed to encode request: \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISummarizationService.swift","line":197,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" logger.warning(\"Mistral API rate limit exceeded - Retry-After: \\(retryAfter, privacy: .public), Reset: \\(rateLimitReset, privacy: .public)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISummarizationService.swift","line":216,"character":1},"reason":"Line should be 120 characters or less; currently it has 156 characters"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"Mistral API Error: \\(errorResponse.error.message)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISummarizationService.swift","line":232,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" logger.error(\"Mistral API Error: HTTP \\(httpResponse.statusCode, privacy: .public), response size: \\(data.count, privacy: .public) bytes\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISummarizationService.swift","line":234,"character":1},"reason":"Line should be 120 characters or less; currently it has 158 characters"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"Mistral API Error: HTTP \\(httpResponse.statusCode)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISummarizationService.swift","line":235,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" logger.info(\"Usage - Prompt: \\(usage.promptTokens, privacy: .public), Completion: \\(usage.completionTokens, privacy: .public), Total: \\(usage.totalTokens, privacy: .public)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralAISummarizationService.swift","line":243,"character":1},"reason":"Line should be 120 characters or less; currently it has 190 characters"}},{"text":" func transcribeAudioFile(at url: URL, recordingId: UUID? = nil) async throws -> MistralTranscribeResult {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":156,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 76 lines"}},{"text":" let result = try await performTranscription(audioData: audioData, fileName: audioChunk.chunkURL.lastPathComponent)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":186,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" private func performTranscription(audioData: Data, fileName: String) async throws -> MistralTranscribeResult {","violation":{"ruleName":"Function Body Length","severity":"error","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":249,"character":13},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 105 lines"}},{"text":" body.append(\"--\\(boundary)\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":266,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"Content-Disposition: form-data; name=\\\"file\\\"; filename=\\\"\\(fileName)\\\"\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":267,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"Content-Type: \\(getContentType(for: fileName))\\r\\n\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":268,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":270,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"--\\(boundary)\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":273,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"Content-Disposition: form-data; name=\\\"model\\\"\\r\\n\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":274,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":276,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"--\\(boundary)\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":279,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"Content-Disposition: form-data; name=\\\"response_format\\\"\\r\\n\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":280,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"verbose_json\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":281,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":282,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"--\\(boundary)\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":285,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"Content-Disposition: form-data; name=\\\"timestamp_granularities[]\\\"\\r\\n\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":286,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"segment\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":287,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":288,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"--\\(boundary)\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":292,"character":25},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"Content-Disposition: form-data; name=\\\"diarize\\\"\\r\\n\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":293,"character":25},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"true\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":294,"character":25},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":295,"character":25},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"--\\(boundary)\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":300,"character":25},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"Content-Disposition: form-data; name=\\\"language\\\"\\r\\n\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":301,"character":25},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":303,"character":25},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"--\\(boundary)--\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":307,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" AppLog.shared.transcription(\"Mistral transcription: model=\\(config.model.rawValue), diarize=\\(config.diarize), size=\\(body.count) bytes\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":311,"character":1},"reason":"Line should be 120 characters or less; currently it has 160 characters"}},{"text":" AppLog.shared.transcription(\"Parsed \\(mistralSegments.count) segments with \\(speakerCount) unique speakers\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":355,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" AppLog.shared.transcription(\"Mistral transcription complete: \\(transcriptText.count) chars, \\(segments.count) segments, \\(String(format: \"%.1f\", processingTime))s\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":379,"character":1},"reason":"Line should be 120 characters or less; currently it has 172 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeService.swift","line":452,"character":1},"reason":"File should contain 400 lines or less: currently contains 452"}},{"text":"struct MistralTranscribeSettingsView: View {","violation":{"ruleName":"Type Body Length","severity":"warning","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeSettingsView.swift","line":10,"character":1},"reason":"Struct body should span 250 lines or less excluding comments and whitespace: currently spans 338 lines"}},{"text":" Text(\"Specify a language code (e.g., 'en', 'fr', 'es') for better accuracy, or leave empty for auto-detection.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/MistralTranscribeSettingsView.swift","line":305,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" func addRecording(url: URL, name: String, date: Date, fileSize: Int64, duration: TimeInterval, quality: AudioQuality, locationData: LocationData? = nil) -> UUID {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift","line":38,"character":1},"reason":"Line should be 120 characters or less; currently it has 166 characters"}},{"text":" func addRecording(url: URL, name: String, date: Date, fileSize: Int64, duration: TimeInterval, quality: AudioQuality, locationData: LocationData? = nil) -> UUID {","violation":{"ruleName":"Function Parameter Count","severity":"warning","ruleDescription":"Number of function parameters should be low.","ruleIdentifier":"function_parameter_count","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift","line":38,"character":5},"reason":"Function should have 5 parameters or less: it currently has 6"}},{"text":" func addWatchRecording(url: URL, name: String, date: Date, fileSize: Int64, duration: TimeInterval, quality: AudioQuality, locationData: LocationData? = nil) -> UUID {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift","line":52,"character":1},"reason":"Line should be 120 characters or less; currently it has 171 characters"}},{"text":" func addWatchRecording(url: URL, name: String, date: Date, fileSize: Int64, duration: TimeInterval, quality: AudioQuality, locationData: LocationData? = nil) -> UUID {","violation":{"ruleName":"Function Parameter Count","severity":"warning","ruleDescription":"Number of function parameters should be low.","ruleIdentifier":"function_parameter_count","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift","line":52,"character":5},"reason":"Function should have 5 parameters or less: it currently has 6"}},{"text":" func addTranscript(for recordingId: UUID, segments: [TranscriptSegment], speakerMappings: [String: String] = [:], engine: TranscriptionEngine? = nil, processingTime: TimeInterval = 0, confidence: Double = 0.5) -> UUID? {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift","line":66,"character":1},"reason":"Line should be 200 characters or less; currently it has 224 characters"}},{"text":" func addSummary(for recordingId: UUID, transcriptId: UUID, summary: String, tasks: [TaskItem] = [], reminders: [ReminderItem] = [], titles: [TitleItem] = [], contentType: ContentType = .general, aiEngine: String = \"Unknown\", aiModel: String, originalLength: Int, processingTime: TimeInterval = 0) -> UUID? {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift","line":81,"character":1},"reason":"Line should be 200 characters or less; currently it has 311 characters"}},{"text":" func getCompleteRecordingData(id: UUID) -> (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)? {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift","line":144,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" func getCompleteRecordingData(id: UUID) -> (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)? {","violation":{"ruleName":"Large Tuple","severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift","line":144,"character":48},"reason":"Tuples should have at most 2 members"}},{"text":" func getAllRecordingsWithData() -> [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)] {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift","line":148,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" func getAllRecordingsWithData() -> [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)] {","violation":{"ruleName":"Large Tuple","severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift","line":148,"character":41},"reason":"Tuples should have at most 2 members"}},{"text":" func getRecordingsWithTranscripts() -> [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)] {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift","line":152,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" func getRecordingsWithTranscripts() -> [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)] {","violation":{"ruleName":"Large Tuple","severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift","line":152,"character":45},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.coreData(\"Deleted local recording and queued iCloud deletion marker for retry: \\(error)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift","line":171,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" AppLog.shared.coreData(\"Deleted local summary but failed to remove iCloud summary records: \\(error)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift","line":193,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.coreData(\"Marked recording local-only and queued iCloud removal for retry: \\(error)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AppDataCoordinator.swift","line":220,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" init(originalURL: URL, chunkURL: URL, sequenceNumber: Int, startTime: TimeInterval, endTime: TimeInterval, fileSize: Int64) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AudioChunkingModels.swift","line":24,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" init(chunkId: UUID, sequenceNumber: Int, transcript: String, segments: [TranscriptSegment], startTime: TimeInterval, endTime: TimeInterval, processingTime: TimeInterval? = nil) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AudioChunkingModels.swift","line":49,"character":1},"reason":"Line should be 120 characters or less; currently it has 182 characters"}},{"text":" static let openAI = ChunkingStrategy.combined(maxBytes: 24 * 1024 * 1024, maxSeconds: 1300) \/\/ 24MB and 1300 seconds (21.67 minutes)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AudioChunkingModels.swift","line":69,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" static let mistralAI = ChunkingStrategy.combined(maxBytes: 24 * 1024 * 1024, maxSeconds: 1300) \/\/ 24MB and 1300 seconds","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AudioChunkingModels.swift","line":73,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" self.tempDirectory = tempDirectory ?? FileManager.default.temporaryDirectory.appendingPathComponent(\"AudioChunks\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AudioChunkingModels.swift","line":100,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" static func create(from url: URL) async throws -> AudioFileInfo {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AudioChunkingModels.swift","line":160,"character":12},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 52 lines"}},{"text":" AppLog.shared.chunking(\"AudioFileInfo.create - File exists: \\(FileManager.default.fileExists(atPath: url.path))\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AudioChunkingModels.swift","line":163,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" AppLog.shared.chunking(\"AudioFileInfo.create - Loaded duration: \\(duration)s (\\(duration\/60) minutes)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AudioChunkingModels.swift","line":167,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" AppLog.shared.chunking(\"AudioFileInfo.create - File size: \\(fileSize) bytes (\\(fileSize\/1024\/1024) MB)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AudioChunkingModels.swift","line":171,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" AppLog.shared.chunking(\"AudioFileInfo.create - Successfully created: duration=\\(audioFileInfo.duration)s, size=\\(audioFileInfo.fileSize) bytes, format=\\(audioFileInfo.format), sampleRate=\\(audioFileInfo.sampleRate), channels=\\(audioFileInfo.channels)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AudioChunkingModels.swift","line":223,"character":1},"reason":"Line should be 200 characters or less; currently it has 275 characters"}},{"text":" return \"High-quality on-device transcription powered by NVIDIA Parakeet. Your audio never leaves your device, ensuring complete privacy.\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AudioModels.swift","line":111,"character":1},"reason":"Line should be 120 characters or less; currently it has 149 characters"}},{"text":" return \"High-quality transcription using OpenAI's Whisper model on your local server (REST API or Wyoming protocol)\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AudioModels.swift","line":115,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" let protocolString = UserDefaults.standard.string(forKey: \"whisperProtocol\") ?? WhisperProtocol.rest.rawValue","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/AudioModels.swift","line":155,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" message: \"No transcription engine has been configured. Please go to Settings to configure a transcription engine.\",","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/ConfigurationWarningHelper.swift","line":40,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" Text(\"No transcription engine has been configured. Please go to Settings to configure a transcription engine.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/ConfigurationWarningHelper.swift","line":69,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":"class CoreDataManager: ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":15,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 904 lines"}},{"text":" AppLog.shared.coreData(\"File not found anywhere for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":184,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" AppLog.shared.coreData(\"Repairing orphaned summary \\(index): ID \\(summary.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":369,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" AppLog.shared.coreData(\"Created recording \\(newRecordingId.uuidString) for summary \\(summary.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":389,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" AppLog.shared.coreData(\"After repair: \\(newRecordingCount) recordings, \\(newSummaryCount) summaries\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":404,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" func cleanupDuplicates() -> (summaries: Int, transcripts: Int) {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":420,"character":5},"reason":"Function should have complexity 10 or less; currently complexity is 16"}},{"text":" func cleanupDuplicates() -> (summaries: Int, transcripts: Int) {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":420,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 77 lines"}},{"text":" AppLog.shared.coreData(\"Found \\(summaries.count) summaries for recording ID: \\(recordingId)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":439,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" AppLog.shared.coreData(\"Deleting duplicate summary ID: \\(summary.id?.uuidString ?? \"nil\") (length: \\(summaryLength) chars)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":444,"character":1},"reason":"Line should be 120 characters or less; currently it has 163 characters"}},{"text":" AppLog.shared.coreData(\"Keeping most recent summary ID: \\(summary.id?.uuidString ?? \"nil\") (length: \\(summaryLength) chars)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":449,"character":1},"reason":"Line should be 120 characters or less; currently it has 164 characters"}},{"text":" AppLog.shared.coreData(\"Found \\(transcripts.count) transcripts for recording ID: \\(recordingId)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":460,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.coreData(\"Deleting duplicate transcript ID: \\(transcript.id?.uuidString ?? \"nil\") (segments: \\(segmentsLength) chars)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":465,"character":1},"reason":"Line should be 120 characters or less; currently it has 172 characters"}},{"text":" AppLog.shared.coreData(\"Keeping most recent transcript ID: \\(transcript.id?.uuidString ?? \"nil\") (segments: \\(segmentsLength) chars)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":470,"character":1},"reason":"Line should be 120 characters or less; currently it has 173 characters"}},{"text":" AppLog.shared.coreData(\"Deleting orphaned summary (no recording): ID \\(summary.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":482,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" AppLog.shared.coreData(\"Deleting orphaned transcript (no recording): ID \\(transcript.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":495,"character":1},"reason":"Line should be 120 characters or less; currently it has 146 characters"}},{"text":" AppLog.shared.coreData(\"Cleanup complete: deleted \\(summariesDeleted) duplicate\/orphaned summaries, \\(transcriptsDeleted) duplicate\/orphaned transcripts\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":505,"character":1},"reason":"Line should be 120 characters or less; currently it has 170 characters"}},{"text":" AppLog.shared.coreData(\"Found \\(summaries.count) summaries for recording \\(recordingId) β€” auto-cleaning duplicates\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":529,"character":1},"reason":"Line should be 120 characters or less; currently it has 147 characters"}},{"text":" AppLog.shared.coreData(\"Auto-deleting duplicate summary ID=\\(summary.id?.uuidString ?? \"nil\"), length=\\(summary.summary?.count ?? 0)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":532,"character":1},"reason":"Line should be 120 characters or less; currently it has 169 characters"}},{"text":" AppLog.shared.coreData(\"Deleting \\(summaries.count) summary\/summaries for recording: \\(recordingId)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":628,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" func getCompleteRecordingData(id: UUID) -> (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)? {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":645,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" func getCompleteRecordingData(id: UUID) -> (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)? {","violation":{"ruleName":"Large Tuple","severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":645,"character":48},"reason":"Tuples should have at most 2 members"}},{"text":" func getAllRecordingsWithData() -> [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)] {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":656,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" func getAllRecordingsWithData() -> [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)] {","violation":{"ruleName":"Large Tuple","severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":656,"character":41},"reason":"Tuples should have at most 2 members"}},{"text":" func getRecordingsWithTranscripts() -> [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)] {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":666,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" func getRecordingsWithTranscripts() -> [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)] {","violation":{"ruleName":"Large Tuple","severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":666,"character":45},"reason":"Tuples should have at most 2 members"}},{"text":" private func convertToTranscriptData(transcriptEntry: TranscriptEntry, recordingEntry: RecordingEntry) -> TranscriptData? {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":700,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" guard let _ = transcriptEntry.id,","violation":{"ruleName":"Unused Optional Binding","severity":"warning","ruleDescription":"Prefer `!= nil` over `let _ =`","ruleIdentifier":"unused_optional_binding","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":701,"character":19},"reason":"Prefer `!= nil` over `let _ =`"}},{"text":" AppLog.shared.coreData(\"Transcript missing id for recording: \\(recordingEntry.id?.uuidString ?? \"nil\")\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":703,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" let url = getAbsoluteURL(for: recordingEntry) ?? preservedContentURL(for: recordingEntry, recordingId: recordingId)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":709,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" private func convertToEnhancedSummaryData(summaryEntry: SummaryEntry, recordingEntry: RecordingEntry) -> EnhancedSummaryData? {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":744,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" guard let _ = summaryEntry.id,","violation":{"ruleName":"Unused Optional Binding","severity":"warning","ruleDescription":"Prefer `!= nil` over `let _ =`","ruleIdentifier":"unused_optional_binding","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":745,"character":19},"reason":"Prefer `!= nil` over `let _ =`"}},{"text":" let url = getAbsoluteURL(for: recordingEntry) ?? preservedContentURL(for: recordingEntry, recordingId: recordingId)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":752,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" AppLog.shared.coreData(\"Cleaning up orphaned recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":920,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.coreData(\"Cleaning up recording with missing file: \\(url.lastPathComponent)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":991,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" AppLog.shared.coreData(\"Preserving recording with transcript\/summary, clearing URL\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":1003,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" AppLog.shared.coreData(\"Recording with unresolvable URL, ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":1010,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" AppLog.shared.coreData(\"Recording ID: \\(recording.id?.uuidString ?? \"nil\") | transcript: \\(hasTranscript) | summary: \\(hasSummary) | transcriptionStatus: \\(recording.transcriptionStatus ?? \"unknown\") | summaryStatus: \\(recording.summaryStatus ?? \"unknown\") | location: \\(hasLocation)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":1047,"character":1},"reason":"Line should be 200 characters or less; currently it has 312 characters"}},{"text":" func syncRecordingURLs() {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":1054,"character":5},"reason":"Function should have complexity 10 or less; currently complexity is 18"}},{"text":" func syncRecordingURLs() {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":1054,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 71 lines"}},{"text":" let fileURLs = try FileManager.default.contentsOfDirectory(at: documentsPath, includingPropertiesForKeys: nil, options: [])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":1094,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"text":" AppLog.shared.coreData(\"Updated URL for recording ID \\(recording.id?.uuidString ?? \"nil\"): \\(oldURL.lastPathComponent) -> \\(newURL.lastPathComponent)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":1105,"character":1},"reason":"Line should be 120 characters or less; currently it has 194 characters"}},{"text":" AppLog.shared.coreData(\"Fixed path for recording ID \\(recording.id?.uuidString ?? \"nil\"): \\(newURL.lastPathComponent)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":1107,"character":1},"reason":"Line should be 120 characters or less; currently it has 162 characters"}},{"text":" AppLog.shared.coreData(\"Updated URL by name match for recording ID \\(recording.id?.uuidString ?? \"nil\"): \\(oldURL.lastPathComponent) -> \\(newURL.lastPathComponent)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":1125,"character":1},"reason":"Line should be 200 characters or less; currently it has 212 characters"}},{"text":" AppLog.shared.coreData(\"Could not find file for recording ID \\(recording.id?.uuidString ?? \"nil\"), expected filename: \\(filename), available files: \\(fileURLs.count)\", level: .error)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":1127,"character":1},"reason":"Line should be 200 characters or less; currently it has 214 characters"}},{"text":" AppLog.shared.coreData(\"Could not find file for recording ID \\(recording.id?.uuidString ?? \"nil\")\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":1130,"character":1},"reason":"Line should be 120 characters or less; currently it has 142 characters"}},{"text":" AppLog.shared.coreData(\"Updated recording URL for ID \\(recording.id?.uuidString ?? \"nil\"): \\(newURL.lastPathComponent)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":1160,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" throw NSError(domain: \"CoreDataManager\", code: 404, userInfo: [NSLocalizedDescriptionKey: \"Recording not found with ID: \\(recordingId)\"])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":1168,"character":1},"reason":"Line should be 120 characters or less; currently it has 149 characters"}},{"text":" throw NSError(domain: \"CoreDataManager\", code: 404, userInfo: [NSLocalizedDescriptionKey: \"Recording not found with ID: \\(recordingId)\"])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":1188,"character":1},"reason":"Line should be 120 characters or less; currently it has 149 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"error","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/CoreDataManager.swift","line":1226,"character":1},"reason":"File should contain 1000 lines or less: currently contains 1226"}},{"text":"class DataMigrationManager: ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":94,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 1614 lines"}},{"text":" await createCoreDataEntries(audioFiles: audioFiles, transcriptFiles: transcriptFiles, summaryFiles: summaryFiles)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":139,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" let fileURLs = try FileManager.default.contentsOfDirectory(at: documentsPath, includingPropertiesForKeys: nil, options: [])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":184,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" let fileURLs = try FileManager.default.contentsOfDirectory(at: documentsPath, includingPropertiesForKeys: nil, options: [])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":200,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" await createRecordingEntry(audioFile: audioFile, transcriptFiles: transcriptFiles, summaryFiles: summaryFiles)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":214,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" private func createRecordingEntry(audioFile: URL, transcriptFiles: [URL], summaryFiles: [URL]) async {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":218,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 64 lines"}},{"text":" AppLog.shared.dataMigration(\"Created transcript entry for recording ID: \\(recordingEntry.id?.uuidString ?? \"nil\")\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":339,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" AppLog.shared.dataMigration(\"Created summary entry for recording ID: \\(recordingEntry.id?.uuidString ?? \"nil\")\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":388,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" func recoverDataFromiCloud() async -> (transcripts: Int, summaries: Int, errors: [String]) {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":407,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 65 lines"}},{"text":" func recoverDataFromiCloud() async -> (transcripts: Int, summaries: Int, errors: [String]) {","violation":{"ruleName":"Large Tuple","severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":407,"character":43},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.dataMigration(\"Found \\(summaries.count) summaries in legacy iCloud\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":425,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" summaryEntry.aiMethod = SummaryMetadataCodec.encode(aiEngine: summary.aiEngine, aiModel: summary.aiModel)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":456,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" AppLog.shared.dataMigration(\"Recovered summary for recording ID: \\(summary.recordingId?.uuidString ?? \"nil\")\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":463,"character":1},"reason":"Line should be 120 characters or less; currently it has 142 characters"}},{"text":" AppLog.shared.dataMigration(\"Summary already exists for recording ID: \\(summary.recordingId?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":465,"character":1},"reason":"Line should be 120 characters or less; currently it has 162 characters"}},{"text":" AppLog.shared.dataMigration(\"Recovery results: \\(transcriptCount) transcripts, \\(summaryCount) summaries recovered\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":489,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" AppLog.shared.dataMigration(\" Recording ID: \\(recording.id?.uuidString ?? \"nil\") - hasTranscript: \\(recording.transcript != nil), hasSummary: \\(recording.summary != nil)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":525,"character":1},"reason":"Line should be 200 characters or less; currently it has 203 characters"}},{"text":" let fileURLs = try FileManager.default.contentsOfDirectory(at: documentsPath, includingPropertiesForKeys: nil, options: [])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":703,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" if transcript.recording == nil {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":759,"character":17},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" if summary.recording == nil {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":777,"character":17},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" AppLog.shared.dataMigration(\"Could not resolve URL for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":816,"character":1},"reason":"Line should be 120 characters or less; currently it has 142 characters"}},{"text":" let fileURLs = try FileManager.default.contentsOfDirectory(at: documentsPath, includingPropertiesForKeys: nil, options: [])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":930,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" if let matchingAudio = audioFiles.first(where: { $0.deletingPathExtension().lastPathComponent == orphanedFile.baseName }) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":936,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" await createRecordingEntry(audioFile: matchingAudio, transcriptFiles: orphanedFile.type == .transcript ? [orphanedFile.fileURL] : [], summaryFiles: orphanedFile.type == .summary ? [orphanedFile.fileURL] : [])","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":938,"character":1},"reason":"Line should be 200 characters or less; currently it has 228 characters"}},{"text":" private func repairBrokenRelationships(_ broken: [BrokenRelationship]) async -> Int {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":950,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 11"}},{"text":" private func repairBrokenRelationships(_ broken: [BrokenRelationship]) async -> Int {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":950,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 56 lines"}},{"text":" AppLog.shared.dataMigration(\"Repair summary - relationships: \\(relationshipFixes), names: \\(nameFixes), URLs: \\(urlFixes), duplicates: \\(duplicateFixes)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1087,"character":1},"reason":"Line should be 120 characters or less; currently it has 181 characters"}},{"text":" private func fixRelationshipInconsistencies() async -> Int {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1098,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 13"}},{"text":" private func fixRelationshipInconsistencies() async -> Int {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1098,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 56 lines"}},{"text":" AppLog.shared.dataMigration(\"Fixed transcript relationship for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1120,"character":1},"reason":"Line should be 120 characters or less; currently it has 158 characters"}},{"text":" AppLog.shared.dataMigration(\"Synced transcript ID for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1126,"character":1},"reason":"Line should be 120 characters or less; currently it has 145 characters"}},{"text":" AppLog.shared.dataMigration(\"Added missing transcript ID for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1132,"character":1},"reason":"Line should be 120 characters or less; currently it has 148 characters"}},{"text":" AppLog.shared.dataMigration(\"Fixed summary relationship for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1146,"character":1},"reason":"Line should be 120 characters or less; currently it has 155 characters"}},{"text":" AppLog.shared.dataMigration(\"Synced summary ID for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1152,"character":1},"reason":"Line should be 120 characters or less; currently it has 142 characters"}},{"text":" AppLog.shared.dataMigration(\"Added missing summary ID for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1158,"character":1},"reason":"Line should be 120 characters or less; currently it has 145 characters"}},{"text":" private func syncRecordingNamesWithTitles() async -> Int {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1175,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 11"}},{"text":" private func syncRecordingNamesWithTitles() async -> Int {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1175,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 66 lines"}},{"text":" AppLog.shared.dataMigration(\"Skipping standardized name for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1189,"character":1},"reason":"Line should be 120 characters or less; currently it has 147 characters"}},{"text":" (currentName.count > 15 && (currentName.contains(\"1754\") || currentName.contains(\"2025\")))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1201,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" AppLog.shared.dataMigration(\"Skipping non-generic name for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1204,"character":1},"reason":"Line should be 120 characters or less; currently it has 146 characters"}},{"text":" AppLog.shared.dataMigration(\"Found summary title for recording ID: \\(recording.id?.uuidString ?? \"nil\") (confidence: \\(bestTitleItem.confidence))\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1219,"character":1},"reason":"Line should be 120 characters or less; currently it has 186 characters"}},{"text":" AppLog.shared.dataMigration(\"Generated title from transcript for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1241,"character":1},"reason":"Line should be 120 characters or less; currently it has 160 characters"}},{"text":" let validatedTitle = RecordingNameGenerator.validateAndFixRecordingName(newTitle, originalName: currentName)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1248,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.dataMigration(\"Converted URL to relative path for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1281,"character":1},"reason":"Line should be 120 characters or less; currently it has 155 characters"}},{"text":" AppLog.shared.dataMigration(\"Removing duplicate recording ID: \\(duplicate.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1329,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" func resolveFilenameTitleDuplicates() async -> Int {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1347,"character":5},"reason":"Function should have complexity 10 or less; currently complexity is 19"}},{"text":" func resolveFilenameTitleDuplicates() async -> Int {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1347,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 94 lines"}},{"text":" \/\/ Check if the other recording has a nice title and content (exclude standardized names from being considered \"nice titles\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1378,"character":1},"reason":"Line should be 120 characters or less; currently it has 149 characters"}},{"text":" let isOtherStandardized = otherName.hasPrefix(\"apprecording-\") || otherName.hasPrefix(\"importedfile-\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1379,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" let timeDifference = abs((recording.recordingDate ?? Date()).timeIntervalSince(otherRecording.recordingDate ?? Date()))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1389,"character":1},"reason":"Line should be 120 characters or less; currently it has 147 characters"}},{"text":" AppLog.shared.dataMigration(\"Potential duplicate pair found - generic ID: \\(recording.id?.uuidString ?? \"nil\"), titled ID: \\(otherRecording.id?.uuidString ?? \"nil\"), timeDiff: \\(Int(timeDifference))s, sameLocation: \\(sameLocation)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1397,"character":1},"reason":"Line should be 200 characters or less; currently it has 279 characters"}},{"text":" AppLog.shared.dataMigration(\"Merging duplicate generic ID: \\(generic.id?.uuidString ?? \"nil\") into titled ID: \\(titled.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1410,"character":1},"reason":"Line should be 120 characters or less; currently it has 176 characters"}},{"text":" AppLog.shared.dataMigration(\"Merged and deleted generic recording ID: \\(generic.id?.uuidString ?? \"nil\")\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1469,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" if transcript.recording == nil {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1502,"character":17},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" AppLog.shared.dataMigration(\"Removing orphaned transcript ID: \\(transcript.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1503,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" AppLog.shared.dataMigration(\"Removing orphaned summary ID: \\(summary.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1522,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" AppLog.shared.dataMigration(\"Keeping preserved summary (anchor recordingId present) ID: \\(summary.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1527,"character":1},"reason":"Line should be 120 characters or less; currently it has 159 characters"}},{"text":" AppLog.shared.dataMigration(\"Recording #\\(index + 1): ID=\\(id), hasTranscript=\\(hasTranscript), hasTranscriptId=\\(hasTranscriptId), hasSummary=\\(hasSummary), hasSummaryId=\\(hasSummaryId), transcriptionStatus=\\(transcriptionStatus), summaryStatus=\\(summaryStatus)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1587,"character":1},"reason":"Line should be 200 characters or less; currently it has 295 characters"}},{"text":" AppLog.shared.dataMigration(\"Recording #\\(index + 1) has generic name pattern, ID: \\(id)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1601,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" AppLog.shared.dataMigration(\" Orphaned transcript ID: \\(transcript.id?.uuidString ?? \"nil\"), recordingId: \\(transcript.recordingId?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1616,"character":1},"reason":"Line should be 120 characters or less; currently it has 186 characters"}},{"text":" AppLog.shared.dataMigration(\" Orphaned summary ID: \\(summary.id?.uuidString ?? \"nil\"), recordingId: \\(summary.recordingId?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1621,"character":1},"reason":"Line should be 120 characters or less; currently it has 177 characters"}},{"text":" func findAndImportOrphanedAudioFiles() async -> Int {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1630,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 54 lines"}},{"text":" let allFiles = try FileManager.default.contentsOfDirectory(at: documentsURL, includingPropertiesForKeys: [.isRegularFileKey], options: [])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1643,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" AppLog.shared.dataMigration(\"Import summary - total files: \\(audioFiles.count), already in DB: \\(existingURLs.count), imported: \\(importedCount)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1688,"character":1},"reason":"Line should be 120 characters or less; currently it has 173 characters"}},{"text":" AppLog.shared.dataMigration(\"Imported orphaned audio file as recording ID: \\(recordingEntry.id?.uuidString ?? \"nil\")\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1751,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" func forceNameSynchronization() async -> Int {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1755,"character":5},"reason":"Function should have complexity 10 or less; currently complexity is 13"}},{"text":" func forceNameSynchronization() async -> Int {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1755,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 78 lines"}},{"text":" (currentName.count > 15 && (currentName.contains(\"1754\") || currentName.contains(\"2025\")))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1774,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" AppLog.shared.dataMigration(\"Skipping non-generic name for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1777,"character":1},"reason":"Line should be 120 characters or less; currently it has 146 characters"}},{"text":" AppLog.shared.dataMigration(\"Processing generic name for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1781,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" AppLog.shared.dataMigration(\"Found summary title for recording ID: \\(recording.id?.uuidString ?? \"nil\") (confidence: \\(bestTitleItem.confidence))\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1793,"character":1},"reason":"Line should be 120 characters or less; currently it has 186 characters"}},{"text":" AppLog.shared.dataMigration(\"Using summary recording name for ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1801,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" AppLog.shared.dataMigration(\"Generated title from transcript for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1822,"character":1},"reason":"Line should be 120 characters or less; currently it has 160 characters"}},{"text":" let validatedTitle = RecordingNameGenerator.validateAndFixRecordingName(newTitle, originalName: currentName)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1829,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.dataMigration(\"No suitable title found for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1837,"character":1},"reason":"Line should be 120 characters or less; currently it has 144 characters"}},{"text":" func fixInvalidURLs() async -> Int {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1921,"character":5},"reason":"Function should have complexity 10 or less; currently complexity is 13"}},{"text":" func fixInvalidURLs() async -> Int {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1921,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 63 lines"}},{"text":" let allFiles = try FileManager.default.contentsOfDirectory(at: documentsURL, includingPropertiesForKeys: [.nameKey])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1932,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.dataMigration(\"Recording has invalid URL, ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1963,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" AppLog.shared.dataMigration(\"Fixed URL for recording ID: \\(recording.id?.uuidString ?? \"nil\")\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1983,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" AppLog.shared.dataMigration(\"Could not find matching file for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":1989,"character":1},"reason":"Line should be 120 characters or less; currently it has 157 characters"}},{"text":" func cleanupMissingAudioReferences() async -> Int {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2010,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 60 lines"}},{"text":" AppLog.shared.dataMigration(\"Recording has no URL, ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2022,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.dataMigration(\"Cleaning up orphaned transcript for URL-less recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2026,"character":1},"reason":"Line should be 120 characters or less; currently it has 165 characters"}},{"text":" AppLog.shared.dataMigration(\"Checking recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2035,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" AppLog.shared.dataMigration(\"Invalid URL format for recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2059,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"text":" AppLog.shared.dataMigration(\"Cleanup decision for recording ID \\(recording.id?.uuidString ?? \"nil\"): shouldCleanup=\\(shouldCleanup) (\\(reason))\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2063,"character":1},"reason":"Line should be 120 characters or less; currently it has 176 characters"}},{"text":" AppLog.shared.dataMigration(\"Cleaning missing audio reference for recording ID: \\(recording.id?.uuidString ?? \"nil\")\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2067,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" AppLog.shared.dataMigration(\"Deleting transcript for recording with no audio file, ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2075,"character":1},"reason":"Line should be 120 characters or less; currently it has 164 characters"}},{"text":" AppLog.shared.dataMigration(\"Comprehensive fix completed - orphans: \\(cleanedOrphans), incomplete: \\(fixedIncomplete), URLs: \\(urlFixes), renames: \\(renames), validations: \\(validations), specific: \\(specificFixes)\")","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2121,"character":1},"reason":"Line should be 200 characters or less; currently it has 224 characters"}},{"text":" private func fixGenericNamedRecordingsIssue() async -> Int {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2127,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 11"}},{"text":" private func fixGenericNamedRecordingsIssue() async -> Int {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2127,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 55 lines"}},{"text":" (currentName.count > 15 && (currentName.contains(\"1754\") || currentName.contains(\"2025\")))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2144,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" AppLog.shared.dataMigration(\"Found generic recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2147,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" AppLog.shared.dataMigration(\"Fixed recording ID: \\(recording.id?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2186,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" private func linkOrphanedContentToRecording(_ recording: RecordingEntry) async {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2204,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 56 lines"}},{"text":" transcriptFetch.predicate = NSPredicate(format: \"recording == nil AND recordingId == %@\", recordingId as CVarArg)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2209,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" AppLog.shared.dataMigration(\"Linking orphaned transcript to recording ID: \\(recordingId)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2214,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" AppLog.shared.dataMigration(\"Updated recording name from transcript for ID: \\(recordingId)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2236,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" let cleanedTitle = RecordingNameGenerator.validateAndFixRecordingName(bestTitle.text, originalName: recording.recordingName ?? \"\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2263,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" AppLog.shared.dataMigration(\"Updated recording name from summary for ID: \\(recordingId)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2266,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"error","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DataMigrationManager.swift","line":2311,"character":1},"reason":"File should contain 1000 lines or less: currently contains 2311"}},{"text":" AppLog.shared.performance(\"DeviceCompatibility: Simulator detected - enabling native speech transcription support\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DeviceCompatibility.swift","line":17,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" AppLog.shared.performance(\"DeviceCompatibility: Native speech transcription supported (RAM: \\(String(format: \"%.1f\", totalMemoryGB))GB)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DeviceCompatibility.swift","line":26,"character":1},"reason":"Line should be 120 characters or less; currently it has 149 characters"}},{"text":" AppLog.shared.performance(\"DeviceCompatibility: Native speech transcription requires 3GB+ RAM (Device has \\(String(format: \"%.1f\", totalMemoryGB))GB)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DeviceCompatibility.swift","line":29,"character":1},"reason":"Line should be 120 characters or less; currently it has 163 characters"}},{"text":" AppLog.shared.performance(\"DeviceCompatibility: FluidAudio supported (RAM: \\(String(format: \"%.1f\", totalMemoryGB))GB)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DeviceCompatibility.swift","line":82,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" AppLog.shared.performance(\"DeviceCompatibility: FluidAudio requires 4GB+ RAM (Device has \\(String(format: \"%.1f\", totalMemoryGB))GB)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/DeviceCompatibility.swift","line":84,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" init(text: String, priority: Priority = .medium, timeReference: String? = nil, category: TaskCategory = .general, confidence: Double = 0.5) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift","line":35,"character":1},"reason":"Line should be 120 characters or less; currently it has 145 characters"}},{"text":" static func fromReminderText(_ text: String) -> TimeReference {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift","line":130,"character":16},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 54 lines"}},{"text":" if lowercased.contains(pattern) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift","line":164,"character":17},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" init(recordingURL: URL, recordingName: String, recordingDate: Date, summary: String, tasks: [TaskItem] = [], reminders: [ReminderItem] = [], titles: [TitleItem] = [], attachments: [SummaryAttachment] = [], userNotes: String? = nil, contentType: ContentType = .general, aiEngine: String = \"Unknown\", aiModel: String, originalLength: Int, processingTime: TimeInterval = 0) {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift","line":356,"character":1},"reason":"Line should be 200 characters or less; currently it has 376 characters"}},{"text":" let reminderConfidence = reminders.isEmpty ? 0.5 : reminders.map { $0.confidence }.reduce(0, +) \/ Double(reminders.count)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift","line":381,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" init(recordingId: UUID, transcriptId: UUID? = nil, recordingURL: URL, recordingName: String, recordingDate: Date, summary: String, tasks: [TaskItem] = [], reminders: [ReminderItem] = [], titles: [TitleItem] = [], attachments: [SummaryAttachment] = [], userNotes: String? = nil, contentType: ContentType = .general, aiEngine: String = \"Unknown\", aiModel: String, originalLength: Int, processingTime: TimeInterval = 0) {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift","line":387,"character":1},"reason":"Line should be 200 characters or less; currently it has 422 characters"}},{"text":" let reminderConfidence = reminders.isEmpty ? 0.5 : reminders.map { $0.confidence }.reduce(0, +) \/ Double(reminders.count)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift","line":412,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" init(id: UUID, recordingId: UUID?, transcriptId: UUID? = nil, recordingURL: URL, recordingName: String, recordingDate: Date, summary: String, tasks: [TaskItem] = [], reminders: [ReminderItem] = [], titles: [TitleItem] = [], attachments: [SummaryAttachment] = [], userNotes: String? = nil, contentType: ContentType = .general, aiEngine: String = \"Unknown\", aiModel: String, originalLength: Int, processingTime: TimeInterval = 0, generatedAt: Date? = nil, version: Int = 1, wordCount: Int? = nil, compressionRatio: Double? = nil, confidence: Double? = nil) {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift","line":418,"character":1},"reason":"Line should be 200 characters or less; currently it has 560 characters"}},{"text":" self.wordCount = wordCount ?? summary.components(separatedBy: .whitespacesAndNewlines).filter { !$0.isEmpty }.count","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift","line":436,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" self.compressionRatio = compressionRatio ?? (originalLength > 0 ? Double(self.wordCount) \/ Double(originalLength) : 0.0)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift","line":438,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" let reminderConfidence = reminders.isEmpty ? 0.5 : reminders.map { $0.confidence }.reduce(0, +) \/ Double(reminders.count)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift","line":442,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" let titleConfidence = titles.isEmpty ? 0.5 : titles.map { $0.confidence }.reduce(0, +) \/ Double(titles.count)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift","line":443,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" let c = try decoder.container(keyedBy: CodingKeys.self)","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift","line":467,"character":13},"reason":"Variable name 'c' should be between 3 and 40 characters long"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/EnhancedSummaryData.swift","line":511,"character":1},"reason":"File should contain 400 lines or less: currently contains 511"}},{"text":"class RecordingArchiveService: ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":62,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 690 lines"}},{"text":" AppLog.shared.recording(\"Archive: not marking \\(recording.recordingName ?? \"unknown\") archived because no destination URL was saved\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":99,"character":1},"reason":"Line should be 120 characters or less; currently it has 164 characters"}},{"text":" AppLog.shared.recording(\"Archived: failed to remove local audio: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":123,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" AppLog.shared.recording(\"Archived \\(archivedCount) of \\(recordings.count) recording(s), removeLocal=\\(removeLocal)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":136,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.recording(\"Failed to query recordings older than \\(days) days: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":162,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" AppLog.shared.recording(\"Cleared archive flags (local audio intact): \\(recording.recordingName ?? \"unknown\")\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":213,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" AppLog.shared.recording(\"Archive: failed to fetch archive locations: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":231,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" func restoreArchivedRecording(_ recording: RecordingEntry, from locationId: UUID? = nil) throws -> URL {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":241,"character":5},"reason":"Function should have complexity 10 or less; currently complexity is 11"}},{"text":" func restoreArchivedRecording(_ recording: RecordingEntry, from locationId: UUID? = nil) throws -> URL {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":241,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 66 lines"}},{"text":" coordinator.coordinate(writingItemAt: sourceURL, options: .forDeleting, error: &coordinatorError) { coordinatedURL in","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":323,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" private func recordArchiveLocations(for recordings: [RecordingEntry], exportedURLs: [URL], exportedAt: Date) -> [RecordingArchiveLocationInfo] {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":343,"character":1},"reason":"Line should be 120 characters or less; currently it has 148 characters"}},{"text":" private func recordArchiveLocations(for recordings: [RecordingEntry], exportedURLs: [URL], exportedAt: Date) -> [RecordingArchiveLocationInfo] {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":343,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 66 lines"}},{"text":" AppLog.shared.recording(\"Archive: exported URL did not match a staged recording: \\(url.lastPathComponent)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":359,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" AppLog.shared.recording(\"Archive: skipped untrackable destination URL \\(url.lastPathComponent)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":409,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" AppLog.shared.recording(\"Archive: failed to resolve bookmark: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":511,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" displayName: object.value(forKey: \"displayName\") as? String ?? object.value(forKey: \"exportedFilename\") as? String ?? \"Archived audio\",","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":574,"character":1},"reason":"Line should be 120 characters or less; currently it has 147 characters"}},{"text":" AppLog.shared.recording(\"Audio export: failed to create staging dir: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":638,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" AppLog.shared.recording(\"Audio export: failed to create staging dir: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":668,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" AppLog.shared.recording(\"Audio export: failed to stage \\(sourceURL.lastPathComponent): \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":707,"character":1},"reason":"Line should be 120 characters or less; currently it has 145 characters"}},{"text":" AppLog.shared.recording(\"Archive: failed to create staging dir: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":730,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" AppLog.shared.recording(\"Archive: failed to stage \\(sourceURL.lastPathComponent): \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":750,"character":1},"reason":"Line should be 120 characters or less; currently it has 144 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingArchiveService.swift","line":924,"character":1},"reason":"File should contain 400 lines or less: currently contains 924"}},{"text":"class RecordingNameGenerator {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":5,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 511 lines"}},{"text":" static func generateRecordingNameFromTranscript(_ transcript: String, contentType: ContentType, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) -> String {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":9,"character":1},"reason":"Line should be 120 characters or less; currently it has 178 characters"}},{"text":" static func generateRecordingNameFromTranscript(_ transcript: String, contentType: ContentType, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) -> String {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":9,"character":5},"reason":"Function should have complexity 10 or less; currently complexity is 15"}},{"text":" static func generateRecordingNameFromTranscript(_ transcript: String, contentType: ContentType, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) -> String {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":9,"character":12},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 60 lines"}},{"text":" AppLog.shared.recording(\"RecordingNameGenerator: Starting name generation with \\(titles.count) titles\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":14,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" AppLog.shared.recording(\"RecordingNameGenerator: Title \\(index + 1): confidence \\(title.confidence)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":16,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.recording(\"RecordingNameGenerator: Processing high-confidence title (confidence: \\(bestTitle.confidence))\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":34,"character":1},"reason":"Line should be 120 characters or less; currently it has 148 characters"}},{"text":" AppLog.shared.recording(\"RecordingNameGenerator: Processing any title (confidence: \\(anyTitle.confidence))\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":46,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" return generateNameFromTranscript(transcript, contentType: contentType, minLength: minLength, maxLength: maxLength)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":89,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" static func generateRecordingName(from summary: String, contentType: ContentType, tasks: [TaskItem], reminders: [ReminderItem]) -> String {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":92,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"text":" let summaryName = generateNameFromSummary(summary, contentType: contentType, minLength: minLength, maxLength: maxLength)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":114,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" let genericNames = [\"the\", \"a\", \"an\", \"this\", \"that\", \"it\", \"and\", \"or\", \"but\", \"in\", \"on\", \"at\", \"to\", \"for\", \"of\", \"with\", \"by\"]","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":127,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" if cleanedName.lowercased().hasSuffix(ext) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":156,"character":13},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" 9. Never end with weak words like \"with\", \"to\", \"for\", \"of\", \"in\", \"on\", \"at\", \"by\", \"from\", \"about\", \"regarding\", \"concerning\", \"pertaining\", \"related\", \"involving\", \"including\", \"containing\", \"featuring\", \"about\", \"regarding\", \"concerning\", \"pertaining\", \"related\", \"involving\", \"including\", \"containing\", \"featuring\"","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":177,"character":1},"reason":"Line should be 200 characters or less; currently it has 327 characters"}},{"text":" **IMPORTANT: Return ONLY the title, nothing else. No quotes, no explanation, no markdown formatting, no extra text, no punctuation at the end.**","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":193,"character":1},"reason":"Line should be 120 characters or less; currently it has 152 characters"}},{"text":" static func cleanStandardizedTitleResponse(_ response: String) -> String {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":202,"character":5},"reason":"Function should have complexity 10 or less; currently complexity is 11"}},{"text":" static func cleanStandardizedTitleResponse(_ response: String) -> String {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":202,"character":12},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 54 lines"}},{"text":" if cleanedTitle.lowercased().hasSuffix(roleSuffix) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":226,"character":13},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" cleanedTitle = String(cleanedTitle.dropLast(roleSuffix.count)).trimmingCharacters(in: .whitespacesAndNewlines)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":227,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" let genericTitles = [\"title\", \"conversation\", \"meeting\", \"discussion\", \"talk\", \"chat\", \"recording\", \"audio\", \"transcript\"]","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":277,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" if genericTitles.contains(lowerTitle) || genericTitles.contains(where: { lowerTitle.contains($0) && words.count <= 2 }) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":279,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" if cleaned.lowercased().hasPrefix(prefix.lowercased()) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":314,"character":13},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" private static func generateNameFromTask(_ task: TaskItem, minLength: Int, maxLength: Int) -> String {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":392,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 11"}},{"text":" let actionKeywords = [\"call\", \"email\", \"meet\", \"buy\", \"get\", \"do\", \"make\", \"see\", \"visit\", \"go\", \"come\", \"take\", \"bring\", \"send\", \"schedule\", \"book\", \"order\", \"pick up\", \"drop off\", \"return\", \"check\", \"review\", \"update\", \"prepare\", \"create\", \"develop\", \"implement\", \"analyze\", \"research\", \"present\", \"discuss\", \"plan\", \"organize\"]","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":396,"character":1},"reason":"Line should be 200 characters or less; currently it has 338 characters"}},{"text":" if taskText.contains(action) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":399,"character":13},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" let eventKeywords = [\"appointment\", \"meeting\", \"deadline\", \"call\", \"email\", \"visit\", \"check\", \"review\", \"presentation\", \"interview\", \"consultation\", \"follow-up\", \"check-in\"]","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":443,"character":1},"reason":"Line should be 120 characters or less; currently it has 181 characters"}},{"text":" if reminderText.contains(event) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":446,"character":13},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" private static func generateNameFromTranscript(_ transcript: String, contentType: ContentType, minLength: Int, maxLength: Int) -> String {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":483,"character":1},"reason":"Line should be 120 characters or less; currently it has 142 characters"}},{"text":" private static func generateNameFromTranscript(_ transcript: String, contentType: ContentType, minLength: Int, maxLength: Int) -> String {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":483,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 16"}},{"text":" private static func generateNameFromTranscript(_ transcript: String, contentType: ContentType, minLength: Int, maxLength: Int) -> String {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":483,"character":20},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 56 lines"}},{"text":" let titleKeywords = [\"meeting about\", \"discussion on\", \"call about\", \"talk about\", \"conversation about\", \"presentation on\", \"review of\", \"planning for\", \"discussion of\", \"interview with\", \"consultation about\", \"briefing on\", \"update on\", \"report on\"]","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":492,"character":1},"reason":"Line should be 200 characters or less; currently it has 258 characters"}},{"text":" private static func generateNameFromSummary(_ summary: String, contentType: ContentType, minLength: Int, maxLength: Int) -> String {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":555,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" AppLog.shared.recording(\"RecordingNameGenerator: Processing title with \\(words.count) words, constraints: min=\\(minLength), max=\\(maxLength)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":603,"character":1},"reason":"Line should be 120 characters or less; currently it has 165 characters"}},{"text":" AppLog.shared.recording(\"RecordingNameGenerator: Name too long, trying shorter (length: \\(shortName.count))\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":625,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" AppLog.shared.recording(\"RecordingNameGenerator: Trying longer name (length: \\(longerName.count))\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":635,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" AppLog.shared.recording(\"RecordingNameGenerator: Using original title (length: \\(title.text.count))\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":644,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingNameGenerator.swift","line":711,"character":1},"reason":"File should contain 400 lines or less: currently contains 711"}},{"text":"class RecordingWorkflowManager: ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":15,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 369 lines"}},{"text":" func createRecording(url: URL, name: String, date: Date, fileSize: Int64, duration: TimeInterval, quality: AudioQuality, locationData: LocationData? = nil) -> UUID {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":33,"character":1},"reason":"Line should be 120 characters or less; currently it has 169 characters"}},{"text":" func createRecording(url: URL, name: String, date: Date, fileSize: Int64, duration: TimeInterval, quality: AudioQuality, locationData: LocationData? = nil) -> UUID {","violation":{"ruleName":"Function Parameter Count","severity":"warning","ruleDescription":"Number of function parameters should be low.","ruleIdentifier":"function_parameter_count","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":33,"character":5},"reason":"Function should have 5 parameters or less: it currently has 6"}},{"text":" AppLog.shared.backgroundProcessing(\"Saving location data - lat: \\(locationData.latitude), lon: \\(locationData.longitude)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":55,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" func createTranscript(for recordingId: UUID, segments: [TranscriptSegment], speakerMappings: [String: String] = [:], engine: TranscriptionEngine? = nil, processingTime: TimeInterval = 0, confidence: Double = 0.5) -> UUID? {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":79,"character":1},"reason":"Line should be 200 characters or less; currently it has 227 characters"}},{"text":" func createTranscript(for recordingId: UUID, segments: [TranscriptSegment], speakerMappings: [String: String] = [:], engine: TranscriptionEngine? = nil, processingTime: TimeInterval = 0, confidence: Double = 0.5) -> UUID? {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":79,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 51 lines"}},{"text":" AppLog.shared.backgroundProcessing(\"Creating transcript for recording: \\(recordingEntry.recordingName ?? \"unknown\")\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":88,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" return replaceTranscript(existingTranscript, with: segments, speakerMappings: speakerMappings, engine: engine, processingTime: processingTime, confidence: confidence)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":93,"character":1},"reason":"Line should be 120 characters or less; currently it has 178 characters"}},{"text":" private func replaceTranscript(_ existingTranscript: TranscriptEntry, with segments: [TranscriptSegment], speakerMappings: [String: String] = [:], engine: TranscriptionEngine? = nil, processingTime: TimeInterval = 0, confidence: Double = 0.5) -> UUID? {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":153,"character":1},"reason":"Line should be 200 characters or less; currently it has 257 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Replacing existing transcript with ID: \\(existingTranscript.id?.uuidString ?? \"unknown\")\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":155,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Transcript replaced successfully with ID: \\(existingTranscript.id?.uuidString ?? \"unknown\")\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":184,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" func createSummary(for recordingId: UUID, transcriptId: UUID, summary: String, tasks: [TaskItem] = [], reminders: [ReminderItem] = [], titles: [TitleItem] = [], contentType: ContentType = .general, aiEngine: String = \"Unknown\", aiModel: String, originalLength: Int, processingTime: TimeInterval = 0) -> UUID? {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":195,"character":1},"reason":"Line should be 200 characters or less; currently it has 314 characters"}},{"text":" func createSummary(for recordingId: UUID, transcriptId: UUID, summary: String, tasks: [TaskItem] = [], reminders: [ReminderItem] = [], titles: [TitleItem] = [], contentType: ContentType = .general, aiEngine: String = \"Unknown\", aiModel: String, originalLength: Int, processingTime: TimeInterval = 0) -> UUID? {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":195,"character":5},"reason":"Function should have complexity 10 or less; currently complexity is 14"}},{"text":" func createSummary(for recordingId: UUID, transcriptId: UUID, summary: String, tasks: [TaskItem] = [], reminders: [ReminderItem] = [], titles: [TitleItem] = [], contentType: ContentType = .general, aiEngine: String = \"Unknown\", aiModel: String, originalLength: Int, processingTime: TimeInterval = 0) -> UUID? {","violation":{"ruleName":"Function Body Length","severity":"error","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":195,"character":5},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 111 lines"}},{"text":" AppLog.shared.backgroundProcessing(\"Summary too short (\\(summaryTrimmed.count) chars) -- skipping save to avoid storing a failed result\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":212,"character":1},"reason":"Line should be 120 characters or less; currently it has 149 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Creating summary for recording: \\(recordingEntry.recordingName ?? \"unknown\")\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":217,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Recording UUID: \\(recordingId), Transcript UUID: \\(transcriptId)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":218,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Found \\(existingSummaries.count) existing summary(ies) to clean up after save\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":230,"character":1},"reason":"Line should be 120 characters or less; currently it has 142 characters"}},{"text":" let recordingURL = appCoordinator?.coreDataManager.getAbsoluteURL(for: recordingEntry) ?? URL(fileURLWithPath: \"\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":235,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Migrated supplemental data from \\(oldId) to \\(summaryData.id)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":306,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Failed to migrate supplemental data from \\(oldId): \\(error)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":308,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Cleaned up \\(deletedCount) old summary(ies) for recording \\(recordingId)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":325,"character":1},"reason":"Line should be 120 characters or less; currently it has 145 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"No valid URL found for recording: \\(recordingEntry.recordingName ?? \"unknown\")\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":410,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Audio file renamed: \\(oldURL.lastPathComponent) -> \\(newURL.lastPathComponent)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":422,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Audio file not found at expected location, checking new name\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":428,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Updated Core Data URL to match existing file: \\(newURL.lastPathComponent)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":434,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Thumbnail generation warning during file rename (can be ignored)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":446,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Failed to save Core Data after file rename: \\(error)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":458,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" AppLog.shared.backgroundProcessing(\"Failed to rename audio file: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":461,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/RecordingWorkflowManager.swift","line":538,"character":1},"reason":"File should contain 400 lines or less: currently contains 538"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/SummarizationEngine.swift","line":29,"character":1},"reason":"Line should be 120 characters or less; currently it has 165 characters"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/SummarizationEngine.swift","line":29,"character":56},"reason":"Tuples should have at most 2 members"}},{"text":" return \"Try with a shorter recording, check your connection, or increase the AI timeout in Settings > AI Processing.\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/SummarizationErrors.swift","line":54,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" return \"This transcript triggered safety filters on this AI engine. Try a different AI engine in Settings (e.g., OpenAI, Claude, or Gemini).\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/SummarizationErrors.swift","line":68,"character":1},"reason":"Line should be 120 characters or less; currently it has 153 characters"}},{"text":" let documents = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first ?? fileManager.temporaryDirectory","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/SummaryAttachmentStore.swift","line":125,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" AppLog.shared.summarization(\"SummaryMetadataCodec: Failed to encode metadata, falling back to plain model string\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/SummaryMetadataCodec.swift","line":28,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" init(recordingURL: URL, recordingName: String, recordingDate: Date, segments: [TranscriptSegment], speakerMappings: [String: String] = [:]) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptData.swift","line":36,"character":1},"reason":"Line should be 120 characters or less; currently it has 145 characters"}},{"text":" init(recordingId: UUID, recordingURL: URL, recordingName: String, recordingDate: Date, segments: [TranscriptSegment], speakerMappings: [String: String] = [:], engine: TranscriptionEngine? = nil, processingTime: TimeInterval = 0, confidence: Double = 0.5) {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptData.swift","line":52,"character":1},"reason":"Line should be 200 characters or less; currently it has 260 characters"}},{"text":" init(id: UUID, recordingId: UUID, recordingURL: URL, recordingName: String, recordingDate: Date, segments: [TranscriptSegment], speakerMappings: [String: String] = [:], engine: TranscriptionEngine? = nil, processingTime: TimeInterval = 0, confidence: Double = 0.5, createdAt: Date? = nil, lastModified: Date? = nil) {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptData.swift","line":68,"character":1},"reason":"Line should be 200 characters or less; currently it has 321 characters"}},{"text":" private func convertCoreDataToTranscriptData(transcriptEntry: TranscriptEntry, recordingEntry: RecordingEntry) -> TranscriptData? {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptManager.swift","line":68,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" AppLog.shared.transcription(\"Could not resolve URL for recording: \\(recordingEntry.recordingName ?? \"unknown\")\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptManager.swift","line":76,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" func activeTranscriptionJobStatus(for recording: RecordingEntry, appCoordinator: AppDataCoordinator) -> JobProcessingStatus? {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptionStarter.swift","line":52,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" AppLog.shared.transcription(\"Cleaned audio created at temp location: \\(tempCleanedURL.lastPathComponent)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptionStarter.swift","line":110,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" guard let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptionStarter.swift","line":113,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" AppLog.shared.transcription(\"Could not access Documents directory, using original file\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptionStarter.swift","line":114,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" performEnhancedTranscription(for: recording, sourceAudioURL: documentsCleanedURL, appCoordinator: appCoordinator)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptionStarter.swift","line":126,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" private func performEnhancedTranscription(for recording: RecordingEntry,","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptionStarter.swift","line":136,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 68 lines"}},{"text":" rawValue: UserDefaults.standard.string(forKey: \"selectedTranscriptionEngine\") ?? TranscriptionEngine.fluidAudio.rawValue","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptionStarter.swift","line":141,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" let result = try await enhancedTranscriptionManager.transcribeAudioFile(at: transcriptionURL, using: selectedEngine)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptionStarter.swift","line":171,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" AppLog.shared.transcription(\"Transcription result: success=\\(result.success), textLength=\\(result.fullText.count)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptionStarter.swift","line":172,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" AppLog.shared.transcription(\"Cleaned up source audio file after fallback: \\(cleanupURL.lastPathComponent)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/TranscriptionStarter.swift","line":213,"character":1},"reason":"Line should be 120 characters or less; currently it has 142 characters"}},{"text":" formatter.setLocalizedDateFormatFromTemplate(timeFormat == .twentyFourHour ? \"M\/d\/yy HH:mm\" : \"M\/d\/yy h:mm a\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/UserPreferences.swift","line":85,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" formatter.setLocalizedDateFormatFromTemplate(timeFormat == .twentyFourHour ? \"MMM d, yyyy HH:mm\" : \"MMM d, yyyy h:mm a\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/UserPreferences.swift","line":88,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" formatter.setLocalizedDateFormatFromTemplate(timeFormat == .twentyFourHour ? \"MMMM d, yyyy HH:mm\" : \"MMMM d, yyyy h:mm a\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/UserPreferences.swift","line":91,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" formatter.setLocalizedDateFormatFromTemplate(timeFormat == .twentyFourHour ? \"EEEE, MMMM d, yyyy HH:mm\" : \"EEEE, MMMM d, yyyy h:mm a\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Models\/UserPreferences.swift","line":94,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" let modified_at: String","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":45,"character":9},"reason":"Variable name 'modified_at' should only contain alphanumeric and other allowed characters"}},{"text":" \"description\": \"The main comprehensive summary of the entire transcript (15-20% of original length). CRITICAL: This should be a LONG, detailed summary with complete overview, all key points, insights, takeaways, main themes and conclusions. Use markdown formatting with ## headers, **bold**, β€’ bullets. This is the primary content field and must be substantial (minimum 500 characters for short transcripts, 2000+ for longer ones).\",","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":124,"character":1},"reason":"Line should be 200 characters or less; currently it has 449 characters"}},{"text":" \"text\": [\"type\": \"string\", \"description\": \"Concise, specific, UNIQUE task description (one clear action item, not a long explanation). Must be different from other tasks.\"],","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":133,"character":1},"reason":"Line should be 120 characters or less; currently it has 197 characters"}},{"text":" \"category\": [\"type\": \"string\", \"enum\": [\"Call\", \"Email\", \"Meeting\", \"Purchase\", \"Research\", \"Travel\", \"Health\", \"General\"]],","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":135,"character":1},"reason":"Line should be 120 characters or less; currently it has 148 characters"}},{"text":" \"timeReference\": [\"type\": [\"string\", \"null\"], \"description\": \"Specific time\/date mentioned or null\"]","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":149,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" \"description\": \"Array of 3-5 diverse, descriptive titles. Each title should capture a different aspect or topic. REQUIRED field - must generate at least 3 titles.\",","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":156,"character":1},"reason":"Line should be 120 characters or less; currently it has 180 characters"}},{"text":" \"text\": [\"type\": \"string\", \"description\": \"Descriptive, unique title (40-60 characters). Each title must be different and capture a distinct aspect of the content.\", \"minLength\": 10, \"maxLength\": 80],","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":162,"character":1},"reason":"Line should be 200 characters or less; currently it has 224 characters"}},{"text":" \"category\": [\"type\": \"string\", \"enum\": [\"Call\", \"Email\", \"Meeting\", \"Purchase\", \"Research\", \"Travel\", \"Health\", \"General\"]],","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":187,"character":1},"reason":"Line should be 120 characters or less; currently it has 148 characters"}},{"text":" \"timeReference\": [\"type\": [\"string\", \"null\"], \"description\": \"Specific time\/date mentioned or null\"]","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":200,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" init(type: String, description: String, items: OllamaProperty? = nil, properties: [String: OllamaProperty]? = nil, required: [String]? = nil) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":256,"character":1},"reason":"Line should be 120 characters or less; currently it has 147 characters"}},{"text":" static func object(_ type: String, _ description: String, properties: [String: OllamaProperty], required: [String]? = nil) -> OllamaProperty {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":273,"character":1},"reason":"Line should be 120 characters or less; currently it has 146 characters"}},{"text":" let num_predict: Int","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":279,"character":9},"reason":"Variable name 'num_predict' should only contain alphanumeric and other allowed characters"}},{"text":" let top_p: Double","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":281,"character":9},"reason":"Variable name 'top_p' should only contain alphanumeric and other allowed characters"}},{"text":" let top_k: Int","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":282,"character":9},"reason":"Variable name 'top_k' should only contain alphanumeric and other allowed characters"}},{"text":" let created_at: String","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":287,"character":9},"reason":"Variable name 'created_at' should only contain alphanumeric and other allowed characters"}},{"text":" let done_reason: String?","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":290,"character":9},"reason":"Variable name 'done_reason' should only contain alphanumeric and other allowed characters"}},{"text":" let total_duration: Int64?","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":292,"character":9},"reason":"Variable name 'total_duration' should only contain alphanumeric and other allowed characters"}},{"text":" let load_duration: Int64?","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":293,"character":9},"reason":"Variable name 'load_duration' should only contain alphanumeric and other allowed characters"}},{"text":" let prompt_eval_count: Int?","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":294,"character":9},"reason":"Variable name 'prompt_eval_count' should only contain alphanumeric and other allowed characters"}},{"text":" let prompt_eval_duration: Int64?","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":295,"character":9},"reason":"Variable name 'prompt_eval_duration' should only contain alphanumeric and other allowed characters"}},{"text":" let eval_count: Int?","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":296,"character":9},"reason":"Variable name 'eval_count' should only contain alphanumeric and other allowed characters"}},{"text":" let eval_duration: Int64?","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":297,"character":9},"reason":"Variable name 'eval_duration' should only contain alphanumeric and other allowed characters"}},{"text":" let tool_calls: [OllamaToolCall]?","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":298,"character":9},"reason":"Variable name 'tool_calls' should only contain alphanumeric and other allowed characters"}},{"text":"class OllamaService: ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":312,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 2057 lines"}},{"text":" AppLog.shared.networking(\"OllamaService: Connection test response: \\(httpResponse.statusCode)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":352,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Connection failed with status \\(httpResponse.statusCode)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":358,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Error response received (\\(data.count) bytes)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":360,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Connection test failed: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":378,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Failed to check model availability: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":415,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Failed to get available models: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":425,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" private func extractJSONFromResponse(_ response: String) -> String {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":474,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 52 lines"}},{"text":" AppLog.shared.networking(\"OllamaService: Successfully converted wrong schema to correct format\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":530,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" if response.contains(\"\\\"summary\\\"\") || response.contains(\"\\\"contentType\\\"\") || response.contains(\"\\\"transcript\\\"\") || response.contains(\"\\\"key_points\\\"\") {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":539,"character":1},"reason":"Line should be 120 characters or less; currently it has 163 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Detected complete processing context but invalid schema, returning empty structure\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":541,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Failed to convert wrong schema: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":603,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" func processComplete(from text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":666,"character":1},"reason":"Line should be 120 characters or less; currently it has 172 characters"}},{"text":" func processComplete(from text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":666,"character":5},"reason":"Function should have complexity 10 or less; currently complexity is 11"}},{"text":" func processComplete(from text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Function Body Length","severity":"error","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":666,"character":5},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 121 lines"}},{"text":" func processComplete(from text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":666,"character":61},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.networking(\"OllamaService: Structured outputs failed, falling back to traditional prompting: \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":691,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Raw response for complete processing, length: \\(response.count) characters\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":701,"character":1},"reason":"Line should be 120 characters or less; currently it has 144 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Summary: \\(rawResult.summary.count) chars, Tasks: \\(tasks.count), Reminders: \\(reminders.count), Titles: \\(titles.count)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":760,"character":1},"reason":"Line should be 120 characters or less; currently it has 190 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: JSON parsing failed for complete processing: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":765,"character":1},"reason":"Line should be 120 characters or less; currently it has 144 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Attempting to parse cleaned JSON for complete processing\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":771,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Cleaned JSON parsing also failed: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":821,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" throw OllamaError.parsingError(\"Failed to parse JSON response after cleaning: \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":822,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Summary generation failed with parsing error: \\(message)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":842,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Summary generation failed: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":845,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" let prompt = \"Please analyze the following transcript and create a comprehensive summary using the create_summary function:\\n\\n\\(text)\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":862,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Successfully generated summary using standard tool calling\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":875,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Standard tool calling failed, falling back to traditional prompting: \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":885,"character":1},"reason":"Line should be 120 characters or less; currently it has 153 characters"}},{"text":" \"A comprehensive markdown-formatted summary (approximately 10% of original transcript length) with ## headers, **bold** text, β€’ bullet points, and proper structure. Aim for substantive, detailed content.\"","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":903,"character":1},"reason":"Line should be 200 characters or less; currently it has 232 characters"}},{"text":" private func createCompleteAnalysisTool() -> OllamaTool {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":912,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 64 lines"}},{"text":" \"category\": OllamaProperty.simple(\"string\", \"Category: Call, Email, Meeting, Purchase, Research, Travel, Health, or General\"),","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":934,"character":1},"reason":"Line should be 120 characters or less; currently it has 162 characters"}},{"text":" \"urgency\": OllamaProperty.simple(\"string\", \"Urgency: Immediate, Today, This Week, or Later\"),","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":948,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" \"timeReference\": OllamaProperty.simple(\"string\", \"Specific time\/date mentioned or null\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":949,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" \"category\": OllamaProperty.simple(\"string\", \"Category: Meeting, Personal, Technical, or General\"),","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":962,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" \"category\": OllamaProperty.simple(\"string\", \"Category: Call, Email, Meeting, Purchase, Research, Travel, Health, or General\"),","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":997,"character":1},"reason":"Line should be 120 characters or less; currently it has 162 characters"}},{"text":" \"urgency\": OllamaProperty.simple(\"string\", \"Urgency: Immediate, Today, This Week, or Later\"),","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1011,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" \"category\": OllamaProperty.simple(\"string\", \"Category: Meeting, Personal, Technical, or General\"),","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1041,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" private func createRobustSummaryPrompt(from text: String) -> String {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1056,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 58 lines"}},{"text":" You are a professional AI assistant specialized in analyzing and summarizing conversations, meetings, and transcripts. Your goal is to create comprehensive, well-structured summaries that capture the essential information.","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1073,"character":1},"reason":"Line should be 200 characters or less; currently it has 230 characters"}},{"text":" private func createRobustCompleteProcessingPrompt(from text: String) -> String {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1124,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 55 lines"}},{"text":" You MUST return ONLY valid JSON in the EXACT format specified below. Do not include any other text, explanations, or additional fields.","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1127,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"text":" func extractTasksAndReminders(from text: String) async throws -> (tasks: [TaskItem], reminders: [ReminderItem]) {","violation":{"ruleName":"Function Body Length","severity":"error","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1193,"character":5},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 122 lines"}},{"text":" AppLog.shared.networking(\"OllamaService: Structured outputs failed for tasks\/reminders, falling back: \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1217,"character":1},"reason":"Line should be 120 characters or less; currently it has 145 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Raw response for tasks\/reminders, length: \\(response.count) characters\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1249,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Failed to convert tasks\/reminders response to UTF-8 data\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1260,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Successfully parsed \\(tasks.count) tasks and \\(reminders.count) reminders\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1289,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: JSON parsing failed for tasks\/reminders: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1292,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Attempting to parse cleaned JSON for tasks\/reminders\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1298,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Successfully parsed cleaned JSON with \\(tasks.count) tasks and \\(reminders.count) reminders\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1334,"character":1},"reason":"Line should be 120 characters or less; currently it has 154 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Cleaned JSON parsing also failed for tasks\/reminders: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1337,"character":1},"reason":"Line should be 120 characters or less; currently it has 161 characters"}},{"text":" func extractTitles(from text: String) async throws -> [TitleItem] {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1347,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 68 lines"}},{"text":" AppLog.shared.networking(\"OllamaService: Raw response for titles, length: \\(response.count) characters\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1368,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: JSON parsing failed for titles: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1400,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Failed to convert cleaned titles response to data\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1409,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Successfully parsed cleaned JSON with \\(titles.count) titles\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1424,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Cleaned JSON parsing also failed for titles: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1427,"character":1},"reason":"Line should be 120 characters or less; currently it has 152 characters"}},{"text":" private func processCompleteWithTools(from text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)? {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1437,"character":1},"reason":"Line should be 120 characters or less; currently it has 190 characters"}},{"text":" private func processCompleteWithTools(from text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)? {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1437,"character":78},"reason":"Tuples should have at most 2 members"}},{"text":" let prompt = \"Please analyze the following transcript and provide a complete analysis using the complete_analysis function:\\n\\n\\(text)\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1449,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Standard tool calling failed for complete processing: \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1469,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" private func parseCompleteAnalysisResult(data: Data) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1474,"character":1},"reason":"Line should be 120 characters or less; currently it has 179 characters"}},{"text":" private func parseCompleteAnalysisResult(data: Data) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1474,"character":68},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.networking(\"OllamaService: Failed to parse tool calling result: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1520,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Qwen tool calling failed, falling back: \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1574,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" private func processCompleteWithQwenTools(from text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)? {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1579,"character":1},"reason":"Line should be 120 characters or less; currently it has 194 characters"}},{"text":" private func processCompleteWithQwenTools(from text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)? {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1579,"character":82},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.networking(\"OllamaService: Found create_summary with \\(summary.count) characters\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1597,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Using high-quality Qwen summary for complete processing\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1601,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Successfully created complete result from high-quality summary\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1609,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Final result: Summary: \\(summary.count) chars, Tasks: \\(tasks.count), Reminders: \\(reminders.count), Titles: \\(titles.count)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1610,"character":1},"reason":"Line should be 200 characters or less; currently it has 210 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Failed to extract tasks\/reminders from excellent summary: \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1613,"character":1},"reason":"Line should be 120 characters or less; currently it has 158 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Summary too short (\\(summary.count) chars), falling back\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1618,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: No valid Qwen tool calls in complete processing response, falling back\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1623,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Qwen tool calling failed for complete processing: \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1627,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" private func createQwenToolPrompt(for type: String, text: String) -> String {","violation":{"ruleName":"Function Body Length","severity":"error","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1632,"character":13},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 126 lines"}},{"text":" \"description\": \"A comprehensive markdown-formatted summary (15-20% of original length) with ## headers, **bold** text, β€’ bullet points, and proper structure\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1651,"character":1},"reason":"Line should be 120 characters or less; currently it has 181 characters"}},{"text":" \"description\": \"Perform complete analysis extracting summary, tasks, reminders, titles, and content type\",","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1685,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" \"description\": \"Comprehensive markdown-formatted summary with ## headers, **bold** text, β€’ bullets\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1691,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" \"category\": {\"type\": \"string\", \"description\": \"Category: Call, Email, Meeting, Purchase, Research, Travel, Health, or General\"},","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1701,"character":1},"reason":"Line should be 120 characters or less; currently it has 156 characters"}},{"text":" \"urgency\": {\"type\": \"string\", \"description\": \"Urgency: Immediate, Today, This Week, or Later\"},","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1714,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" \"category\": {\"type\": \"string\", \"description\": \"Category: Meeting, Personal, Technical, or General\"},","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1727,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" {\"name\": \"complete_analysis\", \"arguments\": {\"summary\": \"...\", \"tasks\": [...], \"reminders\": [...], \"titles\": [...], \"contentType\": \"...\"}}","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1747,"character":1},"reason":"Line should be 120 characters or less; currently it has 149 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Failed to parse Qwen tool call JSON: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1785,"character":1},"reason":"Line should be 120 characters or less; currently it has 144 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Found structured Qwen content, using as fallback summary\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1792,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Summary content length: \\(cleanedResponse.count) characters\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1804,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" private func parseQwenCompleteAnalysisResult(arguments: [String: Any]) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1813,"character":1},"reason":"Line should be 120 characters or less; currently it has 197 characters"}},{"text":" private func parseQwenCompleteAnalysisResult(arguments: [String: Any]) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1813,"character":86},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.networking(\"OllamaService: GPT-OSS tool calling failed, falling back: \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1959,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" private func processCompleteWithGPTOSSTools(from text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)? {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1964,"character":1},"reason":"Line should be 120 characters or less; currently it has 196 characters"}},{"text":" private func processCompleteWithGPTOSSTools(from text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)? {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1964,"character":84},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.networking(\"OllamaService: No valid GPT-OSS tool calls in complete processing response, falling back\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1978,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: GPT-OSS tool calling failed for complete processing: \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1982,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" - summary (string): A comprehensive markdown-formatted summary (15-20% of original length) with ## headers, **bold** text, β€’ bullet points, and proper structure","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1996,"character":1},"reason":"Line should be 120 characters or less; currently it has 172 characters"}},{"text":" Please analyze the following transcript and use the create_summary function to generate a well-structured summary:","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":1998,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" - tasks (array): Array of task objects with text, priority (High\/Medium\/Low), category (Call\/Email\/Meeting\/Purchase\/Research\/Travel\/Health\/General), timeReference","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2013,"character":1},"reason":"Line should be 120 characters or less; currently it has 174 characters"}},{"text":" - reminders (array): Array of reminder objects with text, urgency (Immediate\/Today\/This Week\/Later), timeReference","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2014,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" - titles (array): Array of title objects with text (40-60 chars), category (Meeting\/Personal\/Technical\/General), confidence (0.0-1.0)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2015,"character":1},"reason":"Line should be 120 characters or less; currently it has 145 characters"}},{"text":" Please analyze the following transcript and use the complete_analysis function to provide comprehensive analysis:","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2018,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Parsing GPT-OSS response, length: \\(response.count) characters\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2032,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Successfully parsed GPT-OSS function call: \\(functionName)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2048,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Failed to parse GPT-OSS function call JSON: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2052,"character":1},"reason":"Line should be 120 characters or less; currently it has 151 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Attempting to parse extracted JSON from GPT-OSS response\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2060,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Successfully parsed extracted GPT-OSS JSON: \\(functionName)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2065,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Failed to parse extracted GPT-OSS JSON: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2069,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"text":" private func parseGPTOSSCompleteAnalysisResult(arguments: [String: Any]) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2077,"character":1},"reason":"Line should be 120 characters or less; currently it has 199 characters"}},{"text":" private func parseGPTOSSCompleteAnalysisResult(arguments: [String: Any]) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2077,"character":88},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.networking(\"OllamaService: Successfully generated summary using Magistral tool calling\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2153,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Magistral tool calling failed, falling back: \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2162,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" private func processCompleteWithMagistralTools(from text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)? {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2167,"character":1},"reason":"Line should be 120 characters or less; currently it has 199 characters"}},{"text":" private func processCompleteWithMagistralTools(from text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)? {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2167,"character":87},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.networking(\"OllamaService: No valid Magistral tool calls in complete processing response, falling back\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2181,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Magistral tool calling failed for complete processing: \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2185,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" private func createMagistralToolPrompt(for type: String, text: String) -> String {","violation":{"ruleName":"Function Body Length","severity":"error","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2190,"character":13},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 106 lines"}},{"text":" \"description\": \"A comprehensive markdown-formatted summary (15-20% of original length) with ## headers, **bold** text, β€’ bullet points, and proper structure\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2207,"character":1},"reason":"Line should be 120 characters or less; currently it has 179 characters"}},{"text":" [INST]Please analyze the following transcript and use the create_summary tool to generate a well-structured summary:","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2215,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" I need to analyze this transcript and create a comprehensive summary using the create_summary tool. Let me process the content and structure it properly.","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2220,"character":1},"reason":"Line should be 120 characters or less; currently it has 165 characters"}},{"text":" \"description\": \"Perform complete analysis extracting summary, tasks, reminders, titles, and content type\",","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2234,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" \"description\": \"Comprehensive markdown-formatted summary with ## headers, **bold** text, β€’ bullets\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2240,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" \"category\": {\"type\": \"string\", \"description\": \"Category: Call, Email, Meeting, Purchase, Research, Travel, Health, or General\"},","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2249,"character":1},"reason":"Line should be 120 characters or less; currently it has 154 characters"}},{"text":" \"urgency\": {\"type\": \"string\", \"description\": \"Urgency: Immediate, Today, This Week, or Later\"},","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2260,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" \"category\": {\"type\": \"string\", \"description\": \"Category: Meeting, Personal, Technical, or General\"},","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2271,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" [INST]Please analyze the following transcript and use the complete_analysis tool to provide comprehensive analysis:","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2286,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" I need to perform a complete analysis of this transcript, extracting summary, tasks, reminders, titles, and content type. Let me use the complete_analysis tool with all required parameters.","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2291,"character":1},"reason":"Line should be 200 characters or less; currently it has 201 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Successfully parsed Magistral tool call: \\(functionName)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2327,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Failed to parse Magistral arguments JSON: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2331,"character":1},"reason":"Line should be 120 characters or less; currently it has 157 characters"}},{"text":" private func parseMagistralCompleteAnalysisResult(arguments: [String: Any]) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2356,"character":1},"reason":"Line should be 200 characters or less; currently it has 202 characters"}},{"text":" private func parseMagistralCompleteAnalysisResult(arguments: [String: Any]) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2356,"character":91},"reason":"Tuples should have at most 2 members"}},{"text":" private func generateResponseWithTools(prompt: String, model: String, tools: [OllamaTool]) async throws -> OllamaGenerateResponse {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2421,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" private func generateResponseWithTools(prompt: String, model: String, tools: [OllamaTool]) async throws -> OllamaGenerateResponse {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2421,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 59 lines"}},{"text":" AppLog.shared.networking(\"OllamaService: Tool calling network request failed: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2457,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: HTTP error for tool calling - Status: \\(httpResponse.statusCode)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2467,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Received tool calling response data of \\(data.count) bytes\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2477,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Tool calling JSON parsing failed: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2491,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" private func generateResponse(prompt: String, model: String, cleanForJSON: Bool = true) async throws -> String {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2498,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 65 lines"}},{"text":" AppLog.shared.networking(\"OllamaService: Network request failed: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2535,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Raw response content length: \\(generateResponse.response.count) characters\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2562,"character":1},"reason":"Line should be 120 characters or less; currently it has 148 characters"}},{"text":" let cleanedResponse = cleanForJSON ? cleanOllamaResponse(generateResponse.response) : cleanSummaryResponse(generateResponse.response)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2567,"character":1},"reason":"Line should be 120 characters or less; currently it has 145 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Cleaned response length: \\(cleanedResponse.count) characters\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2569,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" throw OllamaError.parsingError(\"Failed to parse JSON response: \\(error.localizedDescription). Response length: \\(data.count) bytes\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2584,"character":1},"reason":"Line should be 120 characters or less; currently it has 144 characters"}},{"text":" private func generateStructuredResponse(prompt: String, model: String, schema: [String: Any]) async throws -> String {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2590,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" private func generateStructuredResponse(prompt: String, model: String, schema: [String: Any]) async throws -> String {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2590,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 55 lines"}},{"text":" AppLog.shared.networking(\"OllamaService: Structured output network request failed: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2625,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: HTTP error for structured output - Status: \\(httpResponse.statusCode)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2635,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Received structured response data of \\(data.count) bytes\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2644,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Structured response received, length: \\(generateResponse.response.count) characters\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2650,"character":1},"reason":"Line should be 120 characters or less; currently it has 153 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Structured output JSON parsing failed: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2657,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" private func createStructuredCompleteProcessingPrompt(from text: String) -> String {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2666,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 57 lines"}},{"text":" You are analyzing a transcript. Extract and summarize the ACTUAL CONTENT discussed, not a description of what type of document it is.","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2669,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" \"tasks\": [{\"text\": \"Specific action item\", \"priority\": \"High|Medium|Low\", \"category\": \"Call|Email|Meeting|Purchase|Research|Travel|Health|General\", \"timeReference\": null}],","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2675,"character":1},"reason":"Line should be 120 characters or less; currently it has 182 characters"}},{"text":" \"reminders\": [{\"text\": \"Time-sensitive item\", \"urgency\": \"Immediate|Today|This Week|Later\", \"timeReference\": null}],","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2676,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" \"titles\": [{\"text\": \"Descriptive title\", \"category\": \"Meeting|Personal|Technical|General\", \"confidence\": 0.8}],","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2677,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" private func parseStructuredCompleteResponse(_ response: String) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2726,"character":1},"reason":"Line should be 120 characters or less; currently it has 191 characters"}},{"text":" private func parseStructuredCompleteResponse(_ response: String) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2726,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 11"}},{"text":" private func parseStructuredCompleteResponse(_ response: String) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2726,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 90 lines"}},{"text":" private func parseStructuredCompleteResponse(_ response: String) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2726,"character":80},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.networking(\"OllamaService: Validating structured response - Summary: \\(summaryLength) chars, Titles: \\(rawResult.titles.count), Tasks: \\(rawResult.tasks.count)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2738,"character":1},"reason":"Line should be 200 characters or less; currently it has 202 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Summary is very short (\\(summaryLength) chars), may need enhancement\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2742,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Skipping invalid task (question format detected)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2756,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Skipping invalid reminder (statement format detected)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2797,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Final: Summary: \\(rawResult.summary.count) chars, Tasks: \\(tasks.count), Reminders: \\(reminders.count), Titles: \\(titles.count)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2842,"character":1},"reason":"Line should be 120 characters or less; currently it has 197 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Structured JSON parsing failed: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2847,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" private func parseStructuredTasksReminders(_ response: String) throws -> (tasks: [TaskItem], reminders: [ReminderItem]) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2852,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" AppLog.shared.networking(\"OllamaService: Structured tasks\/reminders parsing failed: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2891,"character":1},"reason":"Line should be 120 characters or less; currently it has 142 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"error","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaService.swift","line":2955,"character":1},"reason":"File should contain 1000 lines or less: currently contains 2955"}},{"text":"struct OllamaSettingsView: View {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaSettingsView.swift","line":10,"character":1},"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 365 lines"}},{"text":" @AppStorage(EndpointSecurityPolicy.allowInsecurePublicEndpointsKey) private var allowInsecurePublicEndpoints: Bool = false","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaSettingsView.swift","line":18,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OllamaSettingsView.swift","line":448,"character":1},"reason":"File should contain 400 lines or less: currently contains 448"}},{"text":" completionMessage = \"Both models have been downloaded successfully! You can now use on-device AI for transcription and summaries.\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceAIDownloadMonitor.swift","line":60,"character":1},"reason":"Line should be 120 characters or less; currently it has 142 characters"}},{"text":" body: \"On-device AI models have finished downloading. You can now use on-device transcription and summaries.\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceAIDownloadMonitor.swift","line":66,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceAIDownloadMonitor] Notification permission request failed: \\(error.localizedDescription)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceAIDownloadMonitor.swift","line":87,"character":1},"reason":"Line should be 120 characters or less; currently it has 159 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceAIDownloadMonitor] Failed to send notification: \\(error)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceAIDownloadMonitor.swift","line":110,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":"open class OnDeviceLLM: ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":17,"character":6},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 508 lines"}},{"text":" public var preprocess: (_ input: String, _ history: [LLMChat], _ llmInstance: OnDeviceLLM) -> String = { input, _, _ in return input }","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":44,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" let logCallback: @convention(c) (ggml_log_level, UnsafePointer?, UnsafeMutableRawPointer?) -> Void = { level, text, _ in","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":130,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" public init(","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":164,"character":12},"reason":"Initializer body should span 50 lines or less excluding comments and whitespace: currently spans 81 lines"}},{"text":" let modelParams_n = llama_model_n_params(model)","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":202,"character":13},"reason":"Variable name 'modelParams_n' should only contain alphanumeric and other allowed characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLM] Model loaded - size: \\(modelSize \/ 1_000_000)MB, params: \\(modelParams_n \/ 1_000_000)M\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":203,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" let n_batch: UInt32","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":217,"character":13},"reason":"Variable name 'n_batch' should only contain alphanumeric and other allowed characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLM] Context: n_ctx=\\(self.maxTokenCount), n_batch=\\(n_batch), model_train_ctx=\\(modelTrainCtx), threads=\\(processorCount)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":228,"character":1},"reason":"Line should be 120 characters or less; currently it has 185 characters"}},{"text":" if let s = stopSequence, !sequences.contains(s) {","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":241,"character":16},"reason":"Variable name 's' should be between 3 and 40 characters long"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLM] App is backgrounded, stopping token generation to avoid Metal crash\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":412,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLM] Decode failed during token prediction, ending generation\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":426,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" private func tokenizeAndBatchInput(message input: borrowing String) -> Bool {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":433,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 11"}},{"text":" private func tokenizeAndBatchInput(message input: borrowing String) -> Bool {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":433,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 52 lines"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLM] Input too long (\\(tokens.count) tokens), truncating to \\(maxInputTokens) (reserving \\(outputReserve) for output)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":445,"character":1},"reason":"Line should be 120 characters or less; currently it has 184 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLM] Processing \\(totalTokens) input tokens in batches of \\(batchSize)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":462,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" for i in 0...Continuation) -> Bool {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":513,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 14"}},{"text":" private func emitDecoded(token: Token, to output: borrowing AsyncStream.Continuation) -> Bool {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":513,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 56 lines"}},{"text":" struct saved {","violation":{"ruleName":"Type Name","severity":"error","ruleDescription":"Type name should only contain alphanumeric characters, start with an uppercase character and span between 3 and 40 characters in length.\nPrivate types may start with an underscore.","ruleIdentifier":"type_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":514,"character":16},"reason":"Type name 'saved' should start with an uppercase character"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLM] Max output tokens (\\(self.maxOutputTokens)) reached, stopping generation\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":606,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" let seq_id: Int32 = 0","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":628,"character":13},"reason":"Variable name 'seq_id' should only contain alphanumeric and other allowed characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLM] KV cache trimmed: kv_cache(\\(kvCacheTokenCount)) nPast(\\(self.nPast))\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":639,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" public func performInference(to input: String, with makeOutputFrom: @escaping (AsyncStream) async -> String) async {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":644,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLM] Cannot rollback - context is nil (likely already cleared)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":684,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" let seq_id = Int32(0)","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":689,"character":17},"reason":"Variable name 'seq_id' should only contain alphanumeric and other allowed characters"}},{"text":" let bytesWritten = llama_state_get_data(contextPointer, baseAddress.assumingMemoryBound(to: UInt8.self), stateSize)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":719,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" let bytesRead = llama_state_set_data(contextPointer, baseAddress.assumingMemoryBound(to: UInt8.self), stateData.count)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":735,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLM.swift","line":745,"character":1},"reason":"File should contain 400 lines or less: currently contains 745"}},{"text":" @Published public var selectedModel: OnDeviceLLMModelInfo = OnDeviceLLMModelInfo.granite4Micro \/\/ Default, will be updated in init","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift","line":31,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMDownloadManager] Starting download from host: \\(url.host ?? \"unknown\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift","line":127,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMDownloadManager] Error checking disk space: \\(error)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift","line":244,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" public nonisolated func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift","line":264,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" public nonisolated func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift","line":264,"character":24},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 52 lines"}},{"text":" let model = OnDeviceLLMModelInfo.allModels.first(where: { $0.id == modelId }) ?? OnDeviceLLMModelInfo.defaultSummarizationModel","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift","line":283,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMDownloadManager] File saved successfully. Size: \\(formatSize(fileSize))\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift","line":314,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" public nonisolated func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift","line":341,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMDownloadManager] Task completed. Error: \\(error?.localizedDescription ?? \"none\")\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift","line":343,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMDownloadManager] HTTP Status: \\(httpResponse.statusCode)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift","line":346,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" public nonisolated func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift","line":367,"character":1},"reason":"Line should be 120 characters or less; currently it has 195 characters"}},{"text":" public nonisolated func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift","line":401,"character":1},"reason":"Line should be 200 characters or less; currently it has 223 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMDownloadManager] Redirect to host: \\(request.url?.host ?? \"unknown\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift","line":402,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" public nonisolated func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift","line":406,"character":1},"reason":"Line should be 200 characters or less; currently it has 227 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMDownloadManager.swift","line":443,"character":1},"reason":"File should contain 400 lines or less: currently contains 443"}},{"text":"class OnDeviceLLMEngine: SummarizationEngine, ConnectionTestable {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":18,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 468 lines"}},{"text":" var description: String { \"Private, local summarization using models like Llama, Phi, or Mistral running entirely on your device.\" }","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":24,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Model not downloaded: \\(selectedModel.displayName)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":42,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" private let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? \"com.bisonnotes.app\", category: \"OnDeviceLLMEngine\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":58,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" logger.info(\"Configuration updated - Model: \\(newConfig.modelInfo.displayName), Temp: \\(newConfig.temperature)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":130,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" func processComplete(text: String) async throws -> (","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":218,"character":56},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Using accurate tokenization: \\(tokenCount) tokens\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":251,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Using token estimation: \\(tokenCount) tokens\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":255,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Text token count: \\(tokenCount), max context: \\(maxContextTokens), output reserve: \\(outputReserve), effective input limit: \\(effectiveInputLimit)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":258,"character":1},"reason":"Line should be 200 characters or less; currently it has 220 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Large text detected, using chunked processing with overlap\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":262,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Inference interrupted by app backgrounding (GPU not available)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":270,"character":1},"reason":"Line should be 120 characters or less; currently it has 148 characters"}},{"text":" throw OnDeviceLLMError.inferenceFailed(\"On-device AI needs the app to stay open. Please return to the app and try again.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":271,"character":1},"reason":"Line should be 120 characters or less; currently it has 142 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Inference completed at \\(String(format: \"%.1f\", metrics.inferenceTokensPerSecond)) tokens\/sec\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":275,"character":1},"reason":"Line should be 120 characters or less; currently it has 164 characters"}},{"text":" private func processChunkedText(","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":288,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 13"}},{"text":" private func processChunkedText(","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":288,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 92 lines"}},{"text":" ) async throws -> (","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":292,"character":23},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Could not use accurate tokenizer, falling back to estimation: \\(error)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":312,"character":1},"reason":"Line should be 120 characters or less; currently it has 152 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Split into \\(chunks.count) chunks with \\(overlapTokens) token overlap\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":323,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Chunk \\(index + 1) token count (\\(chunkTokenCount)) exceeds limit (\\(maxTokens)). May be truncated by OnDeviceLLM.\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":330,"character":1},"reason":"Line should be 120 characters or less; currently it has 200 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Chunk \\(index + 1): \\(chunkTokenCount) tokens (within limit)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":332,"character":1},"reason":"Line should be 120 characters or less; currently it has 146 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Chunk \\(index + 1) estimated token count (\\(chunkTokenEstimate)) exceeds limit (\\(maxTokens)). May be truncated by OnDeviceLLM.\", level: .error)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":338,"character":1},"reason":"Line should be 200 characters or less; currently it has 213 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Processing chunk \\(index + 1)\/\\(chunks.count)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":350,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Background time critical (\\(remaining)s), aborting to prevent crash\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":363,"character":1},"reason":"Line should be 120 characters or less; currently it has 153 characters"}},{"text":" throw OnDeviceLLMError.inferenceFailed(\"On-device AI needs the app to stay open. Please return to the app and try again.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":364,"character":1},"reason":"Line should be 120 characters or less; currently it has 142 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Chunk \\(index + 1) interrupted by app backgrounding\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":373,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" throw OnDeviceLLMError.inferenceFailed(\"On-device AI needs the app to stay open. Please return to the app and try again.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":374,"character":1},"reason":"Line should be 120 characters or less; currently it has 142 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Combining \\(allSummaries.count) chunk summaries into final summary\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":399,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Chunked processing completed in \\(String(format: \"%.1f\", processingTime))s\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":418,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" private func combineChunkSummaries(","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":464,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 59 lines"}},{"text":" You are consolidating summaries from different parts of a single recording into ONE unified, comprehensive Structured Outline.","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":479,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Meta-summary: \\(metaPromptTokenCount) tokens, max: \\(maxInputForMeta), target: \\(targetWords) words\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":525,"character":1},"reason":"Line should be 120 characters or less; currently it has 173 characters"}},{"text":" private func combineSummariesRecursive(","violation":{"ruleName":"Function Parameter Count","severity":"warning","ruleDescription":"Number of function parameters should be low.","ruleIdentifier":"function_parameter_count","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":547,"character":13},"reason":"Function should have 5 parameters or less: it currently has 8"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMEngine] Splitting \\(summaries.count) summaries into groups of ~\\(summariesPerGroup)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":580,"character":1},"reason":"Line should be 120 characters or less; currently it has 149 characters"}},{"text":" return SummarizationError.configurationRequired(message: \"On-Device AI model not ready. Please download a model in Settings.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":645,"character":1},"reason":"Line should be 120 characters or less; currently it has 142 characters"}},{"text":" return SummarizationError.processingFailed(reason: \"Insufficient disk space. Need \\(formatSize(required)) free.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":651,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMEngine.swift","line":666,"character":1},"reason":"File should contain 400 lines or less: currently contains 666"}},{"text":" let i = Int(self.n_tokens)","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMExtensions.swift","line":87,"character":13},"reason":"Variable name 'i' should be between 3 and 40 characters long"}},{"text":" if let seq_id = self.seq_id[i] {","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMExtensions.swift","line":91,"character":16},"reason":"Variable name 'seq_id' should only contain alphanumeric and other allowed characters"}},{"text":" for (j, id) in ids.enumerated() {","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMExtensions.swift","line":92,"character":18},"reason":"Variable name 'j' should be between 3 and 40 characters long"}},{"text":" downloadURL: \"https:\/\/huggingface.co\/unsloth\/gemma-3n-E4B-it-GGUF\/resolve\/main\/gemma-3n-E4B-it-Q4_K_M.gguf?download=true\",","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMModels.swift","line":162,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" downloadURL: \"https:\/\/huggingface.co\/unsloth\/gemma-3n-E2B-it-GGUF\/resolve\/main\/gemma-3n-E2B-it-Q4_K_M.gguf?download=true\",","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMModels.swift","line":186,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" downloadURL: \"https:\/\/huggingface.co\/unsloth\/Ministral-3-3B-Instruct-2512-GGUF\/resolve\/main\/Ministral-3-3B-Instruct-2512-Q4_K_M.gguf?download=true\",","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMModels.swift","line":212,"character":1},"reason":"Line should be 120 characters or less; currently it has 156 characters"}},{"text":" downloadURL: \"https:\/\/huggingface.co\/unsloth\/granite-4.0-h-tiny-GGUF\/resolve\/main\/granite-4.0-h-tiny-Q4_K_M.gguf?download=true\",","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMModels.swift","line":237,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" public static let qwen3_5_2B = OnDeviceLLMModelInfo(","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMModels.swift","line":258,"character":23},"reason":"Variable name 'qwen3_5_2B' should only contain alphanumeric and other allowed characters"}},{"text":" downloadURL: \"https:\/\/huggingface.co\/unsloth\/Qwen3.5-2B-GGUF\/resolve\/main\/Qwen3.5-2B-UD-Q4_K_XL.gguf?download=true\",","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMModels.swift","line":263,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" public static let qwen3_5_4B = OnDeviceLLMModelInfo(","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMModels.swift","line":289,"character":23},"reason":"Variable name 'qwen3_5_4B' should only contain alphanumeric and other allowed characters"}},{"text":" downloadURL: \"https:\/\/huggingface.co\/unsloth\/granite-4.0-micro-GGUF\/resolve\/main\/granite-4.0-micro-Q4_K_M.gguf?download=true\",","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMModels.swift","line":324,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMModelInfo] Selected model '\\(modelId)' is not available, migrating to default\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMModels.swift","line":477,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMModels.swift","line":540,"character":1},"reason":"File should contain 400 lines or less: currently contains 540"}},{"text":"public class OnDeviceLLMService: ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":50,"character":8},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 685 lines"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMService] Model loaded: \\(config.modelInfo.displayName) (backgrounded: \\(_isAppBackgrounded))\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":104,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMService] generateSummary raw output: \\(result.count) chars\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":162,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMService] Metrics: \\(metrics.inferenceTokenCount) output tokens, \\(String(format: \"%.1f\", metrics.inferenceTokensPerSecond)) tok\/s\", level: .debug)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":164,"character":1},"reason":"Line should be 200 characters or less; currently it has 203 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMService] Model generated empty or minimal response after cleanup\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":171,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" return \"Summary generation encountered an issue. The model produced an empty response. Please try again or use a different model.\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":172,"character":1},"reason":"Line should be 120 characters or less; currently it has 142 characters"}},{"text":" func processComplete(text: String) async throws -> (","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":238,"character":56},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMService] processComplete raw output: \\(result.count) chars\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":266,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMService] Metrics: \\(metrics.inferenceTokenCount) output tokens, \\(String(format: \"%.1f\", metrics.inferenceTokensPerSecond)) tok\/s\", level: .debug)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":268,"character":1},"reason":"Line should be 200 characters or less; currently it has 203 characters"}},{"text":" private func cleanupResponse(_ response: String) -> String {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":299,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 80 lines"}},{"text":" if let thinkRegex = try? NSRegularExpression(pattern: \".*?<\/think>\", options: [.dotMatchesLineSeparators, .caseInsensitive]) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":305,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" if let trailingRole = try? NSRegularExpression(pattern: #\"\\n?(assistant|user|system)\\s*$\"#, options: .caseInsensitive) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":340,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" if cleaned.lowercased().hasPrefix(phrase.lowercased()) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":371,"character":13},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" if let reasoningPattern = try? NSRegularExpression(pattern: #\"(?i)^(okay, let me try|let me try to|the user wants|i need to make sure|let me check).*?(?=\\n\\n##|## Summary|$)\"#, options: [.dotMatchesLineSeparators, .anchorsMatchLines]) {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":378,"character":1},"reason":"Line should be 200 characters or less; currently it has 244 characters"}},{"text":" cleaned = reasoningPattern.stringByReplacingMatches(in: cleaned, options: [], range: range, withTemplate: \"\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":380,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" if let thinkingPattern = try? NSRegularExpression(pattern: #\"^(Alright, |Let me |I should |I need to |Now, putting it together: |Putting it together: ).*?(?=\\n\\n##|## Summary|## Title|$)\"#, options: [.dotMatchesLineSeparators, .caseInsensitive]) {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":386,"character":1},"reason":"Line should be 200 characters or less; currently it has 255 characters"}},{"text":" Extract all actionable tasks from the following transcript. Focus only on personal, actionable items that require follow-up.","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":452,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" IMPORTANT: Return each task on a new line, starting with \"- \" followed directly by the task text. Do NOT use prefixes like [Task 1] or [Task 2].","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":454,"character":1},"reason":"Line should be 120 characters or less; currently it has 152 characters"}},{"text":" Extract all time-sensitive reminders and deadlines from the following transcript. Include dates, times, and deadlines mentioned.","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":465,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" IMPORTANT: Return each reminder on a new line, starting with \"- \" followed directly by the reminder text. Do NOT use prefixes like [Reminder 1] or [Reminder 2].","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":467,"character":1},"reason":"Line should be 120 characters or less; currently it has 168 characters"}},{"text":" Suggest 3-5 concise, descriptive titles for the following transcript. Each title should capture the main topic or theme.","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":478,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" IMPORTANT: Return each title on a new line, starting with \"- \" followed directly by the title text. Do NOT use prefixes like [Title 1] or [Title 2].","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":480,"character":1},"reason":"Line should be 120 characters or less; currently it has 156 characters"}},{"text":" private func createCompleteProcessingPrompt(text: String) -> String {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":489,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 51 lines"}},{"text":" Analyze the following transcript and extract the actual content discussed. Base your response ONLY on what is actually mentioned in the transcript.","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":496,"character":1},"reason":"Line should be 120 characters or less; currently it has 155 characters"}},{"text":" reminders.append(ReminderItem(text: cleaned, timeReference: timeRef, urgency: .later, confidence: 0.8))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":620,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" private func parseCompleteResponse(_ response: String) -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":658,"character":1},"reason":"Line should be 120 characters or less; currently it has 148 characters"}},{"text":" private func parseCompleteResponse(_ response: String) -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) {","violation":{"ruleName":"Cyclomatic Complexity","severity":"error","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":658,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 51"}},{"text":" private func parseCompleteResponse(_ response: String) -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) {","violation":{"ruleName":"Function Body Length","severity":"error","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":658,"character":13},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 245 lines"}},{"text":" private func parseCompleteResponse(_ response: String) -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":658,"character":63},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMService] Thinking content detected (\\(thinkingContent.count) chars)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":685,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMService] Content after thinking (\\(contentAfterThinking.count) chars)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":686,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMService] Model generated thinking content (\\(thinkingContent.count) chars) but no actual response after thinking block (length: \\(cleanedTest.count))\", level: .error)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":703,"character":1},"reason":"Line should be 200 characters or less; currently it has 223 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMService] This may indicate the model hit the output token limit during thinking\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":704,"character":1},"reason":"Line should be 120 characters or less; currently it has 153 characters"}},{"text":" AppLog.shared.summarization(\"[OnDeviceLLMService] Response contains only stop tokens or minimal content (length: \\(cleanedTest.count)), returning empty result\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":706,"character":1},"reason":"Line should be 120 characters or less; currently it has 191 characters"}},{"text":" sanitizedResponse = sanitizedResponse.replacingOccurrences(of: token.lowercased(), with: \"\", options: .caseInsensitive)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":722,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" sanitizedResponse = regex.stringByReplacingMatches(in: sanitizedResponse, options: [], range: range, withTemplate: \"\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":728,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" if let thinkRegex = try? NSRegularExpression(pattern: \".*?<\/think>\", options: [.dotMatchesLineSeparators, .caseInsensitive]) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":732,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" sanitizedResponse = thinkRegex.stringByReplacingMatches(in: sanitizedResponse, options: [], range: range, withTemplate: \"\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":734,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" if sanitizedResponse.lowercased().hasPrefix(phrase.lowercased()) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":758,"character":13},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" sanitizedResponse = String(sanitizedResponse.dropFirst(phrase.count)).trimmingCharacters(in: .whitespacesAndNewlines)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":759,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" if let thinkingPattern = try? NSRegularExpression(pattern: #\"(?i)^(Alright, |Let me |I should |I need to |Okay, let me try|Let me try to|The user wants|I need to make sure|Let me check).*?(?=\\n\\n|##|$)\"#, options: [.dotMatchesLineSeparators, .anchorsMatchLines]) {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":766,"character":1},"reason":"Line should be 200 characters or less; currently it has 272 characters"}},{"text":" sanitizedResponse = thinkingPattern.stringByReplacingMatches(in: sanitizedResponse, options: [], range: range, withTemplate: \"\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":768,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" (lowercased.contains(\"reminder\") && (lowercased.contains(\"##\") || lowercased.hasPrefix(\"reminder\"))) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":794,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" var text = parts.dropFirst().joined(separator: \".\").trimmingCharacters(in: .whitespacesAndNewlines)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":829,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" reminders.append(ReminderItem(text: cleaned, timeReference: timeRef, urgency: .later, confidence: 0.8))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":852,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" var text = parts.dropFirst().joined(separator: \".\").trimmingCharacters(in: .whitespacesAndNewlines)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":859,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" reminders.append(ReminderItem(text: cleaned, timeReference: timeRef, urgency: .later, confidence: 0.8))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":867,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" let cleaned = RecordingNameGenerator.cleanStandardizedTitleResponse(String(text).sanitizedForTitle())","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":878,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" var text = parts.dropFirst().joined(separator: \".\").trimmingCharacters(in: .whitespacesAndNewlines)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":890,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMService.swift","line":983,"character":1},"reason":"File should contain 400 lines or less: currently contains 983"}},{"text":"struct OnDeviceLLMSettingsView: View {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMSettingsView.swift","line":12,"character":1},"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 397 lines"}},{"text":" Text(\"Process transcripts locally on your device using a downloaded AI model. No internet connection required after model download.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMSettingsView.swift","line":42,"character":1},"reason":"Line should be 120 characters or less; currently it has 153 characters"}},{"text":" Text(\"Models available for your device (4-6GB RAM) are experimental. They generate summaries and one title only (no tasks or reminders) and may produce lower quality results.\")","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMSettingsView.swift","line":58,"character":1},"reason":"Line should be 200 characters or less; currently it has 208 characters"}},{"text":" Text(\"This will delete \\(model.displayName) (\\(model.downloadSize)) from your device. You can re-download it later.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMSettingsView.swift","line":126,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" private func modelRow(for model: OnDeviceLLMModelInfo) -> some View {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMSettingsView.swift","line":140,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 62 lines"}},{"text":" Text(\"⚠️ Requires \\(String(format: \"%.0f\", model.requiredRAM))GB RAM (Device: \\(String(format: \"%.1f\", DeviceCapabilities.totalRAMInGB))GB)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMSettingsView.swift","line":181,"character":1},"reason":"Line should be 120 characters or less; currently it has 168 characters"}},{"text":" Text(\"Automatically set based on device RAM: \\(DeviceCapabilities.onDeviceLLMContextSize == 8192 ? \"8k\" : \"16k\") for devices with \\(DeviceCapabilities.onDeviceLLMContextSize == 8192 ? \"<8GB\" : \"β‰₯8GB\") RAM\")","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMSettingsView.swift","line":381,"character":1},"reason":"Line should be 200 characters or less; currently it has 214 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMSettingsView.swift","line":505,"character":1},"reason":"File should contain 400 lines or less: currently contains 505"}},{"text":"You are an AI assistant specialized in processing audio transcripts. Analyze the ACTUAL CONTENT of the transcript and extract only what is explicitly mentioned.","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMTemplate.swift","line":300,"character":1},"reason":"Line should be 120 characters or less; currently it has 160 characters"}},{"text":"Be thorough but concise. Focus on information that is personally relevant to the speaker and actually appears in the transcript.","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OnDeviceLLM\/OnDeviceLLMTemplate.swift","line":316,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" init(model: String, messages: [ChatMessage], temperature: Double? = nil, maxCompletionTokens: Int? = nil, topP: Double? = nil, frequencyPenalty: Double? = nil, presencePenalty: Double? = nil, responseFormat: ResponseFormat? = nil, reasoningEffort: String? = nil) {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIModels.swift","line":118,"character":1},"reason":"Line should be 200 characters or less; currently it has 268 characters"}},{"text":" if isHostMatch(lowercasedHost, provider: provider) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIModels.swift","line":356,"character":13},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" if isHostMatch(lowercasedHost, provider: provider) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIModels.swift","line":364,"character":13},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" if matchesProviderDomain(lowercasedHost, provider: provider) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIModels.swift","line":431,"character":13},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" if matchesProviderDomain(lowercasedHost, provider: provider) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIModels.swift","line":438,"character":13},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: encoder.codingPath, debugDescription: \"Invalid type for AnyCodable\"))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIModels.swift","line":617,"character":1},"reason":"Line should be 120 characters or less; currently it has 155 characters"}},{"text":" throw DecodingError.typeMismatch(AnyCodable.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: \"Could not decode AnyCodable\"))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIModels.swift","line":635,"character":1},"reason":"Line should be 120 characters or less; currently it has 165 characters"}},{"text":" \"category\": [\"type\": \"string\", \"enum\": [\"call\", \"meeting\", \"purchase\", \"research\", \"email\", \"travel\", \"health\", \"general\"]],","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIModels.swift","line":658,"character":1},"reason":"Line should be 120 characters or less; currently it has 152 characters"}},{"text":"\/\/ OpenAIErrorResponse and OpenAIError are defined in OpenAITranscribeService.swift","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIModels.swift","line":726,"character":1},"reason":"File should contain 400 lines or less: currently contains 726"}},{"text":" case off = \"off\"","violation":{"ruleName":"Redundant String Enum Value","severity":"warning","ruleDescription":"String enum values can be omitted when they are equal to the enumcase name","ruleIdentifier":"redundant_string_enum_value","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","line":13,"character":16},"reason":"String enum values can be omitted when they are equal to the enumcase name"}},{"text":" case snarky = \"snarky\"","violation":{"ruleName":"Redundant String Enum Value","severity":"warning","ruleDescription":"String enum values can be omitted when they are equal to the enumcase name","ruleIdentifier":"redundant_string_enum_value","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","line":14,"character":19},"reason":"String enum values can be omitted when they are equal to the enumcase name"}},{"text":" case funny = \"funny\"","violation":{"ruleName":"Redundant String Enum Value","severity":"warning","ruleDescription":"String enum values can be omitted when they are equal to the enumcase name","ruleIdentifier":"redundant_string_enum_value","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","line":15,"character":18},"reason":"String enum values can be omitted when they are equal to the enumcase name"}},{"text":" - Be ruthlessly sarcastic β€” drip with condescension, mock bad ideas, question obvious statements, and add biting commentary after nearly every point","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","line":42,"character":1},"reason":"Line should be 120 characters or less; currently it has 160 characters"}},{"text":" - Use heavy sarcasm tags like \"oh how groundbreaking\", \"truly shocking\", \"what a revelation\", \"nobody saw that coming\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","line":43,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" - Editorialize constantly β€” if something is boring, say it's boring. If something is obvious, mock it for being obvious. If a decision is questionable, tear it apart","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","line":44,"character":1},"reason":"Line should be 120 characters or less; currently it has 177 characters"}},{"text":" - Add parenthetical asides that break the fourth wall and commiserate with the reader about having to sit through this","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","line":45,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" - Channel the energy of a comedian who was forced to attend this meeting\/conversation and is NOT happy about it","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","line":46,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" - Keep it PG and family-friendly β€” no profanity or crude humor, but absolutely DO NOT hold back on the snark, sarcasm, and roasting","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","line":47,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"text":" - Every paragraph should have at least one zinger. If you're not making the reader smirk, you're not being snarky enough","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","line":48,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":"class OpenAIPromptGenerator {","violation":{"ruleName":"Type Body Length","severity":"warning","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","line":70,"character":1},"reason":"Class body should span 250 lines or less excluding comments and whitespace: currently spans 296 lines"}},{"text":" You are an AI assistant specialized in analyzing and summarizing audio transcripts and conversations. Your role is to provide clear, actionable insights from the content provided.","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","line":86,"character":1},"reason":"Line should be 120 characters or less; currently it has 187 characters"}},{"text":" Extract personal, actionable tasks from the following content. Focus only on tasks that are personal to the speaker or require their direct action. Avoid tasks related to national news, public figures, or general world events.","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","line":274,"character":1},"reason":"Line should be 200 characters or less; currently it has 234 characters"}},{"text":" Extract personal, time-sensitive reminders from the following content. Focus only on personal appointments, deadlines, or commitments that directly affect the speaker. Avoid reminders about national news, public events, or general world happenings.","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","line":296,"character":1},"reason":"Line should be 200 characters or less; currently it has 256 characters"}},{"text":" Please analyze the following content and provide a comprehensive response in VALID JSON format only. Do not include any text before or after the JSON. The response must be a single, well-formed JSON object with this exact structure:","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","line":348,"character":1},"reason":"Line should be 200 characters or less; currently it has 240 characters"}},{"text":" \"summary\": \"A detailed summary using Markdown formatting with **bold**, *italic*, ## headers, β€’ bullet points, 1. numbered lists, > blockquotes, etc. (aim for 15-20% of the original transcript length)\",","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","line":351,"character":1},"reason":"Line should be 200 characters or less; currently it has 214 characters"}},{"text":" - Tasks must be PERSONAL and ACTIONABLE to the speaker β€” do NOT include tasks about news, public figures, or world events","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","line":381,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" - Reminders must be PERSONAL and TIME-SENSITIVE to the speaker β€” do NOT include reminders about news events or public happenings","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIPromptGenerator.swift","line":382,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":"class OpenAIResponseParser {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":12,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 358 lines"}},{"text":" static func parseCompleteResponseFromJSON(_ jsonString: String) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":16,"character":1},"reason":"Line should be 120 characters or less; currently it has 164 characters"}},{"text":" static func parseCompleteResponseFromJSON(_ jsonString: String) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":16,"character":12},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 94 lines"}},{"text":" static func parseCompleteResponseFromJSON(_ jsonString: String) throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":16,"character":79},"reason":"Tuples should have at most 2 members"}},{"text":" struct TaskResponse: Codable {","violation":{"ruleName":"Nesting","severity":"warning","ruleDescription":"Types should be nested at most 1 level deep, and functions should be nested at most 2 levels deep.","ruleIdentifier":"nesting","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":29,"character":13},"reason":"Types should be nested at most 1 level deep"}},{"text":" struct ReminderResponse: Codable {","violation":{"ruleName":"Nesting","severity":"warning","ruleDescription":"Types should be nested at most 1 level deep, and functions should be nested at most 2 levels deep.","ruleIdentifier":"nesting","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":37,"character":13},"reason":"Types should be nested at most 1 level deep"}},{"text":" struct TitleResponse: Codable {","violation":{"ruleName":"Nesting","severity":"warning","ruleDescription":"Types should be nested at most 1 level deep, and functions should be nested at most 2 levels deep.","ruleIdentifier":"nesting","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":44,"character":13},"reason":"Types should be nested at most 1 level deep"}},{"text":" category: TaskItem.TaskCategory(rawValue: taskResponse.category?.lowercased() ?? \"general\") ?? .general,","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":79,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" let urgency = ReminderItem.Urgency(rawValue: reminderResponse.urgency?.lowercased() ?? \"later\") ?? .later","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":85,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" if let aiTimeRef = reminderResponse.timeReference, !aiTimeRef.isEmpty && aiTimeRef != \"No time specified\" {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":90,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" let category = TitleItem.TitleCategory(rawValue: titleResponse.category?.lowercased() ?? \"general\") ?? .general","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":105,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" AppLog.shared.networking(\"OpenAI returned empty JSON object - check API key and model configuration\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":126,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"OpenAI returned empty JSON - check API key and model configuration\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":127,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" let category = TitleItem.TitleCategory(rawValue: titleResponse.category?.lowercased() ?? \"general\") ?? .general","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":158,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"Failed to parse titles JSON: \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":168,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" category: TaskItem.TaskCategory(rawValue: taskResponse.category?.lowercased() ?? \"general\") ?? .general,","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":194,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"Failed to parse tasks JSON: \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":199,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" let urgency = ReminderItem.Urgency(rawValue: reminderResponse.urgency?.lowercased() ?? \"later\") ?? .later","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":220,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" if let aiTimeRef = reminderResponse.timeReference, !aiTimeRef.isEmpty && aiTimeRef != \"No time specified\" {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":225,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"Failed to parse reminders JSON: \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":239,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" private static func extractJSONFromResponse(_ response: String) -> String {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":389,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 14"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAIResponseParser.swift","line":483,"character":1},"reason":"File should contain 400 lines or less: currently contains 483"}},{"text":"class OpenAISummarizationService: ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"warning","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift","line":12,"character":1},"reason":"Class body should span 250 lines or less excluding comments and whitespace: currently spans 259 lines"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift","line":136,"character":1},"reason":"Line should be 120 characters or less; currently it has 167 characters"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift","line":136,"character":56},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.networking(\"Provider: \\(config.baseURL), format: \\(cachedMessageFormat.displayName), response_format: \\(cachedShouldUseResponseFormat ? \"json_object\" : \"none\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift","line":168,"character":1},"reason":"Line should be 120 characters or less; currently it has 198 characters"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"Failed to parse models response: \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift","line":290,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" private func makeAPICall(request: OpenAIChatCompletionRequest) async throws -> OpenAIChatCompletionResponse {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift","line":331,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 56 lines"}},{"text":" AppLog.shared.networking(\"OpenAI API Configuration - Model: \\(config.effectiveModelId), BaseURL: \\(config.baseURL)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift","line":351,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"Failed to encode request: \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift","line":369,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" AppLog.shared.networking(\"OpenAI API Response - Status: \\(httpResponse.statusCode), size: \\(data.count) bytes\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift","line":381,"character":1},"reason":"Line should be 120 characters or less; currently it has 142 characters"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"OpenAI API Error: \\(errorResponse.error.message)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift","line":388,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"OpenAI API Error: HTTP \\(httpResponse.statusCode)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift","line":391,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" AppLog.shared.networking(\"OpenAI API Success - Model: \\(apiResponse.model), Tokens: \\(tokenCount), response: \\(apiResponse.choices.first?.message.content.count ?? 0) chars\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift","line":401,"character":1},"reason":"Line should be 120 characters or less; currently it has 200 characters"}},{"text":" throw SummarizationError.aiServiceUnavailable(service: \"OpenAI API request failed: \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift","line":407,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAI\/OpenAISummarizationService.swift","line":410,"character":1},"reason":"File should contain 400 lines or less: currently contains 410"}},{"text":" @AppStorage(EndpointSecurityPolicy.allowInsecurePublicEndpointsKey) private var allowInsecurePublicEndpoints: Bool = false","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISettingsView.swift","line":14,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" Button(action: { showingAPIKeyInfo = true }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISettingsView.swift","line":36,"character":74},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" Text(\"GPT-4o Mini is the cheapest and fastest option. GPT-4o Transcribe is the most robust. Whisper-1 is the legacy model.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISettingsView.swift","line":94,"character":1},"reason":"Line should be 120 characters or less; currently it has 144 characters"}},{"text":" Text(\"You can get your OpenAI API key from platform.openai.com. Go to API Keys section and create a new secret key. Make sure your account has sufficient credits for transcription usage.\")","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISettingsView.swift","line":199,"character":1},"reason":"Line should be 200 characters or less; currently it has 204 characters"}},{"text":"class OpenAISummarizationEngine: SummarizationEngine, ConnectionTestable {","violation":{"ruleName":"Type Body Length","severity":"warning","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":10,"character":1},"reason":"Class body should span 250 lines or less excluding comments and whitespace: currently spans 280 lines"}},{"text":" AppLogger.shared.verbose(\"Checking enableOpenAI setting - Value: \\(isEnabled), Key exists: \\(keyExists)\", category: \"OpenAISummarizationEngine\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":40,"character":1},"reason":"Line should be 120 characters or less; currently it has 156 characters"}},{"text":" AppLog.shared.summarization(\"OpenAISummarizationEngine: Reminder extraction failed: \\(error)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":117,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" AppLog.shared.summarization(\"OpenAISummarizationEngine: Content classification failed: \\(error)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":151,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":156,"character":1},"reason":"Line should be 120 characters or less; currently it has 167 characters"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":156,"character":56},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.summarization(\"Large transcript detected (\\(tokenCount) tokens), using chunked processing\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":172,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" AppLog.shared.summarization(\"OpenAISummarizationEngine: Complete processing failed: \\(error)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":179,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" let modelString = UserDefaults.standard.string(forKey: \"openAISummarizationModel\") ?? OpenAISummarizationModel.gpt41Mini.rawValue","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":188,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" AppLogger.shared.verbose(\"Updating configuration - Model: \\(modelString), BaseURL: \\(baseURL)\", category: \"OpenAISummarizationEngine\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":216,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" private func processChunkedText(_ text: String, service: OpenAISummarizationService) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":231,"character":1},"reason":"Line should be 200 characters or less; currently it has 217 characters"}},{"text":" private func processChunkedText(_ text: String, service: OpenAISummarizationService) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":231,"character":106},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.summarization(\"Processing chunk \\(index + 1) of \\(chunks.count) (\\(TokenManager.getTokenCount(chunk)) tokens)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":250,"character":1},"reason":"Line should be 120 characters or less; currently it has 152 characters"}},{"text":" AppLog.shared.summarization(\"Final results - summary: \\(combinedSummary.count) chars, tasks: \\(uniqueTasks.count), reminders: \\(uniqueReminders.count), titles: \\(uniqueTitles.count)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":284,"character":1},"reason":"Line should be 200 characters or less; currently it has 206 characters"}},{"text":" AppLog.shared.summarization(\"OpenAISummarizationEngine: Service is nil - configuration issue\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":358,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" return SummarizationError.aiServiceUnavailable(service: \"OpenAI API quota exceeded. Please check your billing status.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":383,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" return SummarizationError.aiServiceUnavailable(service: \"OpenAI API rate limit exceeded. Please try again later.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":385,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" return SummarizationError.aiServiceUnavailable(service: \"Invalid OpenAI API key. Please check your configuration.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":387,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" AppLogger.shared.verbose(\"Checking enableOpenAICompatible setting - Value: \\(isEnabled), Key exists: \\(keyExists)\", category: \"OpenAICompatibleEngine\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":427,"character":1},"reason":"Line should be 120 characters or less; currently it has 163 characters"}},{"text":" AppLogger.shared.verbose(\"OpenAI Compatible is not enabled in settings\", category: \"OpenAICompatibleEngine\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":433,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":527,"character":1},"reason":"Line should be 120 characters or less; currently it has 167 characters"}},{"text":" func processComplete(text: String) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":527,"character":56},"reason":"Tuples should have at most 2 members"}},{"text":" AppLogger.shared.verbose(\"Updating configuration - Model: \\(modelId), BaseURL: \\(baseURL)\", category: \"OpenAICompatibleEngine\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":583,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationEngine.swift","line":603,"character":1},"reason":"File should contain 400 lines or less: currently contains 603"}},{"text":" @AppStorage(\"openAISummarizationModel\") private var selectedModel: String = OpenAISummarizationModel.gpt41Mini.rawValue","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":12,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" @AppStorage(EndpointSecurityPolicy.allowInsecurePublicEndpointsKey) private var allowInsecurePublicEndpoints: Bool = false","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":17,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" Button(action: { showingAPIKeyInfo = true }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":82,"character":66},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":"struct OpenAICompatibleSettingsView: View {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":267,"character":1},"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 704 lines"}},{"text":" @AppStorage(EndpointSecurityPolicy.allowInsecurePublicEndpointsKey) private var allowInsecurePublicEndpoints: Bool = false","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":276,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" AppLog.shared.general(\"OpenAICompatibleSettingsView: Initialized enableOpenAICompatible to \\(isSelectedEngine)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":310,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" let modelIds = try await OpenAISummarizationService.fetchCompatibleModels(apiKey: apiKey, baseURL: baseURL)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":336,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" AppLog.shared.general(\"Models: \\(modelIds.prefix(5).joined(separator: \", \"))\\(modelIds.count > 5 ? \"...\" : \"\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":352,"character":1},"reason":"Line should be 120 characters or less; currently it has 151 characters"}},{"text":" Text(\"Get your API key from your provider:\\n\\nβ€’ OpenRouter: openrouter.ai\\nβ€’ Together AI: api.together.xyz\\nβ€’ Groq: console.groq.com\\nβ€’ Replicate: replicate.com\\nβ€’ Fireworks AI: fireworks.ai\\nβ€’ Local services (LiteLLM, vLLM, LocalAI): May not require a real key, use any value like 'local'\")","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":451,"character":1},"reason":"Line should be 200 characters or less; currently it has 307 characters"}},{"text":" Text(\"This engine is currently active and will be used for AI processing. It has been automatically enabled.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":499,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" Text(\"This engine supports many providers through LiteLLM, OpenRouter, and similar services. JSON output quality varies by model. Larger, more recent models generally perform better.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":601,"character":1},"reason":"Line should be 120 characters or less; currently it has 196 characters"}},{"text":" Button(action: { showingAPIKeyInfo = true }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":611,"character":66},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" Text(\"Your API key is stored securely on your device and only used for AI summarization. Some providers (like LocalAI or local LiteLLM) may not require an API key - in that case, you can use any placeholder value.\")","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":643,"character":1},"reason":"Line should be 200 characters or less; currently it has 227 characters"}},{"text":" Text(\"Enter the base URL for your OpenAI-compatible API. Examples:\\nβ€’ LiteLLM: http:\/\/localhost:4000\\nβ€’ vLLM: http:\/\/localhost:8000\/v1\\nβ€’ LocalAI: http:\/\/localhost:8080\/v1\\nβ€’ OpenRouter: https:\/\/openrouter.ai\/api\/v1\\nβ€’ Together AI: https:\/\/api.together.xyz\/v1\")","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":680,"character":1},"reason":"Line should be 200 characters or less; currently it has 273 characters"}},{"text":" Text(\"Enable to discover models from your API endpoint automatically. If your provider supports the \/models endpoint (like LiteLLM, vLLM, LocalAI), it will list all available models.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":702,"character":1},"reason":"Line should be 120 characters or less; currently it has 200 characters"}},{"text":" Text(\"Enter the model ID manually. Common examples: gpt-4o, claude-sonnet-4-5-20250929, llama-4-maverick, gemini-2.5-flash, deepseek-chat, etc.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":704,"character":1},"reason":"Line should be 120 characters or less; currently it has 161 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":730,"character":36},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" Text(\"Fine-tune the AI's behavior. Lower temperature for consistent results, higher for more creative summaries.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":812,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" Text(\"Block-based format: {\\\"content\\\": [{\\\"type\\\": \\\"text\\\", \\\"text\\\": \\\"...\\\"}]}\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":917,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" Text(\"Format is automatically detected from your base URL. Enable override only if auto-detection fails.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":941,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" Text(\"Test your API connection. A successful test means the provider is reachable, but individual model performance may vary. If your model produces poor results, try a different model or adjust generation parameters.\")","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":953,"character":1},"reason":"Line should be 200 characters or less; currently it has 231 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"error","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAISummarizationSettingsView.swift","line":1076,"character":1},"reason":"File should contain 1000 lines or less: currently contains 1076"}},{"text":" func transcribeAudioFile(at url: URL, recordingId: UUID? = nil) async throws -> OpenAITranscribeResult {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":200,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 84 lines"}},{"text":" let result = try await performTranscription(audioData: audioData, fileName: audioChunk.chunkURL.lastPathComponent)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":231,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" recordingId: recordingId ?? UUID() \/\/ TODO: Get actual recording ID from Core Data","violation":{"ruleName":"Todo","severity":"warning","ruleDescription":"TODOs and FIXMEs should be resolved.","ruleIdentifier":"todo","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":254,"character":59},"reason":"TODOs should be resolved (Get actual recording ID from C...)"}},{"text":" private func performTranscription(audioData: Data, fileName: String) async throws -> OpenAITranscribeResult {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":308,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 75 lines"}},{"text":" body.append(\"--\\(boundary)\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":327,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"Content-Disposition: form-data; name=\\\"file\\\"; filename=\\\"\\(fileName)\\\"\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":328,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"Content-Type: \\(getContentType(for: fileName))\\r\\n\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":329,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":331,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"--\\(boundary)\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":334,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"Content-Disposition: form-data; name=\\\"model\\\"\\r\\n\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":335,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":337,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"--\\(boundary)\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":340,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"Content-Disposition: form-data; name=\\\"response_format\\\"\\r\\n\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":341,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"json\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":342,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":343,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"--\\(boundary)\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":349,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"Content-Disposition: form-data; name=\\\"temperature\\\"\\r\\n\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":350,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"0\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":351,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":352,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"--\\(boundary)--\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":355,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" AppLog.shared.transcription(\"Using model: \\(config.model.displayName), request size: \\(body.count) bytes\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":359,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" AppLog.shared.transcription(\"OpenAI API error: HTTP \\(httpResponse.statusCode), response size: \\(data.count) bytes\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":373,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"text":" AppLog.shared.transcription(\"Transcript length: \\(transcribeResponse.text.count) chars, processing time: \\(String(format: \"%.1f\", processingTime))s\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":399,"character":1},"reason":"Line should be 120 characters or less; currently it has 157 characters"}},{"text":" AppLog.shared.transcription(\"Token usage - Input: \\(usage.inputTokens ?? 0), Output: \\(usage.outputTokens ?? 0), Total: \\(usage.totalTokens ?? 0)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":402,"character":1},"reason":"Line should be 120 characters or less; currently it has 174 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/OpenAITranscribeService.swift","line":474,"character":1},"reason":"File should contain 400 lines or less: currently contains 474"}},{"text":"class PerformanceOptimizer: ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","line":87,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 540 lines"}},{"text":" private let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? \"com.bisonnotes.app\", category: \"Performance\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","line":101,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" func processLargeTranscriptWithStreaming(_ text: String, using engine: SummarizationEngine) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","line":387,"character":1},"reason":"Line should be 200 characters or less; currently it has 224 characters"}},{"text":" func processLargeTranscriptWithStreaming(_ text: String, using engine: SummarizationEngine) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","line":387,"character":113},"reason":"Tuples should have at most 2 members"}},{"text":" let result = (summary: finalSummary, tasks: finalTasks, reminders: finalReminders, titles: finalTitles, contentType: finalContentType)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","line":461,"character":1},"reason":"Line should be 120 characters or less; currently it has 142 characters"}},{"text":" func processLargeTranscript(_ text: String, using engine: SummarizationEngine) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","line":522,"character":1},"reason":"Line should be 200 characters or less; currently it has 211 characters"}},{"text":" func processLargeTranscript(_ text: String, using engine: SummarizationEngine) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","line":522,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 59 lines"}},{"text":" func processLargeTranscript(_ text: String, using engine: SummarizationEngine) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","line":522,"character":100},"reason":"Tuples should have at most 2 members"}},{"text":" let result = (summary: finalSummary, tasks: finalTasks, reminders: finalReminders, titles: finalTitles, contentType: finalContentType)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","line":607,"character":1},"reason":"Line should be 120 characters or less; currently it has 142 characters"}},{"text":" private func processChunkWithRetry(_ chunk: String, using engine: SummarizationEngine, retryCount: Int) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","line":646,"character":1},"reason":"Line should be 200 characters or less; currently it has 236 characters"}},{"text":" private func processChunkWithRetry(_ chunk: String, using engine: SummarizationEngine, retryCount: Int) async throws -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","line":646,"character":125},"reason":"Tuples should have at most 2 members"}},{"text":" private func getCachedResult(key: String) -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)? {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","line":770,"character":1},"reason":"Line should be 120 characters or less; currently it has 162 characters"}},{"text":" private func getCachedResult(key: String) -> (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)? {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","line":770,"character":50},"reason":"Tuples should have at most 2 members"}},{"text":" private func cacheResult(key: String, result: (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType), cost: Int) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","line":774,"character":1},"reason":"Line should be 120 characters or less; currently it has 174 characters"}},{"text":" private func cacheResult(key: String, result: (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType), cost: Int) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","line":774,"character":51},"reason":"Tuples should have at most 2 members"}},{"text":" init(averageProcessingTime: TimeInterval = 0.0, wordsPerSecond: Double = 0.0, cacheHitRate: Double = 0.0, memoryEfficiency: Double = 1.0) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","line":916,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"text":" let result: (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","line":941,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" let result: (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","line":941,"character":17},"reason":"Tuples should have at most 2 members"}},{"text":" init(result: (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType), timestamp: Date) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","line":944,"character":1},"reason":"Line should be 120 characters or less; currently it has 147 characters"}},{"text":" init(result: (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType), timestamp: Date) {","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","line":944,"character":18},"reason":"Tuples should have at most 2 members"}},{"text":"}","violation":{"ruleName":"File Length","severity":"error","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/PerformanceOptimizer.swift","line":1130,"character":1},"reason":"File should contain 1000 lines or less: currently contains 1130"}},{"text":" \"Loaded temporary in-memory Core Data fallback after persistent store failure. Existing recordings may be unavailable until the app restarts successfully.\",","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Persistence.swift","line":83,"character":1},"reason":"Line should be 120 characters or less; currently it has 172 characters"}},{"text":" \"Failed to load in-memory Core Data fallback after persistent store failure: \\(error.localizedDescription)\",","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Persistence.swift","line":88,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" typealias ID = UIBackgroundTaskIdentifier","violation":{"ruleName":"Type Name","severity":"warning","ruleDescription":"Type name should only contain alphanumeric characters, start with an uppercase character and span between 3 and 40 characters in length.\nPrivate types may start with an underscore.","ruleIdentifier":"type_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Platform\/PlatformApp.swift","line":266,"character":15},"reason":"Type name 'ID' should be between 3 and 40 characters long"}},{"text":" struct ID: Equatable {","violation":{"ruleName":"Type Name","severity":"warning","ruleDescription":"Type name should only contain alphanumeric characters, start with an uppercase character and span between 3 and 40 characters in length.\nPrivate types may start with an underscore.","ruleIdentifier":"type_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Platform\/PlatformApp.swift","line":283,"character":12},"reason":"Type name 'ID' should be between 3 and 40 characters long"}},{"text":" case `default`, URL, numberPad, decimalPad, emailAddress, asciiCapable, numbersAndPunctuation","violation":{"ruleName":"Superfluous Disable Command","severity":"warning","ruleDescription":"SwiftLint 'disable' commands are superfluous when the disabled rule would not have triggered a violation in the disabled region. Use \" - \" if you wish to document a command.","ruleIdentifier":"superfluous_disable_command","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Platform\/PlatformViewShims.swift","line":50},"reason":"SwiftLint rule 'identifier_name' did not trigger a violation in the disabled region; remove the disable command"}},{"text":"class ReminderExtractor {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":13,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 486 lines"}},{"text":" if lowercased.contains(pattern) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":106,"character":13},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" let confidence = calculateExplicitReminderConfidence(sentence: sentence, pattern: pattern, baseConfidence: confidenceBoost)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":110,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" if lowercased.contains(pattern) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":148,"character":13},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" let urgency = determineUrgencyFromTimeReference(timeReference, sentence: sentence, hint: urgencyHint)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":154,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" let confidence = calculateTimeBasedReminderConfidence(sentence: sentence, pattern: pattern, timeReference: timeReference)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":155,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" if lowercased.contains(pattern) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":198,"character":13},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" let confidence = calculateEventReminderConfidence(sentence: sentence, pattern: pattern, timeReference: timeReference)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":205,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" if lowercased.contains(pattern) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":237,"character":13},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" private func parseRelativeTimeReference(_ sentence: String) -> (original: String, date: Date?, relative: String)? {","violation":{"ruleName":"Large Tuple","severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":316,"character":68},"reason":"Tuples should have at most 2 members"}},{"text":" let relativePatterns: [(pattern: String, dateCalculation: (Date, Calendar) -> Date?, relative: String)] = [","violation":{"ruleName":"Large Tuple","severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":321,"character":32},"reason":"Tuples should have at most 2 members"}},{"text":" if lowercased.contains(pattern) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":335,"character":13},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" private func parseDayOfWeekReference(_ sentence: String) -> (original: String, date: Date?, relative: String)? {","violation":{"ruleName":"Large Tuple","severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":344,"character":65},"reason":"Tuples should have at most 2 members"}},{"text":" if lowercased.contains(dayName) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":355,"character":13},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" if let nextDate = calendar.nextDate(after: now, matching: DateComponents(weekday: weekday), matchingPolicy: .nextTime) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":356,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" if lowercased.contains(pattern) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":378,"character":13},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" if let match = regex?.firstMatch(in: sentence, options: [], range: NSRange(location: 0, length: sentence.count)) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":393,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" if lowercased.contains(pattern) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":411,"character":13},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" private func determineUrgencyFromTimeReference(_ timeReference: ReminderItem.TimeReference, sentence: String, hint: ReminderItem.Urgency? = nil) -> ReminderItem.Urgency {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":444,"character":1},"reason":"Line should be 120 characters or less; currently it has 174 characters"}},{"text":" if lowercased.contains(\"urgent\") || lowercased.contains(\"asap\") || lowercased.contains(\"immediately\") || lowercased.contains(\"right now\") {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":448,"character":1},"reason":"Line should be 120 characters or less; currently it has 147 characters"}},{"text":" if cleaned.lowercased().hasPrefix(prefix) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":502,"character":13},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" private func calculateExplicitReminderConfidence(sentence: String, pattern: String, baseConfidence: Double) -> Double {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":546,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" private func calculateTimeBasedReminderConfidence(sentence: String, pattern: String, timeReference: ReminderItem.TimeReference) -> Double {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":562,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"text":" private func calculateEventReminderConfidence(sentence: String, pattern: String, timeReference: ReminderItem.TimeReference) -> Double {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ReminderExtractor.swift","line":579,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" for i in 0.. [Float] {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/AudioCleanupService.swift","line":287,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" private func applyNoiseReduction(samples: [Float], noiseProfile: NoiseProfile, strength: Float, sampleRate: Float) -> [Float] {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/AudioCleanupService.swift","line":287,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 69 lines"}},{"text":" let paddedInput = [Float](repeating: 0, count: fftSize \/ 2) + samples + [Float](repeating: 0, count: fftSize \/ 2)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/AudioCleanupService.swift","line":305,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" segmentPtr.baseAddress!.withMemoryRebound(to: DSPComplex.self, capacity: fftSize \/ 2) { complexPtr in","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/AudioCleanupService.swift","line":322,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" for i in 0..<(fftSize \/ 2) {","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/AudioCleanupService.swift","line":334,"character":17},"reason":"Variable name 'i' should be between 3 and 40 characters long"}},{"text":" for i in 0.. CGFloat {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":218,"character":1},"reason":"Line should be 120 characters or less; currently it has 156 characters"}},{"text":" private func drawTitle(_ title: String, at y: CGFloat, contentWidth: CGFloat, margins: UIEdgeInsets, context: UIGraphicsPDFRendererContext) -> CGFloat {","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":218,"character":48},"reason":"Variable name 'y' should be between 3 and 40 characters long"}},{"text":" private func drawHeaderWithMap(","violation":{"ruleName":"Function Body Length","severity":"error","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":236,"character":13},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 122 lines"}},{"text":" private func drawHeaderWithMap(","violation":{"ruleName":"Function Parameter Count","severity":"warning","ruleDescription":"Number of function parameters should be low.","ruleIdentifier":"function_parameter_count","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":236,"character":13},"reason":"Function should have 5 parameters or less: it currently has 8"}},{"text":" at y: CGFloat,","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":241,"character":12},"reason":"Variable name 'y' should be between 3 and 40 characters long"}},{"text":" private func drawSummarySection(","violation":{"ruleName":"Function Parameter Count","severity":"error","ruleDescription":"Number of function parameters should be low.","ruleIdentifier":"function_parameter_count","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":385,"character":13},"reason":"Function should have 5 parameters or less: it currently has 9"}},{"text":" at y: CGFloat,","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":387,"character":12},"reason":"Variable name 'y' should be between 3 and 40 characters long"}},{"text":" currentY = drawSectionTitle(\"Summary\", at: currentY, contentWidth: contentWidth, margins: margins, context: context)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":410,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" private func drawAttributedSummary(","violation":{"ruleName":"Function Parameter Count","severity":"error","ruleDescription":"Number of function parameters should be low.","ruleIdentifier":"function_parameter_count","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":432,"character":13},"reason":"Function should have 5 parameters or less: it currently has 9"}},{"text":" at y: CGFloat,","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":434,"character":12},"reason":"Variable name 'y' should be between 3 and 40 characters long"}},{"text":" private func drawTasksSection(","violation":{"ruleName":"Function Parameter Count","severity":"error","ruleDescription":"Number of function parameters should be low.","ruleIdentifier":"function_parameter_count","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":482,"character":13},"reason":"Function should have 5 parameters or less: it currently has 9"}},{"text":" at y: CGFloat,","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":484,"character":12},"reason":"Variable name 'y' should be between 3 and 40 characters long"}},{"text":" currentY = drawSectionTitle(\"Tasks (\\(tasks.count))\", at: currentY, contentWidth: contentWidth, margins: margins, context: context)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":505,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" private func drawUserNotesSection(","violation":{"ruleName":"Function Parameter Count","severity":"error","ruleDescription":"Number of function parameters should be low.","ruleIdentifier":"function_parameter_count","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":536,"character":13},"reason":"Function should have 5 parameters or less: it currently has 9"}},{"text":" at y: CGFloat,","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":538,"character":12},"reason":"Variable name 'y' should be between 3 and 40 characters long"}},{"text":" currentY = drawSectionTitle(\"User Notes\", at: currentY, contentWidth: contentWidth, margins: margins, context: context)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":560,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" private func drawRemindersSection(","violation":{"ruleName":"Function Parameter Count","severity":"error","ruleDescription":"Number of function parameters should be low.","ruleIdentifier":"function_parameter_count","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":583,"character":13},"reason":"Function should have 5 parameters or less: it currently has 9"}},{"text":" at y: CGFloat,","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":585,"character":12},"reason":"Variable name 'y' should be between 3 and 40 characters long"}},{"text":" currentY = drawSectionTitle(\"Reminders (\\(reminders.count))\", at: currentY, contentWidth: contentWidth, margins: margins, context: context)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":606,"character":1},"reason":"Line should be 120 characters or less; currently it has 147 characters"}},{"text":" private func buildHeaderMapImages(summaryData: EnhancedSummaryData, locationData: LocationData?) async -> HeaderMapImages? {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":642,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" private func createZoomedOutMapImage(","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":665,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 54 lines"}},{"text":" AppLog.shared.fileManagement(\"PDFExportService: Regional map generation failed: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":727,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" private func drawMetadataCompactRow(","violation":{"ruleName":"Function Parameter Count","severity":"warning","ruleDescription":"Number of function parameters should be low.","ruleIdentifier":"function_parameter_count","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":745,"character":13},"reason":"Function should have 5 parameters or less: it currently has 7"}},{"text":" x: CGFloat,","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":748,"character":9},"reason":"Variable name 'x' should be between 3 and 40 characters long"}},{"text":" y: inout CGFloat,","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":749,"character":9},"reason":"Variable name 'y' should be between 3 and 40 characters long"}},{"text":" private func drawSectionTitle(_ title: String, at y: CGFloat, contentWidth: CGFloat, margins: UIEdgeInsets, context: UIGraphicsPDFRendererContext) -> CGFloat {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":833,"character":1},"reason":"Line should be 120 characters or less; currently it has 163 characters"}},{"text":" private func drawSectionTitle(_ title: String, at y: CGFloat, contentWidth: CGFloat, margins: UIEdgeInsets, context: UIGraphicsPDFRendererContext) -> CGFloat {","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":833,"character":55},"reason":"Variable name 'y' should be between 3 and 40 characters long"}},{"text":" private func drawBulletPoint(_ text: String, at y: CGFloat, contentWidth: CGFloat, margins: UIEdgeInsets, context: UIGraphicsPDFRendererContext, color: UIColor = UIColor.black) -> CGFloat {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":847,"character":1},"reason":"Line should be 120 characters or less; currently it has 193 characters"}},{"text":" private func drawBulletPoint(_ text: String, at y: CGFloat, contentWidth: CGFloat, margins: UIEdgeInsets, context: UIGraphicsPDFRendererContext, color: UIColor = UIColor.black) -> CGFloat {","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":847,"character":53},"reason":"Variable name 'y' should be between 3 and 40 characters long"}},{"text":" private func checkAndStartNewPageWithBranding(","violation":{"ruleName":"Function Parameter Count","severity":"warning","ruleDescription":"Number of function parameters should be low.","ruleIdentifier":"function_parameter_count","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":860,"character":13},"reason":"Function should have 5 parameters or less: it currently has 8"}},{"text":" private func drawLine(from start: CGPoint, to end: CGPoint, context: UIGraphicsPDFRendererContext, color: UIColor = UIColor.lightGray, width: CGFloat = 1.0) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":880,"character":1},"reason":"Line should be 120 characters or less; currently it has 162 characters"}},{"text":" private func createSmallFallbackMapImage(for locationData: LocationData, size: CGSize) -> UIImage? {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":888,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 61 lines"}},{"text":" let gradient = CGGradient(colorsSpace: CGColorSpaceCreateDeviceRGB(), colors: colors as CFArray, locations: [0.0, 1.0])!","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":898,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" context.drawLinearGradient(gradient, start: CGPoint(x: 0, y: 0), end: CGPoint(x: size.width, y: size.height), options: [])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":899,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" context.setShadow(offset: CGSize(width: 1, height: 1), blur: 2, color: UIColor.black.withAlphaComponent(0.3).cgColor)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":913,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" let coordText = \"\\(String(format: \"%.4f\", locationData.latitude)), \\(String(format: \"%.4f\", locationData.longitude))\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":933,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" let titleSize = titleText.boundingRect(with: size, options: [.usesLineFragmentOrigin], attributes: titleAttributes, context: nil)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":942,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" let coordSize = coordText.boundingRect(with: size, options: [.usesLineFragmentOrigin], attributes: coordAttributes, context: nil)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":957,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":"#endif","violation":{"ruleName":"File Length","severity":"error","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/PDFExportService.swift","line":1006,"character":1},"reason":"File should contain 1000 lines or less: currently contains 1006"}},{"text":"final class RTFExportService {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RTFExportService.swift","line":26,"character":7},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 427 lines"}},{"text":" func generateDocument(","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RTFExportService.swift","line":32,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 57 lines"}},{"text":" AppLog.shared.fileManagement(\"RTFExportService: Invalid summary data - recording name is empty\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RTFExportService.swift","line":41,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" AppLog.shared.fileManagement(\"RTFExportService: Document too large, estimated memory usage: \\(estimatedMemoryUsage) bytes\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RTFExportService.swift","line":92,"character":1},"reason":"Line should be 120 characters or less; currently it has 154 characters"}},{"text":" AppLog.shared.fileManagement(\"RTFExportService: Converting attributed string to RTF document data\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RTFExportService.swift","line":100,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" let data = try document.data(from: NSRange(location: 0, length: documentLength), documentAttributes: documentAttributes)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RTFExportService.swift","line":101,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" AppLog.shared.fileManagement(\"RTFExportService: Document generation failed: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RTFExportService.swift","line":114,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" private func appendMetadata(for summaryData: EnhancedSummaryData, to document: NSMutableAttributedString) {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RTFExportService.swift","line":137,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 64 lines"}},{"text":" (\"Generated: \", DateFormatter.localizedString(from: summaryData.generatedAt, dateStyle: .medium, timeStyle: .short))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RTFExportService.swift","line":193,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" private func appendLocationSection(","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RTFExportService.swift","line":223,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 66 lines"}},{"text":" string: \"\\(String(format: \"%.5f\", locationData.latitude)), \\(String(format: \"%.5f\", locationData.longitude))\\n\",","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RTFExportService.swift","line":274,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" private func appendBulletedList(_ lines: [String], to document: NSMutableAttributedString, includeBullet: Bool = true) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RTFExportService.swift","line":532,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":"#endif","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RTFExportService.swift","line":604,"character":1},"reason":"File should contain 400 lines or less: currently contains 604"}},{"text":" private let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? \"com.bisonnotes.app\", category: \"RecordingCombiner\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RecordingCombiner.swift","line":14,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" guard let exportSession = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetAppleM4A) else {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/RecordingCombiner.swift","line":65,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" private static let jsonPrefixRegex = try! NSRegularExpression(pattern: \"^\\\"summary\\\"\\\\s*:\\\\s*\\\"\", options: [])","violation":{"ruleName":"Force Try","severity":"error","ruleDescription":"Force tries should be avoided","ruleIdentifier":"force_try","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":10,"character":42},"reason":"Force tries should be avoided"}},{"text":" private static let jsonContentRegex = try! NSRegularExpression(pattern: \"^\\\"content\\\"\\\\s*:\\\\s*\\\"\", options: [])","violation":{"ruleName":"Force Try","severity":"error","ruleDescription":"Force tries should be avoided","ruleIdentifier":"force_try","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":11,"character":43},"reason":"Force tries should be avoided"}},{"text":" private static let jsonTextRegex = try! NSRegularExpression(pattern: \"^\\\"text\\\"\\\\s*:\\\\s*\\\"\", options: [])","violation":{"ruleName":"Force Try","severity":"error","ruleDescription":"Force tries should be avoided","ruleIdentifier":"force_try","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":12,"character":40},"reason":"Force tries should be avoided"}},{"text":" private static let jsonSuffixRegex = try! NSRegularExpression(pattern: \"\\\"\\\\s*$\", options: [])","violation":{"ruleName":"Force Try","severity":"error","ruleDescription":"Force tries should be avoided","ruleIdentifier":"force_try","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":13,"character":42},"reason":"Force tries should be avoided"}},{"text":" private static let multipleNewlinesRegex = try! NSRegularExpression(pattern: \"\\n{3,}\", options: [])","violation":{"ruleName":"Force Try","severity":"error","ruleDescription":"Force tries should be avoided","ruleIdentifier":"force_try","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":14,"character":48},"reason":"Force tries should be avoided"}},{"text":" private static let headerRegex = try! NSRegularExpression(pattern: \"^#{1,6}\\\\s+\", options: [])","violation":{"ruleName":"Force Try","severity":"error","ruleDescription":"Force tries should be avoided","ruleIdentifier":"force_try","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":15,"character":38},"reason":"Force tries should be avoided"}},{"text":" private static let bulletRegex = try! NSRegularExpression(pattern: \"^[-*+]\\\\s+\", options: [])","violation":{"ruleName":"Force Try","severity":"error","ruleDescription":"Force tries should be avoided","ruleIdentifier":"force_try","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":16,"character":38},"reason":"Force tries should be avoided"}},{"text":" private static let orderedListRegex = try! NSRegularExpression(pattern: \"^\\\\d+\\\\.\\\\s+\", options: [])","violation":{"ruleName":"Force Try","severity":"error","ruleDescription":"Force tries should be avoided","ruleIdentifier":"force_try","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":17,"character":43},"reason":"Force tries should be avoided"}},{"text":" private static let orderedListSpaceRegex = try! NSRegularExpression(pattern: \"\\\\s+\", options: [])","violation":{"ruleName":"Force Try","severity":"error","ruleDescription":"Force tries should be avoided","ruleIdentifier":"force_try","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":18,"character":48},"reason":"Force tries should be avoided"}},{"text":" private static let markdownLinkRegex = try! NSRegularExpression(pattern: #\"\\[([^\\]]+)\\]\\(([^)]+)\\)\"#, options: [])","violation":{"ruleName":"Force Try","severity":"error","ruleDescription":"Force tries should be avoided","ruleIdentifier":"force_try","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":19,"character":44},"reason":"Force tries should be avoided"}},{"text":" cleaned = jsonContentRegex.stringByReplacingMatches(in: cleaned, options: [], range: NSRange(location: 0, length: cleaned.utf16.count), withTemplate: \"\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":30,"character":1},"reason":"Line should be 120 characters or less; currently it has 161 characters"}},{"text":" cleaned = jsonTextRegex.stringByReplacingMatches(in: cleaned, options: [], range: NSRange(location: 0, length: cleaned.utf16.count), withTemplate: \"\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":31,"character":1},"reason":"Line should be 120 characters or less; currently it has 158 characters"}},{"text":" cleaned = jsonSuffixRegex.stringByReplacingMatches(in: cleaned, options: [], range: NSRange(location: 0, length: cleaned.utf16.count), withTemplate: \"\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":32,"character":1},"reason":"Line should be 120 characters or less; currently it has 160 characters"}},{"text":" cleaned = multipleNewlinesRegex.stringByReplacingMatches(in: cleaned, options: [], range: NSRange(location: 0, length: cleaned.utf16.count), withTemplate: \"\\n\\n\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":35,"character":1},"reason":"Line should be 120 characters or less; currently it has 170 characters"}},{"text":" static func flattenMarkdown(_ text: String) -> String {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":40,"character":12},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 56 lines"}},{"text":" let headerMatches = headerRegex.matches(in: line, options: [], range: NSRange(location: 0, length: line.utf16.count))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":60,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" let bulletMatches = bulletRegex.matches(in: line, options: [], range: NSRange(location: 0, length: line.utf16.count))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":78,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" let orderedMatches = orderedListRegex.matches(in: line, options: [], range: NSRange(location: 0, length: line.utf16.count))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":85,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" let normalizedPrefix = orderedListSpaceRegex.stringByReplacingMatches(in: prefix, options: [], range: NSRange(location: 0, length: prefix.utf16.count), withTemplate: \" \")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":89,"character":1},"reason":"Line should be 120 characters or less; currently it has 186 characters"}},{"text":" let matches = markdownLinkRegex.matches(in: line, options: [], range: NSRange(location: 0, length: line.utf16.count))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":117,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" static func attributedSummary(","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":146,"character":12},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 66 lines"}},{"text":" for (_, rawLine) in lines.enumerated() {","violation":{"ruleName":"Unused Enumerated","severity":"warning","ruleDescription":"When the index or the item is not used, `.enumerated()` can be removed.","ruleIdentifier":"unused_enumerated","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":163,"character":14},"reason":"When the index is not used, `.enumerated()` can be removed"}},{"text":" result.append(NSAttributedString(string: \"\\n\", attributes: [.font: baseFont, .foregroundColor: textColor]))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":167,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" let headerMatches = headerRegex.matches(in: trimmed, options: [], range: NSRange(location: 0, length: trimmed.utf16.count))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":176,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" let headerText = (trimmed as NSString).substring(from: headerMatch.range.length).trimmingCharacters(in: .whitespaces)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":180,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" let bulletMatches = bulletRegex.matches(in: line, options: [], range: NSRange(location: 0, length: line.utf16.count))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":200,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" let orderedMatches = orderedListRegex.matches(in: line, options: [], range: NSRange(location: 0, length: line.utf16.count))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":207,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" let normalized = orderedListSpaceRegex.stringByReplacingMatches(in: prefix, options: [], range: NSRange(location: 0, length: prefix.utf16.count), withTemplate: \" \")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":210,"character":1},"reason":"Line should be 120 characters or less; currently it has 180 characters"}},{"text":" private static func parseInlineStyles(","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":235,"character":20},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 55 lines"}},{"text":" private static func parseInlineStyles(","violation":{"ruleName":"Function Parameter Count","severity":"warning","ruleDescription":"Number of function parameters should be low.","ruleIdentifier":"function_parameter_count","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":235,"character":20},"reason":"Function should have 5 parameters or less: it currently has 6"}},{"text":" var i = line.startIndex","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Services\/SummaryExportFormatter.swift","line":244,"character":13},"reason":"Variable name 'i' should be between 3 and 40 characters long"}},{"text":" let s = String(line[runStart.. some View {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":421,"character":1},"reason":"Line should be 120 characters or less; currently it has 153 characters"}},{"text":" private func recordingsListView(_ filtered: [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)]) -> some View {","violation":{"ruleName":"Large Tuple","severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":421,"character":50},"reason":"Tuples should have at most 2 members"}},{"text":" private func summariesSectionedScroll(_ filtered: [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)]) -> some View {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":466,"character":1},"reason":"Line should be 120 characters or less; currently it has 159 characters"}},{"text":" private func summariesSectionedScroll(_ filtered: [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)]) -> some View {","violation":{"ruleName":"Large Tuple","severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":466,"character":56},"reason":"Tuples should have at most 2 members"}},{"text":" recordingRowView((recording: itemWithDate.recording, transcript: itemWithDate.transcript, summary: itemWithDate.summary))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":501,"character":1},"reason":"Line should be 120 characters or less; currently it has 149 characters"}},{"text":" recordingRowView((recording: itemWithDate.recording, transcript: itemWithDate.transcript, summary: itemWithDate.summary))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":560,"character":1},"reason":"Line should be 120 characters or less; currently it has 153 characters"}},{"text":" Button(action: { showDateFilter = true }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":576,"character":59},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" Image(systemName: isDateFilterActive ? \"line.3.horizontal.decrease.circle.fill\" : \"line.3.horizontal.decrease.circle\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":577,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" private func recordingRowView(_ recordingData: (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)) -> some View {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":607,"character":1},"reason":"Line should be 120 characters or less; currently it has 154 characters"}},{"text":" private func recordingRowView(_ recordingData: (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)) -> some View {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":607,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 60 lines"}},{"text":" private func recordingRowView(_ recordingData: (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)) -> some View {","violation":{"ruleName":"Large Tuple","severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":607,"character":52},"reason":"Tuples should have at most 2 members"}},{"text":" private func summaryActionView(recording: RecordingEntry, summary: EnhancedSummaryData?) -> some View {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":720,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 56 lines"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":731,"character":16},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" } else if recording.summaryStatus == ProcessingStatus.processing.rawValue || (isGeneratingSummary && generatingSummaryRecordingId == recording.id) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":742,"character":1},"reason":"Line should be 120 characters or less; currently it has 156 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":762,"character":16},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" private var filteredRecordings: [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)] {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":924,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" private var filteredRecordings: [(recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)] {","violation":{"ruleName":"Large Tuple","severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":924,"character":38},"reason":"Tuples should have at most 2 members"}},{"text":" let endOfDay = Calendar.current.date(bySettingHour: 23, minute: 59, second: 59, of: dateFilterEnd) ?? dateFilterEnd","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":930,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" private func matchesSearch(_ recordingData: (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?), searchTerms: String) -> Bool {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":950,"character":1},"reason":"Line should be 120 characters or less; currently it has 167 characters"}},{"text":" private func matchesSearch(_ recordingData: (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?), searchTerms: String) -> Bool {","violation":{"ruleName":"Large Tuple","severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":950,"character":49},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.summarization(\"Schema-safe fetch failed, trying standard fetch: \\(error)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":998,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"error","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummariesView.swift","line":1073,"character":1},"reason":"File should contain 1000 lines or less: currently contains 1073"}},{"text":"struct SummaryDetailView: View {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":32,"character":1},"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 1504 lines"}},{"text":" AppLog.shared.summarization(\"SummaryDetailView opened: summary=\\(summaryData.summary.count) chars, tasks=\\(summaryData.tasks.count), reminders=\\(summaryData.reminders.count), titles=\\(summaryData.titles.count)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":174,"character":1},"reason":"Line should be 200 characters or less; currently it has 238 characters"}},{"text":" AppLog.shared.summarization(\"SummaryDetailView: hasLocationData=\\(recording.locationData != nil)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":179,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" Text(\"Are you sure you want to delete this summary? Any notes and attached files will also be deleted. This action cannot be undone. The audio file and transcript will remain unchanged.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":227,"character":1},"reason":"Line should be 120 characters or less; currently it has 199 characters"}},{"text":" activityItems: [ExportActivityItem(data: exportData, fileName: fileName, iconSystemName: exportIconSystemName)],","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":248,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" .confirmationDialog(\"Choose Export Format\", isPresented: $showingExportFormatPicker, titleVisibility: .visible) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":274,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" let safeLongitude = locationData.longitude.isFinite && !locationData.longitude.isNaN ? locationData.longitude : 0.0","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":418,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":503,"character":28},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":520,"character":28},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":555,"character":24},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" metadataRow(title: \"Generation Time\", value: formatDate(summaryData.generatedAt), icon: \"clock.arrow.circlepath\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":671,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" metadataRow(title: \"Compression Ratio\", value: summaryData.formattedCompressionRatio, icon: \"chart.bar.fill\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":674,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" metadataRow(title: \"Processing Time\", value: formattedProcessingTime(summaryData.processingTime), icon: \"timer\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":676,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AITextView(text: summaryData.summary, aiService: AIService.from(aiEngine: summaryData.aiEngine, aiModel: summaryData.aiModel))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":715,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":807,"character":20},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":1023,"character":20},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":1081,"character":20},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":1151,"character":28},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":1183,"character":28},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":1229,"character":20},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" AppLog.shared.summarization(\"Deleted empty anchor recording entry after summary deletion\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":1275,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" AppLog.shared.summarization(\"Recording no longer exists (orphaned summary) - skipping recording update\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":1286,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" AppLog.shared.summarization(\"Refreshing summary from Core Data, new length: \\(latestSummary.summary.count) chars, new model: \\(latestSummary.aiModel)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":1319,"character":1},"reason":"Line should be 120 characters or less; currently it has 178 characters"}},{"text":" \/\/ TODO: Implement custom date detection once Core Data field is added","violation":{"ruleName":"Todo","severity":"warning","ruleDescription":"TODOs and FIXMEs should be resolved.","ruleIdentifier":"todo","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":1397,"character":8},"reason":"TODOs should be resolved (Implement custom date detectio...)"}},{"text":" private func updateRecordingName(to newName: String) {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":1405,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 56 lines"}},{"text":" private func updateRecordingDateTime(to newDateTime: Date) {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":1475,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 52 lines"}},{"text":" throw NSError(domain: \"CoreDataManager\", code: 404, userInfo: [NSLocalizedDescriptionKey: \"Recording not found\"])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":1542,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" throw NSError(domain: \"CoreDataManager\", code: 404, userInfo: [NSLocalizedDescriptionKey: \"Recording not found\"])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":1593,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" let normalizedNotes = userNotes?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == true ? nil : userNotes","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":1710,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" AppLog.shared.summarization(\"\\(format.displayName) generated successfully, size: \\(exportData.count) bytes\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":1770,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" exportFileName = sanitizeFileName(\"\\(summaryData.recordingName)_Summary\", fileExtension: format.fileExtension)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":1773,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":1854,"character":24},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2005,"character":24},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" let success = await integrationManager.addReminderToReminders(reminder, recordingName: recordingName)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2037,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" let success = await integrationManager.addReminderToCalendar(reminder, recordingName: recordingName)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2049,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2105,"character":16},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2150,"character":16},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2214,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2244,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" .disabled(customTitleText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2276,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2283,"character":36},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2295,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2412,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2438,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2460,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2481,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2488,"character":32},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2506,"character":32},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":"struct LocationPickerView: View {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2560,"character":1},"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 427 lines"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2606,"character":32},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2628,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2701,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2755,"character":36},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":2767,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":3079,"character":12},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" let snapshot: MKMapSnapshotter.Snapshot = try await withCheckedThrowingContinuation { (continuation: CheckedContinuation) in","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":3162,"character":1},"reason":"Line should be 120 characters or less; currently it has 166 characters"}},{"text":" private func loadSnapshot(for key: String) async {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":3349,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 71 lines"}},{"text":" func activityViewController(_ controller: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":3591,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" func activityViewController(_ controller: UIActivityViewController, subjectForActivityType activityType: UIActivity.ActivityType?) -> String {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":3598,"character":1},"reason":"Line should be 120 characters or less; currently it has 146 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":3743,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"error","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryDetailView.swift","line":3778,"character":1},"reason":"File should contain 1000 lines or less: currently contains 3778"}},{"text":"class SummaryManager: ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":43,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 1494 lines"}},{"text":" AppLog.shared.summarization(\"Loaded \\(legacySummaries.count) legacy summaries from UserDefaults during init\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":91,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" @available(*, deprecated, message: \"Use AppDataCoordinator.addSummary() for Core Data persistence. This method only updates UI state.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":101,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" AppLog.shared.summarization(\"Enhanced summary saved. Total summaries: \\(self.enhancedSummaries.count)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":116,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" AppLog.shared.summarization(\"Can find summary: \\(self.hasSummary(for: summary.recordingURL))\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":135,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" AppLog.shared.summarization(\"Looking for enhanced summary with file: \\(recordingURL.lastPathComponent)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":159,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" AppLog.shared.summarization(\"hasEnhancedSummary for \\(recordingURL.lastPathComponent) = \\(result)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":218,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" let error = AppError.system(.configurationError(message: \"The selected AI engine is not supported on this device. Please select another AI engine in Settings.\"))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":274,"character":1},"reason":"Line should be 120 characters or less; currently it has 169 characters"}},{"text":" func initializeEngines() {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":280,"character":5},"reason":"Function should have complexity 10 or less; currently complexity is 14"}},{"text":" func initializeEngines() {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":280,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 61 lines"}},{"text":" AppLog.shared.summarization(\"Successfully initialized \\(engine.name) (Available: \\(engine.isAvailable))\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":307,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" AppLog.shared.summarization(\"Engine initialization complete - \\(successfullyInitialized)\/\\(allEngineTypes.count) engines initialized\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":315,"character":1},"reason":"Line should be 120 characters or less; currently it has 142 characters"}},{"text":" AppLog.shared.summarization(\"Saved engine '\\(savedEngineName)' not available, using '\\(availableEngine.name)' temporarily\", level: .default)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":339,"character":1},"reason":"Line should be 120 characters or less; currently it has 156 characters"}},{"text":" if let anyAvailableEngine = availableEngines.values.first(where: { $0.isAvailable && $0.name != \"None\" }) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":349,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" AppLog.shared.summarization(\"On-Device AI not available, using '\\(anyAvailableEngine.name)' as default\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":352,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" AppLog.shared.summarization(\"No available engines found, attempting to find any available engine\", level: .default)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":364,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" AppLog.shared.summarization(\"Engine details: \\(engine.description) (Available: \\(engine.isAvailable))\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":435,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" AppLog.shared.summarization(\"Engine configuration updated for '\\(engineName)' (Available: \\(updatedEngine.isAvailable))\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":459,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" func validateEngineAvailability(_ engineName: String) -> (isValid: Bool, isAvailable: Bool, errorMessage: String?) {","violation":{"ruleName":"Large Tuple","severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":468,"character":62},"reason":"Tuples should have at most 2 members"}},{"text":" func getEngineTypeInfo(for engineType: AIEngineType) -> (description: String, requirements: [String], isComingSoon: Bool) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":549,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" func getEngineTypeInfo(for engineType: AIEngineType) -> (description: String, requirements: [String], isComingSoon: Bool) {","violation":{"ruleName":"Large Tuple","severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":549,"character":61},"reason":"Tuples should have at most 2 members"}},{"text":" \/\/ Don't overwrite the user's saved preference - they may want to use their selected engine when it becomes available again","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":571,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" let selectedEngineName = UserDefaults.standard.string(forKey: \"SelectedAIEngine\") ?? AIEngineType.mlxSwift.rawValue","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":580,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" AppLog.shared.summarization(\"Synced current engine to '\\(selectedEngineName)' from settings\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":586,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" AppLog.shared.summarization(\"Selected engine '\\(selectedEngineName)' not available, keeping current engine\", level: .default)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":588,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" func getEngineInfo(for engineName: String) -> (description: String, isAvailable: Bool, version: String)? {","violation":{"ruleName":"Large Tuple","severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":593,"character":51},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.summarization(\"Current engine '\\(currentEngine.name)' is no longer available\", level: .default)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":754,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" AppLog.shared.summarization(\"Current engine '\\(currentEngine.name)' is no longer available\", level: .default)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":868,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" AppLog.shared.summarization(\"Available: \\(availableCount), Unavailable: \\(unavailableCount), Coming Soon: \\(comingSoonCount)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":943,"character":1},"reason":"Line should be 120 characters or less; currently it has 149 characters"}},{"text":" func generateEnhancedSummary(from text: String, for recordingURL: URL, recordingName: String, recordingDate: Date, coordinator: AppDataCoordinator? = nil, engineName: String? = nil) async throws -> EnhancedSummaryData {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":950,"character":1},"reason":"Line should be 200 characters or less; currently it has 223 characters"}},{"text":" func generateEnhancedSummary(from text: String, for recordingURL: URL, recordingName: String, recordingDate: Date, coordinator: AppDataCoordinator? = nil, engineName: String? = nil) async throws -> EnhancedSummaryData {","violation":{"ruleName":"Cyclomatic Complexity","severity":"error","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":950,"character":5},"reason":"Function should have complexity 10 or less; currently complexity is 21"}},{"text":" func generateEnhancedSummary(from text: String, for recordingURL: URL, recordingName: String, recordingDate: Date, coordinator: AppDataCoordinator? = nil, engineName: String? = nil) async throws -> EnhancedSummaryData {","violation":{"ruleName":"Function Body Length","severity":"error","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":950,"character":5},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 155 lines"}},{"text":" AppLog.shared.summarization(\"Transcript has 50 words or less (\\(words.count) words) - returning transcript as-is\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":963,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" if let index = self.enhancedSummaries.firstIndex(where: { $0.recordingURL == shortTranscriptSummary.recordingURL }) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":983,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" return try await generateBasicSummary(from: text, for: recordingURL, recordingName: recordingName, recordingDate: recordingDate, coordinator: coordinator)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1023,"character":1},"reason":"Line should be 120 characters or less; currently it has 166 characters"}},{"text":" var result: (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1028,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" var result: (summary: String, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], contentType: ContentType)","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1028,"character":21},"reason":"Tuples should have at most 2 members"}},{"text":" throw SummarizationError.processingFailed(reason: \"Ollama returned text that couldn't be parsed. Please check your Ollama model configuration or try a different model.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1070,"character":1},"reason":"Line should be 120 characters or less; currently it has 193 characters"}},{"text":" } else if error.localizedDescription.contains(\"connection\") || error.localizedDescription.contains(\"server\") {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1071,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" let finalRecordingName = intelligentName.isEmpty || intelligentName == \"Recording\" ? recordingName : intelligentName","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1100,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" handleError(SummarizationError.processingFailed(reason: \"Summary quality below threshold\"), context: \"Summary Quality\", recordingName: recordingName)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1121,"character":1},"reason":"Line should be 120 characters or less; currently it has 161 characters"}},{"text":" if let index = self.enhancedSummaries.firstIndex(where: { $0.recordingURL == enhancedSummary.recordingURL }) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1127,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" AppLog.shared.summarization(\"Background task started - unlimited time (foreground or audio session active)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1176,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" private func generateBasicSummary(from text: String, for recordingURL: URL, recordingName: String, recordingDate: Date, coordinator: AppDataCoordinator?) async throws -> EnhancedSummaryData {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1190,"character":1},"reason":"Line should be 120 characters or less; currently it has 195 characters"}},{"text":" private func generateBasicSummary(from text: String, for recordingURL: URL, recordingName: String, recordingDate: Date, coordinator: AppDataCoordinator?) async throws -> EnhancedSummaryData {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1190,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 97 lines"}},{"text":" AppLog.shared.summarization(\"Transcript has 50 words or less (\\(words.count) words) - returning transcript as-is\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1201,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" if let index = self.enhancedSummaries.firstIndex(where: { $0.recordingURL == shortTranscriptSummary.recordingURL }) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1221,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" let finalRecordingName = intelligentName.isEmpty || intelligentName == \"Recording\" ? recordingName : intelligentName","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1262,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" handleError(SummarizationError.processingFailed(reason: \"Basic summary quality below threshold\"), context: \"Basic Summary Quality\", recordingName: recordingName)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1282,"character":1},"reason":"Line should be 120 characters or less; currently it has 173 characters"}},{"text":" if let index = self.enhancedSummaries.firstIndex(where: { $0.recordingURL == enhancedSummary.recordingURL }) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1288,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" private func createBasicSummary(from text: String, contentType: ContentType) -> String {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1321,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 16"}},{"text":" private func createBasicSummary(from text: String, contentType: ContentType) -> String {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1321,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 55 lines"}},{"text":" AppLog.shared.summarization(\"Creating content-type optimized summary for: \\(contentType.rawValue)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1322,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" let scoredSentences = sentences.enumerated().map { _, sentence in","violation":{"ruleName":"Unused Enumerated","severity":"warning","ruleDescription":"When the index or the item is not used, `.enumerated()` can be removed.","ruleIdentifier":"unused_enumerated","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1332,"character":60},"reason":"When the index is not used, `.enumerated()` can be removed"}},{"text":" let meetingKeywords = [\"decision\", \"action item\", \"follow up\", \"next step\", \"agreed\", \"consensus\", \"deadline\", \"schedule\"]","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1339,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" if sentence.lowercased().contains(keyword) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1341,"character":21},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" let reflectionKeywords = [\"i feel\", \"i think\", \"i learned\", \"i realized\", \"i discovered\", \"my experience\", \"i believe\"]","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1346,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" if sentence.lowercased().contains(keyword) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1348,"character":21},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" let technicalKeywords = [\"algorithm\", \"function\", \"method\", \"solution\", \"implementation\", \"architecture\", \"system\", \"code\"]","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1353,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" if sentence.lowercased().contains(keyword) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1355,"character":21},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" AppLog.shared.summarization(\"Content-type optimized summary created: \\(summary.count) characters\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1393,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" AppLog.shared.summarization(\"AI engine task extraction failed, using fallback extractor\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1418,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" AppLog.shared.summarization(\"AI engine reminder extraction failed, using fallback extractor\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1451,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" func extractTasksAndRemindersFromText(_ text: String) async throws -> (tasks: [TaskItem], reminders: [ReminderItem]) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1486,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" AppLog.shared.summarization(\"Extracted \\(taskResults.count) tasks and \\(reminderResults.count) reminders\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1494,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" func extractTasksRemindersAndTitlesFromText(_ text: String) async throws -> (tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1498,"character":1},"reason":"Line should be 120 characters or less; currently it has 149 characters"}},{"text":" func extractTasksRemindersAndTitlesFromText(_ text: String) async throws -> (tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) {","violation":{"ruleName":"Large Tuple","severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1498,"character":81},"reason":"Tuples should have at most 2 members"}},{"text":" AppLog.shared.summarization(\"Extracted \\(taskResults.count) tasks, \\(reminderResults.count) reminders, and \\(titleResults.count) titles\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1507,"character":1},"reason":"Line should be 120 characters or less; currently it has 160 characters"}},{"text":" AppLog.shared.summarization(\"Generating content-type optimized summary for \\(contentType.rawValue)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1514,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" let scoredSentences = sentences.enumerated().map { _, sentence in","violation":{"ruleName":"Unused Enumerated","severity":"warning","ruleDescription":"When the index or the item is not used, `.enumerated()` can be removed.","ruleIdentifier":"unused_enumerated","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1534,"character":60},"reason":"When the index is not used, `.enumerated()` can be removed"}},{"text":" let meetingKeywords = [\"decision\", \"action item\", \"follow up\", \"next step\", \"agreed\", \"consensus\", \"deadline\", \"schedule\"]","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1538,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" if sentence.lowercased().contains(keyword) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1542,"character":17},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" let scoredSentences = sentences.enumerated().map { _, sentence in","violation":{"ruleName":"Unused Enumerated","severity":"warning","ruleDescription":"When the index or the item is not used, `.enumerated()` can be removed.","ruleIdentifier":"unused_enumerated","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1568,"character":60},"reason":"When the index is not used, `.enumerated()` can be removed"}},{"text":" let reflectionKeywords = [\"i feel\", \"i think\", \"i learned\", \"i realized\", \"i discovered\", \"my experience\", \"i believe\"]","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1572,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" if sentence.lowercased().contains(keyword) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1576,"character":17},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" let scoredSentences = sentences.enumerated().map { _, sentence in","violation":{"ruleName":"Unused Enumerated","severity":"warning","ruleDescription":"When the index or the item is not used, `.enumerated()` can be removed.","ruleIdentifier":"unused_enumerated","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1602,"character":60},"reason":"When the index is not used, `.enumerated()` can be removed"}},{"text":" let technicalKeywords = [\"algorithm\", \"function\", \"method\", \"solution\", \"implementation\", \"architecture\", \"system\", \"code\", \"debug\", \"test\"]","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1606,"character":1},"reason":"Line should be 120 characters or less; currently it has 152 characters"}},{"text":" if sentence.lowercased().contains(keyword) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1610,"character":17},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" let scoredSentences = sentences.enumerated().map { _, sentence in","violation":{"ruleName":"Unused Enumerated","severity":"warning","ruleDescription":"When the index or the item is not used, `.enumerated()` can be removed.","ruleIdentifier":"unused_enumerated","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1636,"character":60},"reason":"When the index is not used, `.enumerated()` can be removed"}},{"text":" _ = try await generateEnhancedSummary(from: transcriptText, for: url, recordingName: name, recordingDate: date)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1663,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" AppLog.shared.summarization(\"Chunk \\(index + 1) failed: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1804,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" originalLength: transcript.fullText.components(separatedBy: .whitespacesAndNewlines).filter { !$0.isEmpty }.count,","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1821,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" if let index = enhancedSummaries.firstIndex(where: { $0.recordingURL == combinedEnhancedSummary.recordingURL }) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1826,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" SummarizationError.networkError(underlying: NSError(domain: \"NetworkError\", code: 0, userInfo: [NSLocalizedDescriptionKey: \"Network unavailable\"])),","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1856,"character":1},"reason":"Line should be 120 characters or less; currently it has 164 characters"}},{"text":" summary: \"## Manual Summary Required\\n\\nThis recording requires manual summarization due to processing errors.\\n\\n**Recording:** \\(recordingName)\\n**Date:** \\(DateFormatter.localizedString(from: Date(), dateStyle: .medium, timeStyle: .short))\\n\\nPlease create a summary manually using the app's editing features.\",","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1888,"character":1},"reason":"Line should be 200 characters or less; currently it has 326 characters"}},{"text":" func generateIntelligentRecordingName(from text: String, contentType: ContentType, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem]) -> String {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1924,"character":1},"reason":"Line should be 120 characters or less; currently it has 165 characters"}},{"text":" func updateRecordingNameWithAI(from oldName: String, recordingURL: URL, transcript: String, contentType: ContentType, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], coordinator: AppDataCoordinator?) async throws {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1943,"character":1},"reason":"Line should be 200 characters or less; currently it has 237 characters"}},{"text":" func updateRecordingNameWithAI(from oldName: String, recordingURL: URL, transcript: String, contentType: ContentType, tasks: [TaskItem], reminders: [ReminderItem], titles: [TitleItem], coordinator: AppDataCoordinator?) async throws {","violation":{"ruleName":"Function Parameter Count","severity":"warning","ruleDescription":"Number of function parameters should be low.","ruleIdentifier":"function_parameter_count","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1943,"character":5},"reason":"Function should have 5 parameters or less: it currently has 8"}},{"text":" let newName = generateIntelligentRecordingName(from: transcript, contentType: contentType, tasks: tasks, reminders: reminders, titles: titles)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1947,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" try await updateRecordingName(from: oldName, to: newName, recordingURL: recordingURL, coordinator: coordinator)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1953,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" AppLog.shared.summarization(\"Keeping original name '\\(oldName)' (no meaningful improvement found)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1982,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" private func updateRecordingName(from oldName: String, to newName: String, recordingURL: URL, coordinator: AppDataCoordinator) async throws {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1986,"character":1},"reason":"Line should be 120 characters or less; currently it has 145 characters"}},{"text":" AppLog.shared.summarization(\"Could not find recording in Core Data for file: \\(recordingURL.lastPathComponent)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":1992,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" let averageConfidence = enhancedSummaries.isEmpty ? 0.0 : enhancedSummaries.map { $0.confidence }.reduce(0, +) \/ Double(totalSummaries)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":2086,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"text":" let averageCompressionRatio = enhancedSummaries.isEmpty ? 0.0 : enhancedSummaries.map { $0.compressionRatio }.reduce(0, +) \/ Double(totalSummaries)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":2087,"character":1},"reason":"Line should be 120 characters or less; currently it has 155 characters"}},{"text":" AppLog.shared.summarization(\"saveEnhancedSummariesToDisk() called - this is deprecated, use Core Data instead\", level: .default)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":2111,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" AppLog.shared.summarization(\"Found \\(legacySummaries.count) legacy summaries in UserDefaults - consider migrating to Core Data\", level: .default)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":2124,"character":1},"reason":"Line should be 120 characters or less; currently it has 157 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"error","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryManager.swift","line":2129,"character":1},"reason":"File should contain 1000 lines or less: currently contains 2129"}},{"text":" func regenerateAllSummaries() async {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryRegenerationManager.swift","line":38,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 76 lines"}},{"text":" AppLog.shared.summarization(\"Bulk regeneration name check: nameChanged=\\(newEnhancedSummary.recordingName != summary.recordingName)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryRegenerationManager.swift","line":84,"character":1},"reason":"Line should be 120 characters or less; currently it has 164 characters"}},{"text":" AppLog.shared.summarization(\"Regeneration name check: nameChanged=\\(newEnhancedSummary.recordingName != summary.recordingName)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryRegenerationManager.swift","line":167,"character":1},"reason":"Line should be 120 characters or less; currently it has 155 characters"}},{"text":" AppLog.shared.summarization(\"Failed to regenerate summary for recording \\(recordingId): \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SummaryRegenerationManager.swift","line":205,"character":1},"reason":"Line should be 120 characters or less; currently it has 146 characters"}},{"text":"class SystemIntegrationManager: NSObject, ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"warning","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SystemIntegrationManager.swift","line":18,"character":1},"reason":"Class body should span 250 lines or less excluding comments and whitespace: currently spans 292 lines"}},{"text":" reminder.dueDateComponents = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute], from: dueDate)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SystemIntegrationManager.swift","line":100,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" ekReminder.dueDateComponents = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute], from: dueDate)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SystemIntegrationManager.swift","line":196,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" ekReminder.dueDateComponents = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute], from: relativeDate)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SystemIntegrationManager.swift","line":200,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" func addReminderToCalendar(_ reminder: ReminderItem, recordingName: String) async -> Bool {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SystemIntegrationManager.swift","line":225,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 53 lines"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/SystemIntegrationManager.swift","line":430,"character":1},"reason":"File should contain 400 lines or less: currently contains 430"}},{"text":"class TaskExtractor {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/TaskExtractor.swift","line":13,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 414 lines"}},{"text":" private func extractTaskUsingPatterns(_ sentence: String) -> TaskItem? {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/TaskExtractor.swift","line":79,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 62 lines"}},{"text":" let taskPatterns: [(pattern: String, category: TaskItem.TaskCategory, basePriority: TaskItem.Priority, confidenceBoost: Double)] = [","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/TaskExtractor.swift","line":83,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" let taskPatterns: [(pattern: String, category: TaskItem.TaskCategory, basePriority: TaskItem.Priority, confidenceBoost: Double)] = [","violation":{"ruleName":"Large Tuple","severity":"error","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/TaskExtractor.swift","line":83,"character":28},"reason":"Tuples should have at most 2 members"}},{"text":" if lowercased.contains(pattern) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/TaskExtractor.swift","line":143,"character":13},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" let confidence = calculatePatternConfidence(sentence: sentence, pattern: pattern, baseConfidence: confidenceBoost)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/TaskExtractor.swift","line":147,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" tagger.enumerateTags(in: range, unit: .word, scheme: .lexicalClass, options: [.omitWhitespace, .omitPunctuation]) { tag, tokenRange in","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/TaskExtractor.swift","line":178,"character":1},"reason":"Line should be 120 characters or less; currently it has 142 characters"}},{"text":" if lowercased.hasPrefix(starter) {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/TaskExtractor.swift","line":225,"character":13},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" for i in 0..= \\(SHORT_CALL_THRESHOLD)s threshold) - asking user whether to resume\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Interruptions.swift","line":64,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":"\tfunc attemptResumeAfterUnexpectedStop() async {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Interruptions.swift","line":123,"character":2},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 63 lines"}},{"text":"\t\t\tAppLog.shared.audioSession(\"Resume already in progress, skipping duplicate attemptResumeAfterUnexpectedStop\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Interruptions.swift","line":125,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":"\t\t\t\tAppLog.shared.audioSession(\"Failed to resume recording - recorder not active, treating as real interruption\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Interruptions.swift","line":207,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":"\t\t\tAppLog.shared.audioSession(\"Failed to resume recording: \\(error.localizedDescription), treating as real interruption\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Interruptions.swift","line":211,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":"\tfunc resumeRecordingAfterInterruption(url: URL?) async {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Interruptions.swift","line":217,"character":2},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 79 lines"}},{"text":"\t\t\tAppLog.shared.audioSession(\"Resume already in progress, skipping duplicate resumeRecordingAfterInterruption\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Interruptions.swift","line":230,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":"\t\t\tAppLog.shared.audioSession(\"Recording already being processed, skipping duplicate interruption handling\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Interruptions.swift","line":495,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":"\tfunc recoverInterruptedRecording(url: URL, reason: String) async {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Interruptions.swift","line":532,"character":2},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 63 lines"}},{"text":"\t\tAppLog.shared.audioSession(\"checkForUnprocessedRecording called - recordingBeingProcessed: \\(recordingBeingProcessed), isRecording: \\(isRecording)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Interruptions.swift","line":630,"character":1},"reason":"Line should be 120 characters or less; currently it has 165 characters"}},{"text":"\t\tlet body = \"Your recording was interrupted when the app went to background. Don't worry - it will be saved when you return to the app!\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Interruptions.swift","line":861,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Interruptions.swift","line":900,"character":1},"reason":"File should contain 400 lines or less: currently contains 900"}},{"text":"\tfunc playRecording(url: URL) {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Playback.swift","line":15,"character":2},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 54 lines"}},{"text":"\tfunc mergeRecordingSegments() async {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Segments.swift","line":27,"character":2},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 75 lines"}},{"text":"\t\t\t\tAppLog.shared.recording(\"Added segment \\(index + 1) at \\(currentTime.seconds)s, duration: \\(duration.seconds)s\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Segments.swift","line":70,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":"\t\t\tAppLog.shared.recording(\"Checkpoint: Forced buffer flush at \\(Int(recordingTime))s (no silence for \\(Int(timeSinceLastCheckpoint))s)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Segments.swift","line":240,"character":1},"reason":"Line should be 120 characters or less; currently it has 152 characters"}},{"text":"\tnonisolated func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Utilities.swift","line":30,"character":14},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 59 lines"}},{"text":"\t\t\t\tAppLog.shared.recording(\"Recorder finished but still in recording mode - ignoring (interruption will be handled)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Utilities.swift","line":35,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":"\t\t\t\tAppLog.shared.recording(\"Recording already processed by interruption handler, skipping normal completion\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Utilities.swift","line":42,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":"\t\t\t\t\tAppLog.shared.recording(\"Failed to set preferred input, falling back to default: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Utilities.swift","line":218,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":"\t\t\tlet d = player.duration","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Utilities.swift","line":269,"character":8},"reason":"Variable name 'd' should be between 3 and 40 characters long"}},{"text":"\tfunc checkRecordingLimitsAndWarnings() async {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+Warnings.swift","line":47,"character":2},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 64 lines"}},{"text":"\t\t\t\t\tthrow NSError(domain: \"AudioRecorderViewModel\", code: -2, userInfo: [NSLocalizedDescriptionKey: \"Could not access Documents directory\"])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+WatchIntegration.swift","line":68,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":"\t\t\t\t\tthrow NSError(domain: \"AudioRecorderViewModel\", code: -1, userInfo: [NSLocalizedDescriptionKey: \"App coordinator not available\"])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+WatchIntegration.swift","line":81,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":"\t\t\t\t\tAppLog.shared.watchConnectivity(\"Calling onWatchRecordingSyncCompleted - callback is nil: \\(watchManager.onWatchRecordingSyncCompleted == nil)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+WatchIntegration.swift","line":108,"character":1},"reason":"Line should be 120 characters or less; currently it has 164 characters"}},{"text":"\t\t\t\t\tAppLog.shared.watchConnectivity(\"Called completion callback for successful watch recording: \\(syncRequest.recordingId)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+WatchIntegration.swift","line":110,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":"\t\t\t\t\tAppLog.shared.watchConnectivity(\"Called completion callback for failed watch recording: \\(syncRequest.recordingId)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel+WatchIntegration.swift","line":120,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":"class AudioRecorderViewModel: NSObject, ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","line":20,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 772 lines"}},{"text":"\tlet SHORT_CALL_THRESHOLD: TimeInterval = 180 \/\/ 3 minutes","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","line":126,"character":6},"reason":"Variable name 'SHORT_CALL_THRESHOLD' should only contain alphanumeric and other allowed characters"}},{"text":"\tlet MICROPHONE_RECONNECTION_TIMEOUT: TimeInterval = 300 \/\/ 5 minutes","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","line":130,"character":6},"reason":"Variable name 'MICROPHONE_RECONNECTION_TIMEOUT' should only contain alphanumeric and other allowed characters"}},{"text":"\tlet MAX_RECORDING_DURATION: TimeInterval = 10800 \/\/ 3 hours","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","line":136,"character":6},"reason":"Variable name 'MAX_RECORDING_DURATION' should only contain alphanumeric and other allowed characters"}},{"text":"\tlet DURATION_WARNING_THRESHOLD: TimeInterval = 9900 \/\/ 2h 45m (15 min warning)","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","line":137,"character":6},"reason":"Variable name 'DURATION_WARNING_THRESHOLD' should only contain alphanumeric and other allowed characters"}},{"text":"\tlet MIN_STORAGE_REQUIRED_MB: Int64 = 100 \/\/ Stop recording at 100 MB free","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","line":138,"character":6},"reason":"Variable name 'MIN_STORAGE_REQUIRED_MB' should only contain alphanumeric and other allowed characters"}},{"text":"\tlet STORAGE_WARNING_THRESHOLD_MB: Int64 = 200 \/\/ Warn at 200 MB free","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","line":139,"character":6},"reason":"Variable name 'STORAGE_WARNING_THRESHOLD_MB' should only contain alphanumeric and other allowed characters"}},{"text":"\tlet MIN_BATTERY_LEVEL: Float = 0.05 \/\/ Stop at 5%","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","line":140,"character":6},"reason":"Variable name 'MIN_BATTERY_LEVEL' should only contain alphanumeric and other allowed characters"}},{"text":"\tlet BATTERY_WARNING_THRESHOLD: Float = 0.15 \/\/ Warn at 15%","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","line":141,"character":6},"reason":"Variable name 'BATTERY_WARNING_THRESHOLD' should only contain alphanumeric and other allowed characters"}},{"text":"\tfunc setupNotificationObservers() {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","line":278,"character":2},"reason":"Function should have complexity 10 or less; currently complexity is 18"}},{"text":"\tfunc setupNotificationObservers() {","violation":{"ruleName":"Function Body Length","severity":"error","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","line":278,"character":2},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 115 lines"}},{"text":"\t\t\t\tlet newNotification = Notification(name: AVAudioSession.interruptionNotification, object: nil, userInfo: capturedUserInfo)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","line":300,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":"\t\t\t\t\tlet newNotification = Notification(name: AVAudioSession.routeChangeNotification, object: nil, userInfo: newUserInfo)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","line":318,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":"\t\t\t\t\tAppLog.shared.recording(\"Resume already in progress from another handler, skipping foreground restore\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","line":362,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":"\t\t\t\t\tAppLog.shared.recording(\"App foregrounded without active recording - leaving audio session inactive\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","line":368,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":"\t\t\t\t\t\tif let r = self.audioRecorder, r.isRecording {","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","line":387,"character":14},"reason":"Variable name 'r' should be between 3 and 40 characters long"}},{"text":"\t\t\terrorMessage = \"Recording failed on simulator. Enable Device β†’ Microphone β†’ Internal Microphone in simulator menu, or test on a physical device.\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","line":685,"character":1},"reason":"Line should be 120 characters or less; currently it has 148 characters"}},{"text":"\tfunc stopRecording() {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","line":773,"character":2},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 58 lines"}},{"text":"\t\t\t\t\t\t\tAppLog.shared.recording(\"Detected recorder stopped - waiting for interruption notification (grace period: 5s)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","line":970,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"error","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/AudioRecorderViewModel.swift","line":1051,"character":1},"reason":"File should contain 1000 lines or less: currently contains 1051"}},{"text":"final class CatalystSystemAudioCapture: NSObject, SCStreamOutput, SCStreamDelegate {","violation":{"ruleName":"Type Body Length","severity":"warning","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/CatalystSystemAudioCapture.swift","line":16,"character":7},"reason":"Class body should span 250 lines or less excluding comments and whitespace: currently spans 305 lines"}},{"text":"\tfunc stream(_ stream: SCStream, didOutputSampleBuffer sampleBuffer: CMSampleBuffer, of type: SCStreamOutputType) {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/CatalystSystemAudioCapture.swift","line":170,"character":2},"reason":"Function should have complexity 10 or less; currently complexity is 20"}},{"text":"\tfunc stream(_ stream: SCStream, didOutputSampleBuffer sampleBuffer: CMSampleBuffer, of type: SCStreamOutputType) {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/CatalystSystemAudioCapture.swift","line":170,"character":2},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 55 lines"}},{"text":"\tprivate static func containsAudibleSignal(_ sampleBuffer: CMSampleBuffer) -> Bool {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/CatalystSystemAudioCapture.swift","line":235,"character":10},"reason":"Function should have complexity 10 or less; currently complexity is 12"}},{"text":"\tprivate static func containsAudibleSignal(_ sampleBuffer: CMSampleBuffer) -> Bool {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/CatalystSystemAudioCapture.swift","line":235,"character":17},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 70 lines"}},{"text":"\t\tAppLog.shared.recording(\"Catalyst system audio stream stopped with error: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/ViewModels\/CatalystSystemAudioCapture.swift","line":316,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" } else if engineLower.contains(\"device\") || engineLower.contains(\"apple\") || engineLower.contains(\"mlx\") || modelLower.contains(\"intelligence\") || modelLower.contains(\"gemma\") || modelLower.contains(\"phi\") || modelLower.contains(\"qwen\") || modelLower.contains(\"llama\") || modelLower.contains(\"mistral\") || modelLower.contains(\"olmo\") || modelLower.contains(\"alpaca\") || modelLower.contains(\"bonsai\") || modelLower.contains(\"ternary\") {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AITextView.swift","line":44,"character":1},"reason":"Line should be 200 characters or less; currently it has 443 characters"}},{"text":" let _ = {","violation":{"ruleName":"Redundant Discardable Let","severity":"warning","ruleDescription":"Prefer `_ = foo()` over `let _ = foo()` when discarding a result from a function","ruleIdentifier":"redundant_discardable_let","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AITextView.swift","line":67,"character":9},"reason":"Prefer `_ = foo()` over `let _ = foo()` when discarding a result from a function"}},{"text":" AppLog.shared.summarization(\"AITextView text was cleaned to empty, original length: \\(text.count)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AITextView.swift","line":71,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" AppLog.shared.summarization(\"AITextView cleaning: original=\\(text.count), cleaned=\\(cleaned.count)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AITextView.swift","line":106,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" AITextView(text: \"### Summary with Emoji\\n\\n:checkmark: Task completed successfully\\n:warning: Important note to review\\n:info: Additional information\\n:rocket: Quick start guide\\n:lightbulb: Helpful tips\\n:star: Key highlights\", aiService: .googleAI)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AITextView.swift","line":125,"character":1},"reason":"Line should be 200 characters or less; currently it has 263 characters"}},{"text":" AITextView(text: \"### Product Overview\\n\\nThe company offers an AI-powered tutoring platform.\\n\\n#### Key Features\\n\\nβ€’ Personalized tutoring for students\\nβ€’ Concurrent seating model\", aiService: .googleAI)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AITextView.swift","line":132,"character":1},"reason":"Line should be 200 characters or less; currently it has 218 characters"}},{"text":" AITextView(text: \"### Primary Action Items\\n\\nβ€’ Tim to provide list of suspended accounts\\nβ€’ Confirm deletion with Jack\\nβ€’ Review MOU language for data deletion\\n\\n1. Create sample account for testing\\n2. Review storage quotas\\n3. Implement notification processes\", aiService: .googleAI)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AITextView.swift","line":139,"character":1},"reason":"Line should be 200 characters or less; currently it has 299 characters"}},{"text":" AITextView(text: \"## Market and Political Dynamics\\n\\nβ€’ Federal Reserve Chair **Jerome Powell** discussed potential interest rate cuts\\nβ€’ Stock market surged with Dow rising over 800 points\\nβ€’ Political tensions emerged around Federal Reserve governance\\n\\n### Key Economic Insights\\n\\nβ€’ Investors looking for positive economic signals\\nβ€’ Concerns about political interference in independent institutions\\nβ€’ Discussions about inflation, employment, and market confidence\\n\\n### Notable Political Developments\\n\\nβ€’ President Trump threatening to fire Federal Reserve Governor **Lisa Cook**\\nβ€’ Debates about immigrant labor's economic importance\", aiService: .googleAI)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AITextView.swift","line":146,"character":1},"reason":"Line should be 200 characters or less; currently it has 679 characters"}},{"text":" AITextView(text: \"\\\"summary\\\": \\\"**Storage and Account Management Highlights**\\n\\nβ€’ Retirees will retain **5GB storage**\\nβ€’ Data deletion and account management for alumni\\nβ€’ Google storage quotas and notification processes\\nβ€’ Suspended account cleanup strategy\\\"\", aiService: .googleAI)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AITextView.swift","line":153,"character":1},"reason":"Line should be 200 characters or less; currently it has 299 characters"}},{"text":" Text(\"These are brought in through AWS SDK and other direct dependencies. All dependencies are MIT or Apache 2.0 licensed. See each project repository for full terms.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","line":62,"character":1},"reason":"Line should be 120 characters or less; currently it has 188 characters"}},{"text":" description: \"Apple Silicon ML framework and language-model utilities used for on-device summarization with Ternary Bonsai models.\",","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","line":230,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" TransitiveProject(name: \"Swift NIO Transport Services\", url: URL(string: \"https:\/\/github.com\/apple\/swift-nio-transport-services\")!),","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","line":266,"character":1},"reason":"Line should be 120 characters or less; currently it has 144 characters"}},{"text":" TransitiveProject(name: \"Swift Collections\", url: URL(string: \"https:\/\/github.com\/apple\/swift-collections\")!),","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","line":269,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" TransitiveProject(name: \"Swift Async Algorithms\", url: URL(string: \"https:\/\/github.com\/apple\/swift-async-algorithms\")!),","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","line":275,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" TransitiveProject(name: \"Swift Argument Parser\", url: URL(string: \"https:\/\/github.com\/apple\/swift-argument-parser\")!),","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","line":276,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" TransitiveProject(name: \"Swift Certificates\", url: URL(string: \"https:\/\/github.com\/apple\/swift-certificates\")!),","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","line":278,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" TransitiveProject(name: \"Swift HTTP Structured Headers\", url: URL(string: \"https:\/\/github.com\/apple\/swift-http-structured-headers\")!),","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","line":281,"character":1},"reason":"Line should be 120 characters or less; currently it has 146 characters"}},{"text":" TransitiveProject(name: \"Swift Distributed Tracing\", url: URL(string: \"https:\/\/github.com\/apple\/swift-distributed-tracing\")!),","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","line":282,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" TransitiveProject(name: \"Swift Service Context\", url: URL(string: \"https:\/\/github.com\/apple\/swift-service-context\")!),","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","line":283,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" TransitiveProject(name: \"Swift Configuration\", url: URL(string: \"https:\/\/github.com\/apple\/swift-configuration\")!)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","line":284,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" TransitiveProject(name: \"Async HTTP Client\", url: URL(string: \"https:\/\/github.com\/swift-server\/async-http-client\")!),","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","line":290,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" TransitiveProject(name: \"Swift Service Lifecycle\", url: URL(string: \"https:\/\/github.com\/swift-server\/swift-service-lifecycle\")!),","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","line":291,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" TransitiveProject(name: \"OpenTelemetry Swift\", url: URL(string: \"https:\/\/github.com\/open-telemetry\/opentelemetry-swift\")!),","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","line":293,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" TransitiveProject(name: \"Swift HuggingFace\", url: URL(string: \"https:\/\/github.com\/huggingface\/swift-huggingface\")!),","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","line":297,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" TransitiveProject(name: \"Swift Concurrency Extras\", url: URL(string: \"https:\/\/github.com\/pointfreeco\/swift-concurrency-extras\")!)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AcknowledgementsView.swift","line":301,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(\"NavigateToSection\"))) { notification in","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AdaptiveNavigationView.swift","line":111,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" Text(\"Archive copies are currently limited to iCloud Drive so the app can reliably track, restore, and clean them up.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/ArchiveConfirmationView.swift","line":36,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/ArchiveConfirmationView.swift","line":65,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" .background(Color.accentColor.opacity(0.12), in: RoundedRectangle(cornerRadius: 10, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/ArchiveConfirmationView.swift","line":74,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/ArchiveConfirmationView.swift","line":87,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":"struct AudioPlayerView: View {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioPlayerView.swift","line":11,"character":1},"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 481 lines"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioPlayerView.swift","line":97,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioPlayerView.swift","line":174,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioPlayerView.swift","line":201,"character":12},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" EditableTranscriptView(recording: entry, transcript: transcript, transcriptManager: TranscriptManager.shared)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioPlayerView.swift","line":210,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" transcriptionStarter.startTranscription(for: pending, cleanFirst: true, appCoordinator: appCoordinator)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioPlayerView.swift","line":227,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" transcriptionStarter.startTranscription(for: pending, cleanFirst: false, appCoordinator: appCoordinator)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioPlayerView.swift","line":233,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" Text(\"Cleaning reduces static and normalizes volume, which can improve transcription accuracy. The original audio file is not changed.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioPlayerView.swift","line":240,"character":1},"reason":"Line should be 120 characters or less; currently it has 148 characters"}},{"text":" .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(\"RecordingCloudSyncPreferenceChanged\"))) { _ in","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioPlayerView.swift","line":284,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" .background((isCloudSyncDisabled ? Color.indigo : Color.blue).opacity(0.12), in: RoundedRectangle(cornerRadius: 10, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioPlayerView.swift","line":306,"character":1},"reason":"Line should be 120 characters or less; currently it has 152 characters"}},{"text":" .accessibilityHint(\"Excludes this recording, transcript, and summary from BisonNotes iCloud sync and backup.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioPlayerView.swift","line":328,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioPlayerView.swift","line":352,"character":16},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioPlayerView.swift","line":590,"character":1},"reason":"File should contain 400 lines or less: currently contains 590"}},{"text":" x: min(max(isDragging ? 10 : 8, (geometry.size.width * progress)), geometry.size.width - (isDragging ? 10 : 8)),","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/AudioScrubber.swift","line":75,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" let _ = AppLog.shared.backgroundProcessing(\"BackgroundProcessingView body: activeJobs.count = \\(processingManager.activeJobs.count)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/BackgroundProcessingView.swift","line":17,"character":1},"reason":"Line should be 120 characters or less; currently it has 156 characters"}},{"text":" let _ = AppLog.shared.backgroundProcessing(\"BackgroundProcessingView body: activeJobs.count = \\(processingManager.activeJobs.count)\", level: .debug)","violation":{"ruleName":"Redundant Discardable Let","severity":"warning","ruleDescription":"Prefer `_ = foo()` over `let _ = foo()` when discarding a result from a function","ruleIdentifier":"redundant_discardable_let","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/BackgroundProcessingView.swift","line":17,"character":9},"reason":"Prefer `_ = foo()` over `let _ = foo()` when discarding a result from a function"}},{"text":" value: \"\\(processingManager.activeJobs.filter { $0.status.isError || $0.status.isCancelled }.count)\",","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/BackgroundProcessingView.swift","line":137,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/BackgroundProcessingView.swift","line":470,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/BackgroundProcessingView.swift","line":498,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/BackgroundProcessingView.swift","line":544,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/BackgroundProcessingView.swift","line":569,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/BackgroundProcessingView.swift","line":582,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/BackgroundProcessingView.swift","line":601,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/BackgroundProcessingView.swift","line":620,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/BackgroundProcessingView.swift","line":700,"character":1},"reason":"File should contain 400 lines or less: currently contains 700"}},{"text":"struct CombineRecordingsView: View {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/CombineRecordingsView.swift","line":10,"character":1},"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 467 lines"}},{"text":" init(firstRecording: AudioRecordingFile, secondRecording: AudioRecordingFile, recommendedFirst: AudioRecordingFile) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/CombineRecordingsView.swift","line":35,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" Text(\"Select which recording should be first in the combined file. The recordings will be merged in the order you specify.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/CombineRecordingsView.swift","line":104,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/CombineRecordingsView.swift","line":176,"character":20},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" private func recordingOrderCard(recording: AudioRecordingFile, position: String, isRecommended: Bool) -> some View {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/CombineRecordingsView.swift","line":205,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 51 lines"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/CombineRecordingsView.swift","line":312,"character":12},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" private func combineRecordings() async {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/CombineRecordingsView.swift","line":381,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 15"}},{"text":" private func combineRecordings() async {","violation":{"ruleName":"Function Body Length","severity":"error","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/CombineRecordingsView.swift","line":381,"character":13},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 125 lines"}},{"text":" errorMessage = \"Cannot combine recordings with existing transcripts or summaries. Please delete them first.\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/CombineRecordingsView.swift","line":386,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" AppLog.shared.recording(\"Combine: hasLocation=\\(combinedLocation != nil) for addRecording\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/CombineRecordingsView.swift","line":518,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/CombineRecordingsView.swift","line":577,"character":1},"reason":"File should contain 400 lines or less: currently contains 577"}},{"text":"struct DataMigrationView: View {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":16,"character":1},"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 1014 lines"}},{"text":" @State private var orphanedFilesResults: (deleted: Int, totalSize: Int64, errors: [String])?","violation":{"ruleName":"Large Tuple","severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":43,"character":46},"reason":"Tuples should have at most 2 members"}},{"text":" Text(\"🚨🚨🚨 EXTREME WARNING 🚨🚨🚨\\n\\nYou are about to PERMANENTLY DELETE ALL DATABASE DATA:\\n\\n❌ ALL TRANSCRIPTS will be DELETED FOREVER\\n❌ ALL SUMMARIES will be DELETED FOREVER\\n❌ ALL RECORDING METADATA will be DELETED FOREVER\\n\\nβœ… Audio files will remain on disk (but without any metadata)\\n\\n⚠️ THIS ACTION CANNOT BE UNDONE\\n⚠️ NO RECOVERY IS POSSIBLE\\n⚠️ ALL PROCESSED DATA WILL BE LOST\\n\\nThis is an extreme troubleshooting measure. DO NOT proceed unless you:\\n\\n1. Have a backup of your data\\n2. Understand you will lose ALL transcripts and summaries\\n3. Are prepared to re-transcribe and re-summarize everything\\n\\nOnly tap 'DELETE EVERYTHING' if you absolutely understand the consequences.\")","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":110,"character":1},"reason":"Line should be 200 characters or less; currently it has 708 characters"}},{"text":" Text(\"This will remove summaries and transcripts for recordings that no longer exist. This action cannot be undone.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":123,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" Text(\"This will scan for duplicate summaries and transcripts for the same recording and keep only the most recent one.\\n\\nThis is useful after failed summarization runs that may have created multiple entries.\\n\\nThis action cannot be undone.\")","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":132,"character":1},"reason":"Line should be 200 characters or less; currently it has 259 characters"}},{"text":" Text(\"This will upload ALL local summaries to iCloud. This is useful for:\\n\\nβ€’ Initial setup on a new device\\nβ€’ After restoring from backup\\nβ€’ Manual full synchronization\\n\\nThis may take several minutes depending on the number of summaries.\")","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":147,"character":1},"reason":"Line should be 200 characters or less; currently it has 259 characters"}},{"text":" let result = try await legacyiCloudManager.performFullCloudKitResetAndSync(appCoordinator: appCoordinator)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":154,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" AppLog.shared.dataMigration(\"CloudKit reset complete: deleted \\(result.deleted), uploaded \\(result.uploaded)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":155,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" Text(\"🚨 DESTRUCTIVE ACTION 🚨\\n\\nThis will:\\n\\n1️⃣ DELETE ALL summaries from iCloud\\n2️⃣ Upload fresh copies of all your current summaries\\n\\nThis is the nuclear option for fixing CloudKit sync issues. Use this when:\\n\\nβ€’ CloudKit has orphaned or duplicate data\\nβ€’ Sync is completely broken\\nβ€’ You want a clean slate\\n\\n⚠️ This cannot be undone and may take several minutes.\")","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":162,"character":1},"reason":"Line should be 200 characters or less; currently it has 386 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 18, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":186,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 14, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":196,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":226,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":235,"character":20},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":251,"character":20},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":272,"character":20},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":293,"character":20},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":318,"character":20},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":389,"character":20},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":406,"character":20},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":447,"character":20},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":465,"character":20},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":495,"character":24},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":552,"character":16},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":572,"character":16},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 18, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":590,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" Text(\"This will fetch summaries from iCloud and add any missing entries to your database. It will not overwrite existing local summaries.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":601,"character":1},"reason":"Line should be 120 characters or less; currently it has 151 characters"}},{"text":" Text(\"This will permanently delete \\(orphanedAudioFiles.count) orphaned audio files (\\(formatFileSize(totalOrphanedSize))). This action cannot be undone.\\n\\nThese files exist on disk but are not referenced in your Core Data database.\")","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":611,"character":1},"reason":"Line should be 200 characters or less; currently it has 247 characters"}},{"text":" Text(\"Successfully deleted \\(results.deleted) files, freeing \\(formatFileSize(results.totalSize)) of storage.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":622,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" Text(\"Deleted \\(results.deleted) files, freeing \\(formatFileSize(results.totalSize)) of storage.\\n\\nErrors: \\(results.errors.joined(separator: \", \"))\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":624,"character":1},"reason":"Line should be 120 characters or less; currently it has 171 characters"}},{"text":" \\(result.unsyncedLocalCount > 0 ? \"⚠️ \\(result.unsyncedLocalCount) local summaries not in iCloud\" : \"βœ… All local summaries are synced\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":650,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":673,"character":16},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":690,"character":16},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 18, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":708,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":718,"character":20},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":736,"character":16},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 18, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":754,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":804,"character":28},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":820,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":863,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" return \"Check for missing transcripts and summaries, import legacy files, view database information, or clear all data.\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":904,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" return \"Automatically repair the data integrity issues found during the scan to restore missing transcripts and summaries.\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":908,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" private func cleanupOrphanedData() async throws -> CleanupResults {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":972,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 15"}},{"text":" private func cleanupOrphanedData() async throws -> CleanupResults {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":972,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 93 lines"}},{"text":" AppLog.shared.dataMigration(\"Found \\(allSummaries.count) stored summaries and \\(allTranscripts.count) stored transcripts\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":983,"character":1},"reason":"Line should be 120 characters or less; currently it has 145 characters"}},{"text":" AppLog.shared.dataMigration(\"Found orphaned summary for recording ID: \\(recordingId?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":1003,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" AppLog.shared.dataMigration(\"Found orphaned transcript for recording ID: \\(recordingId?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":1030,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" AppLog.shared.dataMigration(\"Found valid transcript for recording ID: \\(recordingId?.uuidString ?? \"nil\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":1041,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" AppLog.shared.dataMigration(\"Found transcript for non-existent recording file: \\(recordingURL.lastPathComponent)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":1062,"character":1},"reason":"Line should be 120 characters or less; currently it has 145 characters"}},{"text":" AppLog.shared.dataMigration(\"File not found on disk but recording exists in Core Data: \\(recordingURL.lastPathComponent)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":1073,"character":1},"reason":"Line should be 120 characters or less; currently it has 153 characters"}},{"text":" guard let _ = recording.recordingURL,","violation":{"ruleName":"Unused Optional Binding","severity":"warning","ruleDescription":"Prefer `!= nil` over `let _ =`","ruleIdentifier":"unused_optional_binding","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":1080,"character":23},"reason":"Prefer `!= nil` over `let _ =`"}},{"text":" AppLog.shared.dataMigration(\"Found orphaned recording (no file, no transcript, no summary)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":1096,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" AppLog.shared.dataMigration(\"Keeping recording with missing file (has transcript: \\(hasTranscript), has summary: \\(hasSummary))\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":1106,"character":1},"reason":"Line should be 120 characters or less; currently it has 164 characters"}},{"text":" AppLog.shared.dataMigration(\"Cleanup complete: removed \\(orphanedSummaries) summaries, \\(orphanedTranscripts) transcripts, \\(orphanedRecordings) recordings, freed \\(String(format: \"%.1f\", freedSpaceMB)) MB\")","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":1113,"character":1},"reason":"Line should be 200 characters or less; currently it has 215 characters"}},{"text":" AppLog.shared.dataMigration(\"Sync verification complete: local=\\(result.localCount), cloud=\\(result.cloudCount), synced=\\(result.syncedCount), unsynced=\\(result.unsyncedLocalCount), cloudOnly=\\(result.cloudOnlyCount)\")","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":1153,"character":1},"reason":"Line should be 200 characters or less; currently it has 230 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"error","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/DataMigrationView.swift","line":1226,"character":1},"reason":"File should contain 1000 lines or less: currently contains 1226"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/EnhancedDeleteDialog.swift","line":69,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/EnhancedDeleteDialog.swift","line":98,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" Text(\"The summary will be preserved and can be accessed later, even without the original recording.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/EnhancedDeleteDialog.swift","line":105,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 12, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/EnhancedDeleteDialog.swift","line":132,"character":1},"reason":"Line should be 120 characters or less; currently it has 145 characters"}},{"text":" AppLog.shared.fileManagement(\"EnhancedDeleteDialog rendering: hasRecording=\\(relationships.hasRecording), hasTranscript=\\(relationships.transcriptExists), hasSummary=\\(relationships.summaryExists), preserveSummary=\\(preserveSummary)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/EnhancedDeleteDialog.swift","line":152,"character":1},"reason":"Line should be 200 characters or less; currently it has 261 characters"}},{"text":"struct MistralOnboardingView: View {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","line":13,"character":1},"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 476 lines"}},{"text":" .fill(step == currentStep ? Color.orange : (step < currentStep ? Color.orange.opacity(0.5) : Color(.systemGray4)))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","line":72,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" benefitRow(icon: \"waveform\", title: \"Audio Transcription\", detail: \"Voxtral Mini with speaker diarization\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","line":102,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" benefitRow(icon: \"doc.text\", title: \"AI Summaries\", detail: \"Automatic summaries, tasks, and reminders\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","line":103,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" benefitRow(icon: \"gift\", title: \"Free Tier Included\", detail: \"No credit card, all models, 500K tokens\/min\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","line":104,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" Button(action: { withAnimation { currentStep = 1 } }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","line":125,"character":71},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" Text(\"Create a free Mistral AI account on their console. You'll just need an email and phone number.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","line":149,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","line":174,"character":20},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" Button(action: { withAnimation { currentStep = 0 } }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","line":187,"character":75},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","line":195,"character":24},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","line":258,"character":20},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" Button(action: { withAnimation { currentStep = 1 } }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","line":271,"character":75},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","line":279,"character":24},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" Button(action: { withAnimation { currentStep = 2 } }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","line":386,"character":75},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","line":395,"character":28},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","line":457,"character":20},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/MistralOnboardingView.swift","line":576,"character":1},"reason":"File should contain 400 lines or less: currently contains 576"}},{"text":" private let mlxModel: MLXModelOption = MLXModelOption.available.first { $0.id == MLXSwiftSettingsKeys.defaultModelId }","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/OnDeviceAIDownloadView.swift","line":20,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" Text(\"To use on-device AI, we need to download two models to your device. Downloads will continue in the background.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/OnDeviceAIDownloadView.swift","line":68,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" Text(\"You can close this screen and use the app. You'll receive a notification when both models are ready.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/OnDeviceAIDownloadView.swift","line":120,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/OnDeviceAIDownloadView.swift","line":150,"character":20},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" AppLog.shared.summarization(\"OnDeviceAIDownload: Starting MLX \\(mlxModel.displayName) download...\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/OnDeviceAIDownloadView.swift","line":218,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/PreferencesView.swift","line":93,"character":24},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/PreferencesView.swift","line":117,"character":12},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" .background(userPreferences.timeFormat == format ? Color.blue.opacity(0.12) : Color(.tertiarySystemGroupedBackground))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/PreferencesView.swift","line":148,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":"struct RecordingsListView: View {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":19,"character":1},"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 1417 lines"}},{"text":" await deleteRecordingWithRelationships(recording, preserveSummary: preserveSummaryOnDelete)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":111,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" let recommendedRecording = recommended == recordings.first.url ? recordings.first : recordings.second","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":169,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" archiveExportURLs = RecordingArchiveService.shared.prepareArchiveExportURLs(for: recordingsToArchive)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":188,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" let locationText = location.map { \"\\nSaved location: \\($0.providerDisplayName) \/ \\($0.displayName)\" } ?? \"\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":220,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" Text(\"\\(note)\\(dateStr.isEmpty ? \"\" : \" on \\(dateStr)\")\\(locationText)\\n\\nThe audio file is no longer stored locally. Use the download button to restore it, or use \\\"Import Audio Files\\\" if the file was moved.\")","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":221,"character":1},"reason":"Line should be 200 characters or less; currently it has 231 characters"}},{"text":" EditableTranscriptView(recording: entry, transcript: transcript, transcriptManager: TranscriptManager.shared)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":235,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" transcriptionStarter.startTranscription(for: recording, cleanFirst: true, appCoordinator: appCoordinator)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":252,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" transcriptionStarter.startTranscription(for: recording, cleanFirst: false, appCoordinator: appCoordinator)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":258,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" Text(\"Cleaning reduces static and normalizes volume, which can improve transcription accuracy. The original audio file is not changed.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":265,"character":1},"reason":"Line should be 120 characters or less; currently it has 152 characters"}},{"text":" .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(\"RecordingCloudSyncPreferenceChanged\"))) { _ in","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":290,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" Button(action: { showDateFilter = true }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":383,"character":55},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" Image(systemName: isDateFilterActive ? \"line.3.horizontal.decrease.circle.fill\" : \"line.3.horizontal.decrease.circle\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":384,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 10, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":387,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":398,"character":24},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":408,"character":20},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":417,"character":20},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":423,"character":20},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 10, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":430,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":436,"character":16},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 10, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":440,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" return \"No recordings found between \\(dateFilterStart.formatted(date: .abbreviated, time: .omitted)) and \\(dateFilterEnd.formatted(date: .abbreviated, time: .omitted)).\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":522,"character":1},"reason":"Line should be 120 characters or less; currently it has 181 characters"}},{"text":" Text(\"\\(dateFilterStart, format: .dateTime.month().day()) - \\(dateFilterEnd, format: .dateTime.month().day())\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":532,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":538,"character":16},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 12, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":544,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" DatePicker(\"To\", selection: $dateFilterEnd, in: dateFilterStart...Date(), displayedComponents: .date)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":556,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 14, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":559,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" private func recordingRow(for recording: AudioRecordingFile) -> some View {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":625,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 83 lines"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":719,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" Label(\"\\(location.providerDisplayName) \/ \\(location.displayName)\", systemImage: \"externaldrive.badge.checkmark\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":814,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" private func recordingActionButtons(for recording: AudioRecordingFile) -> some View {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":830,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 69 lines"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":845,"character":16},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" .background(Color.accentColor.opacity(0.12), in: RoundedRectangle(cornerRadius: 10, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":853,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" private func transcriptActionButton(for recording: AudioRecordingFile) -> some View {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":955,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 51 lines"}},{"text":" let jobStatus = transcriptionStarter.activeTranscriptionJobStatus(for: entry, appCoordinator: appCoordinator)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":962,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":979,"character":16},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" let endOfDay = Calendar.current.date(bySettingHour: 23, minute: 59, second: 59, of: dateFilterEnd) ?? dateFilterEnd","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":1041,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" archiveRestoreError = \"The export completed, but the selected destination was not iCloud Drive or was not trackable. The audio was left local so you can archive it again to iCloud Drive.\"","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":1092,"character":1},"reason":"Line should be 200 characters or less; currently it has 203 characters"}},{"text":" let skippedText = audioExportSkippedCount == 1 ? \"1 selected recording was\" : \"\\(audioExportSkippedCount) selected recordings were\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":1107,"character":1},"reason":"Line should be 120 characters or less; currently it has 147 characters"}},{"text":" archiveRestoreError = \"\\(skippedText) not exported because the audio is not stored locally. Restore archived audio before exporting it.\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":1108,"character":1},"reason":"Line should be 120 characters or less; currently it has 152 characters"}},{"text":" private func loadRecordings() {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":1118,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 70 lines"}},{"text":" var bestByFilename: [String: (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)] = [:]","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":1123,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" var bestByFilename: [String: (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)] = [:]","violation":{"ruleName":"Large Tuple","severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":1123,"character":38},"reason":"Tuples should have at most 2 members"}},{"text":" func score(_ e: (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)) -> Int {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":1125,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" func score(_ e: (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)) -> Int {","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":1125,"character":22},"reason":"Variable name 'e' should be between 3 and 40 characters long"}},{"text":" func score(_ e: (recording: RecordingEntry, transcript: TranscriptData?, summary: EnhancedSummaryData?)) -> Int {","violation":{"ruleName":"Large Tuple","severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":1125,"character":25},"reason":"Tuples should have at most 2 members"}},{"text":" var s = 0","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":1126,"character":17},"reason":"Variable name 's' should be between 3 and 40 characters long"}},{"text":" guard let _ = recording.locationData else { return false }","violation":{"ruleName":"Unused Optional Binding","severity":"warning","ruleDescription":"Prefer `!= nil` over `let _ =`","ruleIdentifier":"unused_optional_binding","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":1273,"character":23},"reason":"Prefer `!= nil` over `let _ =`"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 12, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":1405,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" message: \"These recordings cannot be combined because:\\n\\n\\(issues.joined(separator: \"\\n\"))\\n\\nPlease delete the transcripts and\/or summaries from both recordings before combining them.\"","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":1467,"character":1},"reason":"Line should be 200 characters or less; currently it has 202 characters"}},{"text":" archiveRestoreError = \"No local audio files are available to export. Restore archived audio before exporting it.\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":1549,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":1608,"character":20},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":"}","violation":{"ruleName":"File Length","severity":"error","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsListView.swift","line":1632,"character":1},"reason":"File should contain 1000 lines or less: currently contains 1632"}},{"text":"struct RecordingsView: View {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsView.swift","line":11,"character":1},"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 582 lines"}},{"text":" Button(action: { recorderVM.startRecording() }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsView.swift","line":116,"character":57},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsView.swift","line":213,"character":28},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(\"ImportTranscriptFromMenu\"))) { _ in","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsView.swift","line":375,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsView.swift","line":503,"character":12},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" return \"Call ended (\\(Int(duration\/60))m \\(Int(duration.truncatingRemainder(dividingBy: 60)))s) - Choose action\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsView.swift","line":626,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/RecordingsView.swift","line":668,"character":1},"reason":"File should contain 400 lines or less: currently contains 668"}},{"text":"struct SettingsView: View {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":15,"character":1},"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 1331 lines"}},{"text":" Text(\"BisonNotes AI and uploads to iCloud are not HIPAA-compliant. When iCloud Sync is enabled, eligible recordings, transcripts, summaries, and selected settings may be uploaded to your private iCloud account. To exclude an item from BisonNotes iCloud sync and backup, mark it Keep on This Device from its recording row or audio player.\")","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":106,"character":1},"reason":"Line should be 200 characters or less; currently it has 351 characters"}},{"text":" message: Text(\"BisonNotes needs macOS Screen Recording permission to capture audio playing from other Mac apps during a recording. BisonNotes records audio only and does not save screen video.\"),","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":113,"character":1},"reason":"Line should be 200 characters or less; currently it has 215 characters"}},{"text":" message: Text(\"macOS did not grant Screen Recording permission, so BisonNotes will keep recording microphone audio only. Enable BisonNotes in System Settings > Privacy & Security > Screen & System Audio Recording, then return to BisonNotes. You may need to restart the app after changing this setting.\"),","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":124,"character":1},"reason":"Line should be 200 characters or less; currently it has 324 characters"}},{"text":" let currentModelId = UserDefaults.standard.string(forKey: OnDeviceLLMModelInfo.SettingsKeys.selectedModelId) ?? \"\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":161,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" ModernStatusPill(text: iCloudManager.isEnabled ? \"Enabled\" : \"Disabled\", tint: iCloudManager.isEnabled ? .green : .secondary)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":401,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" ) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":403,"character":11},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" Text(\"API keys and AWS credentials stay in Keychain and are never included in iCloud settings backups. Leave sensitive settings off unless you explicitly want eligible future sensitive preferences copied to iCloud.\")","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":420,"character":1},"reason":"Line should be 200 characters or less; currently it has 232 characters"}},{"text":" Text(\"Exposes experimental on-device models. Experimental models are less reliable and may produce empty summaries.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":552,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" Image(systemName: recorderVM.selectedInput?.uid == input.uid ? \"largecircle.fill.circle\" : \"circle\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":693,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" Text(\"API keys and AWS credentials stay in Keychain and are never included in iCloud settings backups. Leave sensitive settings off unless you explicitly want eligible future sensitive preferences copied to iCloud.\")","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":813,"character":1},"reason":"Line should be 200 characters or less; currently it has 232 characters"}},{"text":" message: \"We found \\(cloudOnlySummaries.count) summaries in your iCloud that aren't on this device. Would you like to download them?\",","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":915,"character":1},"reason":"Line should be 120 characters or less; currently it has 174 characters"}},{"text":" let count = try await iCloudManager.downloadSummariesFromCloud(appCoordinator: appCoordinator, forRecovery: true)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":921,"character":1},"reason":"Line should be 120 characters or less; currently it has 169 characters"}},{"text":" AppLog.shared.log(\"Downloaded \\(count) summaries from iCloud\", category: .general)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":922,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" AppLog.shared.log(\"Failed to download summaries: \\(error)\", level: .error, category: .general)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":924,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" AppLog.shared.log(\"Failed to check for iCloud data: \\(error)\", level: .error, category: .general)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":940,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" Text(\"Make AI summaries entertaining with a comedic twist. All information is preserved β€” just delivered with flair.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":993,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" Text(\"Exposes experimental models in the On Device AI (Legacy) engine and the smaller Ternary Bonsai 1.7B model in the On Device AI engine. Experimental models are less reliable and may produce empty summaries.\")","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":1001,"character":1},"reason":"Line should be 200 characters or less; currently it has 224 characters"}},{"text":" ) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":1055,"character":31},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" guard let url = URL(string: \"x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture\") else {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":1247,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" \"Backup complete: \\(result.recordingsBackedUp) recordings, \\(result.transcriptsBackedUp) transcripts, \\(result.summariesBackedUp) summaries, \\(result.audioFilesBackedUp) audio uploaded\\(unchangedAudioText), \\(settingsText).\"","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":1311,"character":1},"reason":"Line should be 200 characters or less; currently it has 244 characters"}},{"text":" \"Restore complete: \\(result.recordingsRestored) recordings, \\(result.transcriptsRestored) transcripts, \\(result.summariesRestored) summaries, \\(result.audioFilesRestored) audio files, \\(settingsText)\\(reviewText).\"","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":1351,"character":1},"reason":"Line should be 200 characters or less; currently it has 234 characters"}},{"text":" message: \"We found \\(cloudOnlySummaries.count) summaries in your iCloud that aren't on this device. Would you like to download them?\",","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":1377,"character":1},"reason":"Line should be 120 characters or less; currently it has 162 characters"}},{"text":" let count = try await iCloudManager.downloadSummariesFromCloud(appCoordinator: appCoordinator, forRecovery: true)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":1383,"character":1},"reason":"Line should be 120 characters or less; currently it has 157 characters"}},{"text":" AppLog.shared.log(\"Downloaded \\(count) summaries from iCloud\", category: .general)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":1384,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" AppLog.shared.log(\"Failed to download summaries: \\(error)\", level: .error, category: .general)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":1386,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" ) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":1429,"character":23},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" Text(\"This removes app-created iCloud sync records for the selected item. It does not delete anything already stored locally on this device.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":1604,"character":1},"reason":"Line should be 120 characters or less; currently it has 158 characters"}},{"text":" actionMessage = \"Restored \\(result.recordingsRestored) recordings, \\(result.transcriptsRestored) transcripts, \\(result.summariesRestored) summaries.\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":1631,"character":1},"reason":"Line should be 120 characters or less; currently it has 165 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"error","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SettingsView.swift","line":1964,"character":1},"reason":"File should contain 1000 lines or less: currently contains 1964"}},{"text":"struct SimpleSettingsView: View {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":69,"character":1},"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 501 lines"}},{"text":" NotificationCenter.default.post(name: NSNotification.Name(\"RequestLocationPermission\"), object: nil)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":182,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" Text(\"On-Device AI requires 6GB+ RAM. Your device has \\(String(format: \"%.1f\", DeviceCapabilities.totalRAMInGB))GB RAM.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":300,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" subtitle: \"Free cloud AI with transcription and summaries. No credit card required -- just create an account.\",","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":338,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" subtitle: \"Configure providers manually from app settings. Existing provider configuration is preserved.\",","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":367,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":386,"character":16},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" let transcriptionEngine = UserDefaults.standard.string(forKey: \"selectedTranscriptionEngine\") ?? \"Not Configured\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":492,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" else if transcriptionEngine == TranscriptionEngine.fluidAudio.rawValue && aiEngine == AIEngineType.onDeviceLLM.rawValue {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":504,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" else if transcriptionEngine == TranscriptionEngine.fluidAudio.rawValue && aiEngine == AIEngineType.appleNative.rawValue {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":508,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" private func saveConfiguration() {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":517,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 14"}},{"text":" private func saveConfiguration() {","violation":{"ruleName":"Function Body Length","severity":"error","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":517,"character":13},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 105 lines"}},{"text":" UserDefaults.standard.set(TranscriptionEngine.fluidAudio.rawValue, forKey: \"selectedTranscriptionEngine\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":577,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" UserDefaults.standard.set(MLXSwiftSettingsKeys.defaultModelId, forKey: MLXSwiftSettingsKeys.modelId)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":599,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" NotificationCenter.default.post(name: NSNotification.Name(\"FirstSetupCompleted\"), object: nil)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":627,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" NotificationCenter.default.post(name: NSNotification.Name(\"RequestLocationPermission\"), object: nil)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":630,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" NotificationCenter.default.post(name: NSNotification.Name(\"FirstSetupCompleted\"), object: nil)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":643,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" NotificationCenter.default.post(name: NSNotification.Name(\"RequestLocationPermission\"), object: nil)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":646,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/SimpleSettingsView.swift","line":827,"character":1},"reason":"File should contain 400 lines or less: currently contains 827"}},{"text":"struct TranscriptsView: View {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":25,"character":1},"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 1159 lines"}},{"text":" EditableTranscriptView(recording: recording, transcript: transcript, transcriptManager: TranscriptManager.shared)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":62,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" transcriptionStarter.startTranscription(for: recording, cleanFirst: true, appCoordinator: appCoordinator)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":85,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" transcriptionStarter.startTranscription(for: recording, cleanFirst: false, appCoordinator: appCoordinator)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":91,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" Text(\"Cleaning reduces static and normalizes volume, which can improve transcription accuracy. The original audio file is not changed.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":98,"character":1},"reason":"Line should be 120 characters or less; currently it has 148 characters"}},{"text":" Text(completedTranscriptionText.isEmpty ? \"A background transcription has completed. The transcript is now available for editing.\" : completedTranscriptionText)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":106,"character":1},"reason":"Line should be 120 characters or less; currently it has 172 characters"}},{"text":" Button(action: { showDateFilter = true }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":134,"character":59},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" Image(systemName: isDateFilterActive ? \"line.3.horizontal.decrease.circle.fill\" : \"line.3.horizontal.decrease.circle\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":135,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" return \"No transcripts found between \\(dateFilterStart.formatted(date: .abbreviated, time: .omitted)) and \\(dateFilterEnd.formatted(date: .abbreviated, time: .omitted)).\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":241,"character":1},"reason":"Line should be 120 characters or less; currently it has 182 characters"}},{"text":" Text(\"\\(dateFilterStart, format: .dateTime.month().day()) - \\(dateFilterEnd, format: .dateTime.month().day())\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":251,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":257,"character":16},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" DatePicker(\"To\", selection: $dateFilterEnd, in: dateFilterStart...Date(), displayedComponents: .date)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":272,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" private func transcriptsListView(_ filtered: [(recording: RecordingEntry, transcript: TranscriptData?)], _ filteredImported: [(recording: RecordingEntry, transcript: TranscriptData?)]) -> some View {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":310,"character":1},"reason":"Line should be 200 characters or less; currently it has 203 characters"}},{"text":" private func transcriptsListView(_ filtered: [(recording: RecordingEntry, transcript: TranscriptData?)], _ filteredImported: [(recording: RecordingEntry, transcript: TranscriptData?)]) -> some View {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":310,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 80 lines"}},{"text":" transcriptItemsWithDates(filtered, source: .audio) + transcriptItemsWithDates(filteredImported, source: .imported),","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":315,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" recordingRowView((recording: itemWithDate.recording, transcript: itemWithDate.transcript))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":436,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" Button(action: { showDateFilter = true }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":452,"character":59},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" Image(systemName: isDateFilterActive ? \"line.3.horizontal.decrease.circle.fill\" : \"line.3.horizontal.decrease.circle\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":453,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" importedTranscriptRowView((recording: itemWithDate.recording, transcript: itemWithDate.transcript))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":493,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" Button(action: { showDateFilter = true }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":516,"character":59},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" Image(systemName: isDateFilterActive ? \"line.3.horizontal.decrease.circle.fill\" : \"line.3.horizontal.decrease.circle\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":517,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" private func recordingRowView(_ recordingData: (recording: RecordingEntry, transcript: TranscriptData?)) -> some View {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":628,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" private func importedTranscriptRowView(","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":657,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 57 lines"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":664,"character":16},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" private func recordingInfoView(_ recordingData: (recording: RecordingEntry, transcript: TranscriptData?)) -> some View {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":760,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":799,"character":12},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" private func transcriptButtonView(_ recordingData: (recording: RecordingEntry, transcript: TranscriptData?)) -> some View {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":813,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" let hasActiveJob = transcriptionStarter.hasActiveTranscriptionJob(for: recordingData.recording, appCoordinator: appCoordinator)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":815,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" let jobStatus = transcriptionStarter.activeTranscriptionJobStatus(for: recordingData.recording, appCoordinator: appCoordinator)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":819,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":832,"character":12},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" Text(processingButtonLabel(isCleaning: isCleaning, isQueuedForCleanup: isQueuedForCleanup, jobStatus: jobStatus))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":838,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" .id(\"\\(recordingData.recording.id?.uuidString ?? \"unknown\")-\\(hasTranscript)-\\(hasActiveJob)-\\(isCleaning)-\\(isQueuedForCleanup)-\\(refreshTrigger)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":860,"character":1},"reason":"Line should be 120 characters or less; currently it has 156 characters"}},{"text":" private func processingButtonLabel(isCleaning: Bool, isQueuedForCleanup: Bool, jobStatus: JobProcessingStatus?) -> String {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":881,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" private func summaryButtonView(_ recordingData: (recording: RecordingEntry, transcript: TranscriptData?)) -> some View {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":908,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":923,"character":16},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" AppLog.shared.summarization(\"Failed to queue summary job from TranscriptsView row: \\(error)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1005,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" private func applyFilters(to items: [(recording: RecordingEntry, transcript: TranscriptData?)]) -> [(recording: RecordingEntry, transcript: TranscriptData?)] {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1023,"character":1},"reason":"Line should be 120 characters or less; currently it has 163 characters"}},{"text":" let endOfDay = Calendar.current.date(bySettingHour: 23, minute: 59, second: 59, of: dateFilterEnd) ?? dateFilterEnd","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1029,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" private func matchesSearch(_ recordingData: (recording: RecordingEntry, transcript: TranscriptData?), searchTerms: String) -> Bool {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1049,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":"\t\t\tvar s = 0","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1083,"character":8},"reason":"Variable name 's' should be between 3 and 40 characters long"}},{"text":"\t\tfor rd in recordingsWithData {","violation":{"ruleName":"Identifier Name","severity":"warning","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1091,"character":7},"reason":"Variable name 'rd' should be between 3 and 40 characters long"}},{"text":"\t\tlet (imported, regular) = deduped.reduce(into: (imported: [(RecordingEntry, TranscriptData?)](), regular: [(RecordingEntry, TranscriptData?)]())) { result, item in","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1112,"character":1},"reason":"Line should be 120 characters or less; currently it has 165 characters"}},{"text":" let _ = appCoordinator.loadLocationData(for: recording) else { return false }","violation":{"ruleName":"Unused Optional Binding","severity":"warning","ruleDescription":"Prefer `!= nil` over `let _ =`","ruleIdentifier":"unused_optional_binding","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1208,"character":23},"reason":"Prefer `!= nil` over `let _ =`"}},{"text":" guard !transcriptionStarter.hasActiveTranscriptionJob(for: recording, appCoordinator: appCoordinator) else { return }","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1254,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" private func setupTranscriptionCompletionCallback() {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1261,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 89 lines"}},{"text":" AppLog.shared.transcription(\"Background transcript already saved by BackgroundProcessingManager\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1299,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" self.completedTranscriptionText = \"Transcription completed for: \\(recording.recording.recordingName ?? \"Unknown Recording\")\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1311,"character":1},"reason":"Line should be 120 characters or less; currently it has 148 characters"}},{"text":" AppLog.shared.transcription(\"Background transcription completed, available recordings: \\(recordings.count)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1323,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" AppLog.shared.transcription(\"Background transcript saved to Core Data with ID: \\(transcriptId!)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1360,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" self.completedTranscriptionText = \"Transcription completed for: \\(recording.recording.recordingName ?? \"Unknown Recording\")\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1373,"character":1},"reason":"Line should be 120 characters or less; currently it has 148 characters"}},{"text":"struct EditableTranscriptView: View {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1384,"character":1},"reason":"Struct body should span 350 lines or less excluding comments and whitespace: currently spans 551 lines"}},{"text":" let s = seg.speaker","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1413,"character":17},"reason":"Variable name 's' should be between 3 and 40 characters long"}},{"text":" Text(\"This will replace the current transcript with a new transcription using the currently configured transcription service. This action cannot be undone.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1475,"character":1},"reason":"Line should be 120 characters or less; currently it has 169 characters"}},{"text":" .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(\"TranscriptionRerunCompleted\"))) { notification in","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1554,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" NotificationCenter.default.post(name: NSNotification.Name(\"TranscriptReplacementCompleted\"), object: nil)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1565,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" AppLog.shared.summarization(\"Failed to queue summary job from EditableTranscriptView: \\(error)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1764,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" AppLog.shared.transcription(\"Failed to update recording title from transcript editor: \\(error)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1837,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" private func rerunTranscription() {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1842,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 52 lines"}},{"text":" let selectedEngine = TranscriptionEngine(rawValue: UserDefaults.standard.string(forKey: \"selectedTranscriptionEngine\") ?? TranscriptionEngine.fluidAudio.rawValue) ?? .fluidAudio","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1850,"character":1},"reason":"Line should be 120 characters or less; currently it has 193 characters"}},{"text":" AppLog.shared.transcription(\"Rerunning transcription for file: \\(recordingURL.lastPathComponent)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1863,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" AppLog.shared.transcription(\"Invalid recording URL for fallback transcription rerun\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1884,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" let selectedEngine = TranscriptionEngine(rawValue: UserDefaults.standard.string(forKey: \"selectedTranscriptionEngine\") ?? TranscriptionEngine.fluidAudio.rawValue) ?? .fluidAudio","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1892,"character":1},"reason":"Line should be 120 characters or less; currently it has 197 characters"}},{"text":" let result = try await enhancedTranscriptionManager.transcribeAudioFile(at: recordingURL, using: selectedEngine)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1894,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" AppLog.shared.transcription(\"Transcription rerun result: success=\\(result.success), textLength=\\(result.fullText.count)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1896,"character":1},"reason":"Line should be 120 characters or less; currently it has 156 characters"}},{"text":" NotificationCenter.default.post(name: NSNotification.Name(\"TranscriptReplacementCompleted\"), object: nil)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1906,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" AppLog.shared.transcription(\"Transcription rerun failed or returned empty result\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1909,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" let engineString = UserDefaults.standard.string(forKey: \"selectedTranscriptionEngine\") ?? TranscriptionEngine.fluidAudio.rawValue","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":1978,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" AppLog.shared.transcription(\"Could not find recording entry in Core Data for transcript save\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":2003,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" let hasValidContent = updatedTranscript.segments.contains { !$0.text.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines).isEmpty }","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":2021,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" let s = segment.speaker","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":2042,"character":13},"reason":"Variable name 's' should be between 3 and 40 characters long"}},{"text":" let s = segment.speaker","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":2051,"character":13},"reason":"Variable name 's' should be between 3 and 40 characters long"}},{"text":" .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":2107,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" Section(header: Text(\"Rename Speakers\"), footer: Text(\"Enter a name for each speaker. Changes apply to the entire transcript and are used in AI summaries.\")) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":2214,"character":1},"reason":"Line should be 120 characters or less; currently it has 171 characters"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":2395,"character":24},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":" }) {","violation":{"ruleName":"Multiple Closures with Trailing Closure","severity":"warning","ruleDescription":"Trailing closure syntax should not be used when passing more than one closure argument","ruleIdentifier":"multiple_closures_with_trailing_closure","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":2464,"character":24},"reason":"Trailing closure syntax should not be used when passing more than one closure argument"}},{"text":"}","violation":{"ruleName":"File Length","severity":"error","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Views\/TranscriptViews.swift","line":2496,"character":1},"reason":"File should contain 1000 lines or less: currently contains 2496"}},{"text":" private func handleWatchRecordingReceived(fileURL: URL, metadata: [String: Any]) {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift","line":121,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 71 lines"}},{"text":" AppLog.shared.watchConnectivity(\"Recording \\(recordingId) already imported - re-acking instead of re-importing\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift","line":131,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" AppLog.shared.watchConnectivity(\"Recording \\(recordingId) import already in flight - ignoring duplicate\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift","line":141,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" let backgroundTaskID = UIApplication.shared.beginBackgroundTask(withName: \"WatchFileProcessing\") { [weak self] in","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift","line":158,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" AppLog.shared.watchConnectivity(\"onWatchSyncRecordingReceived callback is nil - file will not be processed\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift","line":207,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" AppLog.shared.watchConnectivity(\"Failed to read received file: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift","line":212,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" AppLog.shared.watchConnectivity(\"Cannot send command - watch not reachable or session not activated\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift","line":309,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.watchConnectivity(\"Unknown or missing message type from watch: \\(message[\"messageType\"] ?? \"nil\")\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift","line":352,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" nonisolated func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift","line":383,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" AppLog.shared.watchConnectivity(\"WCSession activation failed: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift","line":386,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" nonisolated func session(_ session: WCSession, didReceiveMessage message: [String: Any], replyHandler: @escaping ([String: Any]) -> Void) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift","line":438,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"text":" nonisolated func session(_ session: WCSession, didFinish userInfoTransfer: WCSessionUserInfoTransfer, error: Error?) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift","line":466,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" let stagingDir = fileManager.temporaryDirectory.appendingPathComponent(\"WatchTransferStaging\", isDirectory: true)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift","line":491,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" AppLog.shared.watchConnectivity(\"Failed to stage received watch file: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift","line":498,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WatchConnectivity\/WatchConnectivityManager.swift","line":519,"character":1},"reason":"File should contain 400 lines or less: currently contains 519"}},{"text":"struct WebImportDownloader {","violation":{"ruleName":"Type Body Length","severity":"warning","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WebImportDownloader.swift","line":10,"character":1},"reason":"Struct body should span 250 lines or less excluding comments and whitespace: currently spans 273 lines"}},{"text":" let avg_logprob: Double?","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":102,"character":9},"reason":"Variable name 'avg_logprob' should only contain alphanumeric and other allowed characters"}},{"text":" let compression_ratio: Double?","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":103,"character":9},"reason":"Variable name 'compression_ratio' should only contain alphanumeric and other allowed characters"}},{"text":" let no_speech_prob: Double?","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":104,"character":9},"reason":"Variable name 'no_speech_prob' should only contain alphanumeric and other allowed characters"}},{"text":" let detected_language: String","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":109,"character":9},"reason":"Variable name 'detected_language' should only contain alphanumeric and other allowed characters"}},{"text":" let language_code: String","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":110,"character":9},"reason":"Variable name 'language_code' should only contain alphanumeric and other allowed characters"}},{"text":"class WhisperService: ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":117,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 539 lines"}},{"text":" AppLog.shared.transcription(\"WhisperService init - Config: URL='\\(config.serverURL)', Port=\\(config.port), Protocol=\\(config.whisperProtocol.rawValue)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":132,"character":1},"reason":"Line should be 120 characters or less; currently it has 175 characters"}},{"text":" AppLog.shared.transcription(\"REST connection test HTTP status: \\(httpResponse.statusCode)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":201,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" private func performRESTTranscription(url: URL) async throws -> TranscriptionResult {","violation":{"ruleName":"Cyclomatic Complexity","severity":"error","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":354,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 25"}},{"text":" private func performRESTTranscription(url: URL) async throws -> TranscriptionResult {","violation":{"ruleName":"Function Body Length","severity":"error","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":354,"character":13},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 241 lines"}},{"text":" AppLog.shared.transcription(\"Audio duration: \\(String(format: \"%.1f\", duration))s (\\(String(format: \"%.1f\", duration\/60)) minutes)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":364,"character":1},"reason":"Line should be 120 characters or less; currently it has 159 characters"}},{"text":" AppLog.shared.transcription(\"Processing \\(String(format: \"%.1f\", duration\/60)) minute file - expected processing time: ~\\(Int(duration\/60)) minutes\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":367,"character":1},"reason":"Line should be 120 characters or less; currently it has 165 characters"}},{"text":" let audioStreamBasicDescription = CMAudioFormatDescriptionGetStreamBasicDescription(formatDescription)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":390,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" AppLog.shared.transcription(\"Audio format - FormatID: \\(asbd.mFormatID), SampleRate: \\(asbd.mSampleRate)Hz, Channels: \\(asbd.mChannelsPerFrame), BitsPerChannel: \\(asbd.mBitsPerChannel), BytesPerFrame: \\(asbd.mBytesPerFrame), BytesPerPacket: \\(asbd.mBytesPerPacket)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":392,"character":1},"reason":"Line should be 200 characters or less; currently it has 305 characters"}},{"text":" AppLog.shared.transcription(\"Low sample rate: \\(asbd.mSampleRate)Hz - Whisper works best with 16kHz+\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":395,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" AppLog.shared.transcription(\"Uncommon audio format ID: \\(asbd.mFormatID) - Whisper prefers AAC or PCM\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":399,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" AppLog.shared.transcription(\"File metadata - Creation: \\((fileAttributes[FileAttributeKey.creationDate] as? Date).map { \"\\($0)\" } ?? \"unknown\"), Modified: \\((fileAttributes[FileAttributeKey.modificationDate] as? Date).map { \"\\($0)\" } ?? \"unknown\")\", level: .debug)","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":414,"character":1},"reason":"Line should be 200 characters or less; currently it has 276 characters"}},{"text":" body.append(\"--\\(boundary)\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":530,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"Content-Disposition: form-data; name=\\\"audio_file\\\"; filename=\\\"\\(url.lastPathComponent)\\\"\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":531,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" body.append(\"Content-Disposition: form-data; name=\\\"audio_file\\\"; filename=\\\"\\(url.lastPathComponent)\\\"\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":531,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"Content-Type: application\/octet-stream\\r\\n\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":532,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":534,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"--\\(boundary)--\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":535,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" AppLog.shared.transcription(\"Request completed suspiciously fast - expected ~\\(Int(duration\/60)) minutes, actual: \\(String(format: \"%.1f\", requestDuration))s\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":557,"character":1},"reason":"Line should be 120 characters or less; currently it has 190 characters"}},{"text":" AppLog.shared.transcription(\"Parsed response - text length: \\(whisperResponse.text.count) chars, segments: \\(whisperResponse.segments?.count ?? 0), language: \\(whisperResponse.language ?? \"unknown\")\")","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":603,"character":1},"reason":"Line should be 200 characters or less; currently it has 208 characters"}},{"text":" AppLog.shared.transcription(\"Whisper returned empty transcript - segments: \\(whisperResponse.segments?.count ?? 0), language: \\(whisperResponse.language ?? \"unknown\")\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":607,"character":1},"reason":"Line should be 120 characters or less; currently it has 180 characters"}},{"text":" func transcribeAudioInChunks(url: URL, chunkDuration: TimeInterval = 3600, recordingId: UUID? = nil) async throws -> TranscriptionResult {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":683,"character":1},"reason":"Line should be 120 characters or less; currently it has 142 characters"}},{"text":" func transcribeAudioInChunks(url: URL, chunkDuration: TimeInterval = 3600, recordingId: UUID? = nil) async throws -> TranscriptionResult {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":683,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 56 lines"}},{"text":" recordingId: recordingId ?? UUID() \/\/ TODO: Get actual recording ID from Core Data","violation":{"ruleName":"Todo","severity":"warning","ruleDescription":"TODOs and FIXMEs should be resolved.","ruleIdentifier":"todo","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":723,"character":55},"reason":"TODOs should be resolved (Get actual recording ID from C...)"}},{"text":" body.append(\"--\\(boundary)\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":777,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"Content-Disposition: form-data; name=\\\"audio_file\\\"; filename=\\\"\\(url.lastPathComponent)\\\"\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":778,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" body.append(\"Content-Disposition: form-data; name=\\\"audio_file\\\"; filename=\\\"\\(url.lastPathComponent)\\\"\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":778,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"Content-Type: application\/octet-stream\\r\\n\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":779,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":781,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" body.append(\"--\\(boundary)--\\r\\n\".data(using: .utf8)!)","violation":{"ruleName":"Non-optional String -> Data Conversion","severity":"warning","ruleDescription":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`","ruleIdentifier":"non_optional_string_data_conversion","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":782,"character":21},"reason":"Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`"}},{"text":" throw WhisperError.invalidResponse(\"Failed to parse language detection response: \\(error.localizedDescription)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":808,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" AppLog.shared.transcription(\"Language detection completed: \\(languageResponse.detected_language) (\\(languageResponse.language_code)) - confidence: \\(languageResponse.confidence)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":811,"character":1},"reason":"Line should be 120 characters or less; currently it has 187 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperService.swift","line":816,"character":1},"reason":"File should contain 400 lines or less: currently contains 816"}},{"text":"struct WhisperSettingsView: View {","violation":{"ruleName":"Type Body Length","severity":"warning","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperSettingsView.swift","line":10,"character":1},"reason":"Struct body should span 250 lines or less excluding comments and whitespace: currently spans 344 lines"}},{"text":" @AppStorage(EndpointSecurityPolicy.allowInsecurePublicEndpointsKey) private var allowInsecurePublicEndpoints: Bool = false","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperSettingsView.swift","line":15,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" _whisperService = State(initialValue: WhisperService(config: config, chunkingService: AudioFileChunkingService()))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperSettingsView.swift","line":49,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" Text(\"Whisper provides high-quality transcription using OpenAI's Whisper model via REST API. This service runs on your local server for privacy and performance.\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperSettingsView.swift","line":57,"character":1},"reason":"Line should be 120 characters or less; currently it has 186 characters"}},{"text":" TextField(selectedProtocol == .wyoming ? \"10300\" : \"9000\", value: $port, format: .number.grouping(.never))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperSettingsView.swift","line":188,"character":1},"reason":"Line should be 120 characters or less; currently it has 138 characters"}},{"text":" .fill(testResult.hasPrefix(\"βœ…\") ? Color.green.opacity(0.1) : Color.red.opacity(0.1))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperSettingsView.swift","line":259,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" Link(\"Wyoming Protocol Documentation\", destination: URL(string: \"https:\/\/github.com\/rhasspy\/wyoming-whisper\")!)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperSettingsView.swift","line":322,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" Link(\"Wyoming Protocol Specification\", destination: URL(string: \"https:\/\/github.com\/rhasspy\/wyoming\")!)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperSettingsView.swift","line":323,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" Link(\"Whisper REST API Documentation\", destination: URL(string: \"https:\/\/github.com\/guillaumekln\/faster-whisper\")!)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperSettingsView.swift","line":325,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" if serverURL.hasPrefix(\"ws:\/\/\") || serverURL.hasPrefix(\"wss:\/\/\") || serverURL.hasPrefix(\"http:\/\/\") || serverURL.hasPrefix(\"https:\/\/\") {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperSettingsView.swift","line":363,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/WhisperSettingsView.swift","line":447,"character":1},"reason":"File should contain 400 lines or less: currently contains 447"}},{"text":" init(type: WyomingMessageType, data: (any WyomingMessageData)? = nil, payload: Data? = nil, includeTimestamp: Bool = false) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingProtocol.swift","line":43,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: [], debugDescription: \"Cannot encode value\"))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingProtocol.swift","line":123,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" let supports_transcript_streaming: Bool?","violation":{"ruleName":"Identifier Name","severity":"error","ruleDescription":"Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters. In an exception to the above, variable names may start with a capital letter when they are declared as static. Variable names should not be too long or too short.","ruleIdentifier":"identifier_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingProtocol.swift","line":154,"character":9},"reason":"Variable name 'supports_transcript_streaming' should only contain alphanumeric and other allowed characters"}},{"text":" init(rate: Int = WyomingConstants.audioSampleRate, width: Int = WyomingConstants.audioBitDepth, channels: Int = WyomingConstants.audioChannels) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingProtocol.swift","line":228,"character":1},"reason":"Line should be 120 characters or less; currently it has 149 characters"}},{"text":" static func createAudioChunkMessage(audioData: Data, rate: Int = WyomingConstants.audioSampleRate, width: Int = WyomingConstants.audioBitDepth, channels: Int = WyomingConstants.audioChannels) -> WyomingMessage {","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingProtocol.swift","line":267,"character":1},"reason":"Line should be 200 characters or less; currently it has 215 characters"}},{"text":"class WyomingTCPClient: ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"warning","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingTCPClient.swift","line":51,"character":1},"reason":"Class body should span 250 lines or less excluding comments and whitespace: currently spans 291 lines"}},{"text":" AppLog.shared.transcription(\"Too many consecutive errors (\\(consecutiveErrors)), aborting batch send\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingTCPClient.swift","line":293,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" throw WyomingError.serverError(\"Network streaming failed after \\(consecutiveErrors) consecutive errors\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingTCPClient.swift","line":294,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.transcription(\"Chunk \\(index + 1) failed after \\(maxRetries) retries\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingTCPClient.swift","line":302,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" connection.receive(minimumIncompleteLength: 1, maximumLength: 65536) { [weak self] data, _, isComplete, error in","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingTCPClient.swift","line":325,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" let message = WyomingMessageFactory.createAudioChunkMessage(audioData: audioData, rate: rate, width: width, channels: channels)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingTCPClient.swift","line":435,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingTCPClient.swift","line":462,"character":1},"reason":"File should contain 400 lines or less: currently contains 462"}},{"text":" func connect() async throws {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWebSocketClient.swift","line":48,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 53 lines"}},{"text":" AppLog.shared.transcription(\"No handler registered for message type: \\(wyomingMessage.type)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWebSocketClient.swift","line":191,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":"class WyomingWhisperClient: ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":15,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 666 lines"}},{"text":" AppLog.shared.transcription(\"ASR: \\(asrInfo.name), version: \\(asrInfo.version ?? \"unknown\"), models: \\(asrInfo.models?.count ?? 0)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":114,"character":1},"reason":"Line should be 120 characters or less; currently it has 159 characters"}},{"text":" AppLog.shared.transcription(\"Audio duration (\\(Int(duration))s) exceeds \\(Int(maxChunkDuration))s, using chunked transcription\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":259,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" return try await transcribeAudioWithChunking(url: url, recordingId: recordingId, maxChunkDuration: maxChunkDuration)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":260,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.transcription(\"Audio duration (\\(Int(duration))s) is within limits, using standard transcription\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":262,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" private func transcribeAudioStandard(url: URL, recordingId: UUID? = nil) async throws -> TranscriptionResult {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":267,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 13"}},{"text":" private func transcribeAudioStandard(url: URL, recordingId: UUID? = nil) async throws -> TranscriptionResult {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":267,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 74 lines"}},{"text":" AppLog.shared.transcription(\"Wyoming client background task management disabled - parent is handling background tasks\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":278,"character":1},"reason":"Line should be 120 characters or less; currently it has 146 characters"}},{"text":" AppLog.shared.transcription(\"File size: \\(fileSize) bytes (\\(String(format: \"%.1f\", Double(fileSize) \/ (1024 * 1024)))MB)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":306,"character":1},"reason":"Line should be 120 characters or less; currently it has 146 characters"}},{"text":" AppLog.shared.transcription(\"Setting Wyoming timeout: \\(timeoutSeconds)s (\\(timeoutSeconds\/60) minutes)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":325,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.transcription(\"Disconnecting after transcription error\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":349,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" AppLog.shared.transcription(\"Streaming audio (\\(String(format: \"%.1f\", Double(audioData.count)\/1024\/1024))MB, \\(totalChunks) chunks)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":446,"character":1},"reason":"Line should be 120 characters or less; currently it has 157 characters"}},{"text":" CMBlockBufferCopyDataBytes(blockBuffer, atOffset: 0, dataLength: length, destination: bytes.baseAddress!)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":512,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" AppLog.shared.transcription(\"CMBlockBufferCopyDataBytes returned error: \\(result)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":516,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" private func transcribeAudioWithChunking(url: URL, recordingId: UUID?, maxChunkDuration: TimeInterval) async throws -> TranscriptionResult {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":545,"character":1},"reason":"Line should be 120 characters or less; currently it has 144 characters"}},{"text":" private func transcribeAudioWithChunking(url: URL, recordingId: UUID?, maxChunkDuration: TimeInterval) async throws -> TranscriptionResult {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":545,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 16"}},{"text":" private func transcribeAudioWithChunking(url: URL, recordingId: UUID?, maxChunkDuration: TimeInterval) async throws -> TranscriptionResult {","violation":{"ruleName":"Function Body Length","severity":"error","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":545,"character":13},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 137 lines"}},{"text":" AppLog.shared.transcription(\"Wyoming client managing its own background task for chunked transcription\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":551,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" AppLog.shared.transcription(\"Wyoming client background task management disabled - parent is handling chunked transcription\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":553,"character":1},"reason":"Line should be 120 characters or less; currently it has 151 characters"}},{"text":" AppLog.shared.transcription(\"Audio duration: \\(Int(totalDuration))s, splitting into \\(numberOfChunks) chunks of \\(Int(maxChunkDuration))s each\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":573,"character":1},"reason":"Line should be 120 characters or less; currently it has 152 characters"}},{"text":" AppLog.shared.transcription(\"Processing chunk \\(chunkIndex + 1)\/\\(numberOfChunks): \\(Int(chunkStartTime))s - \\(Int(chunkEndTime))s (\\(Int(chunkDuration))s)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":594,"character":1},"reason":"Line should be 120 characters or less; currently it has 184 characters"}},{"text":" try await createAudioChunk(sourceURL: url, outputURL: chunkURL, startTime: chunkStartTime, duration: chunkDuration)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":602,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" AppLog.shared.transcription(\"Disconnecting and reconnecting for chunk \\(chunkIndex + 1)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":609,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" AppLog.shared.transcription(\"Failed to establish fresh connection for chunk \\(chunkIndex + 1)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":619,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" AppLog.shared.transcription(\"Fresh connection established for chunk \\(chunkIndex + 1)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":622,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" AppLog.shared.transcription(\"Connection error detected for chunk \\(chunkIndex + 1), establishing fresh connection\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":662,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" AppLog.shared.transcription(\"Chunk \\(chunkIndex + 1) completed on retry: \\(adjustedSegments.count) segments\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":689,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" AppLog.shared.transcription(\"Retry also failed for chunk \\(chunkIndex + 1): \\(error)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":691,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" AppLog.shared.transcription(\"Could not reconnect for chunk \\(chunkIndex + 1) retry\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":696,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" AppLog.shared.transcription(\"Non-connection error for chunk \\(chunkIndex + 1), skipping retry: \\(error)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":700,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" AppLog.shared.transcription(\"Wyoming client not ending background task - parent is managing it\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":712,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" AppLog.shared.transcription(\"Chunked transcription completed: \\(mergedSegments.count) segments, \\(fullText.count) chars, \\(Int(finalProcessingTime))s\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":724,"character":1},"reason":"Line should be 120 characters or less; currently it has 159 characters"}},{"text":" private func createAudioChunk(sourceURL: URL, outputURL: URL, startTime: TimeInterval, duration: TimeInterval) async throws {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":741,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" AppLog.shared.transcription(\"Creating audio chunk: \\(Int(startTime))s - \\(Int(startTime + duration))s\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":742,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" if timeDifference < 2.0 && isSameSpeaker && !currentSegment.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":802,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" AppLog.shared.transcription(\"Merged \\(segments.count) segments into \\(mergedSegments.count) segments\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":817,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" AppLog.shared.transcription(\"Started Wyoming background task with \\(String(format: \"%.0f\", remainingTime))s remaining\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":850,"character":1},"reason":"Line should be 120 characters or less; currently it has 150 characters"}},{"text":" AppLog.shared.transcription(\"Started Wyoming background task with unlimited time remaining\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":852,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" AppLog.shared.transcription(\"Disconnecting after streaming timeout (no active transcription)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":951,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"warning","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/Wyoming\/WyomingWhisperClient.swift","line":959,"character":1},"reason":"File should contain 400 lines or less: currently contains 959"}},{"text":"class iCloudStorageManager: ObservableObject {","violation":{"ruleName":"Type Body Length","severity":"error","ruleDescription":"Type bodies should not span too many lines","ruleIdentifier":"type_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":140,"character":1},"reason":"Class body should span 350 lines or less excluding comments and whitespace: currently spans 1652 lines"}},{"text":"class iCloudStorageManager: ObservableObject {","violation":{"ruleName":"Type Name","severity":"error","ruleDescription":"Type name should only contain alphanumeric characters, start with an uppercase character and span between 3 and 40 characters in length.\nPrivate types may start with an underscore.","ruleIdentifier":"type_name","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":140,"character":7},"reason":"Type name 'iCloudStorageManager' should start with an uppercase character"}},{"text":" case disabled = \"disabled\"","violation":{"ruleName":"Redundant String Enum Value","severity":"warning","ruleDescription":"String enum values can be omitted when they are equal to the enumcase name","ruleIdentifier":"redundant_string_enum_value","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":200,"character":25},"reason":"String enum values can be omitted when they are equal to the enumcase name"}},{"text":" case changesOnly = \"changesOnly\" \/\/ Only sync when summaries are modified (default)","violation":{"ruleName":"Redundant String Enum Value","severity":"warning","ruleDescription":"String enum values can be omitted when they are equal to the enumcase name","ruleIdentifier":"redundant_string_enum_value","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":201,"character":28},"reason":"String enum values can be omitted when they are equal to the enumcase name"}},{"text":" case periodic = \"periodic\" \/\/ Sync all summaries periodically (legacy behavior)","violation":{"ruleName":"Redundant String Enum Value","severity":"warning","ruleDescription":"String enum values can be omitted when they are equal to the enumcase name","ruleIdentifier":"redundant_string_enum_value","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":202,"character":25},"reason":"String enum values can be omitted when they are equal to the enumcase name"}},{"text":" let error = NSError(domain: \"iCloudStorageManager\", code: 1, userInfo: [NSLocalizedDescriptionKey: \"Failed to initialize CloudKit components\"])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":352,"character":1},"reason":"Line should be 120 characters or less; currently it has 155 characters"}},{"text":" let error = NSError(domain: \"iCloudStorageManager\", code: 2, userInfo: [NSLocalizedDescriptionKey: \"CloudKit not initialized\"])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":382,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" let error = NSError(domain: \"iCloudStorageManager\", code: 3, userInfo: [NSLocalizedDescriptionKey: \"iCloud account not available\"])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":393,"character":1},"reason":"Line should be 120 characters or less; currently it has 147 characters"}},{"text":" \/\/ Note: userDiscoverability permission is deprecated in iOS 17.0 and not needed for private database operations","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":400,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" AppLog.shared.iCloudSync(\"Performing initial full sync (first install: \\(isFirstInstall), requested: \\(shouldPerformFullSyncOnStartup))\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":411,"character":1},"reason":"Line should be 120 characters or less; currently it has 153 characters"}},{"text":" AppLog.shared.iCloudSync(\"Summary belongs to a recording marked Keep on This Device, skipping iCloud sync\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":452,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" AppLog.shared.iCloudSync(\"Batch sync completed with errors: \\(syncedCount) synced, \\(failedCount) failed\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":541,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" private func performIndividualSync(_ summary: EnhancedSummaryData) async throws {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":555,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 13"}},{"text":" private func performIndividualSync(_ summary: EnhancedSummaryData) async throws {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":555,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 52 lines"}},{"text":" throw NSError(domain: \"iCloudStorageManager\", code: 1, userInfo: [NSLocalizedDescriptionKey: \"CloudKit not initialized\"])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":562,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" throw NSError(domain: \"iCloudStorageManager\", code: 2, userInfo: [NSLocalizedDescriptionKey: \"Network unavailable\"])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":566,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.iCloudSync(\"Server record changed, refetching and retrying (attempt \\(retryCount)\/\\(maxRetryAttempts))\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":594,"character":1},"reason":"Line should be 120 characters or less; currently it has 157 characters"}},{"text":" AppLog.shared.iCloudSync(\"Network error, retrying in \\(retryDelay)s (attempt \\(retryCount)\/\\(maxRetryAttempts))\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":599,"character":1},"reason":"Line should be 120 characters or less; currently it has 156 characters"}},{"text":" AppLog.shared.iCloudSync(\"Unknown record type, setting up schema and retrying\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":606,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" AppLog.shared.iCloudSync(\"Retryable CloudKit error, attempt \\(retryCount)\/\\(maxRetryAttempts): \\(ckError.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":612,"character":1},"reason":"Line should be 120 characters or less; currently it has 171 characters"}},{"text":" AppLog.shared.iCloudSync(\"Failed to sync summary after \\(retryCount) attempts: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":619,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" private func handleConflictResolution(for recordID: CKRecord.ID, with summary: EnhancedSummaryData) async throws -> CKRecord {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":626,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" throw NSError(domain: \"iCloudStorageManager\", code: 1, userInfo: [NSLocalizedDescriptionKey: \"Database not available\"])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":628,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" AppLog.shared.iCloudSync(\"Schema issue detected, ensuring schema and creating record\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":646,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" AppLog.shared.iCloudSync(\"Batch sync completed with errors: \\(syncedCount) synced, \\(failedCount) failed\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":709,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" func fetchSummariesFromiCloud(forRecovery: Bool = false) async throws -> [EnhancedSummaryData] {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":747,"character":5},"reason":"Function should have complexity 10 or less; currently complexity is 13"}},{"text":" func fetchSummariesFromiCloud(forRecovery: Bool = false) async throws -> [EnhancedSummaryData] {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":747,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 54 lines"}},{"text":" throw NSError(domain: \"iCloudStorageManager\", code: 1, userInfo: [NSLocalizedDescriptionKey: \"CloudKit not initialized\"])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":759,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" throw NSError(domain: \"iCloudStorageManager\", code: 2, userInfo: [NSLocalizedDescriptionKey: \"Network unavailable\"])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":764,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.iCloudSync(\"Failed to process record: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":788,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" AppLog.shared.iCloudSync(\"Retryable error fetching from iCloud, attempt \\(retryCount)\/\\(maxRetryAttempts): \\(ckError.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":803,"character":1},"reason":"Line should be 120 characters or less; currently it has 179 characters"}},{"text":" AppLog.shared.iCloudSync(\"Failed to fetch summaries from iCloud after \\(retryCount) attempts: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":807,"character":1},"reason":"Line should be 120 characters or less; currently it has 164 characters"}},{"text":" AppLog.shared.iCloudSync(\"Failed to fetch summaries from iCloud after \\(retryCount) attempts: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":811,"character":1},"reason":"Line should be 120 characters or less; currently it has 160 characters"}},{"text":" throw NSError(domain: \"iCloudStorageManager\", code: 3, userInfo: [NSLocalizedDescriptionKey: \"Max retry attempts exceeded\"])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":818,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" AppLog.shared.iCloudSync(\"Cannot perform bidirectional sync - disabled or network unavailable\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":823,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" if let resolved = try await handleSyncConflict(localSummary: localSummary, cloudRecord: try createCloudKitRecord(from: cloudSummary)) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":849,"character":1},"reason":"Line should be 120 characters or less; currently it has 159 characters"}},{"text":" if localLookup[cloudSummary.id] == nil {","violation":{"ruleName":"Prefer For-Where","severity":"warning","ruleDescription":"`where` clauses are preferred over a single `if` inside a `for`","ruleIdentifier":"for_where","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":865,"character":17},"reason":"`where` clauses are preferred over a single `if` inside a `for`"}},{"text":" AppLog.shared.iCloudSync(\"Bidirectional sync completed with conflicts: \\(syncedCount) synced, \\(conflictCount) conflicts\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":877,"character":1},"reason":"Line should be 120 characters or less; currently it has 153 characters"}},{"text":" guard forRecovery || isEnabled, let _ = database else {","violation":{"ruleName":"Unused Optional Binding","severity":"warning","ruleDescription":"Prefer `!= nil` over `let _ =`","ruleIdentifier":"unused_optional_binding","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":894,"character":45},"reason":"Prefer `!= nil` over `let _ =`"}},{"text":" throw NSError(domain: \"iCloudStorageManager\", code: 1, userInfo: [NSLocalizedDescriptionKey: \"iCloud sync not enabled or CloudKit not initialized\"])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":895,"character":1},"reason":"Line should be 120 characters or less; currently it has 160 characters"}},{"text":" AppLog.shared.iCloudSync(\"Failed to create Core Data entry for cloud summary: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":931,"character":1},"reason":"Line should be 120 characters or less; currently it has 144 characters"}},{"text":" AppLog.shared.iCloudSync(\"Failed to decode cloud summary: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":985,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" AppLog.shared.iCloudSync(\"Failed to fetch cloud summary record: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":988,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" func fetchAllSummariesUsingRecordOperation(appCoordinator: AppDataCoordinator? = nil) async throws -> [EnhancedSummaryData] {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1004,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" func fetchAllSummariesUsingRecordOperation(appCoordinator: AppDataCoordinator? = nil) async throws -> [EnhancedSummaryData] {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1004,"character":5},"reason":"Function should have complexity 10 or less; currently complexity is 12"}},{"text":" func fetchAllSummariesUsingRecordOperation(appCoordinator: AppDataCoordinator? = nil) async throws -> [EnhancedSummaryData] {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1004,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 74 lines"}},{"text":" AppLog.shared.iCloudSync(\"UUID scanning + change tracking found \\(summaries.count) summaries\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1019,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" AppLog.shared.iCloudSync(\"UUID scanning + change tracking failed: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1021,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.iCloudSync(\"Brute force scanning found \\(scannedSummaries.count) summaries\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1033,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" AppLog.shared.iCloudSync(\"Failed to fetch from zone using changes: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1081,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" AppLog.shared.iCloudSync(\"Database changes + zone scanning found \\(allSummaries.count) summaries\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1085,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" AppLog.shared.iCloudSync(\"Database changes + zone scanning failed: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1088,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" AppLog.shared.iCloudSync(\"Total unique summaries found: \\(uniqueSummaries.count) (removed \\(allSummaries.count - uniqueSummaries.count) duplicates)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1098,"character":1},"reason":"Line should be 120 characters or less; currently it has 172 characters"}},{"text":" private func fetchSummariesByUUIDScanning(appCoordinator: AppDataCoordinator) async throws -> [EnhancedSummaryData] {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1105,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" private func fetchSummariesByUUIDScanning(appCoordinator: AppDataCoordinator) async throws -> [EnhancedSummaryData] {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1105,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 11"}},{"text":" private func fetchSummariesByUUIDScanning(appCoordinator: AppDataCoordinator) async throws -> [EnhancedSummaryData] {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1105,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 70 lines"}},{"text":" AppLog.shared.iCloudSync(\"No CloudKit record found for local summary: \\(error.localizedDescription)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1148,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" AppLog.shared.iCloudSync(\"Failed to fetch cloud-only record: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1174,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" AppLog.shared.iCloudSync(\"Failed to convert cloud-only record: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1192,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" AppLog.shared.iCloudSync(\"Change tracking found \\(cloudOnlyRecords.count) cloud-only records\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1196,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" AppLog.shared.iCloudSync(\"UUID scanning + change tracking found \\(foundSummaries.count) total summaries\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1202,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.iCloudSync(\"Failed to fetch record with configuration: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1263,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" AppLog.shared.iCloudSync(\"Failed to convert configured record: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1281,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" private func fetchRecordsFromZoneByScanning(_ zoneID: CKRecordZone.ID) async throws -> [EnhancedSummaryData] {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1384,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 12"}},{"text":" let (matchResults, _) = try await database.records(matching: query, inZoneWith: zoneID, desiredKeys: nil, resultsLimit: 1)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1400,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" let (matchResults, _) = try await database.records(matching: query, inZoneWith: zoneID, desiredKeys: nil, resultsLimit: 1000)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1419,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" private func createCoreDataSummary(from cloudSummary: EnhancedSummaryData, appCoordinator: AppDataCoordinator) async throws -> Bool {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1455,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" AppLog.shared.iCloudSync(\"Creating orphaned Core Data summary entry (no local recording\/transcript)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1493,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" private func createOrphanedSummaryEntry(_ cloudSummary: EnhancedSummaryData, appCoordinator: AppDataCoordinator) async throws {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1509,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" private func handleSyncConflict(localSummary: EnhancedSummaryData, cloudRecord: CKRecord) async throws -> EnhancedSummaryData? {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1583,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" AppLog.shared.iCloudSync(\"Auto-backup complete: \\(result.recordingsBackedUp) recordings, \\(result.transcriptsBackedUp) transcripts, \\(result.summariesBackedUp) summaries\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1734,"character":1},"reason":"Line should be 120 characters or less; currently it has 187 characters"}},{"text":" AppLog.shared.iCloudSync(\"Auto-backup failed (will retry on next data change): \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1740,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" AppLog.shared.iCloudSync(\"Skipping full periodic sync - only syncing changes as they occur\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1801,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" AppLog.shared.iCloudSync(\"Failed to encode complex objects during update: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":1996,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" private func createEnhancedSummaryData(from record: CKRecord) throws -> EnhancedSummaryData {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2000,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 61 lines"}},{"text":" throw NSError(domain: \"iCloudStorageManager\", code: 1, userInfo: [NSLocalizedDescriptionKey: \"Missing required fields in CloudKit record\"])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2011,"character":1},"reason":"Line should be 120 characters or less; currently it has 151 characters"}},{"text":" func testCloudKitConnectivity() async -> String {","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2113,"character":5},"reason":"Function should have complexity 10 or less; currently complexity is 12"}},{"text":" func testCloudKitConnectivity() async -> String {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2113,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 71 lines"}},{"text":" let (matchResults, _) = try await database.records(matching: query, inZoneWith: CKRecordZone.default().zoneID, desiredKeys: nil, resultsLimit: 1)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2158,"character":1},"reason":"Line should be 120 characters or less; currently it has 157 characters"}},{"text":" func performFullCloudKitResetAndSync(appCoordinator: AppDataCoordinator) async throws -> (deleted: Int, uploaded: Int) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2260,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" throw NSError(domain: \"iCloudStorageManager\", code: 1, userInfo: [NSLocalizedDescriptionKey: \"iCloud sync not enabled or CloudKit not initialized\"])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2262,"character":1},"reason":"Line should be 120 characters or less; currently it has 160 characters"}},{"text":" if let enhancedSummary = try? convertCoreDataToEnhancedSummary(localSummary, appCoordinator: appCoordinator) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2284,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" AppLog.shared.iCloudSync(\"Failed to upload summary: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2290,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" AppLog.shared.iCloudSync(\"CloudKit reset and sync complete: deleted \\(deletedCount), uploaded \\(uploadedCount)\")","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2296,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" AppLog.shared.iCloudSync(\"Failed to fetch record for deletion: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2330,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" private func convertCoreDataToEnhancedSummary(_ summaryEntry: SummaryEntry, appCoordinator: AppDataCoordinator) throws -> EnhancedSummaryData {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2364,"character":1},"reason":"Line should be 120 characters or less; currently it has 147 characters"}},{"text":" private func convertCoreDataToEnhancedSummary(_ summaryEntry: SummaryEntry, appCoordinator: AppDataCoordinator) throws -> EnhancedSummaryData {","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2364,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 57 lines"}},{"text":" throw NSError(domain: \"iCloudStorageManager\", code: 1, userInfo: [NSLocalizedDescriptionKey: \"Missing required summary fields\"])","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2368,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" func backupAllDataToiCloud(","violation":{"ruleName":"Cyclomatic Complexity","severity":"error","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2740,"character":5},"reason":"Function should have complexity 10 or less; currently complexity is 27"}},{"text":" func backupAllDataToiCloud(","violation":{"ruleName":"Function Body Length","severity":"error","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2740,"character":5},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 410 lines"}},{"text":" AppLog.shared.iCloudSync(\"Backup context - bundle: \\(bundleIdentifier), container: \\(containerIdentifier)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2760,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" excludedRecordingIds.contains(recordingId) || !isActiveBackupRecord(record) ? nil : record.recordID.recordName","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2851,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" updateStringField(Self.fieldRecordingName, value: recording.recordingName, on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2873,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" updateDateField(Self.fieldRecordingDate, value: recording.recordingDate, on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2874,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" updateStringField(Self.fieldRecordingURL, value: recording.recordingURL, on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2875,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" updateStringField(Self.fieldAudioQuality, value: recording.audioQuality, on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2880,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" updateStringField(Self.fieldTranscriptionStatus, value: recording.transcriptionStatus, on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2881,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":" updateStringField(Self.fieldSummaryStatus, value: recording.summaryStatus, on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2882,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" updateStringField(Self.fieldTranscriptId, value: recording.transcriptId?.uuidString, on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2883,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" updateStringField(Self.fieldSummaryId, value: recording.summaryId?.uuidString, on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2884,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" updateDoubleField(Self.fieldLocationLatitude, value: recording.locationLatitude, on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2885,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" updateDoubleField(Self.fieldLocationLongitude, value: recording.locationLongitude, on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2886,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" updateDoubleField(Self.fieldLocationAccuracy, value: recording.locationAccuracy, on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2887,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" updateDateField(Self.fieldLocationTimestamp, value: recording.locationTimestamp, on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2888,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" updateStringField(Self.fieldLocationAddress, value: recording.locationAddress, on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2889,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" updateStringField(Self.fieldAudioFileName, value: localURL.lastPathComponent, on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2900,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" updateInt64Field(Self.fieldAudioByteCount, value: size, on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2903,"character":1},"reason":"Line should be 120 characters or less; currently it has 121 characters"}},{"text":" updateStringField(Self.fieldAudioSignature, value: signature, on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2905,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" updateStringField(Self.fieldRecordingId, value: transcript.recordingId?.uuidString, on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2966,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" updateDoubleField(Self.fieldProcessingTime, value: transcript.processingTime, on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2970,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" updateStringField(Self.fieldSpeakerMappings, value: transcript.speakerMappings, on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":2973,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" AppLog.shared.iCloudSync(\"Removed \\(transcriptResolution.loserRecordIDs.count) older transcript backup records\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3022,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"text":" updateStringField(Self.fieldRecordingId, value: summary.recordingId?.uuidString, on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3069,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" updateStringField(Self.fieldTranscriptId, value: summary.transcriptId?.uuidString, on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3070,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" updateIntField(Self.fieldOriginalLength, value: Int(summary.originalLength), on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3080,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" updateDoubleField(Self.fieldCompressionRatio, value: summary.compressionRatio, on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3081,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" updateDoubleField(Self.fieldProcessingTime, value: summary.processingTime, on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3083,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" updateStringField(Self.fieldRecordingName, value: summary.recording?.recordingName, on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3087,"character":1},"reason":"Line should be 120 characters or less; currently it has 133 characters"}},{"text":" updateDateField(Self.fieldRecordingDate, value: summary.recording?.recordingDate, on: record, changed: &shouldSave)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3088,"character":1},"reason":"Line should be 120 characters or less; currently it has 131 characters"}},{"text":" AppLog.shared.iCloudSync(\"Removed \\(summaryResolution.loserRecordIDs.count) older summary backup records\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3136,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" self.lastMaintenanceMessage = \"\\(items.count) older iCloud item\\(items.count == 1 ? \"\" : \"s\") held for review.\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3233,"character":1},"reason":"Line should be 120 characters or less; currently it has 127 characters"}},{"text":" private func scanCloudOnlyReviewItems(","violation":{"ruleName":"Cyclomatic Complexity","severity":"warning","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3239,"character":13},"reason":"Function should have complexity 10 or less; currently complexity is 15"}},{"text":" private func scanCloudOnlyReviewItems(","violation":{"ruleName":"Function Body Length","severity":"error","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3239,"character":13},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 109 lines"}},{"text":" let recordingRecords = try await fetchBackupRecords(recordType: Self.backupRecordingRecordType, database: database)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3255,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" let transcriptRecords = try await fetchBackupRecords(recordType: Self.backupTranscriptRecordType, database: database)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3256,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" recordingId.map({ !locallyExcludedRecordingIds.contains($0) && !deletedRecordingIds.contains($0) }) ?? true,","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3293,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" recordingId.map({ !locallyExcludedRecordingIds.contains($0) && !deletedRecordingIds.contains($0) }) ?? true,","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3316,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" let recordingId = (record[CloudKitSummaryRecord.recordingIdField] as? String).flatMap { UUID(uuidString: $0) }","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3337,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" recordingId.map({ !locallyExcludedRecordingIds.contains($0) && !deletedRecordingIds.contains($0) }) ?? true else {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3339,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" let deletedCount = try await deleteExistingCloudRecords(legacySchemaBootstrapRecordIDs, database: database)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3354,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" AppLog.shared.iCloudSync(\"Could not clean up legacy schema bootstrap records: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3359,"character":1},"reason":"Line should be 120 characters or less; currently it has 140 characters"}},{"text":" builder.sourceDeviceIdentifier = builder.sourceDeviceIdentifier ?? (record[Self.fieldDeviceIdentifier] as? String)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3384,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" builder.date = builder.date ?? (record[Self.fieldGeneratedAt] as? Date) ?? (record[Self.fieldRecordingDate] as? Date)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3398,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" builder.date = builder.date ?? (record[CloudKitSummaryRecord.generatedAtField] as? Date) ?? (record[CloudKitSummaryRecord.recordingDateField] as? Date)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3415,"character":1},"reason":"Line should be 120 characters or less; currently it has 159 characters"}},{"text":" builder.sourceDeviceIdentifier = builder.sourceDeviceIdentifier ?? (record[CloudKitSummaryRecord.deviceIdentifierField] as? String)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3416,"character":1},"reason":"Line should be 120 characters or less; currently it has 139 characters"}},{"text":" func restoreCloudReviewItem(","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3438,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 62 lines"}},{"text":" recordingRecordNames: Array(trustedManifest.recordings.union(recordingRecords.map { $0.recordID.recordName })).sorted(),","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3487,"character":1},"reason":"Line should be 120 characters or less; currently it has 132 characters"}},{"text":" transcriptRecordNames: Array(trustedManifest.transcripts.union(transcriptRecords.map { $0.recordID.recordName })).sorted(),","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3488,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" summaryRecordNames: Array(trustedManifest.summaries.union(summaryRecords.map { $0.recordID.recordName })).sorted()","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3489,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" func restoreAllDataFromiCloud(","violation":{"ruleName":"Cyclomatic Complexity","severity":"error","ruleDescription":"Complexity of function bodies should be limited.","ruleIdentifier":"cyclomatic_complexity","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3550,"character":5},"reason":"Function should have complexity 10 or less; currently complexity is 41"}},{"text":" func restoreAllDataFromiCloud(","violation":{"ruleName":"Function Body Length","severity":"error","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3550,"character":5},"reason":"Function body should span 100 lines or less excluding comments and whitespace: currently spans 339 lines"}},{"text":" AppLog.shared.iCloudSync(\"Restore context - bundle: \\(bundleIdentifier), container: \\(containerIdentifier)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3571,"character":1},"reason":"Line should be 120 characters or less; currently it has 135 characters"}},{"text":" let locallyExcludedRecordingIds = Set(appCoordinator.coreDataManager.getAllRecordings().compactMap { recording in","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3613,"character":1},"reason":"Line should be 120 characters or less; currently it has 125 characters"}},{"text":" let fileExtension = (backupFileName as NSString).pathExtension.isEmpty ? \"m4a\" : (backupFileName as NSString).pathExtension","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3747,"character":1},"reason":"Line should be 120 characters or less; currently it has 143 characters"}},{"text":" entry.recordingURL = appCoordinator.coreDataManager.urlToRelativePath(destinationURL) ?? uniqueFileName","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3757,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" let reviewItems = (try? await scanCloudOnlyReviewItems(appCoordinator: appCoordinator, database: database)) ?? []","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3898,"character":1},"reason":"Line should be 120 characters or less; currently it has 129 characters"}},{"text":" \" Run Backup Now on the source device and ensure both devices use the same app build channel (both Debug or both TestFlight\/App Store).\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3918,"character":1},"reason":"Line should be 120 characters or less; currently it has 164 characters"}},{"text":" AppLog.shared.iCloudSync(\"Query threw error (\\(error.localizedDescription)), trying schema-safe record discovery\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":3958,"character":1},"reason":"Line should be 120 characters or less; currently it has 141 characters"}},{"text":" func reconcileAllDataWithiCloud(","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":4034,"character":5},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 54 lines"}},{"text":" let recordID = CKRecord.ID(recordName: makeBackupRecordName(prefix: Self.backupDeletionRecordPrefix, id: recordingId))","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":4116,"character":1},"reason":"Line should be 120 characters or less; currently it has 126 characters"}},{"text":" AppLog.shared.iCloudSync(\"Recorded iCloud deletion marker for \\(recordingId.uuidString); removed \\(deletedCloudRecords) cloud content records\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":4138,"character":1},"reason":"Line should be 120 characters or less; currently it has 166 characters"}},{"text":" AppLog.shared.iCloudSync(\"Removed \\(deletedCloudRecords) iCloud records for local-only recording \\(recordingId.uuidString)\", level: .debug)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":4186,"character":1},"reason":"Line should be 120 characters or less; currently it has 147 characters"}},{"text":" get { Self.decodePendingCloudMutations(PendingLocalOnlyCloudRemoval.self, key: Self.pendingLocalOnlyRemovalsKey) }","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":4214,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" lastMaintenanceMessage = \"Existing iCloud copies for local-only recordings will be removed when iCloud sync is available.\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":4268,"character":1},"reason":"Line should be 120 characters or less; currently it has 130 characters"}},{"text":" lastMaintenanceMessage = \"Deleted summaries will be removed from iCloud sync records when iCloud sync is available.\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":4278,"character":1},"reason":"Line should be 120 characters or less; currently it has 124 characters"}},{"text":" func flushPendingiCloudMutations(appCoordinator: AppDataCoordinator) async throws -> (deletions: Int, localOnlyRemovals: Int, summaryRemovals: Int) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":4298,"character":1},"reason":"Line should be 120 characters or less; currently it has 153 characters"}},{"text":" func flushPendingiCloudMutations(appCoordinator: AppDataCoordinator) async throws -> (deletions: Int, localOnlyRemovals: Int, summaryRemovals: Int) {","violation":{"ruleName":"Large Tuple","severity":"warning","ruleDescription":"Tuples shouldn't have too many members. Create a custom type instead.","ruleIdentifier":"large_tuple","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":4298,"character":90},"reason":"Tuples should have at most 2 members"}},{"text":" \"Flushed pending iCloud mutations - deletions: \\(flushedDeletions), local-only removals: \\(flushedLocalOnlyRemovals), summary removals: \\(flushedSummaryRemovals)\",","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":4347,"character":1},"reason":"Line should be 120 characters or less; currently it has 179 characters"}},{"text":" private func applyiCloudDeletionMarkers(appCoordinator: AppDataCoordinator) async throws -> (local: Int, cloud: Int) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":4375,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" ?? decodeBackupRecordUUID(recordName: record.recordID.recordName, prefix: Self.backupDeletionRecordPrefix)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":4390,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" self.lastMaintenanceMessage = \"Applied \\(deletedLocalCount) iCloud deletion\\(deletedLocalCount == 1 ? \"\" : \"s\") to this device and cleaned \\(deletedCloudCount) cloud record\\(deletedCloudCount == 1 ? \"\" : \"s\").\"","violation":{"ruleName":"Line Length","severity":"error","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":4415,"character":1},"reason":"Line should be 200 characters or less; currently it has 226 characters"}},{"text":" ?? decodeBackupRecordUUID(recordName: record.recordID.recordName, prefix: Self.backupDeletionRecordPrefix)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":4429,"character":1},"reason":"Line should be 120 characters or less; currently it has 122 characters"}},{"text":" let transcriptRecords = (try? await fetchBackupRecords(recordType: Self.backupTranscriptRecordType, database: database)) ?? []","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":4458,"character":1},"reason":"Line should be 120 characters or less; currently it has 134 characters"}},{"text":" let summaryRecords = (try? await fetchBackupRecords(recordType: Self.backupSummaryRecordType, database: database)) ?? []","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":4459,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" AppLog.shared.iCloudSync(\"Could not scan legacy summary sync records for deletion cleanup: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":4553,"character":1},"reason":"Line should be 120 characters or less; currently it has 149 characters"}},{"text":" AppLog.shared.iCloudSync(\"Could not scan legacy summary sync records: \\(error.localizedDescription)\", level: .error)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":4576,"character":1},"reason":"Line should be 120 characters or less; currently it has 128 characters"}},{"text":" private func computeBackupStateSignature(","violation":{"ruleName":"Function Body Length","severity":"warning","ruleDescription":"Function bodies should not span too many lines","ruleIdentifier":"function_body_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":4607,"character":13},"reason":"Function body should span 50 lines or less excluding comments and whitespace: currently spans 79 lines"}},{"text":" updateIntField(Self.fieldSyncSchemaVersion, value: Self.activeManifestSchemaVersion, on: record, changed: &changed)","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":4849,"character":1},"reason":"Line should be 120 characters or less; currently it has 123 characters"}},{"text":" \"Deploy the development CloudKit schema for \\(Self.sharedContainerIdentifier) to production, then try syncing again.\"","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":5479,"character":1},"reason":"Line should be 120 characters or less; currently it has 137 characters"}},{"text":" private func collectSettingsForBackup(includeSensitiveSettings: Bool) -> (values: [String: Data], includedSensitiveSettings: Bool) {","violation":{"ruleName":"Line Length","severity":"warning","ruleDescription":"Lines should not span too many characters.","ruleIdentifier":"line_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":5568,"character":1},"reason":"Line should be 120 characters or less; currently it has 136 characters"}},{"text":"}","violation":{"ruleName":"File Length","severity":"error","ruleDescription":"Files should not span too many lines.","ruleIdentifier":"file_length","location":{"file":"file:\/\/\/Users\/champ\/Sources\/BisonNotes-AI\/BisonNotes%20AI\/BisonNotes%20AI\/iCloudStorageManager.swift","line":5753,"character":1},"reason":"File should contain 1000 lines or less: currently contains 5753"}}] \ No newline at end of file diff --git a/BisonNotes AI/BisonNotes AI/SystemIntegrationManager.swift b/BisonNotes AI/BisonNotes AI/SystemIntegrationManager.swift index b4d354e..edc813f 100644 --- a/BisonNotes AI/BisonNotes AI/SystemIntegrationManager.swift +++ b/BisonNotes AI/BisonNotes AI/SystemIntegrationManager.swift @@ -8,7 +8,9 @@ import Foundation import EventKit import SwiftUI +#if canImport(UIKit) import UIKit +#endif // MARK: - System Integration Manager @@ -26,7 +28,7 @@ class SystemIntegrationManager: NSObject, ObservableObject { /// Whether the Google Calendar app is installed on this device var isGoogleCalendarInstalled: Bool { guard let url = URL(string: "googlecalendar://") else { return false } - return UIApplication.shared.canOpenURL(url) + return PlatformApp.canOpen(url) } override init() { @@ -348,7 +350,7 @@ class SystemIntegrationManager: NSObject, ObservableObject { return } - UIApplication.shared.open(url) + PlatformApp.open(url) } // MARK: - Helper Methods diff --git a/BisonNotes AI/BisonNotes AI/TranscriptionSettingsView.swift b/BisonNotes AI/BisonNotes AI/TranscriptionSettingsView.swift index c440412..6071593 100644 --- a/BisonNotes AI/BisonNotes AI/TranscriptionSettingsView.swift +++ b/BisonNotes AI/BisonNotes AI/TranscriptionSettingsView.swift @@ -23,17 +23,36 @@ struct TranscriptionSettingsView: View { @Environment(\.dismiss) private var dismiss var body: some View { - NavigationStack { + Group { settingsContent .navigationTitle("Transcription Settings") .navigationBarTitleDisplayMode(.inline) .toolbar { + #if !os(macOS) ToolbarItem(placement: .navigationBarTrailing) { Button("Done") { dismiss() } } + #endif } + #if os(macOS) + .navigationDestination(isPresented: $showingAWSSettings) { + AWSSettingsView() + } + .navigationDestination(isPresented: $showingWhisperSettings) { + WhisperSettingsView() + } + .navigationDestination(isPresented: $showingFluidAudioSettings) { + FluidAudioSettingsView() + } + .navigationDestination(isPresented: $showingOpenAISettings) { + OpenAISettingsView() + } + .navigationDestination(isPresented: $showingMistralTranscribeSettings) { + MistralTranscribeSettingsView() + } + #else .sheet(isPresented: $showingAWSSettings) { AWSSettingsView() } @@ -51,10 +70,12 @@ struct TranscriptionSettingsView: View { .sheet(isPresented: $showingMistralTranscribeSettings) { MistralTranscribeSettingsView() } + #endif .onChange(of: selectedTranscriptionEngine) { _, newValue in handleEngineSelection(newValue) } } + .platformSettingsNavigation() } @ViewBuilder diff --git a/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+Background.swift b/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+Background.swift index b758b33..7147f6d 100644 --- a/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+Background.swift +++ b/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+Background.swift @@ -6,7 +6,9 @@ // import Foundation +#if canImport(UIKit) import UIKit +#endif // MARK: - Phase 4: Background Task Management @@ -21,7 +23,7 @@ extension AudioRecorderViewModel { #else guard backgroundTask == .invalid else { return } AppLog.shared.backgroundProcessing("Starting background task for recording") - backgroundTask = UIApplication.shared.beginBackgroundTask(withName: "Recording") { [weak self] in + backgroundTask = PlatformBackgroundTask.begin(name: "Recording") { [weak self] in AppLog.shared.backgroundProcessing("Recording background task expiring", level: .error) self?.endBackgroundTask() } @@ -34,7 +36,7 @@ extension AudioRecorderViewModel { #else guard backgroundTask != .invalid else { return } AppLog.shared.backgroundProcessing("Ending recording background task") - UIApplication.shared.endBackgroundTask(backgroundTask) + PlatformBackgroundTask.end(backgroundTask) backgroundTask = .invalid #endif } @@ -42,7 +44,7 @@ extension AudioRecorderViewModel { // MARK: - Background Time Monitoring func startBackgroundTimeMonitoring() { - #if targetEnvironment(macCatalyst) + #if targetEnvironment(macCatalyst) || os(macOS) // No iOS-style background time limit on Mac β€” skip polling. return #else @@ -50,7 +52,7 @@ extension AudioRecorderViewModel { // Check remaining background time every 30 seconds backgroundTimeMonitor = Timer.scheduledTimer(withTimeInterval: 30.0, repeats: true) { [weak self] _ in - let remaining = UIApplication.shared.backgroundTimeRemaining + let remaining = PlatformBackgroundTask.remainingTime // Only log/warn if actually limited (not infinite) if remaining < Double.greatestFiniteMagnitude { diff --git a/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+CallIntelligence.swift b/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+CallIntelligence.swift index bbc4552..bf5eacb 100644 --- a/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+CallIntelligence.swift +++ b/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+CallIntelligence.swift @@ -8,8 +8,10 @@ import Foundation import UserNotifications -#if !targetEnvironment(macCatalyst) +#if os(iOS) && !targetEnvironment(macCatalyst) +#if canImport(CallKit) && os(iOS) import CallKit +#endif // MARK: - CallKit Observer Delegate (Phase 1) diff --git a/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+CatalystEngine.swift b/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+CatalystEngine.swift index 858790b..b67782c 100644 --- a/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+CatalystEngine.swift +++ b/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+CatalystEngine.swift @@ -2,22 +2,26 @@ // AudioRecorderViewModel+CatalystEngine.swift // BisonNotes AI // -// Mac Catalyst recording uses AVAudioEngine + AVAudioFile because +// Mac recording uses AVAudioEngine + AVAudioFile because // AVAudioRecorder cannot reliably set up its AAC/PCM converter on macOS. // The engine taps the input node directly, writes native PCM to a temporary // CAF file, then exports that file to the app's normal M4A recording URL. // -#if targetEnvironment(macCatalyst) +#if targetEnvironment(macCatalyst) || os(macOS) import Foundation @preconcurrency import AVFoundation extension AudioRecorderViewModel { + // Keep the worst-case summed level below full scale while favoring nearby speech. + private static let microphoneMeetingMixGain: Float = 0.5 + private static let systemMeetingMixGain: Float = 0.4 @MainActor func setupCatalystRecording(at url: URL) async { var systemAudioError: Error? + catalystScratchSegmentURLs = [] if isMacSystemAudioCaptureEnabled { let systemAudioURL = Self.catalystSystemAudioURL(for: url) @@ -65,6 +69,7 @@ extension AudioRecorderViewModel { // Tear down any leftover engine state from a previous run. stopCatalystEngineRecording(closingFile: false) + #if targetEnvironment(macCatalyst) do { try startCatalystEnginePipeline(at: url) } catch { @@ -80,10 +85,22 @@ extension AudioRecorderViewModel { throw error } } + #else + // Native macOS uses Core Audio directly. AVAudioSession is an iOS API + // and the Catalyst-only fallback must never run here. + try startCatalystEnginePipeline(at: url) + #endif } - private func startCatalystEnginePipeline(at url: URL) throws { + private func startCatalystEnginePipeline( + at url: URL, + scratchURL suppliedScratchURL: URL? = nil, + removingFinalOutput: Bool = true + ) throws { let engine = AVAudioEngine() + #if os(macOS) + try enhancedAudioSessionManager.configureInputDevice(for: engine) + #endif let inputNode = engine.inputNode let inputFormat = inputNode.outputFormat(forBus: 0) @@ -95,12 +112,12 @@ extension AudioRecorderViewModel { ) } - let scratchURL = Self.catalystScratchURL(for: url) + let scratchURL = suppliedScratchURL ?? Self.catalystScratchURL(for: url) let fileManager = FileManager.default if fileManager.fileExists(atPath: scratchURL.path) { try fileManager.removeItem(at: scratchURL) } - if fileManager.fileExists(atPath: url.path) { + if removingFinalOutput, fileManager.fileExists(atPath: url.path) { try fileManager.removeItem(at: url) } @@ -118,12 +135,14 @@ extension AudioRecorderViewModel { try engine.start() } + #if targetEnvironment(macCatalyst) private func activateCatalystAudioSessionFallback() throws { let session = AVAudioSession.sharedInstance() try session.setCategory(.playAndRecord, mode: .default, options: [.mixWithOthers]) try session.setActive(true) catalystAudioSessionActivated = true } + #endif /// Pause Catalyst recording: remove the input tap so the file stops /// receiving samples. The engine and file stay alive so resume can @@ -160,15 +179,47 @@ extension AudioRecorderViewModel { } catalystAudioEngine = nil catalystEngineFormat = nil + #if os(macOS) + enhancedAudioSessionManager.clearConfiguredInputDevice() + #endif if closingFile { catalystAudioFile = nil + #if targetEnvironment(macCatalyst) if catalystAudioSessionActivated { try? AVAudioSession.sharedInstance().setActive(false, options: .notifyOthersOnDeactivation) catalystAudioSessionActivated = false } + #endif } } + #if os(macOS) + /// Closes the current PCM segment without discarding it. A replacement input + /// may expose a different native format, so recovery always starts a new CAF. + func sealNativeMacScratchSegment() { + let currentScratchURL = catalystScratchRecordingURL + stopCatalystEngineRecording() + if let currentScratchURL, + FileManager.default.fileExists(atPath: currentScratchURL.path), + !catalystScratchSegmentURLs.contains(currentScratchURL) { + catalystScratchSegmentURLs.append(currentScratchURL) + } + catalystScratchRecordingURL = nil + } + + /// Starts the next PCM segment on the currently resolved Core Audio input. + /// The original final URL is retained for the normal stop/finalize flow. + func startNativeMacContinuation(at finalURL: URL) throws { + let segmentIndex = catalystScratchSegmentURLs.count + 1 + let scratchURL = Self.catalystScratchURL(for: finalURL, segmentIndex: segmentIndex) + try startCatalystEnginePipeline( + at: finalURL, + scratchURL: scratchURL, + removingFinalOutput: false + ) + } + #endif + func stopCatalystSystemAudioCapture() async -> URL? { guard let capture = catalystSystemAudioCapture else { catalystSystemAudioURL = nil @@ -193,7 +244,8 @@ extension AudioRecorderViewModel { /// after exporting the native PCM scratch file to M4A. @MainActor func finalizeCatalystRecording(at url: URL) async { - guard let scratchURL = catalystScratchRecordingURL else { + let scratchURLs = allCatalystScratchURLs() + guard !scratchURLs.isEmpty else { AppLog.shared.recording("Catalyst finalize: scratch recording URL is missing", level: .error) errorMessage = "Recording was not saved because the temporary audio file was missing." return @@ -202,18 +254,19 @@ extension AudioRecorderViewModel { do { if let systemAudioURL = catalystSystemAudioURL { try await exportAndMixCatalystRecording( - microphoneScratchURL: scratchURL, + microphoneScratchURLs: scratchURLs, systemAudioURL: systemAudioURL, finalURL: url ) } else { - try await exportCatalystScratchRecording(from: scratchURL, to: url) + try await exportCatalystScratchRecordings(from: scratchURLs, to: url) } } catch { AppLog.shared.recording("Catalyst finalize: failed to export recording: \(error.localizedDescription)", level: .error) errorMessage = "Recording could not be finalized: \(error.localizedDescription)" - try? FileManager.default.removeItem(at: scratchURL) + removeCatalystScratchFiles(scratchURLs) catalystScratchRecordingURL = nil + catalystScratchSegmentURLs = [] return } @@ -246,11 +299,31 @@ extension AudioRecorderViewModel { ) AppLog.shared.recording("Catalyst recording created with workflow manager, ID: \(recordingId)") - self.resetRecordingLocation() - self.recordingStartedAt = nil - self.recordingBeingProcessed = false - self.catalystScratchRecordingURL = nil - self.catalystSystemAudioURL = nil + resetCatalystFinalizationState() + } + + private func resetCatalystFinalizationState() { + resetRecordingLocation() + recordingStartedAt = nil + recordingBeingProcessed = false + catalystScratchRecordingURL = nil + catalystScratchSegmentURLs = [] + catalystSystemAudioURL = nil + } + + private func allCatalystScratchURLs() -> [URL] { + var scratchURLs = catalystScratchSegmentURLs + if let currentScratchURL = catalystScratchRecordingURL, + !scratchURLs.contains(currentScratchURL) { + scratchURLs.append(currentScratchURL) + } + return scratchURLs + } + + private func removeCatalystScratchFiles(_ scratchURLs: [URL]) { + for scratchURL in scratchURLs { + try? FileManager.default.removeItem(at: scratchURL) + } } private func installCatalystInputTap() { @@ -274,13 +347,15 @@ extension AudioRecorderViewModel { } } - private static func catalystScratchURL(for finalURL: URL) -> URL { + private static func catalystScratchURL(for finalURL: URL, segmentIndex: Int? = nil) -> URL { // Stage in the temp directory, not next to the recording: an orphaned // scratch file left by a crash between stop and finalize would otherwise // sit in the recordings directory. The name is derived from the final // recording so the start-pipeline retry cleanup can find and remove it. - FileManager.default.temporaryDirectory - .appendingPathComponent(finalURL.deletingPathExtension().lastPathComponent) + let basename = finalURL.deletingPathExtension().lastPathComponent + let scratchName = segmentIndex.map { "\(basename)-input-\($0)" } ?? basename + return FileManager.default.temporaryDirectory + .appendingPathComponent(scratchName) .appendingPathExtension("caf") } @@ -369,71 +444,140 @@ extension AudioRecorderViewModel { AppLog.shared.recording("Catalyst recording exported to M4A: \(finalURL.lastPathComponent), duration: \(exportedDuration)s, size: \(exportedSize) bytes") } + private func exportCatalystScratchRecordings(from scratchURLs: [URL], to finalURL: URL) async throws { + guard scratchURLs.count > 1 else { + guard let scratchURL = scratchURLs.first else { + throw NSError( + domain: "AudioRecorderViewModel.Catalyst", + code: -13, + userInfo: [NSLocalizedDescriptionKey: "No temporary recording segments were available."] + ) + } + try await exportCatalystScratchRecording(from: scratchURL, to: finalURL) + return + } + + let (composition, insertionTime) = try await makeRecoveredMicrophoneComposition(from: scratchURLs) + guard insertionTime.isValid, insertionTime.seconds > 0, + let exportSession = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetAppleM4A) else { + throw NSError( + domain: "AudioRecorderViewModel.Catalyst", + code: -15, + userInfo: [NSLocalizedDescriptionKey: "Recovered microphone segments contained no audio."] + ) + } + + let fileManager = FileManager.default + let tempURL = fileManager.temporaryDirectory + .appendingPathComponent("catalyst_segments_\(UUID().uuidString).m4a") + try await exportSession.export(to: tempURL, as: .m4a) + let attributes = try fileManager.attributesOfItem(atPath: tempURL.path) + let exportedSize = attributes[.size] as? Int64 ?? 0 + let exportedDuration = try await AVURLAsset(url: tempURL).load(.duration).seconds + guard exportedSize > 0, exportedDuration.isFinite, exportedDuration > 0 else { + try? fileManager.removeItem(at: tempURL) + throw NSError( + domain: "AudioRecorderViewModel.Catalyst", + code: -16, + userInfo: [NSLocalizedDescriptionKey: "Recovered microphone export was empty."] + ) + } + if fileManager.fileExists(atPath: finalURL.path) { + try fileManager.removeItem(at: finalURL) + } + try fileManager.moveItem(at: tempURL, to: finalURL) + AppFileProtection.apply(to: finalURL) + removeCatalystScratchFiles(scratchURLs) + AppLog.shared.recording( + "Recovered Mac microphone segments exported to M4A: \(scratchURLs.count) segments, " + + "duration: \(exportedDuration)s, size: \(exportedSize) bytes" + ) + } + + private func makeRecoveredMicrophoneComposition( + from scratchURLs: [URL] + ) async throws -> (AVMutableComposition, CMTime) { + let composition = AVMutableComposition() + guard let compositionTrack = composition.addMutableTrack( + withMediaType: .audio, + preferredTrackID: kCMPersistentTrackID_Invalid + ) else { + throw NSError( + domain: "AudioRecorderViewModel.Catalyst", + code: -14, + userInfo: [NSLocalizedDescriptionKey: "Could not create a track for recovered microphone audio."] + ) + } + + var insertionTime = CMTime.zero + for scratchURL in scratchURLs { + let asset = AVURLAsset(url: scratchURL) + guard let sourceTrack = try await asset.loadTracks(withMediaType: .audio).first else { continue } + let duration = try await asset.load(.duration) + guard duration.isValid, duration.seconds > 0 else { continue } + try compositionTrack.insertTimeRange( + CMTimeRange(start: .zero, duration: duration), + of: sourceTrack, + at: insertionTime + ) + insertionTime = CMTimeAdd(insertionTime, duration) + } + return (composition, insertionTime) + } + private func exportAndMixCatalystRecording( - microphoneScratchURL: URL, + microphoneScratchURLs: [URL], systemAudioURL: URL, finalURL: URL ) async throws { let fileManager = FileManager.default - let microphoneM4AURL = fileManager.temporaryDirectory - .appendingPathComponent("catalyst_mic_export_\(UUID().uuidString).m4a") do { - try await exportCatalystScratchRecording(from: microphoneScratchURL, to: microphoneM4AURL) try await mixCatalystAudioTracks( - microphoneURL: microphoneM4AURL, + microphoneScratchURLs: microphoneScratchURLs, systemAudioURL: systemAudioURL, finalURL: finalURL ) - try? fileManager.removeItem(at: microphoneM4AURL) + removeCatalystScratchFiles(microphoneScratchURLs) try? fileManager.removeItem(at: systemAudioURL) } catch { AppLog.shared.recording("Catalyst meeting audio mix failed; saving microphone track only: \(error.localizedDescription)", level: .error) - if fileManager.fileExists(atPath: microphoneM4AURL.path) { - if fileManager.fileExists(atPath: finalURL.path) { - try fileManager.removeItem(at: finalURL) - } - try fileManager.moveItem(at: microphoneM4AURL, to: finalURL) - AppFileProtection.apply(to: finalURL) - errorMessage = "Meeting audio could not be mixed into this recording. Saved microphone audio only." - try? fileManager.removeItem(at: systemAudioURL) - return - } - throw error + try await exportCatalystScratchRecordings(from: microphoneScratchURLs, to: finalURL) + errorMessage = "Meeting audio could not be mixed into this recording. Saved microphone audio only." + try? fileManager.removeItem(at: systemAudioURL) } } private func mixCatalystAudioTracks( - microphoneURL: URL, + microphoneScratchURLs: [URL], systemAudioURL: URL, finalURL: URL ) async throws { let fileManager = FileManager.default - let microphoneAsset = AVURLAsset(url: microphoneURL) - let systemAsset = AVURLAsset(url: systemAudioURL) - let composition = AVMutableComposition() - var mixParameters: [AVAudioMixInputParameters] = [] - let microphoneDuration = try await microphoneAsset.load(.duration) - guard microphoneDuration.isValid, microphoneDuration.seconds > 0 else { - throw NSError( - domain: "AudioRecorderViewModel.Catalyst", - code: -12, - userInfo: [NSLocalizedDescriptionKey: "Microphone recording has no audio duration."] - ) - } - - try await addAudioTracks( - from: microphoneAsset, - to: composition, - mixParameters: &mixParameters, - maxDuration: microphoneDuration - ) - try await addAudioTracks( - from: systemAsset, - to: composition, - mixParameters: &mixParameters, - maxDuration: microphoneDuration + let systemAsset = AVURLAsset(url: systemAudioURL) + let (composition, microphoneDuration) = try await makeRecoveredMicrophoneComposition( + from: microphoneScratchURLs + ) + guard microphoneDuration.isValid, microphoneDuration.seconds > 0 else { + throw NSError( + domain: "AudioRecorderViewModel.Catalyst", + code: -12, + userInfo: [NSLocalizedDescriptionKey: "Microphone recording has no audio duration."] ) + } + + var mixParameters: [AVAudioMixInputParameters] = composition.tracks(withMediaType: .audio).map { track in + let parameter = AVMutableAudioMixInputParameters(track: track) + parameter.setVolume(Self.microphoneMeetingMixGain, at: .zero) + return parameter + } + try await addAudioTracks( + from: systemAsset, + to: composition, + mixParameters: &mixParameters, + volume: Self.systemMeetingMixGain, + maxDuration: microphoneDuration + ) guard !composition.tracks(withMediaType: .audio).isEmpty else { throw NSError( @@ -452,11 +596,11 @@ extension AudioRecorderViewModel { code: -10, userInfo: [NSLocalizedDescriptionKey: "Could not create meeting audio export session."] ) - } - exportSession.audioMix = audioMix - exportSession.timeRange = CMTimeRange(start: .zero, duration: microphoneDuration) + } + exportSession.audioMix = audioMix + exportSession.timeRange = CMTimeRange(start: .zero, duration: microphoneDuration) - let tempURL = fileManager.temporaryDirectory + let tempURL = fileManager.temporaryDirectory .appendingPathComponent("catalyst_meeting_mix_\(UUID().uuidString).m4a") if fileManager.fileExists(atPath: tempURL.path) { try fileManager.removeItem(at: tempURL) @@ -487,6 +631,7 @@ extension AudioRecorderViewModel { from asset: AVURLAsset, to composition: AVMutableComposition, mixParameters: inout [AVAudioMixInputParameters], + volume: Float, maxDuration: CMTime? = nil ) async throws { let tracks = try await asset.loadTracks(withMediaType: .audio) @@ -512,7 +657,7 @@ extension AudioRecorderViewModel { at: .zero ) let parameter = AVMutableAudioMixInputParameters(track: compositionTrack) - parameter.setVolume(1.0, at: .zero) + parameter.setVolume(volume, at: .zero) mixParameters.append(parameter) } } diff --git a/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+Interruptions.swift b/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+Interruptions.swift index 194a33d..c76ae09 100644 --- a/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+Interruptions.swift +++ b/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+Interruptions.swift @@ -7,13 +7,16 @@ import Foundation @preconcurrency import AVFoundation +#if canImport(UIKit) import UIKit +#endif import UserNotifications extension AudioRecorderViewModel { // MARK: - Audio Interruption Handling + #if os(iOS) func handleAudioInterruption(_ notification: Notification) { // Forward to session manager for logging and restoration enhancedAudioSessionManager.handleAudioInterruption(notification) @@ -109,6 +112,11 @@ extension AudioRecorderViewModel { break } } + #else + // macOS: AVAudioSession interruptions do not exist. Device-change handling + // arrives with Core Audio listeners in Phase 2.3. + func handleAudioInterruption(_ notification: Notification) {} + #endif /// Attempt to resume recording after an unexpected stop (e.g., declined call without interruption notification) @MainActor @@ -320,6 +328,7 @@ extension AudioRecorderViewModel { // MARK: - Route Change Handling + #if os(iOS) func handleRouteChange(_ notification: Notification) { guard let userInfo = notification.userInfo, let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt, @@ -366,6 +375,9 @@ extension AudioRecorderViewModel { break } } + #else + func handleRouteChange(_ notification: Notification) {} + #endif @MainActor func handleMicrophoneUnavailableDuringRecording() async { @@ -791,8 +803,8 @@ extension AudioRecorderViewModel { let body = "Found and saved your recording from when the app was in background: \(filename.prefix(30))..." // Check app state for notification timing - let appState = await MainActor.run { UIApplication.shared.applicationState } - AppLog.shared.audioSession("App state when sending recovery notification: \(appState.rawValue)", level: .debug) + let appIsActive = await MainActor.run { PlatformApp.isActive } + AppLog.shared.audioSession("App active when sending recovery notification: \(appIsActive)", level: .debug) // Use the proven BackgroundProcessingManager notification system _ = await MainActor.run { diff --git a/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+MicrophoneReconnection.swift b/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+MicrophoneReconnection.swift index 7721136..141402f 100644 --- a/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+MicrophoneReconnection.swift +++ b/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+MicrophoneReconnection.swift @@ -12,6 +12,168 @@ import Foundation extension AudioRecorderViewModel { + #if os(macOS) + func setupMacInputDeviceMonitoring() { + enhancedAudioSessionManager.startInputDeviceMonitoring { [weak self] in + self?.scheduleMacInputDeviceRefresh() + } + scheduleMacInputDeviceRefresh() + } + + /// Core Audio may emit several device-list/default-input callbacks for one + /// physical connect or disconnect. Coalescing avoids rebuilding the engine + /// more than once for the same change. + func scheduleMacInputDeviceRefresh() { + macInputDeviceChangeTask?.cancel() + macInputDeviceChangeTask = Task { @MainActor [weak self] in + do { + try await Task.sleep(for: .milliseconds(250)) + } catch { + return + } + await self?.handleMacInputDevicesChanged() + } + } + + @MainActor + func handleMacInputDevicesChanged() async { + availableInputs = enhancedAudioSessionManager.getAvailableInputs() + + if let storedUID = UserDefaults.standard.string(forKey: preferredInputDefaultsKey) { + if let preferredInput = availableInputs.first(where: { $0.uid == storedUID }) { + selectedInput = preferredInput + } else { + AppLog.shared.audioSession("Preferred Mac microphone disconnected; falling back to the system default") + try? await enhancedAudioSessionManager.clearPreferredInput() + UserDefaults.standard.removeObject(forKey: preferredInputDefaultsKey) + selectedInput = nil + } + } + + switch recordingState { + case .recording, .paused: + guard enhancedAudioSessionManager.recordingInputNeedsRecovery() else { return } + await recoverNativeMacInput(keepPaused: isPaused) + case .waitingForMicrophone: + guard enhancedAudioSessionManager.resolvedInputDeviceID() != nil else { return } + await recoverNativeMacInput(keepPaused: false) + default: + break + } + } + + @MainActor + func recoverNativeMacInput(keepPaused: Bool) async { + guard !isRecoveringMacInput, isRecording, let finalURL = recordingURL else { return } + isRecoveringMacInput = true + defer { isRecoveringMacInput = false } + + let disconnectedAt: Date + let wasAlreadyWaiting: Bool + if case .waitingForMicrophone(let existingDisconnectedAt) = recordingState { + wasAlreadyWaiting = true + disconnectedAt = existingDisconnectedAt + } else { + wasAlreadyWaiting = false + disconnectedAt = Date() + } + + if !wasAlreadyWaiting { + AppLog.shared.audioSession("Mac recording input changed; sealing the current audio segment") + catalystSystemAudioCapture?.setPaused(true) + stopRecordingTimer() + sealNativeMacScratchSegment() + } + + guard enhancedAudioSessionManager.resolvedInputDeviceID() != nil else { + await waitForNativeMacInput(disconnectedAt: disconnectedAt, notify: !wasAlreadyWaiting) + return + } + + do { + try startNativeMacContinuation(at: finalURL) + await finishNativeMacInputRecovery(keepPaused: keepPaused, notify: wasAlreadyWaiting) + } catch { + discardFailedNativeMacContinuation() + AppLog.shared.audioSession("Mac input recovery failed: \(error.localizedDescription)", level: .error) + recordingState = .waitingForMicrophone(disconnectedAt: disconnectedAt) + errorMessage = "Could not use the available microphone: \(error.localizedDescription)" + startNativeMacInputRecoveryMonitoring() + } + } + + @MainActor + private func waitForNativeMacInput(disconnectedAt: Date, notify: Bool) async { + recordingState = .waitingForMicrophone(disconnectedAt: disconnectedAt) + errorMessage = "Microphone disconnected. Recording will resume when an input is available." + if notify { + await sendWarningNotification( + title: "Microphone Disconnected", + body: "Waiting for a microphone to reconnect...", + isCritical: false + ) + } + startNativeMacInputRecoveryMonitoring() + } + + @MainActor + private func finishNativeMacInputRecovery(keepPaused: Bool, notify: Bool) async { + microphoneReconnectionTimer?.invalidate() + microphoneReconnectionTimer = nil + if keepPaused { + pauseCatalystEngineRecording() + recordingState = .paused + } else { + catalystSystemAudioCapture?.setPaused(false) + recordingState = .recording + startRecordingTimer() + } + errorMessage = "Recording continued with the available microphone." + AppLog.shared.audioSession("Mac recording resumed on the available input") + if notify { + await sendWarningNotification( + title: "Recording Resumed", + body: "A microphone is available and recording has resumed.", + isCritical: false + ) + } + } + + private func discardFailedNativeMacContinuation() { + let failedScratchURL = catalystScratchRecordingURL + stopCatalystEngineRecording() + if let failedScratchURL { + try? FileManager.default.removeItem(at: failedScratchURL) + } + catalystScratchRecordingURL = nil + } + + func startNativeMacInputRecoveryMonitoring() { + guard microphoneReconnectionTimer == nil else { return } + microphoneReconnectionTimer = Timer.scheduledTimer(withTimeInterval: 2.0, repeats: true) { [weak self] timer in + Task { @MainActor in + guard let self else { + timer.invalidate() + return + } + guard case .waitingForMicrophone(let disconnectedAt) = self.recordingState else { + timer.invalidate() + self.microphoneReconnectionTimer = nil + return + } + guard Date().timeIntervalSince(disconnectedAt) <= self.MICROPHONE_RECONNECTION_TIMEOUT else { + timer.invalidate() + self.microphoneReconnectionTimer = nil + self.errorMessage = "Recording stopped because no microphone was available for 5 minutes." + self.stopRecording() + return + } + await self.handleMacInputDevicesChanged() + } + } + } + #endif + @MainActor func handleMicrophoneDisconnected() async { guard case .recording = recordingState else { diff --git a/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+Utilities.swift b/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+Utilities.swift index 1b96602..762ce21 100644 --- a/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+Utilities.swift +++ b/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+Utilities.swift @@ -170,6 +170,11 @@ extension AudioRecorderViewModel { try await enhancedAudioSessionManager.setPreferredInput(input) UserDefaults.standard.set(input.uid, forKey: preferredInputDefaultsKey) try await enhancedAudioSessionManager.deactivateSession() + #if os(macOS) + await MainActor.run { + self.scheduleMacInputDeviceRefresh() + } + #endif } catch { errorMessage = "Failed to set preferred input: \(error.localizedDescription)" try? await enhancedAudioSessionManager.deactivateSession() @@ -216,25 +221,27 @@ extension AudioRecorderViewModel { } } else { // Preferred input is no longer available, fall back to default - AppLog.shared.recording("Preferred input no longer available, falling back to iOS default") + AppLog.shared.recording("Preferred input no longer available, falling back to the system default") inputToUse = nil } } - // If no preferred input or it's unavailable, let iOS use its default - // iOS will automatically use the built-in microphone when no preferred input is set + // If no preferred input or it's unavailable, use the platform default. if inputToUse == nil { do { - // Clear the preferred input to let iOS use its default + // Clear the preferred input to let the platform use its default. try await enhancedAudioSessionManager.clearPreferredInput() // Clear the stored preference since the device is no longer available UserDefaults.standard.removeObject(forKey: preferredInputDefaultsKey) // Update selectedInput to nil so UI reflects the fallback selectedInput = nil - AppLog.shared.recording("Using iOS default microphone (preferred input unavailable)") + AppLog.shared.recording("Using the system default microphone (preferred input unavailable)") } catch { - // If clearing fails, iOS will still use default, so just log it - AppLog.shared.recording("Could not clear preferred input, iOS will use default: \(error.localizedDescription)", level: .debug) + // If clearing fails, the platform still falls back to its default input. + AppLog.shared.recording( + "Could not clear preferred input; using the system default: \(error.localizedDescription)", + level: .debug + ) // Still clear the stored preference and update UI UserDefaults.standard.removeObject(forKey: preferredInputDefaultsKey) selectedInput = nil diff --git a/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+Warnings.swift b/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+Warnings.swift index 3ad34da..9a1ec1c 100644 --- a/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+Warnings.swift +++ b/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+Warnings.swift @@ -6,7 +6,9 @@ // import Foundation +#if canImport(UIKit) import UIKit +#endif import UserNotifications // MARK: - Phase 3: Comprehensive Warning System @@ -95,7 +97,8 @@ extension AudioRecorderViewModel { // Skip on Mac β€” UIDevice.batteryLevel returns -1 / unreliable values under // both Mac Catalyst and "Designed for iPad" on Apple Silicon, and enabling // monitoring spams "Error retrieving battery status" to the log. - if !UIDevice.isRunningOnMac { + #if canImport(UIKit) + if !PlatformDevice.isRunningOnMac { UIDevice.current.isBatteryMonitoringEnabled = true let batteryLevel = UIDevice.current.batteryLevel @@ -119,6 +122,7 @@ extension AudioRecorderViewModel { ) } } + #endif } /// Get available storage on device diff --git a/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel.swift b/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel.swift index fb07345..800eeb8 100644 --- a/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel.swift +++ b/BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel.swift @@ -12,8 +12,10 @@ import Combine import CoreLocation import UserNotifications #if !targetEnvironment(macCatalyst) +#if canImport(CallKit) && os(iOS) import CallKit #endif +#endif class AudioRecorderViewModel: NSObject, ObservableObject { @@ -80,24 +82,29 @@ class AudioRecorderViewModel: NSObject, ObservableObject { var lastRecoveryAttempt: Date = Date.distantPast // Background task identifier for recording continuity - var backgroundTask: UIBackgroundTaskIdentifier = .invalid + var backgroundTask: PlatformBackgroundTask.ID = .invalid // Track last checkpoint time for periodic data flushing var lastCheckpointTime: Date = Date.distantPast var recordingStartedAt: (url: URL, date: Date)? - #if targetEnvironment(macCatalyst) - // On Mac Catalyst, AVAudioRecorder cannot reliably encode to the app's + #if targetEnvironment(macCatalyst) || os(macOS) + // On Mac, AVAudioRecorder cannot reliably encode to the app's // M4A target. AVAudioEngine taps deliver PCM buffers to a scratch file that - // is exported to M4A when recording stops; AVAudioSession is only used as a - // fallback if the direct engine path cannot start. + // is exported to M4A when recording stops; Catalyst uses AVAudioSession only + // as a fallback if the direct engine path cannot start. var catalystAudioEngine: AVAudioEngine? var catalystAudioFile: AVAudioFile? var catalystEngineFormat: AVAudioFormat? var catalystScratchRecordingURL: URL? + var catalystScratchSegmentURLs: [URL] = [] var catalystSystemAudioCapture: CatalystSystemAudioCapture? var catalystSystemAudioURL: URL? var catalystAudioSessionActivated = false + #if os(macOS) + var macInputDeviceChangeTask: Task? + var isRecoveringMacInput = false + #endif #endif let checkpointInterval: TimeInterval = 30.0 // Try to checkpoint every 30 seconds let forceCheckpointInterval: TimeInterval = 90.0 // Force checkpoint after 90 seconds even without silence @@ -111,7 +118,7 @@ class AudioRecorderViewModel: NSObject, ObservableObject { var currentSegmentIndex: Int = 0 // Track which segment we're on // Call interruption intelligence (Phase 1) - #if !targetEnvironment(macCatalyst) + #if os(iOS) && !targetEnvironment(macCatalyst) var callObserver: CXCallObserver? #endif var callInterruptionStartTime: Date? @@ -196,8 +203,12 @@ class AudioRecorderViewModel: NSObject, ObservableObject { // Setup notification observers after super.init() setupNotificationObservers() + #if os(macOS) + setupMacInputDeviceMonitoring() + #endif + // Setup CallKit observer for intelligent call interruption handling (Phase 1) - #if !targetEnvironment(macCatalyst) + #if os(iOS) && !targetEnvironment(macCatalyst) setupCallObserver() #endif } @@ -245,6 +256,11 @@ class AudioRecorderViewModel: NSObject, ObservableObject { } deinit { + #if os(macOS) + macInputDeviceChangeTask?.cancel() + enhancedAudioSessionManager.stopInputDeviceMonitoring() + #endif + // Remove observers synchronously since deinit cannot be async if let observer = interruptionObserver { NotificationCenter.default.removeObserver(observer) @@ -260,7 +276,7 @@ class AudioRecorderViewModel: NSObject, ObservableObject { // MARK: - Notification Observers func setupNotificationObservers() { - #if !targetEnvironment(macCatalyst) + #if os(iOS) && !targetEnvironment(macCatalyst) // AVAudioSession interruption/route notifications use Mach ports that don't // exist on Mac β€” registering for them floods the log with "cannot add handler". // Phone-call interruptions and Bluetooth routing don't apply on Mac anyway. @@ -307,7 +323,7 @@ class AudioRecorderViewModel: NSObject, ObservableObject { #endif willEnterForegroundObserver = NotificationCenter.default.addObserver( - forName: UIApplication.willEnterForegroundNotification, + forName: PlatformLifecycle.willEnterForegroundNotification, object: nil, queue: .main ) { [weak self] _ in @@ -385,7 +401,7 @@ class AudioRecorderViewModel: NSObject, ObservableObject { // Add observer for app backgrounding NotificationCenter.default.addObserver( - forName: UIApplication.didEnterBackgroundNotification, + forName: PlatformLifecycle.didEnterBackgroundNotification, object: nil, queue: .main ) { [weak self] _ in @@ -427,7 +443,7 @@ class AudioRecorderViewModel: NSObject, ObservableObject { // MARK: - Call Observer Setup (Phase 1) - #if !targetEnvironment(macCatalyst) + #if os(iOS) && !targetEnvironment(macCatalyst) /// Setup CallKit observer for intelligent call interruption handling func setupCallObserver() { callObserver = CXCallObserver() @@ -455,7 +471,7 @@ class AudioRecorderViewModel: NSObject, ObservableObject { func startRecording() { guard beginRecordingStartup() else { return } AppLog.shared.recording("startRecording: requesting microphone permission") - #if targetEnvironment(macCatalyst) + #if targetEnvironment(macCatalyst) || os(macOS) Task { @MainActor [weak self] in self?.requestMicPermissionAndRecord() } #else AVAudioApplication.requestRecordPermission { [weak self] granted in @@ -490,9 +506,32 @@ class AudioRecorderViewModel: NSObject, ObservableObject { #endif } - #if targetEnvironment(macCatalyst) + #if targetEnvironment(macCatalyst) || os(macOS) @MainActor private func requestMicPermissionAndRecord() { + #if os(macOS) + let status = AVCaptureDevice.authorizationStatus(for: .audio) + AppLog.shared.recording("Mac mic permission status: \(status.rawValue)") + switch status { + case .authorized: + didReceiveMicrophonePermission(granted: true) + case .notDetermined: + AVCaptureDevice.requestAccess(for: .audio) { [weak self] granted in + Task { @MainActor [weak self] in + AppLog.shared.recording("Mac mic permission result: \(granted)") + self?.didReceiveMicrophonePermission(granted: granted) + } + } + case .denied, .restricted: + AppLog.shared.recording("Mac mic permission denied", level: .error) + errorMessage = "Microphone access is denied. Open System Settings β†’ " + + "Privacy & Security β†’ Microphone and enable BisonNotes AI, then try again." + finishRecordingStartup() + @unknown default: + finishRecordingStartup() + errorMessage = "Microphone permission could not be determined." + } + #else let status = AVAudioApplication.shared.recordPermission AppLog.shared.recording("Mac mic permission status: \(status.rawValue)") switch status { @@ -507,7 +546,8 @@ class AudioRecorderViewModel: NSObject, ObservableObject { } case .denied: AppLog.shared.recording("Mac mic permission denied", level: .error) - errorMessage = "Microphone access is denied. Open System Settings β†’ Privacy & Security β†’ Microphone and enable BisonNotes AI, then try again." + errorMessage = "Microphone access is denied. Open System Settings β†’ " + + "Privacy & Security β†’ Microphone and enable BisonNotes AI, then try again." finishRecordingStartup() @unknown default: AVAudioApplication.requestRecordPermission { [weak self] granted in @@ -516,6 +556,7 @@ class AudioRecorderViewModel: NSObject, ObservableObject { } } } + #endif } @MainActor @@ -526,17 +567,25 @@ class AudioRecorderViewModel: NSObject, ObservableObject { return } AppLog.shared.recording("startRecording: microphone permission granted") - // Skip AVAudioSession.setCategory/setActive on Mac β€” those calls communicate - // with mediaserverd via Mach ports that don't exist on macOS, flooding the - // log. AVAudioRecorder uses the default CoreAudio input directly on Mac. + // Skip AVAudioSession.setCategory/setActive on Mac. Native macOS applies + // the selected Core Audio input directly to AVAudioEngine; Catalyst uses + // its existing engine/default-input behavior. + #if os(macOS) + Task { @MainActor [weak self] in + guard let self else { return } + await self.applySelectedInputToSession() + self.setupRecording() + } + #else setupRecording() + #endif } #endif func startBackgroundRecording() { guard beginRecordingStartup() else { return } AppLog.shared.recording("startBackgroundRecording: requesting microphone permission") - #if targetEnvironment(macCatalyst) + #if targetEnvironment(macCatalyst) || os(macOS) Task { @MainActor [weak self] in self?.requestMicPermissionAndRecord() } #else AVAudioApplication.requestRecordPermission { [weak self] granted in @@ -590,7 +639,7 @@ class AudioRecorderViewModel: NSObject, ObservableObject { // capture records system output first, so live mic-only transcription is // disabled for that mode and transcription runs from the saved file. var useLiveTranscription = UserDefaults.standard.bool(forKey: "enableLiveTranscription") - #if targetEnvironment(macCatalyst) + #if targetEnvironment(macCatalyst) || os(macOS) if isMacSystemAudioCaptureEnabled { useLiveTranscription = false } @@ -602,7 +651,7 @@ class AudioRecorderViewModel: NSObject, ObservableObject { } do { - #if targetEnvironment(macCatalyst) + #if targetEnvironment(macCatalyst) || os(macOS) Task { @MainActor in await self.setupCatalystRecording(at: audioFilename) } @@ -680,7 +729,7 @@ class AudioRecorderViewModel: NSObject, ObservableObject { return } - #if targetEnvironment(macCatalyst) + #if targetEnvironment(macCatalyst) || os(macOS) guard catalystAudioEngine != nil else { return } pauseCatalystEngineRecording() #else @@ -699,7 +748,7 @@ class AudioRecorderViewModel: NSObject, ObservableObject { func resumeRecording() { guard isPaused else { return } - #if targetEnvironment(macCatalyst) + #if targetEnvironment(macCatalyst) || os(macOS) do { try resumeCatalystEngineRecording() } catch { @@ -745,7 +794,7 @@ class AudioRecorderViewModel: NSObject, ObservableObject { return } - #if targetEnvironment(macCatalyst) + #if targetEnvironment(macCatalyst) || os(macOS) // On Catalyst, recording is driven by AVAudioEngine + AVAudioFile. // Tear it down here, then run the save flow manually since there's // no AVAudioRecorder delegate to fire it. @@ -777,7 +826,7 @@ class AudioRecorderViewModel: NSObject, ObservableObject { await mergeRecordingSegments() } } else { - #if targetEnvironment(macCatalyst) + #if targetEnvironment(macCatalyst) || os(macOS) if let url = catalystFinalURL { AppLog.shared.recording("Recording finished successfully (Catalyst engine)") Task { @MainActor in @@ -900,7 +949,7 @@ class AudioRecorderViewModel: NSObject, ObservableObject { // while the app is in the background, and we need to detect that. // NOTE: In live transcription mode, audioRecorder is nil so this block is // safely skipped β€” LiveTranscriptionService manages its own AVAudioEngine. - #if targetEnvironment(macCatalyst) + #if targetEnvironment(macCatalyst) || os(macOS) // On Mac Catalyst there is no AVAudioSession interruption model and // AVAudioRecorder.isRecording is unreliable; the recovery flow that // reactivates the session and rebuilds the recorder is a no-op here diff --git a/BisonNotes AI/BisonNotes AI/ViewModels/CatalystSystemAudioCapture.swift b/BisonNotes AI/BisonNotes AI/ViewModels/CatalystSystemAudioCapture.swift index c54dad9..789fbd2 100644 --- a/BisonNotes AI/BisonNotes AI/ViewModels/CatalystSystemAudioCapture.swift +++ b/BisonNotes AI/BisonNotes AI/ViewModels/CatalystSystemAudioCapture.swift @@ -3,10 +3,10 @@ // BisonNotes AI // // Captures Mac system/application audio through ScreenCaptureKit while the -// existing Catalyst microphone recorder continues to capture local speech. +// existing Mac microphone recorder continues to capture local speech. // -#if targetEnvironment(macCatalyst) +#if targetEnvironment(macCatalyst) || os(macOS) import Foundation @preconcurrency import AVFoundation @@ -16,6 +16,7 @@ import ScreenCaptureKit final class CatalystSystemAudioCapture: NSObject, SCStreamOutput, SCStreamDelegate { private let outputURL: URL private let sampleQueue = DispatchQueue(label: "com.bisonnotesai.catalyst-system-audio") + private let discardedVideoQueue = DispatchQueue(label: "com.bisonnotesai.catalyst-system-video-discard") private var stream: SCStream? private var assetWriter: AVAssetWriter? @@ -26,9 +27,13 @@ final class CatalystSystemAudioCapture: NSObject, SCStreamOutput, SCStreamDelega private var pauseStartedAt: CMTime? private var accumulatedPausedDuration = CMTime.zero private var didReceiveAudio = false + private var audibleAudioDuration: Double = 0 private var isPaused = false private var stopError: Error? + private static let audibleAmplitudeThreshold: Float = 0.001 + private static let minimumAudibleDuration = 0.05 + init(outputURL: URL) { self.outputURL = outputURL super.init() @@ -77,18 +82,11 @@ final class CatalystSystemAudioCapture: NSObject, SCStreamOutput, SCStreamDelega ) } - let config = SCStreamConfiguration() - config.width = max(display.width, 2) - config.height = max(display.height, 2) - config.minimumFrameInterval = CMTime(value: 1, timescale: 2) - config.queueDepth = 3 - config.capturesAudio = true - config.excludesCurrentProcessAudio = true - config.sampleRate = 48_000 - config.channelCount = 2 + let config = Self.makeSystemAudioConfiguration() let filter = SCContentFilter(display: display, excludingWindows: []) let stream = SCStream(filter: filter, configuration: config, delegate: self) + try stream.addStreamOutput(self, type: .screen, sampleHandlerQueue: discardedVideoQueue) try stream.addStreamOutput(self, type: .audio, sampleHandlerQueue: sampleQueue) self.assetWriter = writer @@ -99,6 +97,22 @@ final class CatalystSystemAudioCapture: NSObject, SCStreamOutput, SCStreamDelega AppLog.shared.recording("Catalyst system audio capture started") } + private static func makeSystemAudioConfiguration() -> SCStreamConfiguration { + let config = SCStreamConfiguration() + // ScreenCaptureKit always produces a screen stream, even when the app only + // needs system audio. The tiny no-op screen output prevents repeated + // "stream output NOT found" logs for otherwise-unclaimed video frames. + config.width = 2 + config.height = 2 + config.minimumFrameInterval = CMTime(value: 1, timescale: 1) + config.queueDepth = 3 + config.capturesAudio = true + config.excludesCurrentProcessAudio = true + config.sampleRate = 48_000 + config.channelCount = 2 + return config + } + func setPaused(_ paused: Bool) { sampleQueue.async { [weak self] in guard let self else { return } @@ -137,10 +151,15 @@ final class CatalystSystemAudioCapture: NSObject, SCStreamOutput, SCStreamDelega let fileManager = FileManager.default guard didReceiveAudio, + audibleAudioDuration >= Self.minimumAudibleDuration, fileManager.fileExists(atPath: outputURL.path), (try? fileManager.attributesOfItem(atPath: outputURL.path)[.size] as? Int64) ?? 0 > 0 else { try? fileManager.removeItem(at: outputURL) - AppLog.shared.recording("Catalyst system audio capture produced no audio; continuing with microphone recording only", level: .debug) + AppLog.shared.recording( + "Catalyst system audio capture contained no sustained audible signal; " + + "continuing with microphone recording only", + level: .debug + ) return nil } @@ -195,12 +214,103 @@ final class CatalystSystemAudioCapture: NSObject, SCStreamOutput, SCStreamDelega if input.append(retimedBuffer) { didReceiveAudio = true + if Self.containsAudibleSignal(sampleBuffer) { + let duration = CMSampleBufferGetDuration(sampleBuffer).seconds + if duration.isFinite, duration > 0 { + audibleAudioDuration += duration + } else if let formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer), + let streamDescription = CMAudioFormatDescriptionGetStreamBasicDescription(formatDescription) { + let sampleRate = streamDescription.pointee.mSampleRate + if sampleRate > 0 { + audibleAudioDuration += Double(CMSampleBufferGetNumSamples(sampleBuffer)) / sampleRate + } + } + } } else if let error = writer.error { stopError = error AppLog.shared.recording("Catalyst system audio append failed: \(error.localizedDescription)", level: .error) } } + private static func containsAudibleSignal(_ sampleBuffer: CMSampleBuffer) -> Bool { + guard let formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer), + let streamDescription = CMAudioFormatDescriptionGetStreamBasicDescription(formatDescription) else { + // Preserve unknown formats rather than risk dropping real system audio. + return true + } + + let format = streamDescription.pointee + guard format.mFormatID == kAudioFormatLinearPCM else { return true } + + var bufferListSize = 0 + let sizeStatus = CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer( + sampleBuffer, + bufferListSizeNeededOut: &bufferListSize, + bufferListOut: nil, + bufferListSize: 0, + blockBufferAllocator: nil, + blockBufferMemoryAllocator: nil, + flags: 0, + blockBufferOut: nil + ) + guard sizeStatus == noErr, bufferListSize > 0 else { return true } + + let rawBufferList = UnsafeMutableRawPointer.allocate( + byteCount: bufferListSize, + alignment: MemoryLayout.alignment + ) + defer { rawBufferList.deallocate() } + let audioBufferList = rawBufferList.bindMemory(to: AudioBufferList.self, capacity: 1) + var retainedBlockBuffer: CMBlockBuffer? + let listStatus = CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer( + sampleBuffer, + bufferListSizeNeededOut: nil, + bufferListOut: audioBufferList, + bufferListSize: bufferListSize, + blockBufferAllocator: nil, + blockBufferMemoryAllocator: nil, + flags: 0, + blockBufferOut: &retainedBlockBuffer + ) + guard listStatus == noErr else { return true } + + let isFloat = format.mFormatFlags & kAudioFormatFlagIsFloat != 0 + let isSignedInteger = format.mFormatFlags & kAudioFormatFlagIsSignedInteger != 0 + let bufferCount = Int(audioBufferList.pointee.mNumberBuffers) + + return withUnsafeMutablePointer(to: &audioBufferList.pointee.mBuffers) { firstBuffer in + for bufferIndex in 0...size) + for index in 0..<(byteCount / MemoryLayout.size) + where abs(samples[index]) >= audibleAmplitudeThreshold { + return true + } + } else if isSignedInteger, format.mBitsPerChannel == 16 { + let samples = data.bindMemory(to: Int16.self, capacity: byteCount / MemoryLayout.size) + let threshold = Int16(Float(Int16.max) * audibleAmplitudeThreshold) + for index in 0..<(byteCount / MemoryLayout.size) + where abs(Int(samples[index])) >= Int(threshold) { + return true + } + } else if isSignedInteger, format.mBitsPerChannel == 32 { + let samples = data.bindMemory(to: Int32.self, capacity: byteCount / MemoryLayout.size) + let threshold = Int64(Float(Int32.max) * audibleAmplitudeThreshold) + for index in 0..<(byteCount / MemoryLayout.size) + where abs(Int64(samples[index])) >= threshold { + return true + } + } else { + return true + } + } + return false + } + } + func stream(_ stream: SCStream, didStopWithError error: Error) { stopError = error AppLog.shared.recording("Catalyst system audio stream stopped with error: \(error.localizedDescription)", level: .error) diff --git a/BisonNotes AI/BisonNotes AI/Views/AcknowledgementsView.swift b/BisonNotes AI/BisonNotes AI/Views/AcknowledgementsView.swift index 36ec691..825d915 100644 --- a/BisonNotes AI/BisonNotes AI/Views/AcknowledgementsView.swift +++ b/BisonNotes AI/BisonNotes AI/Views/AcknowledgementsView.swift @@ -10,7 +10,10 @@ struct AcknowledgementsView: View { @State private var showTransitiveDependencies = false var body: some View { - NavigationStack { + Group { + #if os(macOS) + nativeMacContent + #else Form { Section { Text("BisonNotes AI is built on the shoulders of outstanding open-source projects.") @@ -68,8 +71,119 @@ struct AcknowledgementsView: View { Button("Done") { dismiss() } } } + #endif } + .platformSettingsNavigation() } + + #if os(macOS) + private var nativeMacContent: some View { + ScrollView { + VStack(alignment: .leading, spacing: 22) { + VStack(alignment: .leading, spacing: 6) { + Text("Acknowledgements") + .font(.largeTitle.bold()) + Text("Open-source software that makes BisonNotes AI possible.") + .font(.subheadline) + .foregroundStyle(.secondary) + } + + acknowledgementCard(title: "Direct Dependencies", systemImage: "shippingbox") { + ForEach(Array(directDependencies.enumerated()), id: \.element.id) { index, dependency in + if index > 0 { + Divider() + } + + VStack(alignment: .leading, spacing: 7) { + HStack(alignment: .firstTextBaseline) { + Text(dependency.name) + .font(.headline) + Spacer() + Text(dependency.license) + .font(.caption.weight(.medium)) + .foregroundStyle(.secondary) + } + + Text(dependency.description) + .font(.subheadline) + .foregroundStyle(.secondary) + .fixedSize(horizontal: false, vertical: true) + + Link(dependency.linkText, destination: dependency.url) + .font(.caption) + } + .padding(.vertical, 3) + } + } + + acknowledgementCard(title: "Transitive Dependencies", systemImage: "square.stack.3d.up") { + DisclosureGroup(isExpanded: $showTransitiveDependencies) { + VStack(alignment: .leading, spacing: 18) { + ForEach(transitiveDependencyGroups) { group in + VStack(alignment: .leading, spacing: 8) { + Text(group.title) + .font(.subheadline.weight(.semibold)) + + LazyVGrid( + columns: [ + GridItem(.flexible(), alignment: .leading), + GridItem(.flexible(), alignment: .leading) + ], + alignment: .leading, + spacing: 7 + ) { + ForEach(group.projects) { project in + Link(project.name, destination: project.url) + .font(.caption) + } + } + } + } + } + .padding(.top, 12) + } label: { + Text(showTransitiveDependencies ? "Hide dependency list" : "Show dependency list") + .fontWeight(.medium) + } + + Text( + "These projects arrive through the direct dependencies above. " + + "Each is licensed under MIT or Apache 2.0; follow its repository link for complete terms." + ) + .font(.caption) + .foregroundStyle(.secondary) + .fixedSize(horizontal: false, vertical: true) + } + } + .frame(maxWidth: 680) + .frame(maxWidth: .infinity, alignment: .top) + .padding(28) + } + .background(Color(.systemGroupedBackground)) + .navigationTitle("Acknowledgements") + } + + private func acknowledgementCard( + title: String, + systemImage: String, + @ViewBuilder content: () -> Content + ) -> some View { + VStack(alignment: .leading, spacing: 16) { + Label(title, systemImage: systemImage) + .font(.headline) + .foregroundStyle(.indigo) + + content() + } + .padding(18) + .frame(maxWidth: .infinity, alignment: .leading) + .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 14)) + .overlay { + RoundedRectangle(cornerRadius: 14) + .stroke(Color.primary.opacity(0.08), lineWidth: 1) + } + } + #endif } private struct DependencyCard: Identifiable { diff --git a/BisonNotes AI/BisonNotes AI/Views/AudioPlayerView.swift b/BisonNotes AI/BisonNotes AI/Views/AudioPlayerView.swift index 95be326..abe9fb5 100644 --- a/BisonNotes AI/BisonNotes AI/Views/AudioPlayerView.swift +++ b/BisonNotes AI/BisonNotes AI/Views/AudioPlayerView.swift @@ -201,6 +201,7 @@ struct AudioPlayerView: View { }) { if let audioExportURL { ShareSheet(activityItems: [audioExportURL]) + .nativeMacModalSizing(width: 560, height: 440) } } .sheet(item: $selectedRecordingForTranscript) { entry in @@ -208,9 +209,11 @@ struct AudioPlayerView: View { let transcript = appCoordinator.getTranscriptData(for: recordingId) { EditableTranscriptView(recording: entry, transcript: transcript, transcriptManager: TranscriptManager.shared) .environmentObject(appCoordinator) + .nativeMacModalSizing(width: 820, height: 720) } else { TranscriptDetailView(recording: entry, transcriptText: "") .environmentObject(appCoordinator) + .nativeMacModalSizing(width: 820, height: 720) } } .confirmationDialog( diff --git a/BisonNotes AI/BisonNotes AI/Views/BackgroundProcessingView.swift b/BisonNotes AI/BisonNotes AI/Views/BackgroundProcessingView.swift index 74bc0c5..051af53 100644 --- a/BisonNotes AI/BisonNotes AI/Views/BackgroundProcessingView.swift +++ b/BisonNotes AI/BisonNotes AI/Views/BackgroundProcessingView.swift @@ -8,13 +8,14 @@ import SwiftUI struct BackgroundProcessingView: View { + @Environment(\.openWindow) private var openWindow @ObservedObject private var processingManager = BackgroundProcessingManager.shared @State private var selectedJob: ProcessingJob? @Environment(\.dismiss) private var dismiss var body: some View { let _ = AppLog.shared.backgroundProcessing("BackgroundProcessingView body: activeJobs.count = \(processingManager.activeJobs.count)", level: .debug) - NavigationStack { + PlatformSettingsNavigationStack { VStack(spacing: 0) { // Header with overall status headerSection @@ -62,6 +63,7 @@ struct BackgroundProcessingView: View { } .sheet(item: $selectedJob) { job in JobDetailView(job: job) + .nativeMacModalSizing(width: 620, height: 540) } } } @@ -152,7 +154,11 @@ struct BackgroundProcessingView: View { LazyVStack(spacing: 12) { ForEach(processingManager.activeJobs) { job in JobCard(job: job) { + #if os(macOS) + openWindow(id: NativeWindowID.processingJob, value: job.id) + #else selectedJob = job + #endif } } } diff --git a/BisonNotes AI/BisonNotes AI/Views/DataMigrationView.swift b/BisonNotes AI/BisonNotes AI/Views/DataMigrationView.swift index 5280e9a..e424457 100644 --- a/BisonNotes AI/BisonNotes AI/Views/DataMigrationView.swift +++ b/BisonNotes AI/BisonNotes AI/Views/DataMigrationView.swift @@ -14,6 +14,7 @@ enum MigrationMode { } struct DataMigrationView: View { + @Environment(\.openWindow) private var openWindow @EnvironmentObject var appCoordinator: AppDataCoordinator @StateObject private var migrationManager = DataMigrationManager() @ObservedObject private var legacyiCloudManager = iCloudStorageManager.shared @@ -442,7 +443,7 @@ struct DataMigrationView: View { // Background Processing Button(action: { - showingBackgroundProcessing = true + presentBackgroundProcessing() }) { HStack { Image(systemName: "gearshape.2") @@ -626,6 +627,7 @@ struct DataMigrationView: View { } .sheet(isPresented: $showingBackgroundProcessing) { BackgroundProcessingView() + .nativeMacModalSizing(width: 760, height: 680) } .alert("iCloud Sync Verification", isPresented: $showingSyncVerification) { Button("OK") { @@ -654,6 +656,14 @@ struct DataMigrationView: View { } } + private func presentBackgroundProcessing() { + #if os(macOS) + openWindow(id: NativeWindowID.backgroundProcessing) + #else + showingBackgroundProcessing = true + #endif + } + private var integrityCheckSection: some View { VStack(spacing: 14) { Button(action: { @@ -1145,17 +1155,10 @@ struct DataMigrationView: View { } catch { AppLog.shared.dataMigration("Failed to verify iCloud sync: \(error)", level: .error) await MainActor.run { - let alert = UIAlertController( + PlatformAlert.present( title: "Verification Failed", - message: "Could not verify iCloud sync: \(error.localizedDescription)", - preferredStyle: .alert + message: "Could not verify iCloud sync: \(error.localizedDescription)" ) - alert.addAction(UIAlertAction(title: "OK", style: .default)) - - if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, - let rootViewController = windowScene.windows.first?.rootViewController { - rootViewController.present(alert, animated: true) - } } } } @@ -1185,17 +1188,10 @@ struct DataMigrationView: View { } catch { AppLog.shared.dataMigration("Failed to sync missing summaries: \(error)", level: .error) await MainActor.run { - let alert = UIAlertController( + PlatformAlert.present( title: "Sync Failed", - message: "Could not sync summaries to iCloud: \(error.localizedDescription)", - preferredStyle: .alert + message: "Could not sync summaries to iCloud: \(error.localizedDescription)" ) - alert.addAction(UIAlertAction(title: "OK", style: .default)) - - if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, - let rootViewController = windowScene.windows.first?.rootViewController { - rootViewController.present(alert, animated: true) - } } } } diff --git a/BisonNotes AI/BisonNotes AI/Views/MistralOnboardingView.swift b/BisonNotes AI/BisonNotes AI/Views/MistralOnboardingView.swift index 3de3e29..459573e 100644 --- a/BisonNotes AI/BisonNotes AI/Views/MistralOnboardingView.swift +++ b/BisonNotes AI/BisonNotes AI/Views/MistralOnboardingView.swift @@ -12,6 +12,7 @@ import UIKit struct MistralOnboardingView: View { @Environment(\.dismiss) private var dismiss + @Environment(\.openURL) private var openURL @SecureStorage(KeychainSecretStore.mistralAPIKey) private var mistralAPIKey: String = "" @AppStorage("mistralModel") private var mistralModel: String = MistralAIModel.mistralMedium2508.rawValue @@ -24,8 +25,6 @@ struct MistralOnboardingView: View { @State private var currentStep = 0 @State private var apiKeyInput: String = "" - @State private var showingSafari = false - @State private var safariURL: URL? @State private var isTestingConnection = false @State private var connectionTestPassed = false @State private var connectionTestFailed = false @@ -61,21 +60,6 @@ struct MistralOnboardingView: View { Button("Cancel") { dismiss() } } } - .sheet(isPresented: $showingSafari) { - if let url = safariURL { - #if !targetEnvironment(macCatalyst) - SafariView(url: url) - #endif - } - } - .onChange(of: showingSafari) { _, isShowing in - #if targetEnvironment(macCatalyst) - if isShowing, let url = safariURL { - UIApplication.shared.open(url) - showingSafari = false - } - #endif - } } } @@ -184,8 +168,9 @@ struct MistralOnboardingView: View { ) Button(action: { - safariURL = URL(string: "https://console.mistral.ai") - showingSafari = true + if let url = URL(string: "https://console.mistral.ai") { + openURL(url) + } }) { Label("Open Mistral Console", systemImage: "safari") .fontWeight(.semibold) @@ -267,8 +252,9 @@ struct MistralOnboardingView: View { ) Button(action: { - safariURL = URL(string: "https://console.mistral.ai/api-keys") - showingSafari = true + if let url = URL(string: "https://console.mistral.ai/api-keys") { + openURL(url) + } }) { Label("Open API Keys Page", systemImage: "safari") .fontWeight(.semibold) @@ -531,11 +517,9 @@ struct MistralOnboardingView: View { // MARK: - Actions private func pasteFromClipboard() { - #if canImport(UIKit) - if let clipboardString = UIPasteboard.general.string, !clipboardString.isEmpty { + if let clipboardString = PlatformPasteboard.string, !clipboardString.isEmpty { apiKeyInput = clipboardString.trimmingCharacters(in: .whitespacesAndNewlines) } - #endif } func testConnection() { diff --git a/BisonNotes AI/BisonNotes AI/Views/NativeSummaryWindowView.swift b/BisonNotes AI/BisonNotes AI/Views/NativeSummaryWindowView.swift new file mode 100644 index 0000000..d7c1575 --- /dev/null +++ b/BisonNotes AI/BisonNotes AI/Views/NativeSummaryWindowView.swift @@ -0,0 +1,43 @@ +// +// NativeSummaryWindowView.swift +// BisonNotes AI +// + +#if os(macOS) +import SwiftUI + +/// Resolves a recording at window creation time so native macOS summaries can +/// live in independent, movable windows without copying Core Data objects into +/// the scene value used by `openWindow`. +struct NativeSummaryWindowView: View { + let recordingID: UUID + + @EnvironmentObject private var appCoordinator: AppDataCoordinator + + var body: some View { + Group { + if let completeData = appCoordinator.getCompleteRecordingData(id: recordingID), + let summary = completeData.summary { + SummaryDetailView( + recording: RecordingFile( + url: appCoordinator.getAbsoluteURL(for: completeData.recording) + ?? URL(fileURLWithPath: completeData.recording.recordingURL ?? ""), + name: completeData.recording.recordingName ?? "Unknown", + date: completeData.recording.recordingDate ?? Date(), + duration: completeData.recording.duration, + locationData: appCoordinator.coreDataManager.getLocationData(for: completeData.recording) + ), + summaryData: summary + ) + } else { + ContentUnavailableView( + "Summary Not Available", + systemImage: "doc.text.magnifyingglass", + description: Text("This summary may have been deleted or moved.") + ) + } + } + .frame(minWidth: 620, minHeight: 460) + } +} +#endif diff --git a/BisonNotes AI/BisonNotes AI/Views/OnDeviceAIDownloadView.swift b/BisonNotes AI/BisonNotes AI/Views/OnDeviceAIDownloadView.swift index 91d06e1..21d9c3d 100644 --- a/BisonNotes AI/BisonNotes AI/Views/OnDeviceAIDownloadView.swift +++ b/BisonNotes AI/BisonNotes AI/Views/OnDeviceAIDownloadView.swift @@ -41,6 +41,9 @@ struct OnDeviceAIDownloadView: View { } #if targetEnvironment(macCatalyst) .frame(minWidth: 520, minHeight: 640) + #elseif os(macOS) + .frame(minWidth: 520, minHeight: 480) + .presentationSizing(.page) #endif .onAppear { // Ensure MLX is configured to use the 4B model before checking download state. diff --git a/BisonNotes AI/BisonNotes AI/Views/PreferencesView.swift b/BisonNotes AI/BisonNotes AI/Views/PreferencesView.swift index cad9763..b90f0ef 100644 --- a/BisonNotes AI/BisonNotes AI/Views/PreferencesView.swift +++ b/BisonNotes AI/BisonNotes AI/Views/PreferencesView.swift @@ -13,7 +13,7 @@ struct PreferencesView: View { @State private var showingTimeFormatExample = false var body: some View { - NavigationStack { + PlatformSettingsNavigationStack { ScrollView { VStack(alignment: .leading, spacing: 22) { headerSection @@ -29,12 +29,14 @@ struct PreferencesView: View { .background(Color(.systemGroupedBackground)) .navigationBarTitleDisplayMode(.inline) .toolbar { + #if !os(macOS) ToolbarItem(placement: .topBarLeading) { Button("Done") { dismiss() } .fontWeight(.medium) } + #endif } } } diff --git a/BisonNotes AI/BisonNotes AI/Views/RecordingsListView.swift b/BisonNotes AI/BisonNotes AI/Views/RecordingsListView.swift index c2b84fb..681a00e 100644 --- a/BisonNotes AI/BisonNotes AI/Views/RecordingsListView.swift +++ b/BisonNotes AI/BisonNotes AI/Views/RecordingsListView.swift @@ -17,6 +17,7 @@ class DeletionData: ObservableObject { } struct RecordingsListView: View { + @Environment(\.openWindow) private var openWindow @Environment(\.dismiss) private var dismiss @EnvironmentObject var recorderVM: AudioRecorderViewModel @EnvironmentObject var appCoordinator: AppDataCoordinator @@ -97,6 +98,7 @@ struct RecordingsListView: View { .searchable(text: $searchText, prompt: "Search recordings...") .sheet(isPresented: $showDateFilter) { dateFilterSheet + .nativeMacModalSizing(width: 520, height: 440) } .sheet(isPresented: $showingEnhancedDeleteDialog) { if let recording = deletionData.recordingToDelete, let relationships = deletionData.fileRelationships { @@ -114,6 +116,7 @@ struct RecordingsListView: View { showingEnhancedDeleteDialog = false } ) + .nativeMacModalSizing(width: 680, height: 620) } else { // Loading or error state VStack(spacing: 20) { @@ -149,10 +152,12 @@ struct RecordingsListView: View { .padding() } .padding() + .nativeMacModalSizing(width: 680, height: 620) } } .sheet(item: $selectedLocationData) { locationData in LocationDetailView(locationData: locationData) + .nativeMacModalSizing(width: 680, height: 620) } .sheet(isPresented: $showingCombineView) { if let recordings = recordingsToCombine { @@ -169,6 +174,7 @@ struct RecordingsListView: View { recommendedFirst: recommendedRecording ) .environmentObject(appCoordinator) + .nativeMacModalSizing(width: 760, height: 680) } } .sheet(isPresented: $showingArchiveConfirmation) { @@ -192,46 +198,14 @@ struct RecordingsListView: View { } ) .presentationDetents([.medium, .large]) + .nativeMacModalSizing(width: 680, height: 620) } - .sheet(isPresented: $showingArchiveExportPicker) { - DocumentExportPicker(urls: archiveExportURLs) { success, exportedURLs in - showingArchiveExportPicker = false - if success { - let archivedCount = RecordingArchiveService.shared.archiveRecordings( - recordingsToArchive, - removeLocal: removeLocalAfterArchive, - exportedURLs: exportedURLs - ) - if archivedCount == 0 { - archiveRestoreError = "The export completed, but the selected destination was not iCloud Drive or was not trackable. The audio was left local so you can archive it again to iCloud Drive." - } - isSelectionMode = false - selectedRecordings.removeAll() - loadRecordings() - } - recordingsToArchive = [] - archiveExportURLs = [] - RecordingArchiveService.shared.cleanupArchiveStaging() - } - } - .sheet(isPresented: $showingAudioExportPicker) { - DocumentExportPicker(urls: audioExportURLs) { success, _ in - showingAudioExportPicker = false - if success { - if audioExportSkippedCount > 0 { - let skippedText = audioExportSkippedCount == 1 ? "1 selected recording was" : "\(audioExportSkippedCount) selected recordings were" - archiveRestoreError = "\(skippedText) not exported because the audio is not stored locally. Restore archived audio before exporting it." - } - isSelectionMode = false - selectedRecordings.removeAll() - } - audioExportURLs = [] - audioExportSkippedCount = 0 - RecordingArchiveService.shared.cleanupAudioExportStaging() - } + .background { + exportMoverPresenters } .sheet(isPresented: $showingArchiveOlderThan) { archiveOlderThanSheet + .nativeMacModalSizing(width: 520, height: 440) } .alert("Audio Archived", isPresented: Binding( get: { archiveInfoRecording != nil }, @@ -260,9 +234,11 @@ struct RecordingsListView: View { let transcript = appCoordinator.getTranscriptData(for: recordingId) { EditableTranscriptView(recording: entry, transcript: transcript, transcriptManager: TranscriptManager.shared) .environmentObject(appCoordinator) + .nativeMacModalSizing(width: 820, height: 720) } else { TranscriptDetailView(recording: entry, transcriptText: "") .environmentObject(appCoordinator) + .nativeMacModalSizing(width: 820, height: 720) } } .confirmationDialog( @@ -293,6 +269,7 @@ struct RecordingsListView: View { AudioPlayerView(recording: recording) .environmentObject(recorderVM) .environmentObject(appCoordinator) + .nativeMacModalSizing(width: 720, height: 680) } .onAppear { refreshFileRelationships() @@ -783,7 +760,12 @@ struct RecordingsListView: View { selectedRecordingForPlayer = nil archiveInfoRecording = recording } else { + #if os(macOS) + guard let recordingID = recording.recordingId else { return } + openWindow(id: NativeWindowID.recording, value: recordingID) + #else selectedRecordingForPlayer = recording + #endif } } @@ -884,23 +866,27 @@ struct RecordingsListView: View { clearLocalArchiveState(recording) } } else { + #if os(macOS) + Button { + openOrSelectRecording(recording) + } label: { + playRecordingIcon + } + .buttonStyle(.plain) + .accessibilityLabel("Play Audio for \(recording.name)") + .accessibilityIdentifier("bisonnotes.recording.action.play-audio") + #else NavigationLink { AudioPlayerView(recording: recording) .environmentObject(recorderVM) .environmentObject(appCoordinator) } label: { - Image(systemName: "play.fill") - .font(.headline) - .foregroundColor(.accentColor) - .frame(width: 44, height: 44) - .background( - Color.accentColor.opacity(0.12), - in: RoundedRectangle(cornerRadius: 10, style: .continuous) - ) + playRecordingIcon } .buttonStyle(.plain) .accessibilityLabel("Play Audio for \(recording.name)") .accessibilityIdentifier("bisonnotes.recording.action.play-audio") + #endif } cloudSyncPreferenceButton(for: recording) @@ -916,6 +902,17 @@ struct RecordingsListView: View { } } + private var playRecordingIcon: some View { + Image(systemName: "play.fill") + .font(.headline) + .foregroundColor(.accentColor) + .frame(width: 44, height: 44) + .background( + Color.accentColor.opacity(0.12), + in: RoundedRectangle(cornerRadius: 10, style: .continuous) + ) + } + @ViewBuilder private func cloudSyncPreferenceButton(for recording: AudioRecordingFile) -> some View { if recording.recordingId != nil { @@ -1060,6 +1057,64 @@ struct RecordingsListView: View { return result } + @ViewBuilder + private var exportMoverPresenters: some View { + // SwiftUI logs and refuses the operation when fileMover is mounted with + // an empty files array, even if its presentation binding is false. + if !archiveExportURLs.isEmpty { + Color.clear + .fileMover(isPresented: $showingArchiveExportPicker, files: archiveExportURLs) { result in + completeArchiveExport(exportedURLs: try? result.get()) + } onCancellation: { + completeArchiveExport(exportedURLs: nil) + } + } + + if !audioExportURLs.isEmpty { + Color.clear + .fileMover(isPresented: $showingAudioExportPicker, files: audioExportURLs) { result in + completeAudioExport(success: (try? result.get()) != nil) + } onCancellation: { + completeAudioExport(success: false) + } + } + } + + private func completeArchiveExport(exportedURLs: [URL]?) { + showingArchiveExportPicker = false + if let exportedURLs { + let archivedCount = RecordingArchiveService.shared.archiveRecordings( + recordingsToArchive, + removeLocal: removeLocalAfterArchive, + exportedURLs: exportedURLs + ) + if archivedCount == 0 { + archiveRestoreError = "The export completed, but the selected destination was not iCloud Drive or was not trackable. The audio was left local so you can archive it again to iCloud Drive." + } + isSelectionMode = false + selectedRecordings.removeAll() + loadRecordings() + } + recordingsToArchive = [] + archiveExportURLs = [] + RecordingArchiveService.shared.cleanupArchiveStaging() + } + + private func completeAudioExport(success: Bool) { + showingAudioExportPicker = false + if success { + if audioExportSkippedCount > 0 { + let skippedText = audioExportSkippedCount == 1 ? "1 selected recording was" : "\(audioExportSkippedCount) selected recordings were" + archiveRestoreError = "\(skippedText) not exported because the audio is not stored locally. Restore archived audio before exporting it." + } + isSelectionMode = false + selectedRecordings.removeAll() + } + audioExportURLs = [] + audioExportSkippedCount = 0 + RecordingArchiveService.shared.cleanupAudioExportStaging() + } + private func loadRecordings() { // Use the app coordinator to get recordings with proper database names let recordingsWithData = appCoordinator.getAllRecordingsWithData() @@ -1179,7 +1234,11 @@ struct RecordingsListView: View { } private func showLocationDetails(_ locationData: LocationData) { + #if os(macOS) + openWindow(id: NativeWindowID.location, value: locationData) + #else selectedLocationData = locationData + #endif } private func toggleCloudSyncPreference(for recording: AudioRecordingFile) { @@ -1403,17 +1462,10 @@ struct RecordingsListView: View { if !issues.isEmpty { // Show alert explaining why they can't combine - let alert = UIAlertController( + PlatformAlert.present( title: "Cannot Combine Recordings", - message: "These recordings cannot be combined because:\n\n\(issues.joined(separator: "\n"))\n\nPlease delete the transcripts and/or summaries from both recordings before combining them.", - preferredStyle: .alert + message: "These recordings cannot be combined because:\n\n\(issues.joined(separator: "\n"))\n\nPlease delete the transcripts and/or summaries from both recordings before combining them." ) - alert.addAction(UIAlertAction(title: "OK", style: .default)) - - if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, - let rootViewController = windowScene.windows.first?.rootViewController { - rootViewController.present(alert, animated: true) - } // Exit selection mode isSelectionMode = false @@ -1448,7 +1500,9 @@ struct RecordingsListView: View { _ = try RecordingArchiveService.shared.restoreArchivedRecording(recordingEntry) loadRecordings() refreshFileRelationships() - selectedRecordingForPlayer = recordings.first { $0.recordingId == recordingId } + if let restoredRecording = recordings.first(where: { $0.recordingId == recordingId }) { + openOrSelectRecording(restoredRecording) + } } catch { archiveRestoreError = error.localizedDescription } diff --git a/BisonNotes AI/BisonNotes AI/Views/RecordingsView.swift b/BisonNotes AI/BisonNotes AI/Views/RecordingsView.swift index a5fb025..568629e 100644 --- a/BisonNotes AI/BisonNotes AI/Views/RecordingsView.swift +++ b/BisonNotes AI/BisonNotes AI/Views/RecordingsView.swift @@ -6,24 +6,22 @@ // import SwiftUI -#if !targetEnvironment(macCatalyst) -import SafariServices -#endif +import UniformTypeIdentifiers struct RecordingsView: View { + @Environment(\.openWindow) private var openWindow + @Environment(\.openURL) private var openURL @EnvironmentObject var recorderVM: AudioRecorderViewModel @EnvironmentObject var importManager: FileImportManager @EnvironmentObject var transcriptImportManager: TranscriptImportManager @Environment(\.accessibilityReduceMotion) private var reduceMotion - @StateObject private var documentPickerCoordinator = DocumentPickerCoordinator() - @StateObject private var textDocumentPickerCoordinator = DocumentPickerCoordinator() - @StateObject private var videoPickerCoordinator = DocumentPickerCoordinator() + @State private var showingAudioImporter = false + @State private var showingTranscriptImporter = false @StateObject private var webImportManager = WebImportManager() @ObservedObject private var processingManager = BackgroundProcessingManager.shared @State private var recordings: [AudioRecordingFile] = [] @State private var showingRecordingsList = false @State private var showingBackgroundProcessing = false - @State private var showingHelpDocumentation = false @State private var showingWebImport = false @State private var showingRecorderError = false @State private var recorderErrorMessage = "" @@ -146,6 +144,27 @@ struct RecordingsView: View { .accessibilityIdentifier(BisonNotesAccessibilityID.startRecordingButton) } + // File-importer URLs are security-scoped; hold access for the whole import. + private func handleImport(_ result: Result<[URL], Error>, using importFiles: @escaping ([URL]) async -> Void) { + guard case .success(let urls) = result, !urls.isEmpty else { return } + Task { + let accessedURLs = urls.filter { $0.startAccessingSecurityScopedResource() } + defer { accessedURLs.forEach { $0.stopAccessingSecurityScopedResource() } } + await importFiles(urls) + } + } + + private static let transcriptContentTypes: [UTType] = { + var types: [UTType] = [.plainText, .text, .pdf] + types.append(UTType(importedAs: "org.openxmlformats.wordprocessingml.document")) + for ext in ["md", "markdown", "docx", "doc"] { + if let type = UTType(filenameExtension: ext) { + types.append(type) + } + } + return types + }() + private func recordingActionButton( _ config: RecordingActionConfig, action: @escaping () -> Void @@ -188,7 +207,9 @@ struct RecordingsView: View { Spacer() Button(action: { - showingHelpDocumentation = true + if let url = URL(string: "https://www.bisonnetworking.com/bisonnotes-ai/") { + openURL(url) + } }) { Image(systemName: "questionmark.circle") .font(.title3) @@ -238,7 +259,7 @@ struct RecordingsView: View { accessibilityIdentifier: BisonNotesAccessibilityID.viewRecordingsButton ) ) { - showingRecordingsList = true + presentRecordingsLibrary() } homeActionButton( @@ -250,14 +271,7 @@ struct RecordingsView: View { accessibilityIdentifier: BisonNotesAccessibilityID.importAudioButton ) ) { - // Directly trigger document picker for audio files - documentPickerCoordinator.selectAudioFiles { urls in - if !urls.isEmpty { - Task { - await importManager.importAudioFiles(from: urls) - } - } - } + showingAudioImporter = true } homeActionButton( @@ -273,7 +287,6 @@ struct RecordingsView: View { } // Video import button hidden β€” feature not yet ready for users - // videoPickerCoordinator.selectVideoFiles { ... } homeActionButton( HomeActionConfig( @@ -284,14 +297,7 @@ struct RecordingsView: View { accessibilityIdentifier: BisonNotesAccessibilityID.importTranscriptButton ) ) { - // Trigger document picker for text files - textDocumentPickerCoordinator.selectTextFiles { urls in - if !urls.isEmpty { - Task { - await transcriptImportManager.importTranscriptFiles(from: urls) - } - } - } + showingTranscriptImporter = true } } @@ -311,11 +317,23 @@ struct RecordingsView: View { } .scrollIndicators(.hidden) .background(Color(.systemGroupedBackground)) - .sheet(isPresented: $documentPickerCoordinator.isShowingPicker) { - AudioDocumentPicker(isPresented: $documentPickerCoordinator.isShowingPicker, coordinator: documentPickerCoordinator) + .fileImporter( + isPresented: $showingAudioImporter, + allowedContentTypes: [.audio], + allowsMultipleSelection: true + ) { result in + handleImport(result) { urls in + await importManager.importAudioFiles(from: urls) + } } - .sheet(isPresented: $textDocumentPickerCoordinator.isShowingPicker) { - TextDocumentPicker(isPresented: $textDocumentPickerCoordinator.isShowingPicker, coordinator: textDocumentPickerCoordinator) + .fileImporter( + isPresented: $showingTranscriptImporter, + allowedContentTypes: Self.transcriptContentTypes, + allowsMultipleSelection: true + ) { result in + handleImport(result) { urls in + await transcriptImportManager.importTranscriptFiles(from: urls) + } } .sheet(isPresented: $showingWebImport) { WebImportSheet( @@ -323,26 +341,12 @@ struct RecordingsView: View { fileImportManager: importManager, transcriptImportManager: transcriptImportManager ) + .nativeMacModalSizing(width: 700, height: 620) } - // Video picker sheet hidden β€” feature not yet ready for users - // .sheet(isPresented: $videoPickerCoordinator.isShowingPicker) { ... } + // Video import hidden β€” feature not yet ready for users .sheet(isPresented: $showingBackgroundProcessing) { BackgroundProcessingView() - } - .sheet(isPresented: $showingHelpDocumentation) { - #if !targetEnvironment(macCatalyst) - if let url = URL(string: "https://www.bisonnetworking.com/bisonnotes-ai/") { - SafariView(url: url) - } - #endif - } - .onChange(of: showingHelpDocumentation) { _, isShowing in - #if targetEnvironment(macCatalyst) - if isShowing, let url = URL(string: "https://www.bisonnetworking.com/bisonnotes-ai/") { - UIApplication.shared.open(url) - showingHelpDocumentation = false - } - #endif + .nativeMacModalSizing(width: 760, height: 680) } .alert("Audio Import Results", isPresented: $importManager.showingImportAlert) { Button("OK", role: .cancel) {} @@ -366,22 +370,10 @@ struct RecordingsView: View { } } .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("ImportAudioFromMenu"))) { _ in - documentPickerCoordinator.selectAudioFiles { urls in - if !urls.isEmpty { - Task { - await importManager.importAudioFiles(from: urls) - } - } - } + showingAudioImporter = true } .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("ImportTranscriptFromMenu"))) { _ in - textDocumentPickerCoordinator.selectTextFiles { urls in - if !urls.isEmpty { - Task { - await transcriptImportManager.importTranscriptFiles(from: urls) - } - } - } + showingTranscriptImporter = true } .onReceive( NotificationCenter.default.publisher(for: NSNotification.Name("ImportFromLinkFromMenu")) @@ -405,6 +397,7 @@ struct RecordingsView: View { RecordingsListView() .environment(\.isEmbeddedInSplitView, false) .environmentObject(recorderVM) + .nativeMacModalSizing(width: 900, height: 720) } } @@ -506,7 +499,7 @@ struct RecordingsView: View { private var backgroundProcessingIndicator: some View { Button(action: { - showingBackgroundProcessing = true + presentBackgroundProcessing() }) { HStack { Image(systemName: "gear.circle.fill") @@ -542,6 +535,22 @@ struct RecordingsView: View { .buttonStyle(PlainButtonStyle()) } + private func presentRecordingsLibrary() { + #if os(macOS) + openWindow(id: NativeWindowID.recordings) + #else + showingRecordingsList = true + #endif + } + + private func presentBackgroundProcessing() { + #if os(macOS) + openWindow(id: NativeWindowID.backgroundProcessing) + #else + showingBackgroundProcessing = true + #endif + } + // MARK: - Phase 5: UI Helper Methods @State private var animationActive = true @@ -657,6 +666,3 @@ struct RecordingsView: View { .cornerRadius(8) } } - -// MARK: - Safari View Wrapper -// SafariView is now in Views/SafariView.swift diff --git a/BisonNotes AI/BisonNotes AI/Views/SafariView.swift b/BisonNotes AI/BisonNotes AI/Views/SafariView.swift deleted file mode 100644 index 02d64e7..0000000 --- a/BisonNotes AI/BisonNotes AI/Views/SafariView.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// SafariView.swift -// Audio Journal -// -// Reusable SFSafariViewController wrapper for SwiftUI -// - -import SwiftUI -#if !targetEnvironment(macCatalyst) -import SafariServices -#endif - -#if !targetEnvironment(macCatalyst) -struct SafariView: UIViewControllerRepresentable { - let url: URL - - func makeUIViewController(context: Context) -> SFSafariViewController { - let safariVC = SFSafariViewController(url: url) - safariVC.preferredBarTintColor = UIColor.systemBackground - safariVC.preferredControlTintColor = UIColor.systemBlue - safariVC.dismissButtonStyle = .close - return safariVC - } - - func updateUIViewController(_ uiViewController: SFSafariViewController, context: Context) { - // No updates needed - } -} -#endif diff --git a/BisonNotes AI/BisonNotes AI/Views/SettingsView.swift b/BisonNotes AI/BisonNotes AI/Views/SettingsView.swift index b3f9b8d..a43f97b 100644 --- a/BisonNotes AI/BisonNotes AI/Views/SettingsView.swift +++ b/BisonNotes AI/BisonNotes AI/Views/SettingsView.swift @@ -14,6 +14,7 @@ import CoreGraphics struct SettingsView: View { @Environment(\.dismiss) private var dismiss + @Environment(\.openWindow) private var openWindow @EnvironmentObject var recorderVM: AudioRecorderViewModel @EnvironmentObject var appCoordinator: AppDataCoordinator @StateObject private var regenerationManager: SummaryRegenerationManager @@ -64,10 +65,30 @@ struct SettingsView: View { .navigationTitle("Settings") .navigationBarTitleDisplayMode(.inline) .toolbar { + #if !os(macOS) ToolbarItem(placement: .navigationBarTrailing) { Button("Done") { dismiss() } } + #endif } + #if os(macOS) + .navigationDestination(isPresented: $showingAISettings) { + AISettingsView() + .environmentObject(recorderVM) + } + .navigationDestination(isPresented: $showingTranscriptionSettings) { + TranscriptionSettingsView() + } + .navigationDestination(isPresented: $showingBackgroundProcessing) { + BackgroundProcessingView() + } + .navigationDestination(isPresented: $showingPreferences) { + PreferencesView() + } + .navigationDestination(isPresented: $showingAcknowledgements) { + AcknowledgementsView() + } + #endif } .alert("Regeneration Complete", isPresented: $regenerationManager.showingRegenerationAlert) { Button("OK") { @@ -113,6 +134,8 @@ struct SettingsView: View { .sheet(isPresented: $showingCloudReview) { CloudReviewItemsView(includeAudioFiles: iCloudBackupIncludeAudioFiles) .environmentObject(appCoordinator) + .nativeMacModalSizing(width: 780, height: 700) + .nativeMacModalDismissControl() } .onAppear { refreshEngineStatuses() @@ -149,6 +172,7 @@ struct SettingsView: View { SummaryManager.shared.setEngine(AIEngineType.appleNative.rawValue) } } + #if !os(macOS) .sheet(isPresented: $showingAISettings) { AISettingsView() .environmentObject(recorderVM) @@ -159,16 +183,19 @@ struct SettingsView: View { .sheet(isPresented: $showingBackgroundProcessing) { BackgroundProcessingView() } - .sheet(isPresented: $showingDataMigration) { - DataMigrationView() - .environmentObject(appCoordinator) - } .sheet(isPresented: $showingPreferences) { PreferencesView() } .sheet(isPresented: $showingAcknowledgements) { AcknowledgementsView() } + #endif + .sheet(isPresented: $showingDataMigration) { + DataMigrationView() + .environmentObject(appCoordinator) + .nativeMacModalSizing(width: 800, height: 700) + .nativeMacModalDismissControl("Cancel") + } .overlay { if isPreparingLogs { ZStack { @@ -275,29 +302,6 @@ struct SettingsView: View { systemImage: "mic.fill", tint: .green ) - - Toggle(isOn: Binding( - get: { recorderVM.isMacSystemAudioCaptureEnabled }, - set: { handleMacSystemAudioCaptureToggle($0) } - )) { - ModernSettingsLabel( - title: "Record Meeting Audio", - subtitle: "Capture audio playing from other Mac apps while recording", - systemImage: "macwindow.on.rectangle", - tint: .purple - ) - } - .disabled(recorderVM.isRecording) - .accessibilityValue(AccessibilitySupport.statusValue(isOn: recorderVM.isMacSystemAudioCaptureEnabled)) - - if recorderVM.isMacSystemAudioCaptureEnabled { - ModernInlineStatus( - title: "Meeting audio capture is enabled", - subtitle: "If macOS permission changes later, BisonNotes saves microphone audio only.", - systemImage: "rectangle.dashed.badge.record", - tint: .orange - ) - } #else if recorderVM.availableInputs.isEmpty { ModernInlineStatus( @@ -335,6 +339,33 @@ struct SettingsView: View { Divider() #endif + #if targetEnvironment(macCatalyst) || os(macOS) + Toggle(isOn: Binding( + get: { recorderVM.isMacSystemAudioCaptureEnabled }, + set: { handleMacSystemAudioCaptureToggle($0) } + )) { + ModernSettingsLabel( + title: "Record Meeting Audio", + subtitle: "Capture audio playing from other Mac apps while recording", + systemImage: "macwindow.on.rectangle", + tint: .purple + ) + } + .disabled(recorderVM.isRecording) + .accessibilityValue(AccessibilitySupport.statusValue(isOn: recorderVM.isMacSystemAudioCaptureEnabled)) + + if recorderVM.isMacSystemAudioCaptureEnabled { + ModernInlineStatus( + title: "Meeting audio capture is enabled", + subtitle: "If macOS permission changes later, BisonNotes saves microphone audio only.", + systemImage: "rectangle.dashed.badge.record", + tint: .orange + ) + } + + Divider() + #endif + Toggle(isOn: Binding( get: { recorderVM.isLocationTrackingEnabled }, set: { recorderVM.toggleLocationTracking($0) } @@ -545,7 +576,7 @@ struct SettingsView: View { subtitle: "Manage transcription and summarization jobs", systemImage: "gearshape.2", tint: .blue, - action: { showingBackgroundProcessing = true } + action: { presentBackgroundProcessing() } ) Button { @@ -879,54 +910,39 @@ struct SettingsView: View { if !cloudOnlySummaries.isEmpty { await MainActor.run { - let alert = UIAlertController( + PlatformAlert.present( title: "iCloud Data Found", message: "We found \(cloudOnlySummaries.count) summaries in your iCloud that aren't on this device. Would you like to download them?", - preferredStyle: .alert - ) - alert.addAction(UIAlertAction(title: "Cancel", style: .cancel)) - alert.addAction(UIAlertAction(title: "Download", style: .default) { _ in - Task { - do { - let count = try await iCloudManager.downloadSummariesFromCloud(appCoordinator: appCoordinator, forRecovery: true) - AppLog.shared.log("Downloaded \(count) summaries from iCloud", category: .general) - } catch { - AppLog.shared.log("Failed to download summaries: \(error)", level: .error, category: .general) + actions: [ + PlatformAlert.Action(title: "Cancel", isCancel: true), + PlatformAlert.Action(title: "Download") { + Task { + do { + let count = try await iCloudManager.downloadSummariesFromCloud(appCoordinator: appCoordinator, forRecovery: true) + AppLog.shared.log("Downloaded \(count) summaries from iCloud", category: .general) + } catch { + AppLog.shared.log("Failed to download summaries: \(error)", level: .error, category: .general) + } + } } - } - }) - if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, - let rootViewController = windowScene.windows.first?.rootViewController { - rootViewController.present(alert, animated: true) - } + ] + ) } } else { await MainActor.run { - let alert = UIAlertController( + PlatformAlert.present( title: "No iCloud Data", - message: "No summaries were found in your iCloud account.", - preferredStyle: .alert + message: "No summaries were found in your iCloud account." ) - alert.addAction(UIAlertAction(title: "OK", style: .default)) - if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, - let rootViewController = windowScene.windows.first?.rootViewController { - rootViewController.present(alert, animated: true) - } } } } catch { AppLog.shared.log("Failed to check for iCloud data: \(error)", level: .error, category: .general) await MainActor.run { - let alert = UIAlertController( + PlatformAlert.present( title: "Check Failed", - message: "Could not check for iCloud data: \(error.localizedDescription)", - preferredStyle: .alert + message: "Could not check for iCloud data: \(error.localizedDescription)" ) - alert.addAction(UIAlertAction(title: "OK", style: .default)) - if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, - let rootViewController = windowScene.windows.first?.rootViewController { - rootViewController.present(alert, animated: true) - } } } } @@ -1001,7 +1017,7 @@ struct SettingsView: View { } Button { - showingBackgroundProcessing = true + presentBackgroundProcessing() } label: { HStack { VStack(alignment: .leading, spacing: 2) { @@ -1078,6 +1094,14 @@ struct SettingsView: View { } } + private func presentBackgroundProcessing() { + #if os(macOS) + openWindow(id: NativeWindowID.backgroundProcessing) + #else + showingBackgroundProcessing = true + #endif + } + private var aboutSection: some View { Section("About") { Button { @@ -1163,6 +1187,7 @@ struct SettingsView: View { } } + #if os(iOS) private func microphoneTypeDescription(for portType: AVAudioSession.Port) -> String { switch portType { case .builtInMic: @@ -1187,6 +1212,7 @@ struct SettingsView: View { return portType.rawValue.capitalized } } + #endif private func handleMacSystemAudioCaptureToggle(_ enabled: Bool) { #if targetEnvironment(macCatalyst) @@ -1221,7 +1247,7 @@ struct SettingsView: View { guard let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture") else { return } - UIApplication.shared.open(url) + PlatformApp.open(url) #endif } @@ -1346,54 +1372,39 @@ struct SettingsView: View { if !cloudOnlySummaries.isEmpty { await MainActor.run { - let alert = UIAlertController( + PlatformAlert.present( title: "iCloud Data Found", message: "We found \(cloudOnlySummaries.count) summaries in your iCloud that aren't on this device. Would you like to download them?", - preferredStyle: .alert - ) - alert.addAction(UIAlertAction(title: "Cancel", style: .cancel)) - alert.addAction(UIAlertAction(title: "Download", style: .default) { _ in - Task { - do { - let count = try await iCloudManager.downloadSummariesFromCloud(appCoordinator: appCoordinator, forRecovery: true) - AppLog.shared.log("Downloaded \(count) summaries from iCloud", category: .general) - } catch { - AppLog.shared.log("Failed to download summaries: \(error)", level: .error, category: .general) + actions: [ + PlatformAlert.Action(title: "Cancel", isCancel: true), + PlatformAlert.Action(title: "Download") { + Task { + do { + let count = try await iCloudManager.downloadSummariesFromCloud(appCoordinator: appCoordinator, forRecovery: true) + AppLog.shared.log("Downloaded \(count) summaries from iCloud", category: .general) + } catch { + AppLog.shared.log("Failed to download summaries: \(error)", level: .error, category: .general) + } + } } - } - }) - if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, - let rootViewController = windowScene.windows.first?.rootViewController { - rootViewController.present(alert, animated: true) - } + ] + ) } } else { await MainActor.run { - let alert = UIAlertController( + PlatformAlert.present( title: "No iCloud Data", - message: "No summaries were found in your iCloud account.", - preferredStyle: .alert + message: "No summaries were found in your iCloud account." ) - alert.addAction(UIAlertAction(title: "OK", style: .default)) - if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, - let rootViewController = windowScene.windows.first?.rootViewController { - rootViewController.present(alert, animated: true) - } } } } catch { AppLog.shared.log("Failed to check for iCloud data: \(error)", level: .error, category: .general) await MainActor.run { - let alert = UIAlertController( + PlatformAlert.present( title: "Check Failed", - message: "Could not check for iCloud data: \(error.localizedDescription)", - preferredStyle: .alert + message: "Could not check for iCloud data: \(error.localizedDescription)" ) - alert.addAction(UIAlertAction(title: "OK", style: .default)) - if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, - let rootViewController = windowScene.windows.first?.rootViewController { - rootViewController.present(alert, animated: true) - } } } } @@ -1775,6 +1786,10 @@ private struct ModernSettingsNavigationRow: View { value: subtitle, hint: "Opens \(title)." ) + .accessibilityAddTraits(.isButton) + .accessibilityAction { + action() + } } } diff --git a/BisonNotes AI/BisonNotes AI/Views/SimpleSettingsView.swift b/BisonNotes AI/BisonNotes AI/Views/SimpleSettingsView.swift index 2c86b08..df8aff8 100644 --- a/BisonNotes AI/BisonNotes AI/Views/SimpleSettingsView.swift +++ b/BisonNotes AI/BisonNotes AI/Views/SimpleSettingsView.swift @@ -6,10 +6,6 @@ // import SwiftUI -import UIKit -#if !targetEnvironment(macCatalyst) -import SafariServices -#endif enum ProcessingOption: String, CaseIterable { case openai = "OpenAI" @@ -72,6 +68,10 @@ enum ProcessingOption: String, CaseIterable { struct SimpleSettingsView: View { @Environment(\.dismiss) private var dismiss + @Environment(\.openURL) private var openURL + #if os(macOS) + @Environment(\.openSettings) private var openSettings + #endif @EnvironmentObject var recorderVM: AudioRecorderViewModel @EnvironmentObject var appCoordinator: AppDataCoordinator @State private var selectedOption: ProcessingOption = .chooseLater @@ -83,7 +83,6 @@ struct SimpleSettingsView: View { @State private var isFirstLaunch = false @State private var deviceSupported = false @State private var showingOnDeviceLLMSettings = false - @State private var showingHelpDocumentation = false @State private var showingOnDeviceAIDownload = false @State private var showingMistralOnboarding = false @@ -148,31 +147,20 @@ struct SimpleSettingsView: View { } } } + #if !os(macOS) .sheet(isPresented: $showingAdvancedSettings) { // SettingsView provides its own NavigationStack and Done toolbar. SettingsView() .environmentObject(recorderVM) .environmentObject(appCoordinator) } + #endif .sheet(isPresented: $showingOnDeviceLLMSettings) { NavigationStack { OnDeviceLLMSettingsView() } - } - .sheet(isPresented: $showingHelpDocumentation) { - #if !targetEnvironment(macCatalyst) - if let url = URL(string: "https://www.bisonnetworking.com/bisonnotes-ai/#simple-vs-advanced-settings") { - SafariView(url: url) - } - #endif - } - .onChange(of: showingHelpDocumentation) { _, isShowing in - #if targetEnvironment(macCatalyst) - if isShowing, let url = URL(string: "https://www.bisonnetworking.com/bisonnotes-ai/#simple-vs-advanced-settings") { - UIApplication.shared.open(url) - showingHelpDocumentation = false - } - #endif + .nativeMacModalSizing(width: 760, height: 700) + .nativeMacModalDismissControl() } .sheet(isPresented: $showingOnDeviceAIDownload) { OnDeviceAIDownloadView( @@ -182,8 +170,9 @@ struct SimpleSettingsView: View { showingOnDeviceAIDownload = false } ) + .nativeMacModalSizing(width: 700, height: 620) } - .fullScreenCover(isPresented: $showingMistralOnboarding) { + .platformFullScreenCover(isPresented: $showingMistralOnboarding) { MistralOnboardingView(onSetupComplete: { // Mistral onboarding completed β€” mark first setup done and navigate UserDefaults.standard.set(true, forKey: "hasCompletedFirstSetup") @@ -222,9 +211,7 @@ struct SimpleSettingsView: View { Spacer(minLength: 8) - Button(action: { - showingAdvancedSettings = true - }) { + Button(action: presentAdvancedSettings) { Image(systemName: "gearshape.fill") .font(.system(size: 17, weight: .semibold)) .foregroundStyle(.secondary) @@ -393,7 +380,9 @@ struct SimpleSettingsView: View { } Button(action: { - showingHelpDocumentation = true + if let url = URL(string: "https://www.bisonnetworking.com/bisonnotes-ai/#simple-vs-advanced-settings") { + openURL(url) + } }) { Label { Text("Learn More About Processing Options") @@ -574,7 +563,7 @@ struct SimpleSettingsView: View { // Immediately open the advanced settings page try await Task.sleep(nanoseconds: 500_000_000) // Brief delay to show message await MainActor.run { - showingAdvancedSettings = true + presentAdvancedSettings() } } else if selectedOption == .mistralAI { // Mistral AI with existing key β€” activate as the selected engine @@ -672,6 +661,15 @@ struct SimpleSettingsView: View { } } } + + @MainActor + private func presentAdvancedSettings() { + #if os(macOS) + openSettings() + #else + showingAdvancedSettings = true + #endif + } } private struct SetupCard: View { diff --git a/BisonNotes AI/BisonNotes AI/Views/TranscriptViews.swift b/BisonNotes AI/BisonNotes AI/Views/TranscriptViews.swift index e95e71d..4a41a39 100644 --- a/BisonNotes AI/BisonNotes AI/Views/TranscriptViews.swift +++ b/BisonNotes AI/BisonNotes AI/Views/TranscriptViews.swift @@ -23,6 +23,7 @@ private struct TranscriptWithDate { } struct TranscriptsView: View { + @Environment(\.openWindow) private var openWindow @EnvironmentObject var recorderVM: AudioRecorderViewModel @EnvironmentObject var appCoordinator: AppDataCoordinator @StateObject private var enhancedTranscriptionManager = EnhancedTranscriptionManager() @@ -46,6 +47,8 @@ struct TranscriptsView: View { @State private var dateFilterEnd: Date = Date() @State private var isDateFilterActive = false @State private var expandedTranscriptDateSections: Set = [.today] + @State private var isPendingTranscriptsExpanded = false + @State private var isTranscriptArchiveExpanded = false /// Shared service that owns the serial audio-cleanup queue and transcription start. @ObservedObject private var transcriptionStarter = TranscriptionStarter.shared /// Recordings whose summary generation we kicked off and are still awaiting completion. @@ -61,14 +64,17 @@ struct TranscriptsView: View { EditableTranscriptView(recording: recording, transcript: transcript, transcriptManager: TranscriptManager.shared) .environmentObject(appCoordinator) .environmentObject(recorderVM) + .nativeMacModalSizing(width: 820, height: 720) } else { TranscriptDetailView(recording: recording, transcriptText: "") .environmentObject(appCoordinator) .environmentObject(recorderVM) + .nativeMacModalSizing(width: 820, height: 720) } } .sheet(item: $selectedLocationData) { locationData in LocationDetailView(locationData: locationData) + .nativeMacModalSizing(width: 680, height: 620) } .confirmationDialog( "Clean Audio Before Transcribing?", @@ -135,6 +141,7 @@ struct TranscriptsView: View { } .sheet(isPresented: $showDateFilter) { dateFilterSheet + .nativeMacModalSizing(width: 520, height: 440) } .onAppear { loadRecordings() @@ -303,33 +310,10 @@ struct TranscriptsView: View { } private func transcriptsListView(_ filtered: [(recording: RecordingEntry, transcript: TranscriptData?)], _ filteredImported: [(recording: RecordingEntry, transcript: TranscriptData?)]) -> some View { - #if targetEnvironment(macCatalyst) - // On Mac Catalyst, the preview-+-NavigationLink-to-More pattern wedges the responder chain - // (destination renders but becomes unresponsive). Render everything inline instead. - let sectioned = DateSectionHelper.groupBySection( - transcriptItemsWithDates(filtered, source: .audio) + transcriptItemsWithDates(filteredImported, source: .imported), - dateKeyPath: \.date - ) - - return List { - ForEach(sectioned, id: \.section) { sectionData in - Section( - header: CollapsibleDateSectionHeader( - title: sectionData.section.title, - count: sectionData.items.count, - isExpanded: isTranscriptDateSectionExpanded(sectionData.section), - isAlwaysExpanded: false, - onToggle: { toggleTranscriptDateSection(sectionData.section) } - ) - ) { - if isTranscriptDateSectionExpanded(sectionData.section) { - transcriptDateSectionRows(sectionData.items) - } - } - } - } - .id("list-\(isDateFilterActive)-\(dateFilterStart)-\(dateFilterEnd)-\(searchText)") - .accessibilityIdentifier(BisonNotesAccessibilityID.transcriptList) + #if os(macOS) || targetEnvironment(macCatalyst) + // A NavigationLink to a List with interactive section headers can wedge the + // responder chain on both Mac implementations. Keep the complete archive inline. + return macTranscriptsListView(filtered, filteredImported) #else // iOS / iPadOS: preview cards with "More" navigation to the full list page. let recentRecordings = Array(filtered.prefix(3)) @@ -395,6 +379,132 @@ struct TranscriptsView: View { #endif } + private func macTranscriptsListView( + _ filtered: [(recording: RecordingEntry, transcript: TranscriptData?)], + _ filteredImported: [(recording: RecordingEntry, transcript: TranscriptData?)] + ) -> some View { + let availableRecordings = filtered.filter { $0.transcript != nil } + let availableImported = filteredImported.filter { $0.transcript != nil } + let pendingRecordings = filtered.filter { $0.transcript == nil } + let availableTranscripts = ( + transcriptItemsWithDates(availableRecordings, source: .audio) + + transcriptItemsWithDates(availableImported, source: .imported) + ).sorted { $0.date > $1.date } + let recentTranscripts = Array(availableTranscripts.prefix(3)) + let archivedTranscripts = Array(availableTranscripts.dropFirst(recentTranscripts.count)) + let sectioned = DateSectionHelper.groupBySection( + archivedTranscripts, + dateKeyPath: \.date + ) + + return ScrollView { + LazyVStack(alignment: .leading, spacing: 20) { + if !recentTranscripts.isEmpty { + transcriptSectionHeader( + title: "Recent Transcripts", + count: availableTranscripts.count, + systemImage: "text.document.fill" + ) + recentTranscriptRows(recentTranscripts) + } + + if !archivedTranscripts.isEmpty { + Button { + withAnimation(.easeInOut(duration: 0.2)) { + isTranscriptArchiveExpanded.toggle() + } + } label: { + inlineTranscriptArchiveRow( + count: archivedTranscripts.count, + isExpanded: isTranscriptArchiveExpanded + ) + } + .buttonStyle(.plain) + + if isTranscriptArchiveExpanded { + ForEach(sectioned, id: \.section) { sectionData in + CollapsibleDateSectionHeader( + title: sectionData.section.title, + count: sectionData.items.count, + isExpanded: isTranscriptDateSectionExpanded(sectionData.section), + isAlwaysExpanded: false, + onToggle: { toggleTranscriptDateSection(sectionData.section) } + ) + + if isTranscriptDateSectionExpanded(sectionData.section) { + transcriptDateSectionRows(sectionData.items) + } + } + } + } + + if !pendingRecordings.isEmpty { + CollapsibleDateSectionHeader( + title: "Ready to Transcribe", + count: pendingRecordings.count, + isExpanded: isPendingTranscriptsExpanded, + isAlwaysExpanded: false, + onToggle: { isPendingTranscriptsExpanded.toggle() } + ) + + if isPendingTranscriptsExpanded { + ForEach(pendingRecordings, id: \.recording.objectID) { item in + recordingRowView(item) + } + } + } + } + .padding(.horizontal, 20) + .padding(.top, 18) + .padding(.bottom, 96) + .frame(maxWidth: 700) + .frame(maxWidth: .infinity) + } + .background(Color(.systemGroupedBackground)) + .refreshable { loadRecordings() } + .id("list-\(isDateFilterActive)-\(dateFilterStart)-\(dateFilterEnd)-\(searchText)") + .accessibilityIdentifier(BisonNotesAccessibilityID.transcriptList) + } + + @ViewBuilder + private func recentTranscriptRows(_ items: [TranscriptWithDate]) -> some View { + ForEach(items, id: \.recording.objectID) { item in + if item.source == .audio { + recordingRowView((recording: item.recording, transcript: item.transcript)) + } else { + importedTranscriptRowView((recording: item.recording, transcript: item.transcript)) + } + } + } + + private func inlineTranscriptArchiveRow(count: Int, isExpanded: Bool) -> some View { + HStack(spacing: 12) { + Image(systemName: "archivebox") + .font(.title3) + .foregroundColor(.accentColor) + + VStack(alignment: .leading, spacing: 2) { + Text(isExpanded ? "Hide older transcripts" : "Browse older transcripts") + .font(.subheadline.weight(.semibold)) + Text("\(count) older \(count == 1 ? "transcript" : "transcripts")") + .font(.caption) + .foregroundColor(.secondary) + } + + Spacer() + + Image(systemName: isExpanded ? "chevron.up" : "chevron.down") + .font(.caption.weight(.semibold)) + .foregroundColor(.secondary) + } + .padding(14) + .background(Color(.secondarySystemGroupedBackground)) + .clipShape(RoundedRectangle(cornerRadius: 15)) + .contentShape(Rectangle()) + .accessibilityElement(children: .combine) + .accessibilityHint(isExpanded ? "Collapses the transcript archive." : "Expands the transcript archive inline.") + } + private var audioRecordingsFullListView: some View { struct RecordingWithDate { let recording: RecordingEntry @@ -403,7 +513,10 @@ struct TranscriptsView: View { } // Respect the same date/search filters as the main page - let recordingsWithDates: [RecordingWithDate] = filteredRecordings.compactMap { item in + let availableRecordings = filteredRecordings.filter { $0.transcript != nil } + let pendingRecordings = filteredRecordings.filter { $0.transcript == nil } + + let recordingsWithDates: [RecordingWithDate] = availableRecordings.compactMap { item in guard let date = item.recording.recordingDate else { return nil } return RecordingWithDate(recording: item.recording, transcript: item.transcript, date: date) } @@ -436,6 +549,27 @@ struct TranscriptsView: View { } } } + + if !pendingRecordings.isEmpty { + Section( + header: CollapsibleDateSectionHeader( + title: "Ready to Transcribe", + count: pendingRecordings.count, + isExpanded: isPendingTranscriptsExpanded, + isAlwaysExpanded: false, + onToggle: { isPendingTranscriptsExpanded.toggle() } + ) + ) { + if isPendingTranscriptsExpanded { + ForEach(pendingRecordings, id: \.recording.objectID) { item in + recordingRowView(item) + .listRowInsets(EdgeInsets(top: 6, leading: 16, bottom: 6, trailing: 16)) + .listRowSeparator(.hidden) + .listRowBackground(Color.clear) + } + } + } + } } .listStyle(.plain) .scrollContentBackground(.hidden) @@ -461,6 +595,7 @@ struct TranscriptsView: View { // Respect the same date/search filters as the main page let importedWithDates: [ImportedWithDate] = filteredImportedTranscripts.compactMap { item in + guard item.transcript != nil else { return nil } guard let date = item.recording.recordingDate else { return nil } return ImportedWithDate(recording: item.recording, transcript: item.transcript, date: date) } @@ -655,7 +790,7 @@ struct TranscriptsView: View { ) -> some View { HStack(alignment: .center, spacing: 12) { Button(action: { - selectedRecording = recordingData.recording + presentTranscript(recordingData.recording) }) { importedTranscriptRowContent(recordingData, showsChevron: onDelete == nil) } @@ -790,7 +925,7 @@ struct TranscriptsView: View { private func locationButtonView(_ locationData: LocationData, recordingURL: URL) -> some View { Button(action: { - selectedLocationData = locationData + presentLocation(locationData) }) { HStack { Image(systemName: "location.fill") @@ -817,7 +952,7 @@ struct TranscriptsView: View { return Button(action: { if hasTranscript { // Show existing transcript for editing - always allowed - selectedRecording = recordingData.recording + presentTranscript(recordingData.recording) } else { // Generate new transcript - only if this recording doesn't already have an active job if !isProcessing { @@ -855,6 +990,23 @@ struct TranscriptsView: View { .id("\(recordingData.recording.id?.uuidString ?? "unknown")-\(hasTranscript)-\(hasActiveJob)-\(isCleaning)-\(isQueuedForCleanup)-\(refreshTrigger)") } + private func presentTranscript(_ recording: RecordingEntry) { + #if os(macOS) + guard let recordingID = recording.id else { return } + openWindow(id: NativeWindowID.transcript, value: recordingID) + #else + selectedRecording = recording + #endif + } + + private func presentLocation(_ locationData: LocationData) { + #if os(macOS) + openWindow(id: NativeWindowID.location, value: locationData) + #else + selectedLocationData = locationData + #endif + } + /// Returns the appropriate label for the processing button based on current phase private func processingButtonLabel(isCleaning: Bool, isQueuedForCleanup: Bool, jobStatus: JobProcessingStatus?) -> String { if isCleaning { @@ -1406,86 +1558,22 @@ struct EditableTranscriptView: View { } var body: some View { - // NavigationStack { Form } is the only sheet pattern that scrolls reliably - // on Mac Catalyst. See feedback_mac_catalyst_scrollview.md. NavigationStack { - Form { - Section { - recordingTitleEditor - } - - if editedSegments.isEmpty { - Section { - VStack(spacing: 16) { - Image(systemName: "doc.text") - .font(.system(size: 48)) - .foregroundColor(.accentColor) - Text("No transcript content available") - .font(.title3) - .fontWeight(.semibold) - .foregroundColor(.secondary) - Text("Transcript segments: \(editedSegments.count)") - .font(.caption) - .foregroundColor(.secondary) - } - .frame(maxWidth: .infinity) - .padding(.vertical, 24) - } - } else { - if !uniqueSpeakers.isEmpty { - Section { - Button { - showingSpeakerEditor = true - } label: { - HStack { - Image(systemName: "person.2.fill") - .foregroundColor(.purple) - Text("Edit Speakers (\(uniqueSpeakers.count))") - .foregroundColor(.primary) - Spacer() - Image(systemName: "chevron.right") - .font(.caption) - .foregroundColor(.secondary) - } - .contentShape(Rectangle()) - } - .buttonStyle(.plain) - .accessibilityLabel("Edit Speakers") - .accessibilityValue( - AccessibilitySupport.itemCount(uniqueSpeakers.count, singular: "speaker") - ) - } - } - - Section("Segments") { - ForEach(Array(editedSegments.enumerated()), id: \.offset) { index, _ in - TranscriptSegmentView(segment: $editedSegments[index], speakerMappings: speakerMappings) - } - } - .id("transcript-\(editedSegments.count)-\(editedSegments.first?.text.prefix(10).hashValue ?? 0)") + Group { + #if os(macOS) + // Native macOS needs one explicit scroll owner for the full + // transcript. Each segment editor expands instead of scrolling. + List { + transcriptSections } - - summarySection - - Section { - Button { - showingRerunAlert = true - } label: { - HStack { - if isRerunningTranscription { - ProgressView().scaleEffect(0.8) - Text("Rerunning Transcription...") - } else { - Image(systemName: "arrow.clockwise") - Text("Rerun Transcription") - } - Spacer() - } - .contentShape(Rectangle()) - } - .buttonStyle(.plain) - .disabled(isRerunningTranscription) + .listStyle(.inset) + .scrollIndicators(.visible) + #else + // Form preserves the established iOS and Catalyst behavior. + Form { + transcriptSections } + #endif } .scrollContentBackground(.hidden) .background(Color(.systemGroupedBackground)) @@ -1546,9 +1634,37 @@ struct EditableTranscriptView: View { speakerIds: uniqueSpeakers, speakerMappings: $speakerMappings ) + .nativeMacModalSizing(width: 620, height: 560) } .sheet(isPresented: $showSummarySheet) { + #if os(macOS) + VStack(spacing: 0) { + HStack { + Text("Summary") + .font(.headline) + Spacer() + Button("Done") { + showSummarySheet = false + } + .keyboardShortcut(.cancelAction) + .accessibilityHint("Closes the summary and returns to the transcript.") + } + .padding(.horizontal, 16) + .padding(.vertical, 10) + .background(.bar) + + Divider() + + summarySheetContent + } + .onExitCommand { + showSummarySheet = false + } + .nativeMacModalSizing(width: 760, height: 680) + #else summarySheetContent + .nativeMacModalSizing(width: 760, height: 680) + #endif } .alert("Unable to Generate Summary", isPresented: Binding( get: { summaryGenerationError != nil }, @@ -1587,6 +1703,86 @@ struct EditableTranscriptView: View { } } + @ViewBuilder + private var transcriptSections: some View { + Section { + recordingTitleEditor + } + + if editedSegments.isEmpty { + Section { + VStack(spacing: 16) { + Image(systemName: "doc.text") + .font(.system(size: 48)) + .foregroundColor(.accentColor) + Text("No transcript content available") + .font(.title3) + .fontWeight(.semibold) + .foregroundColor(.secondary) + Text("Transcript segments: \(editedSegments.count)") + .font(.caption) + .foregroundColor(.secondary) + } + .frame(maxWidth: .infinity) + .padding(.vertical, 24) + } + } else { + if !uniqueSpeakers.isEmpty { + Section { + Button { + showingSpeakerEditor = true + } label: { + HStack { + Image(systemName: "person.2.fill") + .foregroundColor(.purple) + Text("Edit Speakers (\(uniqueSpeakers.count))") + .foregroundColor(.primary) + Spacer() + Image(systemName: "chevron.right") + .font(.caption) + .foregroundColor(.secondary) + } + .contentShape(Rectangle()) + } + .buttonStyle(.plain) + .accessibilityLabel("Edit Speakers") + .accessibilityValue( + AccessibilitySupport.itemCount(uniqueSpeakers.count, singular: "speaker") + ) + } + } + + Section("Segments") { + ForEach(Array(editedSegments.enumerated()), id: \.offset) { index, _ in + TranscriptSegmentView(segment: $editedSegments[index], speakerMappings: speakerMappings) + } + } + .id("transcript-\(editedSegments.count)-\(editedSegments.first?.text.prefix(10).hashValue ?? 0)") + } + + summarySection + + Section { + Button { + showingRerunAlert = true + } label: { + HStack { + if isRerunningTranscription { + ProgressView().scaleEffect(0.8) + Text("Rerunning Transcription...") + } else { + Image(systemName: "arrow.clockwise") + Text("Rerun Transcription") + } + Spacer() + } + .contentShape(Rectangle()) + } + .buttonStyle(.plain) + .disabled(isRerunningTranscription) + } + } + private var recordingTitleEditor: some View { RecordingTitleEditorView( title: $editableRecordingName, @@ -2024,12 +2220,7 @@ struct TranscriptSegmentView: View { Spacer() } - TextEditor(text: Binding( - get: { segment.text }, - set: { segment = TranscriptSegment(speaker: segment.speaker, text: $0, startTime: segment.startTime, endTime: segment.endTime) } - )) - .font(.body) - .frame(minHeight: max(120, calculateTextHeight(for: segment.text))) + transcriptTextEditor .padding(12) .background(Color(.systemBackground), in: RoundedRectangle(cornerRadius: 12, style: .continuous)) .overlay( @@ -2046,6 +2237,39 @@ struct TranscriptSegmentView: View { .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 16, style: .continuous)) } + @ViewBuilder + private var transcriptTextEditor: some View { + #if os(macOS) + // A multiline TextField expands and is not backed by its own scroll + // view, so wheel/trackpad events always reach the transcript List. + TextField("Transcript segment", text: segmentTextBinding, axis: .vertical) + .font(.body) + .textFieldStyle(.plain) + .lineLimit(nil) + .fixedSize(horizontal: false, vertical: true) + .frame(maxWidth: .infinity, alignment: .leading) + .frame(minHeight: 120, alignment: .topLeading) + #else + TextEditor(text: segmentTextBinding) + .font(.body) + .frame(minHeight: max(120, calculateTextHeight(for: segment.text))) + #endif + } + + private var segmentTextBinding: Binding { + Binding( + get: { segment.text }, + set: { + segment = TranscriptSegment( + speaker: segment.speaker, + text: $0, + startTime: segment.startTime, + endTime: segment.endTime + ) + } + ) + } + private func formatTime(_ time: TimeInterval) -> String { let minutes = Int(time) / 60 let seconds = Int(time) % 60 @@ -2297,7 +2521,7 @@ struct TitleRowView: View { // Copy button Button(action: { - UIPasteboard.general.string = title.text + PlatformPasteboard.string = title.text }) { Image(systemName: "doc.on.doc") .font(.caption2) @@ -2366,7 +2590,7 @@ struct EnhancedTitleRowView: View { // Copy button Button(action: { - UIPasteboard.general.string = title.text + PlatformPasteboard.string = title.text }) { Image(systemName: "doc.on.doc") .font(.caption2) diff --git a/BisonNotes AI/BisonNotes AI/WatchConnectivity/WatchConnectivityManager.swift b/BisonNotes AI/BisonNotes AI/WatchConnectivity/WatchConnectivityManager.swift index f11b697..5f1c405 100644 --- a/BisonNotes AI/BisonNotes AI/WatchConnectivity/WatchConnectivityManager.swift +++ b/BisonNotes AI/BisonNotes AI/WatchConnectivity/WatchConnectivityManager.swift @@ -6,15 +6,17 @@ // import Foundation -#if !targetEnvironment(macCatalyst) +#if os(iOS) && !targetEnvironment(macCatalyst) @preconcurrency import WatchConnectivity #endif import Combine +#if canImport(UIKit) import UIKit +#endif -#if targetEnvironment(macCatalyst) -// MARK: - Mac Catalyst Stub -/// Minimal stub for Mac Catalyst where WatchConnectivity is not available +#if targetEnvironment(macCatalyst) || os(macOS) +// MARK: - Mac Stub +/// Minimal stub for Mac (Catalyst and native) where WatchConnectivity is not available @MainActor class WatchConnectivityManager: NSObject, ObservableObject { @Published var connectionState: WatchConnectionState = .disconnected @@ -503,7 +505,7 @@ extension WatchConnectivityManager: WCSessionDelegate { } } } -#endif // !targetEnvironment(macCatalyst) +#endif // targetEnvironment(macCatalyst) || os(macOS) // MARK: - Extensions diff --git a/BisonNotes AI/BisonNotes AI/WhisperSettingsView.swift b/BisonNotes AI/BisonNotes AI/WhisperSettingsView.swift index 7e5672a..f3fb452 100644 --- a/BisonNotes AI/BisonNotes AI/WhisperSettingsView.swift +++ b/BisonNotes AI/BisonNotes AI/WhisperSettingsView.swift @@ -50,7 +50,7 @@ struct WhisperSettingsView: View { } var body: some View { - NavigationStack { + PlatformSettingsNavigationStack { Form { Section(header: Text("Whisper Service")) { VStack(alignment: .leading, spacing: 8) { @@ -327,6 +327,7 @@ struct WhisperSettingsView: View { Link("Whisper Model Information", destination: URL(string: "https://openai.com/research/whisper")!) } } + .nativeMacSettingsFormStyle() .scrollContentBackground(.hidden) .background(Color(.systemGroupedBackground)) .navigationTitle("Whisper Settings") diff --git a/BisonNotes AI/BisonNotes AI/Wyoming/WyomingWhisperClient.swift b/BisonNotes AI/BisonNotes AI/Wyoming/WyomingWhisperClient.swift index b4918fb..0da6fd2 100644 --- a/BisonNotes AI/BisonNotes AI/Wyoming/WyomingWhisperClient.swift +++ b/BisonNotes AI/BisonNotes AI/Wyoming/WyomingWhisperClient.swift @@ -7,7 +7,9 @@ import Foundation import AVFoundation +#if canImport(UIKit) import UIKit +#endif @MainActor class WyomingWhisperClient: ObservableObject { @@ -25,7 +27,7 @@ class WyomingWhisperClient: ObservableObject { private var currentTranscription: CheckedContinuation? private var transcriptionResult = "" private var serverInfo: WyomingInfoData? - private var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid + private var backgroundTaskID: PlatformBackgroundTask.ID = .invalid private var streamingTimeoutTask: Task? private var isProcessingChunk = false private var shouldManageBackgroundTask = true // Can be disabled when called from another background context @@ -833,7 +835,7 @@ class WyomingWhisperClient: ObservableObject { return } - backgroundTaskID = UIApplication.shared.beginBackgroundTask(withName: "WyomingTranscription") { [weak self] in + backgroundTaskID = PlatformBackgroundTask.begin(name: "WyomingTranscription") { [weak self] in AppLog.shared.transcription("Wyoming background task is about to expire", level: .error) Task { @MainActor in await self?.handleBackgroundTaskExpiration() @@ -843,7 +845,7 @@ class WyomingWhisperClient: ObservableObject { if backgroundTaskID == .invalid { AppLog.shared.transcription("Failed to start Wyoming background task", level: .error) } else { - let remainingTime = UIApplication.shared.backgroundTimeRemaining + let remainingTime = PlatformBackgroundTask.remainingTime if remainingTime.isFinite { AppLog.shared.transcription("Started Wyoming background task with \(String(format: "%.0f", remainingTime))s remaining", level: .debug) } else { @@ -855,7 +857,7 @@ class WyomingWhisperClient: ObservableObject { private func endBackgroundTask() { if backgroundTaskID != .invalid { AppLog.shared.transcription("Ending Wyoming background task: \(backgroundTaskID.rawValue)", level: .debug) - UIApplication.shared.endBackgroundTask(backgroundTaskID) + PlatformBackgroundTask.end(backgroundTaskID) backgroundTaskID = .invalid } } diff --git a/BisonNotes AI/BisonNotes AI/iCloudStorageManager.swift b/BisonNotes AI/BisonNotes AI/iCloudStorageManager.swift index 31c5bf5..746d00f 100644 --- a/BisonNotes AI/BisonNotes AI/iCloudStorageManager.swift +++ b/BisonNotes AI/BisonNotes AI/iCloudStorageManager.swift @@ -296,7 +296,7 @@ class iCloudStorageManager: ObservableObject { } init() { - self.deviceIdentifier = UIDevice.current.identifierForVendor?.uuidString ?? UUID().uuidString + self.deviceIdentifier = PlatformDevice.vendorIdentifier // Load saved settings self.isEnabled = UserDefaults.standard.bool(forKey: "iCloudSyncEnabled") diff --git a/BisonNotes AI/BisonNotes AITests/MLXSwiftResponseCleanerTests.swift b/BisonNotes AI/BisonNotes AITests/MLXSwiftResponseCleanerTests.swift new file mode 100644 index 0000000..eb2e7c1 --- /dev/null +++ b/BisonNotes AI/BisonNotes AITests/MLXSwiftResponseCleanerTests.swift @@ -0,0 +1,121 @@ +// +// MLXSwiftResponseCleanerTests.swift +// BisonNotes AITests +// + +import XCTest +@testable import BisonNotes_AI + +final class MLXSwiftResponseCleanerTests: XCTestCase { + func testRemovesClosedThinkingBlock() { + let response = """ + + I should inspect every constraint before answering. + + + ## Summary + Final meeting summary. + """ + + XCTAssertEqual( + MLXSwiftResponseCleaner.stripThinking(from: response), + "## Summary\nFinal meeting summary." + ) + } + + func testDropsUnterminatedThinkingBlock() { + let response = """ + + The model reached its output limit while reasoning. + """ + + XCTAssertEqual(MLXSwiftResponseCleaner.stripThinking(from: response), "") + } + + func testRemovesProseThinkingPreambleBeforeSummary() { + let response = """ + Here's a thinking process: + + 1. Analyze User Input + 2. Apply the constraints + + ## Summary + ### Overview + Final meeting summary. + """ + + XCTAssertEqual( + MLXSwiftResponseCleaner.stripThinking(from: response), + "## Summary\n### Overview\nFinal meeting summary." + ) + } + + func testRemovesProseThinkingPreambleBeforeFinalAnswerMarker() { + let response = """ + Reasoning process: + Check the transcript and organize the result. + + Final answer: + The final summary begins here. + """ + + XCTAssertEqual( + MLXSwiftResponseCleaner.stripThinking(from: response), + "The final summary begins here." + ) + } + + func testPreservesOrdinarySummaryText() { + let response = """ + ## Summary + The team discussed its decision-making process. + """ + + XCTAssertEqual( + MLXSwiftResponseCleaner.stripThinking(from: response), + response + ) + } + + func testThinkingResponseStillExtractsEveryStructuredSection() { + let response = """ + + Check the transcript carefully for tasks, dates, and possible titles. + + + ## Summary + ### Overview + The team reviewed alumni account management. + + ## Tasks + - Remove archived Google Photos data + - Update the alumni affiliation + + ## Reminders + - Complete the license review by August 1 + + ## Suggested Titles + - Alumni Account Management Review + - Workspace Archiving and Licensing + """ + + let result = MLXSwiftResponseParser.parseMarkdown( + response, + fallbackText: "The team reviewed alumni account management." + ) + + XCTAssertFalse(result.summary.contains("Check the transcript")) + XCTAssertTrue(result.summary.contains("alumni account management")) + XCTAssertEqual(result.tasks.map(\.text), [ + "Remove archived Google Photos data", + "Update the alumni affiliation" + ]) + XCTAssertEqual(result.reminders.map(\.text), [ + "Complete the license review by August 1" + ]) + XCTAssertEqual(result.titles.map(\.text), [ + "Alumni Account Management Review", + "Workspace Archiving and Licensing" + ]) + } +} diff --git a/BisonNotes AI/Shared/WatchRecordingMessage.swift b/BisonNotes AI/Shared/WatchRecordingMessage.swift index ea15a80..c4940fa 100644 --- a/BisonNotes AI/Shared/WatchRecordingMessage.swift +++ b/BisonNotes AI/Shared/WatchRecordingMessage.swift @@ -6,7 +6,9 @@ // import Foundation +#if canImport(WatchConnectivity) import WatchConnectivity +#endif import CoreLocation /// Messages sent between watch and phone for recording coordination. @@ -88,6 +90,7 @@ enum WatchDeviceType: String, Codable, CaseIterable { case appleWatch = "Apple Watch" } +#if canImport(WatchConnectivity) /// Extension to simplify WatchConnectivity message sending extension WCSession { /// Send a recording message with optional user info @@ -107,6 +110,7 @@ extension WCSession { } } } +#endif /// Data structure for sync request struct WatchSyncRequest: Codable { @@ -236,7 +240,7 @@ struct WatchLocationData: Codable, Equatable { } /// Shared location data structure - compatible with both iPhone and Watch apps -struct LocationData: Codable, Identifiable, Sendable { +struct LocationData: Codable, Identifiable, Hashable, Sendable { let id: UUID let latitude: Double let longitude: Double @@ -304,4 +308,4 @@ struct LocationData: Codable, Identifiable, Sendable { } return coordinateString } -} \ No newline at end of file +} diff --git a/README.md b/README.md index 9f0cc3c..b90d0e0 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,7 @@ The project uses Swift Package Manager for dependency management. Major dependen ### **On-Device AI** - **MLX Swift / MLX Swift LM**: Backs the default On Device AI summarization path in v2.0. - Models: Ternary Bonsai 1.7B (~470 MB, 4 GB+ RAM), 4B (~1.1 GB, 6 GB+ RAM, default), and 8B (~2.3 GB, 8 GB+ RAM) + - Native macOS also offers Ternary Bonsai 27B (~8.5 GB, 16 GB+ RAM); it is not available in the iOS or Mac Catalyst model catalog - Models download from Hugging Face on first use and run locally after download - 4-6 GB devices use the 1.7B model; 6 GB+ devices default to the 4B model; 8 GB+ devices can select the 8B model - **llama.cpp**: Embedded as a pre-compiled xcframework (`Frameworks/llama.xcframework`) for Metal-accelerated on-device LLM inference @@ -291,6 +292,7 @@ The on-device AI feature enables completely private, offline AI processing. v2.1 - **4GB+ RAM**: Ternary Bonsai 1.7B (~470 MB) - compact model for devices with limited memory - **6GB+ RAM**: Ternary Bonsai 4B (~1.1 GB) - default model for most supported devices - **8GB+ RAM**: Ternary Bonsai 8B (~2.3 GB) - slower but higher-quality summaries +- **Native macOS, 16GB+ RAM**: Ternary Bonsai 27B (~8.5 GB) - laptop-class reasoning; unavailable on iOS and Mac Catalyst - **Context Window**: 16K tokens - **Migration**: Existing users on the removed LFM model or legacy llama on sub-6GB devices are moved to MLX 1.7B when possible. Devices below 4GB fall back to Mistral AI. diff --git a/docs/bisonnotes-ai-guide.html b/docs/bisonnotes-ai-guide.html index 859bd50..e7d1387 100644 --- a/docs/bisonnotes-ai-guide.html +++ b/docs/bisonnotes-ai-guide.html @@ -314,14 +314,15 @@

Requirements

  • Transcription: iOS 17.0+, 4GB+ RAM. Uses Parakeet (default) for on-device transcription.
  • AI Summary (MLX Swift): 4GB+ RAM. Uses Ternary Bonsai models scaled to your device.
  • Legacy AI Summary (llama.cpp): 6GB+ RAM. Available as On Device AI (Legacy).
  • -
  • Storage: MLX models are about 470 MB to 2.3 GB; legacy llama.cpp models are about 1.3 GB to 4.5 GB; Parakeet transcription downloads separately.
  • +
  • Storage: MLX models are about 470 MB to 2.3 GB on iPhone and iPad. Native macOS also offers an optional 27B model of about 8.5 GB. Legacy llama.cpp models are about 1.3 GB to 4.5 GB; Parakeet transcription downloads separately.
  • -

    Default MLX Models (by RAM)

    +

    MLX Models (by RAM)

    • 4GB+: Ternary Bonsai 1.7B (~470 MB) β€” Compact local summaries for lower-memory devices
    • 6GB+: Ternary Bonsai 4B (~1.1 GB) β€” Default model for most supported devices
    • 8GB+: Ternary Bonsai 8B (~2.3 GB) β€” Slower but higher-quality summaries
    • +
    • Native macOS, 16GB+: Ternary Bonsai 27B (~8.5 GB) β€” Laptop-class reasoning; not available on iPhone, iPad, or Mac Catalyst

    Legacy llama.cpp Models (6GB+)

    diff --git a/docs/macos-migration-plan.md b/docs/macos-migration-plan.md new file mode 100644 index 0000000..5507d32 --- /dev/null +++ b/docs/macos-migration-plan.md @@ -0,0 +1,238 @@ +# macOS Native Migration Plan + +**Branch:** `native-macos` (off `v2.2`) +**Goal:** Replace the Mac Catalyst build with a native macOS SwiftUI target, without ever breaking the shipping iOS/Catalyst app, then delete Catalyst and collect the maintenance rewards (unpin aws-sdk-swift, delete the hand-built llama Catalyst slice, drop the textual fork patches). + +This document is written for an AI agent (or human) to execute incrementally. Every task has a verification step. Work phase by phase, task by task, committing after each green verification loop. + +--- + +## Progress log + +- **Phase 0 β€” DONE** (commits `930bcbf3`, `3fd6cb53`, `c4195e50`). SafariView, document pickers, and the PlatformApp shim landed; iOS + Catalyst green. +- **Phase 1 β€” DONE** (commit `42a1a6e0`). Native `BisonNotes AI macOS` target + scheme created; iOS-only APIs fenced. **All three targets build green** (macOS native, iOS Simulator, Mac Catalyst). Launch-verified: the native app runs, opens the Core Data store read-write **in the same container the Catalyst app uses** (`~/Library/Containers/Bison-Networking.BisonNotes-AI/`, same bundle ID β€” validates the Phase 4.1 data-continuity design), and quits cleanly with no crash report (the historical Catalyst quit-crash did not reproduce). Screenshot verification was blocked by the environment's display sandbox; UI was confirmed via process + open-file inspection instead. +- **Phase 2.1 β€” IMPLEMENTED, RUNTIME QA PENDING** (commit `a9b92463`). Native macOS now uses the shared Mac AVAudioEngine/AVAudioFile microphone path and ScreenCaptureKit system-audio path. The AVAudioSession retry/deactivation fallback remains Catalyst-only. Native macOS, iOS Simulator, and Mac Catalyst builds are green; a signed native build still needs the Phase 2 exit-criteria mic/system-audio hardware pass. +- **Phase 2.2 β€” IMPLEMENTED, RUNTIME QA PENDING** (commit `5ed60e59`). Native macOS now discovers microphones with `AVCaptureDevice`, maps them to Core Audio device IDs, identifies the system default input, and applies the selected device directly to the recording engine without changing the system-wide default. Live discovery/default-device mapping and all three builds are green; selection plus recording still needs the signed-app hardware pass. +- **Phase 2.3 β€” IMPLEMENTED, RUNTIME QA PENDING.** Native macOS now monitors Core Audio's device list and default-input properties, coalesces duplicate change events, and rebuilds the recording engine when the active microphone changes. Each input format records to a separate PCM segment, preserved segments are concatenated during final M4A export, system-audio capture pauses during the gap, and a disconnected preferred microphone falls back to the system default. Native macOS, iOS Simulator, and Mac Catalyst builds are green; physical USB/Bluetooth connect-disconnect testing during a signed recording is still required. +- **Phase 2.4 β€” IMPLEMENTED, RUNTIME QA PENDING.** Native macOS now wraps long-running transcription and summarization work in `ProcessInfo` activities that prevent App Nap while allowing normal idle system sleep. Mac builds no longer run iOS background-task expiration polling, 25-second task refresh loops, silent-audio keep-alive, or `BGTaskScheduler` registration. iOS retains its existing finite background-task and scheduler behavior. Native macOS, iOS Simulator, and Mac Catalyst builds are green; a long hidden-window transcription/summary pass remains pending. +- **Phase 2.5 β€” IMPLEMENTED, RUNTIME QA PENDING.** The native macOS PlatformServices layer now covers URL opening, app lifecycle notifications, ProcessInfo activities, and AppKit sharing. Summary exports generate real RTF and paginated PDF files through a shared AppKit/Core Text renderer; summary and diagnostic-log exports use `NSSharingServicePicker` with Finder fallback. All `TODO(macos-phase2)` markers are gone and all three targets build green; native RTF/PDF content and the available sharing destinations still need a signed-app visual pass. +- **Phase 2.6 β€” IMPLEMENTED, RUNTIME QA PENDING.** The remaining MISC conditionals have been audited. Native macOS now persists and resolves security-scoped recording-archive bookmarks, reports battery state as plugged in/full while still respecting Low Power Mode, uses the existing host-memory MLX guard, excludes Action Button guidance, and retains a no-op WatchConnectivity implementation. Native macOS, iOS Simulator, and Mac Catalyst builds plus the iOS unit-test target are green; a signed-app archive export/relaunch/restore pass remains pending. +- **Phase 3 β€” DONE.** The app-wide presentation audit covers all 60 sheet/full-screen sites. Summaries, transcripts, players, library, location, and processing views use movable/resizable native windows where appropriate, while true modal tasks remain bounded sheets. The native app has a dedicated Settings window, standard File/Edit commands and shortcuts, a resizable main window, and a complete Mac icon set. Native macOS, iOS Simulator, and Mac Catalyst builds, the iOS unit-test target, SwiftLint, and a native Release archive are green. User testing confirmed whole-window summary/transcript scrolling, nested-summary dismissal, artifact-free microphone recording, and `StartRecordingIntent` from Shortcuts with the app both closed and open. Detailed evidence is in `docs/macos-phase-3-exit-report.md`. +- **Phase 4.1 β€” DONE** (commit `2bbbced7`). A populated Catalyst install was replaced by the native app without losing recordings, transcripts, summaries, documents, or settings. The native app reopened the same persistent store and sandbox data; no relocation path was required. Detailed evidence is in `docs/macos-phase-4.1-data-continuity-report.md`. +- **Native Settings polish β€” IMPLEMENTED, USER VISUAL QA PENDING.** Setup now opens the dedicated macOS Settings window instead of stacking a Settings sheet over the main window. Settings and its provider/model panels share one navigation hierarchy; true tasks remain modal. Acknowledgements and MLX On Device AI use bounded, top-aligned Mac card layouts, while the remaining settings forms use grouped native styling. Native macOS, iOS Simulator, and Mac Catalyst Debug builds are green; the root Settings window passed a live visual check, and each destination still needs the user walkthrough. +- **Xcode recommended settings β€” APPLIED.** Project and shared-scheme upgrade metadata now match Xcode 26.6; the native macOS target enables dead-code stripping and app-group registration in Debug and Release. These settings were present for the green three-platform Phase 2.2 build loop. +- **Next: Phase 4.2** β€” run the Mac beta/TestFlight soak and complete the outstanding signed-app hardware/runtime cases, including microphone changes during recording, long hidden-window processing, archive bookmark restoration, and the full Settings destination walkthrough. + +--- + +## Ground rules (read before every work session) + +1. **Never break the iOS or Catalyst build.** Both must build green after every commit until Phase 4 cutover. Run the verification loop (below) before every commit. +2. **One task per commit.** Small, revertable commits. Conventional prefixes: `refactor:` (Phase 0), `feat(macos):` (Phases 1–3), `chore:` (cleanup). +3. **Do not bump aws-sdk-swift past 1.6.113** until Phase 4 cutover. SPM versions are project-wide; the Catalyst archive bug (see CLAUDE.md "Archive-only failures") applies as long as the Catalyst destination exists. +4. **Do not touch `Frameworks/llama.xcframework/ios-arm64-maccatalyst/`** until Phase 4. +5. **`#if targetEnvironment(macCatalyst)` semantics:** on native macOS this is FALSE. Any behavior currently gated to Catalyst that native macOS also needs must be re-fenced as `#if targetEnvironment(macCatalyst) || os(macOS)`. Any iOS-only API usage must be fenced `#if os(iOS)` (which is TRUE on Catalyst β€” fence Catalyst-excluded iOS code as `#if os(iOS) && !targetEnvironment(macCatalyst)`). +6. **Known Catalyst UI landmines** (do not regress; both remain relevant until cutover): + - SwiftUI `ScrollView` is broken inside Mac Catalyst sheets β€” use `Form`/`List`. + - Multiple `Button`s in one `Form` row need explicit `.buttonStyle(.borderless)` or they share one tap target. + +## Verification loop + +Run from `BisonNotes AI/` (the directory containing `BisonNotes AI.xcodeproj`). Build output is large β€” pipe through `tail`/`grep` and check exit codes. + +```bash +# 1. iOS Simulator build (primary platform) +xcodebuild -project "BisonNotes AI.xcodeproj" -scheme "BisonNotes AI" \ + -destination 'platform=iOS Simulator,name=iPhone 17' \ + build 2>&1 | tail -5 # expect: ** BUILD SUCCEEDED ** + +# 2. Mac Catalyst build (until Phase 4) +xcodebuild -project "BisonNotes AI.xcodeproj" -scheme "BisonNotes AI" \ + -destination 'platform=macOS,variant=Mac Catalyst,arch=arm64' \ + build 2>&1 | tail -5 # expect: ** BUILD SUCCEEDED ** + +# 3. Unit tests (when logic changed, not for pure UI refactors) +xcodebuild -project "BisonNotes AI.xcodeproj" -scheme "BisonNotes AI" \ + -destination 'platform=iOS Simulator,name=iPhone 17' \ + test 2>&1 | tail -10 + +# 4. Native macOS build (Phase 1 onward) +xcodebuild -project "BisonNotes AI.xcodeproj" -scheme "BisonNotes AI macOS" \ + -destination 'platform=macOS,arch=arm64' \ + build 2>&1 | tail -5 + +# 5. Catalyst archive smoke test (only before release-tagging, it is slow) +./Scripts/archive-catalyst.sh +``` + +If a build fails: read the first error (`grep -m5 "error:"`), fix, loop. Do not commit with any step red. If a failure resists 3 fix attempts, stop and record the blocker in this file under "Open issues". + +--- + +## Phase 0 β€” Cross-platform groundwork (no new target yet) + +Shrinks the eventual port and benefits iOS/Catalyst immediately. Each task is independently committable and must keep both builds green. + +### 0.1 Replace SafariView with cross-platform link opening +- `Views/SafariView.swift` wraps `SFSafariViewController` with Catalyst conditionals. Find all call sites (`grep -rn "SafariView" --include='*.swift'`). +- Replace usage with `Link` or `@Environment(\.openURL)`; delete `SafariView.swift` if nothing else uses it (in-app Safari sheet UX on iOS is acceptable to lose only if call sites are informational links; otherwise keep an `#if os(iOS)` Safari path and an `openURL` fallback β€” judgment call, prefer deletion for simplicity). +- Verify: loop steps 1–2. + +### 0.2 Replace UIDocumentPicker wrappers with fileImporter/fileExporter +- `DocumentPickerCoordinator.swift` (import) and `DocumentExportPicker.swift` (export) wrap `UIDocumentPickerViewController`. +- Find call sites; replace with `.fileImporter(isPresented:allowedContentTypes:allowsMultipleSelection:)` and `.fileExporter`. Preserve security-scoped resource access (`startAccessingSecurityScopedResource`) where present today. +- Watch out: `.fileImporter` on Catalyst presents differently but works; test import of an audio file and export of a summary on both platforms if a simulator/Catalyst run is feasible, else rely on builds + unit tests and note it for manual QA. +- Verify: loop steps 1–3. + +### 0.3 PlatformServices shim for UIApplication call sites +- Create `Platform/PlatformServices.swift` exposing the small set of capabilities the app actually uses. Inventory first (`grep -rn "UIApplication" --include='*.swift' "BisonNotes AI"`), expected clusters: + - `open(_ url:)` β†’ route to `@Environment(\.openURL)` in views; `UIApplication.shared.open` in managers (macOS later: `NSWorkspace`) + - `isIdleTimerDisabled` (recording keep-awake) β†’ macOS later: `ProcessInfo.processInfo.beginActivity` + - lifecycle notifications (`didEnterBackground`, `willEnterForeground`, `didBecomeActive`) β†’ abstract as `PlatformLifecycle` notification names (macOS later: `NSApplication` equivalents) + - `beginBackgroundTask`/`endBackgroundTask` β†’ abstract as `PlatformBackgroundAssertion` (macOS later: no-op / `ProcessInfo` activity) +- Mechanical migration: one call-site cluster per commit is fine; do NOT redesign manager logic while shimming. +- Exclude UITests targets from the shim (they legitimately use `UIApplication`/XCUI APIs). +- Verify: loop steps 1–3 after each cluster. + +### Phase 0 exit criteria +- `SafariView.swift`, `DocumentPickerCoordinator.swift`, `DocumentExportPicker.swift` deleted or reduced to cross-platform SwiftUI. +- The only files still referencing `UIApplication` are: `Platform/PlatformApp.swift` (the shim), `AppDelegate.swift` + `BisonNotesAIApp.swift` (delegate adaptor β€” inherently UIKit until Phase 1), `WatchConnectivity/WatchConnectivityManager.swift` (KEEP-iOS), and the four window-scene/share-sheet sites (`LogExporter.swift`, `Views/SettingsView.swift`, `Views/RecordingsListView.swift`, `Views/DataMigrationView.swift`) whose presentation is feature-specific and ports in Phase 2.5 (NSSharingServicePicker on macOS). +- iOS + Catalyst builds green; unit tests pass. + +--- + +## Phase 1 β€” Stand up the native macOS target + +### 1.1 Create target +- Duplicate the `BisonNotes AI` app target as **`BisonNotes AI macOS`** (native macOS SwiftUI app, NOT Catalyst). Same sources, same asset catalog, same Core Data model. Create a matching scheme `BisonNotes AI macOS`. +- **Bundle ID: use the same bundle ID as the Catalyst app** (`PRODUCT_BUNDLE_IDENTIFIER` unchanged) so the native app inherits the container and replaces the Catalyst app on the App Store at cutover. The two targets cannot be installed simultaneously β€” that is expected; use the Catalyst target for Catalyst testing and the macOS target for native testing. +- Carry over: `EXCLUDED_ARCHS = x86_64` (app is Apple Silicon-only: MLX + arm64-only llama), entitlements (App Groups, mic, speech, screen capture for ScreenCaptureKit), Info.plist usage strings. +- Exclude from the macOS target's compile sources / dependencies: Watch app embedding, `BisonNotes AI ControlsExtension`, `BisonNotes Share` (deferred), `WatchConnectivity/` sources. + +### 1.2 Dependency sanity +- llama.xcframework: native macOS resolves to the stock `macos-arm64_x86_64` slice. No action needed; do NOT touch the Catalyst slice. +- MLX-Swift, FluidAudio, textual: expect to build natively. textual takes its upstream AppKit path on native macOS (the Catalyst guards are `!targetEnvironment(macCatalyst)` and don't affect native macOS). +- aws-sdk-swift: stays pinned (rule 3). Confirm a native macOS **archive** succeeds once the target builds (`xcodebuild archive -scheme "BisonNotes AI macOS" -destination 'generic/platform=macOS' ONLY_ACTIVE_ARCH=NO EXCLUDED_ARCHS=x86_64`) β€” this validates the Phase 4 unpin assumption early. + +### 1.3 Compile to first launch +- Iterate: build macOS target, take the first batch of errors, fence iOS-only code (`#if os(iOS)`), stub macOS gaps with `// TODO(macos-phase2)` markers, loop. +- Known iOS-only APIs that will need fencing: `AVAudioSession` (audio files β€” see Phase 2, stub recording as disabled for now), `BGTaskScheduler`, `UIDevice`, `UIImpactFeedbackGenerator`, `WatchConnectivity`, `UIPasteboard` (β†’ `NSPasteboard`), `CallKit`/call intelligence if present. +- Milestone: app launches on macOS, shows the recordings list backed by Core Data, playback works, recording button present but disabled. + +### Phase 1 exit criteria +- `xcodebuild build` green for all three: iOS sim, Catalyst, macOS. +- macOS app launches and reads/writes Core Data. +- `grep -rn "TODO(macos-phase2)" --include='*.swift'` list captured as the Phase 2 worklist. + +--- + +## Phase 2 β€” Port the platform layer + +Work the `TODO(macos-phase2)` list plus the punch list below, in this order: + +### 2.1 Recording engine (highest value, mostly done) +- `ViewModels/AudioRecorderViewModel+CatalystEngine.swift` (AVAudioEngine + AVAudioFile mic recording, CAFβ†’M4A export) and `ViewModels/CatalystSystemAudioCapture.swift` (ScreenCaptureKit system audio) are native-API implementations already. Re-fence both from `#if targetEnvironment(macCatalyst)` to `#if targetEnvironment(macCatalyst) || os(macOS)`. Consider renaming `Catalyst*` β†’ `Mac*` (mechanical, keep it a separate commit). +- Remove/fence their `AVAudioSession` touchpoints for macOS (engine input works without a session on macOS). + +### 2.2 Audio session & device management +- `EnhancedAudioSessionManager.swift` (14 conditionals): fence all `AVAudioSession` configuration to `#if os(iOS)`. On macOS, input selection = Core Audio default input device + `AVCaptureDevice.DiscoverySession` enumeration for the Settings picker. +- Mic permission: `AVCaptureDevice.requestAccess(for: .audio)` β€” same TCC flow, works on macOS. + +### 2.3 Interruptions and device changes +- `+Interruptions.swift`, `+MicrophoneReconnection.swift`: AVAudioSession route-change/interruption notifications are iOS-only. macOS equivalent: Core Audio property listeners (`kAudioHardwarePropertyDefaultInputDevice`) to detect mic unplug/change; pause-and-recover semantics should match the existing Catalyst behavior. +- **Risk pocket:** Bluetooth mic connect/disconnect mid-recording. Test explicitly (manual QA note). + +### 2.4 Background processing +- `BackgroundProcessingManager.swift` + `+Background.swift`: fence `BGTaskScheduler`/`beginBackgroundTask` to `#if os(iOS)`. On macOS, jobs simply continue running; use `ProcessInfo.beginActivity(.userInitiated)` around long jobs to prevent App Nap. This deletes complexity β€” do not port iOS scheduling ceremony. + +### 2.5 PlatformServices macOS implementations +- Fill in the macOS side of the Phase 0.3 shim: `NSWorkspace.shared.open`, `ProcessInfo` activities, `NSApplication` lifecycle notifications. + +### 2.6 Remaining punch list +Work through the categorized conditional inventory (appendix below) tagged MISC: `DeviceCapabilities`, `MLXSwiftEngine`, `PerformanceOptimizer` (battery APIs are iOS-only β†’ on macOS report "plugged in"), `RecordingArchiveService`, `WatchConnectivityManager` (stays iOS-only, fenced). + +### Phase 2 exit criteria (loop until all pass on macOS) +- Record a mic-only note β†’ transcript β†’ summary end-to-end. +- Record with system audio (ScreenCaptureKit) β†’ verify mixed/parallel files as on Catalyst. +- On-device transcription + LLM summary (llama and/or MLX path) complete. +- Cloud engines (OpenAI/Bedrock/Gemini) reachable (config permitting). +- Quit app during background processing β†’ relaunch β†’ job recovers (matches memory: quit-crash was a Catalyst Phase-2 test item). +- Zero remaining `TODO(macos-phase2)` markers. + +--- + +## Phase 3 β€” Mac idioms & UI cleanup + +### 3.1 Re-audit Catalyst UI workarounds on native macOS +- For every UI-WORKAROUND conditional in the appendix: check whether native macOS needs it. ScrollView-in-sheet and Form-button bugs are Catalyst-renderer bugs; native macOS likely renders correctly. Keep Catalyst behavior unchanged; add `os(macOS)` branches only where native misbehaves. +- Implemented: native summary buttons open a value-backed `WindowGroup` with default/minimum dimensions, and `SummaryDetailView` uses a `List` on macOS for an explicit scrolling viewport. The model-download sheet keeps native page presentation. Catalyst-only list/Form workarounds remain isolated, and native Settings combines direct microphone selection with system-audio capture controls. +### 3.2 Mac app conventions +- `Settings` scene (⌘,) wrapping the existing settings views; menu-bar `Commands` (New Recording ⌘N, Import…, Export…); `defaultSize` + `minWidth/minHeight` on the main `WindowGroup`; standard Edit-menu behaviors in text views. +- Implemented: the native Settings scene shares the app-level recorder/coordinator objects with the main window; the main window defaults to 1100Γ—720 with an 860Γ—560 content minimum; File commands navigate before dispatching New Recording/import actions; and focused scene values route Export only to the active summary window. The asset catalog now includes all native Mac icon renditions from 16Γ—16 through 512Γ—512 points at 1x/2x. +### 3.3 Deferred items (create follow-up issues, do not block cutover) +- macOS Share extension port; macOS widgets; Shortcuts/App Intents parity check (App Intents work on macOS β€” verify `StartRecordingIntent`). +- Completed: `docs/macos-phase-3.3-deferred-parity-audit.md` records the target, source, embedding, entitlement, and generated-metadata evidence. The Share extension port is tracked by GitHub issue #102; the native WidgetKit target is tracked by issue #101. Native `StartRecordingIntent` registration and its signed-app Shortcuts runtime check are complete. + +### Phase 3 exit criteria +- Full manual pass of `docs/testing-regimen.md` on native macOS. +- App feels Mac-native: settings window, menu commands, resizable window, keyboard shortcuts. + +--- + +## Phase 4 β€” Parity testing, data continuity, cutover + +### 4.1 Data continuity (must not go wrong) +- On a Mac with the Catalyst app installed and populated: install the native build (same bundle ID) over it. Verify recordings, transcripts, summaries, and settings all present. The container (`~/Library/Containers/` / App Group) must match; if paths differ, extend `DataMigrationManager` with a one-time relocation and re-test. +### 4.2 Beta +- TestFlight for Mac side-by-side soak; run the Phase-2 checklist from memory (recording, external mic swap, AI inference, long-session scrolling, quit-while-processing). +### 4.3 Cutover & rewards (single PR, in this order) +1. Remove Mac Catalyst from the iOS target's supported destinations. +2. Delete `Frameworks/llama.xcframework/ios-arm64-maccatalyst/` and its `Info.plist` entry. +3. Delete `Scripts/archive-catalyst.sh`. +4. Unpin aws-sdk-swift (verify smithy plugin issue irrelevant for iOS + native macOS archives; bump and archive both). +5. Simplify `textual` fork (drop Catalyst guards at next rebase β€” separate repo task). +6. Purge now-dead `targetEnvironment(macCatalyst)` branches. +7. Rewrite CLAUDE.md Catalyst sections; update memory files. +- Verify: iOS archive + macOS archive + full test suite green. + +--- + +## Open issues + +(record blockers here as they arise) + +--- + +## Appendix: Catalyst-conditional punch list (as of branch creation, 74 sites) + +Legend: **AUDIO** = port in Phase 2.1–2.3 Β· **BACKGROUND** = Phase 2.4 Β· **UI** = re-audit in Phase 3.1 Β· **MISC** = Phase 2.6 Β· **KEEP-iOS** = stays fenced iOS-only + +| File | Lines | Category | +|---|---|---| +| EnhancedAudioSessionManager.swift | 138, 156, 210, 231, 256, 274, 290, 299, 312, 323, 342, 373, 387, 499 | AUDIO | +| ViewModels/AudioRecorderViewModel.swift | 14, 89, 114, 200, 214, 263, 430, 458, 493, 539, 593, 605, 683, 702, 748, 780, 903 | AUDIO | +| ViewModels/AudioRecorderViewModel+CatalystEngine.swift | 11 | AUDIO (re-fence for macOS) | +| ViewModels/CatalystSystemAudioCapture.swift | 9 | AUDIO (re-fence for macOS) | +| ViewModels/AudioRecorderViewModel+Interruptions.swift | 59 | AUDIO | +| ViewModels/AudioRecorderViewModel+CallIntelligence.swift | 11 | KEEP-iOS (call detection) | +| ViewModels/AudioRecorderViewModel+Background.swift | 16, 32, 45 | BACKGROUND | +| BackgroundProcessingManager.swift | 2183, 2217, 2237, 2298 | BACKGROUND | +| BisonNotesAIApp.swift | 535, 977 | BACKGROUND | +| PerformanceOptimizer.swift | 17 | MISC (battery APIs) | +| DeviceCapabilities.swift | 43 | MISC | +| MLXSwiftEngine.swift | 586 | MISC | +| Models/RecordingArchiveService.swift | 393, 492 | MISC | +| WatchConnectivity/WatchConnectivityManager.swift | 9, 15, 506 | KEEP-iOS | +| Views/SettingsView.swift | 11, 271, 636, 683, 1192, 1210, 1220 | UI | +| Views/SimpleSettingsView.swift | 10, 163, 170 | UI | +| Views/RecordingsView.swift | 9, 333, 340 | UI | +| SummariesView.swift | 337, 418 | UI | +| Views/MistralOnboardingView.swift | 66, 72 | UI | +| Views/TranscriptViews.swift | 306 | UI | +| Views/AITextView.swift | 80 | UI | +| Views/SafariView.swift | 9, 13 | UI (deleted in Phase 0.1) | +| Views/OnDeviceAIDownloadView.swift | 42 | UI | + +Line numbers drift as the branch evolves; re-run +`grep -rn "targetEnvironment(macCatalyst)" --include='*.swift' "BisonNotes AI/BisonNotes AI"` +to refresh before starting each phase. diff --git a/docs/macos-phase-3-exit-report.md b/docs/macos-phase-3-exit-report.md new file mode 100644 index 0000000..be0d624 --- /dev/null +++ b/docs/macos-phase-3-exit-report.md @@ -0,0 +1,57 @@ +# Native macOS Phase 3 Exit Report + +**Branch:** `native-macos` +**Date:** 2026-07-19 +**Status:** Pass β€” Phase 3 complete + +## Automated verification + +| Check | Result | Evidence | +| --- | --- | --- | +| SwiftLint current-delta gate | Pass | Normal lint with the refreshed committed baseline reports 0 violations in 173 Swift files. | +| Native macOS Debug build | Pass | `BisonNotes AI macOS`, destination `platform=macOS`. | +| Native macOS Release archive | Pass | Generic macOS archive produced at `/private/tmp/BisonNotes-Native-Mac-Phase3-final.xcarchive`; it contains the arm64 app signed with the configured Apple Development identity. Distribution export and notarization remain Phase 4 work. | +| Mac Catalyst Debug build | Pass | `BisonNotes AI`, destination `platform=macOS,variant=Mac Catalyst`. | +| iOS Simulator Debug build | Pass | `BisonNotes AI`, generic iOS Simulator destination. | +| Unit and integration tests | Pass | Full `BisonNotes AITests` target on iPhone 17 Pro simulator. | +| App Intent extraction | Pass | Native product contains `StartRecordingIntent`, `openAppWhenRun`, discoverability metadata, and all four App Shortcut phrases. | +| Application icon assets | Pass | Native `Assets.car` contains the ten expected Mac AppIcon renditions from 16Γ—16 through 512Γ—512 points at 1x/2x; the product declares `CFBundleIconName = AppIcon`. | + +## Live native-app inspection + +The built native app was launched and inspected through AppKit in the running process: + +- The main app menu contains BisonNotes AI, File, Edit, View, Window, and Help. +- File contains New Recording, Import Audio, Import Transcript, Import From Link, and focused Summary Export commands. Key equivalents resolve to Command-N, Command-I, Shift-Command-I, and Shift-Command-L as designed. +- Edit contains the standard Undo, Redo, Cut, Copy, Paste, Delete, Select All, Writing Tools, Dictation, and Emoji commands. +- The reopened main window is 1100Γ—720, reports an 860Γ—612 outer-frame minimum (the configured 860Γ—560 content minimum plus title-bar chrome), and carries the resizable style bit. +- Invoking the real Settings menu item opened a distinct Settings window at 760Γ—700. +- Invoking File > Import From Link opened a 700Γ—685 sheet attached to the main window; the sheet was then closed without modifying data. + +## User-confirmed native interaction cases + +- Native microphone recording completed without the speech-only clicking/static artifact after the audio-path repair. +- Summary content opens in a movable, bounded window and scrolls as a whole. +- Edit Transcript opens in its own window and the complete segment list scrolls as one document rather than trapping scroll gestures inside segment editors. +- A summary opened from Edit Transcript has a visible Done action and closes with Escape. + +## Final Phase 3 confirmation + +The user completed the remaining Shortcuts discovery and invocation check: + +- **BisonNotes AI > Start Recording** was available in Shortcuts. +- Running it with BisonNotes AI closed opened the native app and started one recording. +- Running it again with BisonNotes AI already open started exactly one new recording. + +Together with the automated, live-AppKit, and user-confirmed window checks above, this satisfies the Phase 3 exit criteria. + +## Phase 2 / Phase 4 runtime backlog + +These do not block the Mac-idiom implementation audit, but remain release gates before the Phase 4 beta: + +- External USB/Bluetooth input connect/disconnect during recording. +- Real ScreenCaptureKit meeting/system-audio recording. +- Long hidden-window transcription/summary and quit/relaunch recovery. +- Native PDF/RTF visual output and sharing destinations. +- Recording-archive export, relaunch, and bookmark-based restoration. +- Populated Catalyst-to-native data-continuity installation test. diff --git a/docs/macos-phase-3.3-deferred-parity-audit.md b/docs/macos-phase-3.3-deferred-parity-audit.md new file mode 100644 index 0000000..a649f8a --- /dev/null +++ b/docs/macos-phase-3.3-deferred-parity-audit.md @@ -0,0 +1,78 @@ +# Native macOS Deferred Parity Audit + +## Scope + +Phase 3.3 checks whether the existing Share extension, widgets, and App Intents +carry over to the native macOS app. Deferred features do not block the Phase 4 +cutover, but each gap needs an explicit owner and acceptance criteria. + +## Results + +| Area | Current native macOS state | Phase 3.3 decision | +| --- | --- | --- | +| Share extension | Not present. The existing extension imports UIKit, subclasses `UIViewController`, uses `UIApplication` launch paths, and is embedded only for iOS. | Defer a dedicated AppKit/macOS extension to [issue #102](https://github.com/bisonbet/BisonNotes-AI/issues/102). | +| Widgets | Not present. The complication target is watchOS-only, while the Control Widget target explicitly supports only iOS and uses an iOS-only declaration. | Defer a native WidgetKit target to [issue #101](https://github.com/bisonbet/BisonNotes-AI/issues/101). | +| Shortcuts / App Intents | Implemented. `StartRecordingIntent` and `AppShortcuts` compile into the native app, and Xcode emits them in the signed app's App Intents metadata. | No implementation follow-up. Retain a signed-app runtime check in the Phase 3 exit QA. | + +## Share extension + +The `BisonNotes Share` target is not a cross-platform extension: + +- `ShareViewController.swift` imports UIKit and subclasses `UIViewController`. +- Opening the app depends on `UIApplication` runtime and responder-chain calls. +- The extension product is embedded with an iOS platform filter. +- The native `BisonNotes AI macOS` target has no dependency on or embed phase + for the extension. + +The receiving half is already reusable. The native app has the +`group.bisonnotesai.shared` entitlement, authenticated ShareInbox token +consumption, inbox scanning, and Darwin-notification handling. A future Mac +extension should preserve this contract and replace only the extension UI and +app-launch mechanism. File-menu audio, transcript, and link imports cover the +cutover use case until that work is scheduled. + +Follow-up: [Port the Share extension to native macOS (#102)](https://github.com/bisonbet/BisonNotes-AI/issues/102). + +## Widgets + +Neither existing widget target applies to the native Mac app: + +- `BisonNotes Watch WidgetExtension` targets watchOS and exposes Watch accessory + widget families. +- `BisonNotes AI ControlsExtension` targets only iPhone/iPad platforms and its + source is declared available for iOS 18 or newer. +- The native macOS target embeds neither extension. + +A future Mac widget can reuse `StartRecordingIntent` and App Group state. It +should not introduce another recording-control path. Command-N, File-menu +commands, and the Shortcuts action provide native entry points in the meantime. + +Follow-up: [Add native macOS WidgetKit support (#101)](https://github.com/bisonbet/BisonNotes-AI/issues/101). + +## Shortcuts and App Intents + +The existing implementation is included in the native macOS target: + +- `StartRecordingIntent` is discoverable, opens the app, and writes the shared + recording request through `ActionButtonLaunchManager`. +- `AppShortcuts` publishes four Start Recording phrases. +- `ContentView` consumes the request when the app becomes active and starts the + shared recorder after initialization. +- The native app carries the required App Group entitlement. + +The native Debug product contains +`Contents/Resources/Metadata.appintents/extract.actionsdata`. Xcode's extracted +metadata identifies `BisonNotes_AI.StartRecordingIntent`, marks it discoverable +with `openAppWhenRun`, and includes all four phrases. This proves native target +registration and metadata extraction; it does not replace the signed-app check +below. + +## Remaining Phase 3 exit QA + +- In Shortcuts on macOS, find BisonNotes AI's **Start Recording** action. +- Run it while the app is closed and while it is already open. +- Confirm the native app activates, requests microphone permission when needed, + navigates to Record, and begins exactly one recording. +- Stop and save the recording, then confirm normal transcript processing still + works. + diff --git a/docs/macos-phase-4.1-data-continuity-report.md b/docs/macos-phase-4.1-data-continuity-report.md new file mode 100644 index 0000000..097bcc5 --- /dev/null +++ b/docs/macos-phase-4.1-data-continuity-report.md @@ -0,0 +1,122 @@ +# Native macOS Phase 4.1 Data-Continuity Report + +**Branch:** `native-macos` + +**Date:** 2026-07-19 + +**Status:** Continuity and settings spot check passed; extended manual QA deferred + +## Replacement candidates + +| Property | Installed Catalyst app | Native candidate | +| --- | --- | --- | +| Location | `/Applications/BisonNotes AI.app` | `/private/tmp/BisonNotes-Native-Mac-Phase3-final.xcarchive/Products/Applications/BisonNotes AI.app` | +| Platform | `MACCATALYST` | native `MACOS` | +| Version | 2.1 (8) | 2.2 (7) | +| Architecture | arm64 | arm64 | +| Bundle identifier | `Bison-Networking.BisonNotes-AI` | `Bison-Networking.BisonNotes-AI` | +| Team identifier | `4W55VW7UXX` | `4W55VW7UXX` | +| Sandbox | enabled | enabled | +| App Group | `group.bisonnotesai.shared` | `group.bisonnotesai.shared` | +| iCloud containers | `iCloud.Bison-Networking.BisonNotes-AI` | `iCloud.Bison-Networking.BisonNotes-AI` | + +Both builds therefore resolve the same sandbox container, App Group container, Core Data model name, Documents directory, and standard `UserDefaults` domain. `PersistenceController` uses the default store URL for `NSPersistentContainer(name: "BisonNotes_AI")`; no platform-specific relocation path is present. + +## Populated Catalyst baseline + +The Catalyst app was closed before capture. Its existing sandbox is: + +`~/Library/Containers/Bison-Networking.BisonNotes-AI` + +| Data | Pre-install value | +| --- | ---: | +| Container logical size | 36 GB | +| Documents logical size | 647 MB | +| Document files | 59 | +| Document bytes | 678,638,632 | +| M4A files | 44 | +| MP3 files | 2 | +| Location sidecars | 6 | +| Recording metadata sidecars | 6 | +| Relationship manifests | 1 | +| Recording Core Data rows | 54 | +| Transcript Core Data rows | 31 | +| Summary Core Data rows | 53 | +| Processing-job rows | 0 | +| Archive-location rows | 0 | + +Pre-install stable-file hashes: + +- Preferences: `d99c9c6482c7661e54be395354b76c49701c3c6fb4ea7ee4d3f29376c7f7e3d0` +- File relationships: `79983f32910eebc1689df9afcd261f05fcc804fd97b11b36cc63036062e4fea0` + +The 32 GB cache directory is primarily downloaded/rebuildable AI-model content and was deliberately excluded from the rollback copy. + +## Rollback snapshot + +An APFS clone-based snapshot was created at: + +`/private/tmp/bisonnotes-phase41-backup.QIXwtm` + +It contains the original Catalyst app plus Documents, the Core Data store and WAL/SHM files, preferences, summary-location snapshots, and the App Group container. The copied Documents, Core Data, and preferences were compared with their sources immediately after capture and matched byte-for-byte. Snapshot logical size is 678 MB. + +## Native replacement result + +The installed Catalyst bundle was moved intact to the rollback snapshot, and the native candidate was installed at `/Applications/BisonNotes AI.app`. Post-install inspection confirmed: + +- `/Applications/BisonNotes AI.app` is version 2.2 (7), platform `MACOS`. +- The preserved installed app remains version 2.1 (8), platform `MACCATALYST`, at `/private/tmp/bisonnotes-phase41-backup.QIXwtm/BisonNotes AI Installed Catalyst.app`. +- The first native launch ran the executable from `/Applications` and opened the original `BisonNotes_AI.sqlite`, WAL, and SHM files in the existing sandbox. +- Core Data remained at 54 recordings, 31 transcripts, 53 summaries, zero processing jobs, and zero archive locations. +- Documents remained at 59 files and 678,638,632 bytes and matched the rollback snapshot byte-for-byte. +- The relationship manifest hash remained unchanged. +- The preferences plist was rewritten during launch, but all 111 pre-install preference keys remained present with no additions or removals. +- No Core Data, persistent-store, migration, failure, fault, or crash messages appeared in the native launch log. + +The native app then quit cleanly. Closed-store counts and Documents still matched the baseline. A second native launch again opened the same persistent store, retained every count and document, and emitted no matching persistence/migration faults. + +## Native settings-window follow-up + +Manual inspection of the installed native app exposed two presentation defects that did not affect persisted data: + +- Settings and nested engine sheets could lose their navigation toolbar dismissal controls, leaving no visible Done button and no Escape-key exit. +- The FluidAudio and Mistral Transcription forms inherited unsuitable iOS form geometry on native macOS, causing excessive blank space, misaligned fields, and clipped values. + +The native window routing now supplies a content-level dismissal control with Escape-key support to Settings, Transcription, AI-engine, and nested configuration sheets. FluidAudio and Mistral Transcription use bounded, top-aligned native macOS card layouts while retaining their existing iOS and Catalyst forms. + +The corrected Release archive is: + +`/private/tmp/BisonNotes-Native-Mac-Phase41-settings-ui.xcarchive` + +The installed `/Applications/BisonNotes AI.app` was compared with that archive and matched exactly. It remains version 2.2 (7), platform `MACOS`. The preceding native bundle is retained at `/private/tmp/bisonnotes-phase41-backup.QIXwtm/BisonNotes AI Native Pre-Settings-UI-Fix.app` in addition to the original Catalyst rollback copy. + +Verification for the follow-up build: + +- Swift source parsing passed for the changed settings views. +- Normal SwiftLint passed with zero violations in 173 files. +- Native macOS, Mac Catalyst, and iOS Simulator Debug builds passed. +- The signed native macOS Release archive passed. +- The Catalyst unit-test host stalled on the first existing Core Data regression test and was stopped without producing a test result. The same suite had passed before the final presentation-only layout refinement. + +On 2026-07-19, the user manually checked the corrected installed build and reported that the affected windows looked okay. This is recorded as a Phase 4.1 spot-check pass, not an exhaustive release sign-off. Broader manual validationβ€”including additional recording playback and wider transcript, summary, and settings coverageβ€”was explicitly deferred to a later session. The automated data comparisons found no need for a one-time data relocation. + +## Native Settings second-pass polish + +Screenshots captured on 2026-07-21 exposed a broader presentation problem than the first follow-up addressed. Opening Settings from Setup still presented a large sheet over the main window, and opening a provider or model panel stacked another sheet on top. SwiftUI `Form` also produced unsuitable native Mac geometry in Acknowledgements and MLX On Device AI: oversized empty title regions, centered or clipped content, controls stretched across the whole window, and advanced settings without useful grouping. + +The second pass establishes one macOS settings hierarchy: + +- Setup's settings action opens the app's dedicated SwiftUI `Settings` scene. +- Settings, AI Settings, Transcription Settings, Preferences, Background Processing, and provider/model destinations push within one navigation stack on macOS. iOS and Catalyst retain their existing modal presentation behavior. +- True tasks such as migration, cloud review, model download, and onboarding remain modal. +- Acknowledgements and MLX On Device AI use purpose-built, bounded Mac layouts with readable cards, consistent spacing, and scrollable advanced content. +- Remaining settings forms opt into grouped macOS form styling rather than inheriting the iOS sheet geometry. +- Shared settings rows preserve their accessibility button role and activation action. + +Verification for this second pass: + +- Native macOS, iOS Simulator, and Mac Catalyst Debug builds passed. +- The root native Settings window was launched and inspected live. It opened as a separate, correctly sized window with top-aligned cards and no dimmed or stacked parent sheet. +- The first user walkthrough exposed that the root `navigationDestination` modifiers were attached to the outside of the `NavigationStack`, so SwiftUI ignored Display Preferences, AI Settings, Transcription Settings, and Acknowledgements. Moving the modifiers onto the stack's content resolved the console warnings. +- A rebuilt live UI pass opened Display Preferences, AI Settings, Transcription Settings, Acknowledgements, and the separate Background Processing window successfully. Deeper provider controls still require the continuing panel-by-panel user walkthrough. +- Normal SwiftLint passed with zero violations in 173 files, and the final whitespace check passed. diff --git a/docs/macos-window-presentation-audit.md b/docs/macos-window-presentation-audit.md new file mode 100644 index 0000000..ad545af --- /dev/null +++ b/docs/macos-window-presentation-audit.md @@ -0,0 +1,45 @@ +# Native macOS Window Presentation Audit + +## Scope + +This audit covers every secondary SwiftUI presentation in the main app source as of Phase 3. It was prompted by transcript and summary details inheriting sheet content size, which could create windows taller than the display with inaccessible content. + +The inventory contained 60 presentation sites: + +- 28 settings, engine-configuration, and onboarding presentations. +- 13 recording, import, archive, player, and deletion presentations. +- 12 summary, attachment, location, and system-integration presentations. +- 5 transcript, speaker, location, and filter presentations. +- 2 background-processing and data-migration presentations. + +## Native presentation policy + +Document-like content that users may read or work with alongside the main app opens in an independent, movable, resizable macOS window. Each window has an explicit default size and content minimum: + +| Content | Window scene | Route value | +| --- | --- | --- | +| Summary detail | `summary-detail` | Recording UUID | +| Transcript viewer/editor | `transcript-detail` | Recording UUID | +| Audio player/recording detail | `recording-detail` | Recording UUID | +| Recordings library | `recordings-library` | Single window | +| Location map/detail | `location-detail` | Encoded `LocationData` | +| Background processing | `background-processing` | Single window | +| Processing job detail | `processing-job-detail` | Job UUID | + +True modal work remains attached to its parent window: filters, confirmations, pickers, title/date/note/speaker editors, attachment previews, import forms, archive/combine flows, and engine configuration. Every such presentation now receives a bounded native Mac viewport through `nativeMacModalSizing`; its contained `List`, `Form`, `ScrollView`, map, or PDF view owns scrolling. iPhone full-screen onboarding flows use `platformFullScreenCover`, which presents a bounded sheet on native macOS while retaining the full-screen cover on iOS and Catalyst. + +## Entry-point audit + +- `TranscriptsView` routes both audio and imported transcript rows to the transcript window. +- `RecordingsListView` routes row activation, the Play button, and post-archive restoration to the recording window. +- Summary rows continue to route to the summary window using an explicit scene ID. +- Location actions in transcript, recording, and summary views route to the location window. +- Background-processing actions in recording, settings, and migration views route to one activity window; job cards route to job-detail windows. +- Settings/configuration, attachment, import, filter, confirmation, and editor presentations remain modal and use bounded sizing. + +## Verification + +- Swift syntax parsing covers every changed presentation file. +- Native macOS, iOS Simulator, and Mac Catalyst targets must build before commit. +- The iOS unit-test target must pass before commit. +- Signed-app visual QA should open each independent window, move and resize it, confirm scrolling at minimum size, and exercise at least one representative modal from each inventory group. diff --git a/docs/testing-regimen.md b/docs/testing-regimen.md index 230045a..3782799 100644 --- a/docs/testing-regimen.md +++ b/docs/testing-regimen.md @@ -1,6 +1,6 @@ # BisonNotes Regression Testing Regimen -This regimen protects the release-critical paths that are expensive to rediscover manually: recording file validity, transcription flow, iCloud exclusions, watch transfer state, share import, Catalyst audio, and launch/navigation smoke coverage. +This regimen protects the release-critical paths that are expensive to rediscover manually: recording file validity, transcription flow, iCloud exclusions, watch transfer state, share import, Catalyst and native Mac behavior, and launch/navigation smoke coverage. ## Local Pre-Merge Gate @@ -36,9 +36,42 @@ Run the local pre-merge gate, then run: ```bash xcodebuild test -project "BisonNotes AI/BisonNotes AI.xcodeproj" -scheme "BisonNotes AI Watch App" -destination 'platform=watchOS Simulator,name=Apple Watch Series 11 (46mm)' -derivedDataPath /private/tmp/bisonnotes-watch-test-derived xcodebuild -project "BisonNotes AI/BisonNotes AI.xcodeproj" -scheme "BisonNotes AI" -destination 'platform=macOS,variant=Mac Catalyst' -configuration Debug -derivedDataPath /private/tmp/bisonnotes-catalyst-derived build +xcodebuild -project "BisonNotes AI/BisonNotes AI.xcodeproj" -scheme "BisonNotes AI macOS" -destination 'platform=macOS' -configuration Debug -derivedDataPath /private/tmp/bisonnotes-native-mac-derived build ``` -Expected result: watch metadata tests pass, the watch scheme builds, and the Catalyst build compiles with the current SwiftPM package graph. +Expected result: watch metadata tests pass, the watch scheme builds, and both Mac targets compile with the current SwiftPM package graph. + +Before a native Mac beta or cutover candidate, also archive the native app: + +```bash +xcodebuild archive -project "BisonNotes AI/BisonNotes AI.xcodeproj" -scheme "BisonNotes AI macOS" -destination 'generic/platform=macOS' -archivePath /private/tmp/BisonNotes-Native-Mac.xcarchive ONLY_ACTIVE_ARCH=NO EXCLUDED_ARCHS=x86_64 +``` + +## Native macOS Phase 3 Exit Gate + +Use a signed native build. The Phase 3 gate is complete only when the automated checks are green and every interaction below has been exercised. Record results in `docs/macos-phase-3-exit-report.md`. + +### Automated and product inspection + +- Run `git diff --check` and normal SwiftLint from `BisonNotes AI/BisonNotes AI` using the committed baseline. +- Build native macOS, iOS Simulator, and Mac Catalyst; run the iOS unit-test target. +- Inspect the native product's `Metadata.appintents/extract.actionsdata` for `StartRecordingIntent` and its App Shortcut phrases. +- Inspect the compiled asset catalog for every Mac AppIcon rendition from 16Γ—16 through 512Γ—512 points at 1x/2x. +- Confirm the main window is resizable, honors its minimum size, and reopens after its last window is closed. + +### Mac-native interaction pass + +- Open Settings with Command-comma; confirm it is a separate, closable Settings window and controls remain scrollable. +- Verify File-menu commands and key equivalents: New Recording (Command-N), Import Audio (Command-I), Import Transcript (Shift-Command-I), and Import From Link (Shift-Command-L). +- Open Import From Link from the File menu and confirm it is a bounded modal attached to the main window. +- Verify Command-1/2/3 navigation and the standard Undo, Redo, Cut, Copy, Paste, and Select All Edit commands in a text field. +- Open summary, transcript, recording/player, recordings-library, location, background-processing, and processing-job windows where data is available. Move and resize them, confirm their whole content scrolls at minimum size, and confirm they close normally. +- From Edit Transcript, open its summary, then close it with both Done and Escape. +- Exercise one representative bounded modal for import, settings/configuration, and content editing. +- In the Shortcuts app, find BisonNotes AI's Start Recording action. Run it once while the app is closed and once while it is already open; each run must activate the native app and start exactly one recording. +- Verify the Dock/Finder icon is the BisonNotes icon rather than a blank placeholder. + +Phase 2 hardware/runtime cases such as external-microphone hot swap, ScreenCaptureKit meeting audio, long background processing, export/share destinations, and archive bookmark restoration remain mandatory before Phase 4 beta even if the Phase 3 Mac-idiom gate is green. ## Manual Hardware Validation @@ -46,12 +79,13 @@ Simulator tests are not enough for these capabilities. Capture evidence for ever - iPhone/iPad: record with the real microphone, stop, verify playback duration is non-zero, and generate a transcript. - Mac Catalyst: record microphone-only audio, then record a real meeting/system-audio source with meeting-audio capture enabled; verify the final audio plays and has non-zero duration. +- Native macOS: repeat the microphone-only and meeting/system-audio recordings; change the selected microphone, hot-plug an external input during recording, and verify the final audio has no clicks, clipping, gaps beyond the device transition, or duplicated system audio. - Apple Watch: tap to record, mute to pause, unmute to resume, stop, transfer to iPhone, and verify import appears once. - Parakeet: download or reuse the on-device model on a supported device and transcribe a short known audio fixture. - iCloud: verify eligible content syncs across two devices or matching TestFlight builds, and verify a recording marked Keep on This Device does not sync. - Share extension: import audio from Voice Memos or Files, then verify the app creates a recording without scanning unrelated shared-container files. - System integrations: smoke-test Control Center recording and Action Button launch on supported devices. -- Accessibility: complete common tasks with VoiceOver and Voice Control on iPhone/iPad; sample Switch Control; verify Full Keyboard Access on iPad keyboard and Mac Catalyst; test largest Dynamic Type sizes; test light/dark, Increase Contrast, Reduce Transparency, Bold Text, Grayscale, and Differentiate Without Color; enable Reduce Motion and verify recording indicators remain understandable; test Apple Watch VoiceOver for start, mute, stop, transfer progress, low battery, and error recovery. +- Accessibility: complete common tasks with VoiceOver and Voice Control on iPhone/iPad; sample Switch Control; verify Full Keyboard Access on iPad keyboard, Mac Catalyst, and native macOS; test largest Dynamic Type sizes; test light/dark, Increase Contrast, Reduce Transparency, Bold Text, Grayscale, and Differentiate Without Color; enable Reduce Motion and verify recording indicators remain understandable; test Apple Watch VoiceOver for start, mute, stop, transfer progress, low battery, and error recovery. Record screenshots, resulting audio duration, transcript text, sync/import status, and relevant log excerpts for the release notes or PR.