{"$schema":"https://json.schemastore.org/sarif-2.1.0.json","version":"2.1.0","runs":[{"tool":{"driver":{"name":"codehealth","informationUri":"https://codehealth.canine.dev","rules":[{"id":"D1","name":"Cyclomatic Complexity","shortDescription":{"text":"Cyclomatic Complexity"},"helpUri":"https://codehealth.canine.dev/dimensions/D1"},{"id":"D2","name":"Cognitive Complexity","shortDescription":{"text":"Cognitive Complexity"},"helpUri":"https://codehealth.canine.dev/dimensions/D2"},{"id":"D3","name":"God Classes","shortDescription":{"text":"God Classes"},"helpUri":"https://codehealth.canine.dev/dimensions/D3"},{"id":"D4","name":"Code Duplication","shortDescription":{"text":"Code Duplication"},"helpUri":"https://codehealth.canine.dev/dimensions/D4"},{"id":"D6","name":"Cohesion (LCOM4)","shortDescription":{"text":"Cohesion (LCOM4)"},"helpUri":"https://codehealth.canine.dev/dimensions/D6"},{"id":"D9","name":"Test Distribution","shortDescription":{"text":"Test Distribution"},"helpUri":"https://codehealth.canine.dev/dimensions/D9"},{"id":"D13","name":"Secret Scanning","shortDescription":{"text":"Secret Scanning"},"helpUri":"https://codehealth.canine.dev/dimensions/D13","relationships":[{"target":{"id":"CWE-798","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]},{"target":{"id":"CWE-259","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]}],"properties":{"cwe":["CWE-798","CWE-259"]}},{"id":"D15","name":"Churn \u00D7 Complexity Hotspots","shortDescription":{"text":"Churn \u00D7 Complexity Hotspots"},"helpUri":"https://codehealth.canine.dev/dimensions/D15"},{"id":"D17","name":"Explicit Debt","shortDescription":{"text":"Explicit Debt"},"helpUri":"https://codehealth.canine.dev/dimensions/D17"},{"id":"D19","name":"Documentation Quality","shortDescription":{"text":"Documentation Quality"},"helpUri":"https://codehealth.canine.dev/dimensions/D19"},{"id":"D20","name":"ADR Quality","shortDescription":{"text":"ADR Quality"},"helpUri":"https://codehealth.canine.dev/dimensions/D20"},{"id":"D21","name":"Naming Consistency","shortDescription":{"text":"Naming Consistency"},"helpUri":"https://codehealth.canine.dev/dimensions/D21"},{"id":"D22","name":"Internal API Consistency","shortDescription":{"text":"Internal API Consistency"},"helpUri":"https://codehealth.canine.dev/dimensions/D22"},{"id":"D26","name":"Project Cohesion","shortDescription":{"text":"Project Cohesion"},"helpUri":"https://codehealth.canine.dev/dimensions/D26"},{"id":"D28","name":"Secrets (history)","shortDescription":{"text":"Secrets (history)"},"helpUri":"https://codehealth.canine.dev/dimensions/D28","relationships":[{"target":{"id":"CWE-798","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]},{"target":{"id":"CWE-259","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]}],"properties":{"cwe":["CWE-798","CWE-259"]}},{"id":"D29","name":"Static Analysis (SAST)","shortDescription":{"text":"Static Analysis (SAST)"},"helpUri":"https://codehealth.canine.dev/dimensions/D29","relationships":[{"target":{"id":"CWE-79","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]},{"target":{"id":"CWE-89","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]},{"target":{"id":"CWE-78","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]},{"target":{"id":"CWE-94","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]},{"target":{"id":"CWE-77","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]}],"properties":{"cwe":["CWE-79","CWE-89","CWE-78","CWE-94","CWE-77"]}},{"id":"D30","name":"Dependency Vulnerabilities","shortDescription":{"text":"Dependency Vulnerabilities"},"helpUri":"https://codehealth.canine.dev/dimensions/D30","relationships":[{"target":{"id":"CWE-1395","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]},{"target":{"id":"CWE-937","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]}],"properties":{"cwe":["CWE-1395","CWE-937"]}},{"id":"D34","name":"Knowledge Freshness","shortDescription":{"text":"Knowledge Freshness"},"helpUri":"https://codehealth.canine.dev/dimensions/D34"},{"id":"D35","name":"Change Coupling","shortDescription":{"text":"Change Coupling"},"helpUri":"https://codehealth.canine.dev/dimensions/D35"},{"id":"D36","name":"Supply-chain Provenance \u0026 Signing","shortDescription":{"text":"Supply-chain Provenance \u0026 Signing"},"helpUri":"https://codehealth.canine.dev/dimensions/D36","relationships":[{"target":{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]},{"target":{"id":"CWE-494","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]}],"properties":{"cwe":["CWE-1357","CWE-494"]}},{"id":"D43","name":"Malicious Dependencies","shortDescription":{"text":"Malicious Dependencies"},"helpUri":"https://codehealth.canine.dev/dimensions/D43","relationships":[{"target":{"id":"CWE-506","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]}],"properties":{"cwe":["CWE-506"]}},{"id":"AX10","name":"Code composition","shortDescription":{"text":"Code composition"},"helpUri":"https://codehealth.canine.dev/dimensions/AX10"},{"id":"AX3","name":"Project dependency cycles","shortDescription":{"text":"Project dependency cycles"},"helpUri":"https://codehealth.canine.dev/dimensions/AX3"},{"id":"AX4","name":"Dependency direction","shortDescription":{"text":"Dependency direction"},"helpUri":"https://codehealth.canine.dev/dimensions/AX4"},{"id":"AX9","name":"CQS / query purity","shortDescription":{"text":"CQS / query purity"},"helpUri":"https://codehealth.canine.dev/dimensions/AX9"},{"id":"ES1","name":"Fold determinism","shortDescription":{"text":"Fold determinism"},"helpUri":"https://codehealth.canine.dev/dimensions/ES1"},{"id":"ES2","name":"Immutable events","shortDescription":{"text":"Immutable events"},"helpUri":"https://codehealth.canine.dev/dimensions/ES2"},{"id":"M1","name":"Documentation (README)","shortDescription":{"text":"Documentation (README)"},"helpUri":"https://codehealth.canine.dev/dimensions/M1"},{"id":"M2","name":"Architecture documentation","shortDescription":{"text":"Architecture documentation"},"helpUri":"https://codehealth.canine.dev/dimensions/M2"},{"id":"M3","name":"Folder \u0026 project structure","shortDescription":{"text":"Folder \u0026 project structure"},"helpUri":"https://codehealth.canine.dev/dimensions/M3"},{"id":"M4","name":"Documentation accuracy","shortDescription":{"text":"Documentation accuracy"},"helpUri":"https://codehealth.canine.dev/dimensions/M4"},{"id":"P1","name":"CI/CD gates","shortDescription":{"text":"CI/CD gates"},"helpUri":"https://codehealth.canine.dev/dimensions/P1"},{"id":"P10","name":"Library API \u0026 versioning","shortDescription":{"text":"Library API \u0026 versioning"},"helpUri":"https://codehealth.canine.dev/dimensions/P10"},{"id":"P12","name":"CI test-gate honesty","shortDescription":{"text":"CI test-gate honesty"},"helpUri":"https://codehealth.canine.dev/dimensions/P12"},{"id":"P2","name":"Observability","shortDescription":{"text":"Observability"},"helpUri":"https://codehealth.canine.dev/dimensions/P2"},{"id":"P3","name":"Security \u0026 performance tooling","shortDescription":{"text":"Security \u0026 performance tooling"},"helpUri":"https://codehealth.canine.dev/dimensions/P3"},{"id":"P5","name":"DR \u0026 Backup","shortDescription":{"text":"DR \u0026 Backup"},"helpUri":"https://codehealth.canine.dev/dimensions/P5"},{"id":"P6","name":"Release Hygiene","shortDescription":{"text":"Release Hygiene"},"helpUri":"https://codehealth.canine.dev/dimensions/P6"},{"id":"PF3","name":"Async \u0026 latency hygiene","shortDescription":{"text":"Async \u0026 latency hygiene"},"helpUri":"https://codehealth.canine.dev/dimensions/PF3"},{"id":"X10","name":"Duplicated predicate","shortDescription":{"text":"Duplicated predicate"},"helpUri":"https://codehealth.canine.dev/dimensions/X10"},{"id":"X6","name":"Hand-rolled structured-format parsing","shortDescription":{"text":"Hand-rolled structured-format parsing"},"helpUri":"https://codehealth.canine.dev/dimensions/X6"},{"id":"X9","name":"Subsumed condition operand","shortDescription":{"text":"Subsumed condition operand"},"helpUri":"https://codehealth.canine.dev/dimensions/X9"}]}},"results":[{"ruleId":"D1","level":"warning","message":{"text":"App::update (cyclomatic 332): App::update has cyclomatic complexity 332 (threshold 15). To reduce it, keep the dispatch but shrink the arms: move each non-trivial case body into its own named function (or onto the value being matched) so the dispatch reads one line per case, and group related cases into a sub-dispatch. Where every arm is uniform \u2014 the same kind of value, with no behaviour of its own \u2014 a table keyed by the case is the shorter form; wherever the arms carry different data or different behaviour, keep them as cases, because collapsing those trades an explicit, reviewable set of cases for nothing. This file is where this pass\u0027s cyclomatic complexity CONCENTRATES: src/gui/app.rs holds 4 of the 29 functions over the threshold \u2014 including the worst \u2014 and 390 of the 844 points over it (46%), 2.7\u00D7 the next-largest file (src/cli.rs at 142). No single row can show this, because each is measured only against the threshold: reducing this one file moves this dimension further than any other file in the repository."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":1491}}}],"partialFingerprints":{"codehealthFindingId/v1":"fbfb4cd0d626aad3f32485ce7faf35f05b26239e560ab8592b16e273a1afe370"}},{"ruleId":"D1","level":"warning","message":{"text":"ludusavi::cli::run (cyclomatic 157): ludusavi::cli::run has cyclomatic complexity 157 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/cli.rs"},"region":{"startLine":142}}}],"partialFingerprints":{"codehealthFindingId/v1":"5389acacacedcfcd4a18f06877b0004b6bd0cc0664208827e5a4129513be88ba"}},{"ruleId":"D1","level":"warning","message":{"text":"TextHistories::input (cyclomatic 85): TextHistories::input has cyclomatic complexity 85 (threshold 15). To reduce it, keep the dispatch but shrink the arms: move each non-trivial case body into its own named function (or onto the value being matched) so the dispatch reads one line per case, and group related cases into a sub-dispatch. Where every arm is uniform \u2014 the same kind of value, with no behaviour of its own \u2014 a table keyed by the case is the shorter form; wherever the arms carry different data or different behaviour, keep them as cases, because collapsing those trades an explicit, reviewable set of cases for nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/shortcuts.rs"},"region":{"startLine":316}}}],"partialFingerprints":{"codehealthFindingId/v1":"e9cc0b480b5596be9402749a69931737ac48d78310271c85640a8e710bb229ee"}},{"ruleId":"D1","level":"warning","message":{"text":"App::handle_backup (cyclomatic 60): App::handle_backup has cyclomatic complexity 60 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top. This file is where this pass\u0027s cyclomatic complexity CONCENTRATES: src/gui/app.rs holds 4 of the 29 functions over the threshold \u2014 including the worst \u2014 and 390 of the 844 points over it (46%), 2.7\u00D7 the next-largest file (src/cli.rs at 142). No single row can show this, because each is measured only against the threshold: reducing this one file moves this dimension further than any other file in the repository."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":296}}}],"partialFingerprints":{"codehealthFindingId/v1":"a402536b952cbbadc4bff512a0b8db9cf585c37ae3168b59dab474aaa41dc65c"}},{"ruleId":"D1","level":"warning","message":{"text":"TitleFinder::find (cyclomatic 52): TitleFinder::find has cyclomatic complexity 52 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/title.rs"},"region":{"startLine":169}}}],"partialFingerprints":{"codehealthFindingId/v1":"374ad6439144198b53287be452dd447556c4ca48b5f1fc7db74e8eecf560dd9c"}},{"ruleId":"D1","level":"warning","message":{"text":"ludusavi::scan::scan_game_for_backup (cyclomatic 50): ludusavi::scan::scan_game_for_backup has cyclomatic complexity 50 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan.rs"},"region":{"startLine":544}}}],"partialFingerprints":{"codehealthFindingId/v1":"d539288847a6434a56281639386d901627a78a533dc0e1bb425094c8fca15f66"}},{"ruleId":"D1","level":"warning","message":{"text":"App::handle_restore (cyclomatic 40): App::handle_restore has cyclomatic complexity 40 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top. This file is where this pass\u0027s cyclomatic complexity CONCENTRATES: src/gui/app.rs holds 4 of the 29 functions over the threshold \u2014 including the worst \u2014 and 390 of the 844 points over it (46%), 2.7\u00D7 the next-largest file (src/cli.rs at 142). No single row can show this, because each is measured only against the threshold: reducing this one file moves this dimension further than any other file in the repository."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":731}}}],"partialFingerprints":{"codehealthFindingId/v1":"79f591811faff4e5858141012e7015b6b4bb929b12a05fd7b467388bec0848bb"}},{"ruleId":"D1","level":"warning","message":{"text":"ludusavi::scan::parse_paths (cyclomatic 40): ludusavi::scan::parse_paths has cyclomatic complexity 40 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan.rs"},"region":{"startLine":139}}}],"partialFingerprints":{"codehealthFindingId/v1":"5258e2a9eafe7e8f3698da2872d1cd8b56f8422dae0dd46cd57085a5bba972e1"}},{"ruleId":"D1","level":"warning","message":{"text":"StrictPath::analyze_with_mode (cyclomatic 36): StrictPath::analyze_with_mode has cyclomatic complexity 36 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/path.rs"},"region":{"startLine":289}}}],"partialFingerprints":{"codehealthFindingId/v1":"fdebb7d630cf451d4306422364594f7b33fde024ef0ec9caea6d9031d029ef4e"}},{"ruleId":"D1","level":"warning","message":{"text":"Theme::style (cyclomatic 30): Theme::style has cyclomatic complexity 30 (threshold 15). To reduce it, keep the dispatch but shrink the arms: move each non-trivial case body into its own named function (or onto the value being matched) so the dispatch reads one line per case, and group related cases into a sub-dispatch. Where every arm is uniform \u2014 the same kind of value, with no behaviour of its own \u2014 a table keyed by the case is the shorter form; wherever the arms carry different data or different behaviour, keep them as cases, because collapsing those trades an explicit, reviewable set of cases for nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/style.rs"},"region":{"startLine":184}}}],"partialFingerprints":{"codehealthFindingId/v1":"a59c4bca7833fa49a15d9f7230be40f4bc02ece9e0c3206506de4a8ee65ba8e6"}},{"ruleId":"D1","level":"warning","message":{"text":"Theme::style (cyclomatic 29): Theme::style has cyclomatic complexity 29 (threshold 15). To reduce it, keep the dispatch but shrink the arms: move each non-trivial case body into its own named function (or onto the value being matched) so the dispatch reads one line per case, and group related cases into a sub-dispatch. Where every arm is uniform \u2014 the same kind of value, with no behaviour of its own \u2014 a table keyed by the case is the shorter form; wherever the arms carry different data or different behaviour, keep them as cases, because collapsing those trades an explicit, reviewable set of cases for nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/style.rs"},"region":{"startLine":326}}}],"partialFingerprints":{"codehealthFindingId/v1":"5979d1ec56d862ee7746004a45909673542c3a172bf8b58db094c3ecaf7823cc"}},{"ruleId":"D1","level":"warning","message":{"text":"Ludusavi::back_up (cyclomatic 26): Ludusavi::back_up has cyclomatic complexity 26 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/api.rs"},"region":{"startLine":119}}}],"partialFingerprints":{"codehealthFindingId/v1":"16423e9aaa680f30f4a7a947ddadd8ff8dea77edd2b5576cc80a50e442ef7d00"}},{"ruleId":"D1","level":"warning","message":{"text":"GameListEntry::view (cyclomatic 26): GameListEntry::view has cyclomatic complexity 26 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/game_list.rs"},"region":{"startLine":49}}}],"partialFingerprints":{"codehealthFindingId/v1":"12da935a51acec1dd4b31d567bbc5cdc8dd7353874f174da6fd9b53ec3a166ff"}},{"ruleId":"D1","level":"warning","message":{"text":"Reporter::add_game (cyclomatic 25): Reporter::add_game has cyclomatic complexity 25 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/report.rs"},"region":{"startLine":311}}}],"partialFingerprints":{"codehealthFindingId/v1":"b77f6c2be2c22c02f8c97978ba5be17d766833af4388b2a9b924bdbeea02f1ca"}},{"ruleId":"D1","level":"warning","message":{"text":"Config::find_missing_roots (cyclomatic 23): Config::find_missing_roots has cyclomatic complexity 23 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/resource/config.rs"},"region":{"startLine":1444}}}],"partialFingerprints":{"codehealthFindingId/v1":"946cb0bd83f0436e80e98ab004fa930590990eee45240debce59bf5ab43b82eb"}},{"ruleId":"D1","level":"warning","message":{"text":"ludusavi::scan::semantic::convert::windows_physical_to_semantic (cyclomatic 23): ludusavi::scan::semantic::convert::windows_physical_to_semantic has cyclomatic complexity 23 (threshold 15). To reduce it, name the conditions: bind each compound test to a well-named local or a small predicate function, so the body reads as a sequence of named decisions rather than a chain of operators."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/semantic/convert.rs"},"region":{"startLine":63}}}],"partialFingerprints":{"codehealthFindingId/v1":"072c83166bfcc12a027fa6b81f586b759f340cef29bbde637c12ff8773534cbc"}},{"ruleId":"D1","level":"warning","message":{"text":"ludusavi::scan::semantic::convert::wine_physical_to_semantic (cyclomatic 23): ludusavi::scan::semantic::convert::wine_physical_to_semantic has cyclomatic complexity 23 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/semantic/convert.rs"},"region":{"startLine":184}}}],"partialFingerprints":{"codehealthFindingId/v1":"73b7b9d6ecd1aab1625505b9f0050e4a833a43c93036add691187aa4b423d09e"}},{"ruleId":"D1","level":"warning","message":{"text":"Ludusavi::restore (cyclomatic 22): Ludusavi::restore has cyclomatic complexity 22 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/api.rs"},"region":{"startLine":312}}}],"partialFingerprints":{"codehealthFindingId/v1":"2757804cca772a4dd61b90338a89a10bd6d5a289a8616064fca8b8d5cf04d3da"}},{"ruleId":"D1","level":"warning","message":{"text":"FileTreeNode::view (cyclomatic 20): FileTreeNode::view has cyclomatic complexity 20 (threshold 15). To reduce it, keep the dispatch but shrink the arms: move each non-trivial case body into its own named function (or onto the value being matched) so the dispatch reads one line per case, and group related cases into a sub-dispatch. Where every arm is uniform \u2014 the same kind of value, with no behaviour of its own \u2014 a table keyed by the case is the shorter form; wherever the arms carry different data or different behaviour, keep them as cases, because collapsing those trades an explicit, reviewable set of cases for nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/file_tree.rs"},"region":{"startLine":103}}}],"partialFingerprints":{"codehealthFindingId/v1":"cf1dce961daeb76415d9f6388647deb7341a40eecab5a326c6a0b7066b1f780b"}},{"ruleId":"D1","level":"warning","message":{"text":"Modal::message (cyclomatic 20): Modal::message has cyclomatic complexity 20 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/modal.rs"},"region":{"startLine":303}}}],"partialFingerprints":{"codehealthFindingId/v1":"e601642f510f69e7f226f92643d886455ae5809f591a4ce9cdfe3a2c225a5526"}},{"ruleId":"D1","level":"warning","message":{"text":"GameLayout::execute_backup_as_zip (cyclomatic 20): GameLayout::execute_backup_as_zip has cyclomatic complexity 20 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/layout.rs"},"region":{"startLine":1258}}}],"partialFingerprints":{"codehealthFindingId/v1":"53b5f28a1cf739580d050d658364f2afacf6af25cb037058f12cc7e887162f4e"}},{"ruleId":"D1","level":"warning","message":{"text":"Modal::text (cyclomatic 19): Modal::text has cyclomatic complexity 19 (threshold 15). To reduce it, keep the dispatch but shrink the arms: move each non-trivial case body into its own named function (or onto the value being matched) so the dispatch reads one line per case, and group related cases into a sub-dispatch. Where every arm is uniform \u2014 the same kind of value, with no behaviour of its own \u2014 a table keyed by the case is the shorter form; wherever the arms carry different data or different behaviour, keep them as cases, because collapsing those trades an explicit, reviewable set of cases for nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/modal.rs"},"region":{"startLine":259}}}],"partialFingerprints":{"codehealthFindingId/v1":"7f4c162d83491f8f5eb297bcf2e1b44080813dd0ca504ee83b97a8b39c517d1e"}},{"ruleId":"D1","level":"warning","message":{"text":"GameLayout::validate (cyclomatic 19): GameLayout::validate has cyclomatic complexity 19 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/layout.rs"},"region":{"startLine":2105}}}],"partialFingerprints":{"codehealthFindingId/v1":"589bc0edb07a9c0cf47f14d84fbf44e829a81271dcbcc3a60b6a049e4fa16e7b"}},{"ruleId":"D1","level":"warning","message":{"text":"App::handle_validation (cyclomatic 18): App::handle_validation has cyclomatic complexity 18 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top. This file is where this pass\u0027s cyclomatic complexity CONCENTRATES: src/gui/app.rs holds 4 of the 29 functions over the threshold \u2014 including the worst \u2014 and 390 of the 844 points over it (46%), 2.7\u00D7 the next-largest file (src/cli.rs at 142). No single row can show this, because each is measured only against the threshold: reducing this one file moves this dimension further than any other file in the repository."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":1037}}}],"partialFingerprints":{"codehealthFindingId/v1":"57c3df7c5eab820cd6e7da6b88fb1ffa1a5373c10c35dd9ba53c5f51de9e2930"}},{"ruleId":"D1","level":"warning","message":{"text":"ludusavi::scan::launchers::generic::scan (cyclomatic 18): ludusavi::scan::launchers::generic::scan has cyclomatic complexity 18 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/launchers/generic.rs"},"region":{"startLine":52}}}],"partialFingerprints":{"codehealthFindingId/v1":"1d650bd13842063cb66d7d3a02b93a3fc89c51dc06e07911e8f94ae59cedd6e0"}},{"ruleId":"D1","level":"warning","message":{"text":"Progress::view (cyclomatic 17): Progress::view has cyclomatic complexity 17 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/widget.rs"},"region":{"startLine":231}}}],"partialFingerprints":{"codehealthFindingId/v1":"70ba817eb446b279a22b50a0100cdd95c0ace4c3e272af49d5a9b3a7c75f63fb"}},{"ruleId":"D1","level":"warning","message":{"text":"DuplicateDetector::duplicate_games (cyclomatic 17): DuplicateDetector::duplicate_games has cyclomatic complexity 17 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/duplicate.rs"},"region":{"startLine":326}}}],"partialFingerprints":{"codehealthFindingId/v1":"1a21280fb860c34847ae359de31cec28fa034ead3c0a2a649f9b82a70969c540"}},{"ruleId":"D1","level":"warning","message":{"text":"DuplicateDetector::remove_game_and_refresh (cyclomatic 16): DuplicateDetector::remove_game_and_refresh has cyclomatic complexity 16 (threshold 15). To reduce it, break up the iteration: give each loop body a named function, and split a multi-phase loop into one function per phase so no single body carries the whole pipeline."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/duplicate.rs"},"region":{"startLine":178}}}],"partialFingerprints":{"codehealthFindingId/v1":"0b934b773b38bea1056b8050edccd574833eb2badb585b5bfa62070025c6daa5"}},{"ruleId":"D1","level":"warning","message":{"text":"ludusavi::scan::game_file_target (cyclomatic 16): ludusavi::scan::game_file_target has cyclomatic complexity 16 (threshold 15). To reduce it, separate the branches: extract each independent case into its own named function so the top-level body reads as a short sequence of named decisions."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan.rs"},"region":{"startLine":65}}}],"partialFingerprints":{"codehealthFindingId/v1":"2f6c8752c90d4c6e246d93a8206968af666944e7c0dc218c67786f54c2e70689"}},{"ruleId":"D2","level":"warning","message":{"text":"ludusavi::cli::run (cognitive 311): ludusavi::cli::run has cognitive complexity 311 (threshold 15). Drivers by points: if/else 98 (209 pts), match/switch 30 (68 pts), boolean chains 23, loops 5 (11 pts) (nesting depth added 155). To reduce it, flatten the nesting: this score is depth rather than breadth \u2014 most of its points come from checks stacked inside one another, so the work sits several levels in. Invert each enclosing check into an early exit (a return, or the language\u0027s equivalent) so the happy path stays at one level, and where a level cannot be exited early, lift the block it encloses into its own named function."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/cli.rs"},"region":{"startLine":142}}}],"partialFingerprints":{"codehealthFindingId/v1":"cc07d14ab741cb81f5fa4db24a820236e32962d1fb19913fe13316a5fc4eab96"}},{"ruleId":"D2","level":"warning","message":{"text":"App::update (cognitive 283): App::update has cognitive complexity 283 (threshold 15). Drivers by points: if/else 56 (139 pts), match/switch 57 (105 pts), loops 12 (34 pts), boolean chains 5 (nesting depth added 153). The drivers above price the dispatch low by construction \u2014 a dispatch is charged once however many cases it lists, while each branch inside an arm is charged in full \u2014 so most of this count is what the case bodies hold, and the arms are where it can be reduced. To reduce it, keep the dispatch but shrink the arms: move each non-trivial case body into its own named function (or onto the value being matched) so the dispatch reads one line per case, and group related cases into a sub-dispatch. Keep every case explicit, and make the behaviour for cases you do not list a deliberate choice rather than an accident."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":1491}}}],"partialFingerprints":{"codehealthFindingId/v1":"66226acf114cf31fd067a4541d73db2e701fe8e5ebb51ec8f39da53e6b65dbb7"}},{"ruleId":"D2","level":"warning","message":{"text":"ludusavi::scan::scan_game_for_backup (cognitive 131): ludusavi::scan::scan_game_for_backup has cognitive complexity 131 (threshold 15). Drivers by points: if/else 26 (81 pts), loops 21 (46 pts), boolean chains 2, match/switch 1 (2 pts) (nesting depth added 81). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan.rs"},"region":{"startLine":544}}}],"partialFingerprints":{"codehealthFindingId/v1":"4876002ba59208ac00f19ec22a2586eb37c5b7c9716c76fa76f613c4bbfc2c57"}},{"ruleId":"D2","level":"warning","message":{"text":"App::handle_backup (cognitive 118): App::handle_backup has cognitive complexity 118 (threshold 15). Drivers by points: if/else 41 (88 pts), boolean chains 10, loops 4 (10 pts), match/switch 5 (10 pts) (nesting depth added 58). The drivers above price the dispatch low by construction \u2014 a dispatch is charged once however many cases it lists, while each branch inside an arm is charged in full \u2014 so most of this count is what the case bodies hold, and the arms are where it can be reduced. To reduce it, keep the dispatch but shrink the arms: move each non-trivial case body into its own named function (or onto the value being matched) so the dispatch reads one line per case, and group related cases into a sub-dispatch. Keep every case explicit, and make the behaviour for cases you do not list a deliberate choice rather than an accident."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":296}}}],"partialFingerprints":{"codehealthFindingId/v1":"e55269673554307fafc1e0ad6a824770f3f5aa53b76fb03908208e9a26910e2a"}},{"ruleId":"D2","level":"warning","message":{"text":"TitleFinder::find (cognitive 116): TitleFinder::find has cognitive complexity 116 (threshold 15). Drivers by points: if/else 26 (75 pts), loops 6 (18 pts), boolean chains 14, match/switch 3 (9 pts) (nesting depth added 67). To reduce it, flatten the nesting: this score is depth rather than breadth \u2014 most of its points come from checks stacked inside one another, so the work sits several levels in. Invert each enclosing check into an early exit (a return, or the language\u0027s equivalent) so the happy path stays at one level, and where a level cannot be exited early, lift the block it encloses into its own named function."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/title.rs"},"region":{"startLine":169}}}],"partialFingerprints":{"codehealthFindingId/v1":"a3a692832601fe23ec8ff2508006a411cfdb4ccee3dd5adcb97662c0d1d5d641"}},{"ruleId":"D2","level":"warning","message":{"text":"App::handle_restore (cognitive 78): App::handle_restore has cognitive complexity 78 (threshold 15). Drivers by points: if/else 27 (58 pts), loops 4 (10 pts), boolean chains 5, match/switch 3 (5 pts) (nesting depth added 39). The drivers above price the dispatch low by construction \u2014 a dispatch is charged once however many cases it lists, while each branch inside an arm is charged in full \u2014 so most of this count is what the case bodies hold, and the arms are where it can be reduced. To reduce it, keep the dispatch but shrink the arms: move each non-trivial case body into its own named function (or onto the value being matched) so the dispatch reads one line per case, and group related cases into a sub-dispatch. Keep every case explicit, and make the behaviour for cases you do not list a deliberate choice rather than an accident."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":731}}}],"partialFingerprints":{"codehealthFindingId/v1":"15070e61b02a28d89cabcef7347f24382fc08b0aef279875b6188d8fa2891969"}},{"ruleId":"D2","level":"warning","message":{"text":"GameLayout::validate (cognitive 64): GameLayout::validate has cognitive complexity 64 (threshold 15). Drivers by points: if/else 12 (45 pts), loops 4 (14 pts), match/switch 2 (5 pts) (nesting depth added 46). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/layout.rs"},"region":{"startLine":2105}}}],"partialFingerprints":{"codehealthFindingId/v1":"d02ea0381f861715fbbad5daf29fed45be1f6abe984dc5fdd42b2d55ba3267aa"}},{"ruleId":"D2","level":"warning","message":{"text":"ludusavi::scan::parse_paths (cognitive 62): ludusavi::scan::parse_paths has cognitive complexity 62 (threshold 15). Drivers by points: if/else 19 (38 pts), loops 4 (13 pts), match/switch 3 (6 pts), boolean chains 5 (nesting depth added 31). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan.rs"},"region":{"startLine":139}}}],"partialFingerprints":{"codehealthFindingId/v1":"1456ff320614bcae090fff5dc958e6213089843de5c7213f4b57a7803f3c1af7"}},{"ruleId":"D2","level":"warning","message":{"text":"Reporter::add_game (cognitive 59): Reporter::add_game has cognitive complexity 59 (threshold 15). Drivers by points: if/else 17 (42 pts), loops 5 (11 pts), match/switch 3 (6 pts) (nesting depth added 34). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/report.rs"},"region":{"startLine":311}}}],"partialFingerprints":{"codehealthFindingId/v1":"5b307ff607ab51115c2f8f3cde95b32489095c69753e22b6750c5009c8c217e3"}},{"ruleId":"D2","level":"warning","message":{"text":"StrictPath::analyze_with_mode (cognitive 52): StrictPath::analyze_with_mode has cognitive complexity 52 (threshold 15). Drivers by points: if/else 10 (29 pts), match/switch 6 (15 pts), loops 3 (6 pts), boolean chains 2 (nesting depth added 31). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/path.rs"},"region":{"startLine":289}}}],"partialFingerprints":{"codehealthFindingId/v1":"8c46f82e2c57bcac29598ae93bc1085dd0f668d57ba93895784d82a5addb1bfe"}},{"ruleId":"D2","level":"warning","message":{"text":"DuplicateDetector::duplicate_games (cognitive 48): DuplicateDetector::duplicate_games has cognitive complexity 48 (threshold 15). Drivers by points: if/else 9 (26 pts), loops 7 (22 pts) (nesting depth added 32). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/duplicate.rs"},"region":{"startLine":326}}}],"partialFingerprints":{"codehealthFindingId/v1":"ab03c993c687a99d16e5c57ebfadce4b584fb7eae9bdefda8517e008846af513"}},{"ruleId":"D2","level":"warning","message":{"text":"Ludusavi::back_up (cognitive 47): Ludusavi::back_up has cognitive complexity 47 (threshold 15). Drivers by points: if/else 18 (32 pts), boolean chains 7, match/switch 2 (6 pts), loops 2 (nesting depth added 18). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/api.rs"},"region":{"startLine":119}}}],"partialFingerprints":{"codehealthFindingId/v1":"3fb36e285e45d9629454a57c0af262181a8d105c51922f5697b51768f452b001"}},{"ruleId":"D2","level":"warning","message":{"text":"Ludusavi::restore (cognitive 42): Ludusavi::restore has cognitive complexity 42 (threshold 15). Drivers by points: if/else 16 (28 pts), boolean chains 6, match/switch 2 (6 pts), loops 2 (nesting depth added 16). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/api.rs"},"region":{"startLine":312}}}],"partialFingerprints":{"codehealthFindingId/v1":"8076180f660577e6076e68d1822783281200b40ffd43a292016fe9b081a3c3df"}},{"ruleId":"D2","level":"warning","message":{"text":"ludusavi::scan::launchers::generic::scan (cognitive 39): ludusavi::scan::launchers::generic::scan has cognitive complexity 39 (threshold 15). Drivers by points: if/else 12 (29 pts), loops 5 (7 pts), boolean chains 2, match/switch 1 (nesting depth added 19). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/launchers/generic.rs"},"region":{"startLine":52}}}],"partialFingerprints":{"codehealthFindingId/v1":"1c16117d961f923b4683ab5da6a893605867c41273c051cce6389faa5ed997ea"}},{"ruleId":"D2","level":"warning","message":{"text":"DuplicateDetector::remove_game_and_refresh (cognitive 38): DuplicateDetector::remove_game_and_refresh has cognitive complexity 38 (threshold 15). Drivers by points: loops 8 (24 pts), if/else 7 (14 pts) (nesting depth added 23). To reduce it, break up the iteration: give each loop body a named function, and split a multi-phase loop into one function per phase so no single body carries the whole pipeline."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/duplicate.rs"},"region":{"startLine":178}}}],"partialFingerprints":{"codehealthFindingId/v1":"a9a0b6154633d7aa3b72a370a2be1011a9cf39354d85dc4d28fd688c672e9d4f"}},{"ruleId":"D2","level":"warning","message":{"text":"Config::find_missing_roots (cognitive 36): Config::find_missing_roots has cognitive complexity 36 (threshold 15). Drivers by points: if/else 12 (23 pts), loops 5 (7 pts), boolean chains 3, match/switch 2 (3 pts) (nesting depth added 14). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/resource/config.rs"},"region":{"startLine":1444}}}],"partialFingerprints":{"codehealthFindingId/v1":"264da5eb32de3f1ffc3702d59d7c2ab2c79de606aa5ce01f54474409e712e64b"}},{"ruleId":"D2","level":"warning","message":{"text":"Hives::restore (cognitive 34): Hives::restore has cognitive complexity 34 (threshold 15). Drivers by points: if/else 9 (24 pts), loops 3 (6 pts), match/switch 1 (3 pts), boolean chains 1 (nesting depth added 20). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/registry/win.rs"},"region":{"startLine":302}}}],"partialFingerprints":{"codehealthFindingId/v1":"cd3a3d6c6dc4408216d641587279be11991cc42361b097f3cc891d1972ebf00e"}},{"ruleId":"D2","level":"warning","message":{"text":"ludusavi::cloud::rclone_monitor::run (cognitive 34): ludusavi::cloud::rclone_monitor::run has cognitive complexity 34 (threshold 15). Drivers by points: if/else 5 (22 pts), match/switch 3 (10 pts), loops 1 (2 pts) (nesting depth added 25). The drivers above price the dispatch low by construction \u2014 a dispatch is charged once however many cases it lists, while each branch inside an arm is charged in full \u2014 so most of this count is what the case bodies hold, and the arms are where it can be reduced. To reduce it, keep the dispatch but shrink the arms: move each non-trivial case body into its own named function (or onto the value being matched) so the dispatch reads one line per case, and group related cases into a sub-dispatch. Keep every case explicit, and make the behaviour for cases you do not list a deliberate choice rather than an accident."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/cloud.rs"},"region":{"startLine":766}}}],"partialFingerprints":{"codehealthFindingId/v1":"944e71309e22d7b05f0c2fca2e33063860fe0c1c3b9d6eb9e9dd38a5bb0c8a58"}},{"ruleId":"D2","level":"warning","message":{"text":"ludusavi::scan::semantic::convert::wine_physical_to_semantic (cognitive 33): ludusavi::scan::semantic::convert::wine_physical_to_semantic has cognitive complexity 33 (threshold 15). Drivers by points: if/else 16 (27 pts), boolean chains 6 (nesting depth added 11). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/semantic/convert.rs"},"region":{"startLine":184}}}],"partialFingerprints":{"codehealthFindingId/v1":"14e452e19313dc1cbdaa32ff77fc6e3ead2bfb3d7a11099b6412ca3d0d0373eb"}},{"ruleId":"D2","level":"warning","message":{"text":"App::handle_validation (cognitive 31): App::handle_validation has cognitive complexity 31 (threshold 15). Drivers by points: if/else 11 (23 pts), loops 2 (4 pts), match/switch 2 (3 pts), boolean chains 1 (nesting depth added 15). The drivers above price the dispatch low by construction \u2014 a dispatch is charged once however many cases it lists, while each branch inside an arm is charged in full \u2014 so most of this count is what the case bodies hold, and the arms are where it can be reduced. To reduce it, keep the dispatch but shrink the arms: move each non-trivial case body into its own named function (or onto the value being matched) so the dispatch reads one line per case, and group related cases into a sub-dispatch. Keep every case explicit, and make the behaviour for cases you do not list a deliberate choice rather than an accident."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":1037}}}],"partialFingerprints":{"codehealthFindingId/v1":"012d5287425f92efe0577cf71afd5f9b48e84684be8c06fb9bd53dce2c69539f"}},{"ruleId":"D2","level":"warning","message":{"text":"GameListEntry::view (cognitive 31): GameListEntry::view has cognitive complexity 31 (threshold 15). Drivers by points: if/else 19 (20 pts), match/switch 5 (6 pts), boolean chains 5 (nesting depth added 2). To reduce it, split the body: this score is breadth rather than depth \u2014 many checks laid out side by side rather than nested inside one another, so inverting conditions into early returns has nothing left to flatten. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/game_list.rs"},"region":{"startLine":49}}}],"partialFingerprints":{"codehealthFindingId/v1":"cb05149bc07cfcb7d2796be1306409b8f2377fac3d50258eac55d19b844a017c"}},{"ruleId":"D2","level":"warning","message":{"text":"GameLayout::execute_backup_as_zip (cognitive 31): GameLayout::execute_backup_as_zip has cognitive complexity 31 (threshold 15). Drivers by points: if/else 8 (16 pts), match/switch 6 (11 pts), loops 3 (4 pts) (nesting depth added 14). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/layout.rs"},"region":{"startLine":1258}}}],"partialFingerprints":{"codehealthFindingId/v1":"f7177f0fadb9632679af3a94fa28691c5160d4c9e195f21b7b99345a2c6bb3a6"}},{"ruleId":"D2","level":"warning","message":{"text":"GameLayout::restore (cognitive 29): GameLayout::restore has cognitive complexity 29 (threshold 15). Drivers by points: if/else 6 (14 pts), match/switch 4 (12 pts), boolean chains 2, loops 1 (nesting depth added 16). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/layout.rs"},"region":{"startLine":1763}}}],"partialFingerprints":{"codehealthFindingId/v1":"95f6908720e9557dec61be4e952504a47490b7d2af50e1c04a130f2e98b71682"}},{"ruleId":"D2","level":"warning","message":{"text":"ludusavi::scan::game_file_target (cognitive 27): ludusavi::scan::game_file_target has cognitive complexity 27 (threshold 15). Drivers by points: match/switch 3 (11 pts), if/else 7 (10 pts), boolean chains 4, loops 1 (2 pts) (nesting depth added 12). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan.rs"},"region":{"startLine":65}}}],"partialFingerprints":{"codehealthFindingId/v1":"2d1df0a753cd6d7ded65c6899390a00e46b8c48108c99e2b608125b15c03024d"}},{"ruleId":"D2","level":"warning","message":{"text":"Manifest::incorporate_secondary_manifest (cognitive 25): Manifest::incorporate_secondary_manifest has cognitive complexity 25 (threshold 15). Drivers by points: if/else 9 (18 pts), loops 3 (7 pts) (nesting depth added 13). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/resource/manifest.rs"},"region":{"startLine":802}}}],"partialFingerprints":{"codehealthFindingId/v1":"bca4c6d6dc1e43beacd6f04f5be3163d6aa977ac067e20704b50b10eddcfa8af"}},{"ruleId":"D2","level":"warning","message":{"text":"DuplicateDetector::count_duplicated_items_for (cognitive 25): DuplicateDetector::count_duplicated_items_for has cognitive complexity 25 (threshold 15). Drivers by points: if/else 6 (17 pts), loops 4 (5 pts), boolean chains 3 (nesting depth added 12). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/duplicate.rs"},"region":{"startLine":291}}}],"partialFingerprints":{"codehealthFindingId/v1":"a83aaa86a01d7451390d96cf640b9efc4b71a2f576066e67f1157cea995849ae"}},{"ruleId":"D2","level":"warning","message":{"text":"Progress::view (cognitive 22): Progress::view has cognitive complexity 22 (threshold 15). Drivers by points: if/else 10 (16 pts), match/switch 3 (4 pts), boolean chains 2 (nesting depth added 7). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/widget.rs"},"region":{"startLine":231}}}],"partialFingerprints":{"codehealthFindingId/v1":"0c5347f6fbd25f8004616b3d10889dce6768c53535f7448e390054c80b6c29ae"}},{"ruleId":"D2","level":"warning","message":{"text":"GameLayout::scan_for_restoration (cognitive 22): GameLayout::scan_for_restoration has cognitive complexity 22 (threshold 15). Drivers by points: loops 3 (9 pts), if/else 4 (8 pts), match/switch 1 (4 pts), boolean chains 1 (nesting depth added 13). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/layout.rs"},"region":{"startLine":1654}}}],"partialFingerprints":{"codehealthFindingId/v1":"e8ef5f98c6484769198a5318a39539d342e84e34c68236fa1eafbac6e58f70ea"}},{"ruleId":"D2","level":"warning","message":{"text":"ludusavi::scan::semantic::convert::windows_physical_to_semantic (cognitive 22): ludusavi::scan::semantic::convert::windows_physical_to_semantic has cognitive complexity 22 (threshold 15). Drivers by points: boolean chains 11, if/else 11. To reduce it, name the conditions: bind each compound test to a well-named local or a small predicate function, so the body reads as a sequence of named decisions rather than a chain of operators."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/semantic/convert.rs"},"region":{"startLine":63}}}],"partialFingerprints":{"codehealthFindingId/v1":"4fcec8f596dffd3c81e4cf91b688c7042913ce5456a8f9840fbfc8eed0069b33"}},{"ruleId":"D2","level":"warning","message":{"text":"FileTreeNode::view (cognitive 21): FileTreeNode::view has cognitive complexity 21 (threshold 15). Drivers by points: match/switch 8 (11 pts), if/else 7 (9 pts), boolean chains 1 (nesting depth added 5). To reduce it, keep the dispatch but shrink the arms: move each non-trivial case body into its own named function (or onto the value being matched) so the dispatch reads one line per case, and group related cases into a sub-dispatch. Keep every case explicit, and make the behaviour for cases you do not list a deliberate choice rather than an accident."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/file_tree.rs"},"region":{"startLine":103}}}],"partialFingerprints":{"codehealthFindingId/v1":"3e0a56d960b6da396aa08a814830ff180e8ce99a62198502acd0c4ca97d7acf3"}},{"ruleId":"D2","level":"warning","message":{"text":"ludusavi::scan::launchers::lutris::scan_db (cognitive 21): ludusavi::scan::launchers::lutris::scan_db has cognitive complexity 21 (threshold 15). Drivers by points: if/else 6 (13 pts), match/switch 2 (6 pts), boolean chains 1, loops 1 (nesting depth added 11). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/launchers/lutris.rs"},"region":{"startLine":199}}}],"partialFingerprints":{"codehealthFindingId/v1":"28399313cddcab82cf4c57a0a61cd69c068fc0e644d0830131834593d6665ad1"}},{"ruleId":"D2","level":"warning","message":{"text":"App::new (cognitive 20): App::new has cognitive complexity 20 (threshold 15). Drivers by points: if/else 11 (14 pts), match/switch 3 (5 pts), boolean chains 1 (nesting depth added 5). To reduce it, split the body: most of this score is breadth rather than depth \u2014 checks laid out side by side rather than stacked \u2014 so group the statements between the checks into named steps and move each step into its own function. Some of it IS depth: where a check sits inside another whose only job is to reach it, merge the two into one condition, and where an else follows a branch that already returns, drop the trailing else and let the rest of the body continue at one level."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":1364}}}],"partialFingerprints":{"codehealthFindingId/v1":"38e7b90a371b72b1dd54c9ba01ac93f412d017cd91fcce16a903a66e164fdf5e"}},{"ruleId":"D2","level":"warning","message":{"text":"GameList::update_game (cognitive 20): GameList::update_game has cognitive complexity 20 (threshold 15). Drivers by points: if/else 7 (15 pts), boolean chains 2, loops 1 (2 pts), match/switch 1 (nesting depth added 9). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/game_list.rs"},"region":{"startLine":692}}}],"partialFingerprints":{"codehealthFindingId/v1":"9ac7dd2230d9584ebcb923efd322f60c7972f000a9f303d5bb05966bf3f5a7d7"}},{"ruleId":"D2","level":"warning","message":{"text":"Modal::message (cognitive 20): Modal::message has cognitive complexity 20 (threshold 15). Drivers by points: if/else 10 (16 pts), boolean chains 3, match/switch 1 (nesting depth added 6). The drivers above price the dispatch low by construction \u2014 a dispatch is charged once however many cases it lists, while each branch inside an arm is charged in full \u2014 so most of this count is what the case bodies hold, and the arms are where it can be reduced. To reduce it, keep the dispatch but shrink the arms: move each non-trivial case body into its own named function (or onto the value being matched) so the dispatch reads one line per case, and group related cases into a sub-dispatch. Keep every case explicit, and make the behaviour for cases you do not list a deliberate choice rather than an accident."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/modal.rs"},"region":{"startLine":303}}}],"partialFingerprints":{"codehealthFindingId/v1":"8889284927d571c67c37cf9ecdb71e61f0641e9d975f8245e37817fade30c374"}},{"ruleId":"D2","level":"warning","message":{"text":"RcloneProcess::events (cognitive 19): RcloneProcess::events has cognitive complexity 19 (threshold 15). Drivers by points: match/switch 3 (11 pts), if/else 3 (6 pts), loops 1 (2 pts) (nesting depth added 12). To reduce it, keep the dispatch but shrink the arms: move each non-trivial case body into its own named function (or onto the value being matched) so the dispatch reads one line per case, and group related cases into a sub-dispatch. Keep every case explicit, and make the behaviour for cases you do not list a deliberate choice rather than an accident."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/cloud.rs"},"region":{"startLine":84}}}],"partialFingerprints":{"codehealthFindingId/v1":"6c6df95b97a0a59284431955e5bab4947ed756f5b5555932a1871b467c16a4ff"}},{"ruleId":"D2","level":"warning","message":{"text":"Backup::prune_failures (cognitive 19): Backup::prune_failures has cognitive complexity 19 (threshold 15). Drivers by points: if/else 4 (10 pts), loops 4 (8 pts), match/switch 1 (nesting depth added 10). The drivers above price the dispatch low by construction \u2014 a dispatch is charged once however many cases it lists, while each branch inside an arm is charged in full \u2014 so most of this count is what the case bodies hold, and the arms are where it can be reduced. To reduce it, keep the dispatch but shrink the arms: move each non-trivial case body into its own named function (or onto the value being matched) so the dispatch reads one line per case, and group related cases into a sub-dispatch. Keep every case explicit, and make the behaviour for cases you do not list a deliberate choice rather than an accident."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/layout.rs"},"region":{"startLine":184}}}],"partialFingerprints":{"codehealthFindingId/v1":"b11e977150377fc5c2a0f21e781b7ab3d914f88a320386127879ffe562b9df8c"}},{"ruleId":"D2","level":"warning","message":{"text":"GameLayout::forget_excess_backups (cognitive 19): GameLayout::forget_excess_backups has cognitive complexity 19 (threshold 15). Drivers by points: if/else 5 (10 pts), loops 3 (5 pts), boolean chains 4 (nesting depth added 7). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/layout.rs"},"region":{"startLine":1421}}}],"partialFingerprints":{"codehealthFindingId/v1":"a5a5bf0f17c3567bd22c70ae0124e6cd6e639db3b22669750bba61d9f294494f"}},{"ruleId":"D2","level":"warning","message":{"text":"GameLayout::modify_backup (cognitive 19): GameLayout::modify_backup has cognitive complexity 19 (threshold 15). Drivers by points: if/else 5 (13 pts), loops 2 (5 pts), match/switch 1 (nesting depth added 11). The drivers above price the dispatch low by construction \u2014 a dispatch is charged once however many cases it lists, while each branch inside an arm is charged in full \u2014 so most of this count is what the case bodies hold, and the arms are where it can be reduced. To reduce it, keep the dispatch but shrink the arms: move each non-trivial case body into its own named function (or onto the value being matched) so the dispatch reads one line per case, and group related cases into a sub-dispatch. Keep every case explicit, and make the behaviour for cases you do not list a deliberate choice rather than an accident."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/layout.rs"},"region":{"startLine":2055}}}],"partialFingerprints":{"codehealthFindingId/v1":"f2bfabe30a2e5ee126867fd13c335f9525fb0f93faf7e70165a12ec32af105bf"}},{"ruleId":"D2","level":"warning","message":{"text":"ScanInfo::count_changes (cognitive 19): ScanInfo::count_changes has cognitive complexity 19 (threshold 15). Drivers by points: if/else 8 (14 pts), loops 3 (4 pts), boolean chains 1 (nesting depth added 7). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/preview.rs"},"region":{"startLine":194}}}],"partialFingerprints":{"codehealthFindingId/v1":"b284007f7bb4ef170b1f4dffb38aa81d349d8786f330a2dd64cbdf718ab04b20"}},{"ruleId":"D2","level":"warning","message":{"text":"GameLayout::plan_differential_backup (cognitive 18): GameLayout::plan_differential_backup has cognitive complexity 18 (threshold 15). Drivers by points: if/else 6 (12 pts), loops 2 (3 pts), match/switch 1 (2 pts), boolean chains 1 (nesting depth added 8). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/layout.rs"},"region":{"startLine":1131}}}],"partialFingerprints":{"codehealthFindingId/v1":"d071f3e89925be0e0c888af24fc52c9926325d72be88f0719ff6104e91a98a4a"}},{"ruleId":"D2","level":"warning","message":{"text":"Hives::from (cognitive 18): Hives::from has cognitive complexity 18 (threshold 15). Drivers by points: if/else 3 (8 pts), match/switch 2 (6 pts), loops 2 (4 pts) (nesting depth added 11). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/registry.rs"},"region":{"startLine":170}}}],"partialFingerprints":{"codehealthFindingId/v1":"f7c711ada53248c29c12dcbff0c241f915f28881ee90ef0290028a798af5e0a5"}},{"ruleId":"D2","level":"warning","message":{"text":"ludusavi::cli::api::process (cognitive 18): ludusavi::cli::api::process has cognitive complexity 18 (threshold 15). Drivers by points: if/else 4 (12 pts), match/switch 2 (5 pts), loops 1 (nesting depth added 11). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/cli/api.rs"},"region":{"startLine":205}}}],"partialFingerprints":{"codehealthFindingId/v1":"c5b1e579e09cd0363a18460f7e7dd4065c4c1a510628ea3b0f71d17726d9d3fd"}},{"ruleId":"D2","level":"warning","message":{"text":"Theme::style (cognitive 17): Theme::style has cognitive complexity 17 (threshold 15). Drivers by points: match/switch 14 (17 pts) (nesting depth added 3). To reduce it, keep the dispatch but shrink the arms: move each non-trivial case body into its own named function (or onto the value being matched) so the dispatch reads one line per case, and group related cases into a sub-dispatch. Keep every case explicit, and make the behaviour for cases you do not list a deliberate choice rather than an accident."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/style.rs"},"region":{"startLine":184}}}],"partialFingerprints":{"codehealthFindingId/v1":"675e0de3a9ac97ee2da71bc38705039844b1615e32bf1825499830ac1b0176a7"}},{"ruleId":"D2","level":"warning","message":{"text":"ToggledRegistryEntry::prune (cognitive 17): ToggledRegistryEntry::prune has cognitive complexity 17 (threshold 15). Drivers by points: if/else 5 (11 pts), loops 2 (6 pts) (nesting depth added 10). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/resource/config.rs"},"region":{"startLine":742}}}],"partialFingerprints":{"codehealthFindingId/v1":"e225b6beacbe96ce62675dde03ab1bf4e511916d1908790a27159e3a1367fc25"}},{"ruleId":"D2","level":"warning","message":{"text":"ludusavi::scan::registry::win::scan_registry_key (cognitive 17): ludusavi::scan::registry::win::scan_registry_key has cognitive complexity 17 (threshold 15). Drivers by points: if/else 4 (8 pts), match/switch 2 (5 pts), loops 2 (4 pts) (nesting depth added 9). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/registry/win.rs"},"region":{"startLine":129}}}],"partialFingerprints":{"codehealthFindingId/v1":"62cce1df68198dd93f6c2a8b74b57a8bf2d6371e761b1ac332132e7e16328528"}},{"ruleId":"D2","level":"warning","message":{"text":"ludusavi::scan::wine_prefixes_with_included_files (cognitive 17): ludusavi::scan::wine_prefixes_with_included_files has cognitive complexity 17 (threshold 15). Drivers by points: if/else 5 (10 pts), loops 4 (5 pts), boolean chains 2 (nesting depth added 6). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan.rs"},"region":{"startLine":986}}}],"partialFingerprints":{"codehealthFindingId/v1":"3d20f96b695072625900d3d40b72a28b3ede11ff803075c973acbfe32bb7ead6"}},{"ruleId":"D2","level":"warning","message":{"text":"ludusavi::cli::sync_cloud (cognitive 17): ludusavi::cli::sync_cloud has cognitive complexity 17 (threshold 15). Drivers by points: if/else 4 (7 pts), match/switch 4 (7 pts), loops 2 (3 pts) (nesting depth added 7). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/cli.rs"},"region":{"startLine":1369}}}],"partialFingerprints":{"codehealthFindingId/v1":"35ccfac19f39cc91e9636cb85658e35721e4027e0417056188053bed2dfc18be"}},{"ruleId":"D2","level":"warning","message":{"text":"DuplicateDetector::add_game (cognitive 16): DuplicateDetector::add_game has cognitive complexity 16 (threshold 15). Drivers by points: if/else 3 (7 pts), loops 4 (5 pts), boolean chains 4 (nesting depth added 5). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/duplicate.rs"},"region":{"startLine":97}}}],"partialFingerprints":{"codehealthFindingId/v1":"1e0caa7cccf69025d4cac8c871e44ff73969d4e204bded71358154e633ea6fba"}},{"ruleId":"D2","level":"warning","message":{"text":"GameLayout::find_irrelevant_backup_files (cognitive 16): GameLayout::find_irrelevant_backup_files has cognitive complexity 16 (threshold 15). Drivers by points: if/else 5 (11 pts), loops 3 (4 pts), boolean chains 1 (nesting depth added 7). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/layout.rs"},"region":{"startLine":1964}}}],"partialFingerprints":{"codehealthFindingId/v1":"f9b6ed4de96890b234b9f9f0e5c9f07a0800da254add83833d4033ad75789a52"}},{"ruleId":"D2","level":"warning","message":{"text":"ludusavi::scan::launchers::faugus::scan_spec (cognitive 16): ludusavi::scan::launchers::faugus::scan_spec has cognitive complexity 16 (threshold 15). Drivers by points: if/else 6 (11 pts), match/switch 2 (4 pts), loops 1 (nesting depth added 7). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/launchers/faugus.rs"},"region":{"startLine":87}}}],"partialFingerprints":{"codehealthFindingId/v1":"926e8b4607b67283b2cee8c13d60fb5db2361f921462c64b31e6358cd231c250"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: App.update: MethodTooLong \u2014 update runs 1066 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted) in one body. The bar is 100 significant lines; this is 966 over it, 10.66\u00D7 the bar. This is length, not branching: a long straight-line body scores low on complexity and is still read whole to change any part of it, so the complexity numbers beside this row neither confirm nor excuse it. To reduce it, extract each cohesive step of the body \u2014 the runs of statements that work on the same values and would earn the same name \u2014 into its own named unit, and have this one call them in order."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":1491}}}],"partialFingerprints":{"codehealthFindingId/v1":"991bfa10199aad424368cf3ce20cf96a9f8e4fdbd902dbe9d1d4dece34ab377c"}},{"ruleId":"D3","level":"warning","message":{"text":"FunctionTooLong: ludusavi::cli::run: FunctionTooLong \u2014 ludusavi::cli::run runs 888 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted) in one body. The bar is 100 significant lines; this is 788 over it, 8.88\u00D7 the bar. This is length, not branching: a long straight-line body scores low on complexity and is still read whole to change any part of it, so the complexity numbers beside this row neither confirm nor excuse it. To reduce it, extract each cohesive step of the body \u2014 the runs of statements that work on the same values and would earn the same name \u2014 into its own named unit, and have this one call them in order."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/cli.rs"},"region":{"startLine":142}}}],"partialFingerprints":{"codehealthFindingId/v1":"62b9f13a330519abaa2d67ed0014ea94838b1de103933c6df148ee3db134c390"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: Translator: TooManyMethods \u2014 198 methods. The bar is 30 methods; this is 168 over it, 6.60\u00D7 the bar. To reduce it, group the members that share the same data into a smaller type of their own and delegate to it, so no single type carries every responsibility."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/lang.rs"},"region":{"startLine":255}}}],"partialFingerprints":{"codehealthFindingId/v1":"3092766a42a7abc877badb1e21094b2e8e98ca63a739c7e08c2dd023b31358c4"}},{"ruleId":"D3","level":"warning","message":{"text":"ClassTooLong: App: ClassTooLong \u2014 2100 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted), 38 methods, 2 blocks, lines 91-3091. The bar is 400 significant lines; this is 1700 over it, 5.25\u00D7 the bar. To reduce it, group the members that share the same data into a smaller type of their own and delegate to it, so no single type carries every responsibility."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":91}}}],"partialFingerprints":{"codehealthFindingId/v1":"b3f3c5977727330a5faf68058e4ceaf2d05250aff21de5b7dd140b648123fe59"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: gui/app.rs: FileTooLong \u2014 2160 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted), about 97% of them inside a single declaration: App (2 blocks, 91-3091). The bar is 500 significant lines; this is 1660 over it, 4.32\u00D7 the bar. Moving the declarations that sit BESIDE it into sibling files will not shorten this file. Extract from INSIDE that declaration instead: lift each cohesive group of its body \u2014 the parts that share the same inputs and are named together \u2014 into its own unit in a sibling file, and have the original call them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"f14cf2ab21e38ed1becb1a0867fa089ba504ca148f52fcede69845368e83574b"}},{"ruleId":"D3","level":"warning","message":{"text":"FunctionTooLong: ludusavi::gui::screen::other: FunctionTooLong \u2014 ludusavi::gui::screen::other runs 321 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted) in one body. The bar is 100 significant lines; this is 221 over it, 3.21\u00D7 the bar. This is length, not branching: a long straight-line body scores low on complexity and is still read whole to change any part of it, so the complexity numbers beside this row neither confirm nor excuse it. To reduce it, extract each cohesive step of the body \u2014 the runs of statements that work on the same values and would earn the same name \u2014 into its own named unit, and have this one call them in order."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/screen.rs"},"region":{"startLine":304}}}],"partialFingerprints":{"codehealthFindingId/v1":"d3a573c398688522b525d55b37adf330c1aed171739a8cce0465b8baffdb1f47"}},{"ruleId":"D3","level":"warning","message":{"text":"FunctionTooLong: ludusavi::scan::scan_game_for_backup: FunctionTooLong \u2014 ludusavi::scan::scan_game_for_backup runs 313 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted) in one body. The bar is 100 significant lines; this is 213 over it, 3.13\u00D7 the bar. This is length, not branching: a long straight-line body scores low on complexity and is still read whole to change any part of it, so the complexity numbers beside this row neither confirm nor excuse it. To reduce it, extract each cohesive step of the body \u2014 the runs of statements that work on the same values and would earn the same name \u2014 into its own named unit, and have this one call them in order."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan.rs"},"region":{"startLine":544}}}],"partialFingerprints":{"codehealthFindingId/v1":"44af24f66a927f32b8c7fdf35a01c3131a8760f9f5550c8474c113285cdc9378"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: App.handle_backup: MethodTooLong \u2014 handle_backup runs 307 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted) in one body. The bar is 100 significant lines; this is 207 over it, 3.07\u00D7 the bar. This is length, not branching: a long straight-line body scores low on complexity and is still read whole to change any part of it, so the complexity numbers beside this row neither confirm nor excuse it. To reduce it, extract each cohesive step of the body \u2014 the runs of statements that work on the same values and would earn the same name \u2014 into its own named unit, and have this one call them in order."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":296}}}],"partialFingerprints":{"codehealthFindingId/v1":"a536b35791e73193b2d9fba2cf07fccf7d1b39b814c228ee5beadd32e4024545"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: scan/layout.rs: FileTooLong \u2014 1527 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted), about 72% of them inside a single declaration: GameLayout (2 blocks, 560-2190). The bar is 500 significant lines; this is 1027 over it, 3.05\u00D7 the bar. Moving the declarations that sit BESIDE it into sibling files will not shorten this file. Extract from INSIDE that declaration instead: lift each cohesive group of its body \u2014 the parts that share the same inputs and are named together \u2014 into its own unit in a sibling file, and have the original call them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/layout.rs"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"27a37f61bd52e54bef273354ebcc4b6e15b4e18a331cfb759e9f21a186a944cd"}},{"ruleId":"D3","level":"warning","message":{"text":"FunctionTooLong: ludusavi::scan::parse_paths: FunctionTooLong \u2014 ludusavi::scan::parse_paths runs 299 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted) in one body. The bar is 100 significant lines; this is 199 over it, 2.99\u00D7 the bar. This is length, not branching: a long straight-line body scores low on complexity and is still read whole to change any part of it, so the complexity numbers beside this row neither confirm nor excuse it. To reduce it, extract each cohesive step of the body \u2014 the runs of statements that work on the same values and would earn the same name \u2014 into its own named unit, and have this one call them in order."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan.rs"},"region":{"startLine":139}}}],"partialFingerprints":{"codehealthFindingId/v1":"2045e2bf4a79a2a91b60d8f61486846d4779f572b7124b08ba85690df3fa99cc"}},{"ruleId":"D3","level":"warning","message":{"text":"ClassTooLong: GameLayout: ClassTooLong \u2014 1093 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted), 44 methods, 2 blocks, lines 560-2190. The bar is 400 significant lines; this is 693 over it, 2.73\u00D7 the bar. To reduce it, group the members that share the same data into a smaller type of their own and delegate to it, so no single type carries every responsibility."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/layout.rs"},"region":{"startLine":560}}}],"partialFingerprints":{"codehealthFindingId/v1":"e70632df358b2e4a1529acf908c9dbd00c6688052746b6d1d537f34f8b882a09"}},{"ruleId":"D3","level":"warning","message":{"text":"FunctionTooLong: ludusavi::gui::editor::custom_games: FunctionTooLong \u2014 ludusavi::gui::editor::custom_games runs 273 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted) in one body. The bar is 100 significant lines; this is 173 over it, 2.73\u00D7 the bar. This is length, not branching: a long straight-line body scores low on complexity and is still read whole to change any part of it, so the complexity numbers beside this row neither confirm nor excuse it. To reduce it, extract each cohesive step of the body \u2014 the runs of statements that work on the same values and would earn the same name \u2014 into its own named unit, and have this one call them in order."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/editor.rs"},"region":{"startLine":272}}}],"partialFingerprints":{"codehealthFindingId/v1":"5112975b94a1331995b7e51e9c1b36cc72bb42bb86b0816d1abfd730b3a1b392"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: resource/config.rs: FileTooLong \u2014 1349 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted). The bar is 500 significant lines; this is 849 over it, 2.70\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/resource/config.rs"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"a932731a4f6a4a708efb691f34db74c2926af96812e229cbe6b27560386b1178"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: GameListEntry.view: MethodTooLong \u2014 view runs 248 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted) in one body. The bar is 100 significant lines; this is 148 over it, 2.48\u00D7 the bar. This is length, not branching: a long straight-line body scores low on complexity and is still read whole to change any part of it, so the complexity numbers beside this row neither confirm nor excuse it. To reduce it, extract each cohesive step of the body \u2014 the runs of statements that work on the same values and would earn the same name \u2014 into its own named unit, and have this one call them in order."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/game_list.rs"},"region":{"startLine":49}}}],"partialFingerprints":{"codehealthFindingId/v1":"ed744b2f5970f9f0ae8784cb2dd05dd02700b88968cc07481fd6e8a820e72400"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: StrictPath: TooManyMethods \u2014 69 methods. The bar is 30 methods; this is 39 over it, 2.30\u00D7 the bar. To reduce it, group the members that share the same data into a smaller type of their own and delegate to it, so no single type carries every responsibility."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/path.rs"},"region":{"startLine":185}}}],"partialFingerprints":{"codehealthFindingId/v1":"1e5ce973c1f75b0afedfefc2049de3fb0a2fd82e38fcb802e09ee22663295f54"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: src/cli.rs: FileTooLong \u2014 1062 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted). The bar is 500 significant lines; this is 562 over it, 2.12\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/cli.rs"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"e6f109f4ba98439ac843f4ce5c70fd5c8c5a6f795cac2fdf369f601e1a346deb"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: App.handle_restore: MethodTooLong \u2014 handle_restore runs 209 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted) in one body. The bar is 100 significant lines; this is 109 over it, 2.09\u00D7 the bar. This is length, not branching: a long straight-line body scores low on complexity and is still read whole to change any part of it, so the complexity numbers beside this row neither confirm nor excuse it. To reduce it, extract each cohesive step of the body \u2014 the runs of statements that work on the same values and would earn the same name \u2014 into its own named unit, and have this one call them in order."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":731}}}],"partialFingerprints":{"codehealthFindingId/v1":"70dbecc9dd3122069d1ba25c0b8f8ed684cbdc18f81dcf68ddff566b97365218"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: src/lang.rs: FileTooLong \u2014 953 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted), about 73% of them inside a single declaration: Translator (2 blocks, 255-1501). The bar is 500 significant lines; this is 453 over it, 1.91\u00D7 the bar. Moving the declarations that sit BESIDE it into sibling files will not shorten this file. Extract from INSIDE that declaration instead: lift each cohesive group of its body \u2014 the parts that share the same inputs and are named together \u2014 into its own unit in a sibling file, and have the original call them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/lang.rs"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"a015601f14e17c432199c07ee549adf5ec96f92a97b08367416d4db5c17e1285"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: TextHistories.input: MethodTooLong \u2014 input runs 183 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted) in one body. The bar is 100 significant lines; this is 83 over it, 1.83\u00D7 the bar. This is length, not branching: a long straight-line body scores low on complexity and is still read whole to change any part of it, so the complexity numbers beside this row neither confirm nor excuse it. To reduce it, extract each cohesive step of the body \u2014 the runs of statements that work on the same values and would earn the same name \u2014 into its own named unit, and have this one call them in order."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/shortcuts.rs"},"region":{"startLine":316}}}],"partialFingerprints":{"codehealthFindingId/v1":"842365e07b9e9df8d2c55b6111384cac777e97937b98e99806314ee350efe6aa"}},{"ruleId":"D3","level":"warning","message":{"text":"ClassTooLong: Translator: ClassTooLong \u2014 691 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted), 198 methods, 2 blocks, lines 255-1501. The bar is 400 significant lines; this is 291 over it, 1.73\u00D7 the bar. To reduce it, group the members that share the same data into a smaller type of their own and delegate to it, so no single type carries every responsibility."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/lang.rs"},"region":{"startLine":255}}}],"partialFingerprints":{"codehealthFindingId/v1":"5e5326ae6db9d598dcd0537a90b7db139659d7e776316058e324e10d400e01e9"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: Reporter.add_game: MethodTooLong \u2014 add_game runs 170 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted) in one body. The bar is 100 significant lines; this is 70 over it, 1.70\u00D7 the bar. This is length, not branching: a long straight-line body scores low on complexity and is still read whole to change any part of it, so the complexity numbers beside this row neither confirm nor excuse it. To reduce it, extract each cohesive step of the body \u2014 the runs of statements that work on the same values and would earn the same name \u2014 into its own named unit, and have this one call them in order."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/report.rs"},"region":{"startLine":311}}}],"partialFingerprints":{"codehealthFindingId/v1":"f45f10a117946b116782f438e4e068f5ac1653335889f3775417816ca517fd98"}},{"ruleId":"D3","level":"warning","message":{"text":"ClassTooLong: StrictPath: ClassTooLong \u2014 670 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted), 69 methods, 18 blocks, lines 185-1295. The bar is 400 significant lines; this is 270 over it, 1.68\u00D7 the bar. To reduce it, group the members that share the same data into a smaller type of their own and delegate to it, so no single type carries every responsibility."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/path.rs"},"region":{"startLine":185}}}],"partialFingerprints":{"codehealthFindingId/v1":"7852c2d59ab28dc684bce9f63c2cddb8d380d21f7edb0b8436156bee6f473f5b"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: src/path.rs: FileTooLong \u2014 808 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted), about 83% of them inside a single declaration: StrictPath (18 blocks, 185-1295). The bar is 500 significant lines; this is 308 over it, 1.62\u00D7 the bar. Moving the declarations that sit BESIDE it into sibling files will not shorten this file. Extract from INSIDE that declaration instead: lift each cohesive group of its body \u2014 the parts that share the same inputs and are named together \u2014 into its own unit in a sibling file, and have the original call them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/path.rs"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"d0728d1698ee1c8d0facb5aec532dcc7dcef585045741ab74c215f4b7e98988e"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: FileTreeNode.view: MethodTooLong \u2014 view runs 160 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted) in one body. The bar is 100 significant lines; this is 60 over it, 1.60\u00D7 the bar. This is length, not branching: a long straight-line body scores low on complexity and is still read whole to change any part of it, so the complexity numbers beside this row neither confirm nor excuse it. To reduce it, extract each cohesive step of the body \u2014 the runs of statements that work on the same values and would earn the same name \u2014 into its own named unit, and have this one call them in order."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/file_tree.rs"},"region":{"startLine":103}}}],"partialFingerprints":{"codehealthFindingId/v1":"b02f9fded73ecbd660a90468ece182070b7efa319cb9b7afdc6e67c39d095bdc"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: src/scan.rs: FileTooLong \u2014 793 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted). The bar is 500 significant lines; this is 293 over it, 1.59\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan.rs"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"d9470bdffb416d2bf13d5fbd17d563a5dd0c241c89d52947b3eab2c3921f6183"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyFunctions: ludusavi::gui::button: TooManyFunctions \u2014 44 free functions. The bar is 30 free functions; this is 14 over it, 1.47\u00D7 the bar. To reduce it, group the members that share the same data into a smaller type of their own and delegate to it, so no single type carries every responsibility."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/button.rs"},"region":{"startLine":20}}}],"partialFingerprints":{"codehealthFindingId/v1":"42ef9751fc676cfa490d662034acd753da44e644a552fd6d55bbc2a5b8c59e94"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: GameLayout: TooManyMethods \u2014 44 methods. The bar is 30 methods; this is 14 over it, 1.47\u00D7 the bar. To reduce it, group the members that share the same data into a smaller type of their own and delegate to it, so no single type carries every responsibility."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/layout.rs"},"region":{"startLine":560}}}],"partialFingerprints":{"codehealthFindingId/v1":"403c8211487e49785c4400e2ea24b5abc75fd84ae3ffe922b72ec0143fc5876e"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: gui/common.rs: FileTooLong \u2014 689 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted). The bar is 500 significant lines; this is 189 over it, 1.38\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/common.rs"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"582d166aacbbe98c3f18e9e7675b501f0af152e357bd00a17b801232d5e1912a"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: gui/game_list.rs: FileTooLong \u2014 681 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted). The bar is 500 significant lines; this is 181 over it, 1.36\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/game_list.rs"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"686e8ebb847204d8b4c538e37608662099ed3c5aed1ae2c8d0296efd083a076c"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: resource/manifest.rs: FileTooLong \u2014 678 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted). The bar is 500 significant lines; this is 178 over it, 1.36\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/resource/manifest.rs"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"dc3b6d02a691b4b6f197aa589f11e56efbbe6292411cf45d31eaed8361b215f5"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: App: TooManyMethods \u2014 38 methods. The bar is 30 methods; this is 8 over it, 1.27\u00D7 the bar. To reduce it, group the members that share the same data into a smaller type of their own and delegate to it, so no single type carries every responsibility."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":91}}}],"partialFingerprints":{"codehealthFindingId/v1":"3bbcd32e3f9aee485cbcd67a9dfe174d3f15bde4ab6eaf87c284a8209f284e67"}},{"ruleId":"D3","level":"warning","message":{"text":"ClassTooLong: Modal: ClassTooLong \u2014 502 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted), 14 methods, 2 blocks, lines 139-782. The bar is 400 significant lines; this is 102 over it, 1.26\u00D7 the bar. To reduce it, group the members that share the same data into a smaller type of their own and delegate to it, so no single type carries every responsibility."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/modal.rs"},"region":{"startLine":139}}}],"partialFingerprints":{"codehealthFindingId/v1":"064670b4a0196af0d2c2f3e13c3248db4cd5c8eb46c9b87f2dd4b085ae199551"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: gui/modal.rs: FileTooLong \u2014 605 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted), about 83% of them inside a single declaration: Modal (2 blocks, 139-782). The bar is 500 significant lines; this is 105 over it, 1.21\u00D7 the bar. Moving the declarations that sit BESIDE it into sibling files will not shorten this file. Extract from INSIDE that declaration instead: lift each cohesive group of its body \u2014 the parts that share the same inputs and are named together \u2014 into its own unit in a sibling file, and have the original call them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/modal.rs"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"01fd6816627e56d3cec1ff25361547ad6fceb32401076e477c0992cd93d2b05b"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: src/cloud.rs: FileTooLong \u2014 578 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted). The bar is 500 significant lines; this is 78 over it, 1.16\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/cloud.rs"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"49dd54f3d9069e5acf60b5f8fd82b007a8465927214f7eed53c02526ee9fd7c4"}},{"ruleId":"D3","level":"warning","message":{"text":"ClassTooLong: Theme: ClassTooLong \u2014 448 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted), 0 methods, 14 blocks, lines 25-723. The bar is 400 significant lines; this is 48 over it, 1.12\u00D7 the bar. To reduce it, group the members that share the same data into a smaller type of their own and delegate to it, so no single type carries every responsibility."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/style.rs"},"region":{"startLine":25}}}],"partialFingerprints":{"codehealthFindingId/v1":"88e791befd56985de8f5fef398b75c8d1634830a38e72eb88fb28b227d5c3f7b"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: Config.find_missing_roots: MethodTooLong \u2014 find_missing_roots runs 111 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted) in one body. The bar is 100 significant lines; this is 11 over it, 1.11\u00D7 the bar. This is length, not branching: a long straight-line body scores low on complexity and is still read whole to change any part of it, so the complexity numbers beside this row neither confirm nor excuse it. To reduce it, extract each cohesive step of the body \u2014 the runs of statements that work on the same values and would earn the same name \u2014 into its own named unit, and have this one call them in order."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/resource/config.rs"},"region":{"startLine":1444}}}],"partialFingerprints":{"codehealthFindingId/v1":"89236493258b5e36ac21a73629ee78fa2a74716f3ad6d48a8d0c6ea1bdb02c97"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: gui/screen.rs: FileTooLong \u2014 554 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted). The bar is 500 significant lines; this is 54 over it, 1.11\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/screen.rs"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"9525fa7fa87ed68fd748a352eea18bc8774859a634f6ccb93f54abb76986dc8b"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: gui/editor.rs: FileTooLong \u2014 542 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted). The bar is 500 significant lines; this is 42 over it, 1.08\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/editor.rs"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"2f953896488c93572d330f95bf8c7833f48d04c924a943017988edf220d45c80"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: TitleFinder.find: MethodTooLong \u2014 find runs 106 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted) in one body. The bar is 100 significant lines; this is 6 over it, 1.06\u00D7 the bar. This is length, not branching: a long straight-line body scores low on complexity and is still read whole to change any part of it, so the complexity numbers beside this row neither confirm nor excuse it. To reduce it, extract each cohesive step of the body \u2014 the runs of statements that work on the same values and would earn the same name \u2014 into its own named unit, and have this one call them in order."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/title.rs"},"region":{"startLine":169}}}],"partialFingerprints":{"codehealthFindingId/v1":"46325388430fe04d29033d2062b31d83ff277604e7710538866d5410e963d6d1"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: gui/style.rs: FileTooLong \u2014 516 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted), about 87% of them inside a single declaration: Theme (14 blocks, 25-723). The bar is 500 significant lines; this is 16 over it, 1.03\u00D7 the bar. Moving the declarations that sit BESIDE it into sibling files will not shorten this file. Extract from INSIDE that declaration instead: lift each cohesive group of its body \u2014 the parts that share the same inputs and are named together \u2014 into its own unit in a sibling file, and have the original call them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/style.rs"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"103bf4bf3e66cf3b1ccd6a5e8bf88dbcda725d05398c9d6ed39c8e9436c288c4"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: GameLayout.execute_backup_as_zip: MethodTooLong \u2014 execute_backup_as_zip runs 103 significant lines (blank, comment-only and punctuation-only lines excluded, and inline test code \u2014 #[cfg(test)] modules and bare #[test] functions \u2014 not counted) in one body. The bar is 100 significant lines; this is 3 over it, 1.03\u00D7 the bar. This is length, not branching: a long straight-line body scores low on complexity and is still read whole to change any part of it, so the complexity numbers beside this row neither confirm nor excuse it. To reduce it, extract each cohesive step of the body \u2014 the runs of statements that work on the same values and would earn the same name \u2014 into its own named unit, and have this one call them in order."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/layout.rs"},"region":{"startLine":1258}}}],"partialFingerprints":{"codehealthFindingId/v1":"31d35415646925ec9a7b9edb732d8792057576d70ac99bdb26273acf6f033a44"}},{"ruleId":"D4","level":"warning","message":{"text":"Members sharing a duplicated core (5 members, 50\u002B identical tokens): src/gui/modal.rs:608-630 | src/gui/modal.rs:632-669 | src/gui/modal.rs:671-692 | src/gui/modal.rs:694-713 | src/gui/modal.rs:715-734 \u2014 These 5 members share a duplicated core: a run of at least 50 identical tokens appears in every one of them. That run is NOT broken out as duplicated-block rows below \u2014 it is what admitted this row, and the blocks below cover only the part of it that clears the block floor, so they understate the correspondence. Read the members as one construct written 5 times. The repair is at the members\u0027 grain \u2014 factor the shared implementation out once and have all of them call it with their differences as parameters or as an injected step, or, where the difference is systematic, generate them from one template. Extracting the individual blocks below is not the same fix: it leaves every body in place and the next edit still has to be made 5 times."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/modal.rs"},"region":{"startLine":608}}}],"partialFingerprints":{"codehealthFindingId/v1":"a310163e4ef248347ab2a9c652ddb4d2d6021b2d5961e1cfcde56cf357bfe3d1"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (49 lines \u00D7 2): src/scan/layout.rs:764-812 | src/scan/layout.rs:841-889 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/layout.rs"},"region":{"startLine":764}}}],"partialFingerprints":{"codehealthFindingId/v1":"4f65df511bdcbf12f6851518008a3785d786a40fdf2b48a6ebbe7a05347b33f9"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (21 lines \u00D7 2): src/api.rs:173-193 | src/cli.rs:265-285 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/api.rs"},"region":{"startLine":173}}}],"partialFingerprints":{"codehealthFindingId/v1":"c531bf5598d4cbb7897a57b81e14a0d8c7c625059fad8f35fa3f19c611f7ddd9"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (19\u201321 lines \u00D7 2): src/scan.rs:754-772 | src/scan.rs:803-823 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan.rs"},"region":{"startLine":754}}}],"partialFingerprints":{"codehealthFindingId/v1":"22358f42e4e7e36cf3048876795263e0ff457ebbc2fb26aa01d3787c084b1b13"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (21 lines \u00D7 2): src/cli.rs:427-447 | src/cli.rs:657-677 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/cli.rs"},"region":{"startLine":427}}}],"partialFingerprints":{"codehealthFindingId/v1":"3eaea7df2aac9ca6151db74a51546e76096075996902e85f0d43cac8b1c3aac2"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (19 lines \u00D7 2): src/api.rs:602-620 | src/cli.rs:112-130 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/api.rs"},"region":{"startLine":602}}}],"partialFingerprints":{"codehealthFindingId/v1":"07becd15388c9fb6606a79f9ce698d90d0c65918264180952082f5d7fbd175c2"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (18 lines \u00D7 2): src/scan/layout.rs:2110-2127 | src/scan/layout.rs:2150-2167 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/layout.rs"},"region":{"startLine":2110}}}],"partialFingerprints":{"codehealthFindingId/v1":"cbef3d5fa2509d6075f43bcb8d91f2e36e80899c4dcebcdd5c16a7d3e90e697e"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (18 lines \u00D7 2): src/gui/button.rs:267-284 | src/gui/button.rs:287-304 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/button.rs"},"region":{"startLine":267}}}],"partialFingerprints":{"codehealthFindingId/v1":"fbbbafe9e9884bb7398289267c97db85c7832a0dce4d606a6fa5b54d1e73be36"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (18 lines \u00D7 2): src/cli.rs:161-178 | src/cli.rs:464-481 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/cli.rs"},"region":{"startLine":161}}}],"partialFingerprints":{"codehealthFindingId/v1":"ac67aedc576ecb3735c559094857cb60159ee89439fde5bb4c1112bc08450985"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (17 lines \u00D7 3): src/gui/modal.rs:614-630 | src/gui/modal.rs:653-669 | src/gui/modal.rs:676-692 \u2014 all 3 copies are in the same file, so extract the block into one function there and call it from every one of those sites \u2014 resolving only two of them leaves the rest to drift apart the first time one is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/modal.rs"},"region":{"startLine":614}}}],"partialFingerprints":{"codehealthFindingId/v1":"914fa8d25a7c94a887cb0c95eca4fb952834c5432044b76e43e1622682a44b9c"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (16\u201317 lines \u00D7 2): src/gui/app.rs:616-632 | src/gui/app.rs:971-986 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":616}}}],"partialFingerprints":{"codehealthFindingId/v1":"814259b89a2ce59a923e1916f29e38ed056b62184e1e7c18d1efaea6798f5d91"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (17 lines \u00D7 2): src/cli.rs:995-1011 | src/cli.rs:1039-1055 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/cli.rs"},"region":{"startLine":995}}}],"partialFingerprints":{"codehealthFindingId/v1":"e5db5cf38c273b7860897175a064389d5144797954ebcbfb7629437edfb8c75b"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (16 lines \u00D7 2): src/gui/screen.rs:133-148 | src/gui/screen.rs:223-238 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/screen.rs"},"region":{"startLine":133}}}],"partialFingerprints":{"codehealthFindingId/v1":"87fbb95df7768ccbdeccd5fff801512d1ace7f1fef21c43a972088a30f25cf49"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (13\u201315 lines \u00D7 2): src/gui/app.rs:570-582 | src/gui/app.rs:921-935 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":570}}}],"partialFingerprints":{"codehealthFindingId/v1":"d09fd0d43cf59b928bd9a3517eb96b9c8d4aeb6a855605c9b4fbec9091025254"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (15 lines \u00D7 2): src/gui/style.rs:428-442 | src/gui/style.rs:444-458 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/style.rs"},"region":{"startLine":428}}}],"partialFingerprints":{"codehealthFindingId/v1":"4bea36493afc44ef51a09c660aecc78aeb628715be4ece15ac646c26a103badc"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (15 lines \u00D7 2): src/path.rs:1041-1055 | src/path.rs:1073-1087 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/path.rs"},"region":{"startLine":1041}}}],"partialFingerprints":{"codehealthFindingId/v1":"beae50b68fb4063a510977fd17e0b96315d36d085024454552df2f0e86b874a0"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (15 lines \u00D7 2): src/scan/launchers/heroic/nile.rs:47-61 | src/scan/launchers/heroic/sideload.rs:47-61 \u2014 before extracting anything, compare \u0060src/scan/launchers/heroic/nile.rs\u0060 and \u0060src/scan/launchers/heroic/sideload.rs\u0060 as WHOLE FILES: this scan already matched 3 separate duplicated blocks between them, totalling at least 36 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/launchers/heroic/nile.rs"},"region":{"startLine":47}}}],"partialFingerprints":{"codehealthFindingId/v1":"686f15a68962023002ecef9446bceb5a185402848f60adc67bcb29fc3ee4551e"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (13\u201315 lines \u00D7 2): src/scan.rs:774-786 | src/scan.rs:825-839 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan.rs"},"region":{"startLine":774}}}],"partialFingerprints":{"codehealthFindingId/v1":"950b2854ebe6246027f1dda3b5784e8f1288bed62f52a6867fce4a030b874c29"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14 lines \u00D7 5): src/gui/modal.rs:614-627 | src/gui/modal.rs:653-666 | src/gui/modal.rs:676-689 | src/gui/modal.rs:697-710 | src/gui/modal.rs:718-731 \u2014 all 5 copies are in the same file, so extract the block into one function there and call it from every one of those sites \u2014 resolving only two of them leaves the rest to drift apart the first time one is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/modal.rs"},"region":{"startLine":614}}}],"partialFingerprints":{"codehealthFindingId/v1":"dda2bd6e98245db4c2aa28daba14e0d6c5f27019fb79bedb04d15c3854953f1e"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14 lines \u00D7 3): src/scan.rs:217-230 | src/scan.rs:242-255 | src/scan.rs:262-275 \u2014 all 3 copies are in the same file, so extract the block into one function there and call it from every one of those sites \u2014 resolving only two of them leaves the rest to drift apart the first time one is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan.rs"},"region":{"startLine":217}}}],"partialFingerprints":{"codehealthFindingId/v1":"1754dda3d405a5408f618a34af245850ded5d8d29aa557356666c90778b704da"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14 lines \u00D7 2): src/gui/app.rs:688-701 | src/gui/app.rs:1017-1030 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":688}}}],"partialFingerprints":{"codehealthFindingId/v1":"5715be690d63ba6d64159429c7b1ea305f4e2074c9cad1bddee5ba988ad44e51"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14 lines \u00D7 2): src/scan/launchers/faugus.rs:45-58 | src/scan/launchers/heroic.rs:71-84 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/launchers/faugus.rs"},"region":{"startLine":45}}}],"partialFingerprints":{"codehealthFindingId/v1":"d828073c3c6d60c8d5e9d7f161233955422036647425c602f34b08ea8fa22fdb"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11\u201313 lines \u00D7 2): src/scan/layout.rs:187-199 | src/scan/layout.rs:204-214 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/layout.rs"},"region":{"startLine":187}}}],"partialFingerprints":{"codehealthFindingId/v1":"83588dd42dac0719405e3cf6f27c5dd9cb6d287e88a34cb25141d71e308709c6"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (13 lines \u00D7 2): src/scan/layout.rs:814-826 | src/scan/layout.rs:891-903 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/layout.rs"},"region":{"startLine":814}}}],"partialFingerprints":{"codehealthFindingId/v1":"d550ec1db8c5a4aba5b3624b57b140b36b484e6c5c8a5838b4673220e6820dea"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (13 lines \u00D7 2): src/cli.rs:232-244 | src/cli.rs:525-537 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/cli.rs"},"region":{"startLine":232}}}],"partialFingerprints":{"codehealthFindingId/v1":"6c72cf873a1073dd623e4a8fc5c65aab4a75d2fee3f6b16d27ab6e1bc2470120"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 3): src/gui/app.rs:557-568 | src/gui/app.rs:905-916 | src/gui/app.rs:1113-1124 \u2014 all 3 copies are in the same file, so extract the block into one function there and call it from every one of those sites \u2014 resolving only two of them leaves the rest to drift apart the first time one is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":557}}}],"partialFingerprints":{"codehealthFindingId/v1":"8e026ad362d92f9451d6bc2e94bf468b4e5a6cb01a7ef40bd5d85191980ab952"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 2): src/cli/parse.rs:569-580 | src/cli/parse.rs:586-597 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/cli/parse.rs"},"region":{"startLine":569}}}],"partialFingerprints":{"codehealthFindingId/v1":"1c2bb6fc08e78716f913f8fa16fee552a88168367de16ba46bd1309638a97de8"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10\u201312 lines \u00D7 2): src/gui/search.rs:233-244 | src/gui/search.rs:283-292 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/search.rs"},"region":{"startLine":233}}}],"partialFingerprints":{"codehealthFindingId/v1":"17d56af8511b52690e1e4a29a2be700e7870d8613129235511eb9880ed07fd83"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11\u201312 lines \u00D7 2): src/path.rs:404-415 | src/path.rs:1252-1262 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/path.rs"},"region":{"startLine":404}}}],"partialFingerprints":{"codehealthFindingId/v1":"e886fdc9dd41e7a984dd269f0a5466b4e559f4b657b8d57b5291cf5965bb42e1"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 2): src/scan/launchers/heroic/legendary.rs:108-122 | src/scan/launchers/heroic/nile.rs:80-91 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/launchers/heroic/legendary.rs"},"region":{"startLine":108}}}],"partialFingerprints":{"codehealthFindingId/v1":"537e3331e814d1798a428ea8054b30098d502d5ecf34929aef60a32dd429f30a"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 2): src/main.rs:29-40 | src/main.rs:51-63 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/main.rs"},"region":{"startLine":29}}}],"partialFingerprints":{"codehealthFindingId/v1":"aa43dde5c9c76913c54860969a01fd550823129adeaa59db72636f45c08efd7d"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 2): src/cli.rs:388-399 | src/cli.rs:636-647 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/cli.rs"},"region":{"startLine":388}}}],"partialFingerprints":{"codehealthFindingId/v1":"a01123043c32f5e3fc453938abb5c9a56bc608cc3c18e031fe367c3d4fc2f059"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 2): src/cli.rs:977-988 | src/cli.rs:1021-1032 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/cli.rs"},"region":{"startLine":977}}}],"partialFingerprints":{"codehealthFindingId/v1":"a4049936bc977e3226cba28c0ed637af5aba40e9b273d731c5c93fac53630c68"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10\u201311 lines \u00D7 2): src/gui/app.rs:463-472 | src/gui/app.rs:847-857 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":463}}}],"partialFingerprints":{"codehealthFindingId/v1":"229154938c07b1a9bb3cdf65dddad1c32e3128a6f7151ffa6e2007f84e128c78"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 2): src/metadata.rs:27-37 | src/metadata.rs:54-64 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/metadata.rs"},"region":{"startLine":27}}}],"partialFingerprints":{"codehealthFindingId/v1":"cace1c778d751e4f6cca507d633f4d033f91f1f541bea4df32022cb65ed6607b"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 2): src/scan/duplicate.rs:330-340 | src/scan/duplicate.rs:342-352 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/duplicate.rs"},"region":{"startLine":330}}}],"partialFingerprints":{"codehealthFindingId/v1":"4f96b0d141a04e3f0722454a8b941f611c785a0f2cd36551a23ab92fd1313802"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 2): src/gui/app.rs:1233-1242 | src/gui/app.rs:1258-1267 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":1233}}}],"partialFingerprints":{"codehealthFindingId/v1":"0f4c1cbe1718b5d24a5f53a5dd101f328ccad511c4ffacbb3842417755a62f4e"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 2): src/scan/layout.rs:2130-2139 | src/scan/layout.rs:2175-2184 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/layout.rs"},"region":{"startLine":2130}}}],"partialFingerprints":{"codehealthFindingId/v1":"c21d40bc5f064b4239e6dcb097b8908386d602ea6d7afa4784d8b449552a2563"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 2): src/gui/editor.rs:110-119 | src/gui/editor.rs:122-131 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/editor.rs"},"region":{"startLine":110}}}],"partialFingerprints":{"codehealthFindingId/v1":"ff541c5dcfe2bcada58301926a74b75182227647c136f2f33aa8d56ef4af1f70"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): src/gui/app.rs:361-369 | src/gui/app.rs:786-794 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":361}}}],"partialFingerprints":{"codehealthFindingId/v1":"54bf4da65ee302dbd0acb2c873c6d0a2abad3ef1c2666c4606d76c2bb14c73e0"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): src/gui/app.rs:802-810 | src/gui/app.rs:1061-1069 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":802}}}],"partialFingerprints":{"codehealthFindingId/v1":"377d4b1c3297d951a0bee0f4b5e74d84c2bda769e71db5db824ee07ec632efcf"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 3): src/gui/app.rs:2731-2739 | src/gui/app.rs:2745-2753 | src/gui/app.rs:2758-2766 \u2014 all 3 copies are in the same file, so extract the block into one function there and call it from every one of those sites \u2014 resolving only two of them leaves the rest to drift apart the first time one is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":2731}}}],"partialFingerprints":{"codehealthFindingId/v1":"dad7a764c0b0ea19de06d2f01825b08bd5fb670b4b48d235a0b69479f3fcafff"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): src/gui/icon.rs:89-97 | src/gui/icon.rs:104-112 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/icon.rs"},"region":{"startLine":89}}}],"partialFingerprints":{"codehealthFindingId/v1":"137941dc94fcf6a2428e696bbc18492de18c4070b71f263ff914fe860f17b472"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): src/resource/config.rs:1935-1943 | src/resource/config.rs:2010-2018 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/resource/config.rs"},"region":{"startLine":1935}}}],"partialFingerprints":{"codehealthFindingId/v1":"2ab686da2e482afa87371712eb1eea35434d01dd52af942390bf8ed48ba444f4"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): src/scan/duplicate.rs:184-192 | src/scan/duplicate.rs:194-202 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/duplicate.rs"},"region":{"startLine":184}}}],"partialFingerprints":{"codehealthFindingId/v1":"2378f815a67410fa3508817de8698eacde4cd94f5c30de34ad1419445af4c47d"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): src/scan/launchers/heroic/nile.rs:37-45 | src/scan/launchers/heroic/sideload.rs:37-45 \u2014 before extracting anything, compare \u0060src/scan/launchers/heroic/nile.rs\u0060 and \u0060src/scan/launchers/heroic/sideload.rs\u0060 as WHOLE FILES: this scan already matched 3 separate duplicated blocks between them, totalling at least 36 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/launchers/heroic/nile.rs"},"region":{"startLine":37}}}],"partialFingerprints":{"codehealthFindingId/v1":"4e8a9b3d26f1048c5f03090298dbe5667ae96c0e0dc3e120d92945a5bd3a3db2"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8\u20139 lines \u00D7 3): src/scan/title.rs:202-210 | src/scan/title.rs:212-220 | src/scan/title.rs:221-228 \u2014 all 3 copies are in the same file, so extract the block into one function there and call it from every one of those sites \u2014 resolving only two of them leaves the rest to drift apart the first time one is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/title.rs"},"region":{"startLine":202}}}],"partialFingerprints":{"codehealthFindingId/v1":"563bde9801d134dbb150aca6d18d6c30f78bb7a1bc4164415cca1d5adabb8391"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 3): src/scan/semantic/convert.rs:205-212 | src/scan/semantic/convert.rs:221-228 | src/scan/semantic/convert.rs:237-244 \u2014 all 3 copies are in the same file, so extract the block into one function there and call it from every one of those sites \u2014 resolving only two of them leaves the rest to drift apart the first time one is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/semantic/convert.rs"},"region":{"startLine":205}}}],"partialFingerprints":{"codehealthFindingId/v1":"844ab79f32d7165c23378b1d5321efe3673b18d7ccf2d87cb3adb940183536ee"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): src/gui/modal.rs:337-344 | src/gui/modal.rs:356-363 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/modal.rs"},"region":{"startLine":337}}}],"partialFingerprints":{"codehealthFindingId/v1":"23d1cfdaa40c0067d9c5f643dba06a6d664f170c07ef05e45f817b4460165ae6"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): src/gui/screen.rs:88-95 | src/gui/screen.rs:177-184 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/screen.rs"},"region":{"startLine":88}}}],"partialFingerprints":{"codehealthFindingId/v1":"7530f74bfe5c3c33bce44a334ab08e0702eb383d30cf482c8c58ac1ef19c6787"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): src/gui/search.rs:43-50 | src/gui/search.rs:62-69 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/search.rs"},"region":{"startLine":43}}}],"partialFingerprints":{"codehealthFindingId/v1":"f1ededc088a4266390ead63757f536a2ae6113367fef16517d15d90d85538c8c"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): src/scan/layout.rs:1812-1819 | src/scan/layout.rs:1825-1832 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/layout.rs"},"region":{"startLine":1812}}}],"partialFingerprints":{"codehealthFindingId/v1":"068a6884da5506130b319596ffef46590fe972ba17ad2d48ee9c1a3618347063"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): src/cli.rs:509-516 | src/cli.rs:767-774 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/cli.rs"},"region":{"startLine":509}}}],"partialFingerprints":{"codehealthFindingId/v1":"2c974ccef10045959998a054ab33eb82cd40c3b610caaf796bf3a81908770bc5"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): src/cli.rs:723-730 | src/cli.rs:758-765 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/cli.rs"},"region":{"startLine":723}}}],"partialFingerprints":{"codehealthFindingId/v1":"991afaf64d33be328e90f10460bfd78e9bf87b0eb01cc3e5311039202fd4ca4a"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 3): src/scan/duplicate.rs:294-300 | src/scan/duplicate.rs:302-308 | src/scan/duplicate.rs:311-317 \u2014 all 3 copies are in the same file, so extract the block into one function there and call it from every one of those sites \u2014 resolving only two of them leaves the rest to drift apart the first time one is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/duplicate.rs"},"region":{"startLine":294}}}],"partialFingerprints":{"codehealthFindingId/v1":"e7ca0916d1dfb20210da3c582fb98aff14a6bc62c249488a72d7508231093d7a"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): src/gui/app.rs:862-868 | src/gui/app.rs:1092-1098 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":862}}}],"partialFingerprints":{"codehealthFindingId/v1":"3ba8fb73fe866521787829f10a31f72669f22a037b6d285c64fd8089ae4883b9"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): src/path.rs:92-98 | src/path.rs:135-141 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/path.rs"},"region":{"startLine":92}}}],"partialFingerprints":{"codehealthFindingId/v1":"90578f81a339ddc01ed52270faa15b9d66faf010dc8d6aa422f3906202ff923f"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): src/scan/layout.rs:923-929 | src/scan/layout.rs:1988-1994 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/layout.rs"},"region":{"startLine":923}}}],"partialFingerprints":{"codehealthFindingId/v1":"eda5557eda814dd398c50028faa811daee74be0d36736ad92491b0b05a45394f"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): src/scan/layout.rs:1981-1987 | src/scan/layout.rs:2028-2034 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/layout.rs"},"region":{"startLine":1981}}}],"partialFingerprints":{"codehealthFindingId/v1":"ae580bd7b7050651b49877b3f8286b7c8c154ec59c0c6a843f5135167da2776e"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): src/scan.rs:486-492 | src/scan.rs:496-502 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan.rs"},"region":{"startLine":486}}}],"partialFingerprints":{"codehealthFindingId/v1":"32e6a05781d85b02f26168b3605d1d1287c75699c0a1800b2c49956e43c1c5b1"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): src/path.rs:85-90 | src/path.rs:128-133 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/path.rs"},"region":{"startLine":85}}}],"partialFingerprints":{"codehealthFindingId/v1":"9f2cd6233d540f6b79ab9ffcc11c5226938232fd60680deb0fb57fb10d8f1d17"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): src/resource/config.rs:446-451 | src/resource/config.rs:470-475 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/resource/config.rs"},"region":{"startLine":446}}}],"partialFingerprints":{"codehealthFindingId/v1":"32af07acdf16e78c40936acf134290cf6d531275151c948dca957605a6e17bc7"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): src/scan/launchers/heroic/gog.rs:97-102 | src/scan/launchers/heroic/legendary.rs:60-65 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/launchers/heroic/gog.rs"},"region":{"startLine":97}}}],"partialFingerprints":{"codehealthFindingId/v1":"53b5da6f08eb2053c82fca91be9a6053ed4d5d2f3c0cf9138947ee213c6b1a03"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): src/scan.rs:305-310 | src/scan.rs:374-379 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan.rs"},"region":{"startLine":305}}}],"partialFingerprints":{"codehealthFindingId/v1":"870ef775191b69c14e02c2c35dd1ebf138aa33aa5a7144e2f9e3c07377dbe9ca"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 3): src/cli.rs:765-769 | src/cli.rs:995-999 | src/cli.rs:1039-1043 \u2014 all 3 copies are in the same file, so extract the block into one function there and call it from every one of those sites \u2014 resolving only two of them leaves the rest to drift apart the first time one is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/cli.rs"},"region":{"startLine":765}}}],"partialFingerprints":{"codehealthFindingId/v1":"6dfdc6d4701cfbef79ad2a11c5b0507c60fd81ef79361c781ef7fd47268fa0fe"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): src/resource/config.rs:430-434 | src/resource/config.rs:454-458 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/resource/config.rs"},"region":{"startLine":430}}}],"partialFingerprints":{"codehealthFindingId/v1":"ecd8260f05c6942aa785876992a8eb0dc7778a1100612260e13405dcb7457200"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14 lines \u00D7 2): src/cli.rs:249-262 | src/cli.rs:540-553 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/cli.rs"},"region":{"startLine":249}}}],"partialFingerprints":{"codehealthFindingId/v1":"42bdb379c20b218edf899b857befe64d7fe08cbc01a693415f6861f19748f39b"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 3): src/scan/launchers/heroic/legendary.rs:104-115 | src/scan/launchers/heroic/nile.rs:77-84 | src/scan/launchers/heroic/sideload.rs:77-84 \u2014 before extracting anything, compare \u0060src/scan/launchers/heroic/nile.rs\u0060 and \u0060src/scan/launchers/heroic/sideload.rs\u0060 as WHOLE FILES: this scan already matched 3 separate duplicated blocks between them, totalling at least 36 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/launchers/heroic/legendary.rs"},"region":{"startLine":104}}}],"partialFingerprints":{"codehealthFindingId/v1":"1d8cf52fa691ea74825a92c54865e0cd2900b5dff9a28526b377949553fc8b46"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): src/api.rs:263-271 | src/api.rs:425-433 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/api.rs"},"region":{"startLine":263}}}],"partialFingerprints":{"codehealthFindingId/v1":"3eb5c039d639a717b59f89ce381cf92aeee778def6f428f488808448d076797c"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/gui/app.rs: src/gui/app.rs changed 4 times in last 90 days, and the most complex body those changes touched has cyclomatic complexity 332 in App::update at line 1491. 2 of those changes were fix/bug commits, and the other 2 changed it for other reasons \u2014 this file is under both repair and feature pressure. Before the next change lands here, make sure the area it touches is under test, then split that area out of the file so the following change is smaller than this one \u2014 a file this often edited pays the complexity back every time. Counted over 2026-06-12..2026-09-10, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-12 22:28:19 -04:00\u0027 --until=\u00272026-09-10 22:28:19 -04:00\u0027 --full-history --no-merges -- src/gui/app.rs\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":1491}}}],"partialFingerprints":{"codehealthFindingId/v1":"74630a20a70d51cc96cc0d965feef5841d8485faef175d2f1465a1a2217cdc68"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/cli.rs: src/cli.rs changed 3 times in last 90 days, and the most complex body those changes touched has cyclomatic complexity 157 in ludusavi::cli::run at line 142. 2 of those changes were fix/bug commits, so the churn is repair rather than feature work. Before the next change lands here, make sure the area it touches is under test, then split that area out of the file so the following change is smaller than this one \u2014 a file this often edited pays the complexity back every time. Counted over 2026-06-12..2026-09-10, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-12 22:28:19 -04:00\u0027 --until=\u00272026-09-10 22:28:19 -04:00\u0027 --full-history --no-merges -- src/cli.rs\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/cli.rs"},"region":{"startLine":142}}}],"partialFingerprints":{"codehealthFindingId/v1":"344c7030d79234e68ae6632d76eb368a0e485c478a1b4c7f5dd052125763e7c6"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/scan.rs: src/scan.rs changed 7 times in last 90 days, and the most complex body those changes touched has cyclomatic complexity 50 in ludusavi::scan::scan_game_for_backup at line 544. 3 of those changes were fix/bug commits, and the other 4 changed it for other reasons \u2014 this file is under both repair and feature pressure. Before the next change lands here, make sure the area it touches is under test, then split that area out of the file so the following change is smaller than this one \u2014 a file this often edited pays the complexity back every time. Counted over 2026-06-12..2026-09-10, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-12 22:28:19 -04:00\u0027 --until=\u00272026-09-10 22:28:19 -04:00\u0027 --full-history --no-merges -- src/scan.rs\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan.rs"},"region":{"startLine":544}}}],"partialFingerprints":{"codehealthFindingId/v1":"560245f3ccf7b407945560c117f7656c6de438a7440e65aaef6b01dfabadaa19"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/scan/layout.rs: src/scan/layout.rs changed 5 times in last 90 days, and the most complex body those changes touched has cyclomatic complexity 19 in GameLayout::validate at line 2105. 2 of those changes were fix/bug commits, and the other 3 changed it for other reasons \u2014 this file is under both repair and feature pressure. Before the next change lands here, make sure the area it touches is under test, then split that area out of the file so the following change is smaller than this one \u2014 a file this often edited pays the complexity back every time. Counted over 2026-06-12..2026-09-10, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-12 22:28:19 -04:00\u0027 --until=\u00272026-09-10 22:28:19 -04:00\u0027 --full-history --no-merges -- src/scan/layout.rs\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/layout.rs"},"region":{"startLine":2105}}}],"partialFingerprints":{"codehealthFindingId/v1":"4d58e358025b3d6d124225f00396f308aa561796a3e2c17d1a5aace9e4508433"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/scan/semantic/convert.rs: src/scan/semantic/convert.rs changed 4 times in last 90 days, and the most complex body those changes touched has cyclomatic complexity 23 in ludusavi::scan::semantic::convert::windows_physical_to_semantic at line 63. 2 of those changes were fix/bug commits, and the other 2 changed it for other reasons \u2014 this file is under both repair and feature pressure. Before the next change lands here, make sure the area it touches is under test, then split that area out of the file so the following change is smaller than this one \u2014 a file this often edited pays the complexity back every time. Counted over 2026-06-12..2026-09-10, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-12 22:28:19 -04:00\u0027 --until=\u00272026-09-10 22:28:19 -04:00\u0027 --full-history --no-merges -- src/scan/semantic/convert.rs\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/semantic/convert.rs"},"region":{"startLine":63}}}],"partialFingerprints":{"codehealthFindingId/v1":"7db8d23d6418b191636c03c274a3668ca84f73277b217e4510acfbabcb27ea5a"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/api.rs: src/api.rs changed 3 times in last 90 days, and the most complex body those changes touched has cyclomatic complexity 26 in Ludusavi::back_up at line 119. 2 of those changes were fix/bug commits, so the churn is repair rather than feature work. Before the next change lands here, make sure the area it touches is under test, then split that area out of the file so the following change is smaller than this one \u2014 a file this often edited pays the complexity back every time. Counted over 2026-06-12..2026-09-10, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-12 22:28:19 -04:00\u0027 --until=\u00272026-09-10 22:28:19 -04:00\u0027 --full-history --no-merges -- src/api.rs\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/api.rs"},"region":{"startLine":119}}}],"partialFingerprints":{"codehealthFindingId/v1":"7516ea01aaa49110e375cd9893320873fbe93e773c69f02d424c0b9e706dff5c"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/report.rs: src/report.rs changed 2 times in last 90 days, and the most complex body those changes touched has cyclomatic complexity 25 in Reporter::add_game at line 311. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-12..2026-09-10, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-12 22:28:19 -04:00\u0027 --until=\u00272026-09-10 22:28:19 -04:00\u0027 --full-history --no-merges -- src/report.rs\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/report.rs"},"region":{"startLine":311}}}],"partialFingerprints":{"codehealthFindingId/v1":"5290a21b07e8b4f6ff030cffbd57983333ed39c769ff26a10acfaace40faeea8"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Refactor to avoid shared state. \u2014 source code is not a task system: move the work to your tracker and leave a reference instead (e.g. \u0060// REF: #123\u0060), so the task is planned where tasks live and the ticket links back to the code."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/wrap.rs"},"region":{"startLine":44}}}],"partialFingerprints":{"codehealthFindingId/v1":"9e0d4dfc20d064f731367fe93ba40bf597300fc85fc28be1f5999666dd0fd58c"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Support names containing a slash. \u2014 source code is not a task system: move the work to your tracker and leave a reference instead (e.g. \u0060// REF: #123\u0060), so the task is planned where tasks live and the ticket links back to the code."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan.rs"},"region":{"startLine":797}}}],"partialFingerprints":{"codehealthFindingId/v1":"a47aece92d13fa5167fbd75761777df5b8eb81298216ddf8d6ea42b46ea69904"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Fix or remove this case? \u2014 source code is not a task system: move the work to your tracker and leave a reference instead (e.g. \u0060// REF: #123\u0060), so the task is planned where tasks live and the ticket links back to the code."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/path.rs"},"region":{"startLine":1854}}}],"partialFingerprints":{"codehealthFindingId/v1":"80223f056c7276836bbee71c953b4249d0f0617f9a63ada103b9ffca6cb27ba2"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: RTL blocked by https://github.com/iced-rs/iced/issues/250."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/lang.rs"},"region":{"startLine":48}}}],"partialFingerprints":{"codehealthFindingId/v1":"08a27073c1bfb5afc50c006b4f6124baf5f24de606f354d583bfe96db7de87c1"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Detect if saves are unchanged and skip the question? \u2014 source code is not a task system: move the work to your tracker and leave a reference instead (e.g. \u0060// REF: #123\u0060), so the task is planned where tasks live and the ticket links back to the code."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/cli.rs"},"region":{"startLine":1147}}}],"partialFingerprints":{"codehealthFindingId/v1":"64b49d71ffba63be1696b45372daa8f0de89fbcf06dcab0bbbf0825010eeec52"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Legendary returns immediately. Can we handle that? \u2014 source code is not a task system: move the work to your tracker and leave a reference instead (e.g. \u0060// REF: #123\u0060), so the task is planned where tasks live and the ticket links back to the code."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/cli.rs"},"region":{"startLine":1216}}}],"partialFingerprints":{"codehealthFindingId/v1":"bce9044ccb4e4c8025ddfcfdd25f7adb0022b5268c84f71a51ccd837be17cb35"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Must be a string literal. Can we support translation? \u2014 source code is not a task system: move the work to your tracker and leave a reference instead (e.g. \u0060// REF: #123\u0060), so the task is planned where tasks live and the ticket links back to the code."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/cli/ui.rs"},"region":{"startLine":29}}}],"partialFingerprints":{"codehealthFindingId/v1":"8f3892fe2b530c7a552b9785965066a1184a7e378ed4dda9a99347f3335e73fa"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Dialoguer doesn\u0027t have an alert type. \u2014 source code is not a task system: move the work to your tracker and leave a reference instead (e.g. \u0060// REF: #123\u0060), so the task is planned where tasks live and the ticket links back to the code."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/cli/ui.rs"},"region":{"startLine":69}}}],"partialFingerprints":{"codehealthFindingId/v1":"b644a807897f841e54204d616a703ff43a984fb51f2aa448f8d86a140f8d1852"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: This is now handled separately with a \u0060TextEditor\u0060. \u2014 source code is not a task system: move the work to your tracker and leave a reference instead (e.g. \u0060// REF: #123\u0060), so the task is planned where tasks live and the ticket links back to the code."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/shortcuts.rs"},"region":{"startLine":446}}}],"partialFingerprints":{"codehealthFindingId/v1":"9b9d15e82bba1e75bffee81cb1258f894a6272f673d3e798d96282c905fb29ea"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Add an option to validate all backups at once. \u2014 source code is not a task system: move the work to your tracker and leave a reference instead (e.g. \u0060// REF: #123\u0060), so the task is planned where tasks live and the ticket links back to the code."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":1107}}}],"partialFingerprints":{"codehealthFindingId/v1":"b55d57a64573c13485d1d9fdcd27f1121bcc9c2f663b698b50c8f111e58541ef"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Automatically refresh redirected paths in the game list. \u2014 source code is not a task system: move the work to your tracker and leave a reference instead (e.g. \u0060// REF: #123\u0060), so the task is planned where tasks live and the ticket links back to the code."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":1650}}}],"partialFingerprints":{"codehealthFindingId/v1":"38f93294f788c3ec33ab6275bf4d8eda20eb0ef13fda6f021a5e8134075fe76b"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Registry failures are currently ignored during backup. \u2014 source code is not a task system: move the work to your tracker and leave a reference instead (e.g. \u0060// REF: #123\u0060), so the task is planned where tasks live and the ticket links back to the code."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/layout.rs"},"region":{"startLine":197}}}],"partialFingerprints":{"codehealthFindingId/v1":"1a730e4ea69b9d2ecdc86bec4bcf818175c0cac6488e6f0b390198017084a4dc"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Handle key names containing a slash. \u2014 source code is not a task system: move the work to your tracker and leave a reference instead (e.g. \u0060// REF: #123\u0060), so the task is planned where tasks live and the ticket links back to the code."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/registry/win.rs"},"region":{"startLine":187}}}],"partialFingerprints":{"codehealthFindingId/v1":"2a8312794bc6cdd6bf9dd44965f91d2a704f6987f7628f64ddea164701fe33d8"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: The default value has an empty name. How should we represent it? \u2014 source code is not a task system: move the work to your tracker and leave a reference instead (e.g. \u0060// REF: #123\u0060), so the task is planned where tasks live and the ticket links back to the code."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/registry/win.rs"},"region":{"startLine":217}}}],"partialFingerprints":{"codehealthFindingId/v1":"7500e7a109a427dfc18484419ff8ef40f98858345748214d676fd0b4f947ab5d"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Track errors by specific entry, rather than the parent key. \u2014 source code is not a task system: move the work to your tracker and leave a reference instead (e.g. \u0060// REF: #123\u0060), so the task is planned where tasks live and the ticket links back to the code."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/scan/registry/win.rs"},"region":{"startLine":347}}}],"partialFingerprints":{"codehealthFindingId/v1":"c576f9063b9a0d820ee2a42beea0b7fd57ce894f2e1f33a9c58dee21b42dcc31"}},{"ruleId":"D19","level":"note","message":{"text":"Documentation: no installation or build instructions: The \u0027Installation\u0027 section is a valid installation guide but it contains no build or setup steps (e.g. Rust/Cargo install, Flatpak/Flathub download) for the reader to run. Add a short Build and Setup section covering how to get started with Ludusavi on each supported platform."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs/help/installation.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"00768ed3e68c48ae53cc796feb4848361535bde7c4a95255cfb23c44672bbeee"}},{"ruleId":"D19","level":"note","message":{"text":"Documentation: no architecture or design documentation: The troubleshooting guide is focused on runtime behavior rather than the underlying architecture (e.g. why a redirect fails, what data Ludusavi backs up per root type). Add an Architecture/Design section explaining how each root type and redirect type behaves."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs/help/troubleshooting.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"850fe986e9193edb9e0715e5841004eba33d15a095202b419808040428e7c4ac"}},{"ruleId":"D20","level":"note","message":{"text":"No ADRs found: No ADRs found. No recognised ADR directory (\u0060docs/adr/\u0060, \u0060docs/decisions/\u0060, \u0060adr/\u0060, \u0060docs/rfcs/\u0060, an \u0060ADR0001/\u0060 folder, or their siblings) exists anywhere in this tree. What was searched, so you can tell an empty log from a search that missed one: every directory under the tree (build output, dependencies and VCS metadata excepted), for a document that is either any non-index page inside a recognised ADR directory, whatever its name and however deeply nested (\u0060docs/adr/use-postgres.md\u0060, \u0060docs/adr/2024/0001-x.md\u0060); or a file anywhere whose name is ADR-shaped (\u00600001-use-postgres.md\u0060, \u0060adr-012-caching.md\u0060); or, when neither turned anything up, a document carrying the decision-record signature (an \u0022Architecture Decision Record\u0022 heading, or Status / Context / Decision / Consequences as section headings). A decision log that clears none of these \u2014 unnumbered files outside any recognised directory, without those headings \u2014 is not seen by this check and this row is then wrong. If that is your case, say so rather than renaming anything; otherwise, consider recording architectural decisions in \u0060docs/adr/\u0060."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"d2bea044ff79d7d275f5a91a6e2f548586178eaf480274c33960ad020c854631"}},{"ruleId":"D22","level":"warning","message":{"text":"Inconsistent error handling pattern for read operations. Most other I/O operations on StrictPath (e.g., \u0060open\u0060, \u0060write_with_content\u0060, \u0060metadata\u0060, \u0060sha1\u0060) return a \u0060Result\u0060 to handle potential I/O errors. However, \u0060read()\u0060 returns a \u0060String\u0060 directly, implying it panics or unwraps on error, while \u0060try_read()\u0060 provides the safe \u0060Result\u0060 variant. This breaks the uniform \u0060Result\u0060-returning convention established by the rest of the type.: Deprecate \u0060read()\u0060 and \u0060try_read()\u0060, replacing them with a single \u0060read() -\u003E Result\u003CString\u003E\u0060 method to align with \u0060open()\u0060, \u0060metadata()\u0060, and \u0060sha1()\u0060. (signatures: StrictPath.read(): String | StrictPath.try_read(): Result)"},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"8e0832bbdc9361ed99359c64584c60ae4f999276193076298e67f350182fcba7"}},{"ruleId":"D22","level":"warning","message":{"text":"Same inconsistency as above. \u0060sha1()\u0060 returns a \u0060String\u0060 directly, while \u0060try_sha1()\u0060 returns a \u0060Result\u0060. Given that computing a hash can fail (e.g., file not found, permission denied), the direct return is unsafe and inconsistent with the \u0060Result\u0060-returning \u0060try_sha1()\u0060 and other methods like \u0060metadata()\u0060.: Deprecate \u0060sha1()\u0060 and \u0060try_sha1()\u0060, replacing them with a single \u0060sha1() -\u003E Result\u003CString\u003E\u0060 method. (signatures: StrictPath.sha1(): String | StrictPath.try_sha1(): Result)"},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"d7b7a4fa73faceb17996d57080e1275a1d69ee26c7435797b399ddfe0d380500"}},{"ruleId":"D22","level":"warning","message":{"text":"Same inconsistency as above. \u0060same_content()\u0060 returns a \u0060bool\u0060 directly, while \u0060try_same_content()\u0060 returns a \u0060Result\u0060. Comparing file content involves I/O which can fail, so the direct return is unsafe and inconsistent with the \u0060Result\u0060-returning \u0060try_same_content()\u0060.: Deprecate \u0060same_content()\u0060 and \u0060try_same_content()\u0060, replacing them with a single \u0060same_content() -\u003E Result\u003Cbool\u003E\u0060 method. (signatures: StrictPath.same_content(other: StrictPath): bool | StrictPath.try_same_content(other: StrictPath): Result)"},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"37860c717cadbadb33d305e8d10ca0200c938f859679e0ffd98f4fb2a2f2b80f"}},{"ruleId":"D26","level":"note","message":{"text":"Projects may be oversized for their cohesion: 1 of 1 project(s) overshoot their size bounds, lowering Project Cohesion to 0.0/10. The most over is \u0060(repository root)\u0060 (37257 LoC, 338 public types across 11 directories). Review these for cohesion \u2014 draw the boundary inside the module first (group each responsibility into its own package or directory and keep the cross-boundary members non-public), since splitting a published package moves types between packages and breaks consumers."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"d5a94650dc74886a0f1f08eb9fb6775f1fc395279ef7e901c970c9d26f767a72"}},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"43bc41f40199544cee6e6f36d630501ef695fa8c4e7ef378436acb46559db48d"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"cacbc9040cd3c9a9e082f22c27da6695afbdd5fac811c7b56d793ebd42db2234"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"91a235db905f6aafbeb58fc3a79ccd136b59ca4b1901f846d6c109d18c35fb52"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"56e1fd902f55481336f2fd6da648020af980e0582a3fc653ce00253d8ff7009c"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"6d629a4a3fd39a9342831beee038334c87ace9e016c48b21424b16a1bbc23bb6"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"69ab57d858abe8011126444adf2a7ddea385eb3ce6a6f572f6b82e7ae1460ad7"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"a0dcac6f60b5f45024195f38e31c2519bbd5a5187edc818c64a11feb0c510e16"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"4cbf2a5beaeef10088ddf5b7a2242aa89eb0080744cd61f456a8056080b77fa4"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"51d0213925234909b303cdb92b4cd898ffe53b8ee2b9c02642668ad576e030ac"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"cc9b4c263b19ad4f565a0a559b1cabdd221eefe1b387a99e29140eb24de4e9ae"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"f214d9fa881d2fcdddf82f209edcbf2d9d047be8a8e3f98647e6450c5917d6b3"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"6d0ba232e250a3ce608906c9377c60d30dd44615dad659f386b0dbaac99b6437"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"21c3b97f97c2f31a566b14450a65907f8b657ca41a595c614ffbe30e76328a6c"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D30","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"b5308f9ed219ff7d361ed2b01ab7b5fa7a33b0013fcd35575e7068ccda1d2997"},"properties":{"dependency":{"package":"quinn-proto","version":"0.11.8","advisory":"[GHSA redacted]","aliases":["[CVE redacted]","[CVE redacted]","[GHSA redacted]","RUSTSEC-2026-0037","RUSTSEC-2026-0185"],"reachability":{"kind":"unknown"}}}},{"ruleId":"D30","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"0d3d2c2346bccaaa14c1bd0f0713c18ae4de849fffdc7282dbd533ab105c9398"},"properties":{"dependency":{"package":"rustls-webpki","version":"0.102.8","advisory":"[GHSA redacted]","aliases":["[CVE redacted]","[CVE redacted]","[CVE redacted]","[CVE redacted]","[GHSA redacted]","[GHSA redacted]","[GHSA redacted]","RUSTSEC-2026-0049","RUSTSEC-2026-0098","RUSTSEC-2026-0099","RUSTSEC-2026-0104"],"reachability":{"kind":"unknown"}}}},{"ruleId":"D30","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"e16ff181dc5fd33b48cbe021d90502a7d1bebf3d81394fc6c84d46d918f3405e"},"properties":{"dependency":{"package":"hashbrown","version":"0.15.0","advisory":"[GHSA redacted]","aliases":["RUSTSEC-2024-0402"],"reachability":{"kind":"unknown"}}}},{"ruleId":"D30","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"7cb949b0dfc97628adeb5867f44cfbeefa3a6a1068b707709bf0e421e653ea4f"},"properties":{"dependency":{"package":"bytes","version":"1.7.2","advisory":"[GHSA redacted]","aliases":["[CVE redacted]","RUSTSEC-2026-0007"],"reachability":{"kind":"unknown"}}}},{"ruleId":"D30","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"c4418f84a9021f8795e0afb95860a9ded4b00ef98d47f5279b54588b4c689b20"},"properties":{"dependency":{"package":"ring","version":"0.17.8","advisory":"[GHSA redacted]","aliases":["[CVE redacted]","[GHSA redacted]","GO-2025-3678","RUSTSEC-2025-0009"],"reachability":{"kind":"unknown"}}}},{"ruleId":"D30","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"29893d3a3e305da437cc83ee22a1371122931c4170a4efca5bd1b42e190a502c"},"properties":{"dependency":{"package":"idna","version":"0.5.0","advisory":"[GHSA redacted]","aliases":["[CVE redacted]","RUSTSEC-2024-0421"],"reachability":{"kind":"unknown"}}}},{"ruleId":"D30","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"30796cdfee8540412b2acb1c5ba2a73a16d0282f707e0fc1a219acf8019d6265"},"properties":{"dependency":{"package":"rustls","version":"0.23.14","advisory":"[GHSA redacted]","aliases":["[CVE redacted]","[GHSA redacted]","RUSTSEC-2024-0399","RUSTSEC-2026-0285"],"reachability":{"kind":"unknown"}}}},{"ruleId":"D30","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"85ffa314d77812277deab31fb2264e02366c4034561614d82315c198cb6bb99e"},"properties":{"dependency":{"package":"time","version":"0.3.36","advisory":"[GHSA redacted]","aliases":["[CVE redacted]","RUSTSEC-2026-0009"],"reachability":{"kind":"unknown"}}}},{"ruleId":"D30","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"5ceb9040e13548b3df718b94867858f8e5659519eb178fbf2fd0e4e23343e0da"},"properties":{"dependency":{"package":"yaml-rust","version":"0.4.5","advisory":"RUSTSEC-2024-0320","reachability":{"kind":"unknown"}}}},{"ruleId":"D30","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"95686d8e64236c3c2c566e482859faf67a5bbd9dbeebb6f4df8aab56c3496281"},"properties":{"dependency":{"package":"proc-macro-error","version":"1.0.4","advisory":"RUSTSEC-2024-0370","reachability":{"kind":"unknown"}}}},{"ruleId":"D30","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"f48cf8c9f415048128045caa118a1e03769d0b4fe18d7f036c2f3766e3e8d8fb"},"properties":{"dependency":{"package":"instant","version":"0.1.13","advisory":"RUSTSEC-2024-0384","reachability":{"kind":"unknown"}}}},{"ruleId":"D30","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"5922a5beeab5ac077ffb485a783ad545036e79b56239f83da38f3fb84336b113"},"properties":{"dependency":{"package":"paste","version":"1.0.15","advisory":"RUSTSEC-2024-0436","reachability":{"kind":"unknown"}}}},{"ruleId":"D30","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"705e8761c5e609601c0419d94a8bad1aeb6aee434f48ec4660c92e8bf534c9de"},"properties":{"dependency":{"package":"number_prefix","version":"0.4.0","advisory":"RUSTSEC-2025-0119","reachability":{"kind":"unknown"}}}},{"ruleId":"D30","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"b5524f25221308ec94b7206b58afaa59996104c20abaa242285d451f5344e44b"},"properties":{"dependency":{"package":"rustls-pemfile","version":"2.2.0","advisory":"RUSTSEC-2025-0134","reachability":{"kind":"unknown"}}}},{"ruleId":"D30","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"c356dafc2d2f879539349393edf47ceccc3e0771bf15e4dae816abd8594fd25c"},"properties":{"dependency":{"package":"ttf-parser","version":"0.25.0","advisory":"RUSTSEC-2026-0192","reachability":{"kind":"unknown"}}}},{"ruleId":"D30","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"be12c71023c43937a607a177a93163e0581c742a3255ef7103051bf074226b53"},"properties":{"dependency":{"package":"rustybuzz","version":"0.20.1","advisory":"RUSTSEC-2026-0206","reachability":{"kind":"unknown"}}}},{"ruleId":"D30","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"1ab2215dce40c85d1d5ebc42b9ae77feb11c5e06c62f5c4d62872ff5735eb870"},"properties":{"dependency":{"package":"tokio","version":"1.40.0","advisory":"RUSTSEC-2025-0023","aliases":["[GHSA redacted]"],"reachability":{"kind":"unknown"}}}},{"ruleId":"D30","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"bbe030f8c1c144f826bad4cbbd83ebd5ea8dfc9162bb9621a856f9f966813acf"},"properties":{"dependency":{"package":"lru","version":"0.16.2","advisory":"RUSTSEC-2026-0002","aliases":["[GHSA redacted]"],"reachability":{"kind":"unknown"}}}},{"ruleId":"D30","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"d44a25813d8a9e18eb42fa5350a972c298292d454155c6472f091bfb670363df"},"properties":{"dependency":{"package":"rand","version":"0.8.5","advisory":"RUSTSEC-2026-0097","aliases":["[GHSA redacted]"],"reachability":{"kind":"unknown"}}}},{"ruleId":"D30","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"bf9b3890cba73cd3c5d5270d1976bd1bae94596a1c510482b94fe9367ef871f2"},"properties":{"dependency":{"package":"memmap2","version":"0.9.5","advisory":"RUSTSEC-2026-0186","reachability":{"kind":"unknown"}}}},{"ruleId":"D30","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"759d36a63e8483c4a467399ff199fa57fa2e02d89ef311720974588edb9516d4"},"properties":{"dependency":{"package":"anyhow","version":"1.0.100","advisory":"RUSTSEC-2026-0190","reachability":{"kind":"unknown"}}}},{"ruleId":"D30","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"422864efbc32ee020d94634a443edac9d818b90faf02ac96d91c4d66ffa4da37"},"properties":{"dependency":{"package":"lru","version":"0.16.2","advisory":"RUSTSEC-2026-0253","reachability":{"kind":"unknown"}}}},{"ruleId":"D30","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"1916856307d6d77eb7c2c2ad00a860759d15ef7f6f635ef50a6cc2cbe0531cb5"},"properties":{"dependency":{"package":"rkyv","version":"0.7.45","advisory":"RUSTSEC-2026-0001","aliases":["RUSTSEC-2026-0235"],"reachability":{"kind":"unknown"}}}},{"ruleId":"D30","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"5585c48a8c4ed670247ebaa40a533d385248c4e49079fee700e7b93cbab137a9"},"properties":{"dependency":{"package":"quick-xml","version":"0.36.2","advisory":"RUSTSEC-2026-0194","aliases":["RUSTSEC-2026-0195"],"reachability":{"kind":"unknown"}}}},{"ruleId":"D30","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"c4a0c58aca13bc848c37d4c3d5bcb90f8e046f8df5b386f5a3743d0625ad8dae"},"properties":{"dependency":{"package":"crossbeam-epoch","version":"0.9.18","advisory":"RUSTSEC-2026-0204","reachability":{"kind":"unknown"}}}},{"ruleId":"D35","level":"warning","message":{"text":"Change coupling: app.rs \u2194 icon.rs: \u0060src/gui/app.rs\u0060 and \u0060src/gui/icon.rs\u0060 change together 60% of the time (12 of the 20 commits that touched whichever of the two files changed less often, counting a file under its earlier names as well \u2014 a repo-wide or module-wide sweep is evidence about the sweep rather than about any pair inside it and is left out of BOTH sides of this ratio, while a dependency bump, a formatter/rename sweep, or a commit whose edit to one of the two files was a tool directive such as //go:generate or whitespace only is left out of the shared count ONLY, so the two sides are not taken over identical commit sets) with no explicit dependency between them. They sit in the same directory, but in this ecosystem each file is its own module \u2014 a sibling reference still needs an import \u2014 so the missing import edge is real: the coupling runs through shared behaviour, not a declared dependency. If they duplicate structure, extract the common part into one unit; otherwise the coupling is hidden and worth breaking. You can check this without leaving the row: of the 12 shared commits counted here, the most recent 3 are \u0060e9d513dd\u0060 #509: Add button to copy registry paths; \u0060e72a2cb0\u0060 #402: Add choice for how to integrate custom games; \u0060abbacc82\u0060 #402: Add icon when custom game overrides a manifest entry \u2014 run \u0060git show\u0060 on any of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"9c209831a1852a9f7059fc162a78f989979be0ef5c805571afb90430862b5d3a"}},{"ruleId":"D35","level":"warning","message":{"text":"Change coupling: app.rs \u2194 game_list.rs: \u0060src/gui/app.rs\u0060 and \u0060src/gui/game_list.rs\u0060 change together 57% of the time (39 of the 68 commits that touched whichever of the two files changed less often, counting a file under its earlier names as well \u2014 a repo-wide or module-wide sweep is evidence about the sweep rather than about any pair inside it and is left out of BOTH sides of this ratio, while a dependency bump, a formatter/rename sweep, or a commit whose edit to one of the two files was a tool directive such as //go:generate or whitespace only is left out of the shared count ONLY, so the two sides are not taken over identical commit sets) with no explicit dependency between them. They sit in the same directory, but in this ecosystem each file is its own module \u2014 a sibling reference still needs an import \u2014 so the missing import edge is real: the coupling runs through shared behaviour, not a declared dependency. If they duplicate structure, extract the common part into one unit; otherwise the coupling is hidden and worth breaking. You can check this without leaving the row: of the 39 shared commits counted here, the most recent 3 are \u006068936064\u0060 #295: Allow typing multiple lines in backup comments; \u00603be4a58c\u0060 #415: Account for filtered games in status row and toggle-all buttons; \u00601b3fd187\u0060 #415: Fix filtered scan processing disabled games \u2014 run \u0060git show\u0060 on any of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/gui/app.rs"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"5d0d0d96c3e70e7b32c54be79e0c755583b662302cfc374721a4a67968ae051d"}},{"ruleId":"D36","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"9658270ba49f37ed04e99ab1263b6393cd42aed8bdfb7aafd9fa1070f5491895"}},{"ruleId":"D36","level":"note","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"ace515990e7ee0f17b5c17e44dd168a5bdecf90804a3a3dd845cf05540978013"}},{"ruleId":"M2","level":"note","message":{"text":"No ADRs: No Architecture Decision Records found \u2014 no conventional ADR directory, no numbered \u0060NNNN-title\u0060 documents in any markup this check reads, and nothing ADR-shaped by content. Design rationale recorded elsewhere (a design-notes tree, a mailing list, pull-request discussion) is not visible to this check and is not re-findable per decision, so a future maintainer cannot ask why one choice was made and get an answer."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"670b3d6e36a756d63097d0dfbf90afd5fc761308800b9354894a07c3f4e4aa14"}},{"ruleId":"M2","level":"note","message":{"text":"No architecture diagram/doc: No C4/Structurizr/PlantUML/Mermaid/Graphviz/D2 diagram, no drawn diagram named for the architecture, no file named \u0060architecture\u0060 or \u0060design\u0060 in any markup this check reads, and nothing in the README, docs or contributor guides that announces the shape \u2014 no \u0060## Architecture\u0060 heading, no \u0022architecture overview\u0022/\u0022high-level design\u0022 phrasing, no \u0022the architecture is \u2026\u0022 introduction, no guided code tour. A shape laid out in prose that never names itself as the architecture is not visible to this check, and neither is one kept outside the repository, so this row reports the absence of a re-findable shape document \u2014 not evidence that nobody wrote the shape down."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"0c190e7c159d1850ee706c3ac4486e151e8a4fe169de4bf61436b9f399654f06"}},{"ruleId":"M4","level":"note","message":{"text":"README/code drift: README claims Playnite extension exists but the evidence shows no such project \u2014 searched for: \u0060Playnite\u0060. Each was matched case- and separator-insensitively against file and directory NAMES anywhere in the tree, and against the CONTENTS of manifest files (package.json, *.csproj, *.props, *.slnx, *.yml, Dockerfile); the README\u0027s own prose never counts, so a claim is never refuted by merely being made. Nothing outside that search was read \u2014 a footprint living only in a submodule, in a file type not listed here, or under a name none of those terms matches is not seen, and this row is then wrong."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"c2ae1a4c9300a70d51e69a69641bca148c059bd1f2dfa114d96f7aac9bfd7d88"}},{"ruleId":"M4","level":"note","message":{"text":"README/code drift: README claims comparison with GameSave Manager and GBM exists but there is no such project in the repository \u2014 searched for: \u0060GameSave Manager\u0060, \u0060GBM\u0060. Each was matched case- and separator-insensitively against file and directory NAMES anywhere in the tree, and against the CONTENTS of manifest files (package.json, *.csproj, *.props, *.slnx, *.yml, Dockerfile); the README\u0027s own prose never counts, so a claim is never refuted by merely being made. Nothing outside that search was read \u2014 a footprint living only in a submodule, in a file type not listed here, or under a name none of those terms matches is not seen, and this row is then wrong."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"aca00e9b8c0ba9cbd22dcbadbb7e8da31a85338c6aab21abe5a57c3bbed784b9"}}],"taxonomies":[{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d","organization":"MITRE","informationUri":"https://cwe.mitre.org/","isComprehensive":false,"shortDescription":{"text":"The MITRE Common Weakness Enumeration (CWE)."},"taxa":[{"id":"CWE-1357","guid":"e4d2e772-757e-0a5c-bd7d-77052949d866","name":"Reliance on Insufficiently Trustworthy Component","shortDescription":{"text":"Reliance on Insufficiently Trustworthy Component"},"helpUri":"https://cwe.mitre.org/data/definitions/1357.html"},{"id":"CWE-1395","guid":"800e09e7-c11a-8654-9fa6-86f398995fed","name":"Dependency on Vulnerable Third-Party Component","shortDescription":{"text":"Dependency on Vulnerable Third-Party Component"},"helpUri":"https://cwe.mitre.org/data/definitions/1395.html"},{"id":"CWE-259","guid":"ae9ad959-fbb6-9d5e-892d-3dca66da0b69","name":"Use of Hard-coded Password","shortDescription":{"text":"Use of Hard-coded Password"},"helpUri":"https://cwe.mitre.org/data/definitions/259.html"},{"id":"CWE-353","guid":"09d7e902-d4ee-f05d-ae6c-0a1554d0c18f","name":"CWE-353","shortDescription":{"text":"CWE-353"},"helpUri":"https://cwe.mitre.org/data/definitions/353.html"},{"id":"CWE-494","guid":"b8a65e0d-e459-4a55-a931-fc1136482375","name":"Download of Code Without Integrity Check","shortDescription":{"text":"Download of Code Without Integrity Check"},"helpUri":"https://cwe.mitre.org/data/definitions/494.html"},{"id":"CWE-506","guid":"401d6455-56e3-0552-9a39-f77461673e3f","name":"CWE-506","shortDescription":{"text":"CWE-506"},"helpUri":"https://cwe.mitre.org/data/definitions/506.html"},{"id":"CWE-77","guid":"332c8ade-6612-9f56-a06b-d8d90b1a8750","name":"Command Injection","shortDescription":{"text":"Command Injection"},"helpUri":"https://cwe.mitre.org/data/definitions/77.html"},{"id":"CWE-78","guid":"2e31ceaf-c7ae-2e5e-9661-cfb1362789cf","name":"OS Command Injection","shortDescription":{"text":"OS Command Injection"},"helpUri":"https://cwe.mitre.org/data/definitions/78.html"},{"id":"CWE-79","guid":"fd45580b-e8c4-fc5e-8c2f-aa8fab0b4dbf","name":"Cross-site Scripting (XSS)","shortDescription":{"text":"Cross-site Scripting (XSS)"},"helpUri":"https://cwe.mitre.org/data/definitions/79.html"},{"id":"CWE-798","guid":"5e8f057d-fee3-995a-a0cb-9fc5b0d174d1","name":"Use of Hard-coded Credentials","shortDescription":{"text":"Use of Hard-coded Credentials"},"helpUri":"https://cwe.mitre.org/data/definitions/798.html"},{"id":"CWE-89","guid":"6d08fdad-37eb-c150-bbf0-d7d946863407","name":"SQL Injection","shortDescription":{"text":"SQL Injection"},"helpUri":"https://cwe.mitre.org/data/definitions/89.html"},{"id":"CWE-937","guid":"16f316ae-415c-b354-a59b-1f7905f756e9","name":"Using Components with Known Vulnerabilities","shortDescription":{"text":"Using Components with Known Vulnerabilities"},"helpUri":"https://cwe.mitre.org/data/definitions/937.html"},{"id":"CWE-94","guid":"75e7f50c-6c2f-dd52-bf40-bf6c52b861fd","name":"Code Injection","shortDescription":{"text":"Code Injection"},"helpUri":"https://cwe.mitre.org/data/definitions/94.html"}]}],"properties":{"codehealthPublication":{"public":true,"notice":"This is the PUBLIC form of this artifact. Findings are listed in full, but the details of SECURITY findings \u2014 which rule fired, in which file, on which line, and how to fix it \u2014 are deliberately withheld, and any secret-scanner results are excluded entirely. Where detail is absent here it was REMOVED FOR PUBLICATION; it is not missing from the analysis. The complete artifact is available from the repository owner.","securityFindingsRedacted":40,"secretScannerRunsExcluded":0}},"redactionTokens":["A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."]}]}